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 multiEngineObject();
135 void deletedObject();
136 void attachedPropertyScope();
137 void scriptConnect();
138 void scriptDisconnect();
140 void cppOwnershipReturnValue();
141 void ownershipCustomReturnValue();
142 void qlistqobjectMethods();
143 void strictlyEquals();
145 void numberAssignment();
146 void propertySplicing();
147 void signalWithUnknownTypes();
148 void moduleApi_data();
150 void importScripts();
151 void scarceResources();
152 void propertyChangeSlots();
153 void elementAssign();
154 void objectPassThroughSignals();
155 void booleanConversion();
156 void handleReferenceManagement();
160 void dynamicCreationCrash();
162 void nullObjectBinding();
163 void deletedEngine();
164 void libraryScriptAssert();
165 void variantsAssignedUndefined();
167 void qtcreatorbug_1289();
168 void noSpuriousWarningsAtShutdown();
169 void canAssignNullToQObject();
170 void functionAssignment_fromBinding();
171 void functionAssignment_fromJS();
172 void functionAssignment_fromJS_data();
173 void functionAssignmentfromJS_invalid();
179 void nonscriptable();
182 void sharedAttachedObject();
184 void writeRemovesBinding();
185 void aliasBindingsAssignCorrectly();
186 void aliasBindingsOverrideTarget();
187 void aliasWritesOverrideBindings();
188 void aliasToCompositeElement();
190 void dynamicString();
192 void signalHandlers();
194 void callQtInvokables();
195 void invokableObjectArg();
196 void invokableObjectRet();
198 void revisionErrors();
202 QDeclarativeEngine engine;
205 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
207 void tst_qdeclarativeecmascript::assignBasicTypes()
210 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
211 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
212 QVERIFY(object != 0);
213 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
214 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
215 QCOMPARE(object->stringProperty(), QString("Hello World!"));
216 QCOMPARE(object->uintProperty(), uint(10));
217 QCOMPARE(object->intProperty(), -19);
218 QCOMPARE((float)object->realProperty(), float(23.2));
219 QCOMPARE((float)object->doubleProperty(), float(-19.75));
220 QCOMPARE((float)object->floatProperty(), float(8.5));
221 QCOMPARE(object->colorProperty(), QColor("red"));
222 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
223 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
224 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
225 QCOMPARE(object->pointProperty(), QPoint(99,13));
226 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
227 QCOMPARE(object->sizeProperty(), QSize(99, 13));
228 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
229 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
230 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
231 QCOMPARE(object->boolProperty(), true);
232 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
233 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
234 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
238 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
239 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
240 QVERIFY(object != 0);
241 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
242 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
243 QCOMPARE(object->stringProperty(), QString("Hello World!"));
244 QCOMPARE(object->uintProperty(), uint(10));
245 QCOMPARE(object->intProperty(), -19);
246 QCOMPARE((float)object->realProperty(), float(23.2));
247 QCOMPARE((float)object->doubleProperty(), float(-19.75));
248 QCOMPARE((float)object->floatProperty(), float(8.5));
249 QCOMPARE(object->colorProperty(), QColor("red"));
250 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
251 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
252 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
253 QCOMPARE(object->pointProperty(), QPoint(99,13));
254 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
255 QCOMPARE(object->sizeProperty(), QSize(99, 13));
256 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
257 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
258 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
259 QCOMPARE(object->boolProperty(), true);
260 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
261 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
262 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
267 void tst_qdeclarativeecmascript::idShortcutInvalidates()
270 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
271 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
272 QVERIFY(object != 0);
273 QVERIFY(object->objectProperty() != 0);
274 delete object->objectProperty();
275 QVERIFY(object->objectProperty() == 0);
280 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
281 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
282 QVERIFY(object != 0);
283 QVERIFY(object->objectProperty() != 0);
284 delete object->objectProperty();
285 QVERIFY(object->objectProperty() == 0);
290 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
293 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
294 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
295 QVERIFY(object != 0);
296 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
300 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
301 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
302 QVERIFY(object != 0);
303 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
308 void tst_qdeclarativeecmascript::signalAssignment()
311 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
312 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
313 QVERIFY(object != 0);
314 QCOMPARE(object->string(), QString());
315 emit object->basicSignal();
316 QCOMPARE(object->string(), QString("pass"));
321 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
322 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
323 QVERIFY(object != 0);
324 QCOMPARE(object->string(), QString());
325 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
326 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
331 void tst_qdeclarativeecmascript::methods()
334 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
335 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
336 QVERIFY(object != 0);
337 QCOMPARE(object->methodCalled(), false);
338 QCOMPARE(object->methodIntCalled(), false);
339 emit object->basicSignal();
340 QCOMPARE(object->methodCalled(), true);
341 QCOMPARE(object->methodIntCalled(), false);
346 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
347 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
348 QVERIFY(object != 0);
349 QCOMPARE(object->methodCalled(), false);
350 QCOMPARE(object->methodIntCalled(), false);
351 emit object->basicSignal();
352 QCOMPARE(object->methodCalled(), false);
353 QCOMPARE(object->methodIntCalled(), true);
358 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
359 QObject *object = component.create();
360 QVERIFY(object != 0);
361 QCOMPARE(object->property("test").toInt(), 19);
366 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
367 QObject *object = component.create();
368 QVERIFY(object != 0);
369 QCOMPARE(object->property("test").toInt(), 19);
370 QCOMPARE(object->property("test2").toInt(), 17);
371 QCOMPARE(object->property("test3").toInt(), 16);
376 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
377 QObject *object = component.create();
378 QVERIFY(object != 0);
379 QCOMPARE(object->property("test").toInt(), 9);
384 void tst_qdeclarativeecmascript::bindingLoop()
386 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
387 QString warning = component.url().toString() + ":9:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
388 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
389 QObject *object = component.create();
390 QVERIFY(object != 0);
394 void tst_qdeclarativeecmascript::basicExpressions_data()
396 QTest::addColumn<QString>("expression");
397 QTest::addColumn<QVariant>("result");
398 QTest::addColumn<bool>("nest");
400 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
401 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
402 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
403 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
404 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
405 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
406 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
407 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
408 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
409 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
410 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
411 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
412 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
413 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
414 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
415 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
416 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
417 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
418 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
421 void tst_qdeclarativeecmascript::basicExpressions()
423 QFETCH(QString, expression);
424 QFETCH(QVariant, result);
430 MyDefaultObject1 default1;
431 MyDefaultObject3 default3;
432 object1.setStringProperty("Object1");
433 object2.setStringProperty("Object2");
434 object3.setStringProperty("Object3");
436 QDeclarativeContext context(engine.rootContext());
437 QDeclarativeContext nestedContext(&context);
439 context.setContextObject(&default1);
440 context.setContextProperty("a", QVariant(1944));
441 context.setContextProperty("b", QVariant("Milk"));
442 context.setContextProperty("object", &object1);
443 context.setContextProperty("objectOverride", &object2);
444 nestedContext.setContextObject(&default3);
445 nestedContext.setContextProperty("b", QVariant("Cow"));
446 nestedContext.setContextProperty("objectOverride", &object3);
447 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
449 MyExpression expr(nest?&nestedContext:&context, expression);
450 QCOMPARE(expr.evaluate(), result);
453 void tst_qdeclarativeecmascript::arrayExpressions()
459 QDeclarativeContext context(engine.rootContext());
460 context.setContextProperty("a", &obj1);
461 context.setContextProperty("b", &obj2);
462 context.setContextProperty("c", &obj3);
464 MyExpression expr(&context, "[a, b, c, 10]");
465 QVariant result = expr.evaluate();
466 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
467 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
468 QCOMPARE(list.count(), 4);
469 QCOMPARE(list.at(0), &obj1);
470 QCOMPARE(list.at(1), &obj2);
471 QCOMPARE(list.at(2), &obj3);
472 QCOMPARE(list.at(3), (QObject *)0);
475 // Tests that modifying a context property will reevaluate expressions
476 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
478 QDeclarativeContext context(engine.rootContext());
481 MyQmlObject *object3 = new MyQmlObject;
483 object1.setStringProperty("Hello");
484 object2.setStringProperty("World");
486 context.setContextProperty("testProp", QVariant(1));
487 context.setContextProperty("testObj", &object1);
488 context.setContextProperty("testObj2", object3);
491 MyExpression expr(&context, "testProp + 1");
492 QCOMPARE(expr.changed, false);
493 QCOMPARE(expr.evaluate(), QVariant(2));
495 context.setContextProperty("testProp", QVariant(2));
496 QCOMPARE(expr.changed, true);
497 QCOMPARE(expr.evaluate(), QVariant(3));
501 MyExpression expr(&context, "testProp + testProp + testProp");
502 QCOMPARE(expr.changed, false);
503 QCOMPARE(expr.evaluate(), QVariant(6));
505 context.setContextProperty("testProp", QVariant(4));
506 QCOMPARE(expr.changed, true);
507 QCOMPARE(expr.evaluate(), QVariant(12));
511 MyExpression expr(&context, "testObj.stringProperty");
512 QCOMPARE(expr.changed, false);
513 QCOMPARE(expr.evaluate(), QVariant("Hello"));
515 context.setContextProperty("testObj", &object2);
516 QCOMPARE(expr.changed, true);
517 QCOMPARE(expr.evaluate(), QVariant("World"));
521 MyExpression expr(&context, "testObj.stringProperty /**/");
522 QCOMPARE(expr.changed, false);
523 QCOMPARE(expr.evaluate(), QVariant("World"));
525 context.setContextProperty("testObj", &object1);
526 QCOMPARE(expr.changed, true);
527 QCOMPARE(expr.evaluate(), QVariant("Hello"));
531 MyExpression expr(&context, "testObj2");
532 QCOMPARE(expr.changed, false);
533 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
539 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
541 QDeclarativeContext context(engine.rootContext());
545 context.setContextProperty("testObj", &object1);
547 object1.setStringProperty(QLatin1String("Hello"));
548 object2.setStringProperty(QLatin1String("Dog"));
549 object3.setStringProperty(QLatin1String("Cat"));
552 MyExpression expr(&context, "testObj.stringProperty");
553 QCOMPARE(expr.changed, false);
554 QCOMPARE(expr.evaluate(), QVariant("Hello"));
556 object1.setStringProperty(QLatin1String("World"));
557 QCOMPARE(expr.changed, true);
558 QCOMPARE(expr.evaluate(), QVariant("World"));
562 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
563 QCOMPARE(expr.changed, false);
564 QCOMPARE(expr.evaluate(), QVariant());
566 object1.setObjectProperty(&object2);
567 QCOMPARE(expr.changed, true);
568 expr.changed = false;
569 QCOMPARE(expr.evaluate(), QVariant("Dog"));
571 object1.setObjectProperty(&object3);
572 QCOMPARE(expr.changed, true);
573 expr.changed = false;
574 QCOMPARE(expr.evaluate(), QVariant("Cat"));
576 object1.setObjectProperty(0);
577 QCOMPARE(expr.changed, true);
578 expr.changed = false;
579 QCOMPARE(expr.evaluate(), QVariant());
581 object1.setObjectProperty(&object3);
582 QCOMPARE(expr.changed, true);
583 expr.changed = false;
584 QCOMPARE(expr.evaluate(), QVariant("Cat"));
586 object3.setStringProperty("Donkey");
587 QCOMPARE(expr.changed, true);
588 expr.changed = false;
589 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
593 void tst_qdeclarativeecmascript::deferredProperties()
595 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
596 MyDeferredObject *object =
597 qobject_cast<MyDeferredObject *>(component.create());
598 QVERIFY(object != 0);
599 QCOMPARE(object->value(), 0);
600 QVERIFY(object->objectProperty() == 0);
601 QVERIFY(object->objectProperty2() != 0);
602 qmlExecuteDeferred(object);
603 QCOMPARE(object->value(), 10);
604 QVERIFY(object->objectProperty() != 0);
605 MyQmlObject *qmlObject =
606 qobject_cast<MyQmlObject *>(object->objectProperty());
607 QVERIFY(qmlObject != 0);
608 QCOMPARE(qmlObject->value(), 10);
609 object->setValue(19);
610 QCOMPARE(qmlObject->value(), 19);
615 // Check errors on deferred properties are correctly emitted
616 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
618 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
619 MyDeferredObject *object =
620 qobject_cast<MyDeferredObject *>(component.create());
621 QVERIFY(object != 0);
622 QCOMPARE(object->value(), 0);
623 QVERIFY(object->objectProperty() == 0);
624 QVERIFY(object->objectProperty2() == 0);
626 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject* objectProperty";
627 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
629 qmlExecuteDeferred(object);
634 void tst_qdeclarativeecmascript::extensionObjects()
636 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
637 MyExtendedObject *object =
638 qobject_cast<MyExtendedObject *>(component.create());
639 QVERIFY(object != 0);
640 QCOMPARE(object->baseProperty(), 13);
641 QCOMPARE(object->coreProperty(), 9);
642 object->setProperty("extendedProperty", QVariant(11));
643 object->setProperty("baseExtendedProperty", QVariant(92));
644 QCOMPARE(object->coreProperty(), 11);
645 QCOMPARE(object->baseProperty(), 92);
647 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
649 QCOMPARE(nested->baseProperty(), 13);
650 QCOMPARE(nested->coreProperty(), 9);
651 nested->setProperty("extendedProperty", QVariant(11));
652 nested->setProperty("baseExtendedProperty", QVariant(92));
653 QCOMPARE(nested->coreProperty(), 11);
654 QCOMPARE(nested->baseProperty(), 92);
659 void tst_qdeclarativeecmascript::overrideExtensionProperties()
661 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
662 OverrideDefaultPropertyObject *object =
663 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
664 QVERIFY(object != 0);
665 QVERIFY(object->secondProperty() != 0);
666 QVERIFY(object->firstProperty() == 0);
671 void tst_qdeclarativeecmascript::attachedProperties()
674 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
675 QObject *object = component.create();
676 QVERIFY(object != 0);
677 QCOMPARE(object->property("a").toInt(), 19);
678 QCOMPARE(object->property("b").toInt(), 19);
679 QCOMPARE(object->property("c").toInt(), 19);
680 QCOMPARE(object->property("d").toInt(), 19);
685 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
686 QObject *object = component.create();
687 QVERIFY(object != 0);
688 QCOMPARE(object->property("a").toInt(), 26);
689 QCOMPARE(object->property("b").toInt(), 26);
690 QCOMPARE(object->property("c").toInt(), 26);
691 QCOMPARE(object->property("d").toInt(), 26);
697 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
698 QObject *object = component.create();
699 QVERIFY(object != 0);
701 QMetaObject::invokeMethod(object, "writeValue2");
703 MyQmlAttachedObject *attached =
704 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
705 QVERIFY(attached != 0);
707 QCOMPARE(attached->value2(), 9);
712 void tst_qdeclarativeecmascript::enums()
716 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
717 QObject *object = component.create();
718 QVERIFY(object != 0);
720 QCOMPARE(object->property("a").toInt(), 0);
721 QCOMPARE(object->property("b").toInt(), 1);
722 QCOMPARE(object->property("c").toInt(), 2);
723 QCOMPARE(object->property("d").toInt(), 3);
724 QCOMPARE(object->property("e").toInt(), 0);
725 QCOMPARE(object->property("f").toInt(), 1);
726 QCOMPARE(object->property("g").toInt(), 2);
727 QCOMPARE(object->property("h").toInt(), 3);
728 QCOMPARE(object->property("i").toInt(), 19);
729 QCOMPARE(object->property("j").toInt(), 19);
733 // Non-existent enums
735 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
737 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int a";
738 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int b";
739 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
740 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
742 QObject *object = component.create();
743 QVERIFY(object != 0);
744 QCOMPARE(object->property("a").toInt(), 0);
745 QCOMPARE(object->property("b").toInt(), 0);
751 void tst_qdeclarativeecmascript::valueTypeFunctions()
753 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
754 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
756 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
757 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
763 Tests that writing a constant to a property with a binding on it disables the
766 void tst_qdeclarativeecmascript::constantsOverrideBindings()
770 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
771 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
772 QVERIFY(object != 0);
774 QCOMPARE(object->property("c2").toInt(), 0);
775 object->setProperty("c1", QVariant(9));
776 QCOMPARE(object->property("c2").toInt(), 9);
778 emit object->basicSignal();
780 QCOMPARE(object->property("c2").toInt(), 13);
781 object->setProperty("c1", QVariant(8));
782 QCOMPARE(object->property("c2").toInt(), 13);
787 // During construction
789 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
790 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
791 QVERIFY(object != 0);
793 QCOMPARE(object->property("c1").toInt(), 0);
794 QCOMPARE(object->property("c2").toInt(), 10);
795 object->setProperty("c1", QVariant(9));
796 QCOMPARE(object->property("c1").toInt(), 9);
797 QCOMPARE(object->property("c2").toInt(), 10);
805 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
806 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
807 QVERIFY(object != 0);
809 QCOMPARE(object->property("c2").toInt(), 0);
810 object->setProperty("c1", QVariant(9));
811 QCOMPARE(object->property("c2").toInt(), 9);
813 object->setProperty("c2", QVariant(13));
814 QCOMPARE(object->property("c2").toInt(), 13);
815 object->setProperty("c1", QVariant(7));
816 QCOMPARE(object->property("c1").toInt(), 7);
817 QCOMPARE(object->property("c2").toInt(), 13);
825 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
826 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
827 QVERIFY(object != 0);
829 QCOMPARE(object->property("c1").toInt(), 0);
830 QCOMPARE(object->property("c3").toInt(), 10);
831 object->setProperty("c1", QVariant(9));
832 QCOMPARE(object->property("c1").toInt(), 9);
833 QCOMPARE(object->property("c3").toInt(), 10);
840 Tests that assigning a binding to a property that already has a binding causes
841 the original binding to be disabled.
843 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
845 QDeclarativeComponent component(&engine,
846 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
847 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
848 QVERIFY(object != 0);
850 QCOMPARE(object->property("c1").toInt(), 0);
851 QCOMPARE(object->property("c2").toInt(), 0);
852 QCOMPARE(object->property("c3").toInt(), 0);
854 object->setProperty("c1", QVariant(9));
855 QCOMPARE(object->property("c1").toInt(), 9);
856 QCOMPARE(object->property("c2").toInt(), 0);
857 QCOMPARE(object->property("c3").toInt(), 0);
859 object->setProperty("c3", QVariant(8));
860 QCOMPARE(object->property("c1").toInt(), 9);
861 QCOMPARE(object->property("c2").toInt(), 8);
862 QCOMPARE(object->property("c3").toInt(), 8);
868 Access a non-existent attached object.
870 Tests for a regression where this used to crash.
872 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
874 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
876 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString stringProperty";
877 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
879 QObject *object = component.create();
880 QVERIFY(object != 0);
885 void tst_qdeclarativeecmascript::scope()
888 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
889 QObject *object = component.create();
890 QVERIFY(object != 0);
892 QCOMPARE(object->property("test1").toInt(), 1);
893 QCOMPARE(object->property("test2").toInt(), 2);
894 QCOMPARE(object->property("test3").toString(), QString("1Test"));
895 QCOMPARE(object->property("test4").toString(), QString("2Test"));
896 QCOMPARE(object->property("test5").toInt(), 1);
897 QCOMPARE(object->property("test6").toInt(), 1);
898 QCOMPARE(object->property("test7").toInt(), 2);
899 QCOMPARE(object->property("test8").toInt(), 2);
900 QCOMPARE(object->property("test9").toInt(), 1);
901 QCOMPARE(object->property("test10").toInt(), 3);
907 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
908 QObject *object = component.create();
909 QVERIFY(object != 0);
911 QCOMPARE(object->property("test1").toInt(), 19);
912 QCOMPARE(object->property("test2").toInt(), 19);
913 QCOMPARE(object->property("test3").toInt(), 14);
914 QCOMPARE(object->property("test4").toInt(), 14);
915 QCOMPARE(object->property("test5").toInt(), 24);
916 QCOMPARE(object->property("test6").toInt(), 24);
922 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
923 QObject *object = component.create();
924 QVERIFY(object != 0);
926 QCOMPARE(object->property("test1").toBool(), true);
927 QCOMPARE(object->property("test2").toBool(), true);
928 QCOMPARE(object->property("test3").toBool(), true);
933 // Signal argument scope
935 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
936 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
937 QVERIFY(object != 0);
939 QCOMPARE(object->property("test").toInt(), 0);
940 QCOMPARE(object->property("test2").toString(), QString());
942 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
944 QCOMPARE(object->property("test").toInt(), 13);
945 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
951 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
952 QObject *object = component.create();
953 QVERIFY(object != 0);
955 QCOMPARE(object->property("test1").toBool(), true);
956 QCOMPARE(object->property("test2").toBool(), true);
962 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
963 QObject *object = component.create();
964 QVERIFY(object != 0);
966 QCOMPARE(object->property("test").toBool(), true);
972 // In 4.7, non-library javascript files that had no imports shared the imports of their
974 void tst_qdeclarativeecmascript::importScope()
976 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
977 QObject *o = component.create();
980 QCOMPARE(o->property("test").toInt(), 240);
986 Tests that "any" type passes through a synthesized signal parameter. This
987 is essentially a test of QDeclarativeMetaType::copy()
989 void tst_qdeclarativeecmascript::signalParameterTypes()
991 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
992 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
993 QVERIFY(object != 0);
995 emit object->basicSignal();
997 QCOMPARE(object->property("intProperty").toInt(), 10);
998 QCOMPARE(object->property("realProperty").toReal(), 19.2);
999 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1000 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1001 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1002 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1008 Test that two JS objects for the same QObject compare as equal.
1010 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1012 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1013 QObject *object = component.create();
1014 QVERIFY(object != 0);
1016 QCOMPARE(object->property("test1").toBool(), true);
1017 QCOMPARE(object->property("test2").toBool(), true);
1018 QCOMPARE(object->property("test3").toBool(), true);
1019 QCOMPARE(object->property("test4").toBool(), true);
1020 QCOMPARE(object->property("test5").toBool(), true);
1026 Confirm bindings and alias properties can coexist.
1028 Tests for a regression where the binding would not reevaluate.
1030 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1032 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1033 QObject *object = component.create();
1034 QVERIFY(object != 0);
1036 QCOMPARE(object->property("c2").toInt(), 3);
1037 QCOMPARE(object->property("c3").toInt(), 3);
1039 object->setProperty("c2", QVariant(19));
1041 QCOMPARE(object->property("c2").toInt(), 19);
1042 QCOMPARE(object->property("c3").toInt(), 19);
1048 Ensure that we can write undefined value to an alias property,
1049 and that the aliased property is reset correctly if possible.
1051 void tst_qdeclarativeecmascript::aliasPropertyReset()
1053 QObject *object = 0;
1055 // test that a manual write (of undefined) to a resettable aliased property succeeds
1056 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1057 object = c1.create();
1058 QVERIFY(object != 0);
1059 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1060 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1061 QMetaObject::invokeMethod(object, "resetAliased");
1062 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1063 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1066 // test that a manual write (of undefined) to a resettable alias property succeeds
1067 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1068 object = c2.create();
1069 QVERIFY(object != 0);
1070 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1071 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1072 QMetaObject::invokeMethod(object, "resetAlias");
1073 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1074 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1077 // test that an alias to a bound property works correctly
1078 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1079 object = c3.create();
1080 QVERIFY(object != 0);
1081 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1082 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1083 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1084 QMetaObject::invokeMethod(object, "resetAlias");
1085 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1086 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1087 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1090 // test that a manual write (of undefined) to a resettable alias property
1091 // whose aliased property's object has been deleted, does not crash.
1092 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1093 object = c4.create();
1094 QVERIFY(object != 0);
1095 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1096 QObject *loader = object->findChild<QObject*>("loader");
1097 QVERIFY(loader != 0);
1099 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1100 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1101 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1102 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1103 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1106 // test that binding an alias property to an undefined value works correctly
1107 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1108 object = c5.create();
1109 QVERIFY(object != 0);
1110 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1113 // test that a manual write (of undefined) to a non-resettable property fails properly
1114 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1115 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1116 QDeclarativeComponent e1(&engine, url);
1117 object = e1.create();
1118 QVERIFY(object != 0);
1119 QCOMPARE(object->property("intAlias").value<int>(), 12);
1120 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1121 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1122 QMetaObject::invokeMethod(object, "resetAlias");
1123 QCOMPARE(object->property("intAlias").value<int>(), 12);
1124 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1128 void tst_qdeclarativeecmascript::dynamicCreation_data()
1130 QTest::addColumn<QString>("method");
1131 QTest::addColumn<QString>("createdName");
1133 QTest::newRow("One") << "createOne" << "objectOne";
1134 QTest::newRow("Two") << "createTwo" << "objectTwo";
1135 QTest::newRow("Three") << "createThree" << "objectThree";
1139 Test using createQmlObject to dynamically generate an item
1140 Also using createComponent is tested.
1142 void tst_qdeclarativeecmascript::dynamicCreation()
1144 QFETCH(QString, method);
1145 QFETCH(QString, createdName);
1147 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1148 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1149 QVERIFY(object != 0);
1151 QMetaObject::invokeMethod(object, method.toUtf8());
1152 QObject *created = object->objectProperty();
1154 QCOMPARE(created->objectName(), createdName);
1160 Tests the destroy function
1162 void tst_qdeclarativeecmascript::dynamicDestruction()
1165 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1166 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1167 QVERIFY(object != 0);
1168 QDeclarativeGuard<QObject> createdQmlObject = 0;
1170 QMetaObject::invokeMethod(object, "create");
1171 createdQmlObject = object->objectProperty();
1172 QVERIFY(createdQmlObject);
1173 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1175 QMetaObject::invokeMethod(object, "killOther");
1176 QVERIFY(createdQmlObject);
1177 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1178 QVERIFY(createdQmlObject);
1179 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1180 if (createdQmlObject) {
1182 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1185 QVERIFY(!createdQmlObject);
1187 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1188 QMetaObject::invokeMethod(object, "killMe");
1191 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1196 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1197 QObject *o = component.create();
1200 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1202 QMetaObject::invokeMethod(o, "create");
1204 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1206 QMetaObject::invokeMethod(o, "destroy");
1208 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1210 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1217 tests that id.toString() works
1219 void tst_qdeclarativeecmascript::objectToString()
1221 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1222 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1223 QVERIFY(object != 0);
1224 QMetaObject::invokeMethod(object, "testToString");
1225 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1226 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1232 tests that id.hasOwnProperty() works
1234 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1236 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1237 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1238 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1239 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1241 QDeclarativeComponent component(&engine, url);
1242 QObject *object = component.create();
1243 QVERIFY(object != 0);
1245 // test QObjects in QML
1246 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1247 QVERIFY(object->property("result").value<bool>() == true);
1248 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1249 QVERIFY(object->property("result").value<bool>() == false);
1251 // now test other types in QML
1252 QObject *child = object->findChild<QObject*>("typeObj");
1253 QVERIFY(child != 0);
1254 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1255 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1256 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1257 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1258 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1259 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1260 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1261 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1262 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1263 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1264 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1265 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1267 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1268 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1269 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1270 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1271 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1272 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1273 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1274 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1275 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1281 Tests bindings that indirectly cause their own deletion work.
1283 This test is best run under valgrind to ensure no invalid memory access occur.
1285 void tst_qdeclarativeecmascript::selfDeletingBinding()
1288 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1289 QObject *object = component.create();
1290 QVERIFY(object != 0);
1291 object->setProperty("triggerDelete", true);
1296 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1297 QObject *object = component.create();
1298 QVERIFY(object != 0);
1299 object->setProperty("triggerDelete", true);
1305 Test that extended object properties can be accessed.
1307 This test a regression where this used to crash. The issue was specificially
1308 for extended objects that did not include a synthesized meta object (so non-root
1309 and no synthesiszed properties).
1311 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1313 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1314 QObject *object = component.create();
1315 QVERIFY(object != 0);
1320 Test file/lineNumbers for binding/Script errors.
1322 void tst_qdeclarativeecmascript::scriptErrors()
1324 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1325 QString url = component.url().toString();
1327 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1328 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1329 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1330 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1331 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1332 QString warning6 = url + ":7: Unable to assign [undefined] to int x";
1333 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1334 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1336 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1337 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1338 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1339 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1340 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1341 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1342 QVERIFY(object != 0);
1344 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1345 emit object->basicSignal();
1347 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1348 emit object->anotherBasicSignal();
1350 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1351 emit object->thirdBasicSignal();
1357 Test file/lineNumbers for inline functions.
1359 void tst_qdeclarativeecmascript::functionErrors()
1361 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1362 QString url = component.url().toString();
1364 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1366 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1368 QObject *object = component.create();
1369 QVERIFY(object != 0);
1372 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1373 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1374 url = componentTwo.url().toString();
1375 object = componentTwo.create();
1376 QVERIFY(object != 0);
1378 QString srpname = object->property("srp_name").toString();
1380 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1381 QLatin1String(" is not a function");
1382 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1383 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1388 Test various errors that can occur when assigning a property from script
1390 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1392 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1394 QString url = component.url().toString();
1396 QObject *object = component.create();
1397 QVERIFY(object != 0);
1399 QCOMPARE(object->property("test1").toBool(), true);
1400 QCOMPARE(object->property("test2").toBool(), true);
1406 Test bindings still work when the reeval is triggered from within
1409 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1411 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1412 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1413 QVERIFY(object != 0);
1415 QCOMPARE(object->property("base").toReal(), 50.);
1416 QCOMPARE(object->property("test1").toReal(), 50.);
1417 QCOMPARE(object->property("test2").toReal(), 50.);
1419 object->basicSignal();
1421 QCOMPARE(object->property("base").toReal(), 200.);
1422 QCOMPARE(object->property("test1").toReal(), 200.);
1423 QCOMPARE(object->property("test2").toReal(), 200.);
1425 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1427 QCOMPARE(object->property("base").toReal(), 400.);
1428 QCOMPARE(object->property("test1").toReal(), 400.);
1429 QCOMPARE(object->property("test2").toReal(), 400.);
1435 Test that list properties can be iterated from ECMAScript
1437 void tst_qdeclarativeecmascript::listProperties()
1439 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1440 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1441 QVERIFY(object != 0);
1443 QCOMPARE(object->property("test1").toInt(), 21);
1444 QCOMPARE(object->property("test2").toInt(), 2);
1445 QCOMPARE(object->property("test3").toBool(), true);
1446 QCOMPARE(object->property("test4").toBool(), true);
1451 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1453 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1454 QString url = component.url().toString();
1456 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1458 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1459 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1460 QVERIFY(object != 0);
1462 QCOMPARE(object->property("test").toBool(), false);
1464 MyQmlObject object2;
1465 MyQmlObject object3;
1466 object2.setObjectProperty(&object3);
1467 object->setObjectProperty(&object2);
1469 QCOMPARE(object->property("test").toBool(), true);
1474 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1476 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1477 QString url = component.url().toString();
1479 QString warning = component.url().toString() + ":6: Error: JS exception";
1481 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1482 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1483 QVERIFY(object != 0);
1487 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1489 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1490 QString url = component.url().toString();
1492 QString warning = component.url().toString() + ":5: Error: JS exception";
1494 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1495 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1496 QVERIFY(object != 0);
1500 static int transientErrorsMsgCount = 0;
1501 static void transientErrorsMsgHandler(QtMsgType, const char *)
1503 ++transientErrorsMsgCount;
1506 // Check that transient binding errors are not displayed
1507 void tst_qdeclarativeecmascript::transientErrors()
1510 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1512 transientErrorsMsgCount = 0;
1513 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1515 QObject *object = component.create();
1516 QVERIFY(object != 0);
1518 qInstallMsgHandler(old);
1520 QCOMPARE(transientErrorsMsgCount, 0);
1525 // One binding erroring multiple times, but then resolving
1527 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1529 transientErrorsMsgCount = 0;
1530 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1532 QObject *object = component.create();
1533 QVERIFY(object != 0);
1535 qInstallMsgHandler(old);
1537 QCOMPARE(transientErrorsMsgCount, 0);
1543 // Check that errors during shutdown are minimized
1544 void tst_qdeclarativeecmascript::shutdownErrors()
1546 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1547 QObject *object = component.create();
1548 QVERIFY(object != 0);
1550 transientErrorsMsgCount = 0;
1551 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1555 qInstallMsgHandler(old);
1556 QCOMPARE(transientErrorsMsgCount, 0);
1559 void tst_qdeclarativeecmascript::compositePropertyType()
1561 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1562 QTest::ignoreMessage(QtDebugMsg, "hello world");
1563 QObject *object = qobject_cast<QObject *>(component.create());
1568 void tst_qdeclarativeecmascript::jsObject()
1570 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1571 QObject *object = component.create();
1572 QVERIFY(object != 0);
1574 QCOMPARE(object->property("test").toInt(), 92);
1579 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1582 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1583 QObject *object = component.create();
1584 QVERIFY(object != 0);
1586 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1588 object->setProperty("setUndefined", true);
1590 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1592 object->setProperty("setUndefined", false);
1594 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1599 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1600 QObject *object = component.create();
1601 QVERIFY(object != 0);
1603 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1605 QMetaObject::invokeMethod(object, "doReset");
1607 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1614 void tst_qdeclarativeecmascript::bug1()
1616 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1617 QObject *object = component.create();
1618 QVERIFY(object != 0);
1620 QCOMPARE(object->property("test").toInt(), 14);
1622 object->setProperty("a", 11);
1624 QCOMPARE(object->property("test").toInt(), 3);
1626 object->setProperty("b", true);
1628 QCOMPARE(object->property("test").toInt(), 9);
1633 void tst_qdeclarativeecmascript::bug2()
1635 QDeclarativeComponent component(&engine);
1636 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1638 QObject *object = component.create();
1639 QVERIFY(object != 0);
1644 // Don't crash in createObject when the component has errors.
1645 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1647 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1648 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1649 QVERIFY(object != 0);
1651 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1652 QMetaObject::invokeMethod(object, "dontCrash");
1653 QObject *created = object->objectProperty();
1654 QVERIFY(created == 0);
1660 void tst_qdeclarativeecmascript::regExpBug()
1662 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1663 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1664 QVERIFY(object != 0);
1665 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1669 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1671 QString functionSource = QLatin1String("(function(object) { return ") +
1672 QLatin1String(source) + QLatin1String(" })");
1674 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1677 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1678 if (function.IsEmpty())
1680 v8::Handle<v8::Value> args[] = { o };
1681 function->Call(engine->global(), 1, args);
1682 return tc.HasCaught();
1685 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1686 const char *source, v8::Handle<v8::Value> result)
1688 QString functionSource = QLatin1String("(function(object) { return ") +
1689 QLatin1String(source) + QLatin1String(" })");
1691 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1694 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1695 if (function.IsEmpty())
1697 v8::Handle<v8::Value> args[] = { o };
1699 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1704 return value->StrictEquals(result);
1707 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1710 QString functionSource = QLatin1String("(function(object) { return ") +
1711 QLatin1String(source) + QLatin1String(" })");
1713 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1715 return v8::Handle<v8::Value>();
1716 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1717 if (function.IsEmpty())
1718 return v8::Handle<v8::Value>();
1719 v8::Handle<v8::Value> args[] = { o };
1721 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1724 return v8::Handle<v8::Value>();
1728 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1729 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1730 #define EVALUATE(source) evaluate(engine, object, source)
1732 void tst_qdeclarativeecmascript::callQtInvokables()
1734 MyInvokableObject o;
1736 QDeclarativeEngine qmlengine;
1737 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1739 QV8Engine *engine = ep->v8engine();
1741 v8::HandleScope handle_scope;
1742 v8::Context::Scope scope(engine->context());
1744 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1746 // Non-existent methods
1748 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1749 QCOMPARE(o.error(), false);
1750 QCOMPARE(o.invoked(), -1);
1751 QCOMPARE(o.actuals().count(), 0);
1754 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1755 QCOMPARE(o.error(), false);
1756 QCOMPARE(o.invoked(), -1);
1757 QCOMPARE(o.actuals().count(), 0);
1759 // Insufficient arguments
1761 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1762 QCOMPARE(o.error(), false);
1763 QCOMPARE(o.invoked(), -1);
1764 QCOMPARE(o.actuals().count(), 0);
1767 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1768 QCOMPARE(o.error(), false);
1769 QCOMPARE(o.invoked(), -1);
1770 QCOMPARE(o.actuals().count(), 0);
1772 // Excessive arguments
1774 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1775 QCOMPARE(o.error(), false);
1776 QCOMPARE(o.invoked(), 8);
1777 QCOMPARE(o.actuals().count(), 1);
1778 QCOMPARE(o.actuals().at(0), QVariant(10));
1781 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1782 QCOMPARE(o.error(), false);
1783 QCOMPARE(o.invoked(), 9);
1784 QCOMPARE(o.actuals().count(), 2);
1785 QCOMPARE(o.actuals().at(0), QVariant(10));
1786 QCOMPARE(o.actuals().at(1), QVariant(11));
1788 // Test return types
1790 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1791 QCOMPARE(o.error(), false);
1792 QCOMPARE(o.invoked(), 0);
1793 QCOMPARE(o.actuals().count(), 0);
1796 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1797 QCOMPARE(o.error(), false);
1798 QCOMPARE(o.invoked(), 1);
1799 QCOMPARE(o.actuals().count(), 0);
1802 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1803 QCOMPARE(o.error(), false);
1804 QCOMPARE(o.invoked(), 2);
1805 QCOMPARE(o.actuals().count(), 0);
1809 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1810 QVERIFY(!ret.IsEmpty());
1811 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1812 QCOMPARE(o.error(), false);
1813 QCOMPARE(o.invoked(), 3);
1814 QCOMPARE(o.actuals().count(), 0);
1819 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1820 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1821 QCOMPARE(o.error(), false);
1822 QCOMPARE(o.invoked(), 4);
1823 QCOMPARE(o.actuals().count(), 0);
1827 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1828 QCOMPARE(o.error(), false);
1829 QCOMPARE(o.invoked(), 5);
1830 QCOMPARE(o.actuals().count(), 0);
1834 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1835 QVERIFY(ret->IsString());
1836 QCOMPARE(engine->toString(ret), QString("Hello world"));
1837 QCOMPARE(o.error(), false);
1838 QCOMPARE(o.invoked(), 6);
1839 QCOMPARE(o.actuals().count(), 0);
1843 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1844 QCOMPARE(o.error(), false);
1845 QCOMPARE(o.invoked(), 7);
1846 QCOMPARE(o.actuals().count(), 0);
1850 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1851 QCOMPARE(o.error(), false);
1852 QCOMPARE(o.invoked(), 8);
1853 QCOMPARE(o.actuals().count(), 1);
1854 QCOMPARE(o.actuals().at(0), QVariant(94));
1857 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1858 QCOMPARE(o.error(), false);
1859 QCOMPARE(o.invoked(), 8);
1860 QCOMPARE(o.actuals().count(), 1);
1861 QCOMPARE(o.actuals().at(0), QVariant(94));
1864 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1865 QCOMPARE(o.error(), false);
1866 QCOMPARE(o.invoked(), 8);
1867 QCOMPARE(o.actuals().count(), 1);
1868 QCOMPARE(o.actuals().at(0), QVariant(0));
1871 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1872 QCOMPARE(o.error(), false);
1873 QCOMPARE(o.invoked(), 8);
1874 QCOMPARE(o.actuals().count(), 1);
1875 QCOMPARE(o.actuals().at(0), QVariant(0));
1878 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1879 QCOMPARE(o.error(), false);
1880 QCOMPARE(o.invoked(), 8);
1881 QCOMPARE(o.actuals().count(), 1);
1882 QCOMPARE(o.actuals().at(0), QVariant(0));
1885 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1886 QCOMPARE(o.error(), false);
1887 QCOMPARE(o.invoked(), 8);
1888 QCOMPARE(o.actuals().count(), 1);
1889 QCOMPARE(o.actuals().at(0), QVariant(0));
1892 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1893 QCOMPARE(o.error(), false);
1894 QCOMPARE(o.invoked(), 9);
1895 QCOMPARE(o.actuals().count(), 2);
1896 QCOMPARE(o.actuals().at(0), QVariant(122));
1897 QCOMPARE(o.actuals().at(1), QVariant(9));
1900 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1901 QCOMPARE(o.error(), false);
1902 QCOMPARE(o.invoked(), 10);
1903 QCOMPARE(o.actuals().count(), 1);
1904 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1907 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1908 QCOMPARE(o.error(), false);
1909 QCOMPARE(o.invoked(), 10);
1910 QCOMPARE(o.actuals().count(), 1);
1911 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1914 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1915 QCOMPARE(o.error(), false);
1916 QCOMPARE(o.invoked(), 10);
1917 QCOMPARE(o.actuals().count(), 1);
1918 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1921 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1922 QCOMPARE(o.error(), false);
1923 QCOMPARE(o.invoked(), 10);
1924 QCOMPARE(o.actuals().count(), 1);
1925 QCOMPARE(o.actuals().at(0), QVariant(0));
1928 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1929 QCOMPARE(o.error(), false);
1930 QCOMPARE(o.invoked(), 10);
1931 QCOMPARE(o.actuals().count(), 1);
1932 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1935 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
1936 QCOMPARE(o.error(), false);
1937 QCOMPARE(o.invoked(), 10);
1938 QCOMPARE(o.actuals().count(), 1);
1939 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1942 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
1943 QCOMPARE(o.error(), false);
1944 QCOMPARE(o.invoked(), 11);
1945 QCOMPARE(o.actuals().count(), 1);
1946 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
1949 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
1950 QCOMPARE(o.error(), false);
1951 QCOMPARE(o.invoked(), 11);
1952 QCOMPARE(o.actuals().count(), 1);
1953 QCOMPARE(o.actuals().at(0), QVariant("19"));
1957 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
1958 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
1959 QCOMPARE(o.error(), false);
1960 QCOMPARE(o.invoked(), 11);
1961 QCOMPARE(o.actuals().count(), 1);
1962 QCOMPARE(o.actuals().at(0), QVariant(expected));
1966 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
1967 QCOMPARE(o.error(), false);
1968 QCOMPARE(o.invoked(), 11);
1969 QCOMPARE(o.actuals().count(), 1);
1970 QCOMPARE(o.actuals().at(0), QVariant(QString()));
1973 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
1974 QCOMPARE(o.error(), false);
1975 QCOMPARE(o.invoked(), 11);
1976 QCOMPARE(o.actuals().count(), 1);
1977 QCOMPARE(o.actuals().at(0), QVariant(QString()));
1980 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
1981 QCOMPARE(o.error(), false);
1982 QCOMPARE(o.invoked(), 12);
1983 QCOMPARE(o.actuals().count(), 1);
1984 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1987 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
1988 QCOMPARE(o.error(), false);
1989 QCOMPARE(o.invoked(), 12);
1990 QCOMPARE(o.actuals().count(), 1);
1991 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1994 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
1995 QCOMPARE(o.error(), false);
1996 QCOMPARE(o.invoked(), 12);
1997 QCOMPARE(o.actuals().count(), 1);
1998 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2001 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2002 QCOMPARE(o.error(), false);
2003 QCOMPARE(o.invoked(), 12);
2004 QCOMPARE(o.actuals().count(), 1);
2005 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2008 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2009 QCOMPARE(o.error(), false);
2010 QCOMPARE(o.invoked(), 12);
2011 QCOMPARE(o.actuals().count(), 1);
2012 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2015 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2016 QCOMPARE(o.error(), false);
2017 QCOMPARE(o.invoked(), 12);
2018 QCOMPARE(o.actuals().count(), 1);
2019 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2022 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2023 QCOMPARE(o.error(), false);
2024 QCOMPARE(o.invoked(), 13);
2025 QCOMPARE(o.actuals().count(), 1);
2026 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2029 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2030 QCOMPARE(o.error(), false);
2031 QCOMPARE(o.invoked(), 13);
2032 QCOMPARE(o.actuals().count(), 1);
2033 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2036 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2037 QCOMPARE(o.error(), false);
2038 QCOMPARE(o.invoked(), 13);
2039 QCOMPARE(o.actuals().count(), 1);
2040 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2043 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2044 QCOMPARE(o.error(), false);
2045 QCOMPARE(o.invoked(), 13);
2046 QCOMPARE(o.actuals().count(), 1);
2047 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2050 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2051 QCOMPARE(o.error(), false);
2052 QCOMPARE(o.invoked(), 13);
2053 QCOMPARE(o.actuals().count(), 1);
2054 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2057 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2058 QCOMPARE(o.error(), false);
2059 QCOMPARE(o.invoked(), 14);
2060 QCOMPARE(o.actuals().count(), 1);
2061 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2064 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2065 QCOMPARE(o.error(), false);
2066 QCOMPARE(o.invoked(), 14);
2067 QCOMPARE(o.actuals().count(), 1);
2068 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2071 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2072 QCOMPARE(o.error(), false);
2073 QCOMPARE(o.invoked(), 14);
2074 QCOMPARE(o.actuals().count(), 1);
2075 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2078 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2079 QCOMPARE(o.error(), false);
2080 QCOMPARE(o.invoked(), 14);
2081 QCOMPARE(o.actuals().count(), 1);
2082 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2085 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2086 QCOMPARE(o.error(), false);
2087 QCOMPARE(o.invoked(), 15);
2088 QCOMPARE(o.actuals().count(), 2);
2089 QCOMPARE(o.actuals().at(0), QVariant(4));
2090 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2093 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2094 QCOMPARE(o.error(), false);
2095 QCOMPARE(o.invoked(), 15);
2096 QCOMPARE(o.actuals().count(), 2);
2097 QCOMPARE(o.actuals().at(0), QVariant(8));
2098 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2101 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2102 QCOMPARE(o.error(), false);
2103 QCOMPARE(o.invoked(), 15);
2104 QCOMPARE(o.actuals().count(), 2);
2105 QCOMPARE(o.actuals().at(0), QVariant(3));
2106 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2109 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2110 QCOMPARE(o.error(), false);
2111 QCOMPARE(o.invoked(), 15);
2112 QCOMPARE(o.actuals().count(), 2);
2113 QCOMPARE(o.actuals().at(0), QVariant(44));
2114 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2117 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2118 QCOMPARE(o.error(), false);
2119 QCOMPARE(o.invoked(), -1);
2120 QCOMPARE(o.actuals().count(), 0);
2123 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2124 QCOMPARE(o.error(), false);
2125 QCOMPARE(o.invoked(), 16);
2126 QCOMPARE(o.actuals().count(), 1);
2127 QCOMPARE(o.actuals().at(0), QVariant(10));
2130 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2131 QCOMPARE(o.error(), false);
2132 QCOMPARE(o.invoked(), 17);
2133 QCOMPARE(o.actuals().count(), 2);
2134 QCOMPARE(o.actuals().at(0), QVariant(10));
2135 QCOMPARE(o.actuals().at(1), QVariant(11));
2138 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2139 QCOMPARE(o.error(), false);
2140 QCOMPARE(o.invoked(), 18);
2141 QCOMPARE(o.actuals().count(), 1);
2142 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2145 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2146 QCOMPARE(o.error(), false);
2147 QCOMPARE(o.invoked(), 19);
2148 QCOMPARE(o.actuals().count(), 1);
2149 QCOMPARE(o.actuals().at(0), QVariant(9));
2152 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2153 QCOMPARE(o.error(), false);
2154 QCOMPARE(o.invoked(), 20);
2155 QCOMPARE(o.actuals().count(), 2);
2156 QCOMPARE(o.actuals().at(0), QVariant(10));
2157 QCOMPARE(o.actuals().at(1), QVariant(19));
2160 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2161 QCOMPARE(o.error(), false);
2162 QCOMPARE(o.invoked(), 20);
2163 QCOMPARE(o.actuals().count(), 2);
2164 QCOMPARE(o.actuals().at(0), QVariant(10));
2165 QCOMPARE(o.actuals().at(1), QVariant(13));
2168 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2169 QCOMPARE(o.error(), false);
2170 QCOMPARE(o.invoked(), -3);
2171 QCOMPARE(o.actuals().count(), 1);
2172 QCOMPARE(o.actuals().at(0), QVariant(9));
2175 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2176 QCOMPARE(o.error(), false);
2177 QCOMPARE(o.invoked(), 21);
2178 QCOMPARE(o.actuals().count(), 2);
2179 QCOMPARE(o.actuals().at(0), QVariant(9));
2180 QCOMPARE(o.actuals().at(1), QVariant());
2183 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2184 QCOMPARE(o.error(), false);
2185 QCOMPARE(o.invoked(), 21);
2186 QCOMPARE(o.actuals().count(), 2);
2187 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2188 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2191 // QTBUG-13047 (check that you can pass registered object types as args)
2192 void tst_qdeclarativeecmascript::invokableObjectArg()
2194 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2196 QObject *o = component.create();
2198 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2200 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2205 // QTBUG-13047 (check that you can return registered object types from methods)
2206 void tst_qdeclarativeecmascript::invokableObjectRet()
2208 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2210 QObject *o = component.create();
2212 QCOMPARE(o->property("test").toBool(), true);
2217 void tst_qdeclarativeecmascript::listToVariant()
2219 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2221 MyQmlContainer container;
2223 QDeclarativeContext context(engine.rootContext());
2224 context.setContextObject(&container);
2226 QObject *object = component.create(&context);
2227 QVERIFY(object != 0);
2229 QVariant v = object->property("test");
2230 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2231 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2237 void tst_qdeclarativeecmascript::multiEngineObject()
2240 obj.setStringProperty("Howdy planet");
2242 QDeclarativeEngine e1;
2243 e1.rootContext()->setContextProperty("thing", &obj);
2244 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2246 QDeclarativeEngine e2;
2247 e2.rootContext()->setContextProperty("thing", &obj);
2248 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2250 QObject *o1 = c1.create();
2251 QObject *o2 = c2.create();
2253 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2254 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2260 // Test that references to QObjects are cleanup when the object is destroyed
2261 void tst_qdeclarativeecmascript::deletedObject()
2263 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2265 QObject *object = component.create();
2267 QCOMPARE(object->property("test1").toBool(), true);
2268 QCOMPARE(object->property("test2").toBool(), true);
2269 QCOMPARE(object->property("test3").toBool(), true);
2270 QCOMPARE(object->property("test4").toBool(), true);
2275 void tst_qdeclarativeecmascript::attachedPropertyScope()
2277 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2279 QObject *object = component.create();
2280 QVERIFY(object != 0);
2282 MyQmlAttachedObject *attached =
2283 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2284 QVERIFY(attached != 0);
2286 QCOMPARE(object->property("value2").toInt(), 0);
2288 attached->emitMySignal();
2290 QCOMPARE(object->property("value2").toInt(), 9);
2295 void tst_qdeclarativeecmascript::scriptConnect()
2298 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2300 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2301 QVERIFY(object != 0);
2303 QCOMPARE(object->property("test").toBool(), false);
2304 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2305 QCOMPARE(object->property("test").toBool(), true);
2311 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2313 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2314 QVERIFY(object != 0);
2316 QCOMPARE(object->property("test").toBool(), false);
2317 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2318 QCOMPARE(object->property("test").toBool(), true);
2324 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2326 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2327 QVERIFY(object != 0);
2329 QCOMPARE(object->property("test").toBool(), false);
2330 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2331 QCOMPARE(object->property("test").toBool(), true);
2337 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2339 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2340 QVERIFY(object != 0);
2342 QCOMPARE(object->methodCalled(), false);
2343 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2344 QCOMPARE(object->methodCalled(), true);
2350 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2352 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2353 QVERIFY(object != 0);
2355 QCOMPARE(object->methodCalled(), false);
2356 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2357 QCOMPARE(object->methodCalled(), true);
2363 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2365 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2366 QVERIFY(object != 0);
2368 QCOMPARE(object->property("test").toInt(), 0);
2369 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2370 QCOMPARE(object->property("test").toInt(), 2);
2376 void tst_qdeclarativeecmascript::scriptDisconnect()
2379 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.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(), 1);
2387 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2388 QCOMPARE(object->property("test").toInt(), 2);
2389 emit object->basicSignal();
2390 QCOMPARE(object->property("test").toInt(), 2);
2391 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2392 QCOMPARE(object->property("test").toInt(), 2);
2398 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2400 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2401 QVERIFY(object != 0);
2403 QCOMPARE(object->property("test").toInt(), 0);
2404 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2405 QCOMPARE(object->property("test").toInt(), 1);
2406 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2407 QCOMPARE(object->property("test").toInt(), 2);
2408 emit object->basicSignal();
2409 QCOMPARE(object->property("test").toInt(), 2);
2410 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2411 QCOMPARE(object->property("test").toInt(), 2);
2417 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2419 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2420 QVERIFY(object != 0);
2422 QCOMPARE(object->property("test").toInt(), 0);
2423 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2424 QCOMPARE(object->property("test").toInt(), 1);
2425 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2426 QCOMPARE(object->property("test").toInt(), 2);
2427 emit object->basicSignal();
2428 QCOMPARE(object->property("test").toInt(), 2);
2429 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2430 QCOMPARE(object->property("test").toInt(), 3);
2435 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2437 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2438 QVERIFY(object != 0);
2440 QCOMPARE(object->property("test").toInt(), 0);
2441 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2442 QCOMPARE(object->property("test").toInt(), 1);
2443 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2444 QCOMPARE(object->property("test").toInt(), 2);
2445 emit object->basicSignal();
2446 QCOMPARE(object->property("test").toInt(), 2);
2447 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2448 QCOMPARE(object->property("test").toInt(), 3);
2454 class OwnershipObject : public QObject
2458 OwnershipObject() { object = new QObject; }
2460 QPointer<QObject> object;
2463 QObject *getObject() { return object; }
2466 void tst_qdeclarativeecmascript::ownership()
2468 OwnershipObject own;
2469 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2470 context->setContextObject(&own);
2473 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2475 QVERIFY(own.object != 0);
2477 QObject *object = component.create(context);
2479 engine.collectGarbage();
2481 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2483 QVERIFY(own.object == 0);
2488 own.object = new QObject(&own);
2491 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2493 QVERIFY(own.object != 0);
2495 QObject *object = component.create(context);
2497 engine.collectGarbage();
2499 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2501 QVERIFY(own.object != 0);
2509 class CppOwnershipReturnValue : public QObject
2513 CppOwnershipReturnValue() : value(0) {}
2514 ~CppOwnershipReturnValue() { delete value; }
2516 Q_INVOKABLE QObject *create() {
2517 value = new QObject;
2518 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2522 Q_INVOKABLE MyQmlObject *createQmlObject() {
2523 MyQmlObject *rv = new MyQmlObject;
2528 QPointer<QObject> value;
2532 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2533 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2535 CppOwnershipReturnValue source;
2538 QDeclarativeEngine engine;
2539 engine.rootContext()->setContextProperty("source", &source);
2541 QVERIFY(source.value == 0);
2543 QDeclarativeComponent component(&engine);
2544 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2546 QObject *object = component.create();
2548 QVERIFY(object != 0);
2549 QVERIFY(source.value != 0);
2554 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2556 QVERIFY(source.value != 0);
2560 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2562 CppOwnershipReturnValue source;
2565 QDeclarativeEngine engine;
2566 engine.rootContext()->setContextProperty("source", &source);
2568 QVERIFY(source.value == 0);
2570 QDeclarativeComponent component(&engine);
2571 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2573 QObject *object = component.create();
2575 QVERIFY(object != 0);
2576 QVERIFY(source.value != 0);
2581 engine.collectGarbage();
2582 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2584 QVERIFY(source.value == 0);
2587 class QListQObjectMethodsObject : public QObject
2591 QListQObjectMethodsObject() {
2592 m_objects.append(new MyQmlObject());
2593 m_objects.append(new MyQmlObject());
2596 ~QListQObjectMethodsObject() {
2597 qDeleteAll(m_objects);
2601 QList<QObject *> getObjects() { return m_objects; }
2604 QList<QObject *> m_objects;
2607 // Tests that returning a QList<QObject*> from a method works
2608 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2610 QListQObjectMethodsObject obj;
2611 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2612 context->setContextObject(&obj);
2614 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2616 QObject *object = component.create(context);
2618 QCOMPARE(object->property("test").toInt(), 2);
2619 QCOMPARE(object->property("test2").toBool(), true);
2626 void tst_qdeclarativeecmascript::strictlyEquals()
2628 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2630 QObject *object = component.create();
2631 QVERIFY(object != 0);
2633 QCOMPARE(object->property("test1").toBool(), true);
2634 QCOMPARE(object->property("test2").toBool(), true);
2635 QCOMPARE(object->property("test3").toBool(), true);
2636 QCOMPARE(object->property("test4").toBool(), true);
2637 QCOMPARE(object->property("test5").toBool(), true);
2638 QCOMPARE(object->property("test6").toBool(), true);
2639 QCOMPARE(object->property("test7").toBool(), true);
2640 QCOMPARE(object->property("test8").toBool(), true);
2645 void tst_qdeclarativeecmascript::compiled()
2647 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2649 QObject *object = component.create();
2650 QVERIFY(object != 0);
2652 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2653 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2654 QCOMPARE(object->property("test3").toBool(), true);
2655 QCOMPARE(object->property("test4").toBool(), false);
2656 QCOMPARE(object->property("test5").toBool(), false);
2657 QCOMPARE(object->property("test6").toBool(), true);
2659 QCOMPARE(object->property("test7").toInt(), 185);
2660 QCOMPARE(object->property("test8").toInt(), 167);
2661 QCOMPARE(object->property("test9").toBool(), true);
2662 QCOMPARE(object->property("test10").toBool(), false);
2663 QCOMPARE(object->property("test11").toBool(), false);
2664 QCOMPARE(object->property("test12").toBool(), true);
2666 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2667 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2668 QCOMPARE(object->property("test15").toBool(), false);
2669 QCOMPARE(object->property("test16").toBool(), true);
2671 QCOMPARE(object->property("test17").toInt(), 5);
2672 QCOMPARE(object->property("test18").toReal(), qreal(176));
2673 QCOMPARE(object->property("test19").toInt(), 7);
2674 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2675 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2676 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2677 QCOMPARE(object->property("test23").toBool(), true);
2678 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2679 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2684 // Test that numbers assigned in bindings as strings work consistently
2685 void tst_qdeclarativeecmascript::numberAssignment()
2687 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2689 QObject *object = component.create();
2690 QVERIFY(object != 0);
2692 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2693 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2694 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2695 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2696 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2698 QCOMPARE(object->property("test5"), QVariant((int)7));
2699 QCOMPARE(object->property("test6"), QVariant((int)7));
2700 QCOMPARE(object->property("test7"), QVariant((int)6));
2701 QCOMPARE(object->property("test8"), QVariant((int)6));
2703 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2704 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2705 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2706 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2711 void tst_qdeclarativeecmascript::propertySplicing()
2713 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2715 QObject *object = component.create();
2716 QVERIFY(object != 0);
2718 QCOMPARE(object->property("test").toBool(), true);
2724 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2726 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2728 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2729 QVERIFY(object != 0);
2731 MyQmlObject::MyType type;
2732 type.value = 0x8971123;
2733 emit object->signalWithUnknownType(type);
2735 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2737 QCOMPARE(result.value, type.value);
2743 void tst_qdeclarativeecmascript::moduleApi_data()
2745 QTest::addColumn<QUrl>("testfile");
2746 QTest::addColumn<QString>("errorMessage");
2747 QTest::addColumn<QStringList>("warningMessages");
2748 QTest::addColumn<QStringList>("readProperties");
2749 QTest::addColumn<QVariantList>("readExpectedValues");
2750 QTest::addColumn<QStringList>("writeProperties");
2751 QTest::addColumn<QVariantList>("writeValues");
2752 QTest::addColumn<QStringList>("readBackProperties");
2753 QTest::addColumn<QVariantList>("readBackExpectedValues");
2755 QTest::newRow("qobject, register + read + method")
2756 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2759 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2760 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2761 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2767 QTest::newRow("script, register + read")
2768 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2771 << (QStringList() << "scriptTest")
2772 << (QVariantList() << 13)
2778 QTest::newRow("qobject, caching + read")
2779 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2782 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2783 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2789 QTest::newRow("script, caching + read")
2790 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2793 << (QStringList() << "scriptTest")
2794 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2800 QTest::newRow("qobject, writing + readonly constraints")
2801 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2803 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2804 << (QStringList() << "readOnlyProperty" << "writableProperty")
2805 << (QVariantList() << 20 << 50)
2806 << (QStringList() << "firstProperty" << "writableProperty")
2807 << (QVariantList() << 30 << 30)
2808 << (QStringList() << "readOnlyProperty" << "writableProperty")
2809 << (QVariantList() << 20 << 30);
2811 QTest::newRow("script, writing + readonly constraints")
2812 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
2814 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
2815 << (QStringList() << "readBack" << "unchanged")
2816 << (QVariantList() << 13 << 42)
2817 << (QStringList() << "firstProperty" << "secondProperty")
2818 << (QVariantList() << 30 << 30)
2819 << (QStringList() << "readBack" << "unchanged")
2820 << (QVariantList() << 30 << 42);
2822 QTest::newRow("qobject module API enum values in JS")
2823 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
2826 << (QStringList() << "enumValue" << "enumMethod")
2827 << (QVariantList() << 42 << 30)
2833 QTest::newRow("qobject, invalid major version fail")
2834 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
2835 << QString("QDeclarativeComponent: Component is not ready")
2844 QTest::newRow("qobject, invalid minor version fail")
2845 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
2846 << QString("QDeclarativeComponent: Component is not ready")
2856 void tst_qdeclarativeecmascript::moduleApi()
2858 QFETCH(QUrl, testfile);
2859 QFETCH(QString, errorMessage);
2860 QFETCH(QStringList, warningMessages);
2861 QFETCH(QStringList, readProperties);
2862 QFETCH(QVariantList, readExpectedValues);
2863 QFETCH(QStringList, writeProperties);
2864 QFETCH(QVariantList, writeValues);
2865 QFETCH(QStringList, readBackProperties);
2866 QFETCH(QVariantList, readBackExpectedValues);
2868 QDeclarativeComponent component(&engine, testfile);
2870 if (!errorMessage.isEmpty())
2871 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
2873 if (warningMessages.size())
2874 foreach (const QString &warning, warningMessages)
2875 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
2877 QObject *object = component.create();
2878 if (!errorMessage.isEmpty()) {
2879 QVERIFY(object == 0);
2881 QVERIFY(object != 0);
2882 for (int i = 0; i < readProperties.size(); ++i)
2883 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
2884 for (int i = 0; i < writeProperties.size(); ++i)
2885 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
2886 for (int i = 0; i < readBackProperties.size(); ++i)
2887 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
2892 void tst_qdeclarativeecmascript::importScripts()
2894 QObject *object = 0;
2896 // first, ensure that the required behaviour works.
2897 QDeclarativeComponent component(&engine, TEST_FILE("jsimport/testImport.qml"));
2898 object = component.create();
2899 QVERIFY(object != 0);
2900 QCOMPARE(object->property("importedScriptStringValue"), QVariant(QString(QLatin1String("Hello, World!"))));
2901 QCOMPARE(object->property("importedScriptFunctionValue"), QVariant(20));
2902 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(19));
2903 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(2));
2906 QDeclarativeComponent componentTwo(&engine, TEST_FILE("jsimport/testImportScoping.qml"));
2907 object = componentTwo.create();
2908 QVERIFY(object != 0);
2909 QCOMPARE(object->property("componentError"), QVariant(5));
2912 // then, ensure that unintended behaviour does not work.
2913 QDeclarativeComponent failOneComponent(&engine, TEST_FILE("jsimportfail/failOne.qml"));
2914 QString expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined");
2915 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2916 object = failOneComponent.create();
2917 QVERIFY(object != 0);
2918 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2920 QDeclarativeComponent failTwoComponent(&engine, TEST_FILE("jsimportfail/failTwo.qml"));
2921 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs");
2922 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2923 object = failTwoComponent.create();
2924 QVERIFY(object != 0);
2925 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2927 QDeclarativeComponent failThreeComponent(&engine, TEST_FILE("jsimportfail/failThree.qml"));
2928 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined");
2929 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2930 object = failThreeComponent.create();
2931 QVERIFY(object != 0);
2932 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(false));
2934 QDeclarativeComponent failFourComponent(&engine, TEST_FILE("jsimportfail/failFour.qml"));
2935 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest");
2936 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2937 object = failFourComponent.create();
2938 QVERIFY(object != 0);
2939 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(0));
2941 QDeclarativeComponent failFiveComponent(&engine, TEST_FILE("jsimportfail/failFive.qml"));
2942 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component");
2943 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2944 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component");
2945 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2946 object = failFiveComponent.create();
2947 QVERIFY(object != 0);
2948 QCOMPARE(object->property("componentError"), QVariant(0));
2951 // also, test that importing scripts with .pragma library works as required
2952 QDeclarativeComponent pragmaLibraryComponent(&engine, TEST_FILE("jsimport/testImportPragmaLibrary.qml"));
2953 object = pragmaLibraryComponent.create();
2954 QVERIFY(object != 0);
2955 QCOMPARE(object->property("testValue"), QVariant(31));
2958 // and that .pragma library scripts don't inherit imports from any .qml file
2959 QDeclarativeComponent pragmaLibraryComponentTwo(&engine, TEST_FILE("jsimportfail/testImportPragmaLibrary.qml"));
2960 object = pragmaLibraryComponentTwo.create();
2961 QVERIFY(object != 0);
2962 QCOMPARE(object->property("testValue"), QVariant(0));
2966 void tst_qdeclarativeecmascript::scarceResources()
2968 QPixmap origPixmap(100, 100);
2969 origPixmap.fill(Qt::blue);
2971 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
2972 ScarceResourceObject *eo = 0;
2973 QObject *object = 0;
2975 // in the following three cases, the instance created from the component
2976 // has a property which is a copy of the scarce resource; hence, the
2977 // resource should NOT be detached prior to deletion of the object instance,
2978 // unless the resource is destroyed explicitly.
2979 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
2980 object = component.create();
2981 QVERIFY(object != 0);
2982 QVERIFY(object->property("scarceResourceCopy").isValid());
2983 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2984 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2985 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2986 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
2989 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
2990 object = componentTwo.create();
2991 QVERIFY(object != 0);
2992 QVERIFY(object->property("scarceResourceCopy").isValid());
2993 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2994 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2995 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2996 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
2999 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3000 object = componentThree.create();
3001 QVERIFY(object != 0);
3002 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3003 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3004 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3005 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3008 // in the following three cases, no other copy should exist in memory,
3009 // and so it should be detached (unless explicitly preserved).
3010 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3011 object = componentFour.create();
3012 QVERIFY(object != 0);
3013 QVERIFY(object->property("scarceResourceTest").isValid());
3014 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3015 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3016 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3017 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3020 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3021 object = componentFive.create();
3022 QVERIFY(object != 0);
3023 QVERIFY(object->property("scarceResourceTest").isValid());
3024 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3025 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3026 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3027 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3030 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3031 object = componentSix.create();
3032 QVERIFY(object != 0);
3033 QVERIFY(object->property("scarceResourceTest").isValid());
3034 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3035 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3036 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3037 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3040 // test that scarce resources are handled correctly for imports
3041 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3042 object = componentSeven.create();
3043 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3044 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3047 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3048 object = componentEight.create();
3049 QVERIFY(object != 0);
3050 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3051 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3054 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3055 object = componentNine.create();
3056 QVERIFY(object != 0);
3057 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3058 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3059 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3060 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3061 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3062 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3065 // test that scarce resources are handled properly in signal invocation
3066 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3067 object = componentTen.create();
3068 QVERIFY(object != 0);
3069 QObject *srsc = object->findChild<QObject*>("srsc");
3071 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3072 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3073 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3074 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3075 QMetaObject::invokeMethod(srsc, "testSignal");
3076 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3077 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3078 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3079 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3080 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3081 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3082 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3083 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3084 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3085 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3088 // test that scarce resources are handled properly from js functions in qml files
3089 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3090 object = componentEleven.create();
3091 QVERIFY(object != 0);
3092 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3093 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3094 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3095 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3096 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3097 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3098 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3099 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3100 QMetaObject::invokeMethod(object, "releaseScarceResource");
3101 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3102 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3103 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3104 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3107 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3108 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3109 object = componentTwelve.create();
3110 QVERIFY(object != 0);
3111 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3112 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3113 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3114 QString srp_name = object->property("srp_name").toString();
3115 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3116 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3117 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3118 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3119 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3120 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3121 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3125 void tst_qdeclarativeecmascript::propertyChangeSlots()
3127 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3128 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3129 QObject *object = component.create();
3130 QVERIFY(object != 0);
3133 // ensure that invalid property names fail properly.
3134 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3135 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3136 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3137 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3138 object = e1.create();
3139 QVERIFY(object == 0);
3142 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3143 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3144 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3145 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3146 object = e2.create();
3147 QVERIFY(object == 0);
3150 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3151 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3152 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3153 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3154 object = e3.create();
3155 QVERIFY(object == 0);
3158 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3159 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3160 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3161 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3162 object = e4.create();
3163 QVERIFY(object == 0);
3167 // Ensure that QObject type conversion works on binding assignment
3168 void tst_qdeclarativeecmascript::elementAssign()
3170 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3172 QObject *object = component.create();
3173 QVERIFY(object != 0);
3175 QCOMPARE(object->property("test").toBool(), true);
3181 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3183 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3185 QObject *object = component.create();
3186 QVERIFY(object != 0);
3188 QCOMPARE(object->property("test").toBool(), true);
3194 void tst_qdeclarativeecmascript::booleanConversion()
3196 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3198 QObject *object = component.create();
3199 QVERIFY(object != 0);
3201 QCOMPARE(object->property("test_true1").toBool(), true);
3202 QCOMPARE(object->property("test_true2").toBool(), true);
3203 QCOMPARE(object->property("test_true3").toBool(), true);
3204 QCOMPARE(object->property("test_true4").toBool(), true);
3205 QCOMPARE(object->property("test_true5").toBool(), true);
3207 QCOMPARE(object->property("test_false1").toBool(), false);
3208 QCOMPARE(object->property("test_false2").toBool(), false);
3209 QCOMPARE(object->property("test_false3").toBool(), false);
3214 void tst_qdeclarativeecmascript::handleReferenceManagement()
3219 // Linear QObject reference
3220 QDeclarativeEngine hrmEngine;
3221 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3222 QObject *object = component.create();
3223 QVERIFY(object != 0);
3224 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3225 cro->setDtorCount(&dtorCount);
3226 QMetaObject::invokeMethod(object, "createReference");
3227 QMetaObject::invokeMethod(object, "performGc");
3228 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3229 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3231 hrmEngine.collectGarbage();
3232 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3233 QCOMPARE(dtorCount, 3);
3238 // Circular QObject reference
3239 QDeclarativeEngine hrmEngine;
3240 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3241 QObject *object = component.create();
3242 QVERIFY(object != 0);
3243 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3244 cro->setDtorCount(&dtorCount);
3245 QMetaObject::invokeMethod(object, "circularReference");
3246 QMetaObject::invokeMethod(object, "performGc");
3247 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3248 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3250 hrmEngine.collectGarbage();
3251 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3252 QCOMPARE(dtorCount, 3);
3257 // Linear handle reference
3258 QDeclarativeEngine hrmEngine;
3259 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3260 QObject *object = component.create();
3261 QVERIFY(object != 0);
3262 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3264 crh->setDtorCount(&dtorCount);
3265 QMetaObject::invokeMethod(object, "createReference");
3266 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3267 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3268 QVERIFY(first != 0);
3269 QVERIFY(second != 0);
3270 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3271 // now we have to reparent second and make second owned by JS.
3272 second->setParent(0);
3273 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3274 QMetaObject::invokeMethod(object, "performGc");
3275 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3276 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3278 hrmEngine.collectGarbage();
3279 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3280 QCOMPARE(dtorCount, 3);
3285 // Circular handle reference
3286 QDeclarativeEngine hrmEngine;
3287 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3288 QObject *object = component.create();
3289 QVERIFY(object != 0);
3290 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3292 crh->setDtorCount(&dtorCount);
3293 QMetaObject::invokeMethod(object, "circularReference");
3294 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3295 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3296 QVERIFY(first != 0);
3297 QVERIFY(second != 0);
3298 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3299 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3300 // now we have to reparent and change ownership.
3301 first->setParent(0);
3302 second->setParent(0);
3303 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3304 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3305 QMetaObject::invokeMethod(object, "performGc");
3306 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3307 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3309 hrmEngine.collectGarbage();
3310 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3311 QCOMPARE(dtorCount, 3);
3316 // multiple engine interaction - linear reference
3317 QDeclarativeEngine hrmEngine1;
3318 QDeclarativeEngine hrmEngine2;
3319 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3320 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3321 QObject *object1 = component1.create();
3322 QObject *object2 = component2.create();
3323 QVERIFY(object1 != 0);
3324 QVERIFY(object2 != 0);
3325 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3326 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3329 crh1->setDtorCount(&dtorCount);
3330 crh2->setDtorCount(&dtorCount);
3331 QMetaObject::invokeMethod(object1, "createReference");
3332 QMetaObject::invokeMethod(object2, "createReference");
3333 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3334 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3335 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3336 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3337 QVERIFY(first1 != 0);
3338 QVERIFY(second1 != 0);
3339 QVERIFY(first2 != 0);
3340 QVERIFY(second2 != 0);
3341 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3342 // now we have to reparent second2 and make second2 owned by JS.
3343 second2->setParent(0);
3344 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3345 QMetaObject::invokeMethod(object1, "performGc");
3346 QMetaObject::invokeMethod(object2, "performGc");
3347 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3348 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3351 hrmEngine1.collectGarbage();
3352 hrmEngine2.collectGarbage();
3353 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3354 QCOMPARE(dtorCount, 6);
3359 // multiple engine interaction - circular reference
3360 QDeclarativeEngine hrmEngine1;
3361 QDeclarativeEngine hrmEngine2;
3362 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3363 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3364 QObject *object1 = component1.create();
3365 QObject *object2 = component2.create();
3366 QVERIFY(object1 != 0);
3367 QVERIFY(object2 != 0);
3368 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3369 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3372 crh1->setDtorCount(&dtorCount);
3373 crh2->setDtorCount(&dtorCount);
3374 QMetaObject::invokeMethod(object1, "createReference");
3375 QMetaObject::invokeMethod(object2, "createReference");
3376 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3377 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3378 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3379 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3380 QVERIFY(first1 != 0);
3381 QVERIFY(second1 != 0);
3382 QVERIFY(first2 != 0);
3383 QVERIFY(second2 != 0);
3384 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3385 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3386 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3387 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3388 // now we have to reparent and change ownership to JS.
3389 first1->setParent(0);
3390 second1->setParent(0);
3391 first2->setParent(0);
3392 second2->setParent(0);
3393 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
3394 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3395 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3396 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3397 QMetaObject::invokeMethod(object1, "performGc");
3398 QMetaObject::invokeMethod(object2, "performGc");
3399 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3400 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
3403 hrmEngine1.collectGarbage();
3404 hrmEngine2.collectGarbage();
3405 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3406 QCOMPARE(dtorCount, 6);
3411 // multiple engine interaction - linear reference with engine deletion
3412 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
3413 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
3414 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3415 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3416 QObject *object1 = component1.create();
3417 QObject *object2 = component2.create();
3418 QVERIFY(object1 != 0);
3419 QVERIFY(object2 != 0);
3420 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3421 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3424 crh1->setDtorCount(&dtorCount);
3425 crh2->setDtorCount(&dtorCount);
3426 QMetaObject::invokeMethod(object1, "createReference");
3427 QMetaObject::invokeMethod(object2, "createReference");
3428 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3429 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3430 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3431 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3432 QVERIFY(first1 != 0);
3433 QVERIFY(second1 != 0);
3434 QVERIFY(first2 != 0);
3435 QVERIFY(second2 != 0);
3436 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3437 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3438 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3439 // now we have to reparent and change ownership to JS.
3440 first1->setParent(crh1);
3441 second1->setParent(0);
3442 first2->setParent(0);
3443 second2->setParent(0);
3444 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3445 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3446 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3447 QMetaObject::invokeMethod(object1, "performGc");
3448 QMetaObject::invokeMethod(object2, "performGc");
3449 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3450 QCOMPARE(dtorCount, 0);
3452 QMetaObject::invokeMethod(object1, "performGc");
3453 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3454 QCOMPARE(dtorCount, 0);
3457 hrmEngine1->collectGarbage();
3458 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3459 QCOMPARE(dtorCount, 6);
3464 // Test that assigning a null object works
3465 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
3466 void tst_qdeclarativeecmascript::nullObjectBinding()
3468 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
3470 QObject *object = component.create();
3471 QVERIFY(object != 0);
3473 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
3478 // Test that bindings don't evaluate once the engine has been destroyed
3479 void tst_qdeclarativeecmascript::deletedEngine()
3481 QDeclarativeEngine *engine = new QDeclarativeEngine;
3482 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
3484 QObject *object = component.create();
3485 QVERIFY(object != 0);
3487 QCOMPARE(object->property("a").toInt(), 39);
3488 object->setProperty("b", QVariant(9));
3489 QCOMPARE(object->property("a").toInt(), 117);
3493 QCOMPARE(object->property("a").toInt(), 117);
3494 object->setProperty("b", QVariant(10));
3495 QCOMPARE(object->property("a").toInt(), 117);
3500 // Test the crashing part of QTBUG-9705
3501 void tst_qdeclarativeecmascript::libraryScriptAssert()
3503 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
3505 QObject *object = component.create();
3506 QVERIFY(object != 0);
3511 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
3513 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
3515 QObject *object = component.create();
3516 QVERIFY(object != 0);
3518 QCOMPARE(object->property("test1").toInt(), 10);
3519 QCOMPARE(object->property("test2").toInt(), 11);
3521 object->setProperty("runTest", true);
3523 QCOMPARE(object->property("test1"), QVariant());
3524 QCOMPARE(object->property("test2"), QVariant());
3530 void tst_qdeclarativeecmascript::qtbug_9792()
3532 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
3534 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
3536 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
3537 QVERIFY(object != 0);
3539 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
3540 object->basicSignal();
3544 transientErrorsMsgCount = 0;
3545 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3547 object->basicSignal();
3549 qInstallMsgHandler(old);
3551 QCOMPARE(transientErrorsMsgCount, 0);
3556 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
3557 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
3559 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
3561 QObject *o = component.create();
3564 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
3565 QVERIFY(nested != 0);
3567 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
3570 nested = qvariant_cast<QObject *>(o->property("object"));
3571 QVERIFY(nested == 0);
3573 // If the bug is present, the next line will crash
3577 // Test that we shut down without stupid warnings
3578 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
3581 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
3583 QObject *o = component.create();
3585 transientErrorsMsgCount = 0;
3586 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3590 qInstallMsgHandler(old);
3592 QCOMPARE(transientErrorsMsgCount, 0);
3597 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
3599 QObject *o = component.create();
3601 transientErrorsMsgCount = 0;
3602 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3606 qInstallMsgHandler(old);
3608 QCOMPARE(transientErrorsMsgCount, 0);
3612 void tst_qdeclarativeecmascript::canAssignNullToQObject()
3615 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
3617 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3620 QVERIFY(o->objectProperty() != 0);
3622 o->setProperty("runTest", true);
3624 QVERIFY(o->objectProperty() == 0);
3630 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
3632 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3635 QVERIFY(o->objectProperty() == 0);
3641 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
3643 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
3645 QString url = component.url().toString();
3646 QString warning = url + ":4: Unable to assign a function to a property.";
3647 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3649 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3652 QVERIFY(!o->property("a").isValid());
3657 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
3659 QFETCH(QString, triggerProperty);
3661 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3662 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3664 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3666 QVERIFY(!o->property("a").isValid());
3668 o->setProperty("aNumber", QVariant(5));
3669 o->setProperty(triggerProperty.toUtf8().constData(), true);
3670 QCOMPARE(o->property("a"), QVariant(50));
3672 o->setProperty("aNumber", QVariant(10));
3673 QCOMPARE(o->property("a"), QVariant(100));
3678 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
3680 QTest::addColumn<QString>("triggerProperty");
3682 QTest::newRow("assign to property") << "assignToProperty";
3683 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
3685 QTest::newRow("assign to value type") << "assignToValueType";
3687 QTest::newRow("use 'this'") << "assignWithThis";
3688 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
3691 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
3693 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3694 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3696 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3698 QVERIFY(!o->property("a").isValid());
3700 o->setProperty("assignFuncWithoutReturn", true);
3701 QVERIFY(!o->property("a").isValid());
3703 QString url = component.url().toString();
3704 QString warning = url + ":67: Unable to assign QString to int";
3705 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3706 o->setProperty("assignWrongType", true);
3708 warning = url + ":71: Unable to assign QString to int";
3709 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3710 o->setProperty("assignWrongTypeToValueType", true);
3715 void tst_qdeclarativeecmascript::eval()
3717 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
3719 QObject *o = component.create();
3722 QCOMPARE(o->property("test1").toBool(), true);
3723 QCOMPARE(o->property("test2").toBool(), true);
3724 QCOMPARE(o->property("test3").toBool(), true);
3725 QCOMPARE(o->property("test4").toBool(), true);
3726 QCOMPARE(o->property("test5").toBool(), true);
3731 void tst_qdeclarativeecmascript::function()
3733 QDeclarativeComponent component(&engine, TEST_FILE("function.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);
3745 // Test the "Qt.include" method
3746 void tst_qdeclarativeecmascript::include()
3748 // Non-library relative include
3750 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
3751 QObject *o = component.create();
3754 QCOMPARE(o->property("test0").toInt(), 99);
3755 QCOMPARE(o->property("test1").toBool(), true);
3756 QCOMPARE(o->property("test2").toBool(), true);
3757 QCOMPARE(o->property("test2_1").toBool(), true);
3758 QCOMPARE(o->property("test3").toBool(), true);
3759 QCOMPARE(o->property("test3_1").toBool(), true);
3764 // Library relative include
3766 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.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);
3782 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
3783 QObject *o = component.create();
3786 QCOMPARE(o->property("test1").toBool(), true);
3787 QCOMPARE(o->property("test2").toBool(), true);
3788 QCOMPARE(o->property("test3").toBool(), true);
3789 QCOMPARE(o->property("test4").toBool(), true);
3790 QCOMPARE(o->property("test5").toBool(), true);
3791 QCOMPARE(o->property("test6").toBool(), true);
3796 // Including file with ".pragma library"
3798 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
3799 QObject *o = component.create();
3801 QCOMPARE(o->property("test1").toInt(), 100);
3808 TestHTTPServer server(8111);
3809 QVERIFY(server.isValid());
3810 server.serveDirectory(SRCDIR "/data");
3812 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
3813 QObject *o = component.create();
3816 QTRY_VERIFY(o->property("done").toBool() == true);
3817 QTRY_VERIFY(o->property("done2").toBool() == true);
3819 QCOMPARE(o->property("test1").toBool(), true);
3820 QCOMPARE(o->property("test2").toBool(), true);
3821 QCOMPARE(o->property("test3").toBool(), true);
3822 QCOMPARE(o->property("test4").toBool(), true);
3823 QCOMPARE(o->property("test5").toBool(), true);
3825 QCOMPARE(o->property("test6").toBool(), true);
3826 QCOMPARE(o->property("test7").toBool(), true);
3827 QCOMPARE(o->property("test8").toBool(), true);
3828 QCOMPARE(o->property("test9").toBool(), true);
3829 QCOMPARE(o->property("test10").toBool(), true);
3836 TestHTTPServer server(8111);
3837 QVERIFY(server.isValid());
3838 server.serveDirectory(SRCDIR "/data");
3840 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
3841 QObject *o = component.create();
3844 QTRY_VERIFY(o->property("done").toBool() == true);
3846 QCOMPARE(o->property("test1").toBool(), true);
3847 QCOMPARE(o->property("test2").toBool(), true);
3848 QCOMPARE(o->property("test3").toBool(), true);
3854 void tst_qdeclarativeecmascript::signalHandlers()
3856 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
3857 QObject *o = component.create();
3860 QVERIFY(o->property("count").toInt() == 0);
3861 QMetaObject::invokeMethod(o, "testSignalCall");
3862 QCOMPARE(o->property("count").toInt(), 1);
3864 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
3865 QCOMPARE(o->property("count").toInt(), 1);
3866 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
3868 QVERIFY(o->property("funcCount").toInt() == 0);
3869 QMetaObject::invokeMethod(o, "testSignalConnection");
3870 QCOMPARE(o->property("funcCount").toInt(), 1);
3872 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
3873 QCOMPARE(o->property("funcCount").toInt(), 2);
3875 QMetaObject::invokeMethod(o, "testSignalDefined");
3876 QCOMPARE(o->property("definedResult").toBool(), true);
3878 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
3879 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
3884 void tst_qdeclarativeecmascript::qtbug_10696()
3886 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
3887 QObject *o = component.create();
3892 void tst_qdeclarativeecmascript::qtbug_11606()
3894 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
3895 QObject *o = component.create();
3897 QCOMPARE(o->property("test").toBool(), true);
3901 void tst_qdeclarativeecmascript::qtbug_11600()
3903 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
3904 QObject *o = component.create();
3906 QCOMPARE(o->property("test").toBool(), true);
3910 // Reading and writing non-scriptable properties should fail
3911 void tst_qdeclarativeecmascript::nonscriptable()
3913 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
3914 QObject *o = component.create();
3916 QCOMPARE(o->property("readOk").toBool(), true);
3917 QCOMPARE(o->property("writeOk").toBool(), true);
3921 // deleteLater() should not be callable from QML
3922 void tst_qdeclarativeecmascript::deleteLater()
3924 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
3925 QObject *o = component.create();
3927 QCOMPARE(o->property("test").toBool(), true);
3931 void tst_qdeclarativeecmascript::in()
3933 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
3934 QObject *o = component.create();
3936 QCOMPARE(o->property("test1").toBool(), true);
3937 QCOMPARE(o->property("test2").toBool(), true);
3941 void tst_qdeclarativeecmascript::sharedAttachedObject()
3943 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
3944 QObject *o = component.create();
3946 QCOMPARE(o->property("test1").toBool(), true);
3947 QCOMPARE(o->property("test2").toBool(), true);
3952 void tst_qdeclarativeecmascript::objectName()
3954 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
3955 QObject *o = component.create();
3958 QCOMPARE(o->property("test1").toString(), QString("hello"));
3959 QCOMPARE(o->property("test2").toString(), QString("ell"));
3961 o->setObjectName("world");
3963 QCOMPARE(o->property("test1").toString(), QString("world"));
3964 QCOMPARE(o->property("test2").toString(), QString("orl"));
3969 void tst_qdeclarativeecmascript::writeRemovesBinding()
3971 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
3972 QObject *o = component.create();
3975 QCOMPARE(o->property("test").toBool(), true);
3980 // Test bindings assigned to alias properties actually assign to the alias' target
3981 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
3983 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
3984 QObject *o = component.create();
3987 QCOMPARE(o->property("test").toBool(), true);
3992 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
3993 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
3996 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
3997 QObject *o = component.create();
4000 QCOMPARE(o->property("test").toBool(), true);
4006 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4007 QObject *o = component.create();
4010 QCOMPARE(o->property("test").toBool(), true);
4016 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4017 QObject *o = component.create();
4020 QCOMPARE(o->property("test").toBool(), true);
4026 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4027 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4030 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4031 QObject *o = component.create();
4034 QCOMPARE(o->property("test").toBool(), true);
4040 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
4041 QObject *o = component.create();
4044 QCOMPARE(o->property("test").toBool(), true);
4050 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
4051 QObject *o = component.create();
4054 QCOMPARE(o->property("test").toBool(), true);
4060 // Allow an alais to a composite element
4062 void tst_qdeclarativeecmascript::aliasToCompositeElement()
4064 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
4066 QObject *object = component.create();
4067 QVERIFY(object != 0);
4072 void tst_qdeclarativeecmascript::revisionErrors()
4075 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
4076 QString url = component.url().toString();
4078 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4079 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
4080 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
4082 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4083 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4084 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4085 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4086 QVERIFY(object != 0);
4090 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
4091 QString url = component.url().toString();
4093 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
4094 // method2, prop2 from MyRevisionedClass not available
4095 // method4, prop4 from MyRevisionedSubclass not available
4096 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4097 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
4098 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
4099 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
4100 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
4102 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4103 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4104 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4105 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
4106 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
4107 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4108 QVERIFY(object != 0);
4112 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
4113 QString url = component.url().toString();
4115 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
4116 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
4117 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
4118 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
4119 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
4120 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4121 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4122 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4123 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4124 QVERIFY(object != 0);
4129 void tst_qdeclarativeecmascript::revision()
4132 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
4133 QString url = component.url().toString();
4135 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4136 QVERIFY(object != 0);
4140 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
4141 QString url = component.url().toString();
4143 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4144 QVERIFY(object != 0);
4148 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
4149 QString url = component.url().toString();
4151 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4152 QVERIFY(object != 0);
4155 // Test that non-root classes can resolve revisioned methods
4157 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
4159 QObject *object = component.create();
4160 QVERIFY(object != 0);
4161 QCOMPARE(object->property("test").toReal(), 11.);
4166 void tst_qdeclarativeecmascript::realToInt()
4168 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
4169 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
4170 QVERIFY(object != 0);
4172 QMetaObject::invokeMethod(object, "test1");
4173 QCOMPARE(object->value(), int(4));
4174 QMetaObject::invokeMethod(object, "test2");
4175 QCOMPARE(object->value(), int(8));
4177 void tst_qdeclarativeecmascript::dynamicString()
4179 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
4180 QObject *object = component.create();
4181 QVERIFY(object != 0);
4182 QCOMPARE(object->property("stringProperty").toString(),
4183 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
4186 QTEST_MAIN(tst_qdeclarativeecmascript)
4188 #include "tst_qdeclarativeecmascript.moc"