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();
203 QDeclarativeEngine engine;
206 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
208 void tst_qdeclarativeecmascript::assignBasicTypes()
211 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
212 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
213 QVERIFY(object != 0);
214 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
215 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
216 QCOMPARE(object->stringProperty(), QString("Hello World!"));
217 QCOMPARE(object->uintProperty(), uint(10));
218 QCOMPARE(object->intProperty(), -19);
219 QCOMPARE((float)object->realProperty(), float(23.2));
220 QCOMPARE((float)object->doubleProperty(), float(-19.75));
221 QCOMPARE((float)object->floatProperty(), float(8.5));
222 QCOMPARE(object->colorProperty(), QColor("red"));
223 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
224 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
225 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
226 QCOMPARE(object->pointProperty(), QPoint(99,13));
227 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
228 QCOMPARE(object->sizeProperty(), QSize(99, 13));
229 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
230 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
231 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
232 QCOMPARE(object->boolProperty(), true);
233 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
234 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
235 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
239 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
240 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
241 QVERIFY(object != 0);
242 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
243 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
244 QCOMPARE(object->stringProperty(), QString("Hello World!"));
245 QCOMPARE(object->uintProperty(), uint(10));
246 QCOMPARE(object->intProperty(), -19);
247 QCOMPARE((float)object->realProperty(), float(23.2));
248 QCOMPARE((float)object->doubleProperty(), float(-19.75));
249 QCOMPARE((float)object->floatProperty(), float(8.5));
250 QCOMPARE(object->colorProperty(), QColor("red"));
251 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
252 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
253 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
254 QCOMPARE(object->pointProperty(), QPoint(99,13));
255 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
256 QCOMPARE(object->sizeProperty(), QSize(99, 13));
257 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
258 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
259 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
260 QCOMPARE(object->boolProperty(), true);
261 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
262 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
263 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
268 void tst_qdeclarativeecmascript::idShortcutInvalidates()
271 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
272 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
273 QVERIFY(object != 0);
274 QVERIFY(object->objectProperty() != 0);
275 delete object->objectProperty();
276 QVERIFY(object->objectProperty() == 0);
281 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
282 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
283 QVERIFY(object != 0);
284 QVERIFY(object->objectProperty() != 0);
285 delete object->objectProperty();
286 QVERIFY(object->objectProperty() == 0);
291 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
294 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
295 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
296 QVERIFY(object != 0);
297 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
301 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
302 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
303 QVERIFY(object != 0);
304 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
309 void tst_qdeclarativeecmascript::signalAssignment()
312 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
313 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
314 QVERIFY(object != 0);
315 QCOMPARE(object->string(), QString());
316 emit object->basicSignal();
317 QCOMPARE(object->string(), QString("pass"));
322 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
323 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
324 QVERIFY(object != 0);
325 QCOMPARE(object->string(), QString());
326 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
327 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
332 void tst_qdeclarativeecmascript::methods()
335 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
336 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
337 QVERIFY(object != 0);
338 QCOMPARE(object->methodCalled(), false);
339 QCOMPARE(object->methodIntCalled(), false);
340 emit object->basicSignal();
341 QCOMPARE(object->methodCalled(), true);
342 QCOMPARE(object->methodIntCalled(), false);
347 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
348 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
349 QVERIFY(object != 0);
350 QCOMPARE(object->methodCalled(), false);
351 QCOMPARE(object->methodIntCalled(), false);
352 emit object->basicSignal();
353 QCOMPARE(object->methodCalled(), false);
354 QCOMPARE(object->methodIntCalled(), true);
359 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
360 QObject *object = component.create();
361 QVERIFY(object != 0);
362 QCOMPARE(object->property("test").toInt(), 19);
367 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
368 QObject *object = component.create();
369 QVERIFY(object != 0);
370 QCOMPARE(object->property("test").toInt(), 19);
371 QCOMPARE(object->property("test2").toInt(), 17);
372 QCOMPARE(object->property("test3").toInt(), 16);
377 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
378 QObject *object = component.create();
379 QVERIFY(object != 0);
380 QCOMPARE(object->property("test").toInt(), 9);
385 void tst_qdeclarativeecmascript::bindingLoop()
387 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
388 QString warning = component.url().toString() + ":9:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
389 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
390 QObject *object = component.create();
391 QVERIFY(object != 0);
395 void tst_qdeclarativeecmascript::basicExpressions_data()
397 QTest::addColumn<QString>("expression");
398 QTest::addColumn<QVariant>("result");
399 QTest::addColumn<bool>("nest");
401 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
402 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
403 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
404 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
405 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
406 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
407 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
408 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
409 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
410 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
411 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
412 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
413 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
414 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
415 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
416 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
417 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
418 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
419 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
422 void tst_qdeclarativeecmascript::basicExpressions()
424 QFETCH(QString, expression);
425 QFETCH(QVariant, result);
431 MyDefaultObject1 default1;
432 MyDefaultObject3 default3;
433 object1.setStringProperty("Object1");
434 object2.setStringProperty("Object2");
435 object3.setStringProperty("Object3");
437 QDeclarativeContext context(engine.rootContext());
438 QDeclarativeContext nestedContext(&context);
440 context.setContextObject(&default1);
441 context.setContextProperty("a", QVariant(1944));
442 context.setContextProperty("b", QVariant("Milk"));
443 context.setContextProperty("object", &object1);
444 context.setContextProperty("objectOverride", &object2);
445 nestedContext.setContextObject(&default3);
446 nestedContext.setContextProperty("b", QVariant("Cow"));
447 nestedContext.setContextProperty("objectOverride", &object3);
448 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
450 MyExpression expr(nest?&nestedContext:&context, expression);
451 QCOMPARE(expr.evaluate(), result);
454 void tst_qdeclarativeecmascript::arrayExpressions()
460 QDeclarativeContext context(engine.rootContext());
461 context.setContextProperty("a", &obj1);
462 context.setContextProperty("b", &obj2);
463 context.setContextProperty("c", &obj3);
465 MyExpression expr(&context, "[a, b, c, 10]");
466 QVariant result = expr.evaluate();
467 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
468 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
469 QCOMPARE(list.count(), 4);
470 QCOMPARE(list.at(0), &obj1);
471 QCOMPARE(list.at(1), &obj2);
472 QCOMPARE(list.at(2), &obj3);
473 QCOMPARE(list.at(3), (QObject *)0);
476 // Tests that modifying a context property will reevaluate expressions
477 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
479 QDeclarativeContext context(engine.rootContext());
482 MyQmlObject *object3 = new MyQmlObject;
484 object1.setStringProperty("Hello");
485 object2.setStringProperty("World");
487 context.setContextProperty("testProp", QVariant(1));
488 context.setContextProperty("testObj", &object1);
489 context.setContextProperty("testObj2", object3);
492 MyExpression expr(&context, "testProp + 1");
493 QCOMPARE(expr.changed, false);
494 QCOMPARE(expr.evaluate(), QVariant(2));
496 context.setContextProperty("testProp", QVariant(2));
497 QCOMPARE(expr.changed, true);
498 QCOMPARE(expr.evaluate(), QVariant(3));
502 MyExpression expr(&context, "testProp + testProp + testProp");
503 QCOMPARE(expr.changed, false);
504 QCOMPARE(expr.evaluate(), QVariant(6));
506 context.setContextProperty("testProp", QVariant(4));
507 QCOMPARE(expr.changed, true);
508 QCOMPARE(expr.evaluate(), QVariant(12));
512 MyExpression expr(&context, "testObj.stringProperty");
513 QCOMPARE(expr.changed, false);
514 QCOMPARE(expr.evaluate(), QVariant("Hello"));
516 context.setContextProperty("testObj", &object2);
517 QCOMPARE(expr.changed, true);
518 QCOMPARE(expr.evaluate(), QVariant("World"));
522 MyExpression expr(&context, "testObj.stringProperty /**/");
523 QCOMPARE(expr.changed, false);
524 QCOMPARE(expr.evaluate(), QVariant("World"));
526 context.setContextProperty("testObj", &object1);
527 QCOMPARE(expr.changed, true);
528 QCOMPARE(expr.evaluate(), QVariant("Hello"));
532 MyExpression expr(&context, "testObj2");
533 QCOMPARE(expr.changed, false);
534 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
540 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
542 QDeclarativeContext context(engine.rootContext());
546 context.setContextProperty("testObj", &object1);
548 object1.setStringProperty(QLatin1String("Hello"));
549 object2.setStringProperty(QLatin1String("Dog"));
550 object3.setStringProperty(QLatin1String("Cat"));
553 MyExpression expr(&context, "testObj.stringProperty");
554 QCOMPARE(expr.changed, false);
555 QCOMPARE(expr.evaluate(), QVariant("Hello"));
557 object1.setStringProperty(QLatin1String("World"));
558 QCOMPARE(expr.changed, true);
559 QCOMPARE(expr.evaluate(), QVariant("World"));
563 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
564 QCOMPARE(expr.changed, false);
565 QCOMPARE(expr.evaluate(), QVariant());
567 object1.setObjectProperty(&object2);
568 QCOMPARE(expr.changed, true);
569 expr.changed = false;
570 QCOMPARE(expr.evaluate(), QVariant("Dog"));
572 object1.setObjectProperty(&object3);
573 QCOMPARE(expr.changed, true);
574 expr.changed = false;
575 QCOMPARE(expr.evaluate(), QVariant("Cat"));
577 object1.setObjectProperty(0);
578 QCOMPARE(expr.changed, true);
579 expr.changed = false;
580 QCOMPARE(expr.evaluate(), QVariant());
582 object1.setObjectProperty(&object3);
583 QCOMPARE(expr.changed, true);
584 expr.changed = false;
585 QCOMPARE(expr.evaluate(), QVariant("Cat"));
587 object3.setStringProperty("Donkey");
588 QCOMPARE(expr.changed, true);
589 expr.changed = false;
590 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
594 void tst_qdeclarativeecmascript::deferredProperties()
596 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
597 MyDeferredObject *object =
598 qobject_cast<MyDeferredObject *>(component.create());
599 QVERIFY(object != 0);
600 QCOMPARE(object->value(), 0);
601 QVERIFY(object->objectProperty() == 0);
602 QVERIFY(object->objectProperty2() != 0);
603 qmlExecuteDeferred(object);
604 QCOMPARE(object->value(), 10);
605 QVERIFY(object->objectProperty() != 0);
606 MyQmlObject *qmlObject =
607 qobject_cast<MyQmlObject *>(object->objectProperty());
608 QVERIFY(qmlObject != 0);
609 QCOMPARE(qmlObject->value(), 10);
610 object->setValue(19);
611 QCOMPARE(qmlObject->value(), 19);
616 // Check errors on deferred properties are correctly emitted
617 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
619 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
620 MyDeferredObject *object =
621 qobject_cast<MyDeferredObject *>(component.create());
622 QVERIFY(object != 0);
623 QCOMPARE(object->value(), 0);
624 QVERIFY(object->objectProperty() == 0);
625 QVERIFY(object->objectProperty2() == 0);
627 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject* objectProperty";
628 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
630 qmlExecuteDeferred(object);
635 void tst_qdeclarativeecmascript::extensionObjects()
637 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
638 MyExtendedObject *object =
639 qobject_cast<MyExtendedObject *>(component.create());
640 QVERIFY(object != 0);
641 QCOMPARE(object->baseProperty(), 13);
642 QCOMPARE(object->coreProperty(), 9);
643 object->setProperty("extendedProperty", QVariant(11));
644 object->setProperty("baseExtendedProperty", QVariant(92));
645 QCOMPARE(object->coreProperty(), 11);
646 QCOMPARE(object->baseProperty(), 92);
648 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
650 QCOMPARE(nested->baseProperty(), 13);
651 QCOMPARE(nested->coreProperty(), 9);
652 nested->setProperty("extendedProperty", QVariant(11));
653 nested->setProperty("baseExtendedProperty", QVariant(92));
654 QCOMPARE(nested->coreProperty(), 11);
655 QCOMPARE(nested->baseProperty(), 92);
660 void tst_qdeclarativeecmascript::overrideExtensionProperties()
662 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
663 OverrideDefaultPropertyObject *object =
664 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
665 QVERIFY(object != 0);
666 QVERIFY(object->secondProperty() != 0);
667 QVERIFY(object->firstProperty() == 0);
672 void tst_qdeclarativeecmascript::attachedProperties()
675 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
676 QObject *object = component.create();
677 QVERIFY(object != 0);
678 QCOMPARE(object->property("a").toInt(), 19);
679 QCOMPARE(object->property("b").toInt(), 19);
680 QCOMPARE(object->property("c").toInt(), 19);
681 QCOMPARE(object->property("d").toInt(), 19);
686 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
687 QObject *object = component.create();
688 QVERIFY(object != 0);
689 QCOMPARE(object->property("a").toInt(), 26);
690 QCOMPARE(object->property("b").toInt(), 26);
691 QCOMPARE(object->property("c").toInt(), 26);
692 QCOMPARE(object->property("d").toInt(), 26);
698 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
699 QObject *object = component.create();
700 QVERIFY(object != 0);
702 QMetaObject::invokeMethod(object, "writeValue2");
704 MyQmlAttachedObject *attached =
705 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
706 QVERIFY(attached != 0);
708 QCOMPARE(attached->value2(), 9);
713 void tst_qdeclarativeecmascript::enums()
717 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
718 QObject *object = component.create();
719 QVERIFY(object != 0);
721 QCOMPARE(object->property("a").toInt(), 0);
722 QCOMPARE(object->property("b").toInt(), 1);
723 QCOMPARE(object->property("c").toInt(), 2);
724 QCOMPARE(object->property("d").toInt(), 3);
725 QCOMPARE(object->property("e").toInt(), 0);
726 QCOMPARE(object->property("f").toInt(), 1);
727 QCOMPARE(object->property("g").toInt(), 2);
728 QCOMPARE(object->property("h").toInt(), 3);
729 QCOMPARE(object->property("i").toInt(), 19);
730 QCOMPARE(object->property("j").toInt(), 19);
734 // Non-existent enums
736 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
738 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int a";
739 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int b";
740 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
741 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
743 QObject *object = component.create();
744 QVERIFY(object != 0);
745 QCOMPARE(object->property("a").toInt(), 0);
746 QCOMPARE(object->property("b").toInt(), 0);
752 void tst_qdeclarativeecmascript::valueTypeFunctions()
754 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
755 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
757 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
758 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
764 Tests that writing a constant to a property with a binding on it disables the
767 void tst_qdeclarativeecmascript::constantsOverrideBindings()
771 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
772 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
773 QVERIFY(object != 0);
775 QCOMPARE(object->property("c2").toInt(), 0);
776 object->setProperty("c1", QVariant(9));
777 QCOMPARE(object->property("c2").toInt(), 9);
779 emit object->basicSignal();
781 QCOMPARE(object->property("c2").toInt(), 13);
782 object->setProperty("c1", QVariant(8));
783 QCOMPARE(object->property("c2").toInt(), 13);
788 // During construction
790 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
791 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
792 QVERIFY(object != 0);
794 QCOMPARE(object->property("c1").toInt(), 0);
795 QCOMPARE(object->property("c2").toInt(), 10);
796 object->setProperty("c1", QVariant(9));
797 QCOMPARE(object->property("c1").toInt(), 9);
798 QCOMPARE(object->property("c2").toInt(), 10);
806 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
807 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
808 QVERIFY(object != 0);
810 QCOMPARE(object->property("c2").toInt(), 0);
811 object->setProperty("c1", QVariant(9));
812 QCOMPARE(object->property("c2").toInt(), 9);
814 object->setProperty("c2", QVariant(13));
815 QCOMPARE(object->property("c2").toInt(), 13);
816 object->setProperty("c1", QVariant(7));
817 QCOMPARE(object->property("c1").toInt(), 7);
818 QCOMPARE(object->property("c2").toInt(), 13);
826 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
827 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
828 QVERIFY(object != 0);
830 QCOMPARE(object->property("c1").toInt(), 0);
831 QCOMPARE(object->property("c3").toInt(), 10);
832 object->setProperty("c1", QVariant(9));
833 QCOMPARE(object->property("c1").toInt(), 9);
834 QCOMPARE(object->property("c3").toInt(), 10);
841 Tests that assigning a binding to a property that already has a binding causes
842 the original binding to be disabled.
844 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
846 QDeclarativeComponent component(&engine,
847 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
848 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
849 QVERIFY(object != 0);
851 QCOMPARE(object->property("c1").toInt(), 0);
852 QCOMPARE(object->property("c2").toInt(), 0);
853 QCOMPARE(object->property("c3").toInt(), 0);
855 object->setProperty("c1", QVariant(9));
856 QCOMPARE(object->property("c1").toInt(), 9);
857 QCOMPARE(object->property("c2").toInt(), 0);
858 QCOMPARE(object->property("c3").toInt(), 0);
860 object->setProperty("c3", QVariant(8));
861 QCOMPARE(object->property("c1").toInt(), 9);
862 QCOMPARE(object->property("c2").toInt(), 8);
863 QCOMPARE(object->property("c3").toInt(), 8);
869 Access a non-existent attached object.
871 Tests for a regression where this used to crash.
873 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
875 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
877 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString stringProperty";
878 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
880 QObject *object = component.create();
881 QVERIFY(object != 0);
886 void tst_qdeclarativeecmascript::scope()
889 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
890 QObject *object = component.create();
891 QVERIFY(object != 0);
893 QCOMPARE(object->property("test1").toInt(), 1);
894 QCOMPARE(object->property("test2").toInt(), 2);
895 QCOMPARE(object->property("test3").toString(), QString("1Test"));
896 QCOMPARE(object->property("test4").toString(), QString("2Test"));
897 QCOMPARE(object->property("test5").toInt(), 1);
898 QCOMPARE(object->property("test6").toInt(), 1);
899 QCOMPARE(object->property("test7").toInt(), 2);
900 QCOMPARE(object->property("test8").toInt(), 2);
901 QCOMPARE(object->property("test9").toInt(), 1);
902 QCOMPARE(object->property("test10").toInt(), 3);
908 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
909 QObject *object = component.create();
910 QVERIFY(object != 0);
912 QCOMPARE(object->property("test1").toInt(), 19);
913 QCOMPARE(object->property("test2").toInt(), 19);
914 QCOMPARE(object->property("test3").toInt(), 14);
915 QCOMPARE(object->property("test4").toInt(), 14);
916 QCOMPARE(object->property("test5").toInt(), 24);
917 QCOMPARE(object->property("test6").toInt(), 24);
923 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
924 QObject *object = component.create();
925 QVERIFY(object != 0);
927 QCOMPARE(object->property("test1").toBool(), true);
928 QCOMPARE(object->property("test2").toBool(), true);
929 QCOMPARE(object->property("test3").toBool(), true);
934 // Signal argument scope
936 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
937 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
938 QVERIFY(object != 0);
940 QCOMPARE(object->property("test").toInt(), 0);
941 QCOMPARE(object->property("test2").toString(), QString());
943 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
945 QCOMPARE(object->property("test").toInt(), 13);
946 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
952 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
953 QObject *object = component.create();
954 QVERIFY(object != 0);
956 QCOMPARE(object->property("test1").toBool(), true);
957 QCOMPARE(object->property("test2").toBool(), true);
963 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
964 QObject *object = component.create();
965 QVERIFY(object != 0);
967 QCOMPARE(object->property("test").toBool(), true);
973 // In 4.7, non-library javascript files that had no imports shared the imports of their
975 void tst_qdeclarativeecmascript::importScope()
977 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
978 QObject *o = component.create();
981 QCOMPARE(o->property("test").toInt(), 240);
987 Tests that "any" type passes through a synthesized signal parameter. This
988 is essentially a test of QDeclarativeMetaType::copy()
990 void tst_qdeclarativeecmascript::signalParameterTypes()
992 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
993 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
994 QVERIFY(object != 0);
996 emit object->basicSignal();
998 QCOMPARE(object->property("intProperty").toInt(), 10);
999 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1000 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1001 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1002 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1003 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1009 Test that two JS objects for the same QObject compare as equal.
1011 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1013 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1014 QObject *object = component.create();
1015 QVERIFY(object != 0);
1017 QCOMPARE(object->property("test1").toBool(), true);
1018 QCOMPARE(object->property("test2").toBool(), true);
1019 QCOMPARE(object->property("test3").toBool(), true);
1020 QCOMPARE(object->property("test4").toBool(), true);
1021 QCOMPARE(object->property("test5").toBool(), true);
1027 Confirm bindings and alias properties can coexist.
1029 Tests for a regression where the binding would not reevaluate.
1031 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1033 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1034 QObject *object = component.create();
1035 QVERIFY(object != 0);
1037 QCOMPARE(object->property("c2").toInt(), 3);
1038 QCOMPARE(object->property("c3").toInt(), 3);
1040 object->setProperty("c2", QVariant(19));
1042 QCOMPARE(object->property("c2").toInt(), 19);
1043 QCOMPARE(object->property("c3").toInt(), 19);
1049 Ensure that we can write undefined value to an alias property,
1050 and that the aliased property is reset correctly if possible.
1052 void tst_qdeclarativeecmascript::aliasPropertyReset()
1054 QObject *object = 0;
1056 // test that a manual write (of undefined) to a resettable aliased property succeeds
1057 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1058 object = c1.create();
1059 QVERIFY(object != 0);
1060 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1061 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1062 QMetaObject::invokeMethod(object, "resetAliased");
1063 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1064 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1067 // test that a manual write (of undefined) to a resettable alias property succeeds
1068 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1069 object = c2.create();
1070 QVERIFY(object != 0);
1071 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1072 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1073 QMetaObject::invokeMethod(object, "resetAlias");
1074 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1075 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1078 // test that an alias to a bound property works correctly
1079 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1080 object = c3.create();
1081 QVERIFY(object != 0);
1082 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1083 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1084 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1085 QMetaObject::invokeMethod(object, "resetAlias");
1086 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1087 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1088 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1091 // test that a manual write (of undefined) to a resettable alias property
1092 // whose aliased property's object has been deleted, does not crash.
1093 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1094 object = c4.create();
1095 QVERIFY(object != 0);
1096 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1097 QObject *loader = object->findChild<QObject*>("loader");
1098 QVERIFY(loader != 0);
1100 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1101 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1102 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1103 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1104 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1107 // test that binding an alias property to an undefined value works correctly
1108 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1109 object = c5.create();
1110 QVERIFY(object != 0);
1111 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1114 // test that a manual write (of undefined) to a non-resettable property fails properly
1115 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1116 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1117 QDeclarativeComponent e1(&engine, url);
1118 object = e1.create();
1119 QVERIFY(object != 0);
1120 QCOMPARE(object->property("intAlias").value<int>(), 12);
1121 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1122 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1123 QMetaObject::invokeMethod(object, "resetAlias");
1124 QCOMPARE(object->property("intAlias").value<int>(), 12);
1125 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1129 void tst_qdeclarativeecmascript::dynamicCreation_data()
1131 QTest::addColumn<QString>("method");
1132 QTest::addColumn<QString>("createdName");
1134 QTest::newRow("One") << "createOne" << "objectOne";
1135 QTest::newRow("Two") << "createTwo" << "objectTwo";
1136 QTest::newRow("Three") << "createThree" << "objectThree";
1140 Test using createQmlObject to dynamically generate an item
1141 Also using createComponent is tested.
1143 void tst_qdeclarativeecmascript::dynamicCreation()
1145 QFETCH(QString, method);
1146 QFETCH(QString, createdName);
1148 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1149 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1150 QVERIFY(object != 0);
1152 QMetaObject::invokeMethod(object, method.toUtf8());
1153 QObject *created = object->objectProperty();
1155 QCOMPARE(created->objectName(), createdName);
1161 Tests the destroy function
1163 void tst_qdeclarativeecmascript::dynamicDestruction()
1166 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1167 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1168 QVERIFY(object != 0);
1169 QDeclarativeGuard<QObject> createdQmlObject = 0;
1171 QMetaObject::invokeMethod(object, "create");
1172 createdQmlObject = object->objectProperty();
1173 QVERIFY(createdQmlObject);
1174 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1176 QMetaObject::invokeMethod(object, "killOther");
1177 QVERIFY(createdQmlObject);
1178 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1179 QVERIFY(createdQmlObject);
1180 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1181 if (createdQmlObject) {
1183 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1186 QVERIFY(!createdQmlObject);
1188 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1189 QMetaObject::invokeMethod(object, "killMe");
1192 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1197 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1198 QObject *o = component.create();
1201 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1203 QMetaObject::invokeMethod(o, "create");
1205 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1207 QMetaObject::invokeMethod(o, "destroy");
1209 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1211 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1218 tests that id.toString() works
1220 void tst_qdeclarativeecmascript::objectToString()
1222 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1223 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1224 QVERIFY(object != 0);
1225 QMetaObject::invokeMethod(object, "testToString");
1226 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1227 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1233 tests that id.hasOwnProperty() works
1235 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1237 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1238 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1239 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1240 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1242 QDeclarativeComponent component(&engine, url);
1243 QObject *object = component.create();
1244 QVERIFY(object != 0);
1246 // test QObjects in QML
1247 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1248 QVERIFY(object->property("result").value<bool>() == true);
1249 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1250 QVERIFY(object->property("result").value<bool>() == false);
1252 // now test other types in QML
1253 QObject *child = object->findChild<QObject*>("typeObj");
1254 QVERIFY(child != 0);
1255 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1256 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1257 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1258 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1259 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1260 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1261 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1262 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1263 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1264 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1265 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1266 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1268 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1269 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1270 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1271 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1272 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1273 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1274 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1275 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1276 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1282 Tests bindings that indirectly cause their own deletion work.
1284 This test is best run under valgrind to ensure no invalid memory access occur.
1286 void tst_qdeclarativeecmascript::selfDeletingBinding()
1289 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1290 QObject *object = component.create();
1291 QVERIFY(object != 0);
1292 object->setProperty("triggerDelete", true);
1297 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1298 QObject *object = component.create();
1299 QVERIFY(object != 0);
1300 object->setProperty("triggerDelete", true);
1306 Test that extended object properties can be accessed.
1308 This test a regression where this used to crash. The issue was specificially
1309 for extended objects that did not include a synthesized meta object (so non-root
1310 and no synthesiszed properties).
1312 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1314 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1315 QObject *object = component.create();
1316 QVERIFY(object != 0);
1321 Test file/lineNumbers for binding/Script errors.
1323 void tst_qdeclarativeecmascript::scriptErrors()
1325 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1326 QString url = component.url().toString();
1328 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1329 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1330 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1331 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1332 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1333 QString warning6 = url + ":7: Unable to assign [undefined] to int x";
1334 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1335 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1337 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1338 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1339 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1340 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1341 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1342 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1343 QVERIFY(object != 0);
1345 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1346 emit object->basicSignal();
1348 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1349 emit object->anotherBasicSignal();
1351 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1352 emit object->thirdBasicSignal();
1358 Test file/lineNumbers for inline functions.
1360 void tst_qdeclarativeecmascript::functionErrors()
1362 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1363 QString url = component.url().toString();
1365 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1367 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1369 QObject *object = component.create();
1370 QVERIFY(object != 0);
1373 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1374 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1375 url = componentTwo.url().toString();
1376 object = componentTwo.create();
1377 QVERIFY(object != 0);
1379 QString srpname = object->property("srp_name").toString();
1381 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1382 QLatin1String(" is not a function");
1383 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1384 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1389 Test various errors that can occur when assigning a property from script
1391 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1393 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1395 QString url = component.url().toString();
1397 QObject *object = component.create();
1398 QVERIFY(object != 0);
1400 QCOMPARE(object->property("test1").toBool(), true);
1401 QCOMPARE(object->property("test2").toBool(), true);
1407 Test bindings still work when the reeval is triggered from within
1410 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1412 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1413 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1414 QVERIFY(object != 0);
1416 QCOMPARE(object->property("base").toReal(), 50.);
1417 QCOMPARE(object->property("test1").toReal(), 50.);
1418 QCOMPARE(object->property("test2").toReal(), 50.);
1420 object->basicSignal();
1422 QCOMPARE(object->property("base").toReal(), 200.);
1423 QCOMPARE(object->property("test1").toReal(), 200.);
1424 QCOMPARE(object->property("test2").toReal(), 200.);
1426 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1428 QCOMPARE(object->property("base").toReal(), 400.);
1429 QCOMPARE(object->property("test1").toReal(), 400.);
1430 QCOMPARE(object->property("test2").toReal(), 400.);
1436 Test that list properties can be iterated from ECMAScript
1438 void tst_qdeclarativeecmascript::listProperties()
1440 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1441 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1442 QVERIFY(object != 0);
1444 QCOMPARE(object->property("test1").toInt(), 21);
1445 QCOMPARE(object->property("test2").toInt(), 2);
1446 QCOMPARE(object->property("test3").toBool(), true);
1447 QCOMPARE(object->property("test4").toBool(), true);
1452 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1454 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1455 QString url = component.url().toString();
1457 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1459 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1460 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1461 QVERIFY(object != 0);
1463 QCOMPARE(object->property("test").toBool(), false);
1465 MyQmlObject object2;
1466 MyQmlObject object3;
1467 object2.setObjectProperty(&object3);
1468 object->setObjectProperty(&object2);
1470 QCOMPARE(object->property("test").toBool(), true);
1475 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1477 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1478 QString url = component.url().toString();
1480 QString warning = component.url().toString() + ":6: Error: JS exception";
1482 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1483 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1484 QVERIFY(object != 0);
1488 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1490 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1491 QString url = component.url().toString();
1493 QString warning = component.url().toString() + ":5: Error: JS exception";
1495 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1496 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1497 QVERIFY(object != 0);
1501 static int transientErrorsMsgCount = 0;
1502 static void transientErrorsMsgHandler(QtMsgType, const char *)
1504 ++transientErrorsMsgCount;
1507 // Check that transient binding errors are not displayed
1508 void tst_qdeclarativeecmascript::transientErrors()
1511 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1513 transientErrorsMsgCount = 0;
1514 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1516 QObject *object = component.create();
1517 QVERIFY(object != 0);
1519 qInstallMsgHandler(old);
1521 QCOMPARE(transientErrorsMsgCount, 0);
1526 // One binding erroring multiple times, but then resolving
1528 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1530 transientErrorsMsgCount = 0;
1531 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1533 QObject *object = component.create();
1534 QVERIFY(object != 0);
1536 qInstallMsgHandler(old);
1538 QCOMPARE(transientErrorsMsgCount, 0);
1544 // Check that errors during shutdown are minimized
1545 void tst_qdeclarativeecmascript::shutdownErrors()
1547 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1548 QObject *object = component.create();
1549 QVERIFY(object != 0);
1551 transientErrorsMsgCount = 0;
1552 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1556 qInstallMsgHandler(old);
1557 QCOMPARE(transientErrorsMsgCount, 0);
1560 void tst_qdeclarativeecmascript::compositePropertyType()
1562 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1563 QTest::ignoreMessage(QtDebugMsg, "hello world");
1564 QObject *object = qobject_cast<QObject *>(component.create());
1569 void tst_qdeclarativeecmascript::jsObject()
1571 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1572 QObject *object = component.create();
1573 QVERIFY(object != 0);
1575 QCOMPARE(object->property("test").toInt(), 92);
1580 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1583 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1584 QObject *object = component.create();
1585 QVERIFY(object != 0);
1587 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1589 object->setProperty("setUndefined", true);
1591 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1593 object->setProperty("setUndefined", false);
1595 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1600 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1601 QObject *object = component.create();
1602 QVERIFY(object != 0);
1604 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1606 QMetaObject::invokeMethod(object, "doReset");
1608 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1615 void tst_qdeclarativeecmascript::bug1()
1617 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1618 QObject *object = component.create();
1619 QVERIFY(object != 0);
1621 QCOMPARE(object->property("test").toInt(), 14);
1623 object->setProperty("a", 11);
1625 QCOMPARE(object->property("test").toInt(), 3);
1627 object->setProperty("b", true);
1629 QCOMPARE(object->property("test").toInt(), 9);
1634 void tst_qdeclarativeecmascript::bug2()
1636 QDeclarativeComponent component(&engine);
1637 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1639 QObject *object = component.create();
1640 QVERIFY(object != 0);
1645 // Don't crash in createObject when the component has errors.
1646 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1648 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1649 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1650 QVERIFY(object != 0);
1652 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1653 QMetaObject::invokeMethod(object, "dontCrash");
1654 QObject *created = object->objectProperty();
1655 QVERIFY(created == 0);
1661 void tst_qdeclarativeecmascript::regExpBug()
1663 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1664 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1665 QVERIFY(object != 0);
1666 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1670 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1672 QString functionSource = QLatin1String("(function(object) { return ") +
1673 QLatin1String(source) + QLatin1String(" })");
1675 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1678 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1679 if (function.IsEmpty())
1681 v8::Handle<v8::Value> args[] = { o };
1682 function->Call(engine->global(), 1, args);
1683 return tc.HasCaught();
1686 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1687 const char *source, v8::Handle<v8::Value> result)
1689 QString functionSource = QLatin1String("(function(object) { return ") +
1690 QLatin1String(source) + QLatin1String(" })");
1692 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1695 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1696 if (function.IsEmpty())
1698 v8::Handle<v8::Value> args[] = { o };
1700 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1705 return value->StrictEquals(result);
1708 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1711 QString functionSource = QLatin1String("(function(object) { return ") +
1712 QLatin1String(source) + QLatin1String(" })");
1714 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1716 return v8::Handle<v8::Value>();
1717 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1718 if (function.IsEmpty())
1719 return v8::Handle<v8::Value>();
1720 v8::Handle<v8::Value> args[] = { o };
1722 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1725 return v8::Handle<v8::Value>();
1729 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1730 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1731 #define EVALUATE(source) evaluate(engine, object, source)
1733 void tst_qdeclarativeecmascript::callQtInvokables()
1735 MyInvokableObject o;
1737 QDeclarativeEngine qmlengine;
1738 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1740 QV8Engine *engine = ep->v8engine();
1742 v8::HandleScope handle_scope;
1743 v8::Context::Scope scope(engine->context());
1745 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1747 // Non-existent methods
1749 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1750 QCOMPARE(o.error(), false);
1751 QCOMPARE(o.invoked(), -1);
1752 QCOMPARE(o.actuals().count(), 0);
1755 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1756 QCOMPARE(o.error(), false);
1757 QCOMPARE(o.invoked(), -1);
1758 QCOMPARE(o.actuals().count(), 0);
1760 // Insufficient arguments
1762 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1763 QCOMPARE(o.error(), false);
1764 QCOMPARE(o.invoked(), -1);
1765 QCOMPARE(o.actuals().count(), 0);
1768 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1769 QCOMPARE(o.error(), false);
1770 QCOMPARE(o.invoked(), -1);
1771 QCOMPARE(o.actuals().count(), 0);
1773 // Excessive arguments
1775 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1776 QCOMPARE(o.error(), false);
1777 QCOMPARE(o.invoked(), 8);
1778 QCOMPARE(o.actuals().count(), 1);
1779 QCOMPARE(o.actuals().at(0), QVariant(10));
1782 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1783 QCOMPARE(o.error(), false);
1784 QCOMPARE(o.invoked(), 9);
1785 QCOMPARE(o.actuals().count(), 2);
1786 QCOMPARE(o.actuals().at(0), QVariant(10));
1787 QCOMPARE(o.actuals().at(1), QVariant(11));
1789 // Test return types
1791 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1792 QCOMPARE(o.error(), false);
1793 QCOMPARE(o.invoked(), 0);
1794 QCOMPARE(o.actuals().count(), 0);
1797 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1798 QCOMPARE(o.error(), false);
1799 QCOMPARE(o.invoked(), 1);
1800 QCOMPARE(o.actuals().count(), 0);
1803 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1804 QCOMPARE(o.error(), false);
1805 QCOMPARE(o.invoked(), 2);
1806 QCOMPARE(o.actuals().count(), 0);
1810 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1811 QVERIFY(!ret.IsEmpty());
1812 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1813 QCOMPARE(o.error(), false);
1814 QCOMPARE(o.invoked(), 3);
1815 QCOMPARE(o.actuals().count(), 0);
1820 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1821 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1822 QCOMPARE(o.error(), false);
1823 QCOMPARE(o.invoked(), 4);
1824 QCOMPARE(o.actuals().count(), 0);
1828 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1829 QCOMPARE(o.error(), false);
1830 QCOMPARE(o.invoked(), 5);
1831 QCOMPARE(o.actuals().count(), 0);
1835 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1836 QVERIFY(ret->IsString());
1837 QCOMPARE(engine->toString(ret), QString("Hello world"));
1838 QCOMPARE(o.error(), false);
1839 QCOMPARE(o.invoked(), 6);
1840 QCOMPARE(o.actuals().count(), 0);
1844 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1845 QCOMPARE(o.error(), false);
1846 QCOMPARE(o.invoked(), 7);
1847 QCOMPARE(o.actuals().count(), 0);
1851 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1852 QCOMPARE(o.error(), false);
1853 QCOMPARE(o.invoked(), 8);
1854 QCOMPARE(o.actuals().count(), 1);
1855 QCOMPARE(o.actuals().at(0), QVariant(94));
1858 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1859 QCOMPARE(o.error(), false);
1860 QCOMPARE(o.invoked(), 8);
1861 QCOMPARE(o.actuals().count(), 1);
1862 QCOMPARE(o.actuals().at(0), QVariant(94));
1865 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1866 QCOMPARE(o.error(), false);
1867 QCOMPARE(o.invoked(), 8);
1868 QCOMPARE(o.actuals().count(), 1);
1869 QCOMPARE(o.actuals().at(0), QVariant(0));
1872 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1873 QCOMPARE(o.error(), false);
1874 QCOMPARE(o.invoked(), 8);
1875 QCOMPARE(o.actuals().count(), 1);
1876 QCOMPARE(o.actuals().at(0), QVariant(0));
1879 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1880 QCOMPARE(o.error(), false);
1881 QCOMPARE(o.invoked(), 8);
1882 QCOMPARE(o.actuals().count(), 1);
1883 QCOMPARE(o.actuals().at(0), QVariant(0));
1886 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1887 QCOMPARE(o.error(), false);
1888 QCOMPARE(o.invoked(), 8);
1889 QCOMPARE(o.actuals().count(), 1);
1890 QCOMPARE(o.actuals().at(0), QVariant(0));
1893 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1894 QCOMPARE(o.error(), false);
1895 QCOMPARE(o.invoked(), 9);
1896 QCOMPARE(o.actuals().count(), 2);
1897 QCOMPARE(o.actuals().at(0), QVariant(122));
1898 QCOMPARE(o.actuals().at(1), QVariant(9));
1901 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1902 QCOMPARE(o.error(), false);
1903 QCOMPARE(o.invoked(), 10);
1904 QCOMPARE(o.actuals().count(), 1);
1905 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1908 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1909 QCOMPARE(o.error(), false);
1910 QCOMPARE(o.invoked(), 10);
1911 QCOMPARE(o.actuals().count(), 1);
1912 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1915 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1916 QCOMPARE(o.error(), false);
1917 QCOMPARE(o.invoked(), 10);
1918 QCOMPARE(o.actuals().count(), 1);
1919 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1922 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1923 QCOMPARE(o.error(), false);
1924 QCOMPARE(o.invoked(), 10);
1925 QCOMPARE(o.actuals().count(), 1);
1926 QCOMPARE(o.actuals().at(0), QVariant(0));
1929 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1930 QCOMPARE(o.error(), false);
1931 QCOMPARE(o.invoked(), 10);
1932 QCOMPARE(o.actuals().count(), 1);
1933 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1936 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
1937 QCOMPARE(o.error(), false);
1938 QCOMPARE(o.invoked(), 10);
1939 QCOMPARE(o.actuals().count(), 1);
1940 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1943 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
1944 QCOMPARE(o.error(), false);
1945 QCOMPARE(o.invoked(), 11);
1946 QCOMPARE(o.actuals().count(), 1);
1947 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
1950 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
1951 QCOMPARE(o.error(), false);
1952 QCOMPARE(o.invoked(), 11);
1953 QCOMPARE(o.actuals().count(), 1);
1954 QCOMPARE(o.actuals().at(0), QVariant("19"));
1958 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
1959 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
1960 QCOMPARE(o.error(), false);
1961 QCOMPARE(o.invoked(), 11);
1962 QCOMPARE(o.actuals().count(), 1);
1963 QCOMPARE(o.actuals().at(0), QVariant(expected));
1967 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
1968 QCOMPARE(o.error(), false);
1969 QCOMPARE(o.invoked(), 11);
1970 QCOMPARE(o.actuals().count(), 1);
1971 QCOMPARE(o.actuals().at(0), QVariant(QString()));
1974 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
1975 QCOMPARE(o.error(), false);
1976 QCOMPARE(o.invoked(), 11);
1977 QCOMPARE(o.actuals().count(), 1);
1978 QCOMPARE(o.actuals().at(0), QVariant(QString()));
1981 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
1982 QCOMPARE(o.error(), false);
1983 QCOMPARE(o.invoked(), 12);
1984 QCOMPARE(o.actuals().count(), 1);
1985 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1988 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
1989 QCOMPARE(o.error(), false);
1990 QCOMPARE(o.invoked(), 12);
1991 QCOMPARE(o.actuals().count(), 1);
1992 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1995 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
1996 QCOMPARE(o.error(), false);
1997 QCOMPARE(o.invoked(), 12);
1998 QCOMPARE(o.actuals().count(), 1);
1999 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2002 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2003 QCOMPARE(o.error(), false);
2004 QCOMPARE(o.invoked(), 12);
2005 QCOMPARE(o.actuals().count(), 1);
2006 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2009 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2010 QCOMPARE(o.error(), false);
2011 QCOMPARE(o.invoked(), 12);
2012 QCOMPARE(o.actuals().count(), 1);
2013 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2016 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2017 QCOMPARE(o.error(), false);
2018 QCOMPARE(o.invoked(), 12);
2019 QCOMPARE(o.actuals().count(), 1);
2020 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2023 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2024 QCOMPARE(o.error(), false);
2025 QCOMPARE(o.invoked(), 13);
2026 QCOMPARE(o.actuals().count(), 1);
2027 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2030 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2031 QCOMPARE(o.error(), false);
2032 QCOMPARE(o.invoked(), 13);
2033 QCOMPARE(o.actuals().count(), 1);
2034 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2037 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2038 QCOMPARE(o.error(), false);
2039 QCOMPARE(o.invoked(), 13);
2040 QCOMPARE(o.actuals().count(), 1);
2041 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2044 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2045 QCOMPARE(o.error(), false);
2046 QCOMPARE(o.invoked(), 13);
2047 QCOMPARE(o.actuals().count(), 1);
2048 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2051 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2052 QCOMPARE(o.error(), false);
2053 QCOMPARE(o.invoked(), 13);
2054 QCOMPARE(o.actuals().count(), 1);
2055 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2058 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2059 QCOMPARE(o.error(), false);
2060 QCOMPARE(o.invoked(), 14);
2061 QCOMPARE(o.actuals().count(), 1);
2062 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2065 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2066 QCOMPARE(o.error(), false);
2067 QCOMPARE(o.invoked(), 14);
2068 QCOMPARE(o.actuals().count(), 1);
2069 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2072 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2073 QCOMPARE(o.error(), false);
2074 QCOMPARE(o.invoked(), 14);
2075 QCOMPARE(o.actuals().count(), 1);
2076 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2079 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2080 QCOMPARE(o.error(), false);
2081 QCOMPARE(o.invoked(), 14);
2082 QCOMPARE(o.actuals().count(), 1);
2083 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2086 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2087 QCOMPARE(o.error(), false);
2088 QCOMPARE(o.invoked(), 15);
2089 QCOMPARE(o.actuals().count(), 2);
2090 QCOMPARE(o.actuals().at(0), QVariant(4));
2091 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2094 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2095 QCOMPARE(o.error(), false);
2096 QCOMPARE(o.invoked(), 15);
2097 QCOMPARE(o.actuals().count(), 2);
2098 QCOMPARE(o.actuals().at(0), QVariant(8));
2099 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2102 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2103 QCOMPARE(o.error(), false);
2104 QCOMPARE(o.invoked(), 15);
2105 QCOMPARE(o.actuals().count(), 2);
2106 QCOMPARE(o.actuals().at(0), QVariant(3));
2107 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2110 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2111 QCOMPARE(o.error(), false);
2112 QCOMPARE(o.invoked(), 15);
2113 QCOMPARE(o.actuals().count(), 2);
2114 QCOMPARE(o.actuals().at(0), QVariant(44));
2115 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2118 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2119 QCOMPARE(o.error(), false);
2120 QCOMPARE(o.invoked(), -1);
2121 QCOMPARE(o.actuals().count(), 0);
2124 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2125 QCOMPARE(o.error(), false);
2126 QCOMPARE(o.invoked(), 16);
2127 QCOMPARE(o.actuals().count(), 1);
2128 QCOMPARE(o.actuals().at(0), QVariant(10));
2131 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2132 QCOMPARE(o.error(), false);
2133 QCOMPARE(o.invoked(), 17);
2134 QCOMPARE(o.actuals().count(), 2);
2135 QCOMPARE(o.actuals().at(0), QVariant(10));
2136 QCOMPARE(o.actuals().at(1), QVariant(11));
2139 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2140 QCOMPARE(o.error(), false);
2141 QCOMPARE(o.invoked(), 18);
2142 QCOMPARE(o.actuals().count(), 1);
2143 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2146 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2147 QCOMPARE(o.error(), false);
2148 QCOMPARE(o.invoked(), 19);
2149 QCOMPARE(o.actuals().count(), 1);
2150 QCOMPARE(o.actuals().at(0), QVariant(9));
2153 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2154 QCOMPARE(o.error(), false);
2155 QCOMPARE(o.invoked(), 20);
2156 QCOMPARE(o.actuals().count(), 2);
2157 QCOMPARE(o.actuals().at(0), QVariant(10));
2158 QCOMPARE(o.actuals().at(1), QVariant(19));
2161 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2162 QCOMPARE(o.error(), false);
2163 QCOMPARE(o.invoked(), 20);
2164 QCOMPARE(o.actuals().count(), 2);
2165 QCOMPARE(o.actuals().at(0), QVariant(10));
2166 QCOMPARE(o.actuals().at(1), QVariant(13));
2169 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2170 QCOMPARE(o.error(), false);
2171 QCOMPARE(o.invoked(), -3);
2172 QCOMPARE(o.actuals().count(), 1);
2173 QCOMPARE(o.actuals().at(0), QVariant(9));
2176 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2177 QCOMPARE(o.error(), false);
2178 QCOMPARE(o.invoked(), 21);
2179 QCOMPARE(o.actuals().count(), 2);
2180 QCOMPARE(o.actuals().at(0), QVariant(9));
2181 QCOMPARE(o.actuals().at(1), QVariant());
2184 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2185 QCOMPARE(o.error(), false);
2186 QCOMPARE(o.invoked(), 21);
2187 QCOMPARE(o.actuals().count(), 2);
2188 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2189 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2192 // QTBUG-13047 (check that you can pass registered object types as args)
2193 void tst_qdeclarativeecmascript::invokableObjectArg()
2195 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2197 QObject *o = component.create();
2199 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2201 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2206 // QTBUG-13047 (check that you can return registered object types from methods)
2207 void tst_qdeclarativeecmascript::invokableObjectRet()
2209 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2211 QObject *o = component.create();
2213 QCOMPARE(o->property("test").toBool(), true);
2218 void tst_qdeclarativeecmascript::listToVariant()
2220 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2222 MyQmlContainer container;
2224 QDeclarativeContext context(engine.rootContext());
2225 context.setContextObject(&container);
2227 QObject *object = component.create(&context);
2228 QVERIFY(object != 0);
2230 QVariant v = object->property("test");
2231 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2232 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2238 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2239 void tst_qdeclarativeecmascript::listAssignment()
2241 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2242 QObject *obj = component.create();
2243 QCOMPARE(obj->property("list1length").toInt(), 2);
2244 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2245 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2246 QCOMPARE(list1.count(&list1), list2.count(&list2));
2247 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2248 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2253 void tst_qdeclarativeecmascript::multiEngineObject()
2256 obj.setStringProperty("Howdy planet");
2258 QDeclarativeEngine e1;
2259 e1.rootContext()->setContextProperty("thing", &obj);
2260 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2262 QDeclarativeEngine e2;
2263 e2.rootContext()->setContextProperty("thing", &obj);
2264 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2266 QObject *o1 = c1.create();
2267 QObject *o2 = c2.create();
2269 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2270 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2276 // Test that references to QObjects are cleanup when the object is destroyed
2277 void tst_qdeclarativeecmascript::deletedObject()
2279 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2281 QObject *object = component.create();
2283 QCOMPARE(object->property("test1").toBool(), true);
2284 QCOMPARE(object->property("test2").toBool(), true);
2285 QCOMPARE(object->property("test3").toBool(), true);
2286 QCOMPARE(object->property("test4").toBool(), true);
2291 void tst_qdeclarativeecmascript::attachedPropertyScope()
2293 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2295 QObject *object = component.create();
2296 QVERIFY(object != 0);
2298 MyQmlAttachedObject *attached =
2299 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2300 QVERIFY(attached != 0);
2302 QCOMPARE(object->property("value2").toInt(), 0);
2304 attached->emitMySignal();
2306 QCOMPARE(object->property("value2").toInt(), 9);
2311 void tst_qdeclarativeecmascript::scriptConnect()
2314 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2316 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2317 QVERIFY(object != 0);
2319 QCOMPARE(object->property("test").toBool(), false);
2320 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2321 QCOMPARE(object->property("test").toBool(), true);
2327 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2329 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2330 QVERIFY(object != 0);
2332 QCOMPARE(object->property("test").toBool(), false);
2333 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2334 QCOMPARE(object->property("test").toBool(), true);
2340 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2342 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2343 QVERIFY(object != 0);
2345 QCOMPARE(object->property("test").toBool(), false);
2346 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2347 QCOMPARE(object->property("test").toBool(), true);
2353 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2355 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2356 QVERIFY(object != 0);
2358 QCOMPARE(object->methodCalled(), false);
2359 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2360 QCOMPARE(object->methodCalled(), true);
2366 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2368 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2369 QVERIFY(object != 0);
2371 QCOMPARE(object->methodCalled(), false);
2372 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2373 QCOMPARE(object->methodCalled(), true);
2379 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2381 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2382 QVERIFY(object != 0);
2384 QCOMPARE(object->property("test").toInt(), 0);
2385 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2386 QCOMPARE(object->property("test").toInt(), 2);
2392 void tst_qdeclarativeecmascript::scriptDisconnect()
2395 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2397 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2398 QVERIFY(object != 0);
2400 QCOMPARE(object->property("test").toInt(), 0);
2401 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2402 QCOMPARE(object->property("test").toInt(), 1);
2403 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2404 QCOMPARE(object->property("test").toInt(), 2);
2405 emit object->basicSignal();
2406 QCOMPARE(object->property("test").toInt(), 2);
2407 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2408 QCOMPARE(object->property("test").toInt(), 2);
2414 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2416 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2417 QVERIFY(object != 0);
2419 QCOMPARE(object->property("test").toInt(), 0);
2420 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2421 QCOMPARE(object->property("test").toInt(), 1);
2422 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2423 QCOMPARE(object->property("test").toInt(), 2);
2424 emit object->basicSignal();
2425 QCOMPARE(object->property("test").toInt(), 2);
2426 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2427 QCOMPARE(object->property("test").toInt(), 2);
2433 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2435 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2436 QVERIFY(object != 0);
2438 QCOMPARE(object->property("test").toInt(), 0);
2439 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2440 QCOMPARE(object->property("test").toInt(), 1);
2441 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2442 QCOMPARE(object->property("test").toInt(), 2);
2443 emit object->basicSignal();
2444 QCOMPARE(object->property("test").toInt(), 2);
2445 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2446 QCOMPARE(object->property("test").toInt(), 3);
2451 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2453 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2454 QVERIFY(object != 0);
2456 QCOMPARE(object->property("test").toInt(), 0);
2457 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2458 QCOMPARE(object->property("test").toInt(), 1);
2459 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2460 QCOMPARE(object->property("test").toInt(), 2);
2461 emit object->basicSignal();
2462 QCOMPARE(object->property("test").toInt(), 2);
2463 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2464 QCOMPARE(object->property("test").toInt(), 3);
2470 class OwnershipObject : public QObject
2474 OwnershipObject() { object = new QObject; }
2476 QPointer<QObject> object;
2479 QObject *getObject() { return object; }
2482 void tst_qdeclarativeecmascript::ownership()
2484 OwnershipObject own;
2485 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2486 context->setContextObject(&own);
2489 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2491 QVERIFY(own.object != 0);
2493 QObject *object = component.create(context);
2495 engine.collectGarbage();
2497 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2499 QVERIFY(own.object == 0);
2504 own.object = new QObject(&own);
2507 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2509 QVERIFY(own.object != 0);
2511 QObject *object = component.create(context);
2513 engine.collectGarbage();
2515 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2517 QVERIFY(own.object != 0);
2525 class CppOwnershipReturnValue : public QObject
2529 CppOwnershipReturnValue() : value(0) {}
2530 ~CppOwnershipReturnValue() { delete value; }
2532 Q_INVOKABLE QObject *create() {
2533 value = new QObject;
2534 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2538 Q_INVOKABLE MyQmlObject *createQmlObject() {
2539 MyQmlObject *rv = new MyQmlObject;
2544 QPointer<QObject> value;
2548 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2549 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2551 CppOwnershipReturnValue source;
2554 QDeclarativeEngine engine;
2555 engine.rootContext()->setContextProperty("source", &source);
2557 QVERIFY(source.value == 0);
2559 QDeclarativeComponent component(&engine);
2560 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2562 QObject *object = component.create();
2564 QVERIFY(object != 0);
2565 QVERIFY(source.value != 0);
2570 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2572 QVERIFY(source.value != 0);
2576 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2578 CppOwnershipReturnValue source;
2581 QDeclarativeEngine engine;
2582 engine.rootContext()->setContextProperty("source", &source);
2584 QVERIFY(source.value == 0);
2586 QDeclarativeComponent component(&engine);
2587 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2589 QObject *object = component.create();
2591 QVERIFY(object != 0);
2592 QVERIFY(source.value != 0);
2597 engine.collectGarbage();
2598 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2600 QVERIFY(source.value == 0);
2603 class QListQObjectMethodsObject : public QObject
2607 QListQObjectMethodsObject() {
2608 m_objects.append(new MyQmlObject());
2609 m_objects.append(new MyQmlObject());
2612 ~QListQObjectMethodsObject() {
2613 qDeleteAll(m_objects);
2617 QList<QObject *> getObjects() { return m_objects; }
2620 QList<QObject *> m_objects;
2623 // Tests that returning a QList<QObject*> from a method works
2624 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2626 QListQObjectMethodsObject obj;
2627 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2628 context->setContextObject(&obj);
2630 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2632 QObject *object = component.create(context);
2634 QCOMPARE(object->property("test").toInt(), 2);
2635 QCOMPARE(object->property("test2").toBool(), true);
2642 void tst_qdeclarativeecmascript::strictlyEquals()
2644 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2646 QObject *object = component.create();
2647 QVERIFY(object != 0);
2649 QCOMPARE(object->property("test1").toBool(), true);
2650 QCOMPARE(object->property("test2").toBool(), true);
2651 QCOMPARE(object->property("test3").toBool(), true);
2652 QCOMPARE(object->property("test4").toBool(), true);
2653 QCOMPARE(object->property("test5").toBool(), true);
2654 QCOMPARE(object->property("test6").toBool(), true);
2655 QCOMPARE(object->property("test7").toBool(), true);
2656 QCOMPARE(object->property("test8").toBool(), true);
2661 void tst_qdeclarativeecmascript::compiled()
2663 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2665 QObject *object = component.create();
2666 QVERIFY(object != 0);
2668 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2669 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2670 QCOMPARE(object->property("test3").toBool(), true);
2671 QCOMPARE(object->property("test4").toBool(), false);
2672 QCOMPARE(object->property("test5").toBool(), false);
2673 QCOMPARE(object->property("test6").toBool(), true);
2675 QCOMPARE(object->property("test7").toInt(), 185);
2676 QCOMPARE(object->property("test8").toInt(), 167);
2677 QCOMPARE(object->property("test9").toBool(), true);
2678 QCOMPARE(object->property("test10").toBool(), false);
2679 QCOMPARE(object->property("test11").toBool(), false);
2680 QCOMPARE(object->property("test12").toBool(), true);
2682 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2683 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2684 QCOMPARE(object->property("test15").toBool(), false);
2685 QCOMPARE(object->property("test16").toBool(), true);
2687 QCOMPARE(object->property("test17").toInt(), 5);
2688 QCOMPARE(object->property("test18").toReal(), qreal(176));
2689 QCOMPARE(object->property("test19").toInt(), 7);
2690 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2691 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2692 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2693 QCOMPARE(object->property("test23").toBool(), true);
2694 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2695 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2700 // Test that numbers assigned in bindings as strings work consistently
2701 void tst_qdeclarativeecmascript::numberAssignment()
2703 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2705 QObject *object = component.create();
2706 QVERIFY(object != 0);
2708 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2709 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2710 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2711 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2712 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2714 QCOMPARE(object->property("test5"), QVariant((int)7));
2715 QCOMPARE(object->property("test6"), QVariant((int)7));
2716 QCOMPARE(object->property("test7"), QVariant((int)6));
2717 QCOMPARE(object->property("test8"), QVariant((int)6));
2719 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2720 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2721 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2722 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2727 void tst_qdeclarativeecmascript::propertySplicing()
2729 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2731 QObject *object = component.create();
2732 QVERIFY(object != 0);
2734 QCOMPARE(object->property("test").toBool(), true);
2740 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2742 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2744 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2745 QVERIFY(object != 0);
2747 MyQmlObject::MyType type;
2748 type.value = 0x8971123;
2749 emit object->signalWithUnknownType(type);
2751 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2753 QCOMPARE(result.value, type.value);
2759 void tst_qdeclarativeecmascript::moduleApi_data()
2761 QTest::addColumn<QUrl>("testfile");
2762 QTest::addColumn<QString>("errorMessage");
2763 QTest::addColumn<QStringList>("warningMessages");
2764 QTest::addColumn<QStringList>("readProperties");
2765 QTest::addColumn<QVariantList>("readExpectedValues");
2766 QTest::addColumn<QStringList>("writeProperties");
2767 QTest::addColumn<QVariantList>("writeValues");
2768 QTest::addColumn<QStringList>("readBackProperties");
2769 QTest::addColumn<QVariantList>("readBackExpectedValues");
2771 QTest::newRow("qobject, register + read + method")
2772 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2775 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2776 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2777 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2783 QTest::newRow("script, register + read")
2784 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2787 << (QStringList() << "scriptTest")
2788 << (QVariantList() << 13)
2794 QTest::newRow("qobject, caching + read")
2795 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2798 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2799 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2805 QTest::newRow("script, caching + read")
2806 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2809 << (QStringList() << "scriptTest")
2810 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2816 QTest::newRow("qobject, writing + readonly constraints")
2817 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2819 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2820 << (QStringList() << "readOnlyProperty" << "writableProperty")
2821 << (QVariantList() << 20 << 50)
2822 << (QStringList() << "firstProperty" << "writableProperty")
2823 << (QVariantList() << 30 << 30)
2824 << (QStringList() << "readOnlyProperty" << "writableProperty")
2825 << (QVariantList() << 20 << 30);
2827 QTest::newRow("script, writing + readonly constraints")
2828 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
2830 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
2831 << (QStringList() << "readBack" << "unchanged")
2832 << (QVariantList() << 13 << 42)
2833 << (QStringList() << "firstProperty" << "secondProperty")
2834 << (QVariantList() << 30 << 30)
2835 << (QStringList() << "readBack" << "unchanged")
2836 << (QVariantList() << 30 << 42);
2838 QTest::newRow("qobject module API enum values in JS")
2839 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
2842 << (QStringList() << "enumValue" << "enumMethod")
2843 << (QVariantList() << 42 << 30)
2849 QTest::newRow("qobject, invalid major version fail")
2850 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
2851 << QString("QDeclarativeComponent: Component is not ready")
2860 QTest::newRow("qobject, invalid minor version fail")
2861 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
2862 << QString("QDeclarativeComponent: Component is not ready")
2872 void tst_qdeclarativeecmascript::moduleApi()
2874 QFETCH(QUrl, testfile);
2875 QFETCH(QString, errorMessage);
2876 QFETCH(QStringList, warningMessages);
2877 QFETCH(QStringList, readProperties);
2878 QFETCH(QVariantList, readExpectedValues);
2879 QFETCH(QStringList, writeProperties);
2880 QFETCH(QVariantList, writeValues);
2881 QFETCH(QStringList, readBackProperties);
2882 QFETCH(QVariantList, readBackExpectedValues);
2884 QDeclarativeComponent component(&engine, testfile);
2886 if (!errorMessage.isEmpty())
2887 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
2889 if (warningMessages.size())
2890 foreach (const QString &warning, warningMessages)
2891 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
2893 QObject *object = component.create();
2894 if (!errorMessage.isEmpty()) {
2895 QVERIFY(object == 0);
2897 QVERIFY(object != 0);
2898 for (int i = 0; i < readProperties.size(); ++i)
2899 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
2900 for (int i = 0; i < writeProperties.size(); ++i)
2901 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
2902 for (int i = 0; i < readBackProperties.size(); ++i)
2903 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
2908 void tst_qdeclarativeecmascript::importScripts()
2910 QObject *object = 0;
2912 // first, ensure that the required behaviour works.
2913 QDeclarativeComponent component(&engine, TEST_FILE("jsimport/testImport.qml"));
2914 object = component.create();
2915 QVERIFY(object != 0);
2916 QCOMPARE(object->property("importedScriptStringValue"), QVariant(QString(QLatin1String("Hello, World!"))));
2917 QCOMPARE(object->property("importedScriptFunctionValue"), QVariant(20));
2918 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(19));
2919 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(2));
2922 QDeclarativeComponent componentTwo(&engine, TEST_FILE("jsimport/testImportScoping.qml"));
2923 object = componentTwo.create();
2924 QVERIFY(object != 0);
2925 QCOMPARE(object->property("componentError"), QVariant(5));
2928 // then, ensure that unintended behaviour does not work.
2929 QDeclarativeComponent failOneComponent(&engine, TEST_FILE("jsimportfail/failOne.qml"));
2930 QString expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined");
2931 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2932 object = failOneComponent.create();
2933 QVERIFY(object != 0);
2934 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2936 QDeclarativeComponent failTwoComponent(&engine, TEST_FILE("jsimportfail/failTwo.qml"));
2937 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs");
2938 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2939 object = failTwoComponent.create();
2940 QVERIFY(object != 0);
2941 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2943 QDeclarativeComponent failThreeComponent(&engine, TEST_FILE("jsimportfail/failThree.qml"));
2944 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined");
2945 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2946 object = failThreeComponent.create();
2947 QVERIFY(object != 0);
2948 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(false));
2950 QDeclarativeComponent failFourComponent(&engine, TEST_FILE("jsimportfail/failFour.qml"));
2951 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest");
2952 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2953 object = failFourComponent.create();
2954 QVERIFY(object != 0);
2955 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(0));
2957 QDeclarativeComponent failFiveComponent(&engine, TEST_FILE("jsimportfail/failFive.qml"));
2958 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component");
2959 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2960 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component");
2961 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2962 object = failFiveComponent.create();
2963 QVERIFY(object != 0);
2964 QCOMPARE(object->property("componentError"), QVariant(0));
2967 // also, test that importing scripts with .pragma library works as required
2968 QDeclarativeComponent pragmaLibraryComponent(&engine, TEST_FILE("jsimport/testImportPragmaLibrary.qml"));
2969 object = pragmaLibraryComponent.create();
2970 QVERIFY(object != 0);
2971 QCOMPARE(object->property("testValue"), QVariant(31));
2974 // and that .pragma library scripts don't inherit imports from any .qml file
2975 QDeclarativeComponent pragmaLibraryComponentTwo(&engine, TEST_FILE("jsimportfail/testImportPragmaLibrary.qml"));
2976 object = pragmaLibraryComponentTwo.create();
2977 QVERIFY(object != 0);
2978 QCOMPARE(object->property("testValue"), QVariant(0));
2982 void tst_qdeclarativeecmascript::scarceResources()
2984 QPixmap origPixmap(100, 100);
2985 origPixmap.fill(Qt::blue);
2987 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
2988 ScarceResourceObject *eo = 0;
2989 QObject *object = 0;
2991 // in the following three cases, the instance created from the component
2992 // has a property which is a copy of the scarce resource; hence, the
2993 // resource should NOT be detached prior to deletion of the object instance,
2994 // unless the resource is destroyed explicitly.
2995 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
2996 object = component.create();
2997 QVERIFY(object != 0);
2998 QVERIFY(object->property("scarceResourceCopy").isValid());
2999 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3000 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3001 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3002 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3005 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3006 object = componentTwo.create();
3007 QVERIFY(object != 0);
3008 QVERIFY(object->property("scarceResourceCopy").isValid());
3009 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3010 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3011 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3012 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3015 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3016 object = componentThree.create();
3017 QVERIFY(object != 0);
3018 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3019 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3020 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3021 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3024 // in the following three cases, no other copy should exist in memory,
3025 // and so it should be detached (unless explicitly preserved).
3026 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3027 object = componentFour.create();
3028 QVERIFY(object != 0);
3029 QVERIFY(object->property("scarceResourceTest").isValid());
3030 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3031 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3032 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3033 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3036 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3037 object = componentFive.create();
3038 QVERIFY(object != 0);
3039 QVERIFY(object->property("scarceResourceTest").isValid());
3040 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3041 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3042 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3043 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3046 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3047 object = componentSix.create();
3048 QVERIFY(object != 0);
3049 QVERIFY(object->property("scarceResourceTest").isValid());
3050 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3051 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3052 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3053 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3056 // test that scarce resources are handled correctly for imports
3057 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3058 object = componentSeven.create();
3059 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3060 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3063 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3064 object = componentEight.create();
3065 QVERIFY(object != 0);
3066 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3067 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3070 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3071 object = componentNine.create();
3072 QVERIFY(object != 0);
3073 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3074 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3075 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3076 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3077 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3078 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3081 // test that scarce resources are handled properly in signal invocation
3082 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3083 object = componentTen.create();
3084 QVERIFY(object != 0);
3085 QObject *srsc = object->findChild<QObject*>("srsc");
3087 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3088 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3089 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3090 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3091 QMetaObject::invokeMethod(srsc, "testSignal");
3092 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3093 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3094 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3095 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3096 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3097 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3098 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3099 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3100 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3101 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3104 // test that scarce resources are handled properly from js functions in qml files
3105 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3106 object = componentEleven.create();
3107 QVERIFY(object != 0);
3108 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3109 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3110 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3111 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3112 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3113 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3114 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3115 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3116 QMetaObject::invokeMethod(object, "releaseScarceResource");
3117 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3118 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3119 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3120 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3123 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3124 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3125 object = componentTwelve.create();
3126 QVERIFY(object != 0);
3127 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3128 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3129 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3130 QString srp_name = object->property("srp_name").toString();
3131 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3132 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3133 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3134 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3135 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3136 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3137 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3141 void tst_qdeclarativeecmascript::propertyChangeSlots()
3143 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3144 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3145 QObject *object = component.create();
3146 QVERIFY(object != 0);
3149 // ensure that invalid property names fail properly.
3150 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3151 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3152 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3153 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3154 object = e1.create();
3155 QVERIFY(object == 0);
3158 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3159 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3160 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3161 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3162 object = e2.create();
3163 QVERIFY(object == 0);
3166 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3167 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3168 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3169 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3170 object = e3.create();
3171 QVERIFY(object == 0);
3174 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3175 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3176 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3177 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3178 object = e4.create();
3179 QVERIFY(object == 0);
3183 // Ensure that QObject type conversion works on binding assignment
3184 void tst_qdeclarativeecmascript::elementAssign()
3186 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3188 QObject *object = component.create();
3189 QVERIFY(object != 0);
3191 QCOMPARE(object->property("test").toBool(), true);
3197 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3199 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3201 QObject *object = component.create();
3202 QVERIFY(object != 0);
3204 QCOMPARE(object->property("test").toBool(), true);
3210 void tst_qdeclarativeecmascript::booleanConversion()
3212 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3214 QObject *object = component.create();
3215 QVERIFY(object != 0);
3217 QCOMPARE(object->property("test_true1").toBool(), true);
3218 QCOMPARE(object->property("test_true2").toBool(), true);
3219 QCOMPARE(object->property("test_true3").toBool(), true);
3220 QCOMPARE(object->property("test_true4").toBool(), true);
3221 QCOMPARE(object->property("test_true5").toBool(), true);
3223 QCOMPARE(object->property("test_false1").toBool(), false);
3224 QCOMPARE(object->property("test_false2").toBool(), false);
3225 QCOMPARE(object->property("test_false3").toBool(), false);
3230 void tst_qdeclarativeecmascript::handleReferenceManagement()
3235 // Linear QObject reference
3236 QDeclarativeEngine hrmEngine;
3237 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3238 QObject *object = component.create();
3239 QVERIFY(object != 0);
3240 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3241 cro->setDtorCount(&dtorCount);
3242 QMetaObject::invokeMethod(object, "createReference");
3243 QMetaObject::invokeMethod(object, "performGc");
3244 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3245 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3247 hrmEngine.collectGarbage();
3248 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3249 QCOMPARE(dtorCount, 3);
3254 // Circular QObject reference
3255 QDeclarativeEngine hrmEngine;
3256 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3257 QObject *object = component.create();
3258 QVERIFY(object != 0);
3259 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3260 cro->setDtorCount(&dtorCount);
3261 QMetaObject::invokeMethod(object, "circularReference");
3262 QMetaObject::invokeMethod(object, "performGc");
3263 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3264 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3266 hrmEngine.collectGarbage();
3267 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3268 QCOMPARE(dtorCount, 3);
3273 // Linear handle reference
3274 QDeclarativeEngine hrmEngine;
3275 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3276 QObject *object = component.create();
3277 QVERIFY(object != 0);
3278 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3280 crh->setDtorCount(&dtorCount);
3281 QMetaObject::invokeMethod(object, "createReference");
3282 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3283 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3284 QVERIFY(first != 0);
3285 QVERIFY(second != 0);
3286 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3287 // now we have to reparent second and make second owned by JS.
3288 second->setParent(0);
3289 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3290 QMetaObject::invokeMethod(object, "performGc");
3291 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3292 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3294 hrmEngine.collectGarbage();
3295 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3296 QCOMPARE(dtorCount, 3);
3301 // Circular handle reference
3302 QDeclarativeEngine hrmEngine;
3303 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3304 QObject *object = component.create();
3305 QVERIFY(object != 0);
3306 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3308 crh->setDtorCount(&dtorCount);
3309 QMetaObject::invokeMethod(object, "circularReference");
3310 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3311 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3312 QVERIFY(first != 0);
3313 QVERIFY(second != 0);
3314 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3315 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3316 // now we have to reparent and change ownership.
3317 first->setParent(0);
3318 second->setParent(0);
3319 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3320 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3321 QMetaObject::invokeMethod(object, "performGc");
3322 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3323 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3325 hrmEngine.collectGarbage();
3326 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3327 QCOMPARE(dtorCount, 3);
3332 // multiple engine interaction - linear reference
3333 QDeclarativeEngine hrmEngine1;
3334 QDeclarativeEngine hrmEngine2;
3335 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3336 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3337 QObject *object1 = component1.create();
3338 QObject *object2 = component2.create();
3339 QVERIFY(object1 != 0);
3340 QVERIFY(object2 != 0);
3341 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3342 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3345 crh1->setDtorCount(&dtorCount);
3346 crh2->setDtorCount(&dtorCount);
3347 QMetaObject::invokeMethod(object1, "createReference");
3348 QMetaObject::invokeMethod(object2, "createReference");
3349 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3350 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3351 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3352 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3353 QVERIFY(first1 != 0);
3354 QVERIFY(second1 != 0);
3355 QVERIFY(first2 != 0);
3356 QVERIFY(second2 != 0);
3357 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3358 // now we have to reparent second2 and make second2 owned by JS.
3359 second2->setParent(0);
3360 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3361 QMetaObject::invokeMethod(object1, "performGc");
3362 QMetaObject::invokeMethod(object2, "performGc");
3363 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3364 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3367 hrmEngine1.collectGarbage();
3368 hrmEngine2.collectGarbage();
3369 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3370 QCOMPARE(dtorCount, 6);
3375 // multiple engine interaction - circular reference
3376 QDeclarativeEngine hrmEngine1;
3377 QDeclarativeEngine hrmEngine2;
3378 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3379 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3380 QObject *object1 = component1.create();
3381 QObject *object2 = component2.create();
3382 QVERIFY(object1 != 0);
3383 QVERIFY(object2 != 0);
3384 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3385 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3388 crh1->setDtorCount(&dtorCount);
3389 crh2->setDtorCount(&dtorCount);
3390 QMetaObject::invokeMethod(object1, "createReference");
3391 QMetaObject::invokeMethod(object2, "createReference");
3392 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3393 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3394 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3395 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3396 QVERIFY(first1 != 0);
3397 QVERIFY(second1 != 0);
3398 QVERIFY(first2 != 0);
3399 QVERIFY(second2 != 0);
3400 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3401 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3402 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3403 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3404 // now we have to reparent and change ownership to JS.
3405 first1->setParent(0);
3406 second1->setParent(0);
3407 first2->setParent(0);
3408 second2->setParent(0);
3409 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
3410 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3411 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3412 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3413 QMetaObject::invokeMethod(object1, "performGc");
3414 QMetaObject::invokeMethod(object2, "performGc");
3415 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3416 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
3419 hrmEngine1.collectGarbage();
3420 hrmEngine2.collectGarbage();
3421 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3422 QCOMPARE(dtorCount, 6);
3427 // multiple engine interaction - linear reference with engine deletion
3428 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
3429 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
3430 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3431 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3432 QObject *object1 = component1.create();
3433 QObject *object2 = component2.create();
3434 QVERIFY(object1 != 0);
3435 QVERIFY(object2 != 0);
3436 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3437 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3440 crh1->setDtorCount(&dtorCount);
3441 crh2->setDtorCount(&dtorCount);
3442 QMetaObject::invokeMethod(object1, "createReference");
3443 QMetaObject::invokeMethod(object2, "createReference");
3444 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3445 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3446 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3447 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3448 QVERIFY(first1 != 0);
3449 QVERIFY(second1 != 0);
3450 QVERIFY(first2 != 0);
3451 QVERIFY(second2 != 0);
3452 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3453 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3454 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3455 // now we have to reparent and change ownership to JS.
3456 first1->setParent(crh1);
3457 second1->setParent(0);
3458 first2->setParent(0);
3459 second2->setParent(0);
3460 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3461 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3462 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3463 QMetaObject::invokeMethod(object1, "performGc");
3464 QMetaObject::invokeMethod(object2, "performGc");
3465 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3466 QCOMPARE(dtorCount, 0);
3468 QMetaObject::invokeMethod(object1, "performGc");
3469 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3470 QCOMPARE(dtorCount, 0);
3473 hrmEngine1->collectGarbage();
3474 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3475 QCOMPARE(dtorCount, 6);
3480 // Test that assigning a null object works
3481 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
3482 void tst_qdeclarativeecmascript::nullObjectBinding()
3484 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
3486 QObject *object = component.create();
3487 QVERIFY(object != 0);
3489 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
3494 // Test that bindings don't evaluate once the engine has been destroyed
3495 void tst_qdeclarativeecmascript::deletedEngine()
3497 QDeclarativeEngine *engine = new QDeclarativeEngine;
3498 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
3500 QObject *object = component.create();
3501 QVERIFY(object != 0);
3503 QCOMPARE(object->property("a").toInt(), 39);
3504 object->setProperty("b", QVariant(9));
3505 QCOMPARE(object->property("a").toInt(), 117);
3509 QCOMPARE(object->property("a").toInt(), 117);
3510 object->setProperty("b", QVariant(10));
3511 QCOMPARE(object->property("a").toInt(), 117);
3516 // Test the crashing part of QTBUG-9705
3517 void tst_qdeclarativeecmascript::libraryScriptAssert()
3519 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
3521 QObject *object = component.create();
3522 QVERIFY(object != 0);
3527 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
3529 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
3531 QObject *object = component.create();
3532 QVERIFY(object != 0);
3534 QCOMPARE(object->property("test1").toInt(), 10);
3535 QCOMPARE(object->property("test2").toInt(), 11);
3537 object->setProperty("runTest", true);
3539 QCOMPARE(object->property("test1"), QVariant());
3540 QCOMPARE(object->property("test2"), QVariant());
3546 void tst_qdeclarativeecmascript::qtbug_9792()
3548 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
3550 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
3552 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
3553 QVERIFY(object != 0);
3555 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
3556 object->basicSignal();
3560 transientErrorsMsgCount = 0;
3561 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3563 object->basicSignal();
3565 qInstallMsgHandler(old);
3567 QCOMPARE(transientErrorsMsgCount, 0);
3572 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
3573 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
3575 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
3577 QObject *o = component.create();
3580 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
3581 QVERIFY(nested != 0);
3583 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
3586 nested = qvariant_cast<QObject *>(o->property("object"));
3587 QVERIFY(nested == 0);
3589 // If the bug is present, the next line will crash
3593 // Test that we shut down without stupid warnings
3594 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
3597 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
3599 QObject *o = component.create();
3601 transientErrorsMsgCount = 0;
3602 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3606 qInstallMsgHandler(old);
3608 QCOMPARE(transientErrorsMsgCount, 0);
3613 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
3615 QObject *o = component.create();
3617 transientErrorsMsgCount = 0;
3618 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3622 qInstallMsgHandler(old);
3624 QCOMPARE(transientErrorsMsgCount, 0);
3628 void tst_qdeclarativeecmascript::canAssignNullToQObject()
3631 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
3633 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3636 QVERIFY(o->objectProperty() != 0);
3638 o->setProperty("runTest", true);
3640 QVERIFY(o->objectProperty() == 0);
3646 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
3648 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3651 QVERIFY(o->objectProperty() == 0);
3657 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
3659 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
3661 QString url = component.url().toString();
3662 QString warning = url + ":4: Unable to assign a function to a property.";
3663 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3665 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3668 QVERIFY(!o->property("a").isValid());
3673 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
3675 QFETCH(QString, triggerProperty);
3677 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3678 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3680 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3682 QVERIFY(!o->property("a").isValid());
3684 o->setProperty("aNumber", QVariant(5));
3685 o->setProperty(triggerProperty.toUtf8().constData(), true);
3686 QCOMPARE(o->property("a"), QVariant(50));
3688 o->setProperty("aNumber", QVariant(10));
3689 QCOMPARE(o->property("a"), QVariant(100));
3694 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
3696 QTest::addColumn<QString>("triggerProperty");
3698 QTest::newRow("assign to property") << "assignToProperty";
3699 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
3701 QTest::newRow("assign to value type") << "assignToValueType";
3703 QTest::newRow("use 'this'") << "assignWithThis";
3704 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
3707 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
3709 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3710 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3712 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3714 QVERIFY(!o->property("a").isValid());
3716 o->setProperty("assignFuncWithoutReturn", true);
3717 QVERIFY(!o->property("a").isValid());
3719 QString url = component.url().toString();
3720 QString warning = url + ":67: Unable to assign QString to int";
3721 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3722 o->setProperty("assignWrongType", true);
3724 warning = url + ":71: Unable to assign QString to int";
3725 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3726 o->setProperty("assignWrongTypeToValueType", true);
3731 void tst_qdeclarativeecmascript::eval()
3733 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
3735 QObject *o = component.create();
3738 QCOMPARE(o->property("test1").toBool(), true);
3739 QCOMPARE(o->property("test2").toBool(), true);
3740 QCOMPARE(o->property("test3").toBool(), true);
3741 QCOMPARE(o->property("test4").toBool(), true);
3742 QCOMPARE(o->property("test5").toBool(), true);
3747 void tst_qdeclarativeecmascript::function()
3749 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
3751 QObject *o = component.create();
3754 QCOMPARE(o->property("test1").toBool(), true);
3755 QCOMPARE(o->property("test2").toBool(), true);
3756 QCOMPARE(o->property("test3").toBool(), true);
3761 // Test the "Qt.include" method
3762 void tst_qdeclarativeecmascript::include()
3764 // Non-library relative include
3766 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
3767 QObject *o = component.create();
3770 QCOMPARE(o->property("test0").toInt(), 99);
3771 QCOMPARE(o->property("test1").toBool(), true);
3772 QCOMPARE(o->property("test2").toBool(), true);
3773 QCOMPARE(o->property("test2_1").toBool(), true);
3774 QCOMPARE(o->property("test3").toBool(), true);
3775 QCOMPARE(o->property("test3_1").toBool(), true);
3780 // Library relative include
3782 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
3783 QObject *o = component.create();
3786 QCOMPARE(o->property("test0").toInt(), 99);
3787 QCOMPARE(o->property("test1").toBool(), true);
3788 QCOMPARE(o->property("test2").toBool(), true);
3789 QCOMPARE(o->property("test2_1").toBool(), true);
3790 QCOMPARE(o->property("test3").toBool(), true);
3791 QCOMPARE(o->property("test3_1").toBool(), true);
3798 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
3799 QObject *o = component.create();
3802 QCOMPARE(o->property("test1").toBool(), true);
3803 QCOMPARE(o->property("test2").toBool(), true);
3804 QCOMPARE(o->property("test3").toBool(), true);
3805 QCOMPARE(o->property("test4").toBool(), true);
3806 QCOMPARE(o->property("test5").toBool(), true);
3807 QCOMPARE(o->property("test6").toBool(), true);
3812 // Including file with ".pragma library"
3814 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
3815 QObject *o = component.create();
3817 QCOMPARE(o->property("test1").toInt(), 100);
3824 TestHTTPServer server(8111);
3825 QVERIFY(server.isValid());
3826 server.serveDirectory(SRCDIR "/data");
3828 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
3829 QObject *o = component.create();
3832 QTRY_VERIFY(o->property("done").toBool() == true);
3833 QTRY_VERIFY(o->property("done2").toBool() == true);
3835 QCOMPARE(o->property("test1").toBool(), true);
3836 QCOMPARE(o->property("test2").toBool(), true);
3837 QCOMPARE(o->property("test3").toBool(), true);
3838 QCOMPARE(o->property("test4").toBool(), true);
3839 QCOMPARE(o->property("test5").toBool(), true);
3841 QCOMPARE(o->property("test6").toBool(), true);
3842 QCOMPARE(o->property("test7").toBool(), true);
3843 QCOMPARE(o->property("test8").toBool(), true);
3844 QCOMPARE(o->property("test9").toBool(), true);
3845 QCOMPARE(o->property("test10").toBool(), true);
3852 TestHTTPServer server(8111);
3853 QVERIFY(server.isValid());
3854 server.serveDirectory(SRCDIR "/data");
3856 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
3857 QObject *o = component.create();
3860 QTRY_VERIFY(o->property("done").toBool() == true);
3862 QCOMPARE(o->property("test1").toBool(), true);
3863 QCOMPARE(o->property("test2").toBool(), true);
3864 QCOMPARE(o->property("test3").toBool(), true);
3870 void tst_qdeclarativeecmascript::signalHandlers()
3872 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
3873 QObject *o = component.create();
3876 QVERIFY(o->property("count").toInt() == 0);
3877 QMetaObject::invokeMethod(o, "testSignalCall");
3878 QCOMPARE(o->property("count").toInt(), 1);
3880 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
3881 QCOMPARE(o->property("count").toInt(), 1);
3882 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
3884 QVERIFY(o->property("funcCount").toInt() == 0);
3885 QMetaObject::invokeMethod(o, "testSignalConnection");
3886 QCOMPARE(o->property("funcCount").toInt(), 1);
3888 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
3889 QCOMPARE(o->property("funcCount").toInt(), 2);
3891 QMetaObject::invokeMethod(o, "testSignalDefined");
3892 QCOMPARE(o->property("definedResult").toBool(), true);
3894 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
3895 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
3900 void tst_qdeclarativeecmascript::qtbug_10696()
3902 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
3903 QObject *o = component.create();
3908 void tst_qdeclarativeecmascript::qtbug_11606()
3910 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
3911 QObject *o = component.create();
3913 QCOMPARE(o->property("test").toBool(), true);
3917 void tst_qdeclarativeecmascript::qtbug_11600()
3919 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
3920 QObject *o = component.create();
3922 QCOMPARE(o->property("test").toBool(), true);
3926 // Reading and writing non-scriptable properties should fail
3927 void tst_qdeclarativeecmascript::nonscriptable()
3929 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
3930 QObject *o = component.create();
3932 QCOMPARE(o->property("readOk").toBool(), true);
3933 QCOMPARE(o->property("writeOk").toBool(), true);
3937 // deleteLater() should not be callable from QML
3938 void tst_qdeclarativeecmascript::deleteLater()
3940 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
3941 QObject *o = component.create();
3943 QCOMPARE(o->property("test").toBool(), true);
3947 void tst_qdeclarativeecmascript::in()
3949 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
3950 QObject *o = component.create();
3952 QCOMPARE(o->property("test1").toBool(), true);
3953 QCOMPARE(o->property("test2").toBool(), true);
3957 void tst_qdeclarativeecmascript::sharedAttachedObject()
3959 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
3960 QObject *o = component.create();
3962 QCOMPARE(o->property("test1").toBool(), true);
3963 QCOMPARE(o->property("test2").toBool(), true);
3968 void tst_qdeclarativeecmascript::objectName()
3970 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
3971 QObject *o = component.create();
3974 QCOMPARE(o->property("test1").toString(), QString("hello"));
3975 QCOMPARE(o->property("test2").toString(), QString("ell"));
3977 o->setObjectName("world");
3979 QCOMPARE(o->property("test1").toString(), QString("world"));
3980 QCOMPARE(o->property("test2").toString(), QString("orl"));
3985 void tst_qdeclarativeecmascript::writeRemovesBinding()
3987 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
3988 QObject *o = component.create();
3991 QCOMPARE(o->property("test").toBool(), true);
3996 // Test bindings assigned to alias properties actually assign to the alias' target
3997 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
3999 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4000 QObject *o = component.create();
4003 QCOMPARE(o->property("test").toBool(), true);
4008 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4009 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4012 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4013 QObject *o = component.create();
4016 QCOMPARE(o->property("test").toBool(), true);
4022 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4023 QObject *o = component.create();
4026 QCOMPARE(o->property("test").toBool(), true);
4032 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4033 QObject *o = component.create();
4036 QCOMPARE(o->property("test").toBool(), true);
4042 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4043 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4046 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4047 QObject *o = component.create();
4050 QCOMPARE(o->property("test").toBool(), true);
4056 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
4057 QObject *o = component.create();
4060 QCOMPARE(o->property("test").toBool(), true);
4066 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
4067 QObject *o = component.create();
4070 QCOMPARE(o->property("test").toBool(), true);
4076 // Allow an alais to a composite element
4078 void tst_qdeclarativeecmascript::aliasToCompositeElement()
4080 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
4082 QObject *object = component.create();
4083 QVERIFY(object != 0);
4088 void tst_qdeclarativeecmascript::revisionErrors()
4091 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
4092 QString url = component.url().toString();
4094 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4095 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
4096 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
4098 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4099 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4100 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4101 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4102 QVERIFY(object != 0);
4106 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
4107 QString url = component.url().toString();
4109 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
4110 // method2, prop2 from MyRevisionedClass not available
4111 // method4, prop4 from MyRevisionedSubclass not available
4112 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4113 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
4114 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
4115 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
4116 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
4118 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4119 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4120 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4121 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
4122 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
4123 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4124 QVERIFY(object != 0);
4128 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
4129 QString url = component.url().toString();
4131 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
4132 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
4133 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
4134 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
4135 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
4136 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4137 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4138 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4139 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4140 QVERIFY(object != 0);
4145 void tst_qdeclarativeecmascript::revision()
4148 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
4149 QString url = component.url().toString();
4151 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4152 QVERIFY(object != 0);
4156 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
4157 QString url = component.url().toString();
4159 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4160 QVERIFY(object != 0);
4164 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
4165 QString url = component.url().toString();
4167 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4168 QVERIFY(object != 0);
4171 // Test that non-root classes can resolve revisioned methods
4173 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
4175 QObject *object = component.create();
4176 QVERIFY(object != 0);
4177 QCOMPARE(object->property("test").toReal(), 11.);
4182 void tst_qdeclarativeecmascript::realToInt()
4184 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
4185 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
4186 QVERIFY(object != 0);
4188 QMetaObject::invokeMethod(object, "test1");
4189 QCOMPARE(object->value(), int(4));
4190 QMetaObject::invokeMethod(object, "test2");
4191 QCOMPARE(object->value(), int(8));
4193 void tst_qdeclarativeecmascript::dynamicString()
4195 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
4196 QObject *object = component.create();
4197 QVERIFY(object != 0);
4198 QCOMPARE(object->property("stringProperty").toString(),
4199 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
4202 QTEST_MAIN(tst_qdeclarativeecmascript)
4204 #include "tst_qdeclarativeecmascript.moc"