1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <QtDeclarative/qdeclarativecomponent.h>
43 #include <QtDeclarative/qdeclarativeengine.h>
44 #include <QtDeclarative/qdeclarativeexpression.h>
45 #include <QtDeclarative/qdeclarativecontext.h>
46 #include <QtCore/qfileinfo.h>
47 #include <QtCore/qdebug.h>
48 #include <QtDeclarative/private/qdeclarativeguard_p.h>
49 #include <QtCore/qdir.h>
50 #include <QtCore/qnumeric.h>
51 #include <private/qdeclarativeengine_p.h>
52 #include "testtypes.h"
53 #include "testhttpserver.h"
54 #include "../../../shared/util.h"
57 // In Symbian OS test data is located in applications private dir
62 This test covers evaluation of ECMAScript expressions and bindings from within
63 QML. This does not include static QML language issues.
65 Static QML language issues are covered in qmllanguage
67 inline QUrl TEST_FILE(const QString &filename)
69 QFileInfo fileInfo(__FILE__);
70 return QUrl::fromLocalFile(fileInfo.absoluteDir().filePath("data/" + filename));
73 inline QUrl TEST_FILE(const char *filename)
75 return TEST_FILE(QLatin1String(filename));
78 class tst_qdeclarativeecmascript : public QObject
82 tst_qdeclarativeecmascript() {}
86 void assignBasicTypes();
87 void idShortcutInvalidates();
88 void boolPropertiesEvaluateAsBool();
90 void signalAssignment();
92 void basicExpressions();
93 void basicExpressions_data();
94 void arrayExpressions();
95 void contextPropertiesTriggerReeval();
96 void objectPropertiesTriggerReeval();
97 void deferredProperties();
98 void deferredPropertiesErrors();
99 void extensionObjects();
100 void overrideExtensionProperties();
101 void attachedProperties();
103 void valueTypeFunctions();
104 void constantsOverrideBindings();
105 void outerBindingOverridesInnerBinding();
106 void aliasPropertyAndBinding();
107 void aliasPropertyReset();
108 void nonExistentAttachedObject();
111 void signalParameterTypes();
112 void objectsCompareAsEqual();
113 void dynamicCreation_data();
114 void dynamicCreation();
115 void dynamicDestruction();
116 void objectToString();
117 void objectHasOwnProperty();
118 void selfDeletingBinding();
119 void extendedObjectPropertyLookup();
121 void functionErrors();
122 void propertyAssignmentErrors();
123 void signalTriggeredBindings();
124 void listProperties();
125 void exceptionClearsOnReeval();
126 void exceptionSlotProducesWarning();
127 void exceptionBindingProducesWarning();
128 void transientErrors();
129 void shutdownErrors();
130 void compositePropertyType();
132 void undefinedResetsProperty();
133 void listToVariant();
134 void listAssignment();
135 void multiEngineObject();
136 void deletedObject();
137 void attachedPropertyScope();
138 void scriptConnect();
139 void scriptDisconnect();
141 void cppOwnershipReturnValue();
142 void ownershipCustomReturnValue();
143 void qlistqobjectMethods();
144 void strictlyEquals();
146 void numberAssignment();
147 void propertySplicing();
148 void signalWithUnknownTypes();
149 void signalWithJSValueInVariant_data();
150 void signalWithJSValueInVariant();
151 void signalWithJSValueInVariant_twoEngines_data();
152 void signalWithJSValueInVariant_twoEngines();
153 void moduleApi_data();
155 void importScripts();
156 void scarceResources();
157 void propertyChangeSlots();
158 void elementAssign();
159 void objectPassThroughSignals();
160 void booleanConversion();
161 void handleReferenceManagement();
166 void dynamicCreationCrash();
167 void dynamicCreationOwnership();
169 void nullObjectBinding();
170 void deletedEngine();
171 void libraryScriptAssert();
172 void variantsAssignedUndefined();
174 void qtcreatorbug_1289();
175 void noSpuriousWarningsAtShutdown();
176 void canAssignNullToQObject();
177 void functionAssignment_fromBinding();
178 void functionAssignment_fromJS();
179 void functionAssignment_fromJS_data();
180 void functionAssignmentfromJS_invalid();
186 void nonscriptable();
189 void sharedAttachedObject();
191 void writeRemovesBinding();
192 void aliasBindingsAssignCorrectly();
193 void aliasBindingsOverrideTarget();
194 void aliasWritesOverrideBindings();
195 void aliasToCompositeElement();
197 void dynamicString();
199 void signalHandlers();
201 void callQtInvokables();
202 void invokableObjectArg();
203 void invokableObjectRet();
205 void revisionErrors();
208 void automaticSemicolon();
211 QDeclarativeEngine engine;
214 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
216 void tst_qdeclarativeecmascript::assignBasicTypes()
219 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
220 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
221 QVERIFY(object != 0);
222 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
223 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
224 QCOMPARE(object->stringProperty(), QString("Hello World!"));
225 QCOMPARE(object->uintProperty(), uint(10));
226 QCOMPARE(object->intProperty(), -19);
227 QCOMPARE((float)object->realProperty(), float(23.2));
228 QCOMPARE((float)object->doubleProperty(), float(-19.75));
229 QCOMPARE((float)object->floatProperty(), float(8.5));
230 QCOMPARE(object->colorProperty(), QColor("red"));
231 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
232 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
233 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
234 QCOMPARE(object->pointProperty(), QPoint(99,13));
235 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
236 QCOMPARE(object->sizeProperty(), QSize(99, 13));
237 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
238 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
239 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
240 QCOMPARE(object->boolProperty(), true);
241 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
242 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
243 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
247 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
248 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
249 QVERIFY(object != 0);
250 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
251 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
252 QCOMPARE(object->stringProperty(), QString("Hello World!"));
253 QCOMPARE(object->uintProperty(), uint(10));
254 QCOMPARE(object->intProperty(), -19);
255 QCOMPARE((float)object->realProperty(), float(23.2));
256 QCOMPARE((float)object->doubleProperty(), float(-19.75));
257 QCOMPARE((float)object->floatProperty(), float(8.5));
258 QCOMPARE(object->colorProperty(), QColor("red"));
259 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
260 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
261 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
262 QCOMPARE(object->pointProperty(), QPoint(99,13));
263 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
264 QCOMPARE(object->sizeProperty(), QSize(99, 13));
265 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
266 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
267 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
268 QCOMPARE(object->boolProperty(), true);
269 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
270 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
271 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
276 void tst_qdeclarativeecmascript::idShortcutInvalidates()
279 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
280 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
281 QVERIFY(object != 0);
282 QVERIFY(object->objectProperty() != 0);
283 delete object->objectProperty();
284 QVERIFY(object->objectProperty() == 0);
289 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
290 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
291 QVERIFY(object != 0);
292 QVERIFY(object->objectProperty() != 0);
293 delete object->objectProperty();
294 QVERIFY(object->objectProperty() == 0);
299 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
302 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
303 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
304 QVERIFY(object != 0);
305 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
309 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
310 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
311 QVERIFY(object != 0);
312 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
317 void tst_qdeclarativeecmascript::signalAssignment()
320 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
321 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
322 QVERIFY(object != 0);
323 QCOMPARE(object->string(), QString());
324 emit object->basicSignal();
325 QCOMPARE(object->string(), QString("pass"));
330 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
331 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
332 QVERIFY(object != 0);
333 QCOMPARE(object->string(), QString());
334 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
335 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
340 void tst_qdeclarativeecmascript::methods()
343 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
344 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
345 QVERIFY(object != 0);
346 QCOMPARE(object->methodCalled(), false);
347 QCOMPARE(object->methodIntCalled(), false);
348 emit object->basicSignal();
349 QCOMPARE(object->methodCalled(), true);
350 QCOMPARE(object->methodIntCalled(), false);
355 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
356 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
357 QVERIFY(object != 0);
358 QCOMPARE(object->methodCalled(), false);
359 QCOMPARE(object->methodIntCalled(), false);
360 emit object->basicSignal();
361 QCOMPARE(object->methodCalled(), false);
362 QCOMPARE(object->methodIntCalled(), true);
367 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
368 QObject *object = component.create();
369 QVERIFY(object != 0);
370 QCOMPARE(object->property("test").toInt(), 19);
375 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
376 QObject *object = component.create();
377 QVERIFY(object != 0);
378 QCOMPARE(object->property("test").toInt(), 19);
379 QCOMPARE(object->property("test2").toInt(), 17);
380 QCOMPARE(object->property("test3").toInt(), 16);
385 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
386 QObject *object = component.create();
387 QVERIFY(object != 0);
388 QCOMPARE(object->property("test").toInt(), 9);
393 void tst_qdeclarativeecmascript::bindingLoop()
395 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
396 QString warning = component.url().toString() + ":9:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
397 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
398 QObject *object = component.create();
399 QVERIFY(object != 0);
403 void tst_qdeclarativeecmascript::basicExpressions_data()
405 QTest::addColumn<QString>("expression");
406 QTest::addColumn<QVariant>("result");
407 QTest::addColumn<bool>("nest");
409 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
410 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
411 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
412 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
413 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
414 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
415 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
416 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
417 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
418 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
419 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
420 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
421 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
422 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
423 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
424 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
425 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
426 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
427 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
430 void tst_qdeclarativeecmascript::basicExpressions()
432 QFETCH(QString, expression);
433 QFETCH(QVariant, result);
439 MyDefaultObject1 default1;
440 MyDefaultObject3 default3;
441 object1.setStringProperty("Object1");
442 object2.setStringProperty("Object2");
443 object3.setStringProperty("Object3");
445 QDeclarativeContext context(engine.rootContext());
446 QDeclarativeContext nestedContext(&context);
448 context.setContextObject(&default1);
449 context.setContextProperty("a", QVariant(1944));
450 context.setContextProperty("b", QVariant("Milk"));
451 context.setContextProperty("object", &object1);
452 context.setContextProperty("objectOverride", &object2);
453 nestedContext.setContextObject(&default3);
454 nestedContext.setContextProperty("b", QVariant("Cow"));
455 nestedContext.setContextProperty("objectOverride", &object3);
456 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
458 MyExpression expr(nest?&nestedContext:&context, expression);
459 QCOMPARE(expr.evaluate(), result);
462 void tst_qdeclarativeecmascript::arrayExpressions()
468 QDeclarativeContext context(engine.rootContext());
469 context.setContextProperty("a", &obj1);
470 context.setContextProperty("b", &obj2);
471 context.setContextProperty("c", &obj3);
473 MyExpression expr(&context, "[a, b, c, 10]");
474 QVariant result = expr.evaluate();
475 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
476 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
477 QCOMPARE(list.count(), 4);
478 QCOMPARE(list.at(0), &obj1);
479 QCOMPARE(list.at(1), &obj2);
480 QCOMPARE(list.at(2), &obj3);
481 QCOMPARE(list.at(3), (QObject *)0);
484 // Tests that modifying a context property will reevaluate expressions
485 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
487 QDeclarativeContext context(engine.rootContext());
490 MyQmlObject *object3 = new MyQmlObject;
492 object1.setStringProperty("Hello");
493 object2.setStringProperty("World");
495 context.setContextProperty("testProp", QVariant(1));
496 context.setContextProperty("testObj", &object1);
497 context.setContextProperty("testObj2", object3);
500 MyExpression expr(&context, "testProp + 1");
501 QCOMPARE(expr.changed, false);
502 QCOMPARE(expr.evaluate(), QVariant(2));
504 context.setContextProperty("testProp", QVariant(2));
505 QCOMPARE(expr.changed, true);
506 QCOMPARE(expr.evaluate(), QVariant(3));
510 MyExpression expr(&context, "testProp + testProp + testProp");
511 QCOMPARE(expr.changed, false);
512 QCOMPARE(expr.evaluate(), QVariant(6));
514 context.setContextProperty("testProp", QVariant(4));
515 QCOMPARE(expr.changed, true);
516 QCOMPARE(expr.evaluate(), QVariant(12));
520 MyExpression expr(&context, "testObj.stringProperty");
521 QCOMPARE(expr.changed, false);
522 QCOMPARE(expr.evaluate(), QVariant("Hello"));
524 context.setContextProperty("testObj", &object2);
525 QCOMPARE(expr.changed, true);
526 QCOMPARE(expr.evaluate(), QVariant("World"));
530 MyExpression expr(&context, "testObj.stringProperty /**/");
531 QCOMPARE(expr.changed, false);
532 QCOMPARE(expr.evaluate(), QVariant("World"));
534 context.setContextProperty("testObj", &object1);
535 QCOMPARE(expr.changed, true);
536 QCOMPARE(expr.evaluate(), QVariant("Hello"));
540 MyExpression expr(&context, "testObj2");
541 QCOMPARE(expr.changed, false);
542 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
548 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
550 QDeclarativeContext context(engine.rootContext());
554 context.setContextProperty("testObj", &object1);
556 object1.setStringProperty(QLatin1String("Hello"));
557 object2.setStringProperty(QLatin1String("Dog"));
558 object3.setStringProperty(QLatin1String("Cat"));
561 MyExpression expr(&context, "testObj.stringProperty");
562 QCOMPARE(expr.changed, false);
563 QCOMPARE(expr.evaluate(), QVariant("Hello"));
565 object1.setStringProperty(QLatin1String("World"));
566 QCOMPARE(expr.changed, true);
567 QCOMPARE(expr.evaluate(), QVariant("World"));
571 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
572 QCOMPARE(expr.changed, false);
573 QCOMPARE(expr.evaluate(), QVariant());
575 object1.setObjectProperty(&object2);
576 QCOMPARE(expr.changed, true);
577 expr.changed = false;
578 QCOMPARE(expr.evaluate(), QVariant("Dog"));
580 object1.setObjectProperty(&object3);
581 QCOMPARE(expr.changed, true);
582 expr.changed = false;
583 QCOMPARE(expr.evaluate(), QVariant("Cat"));
585 object1.setObjectProperty(0);
586 QCOMPARE(expr.changed, true);
587 expr.changed = false;
588 QCOMPARE(expr.evaluate(), QVariant());
590 object1.setObjectProperty(&object3);
591 QCOMPARE(expr.changed, true);
592 expr.changed = false;
593 QCOMPARE(expr.evaluate(), QVariant("Cat"));
595 object3.setStringProperty("Donkey");
596 QCOMPARE(expr.changed, true);
597 expr.changed = false;
598 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
602 void tst_qdeclarativeecmascript::deferredProperties()
604 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
605 MyDeferredObject *object =
606 qobject_cast<MyDeferredObject *>(component.create());
607 QVERIFY(object != 0);
608 QCOMPARE(object->value(), 0);
609 QVERIFY(object->objectProperty() == 0);
610 QVERIFY(object->objectProperty2() != 0);
611 qmlExecuteDeferred(object);
612 QCOMPARE(object->value(), 10);
613 QVERIFY(object->objectProperty() != 0);
614 MyQmlObject *qmlObject =
615 qobject_cast<MyQmlObject *>(object->objectProperty());
616 QVERIFY(qmlObject != 0);
617 QCOMPARE(qmlObject->value(), 10);
618 object->setValue(19);
619 QCOMPARE(qmlObject->value(), 19);
624 // Check errors on deferred properties are correctly emitted
625 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
627 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
628 MyDeferredObject *object =
629 qobject_cast<MyDeferredObject *>(component.create());
630 QVERIFY(object != 0);
631 QCOMPARE(object->value(), 0);
632 QVERIFY(object->objectProperty() == 0);
633 QVERIFY(object->objectProperty2() == 0);
635 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject* objectProperty";
636 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
638 qmlExecuteDeferred(object);
643 void tst_qdeclarativeecmascript::extensionObjects()
645 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
646 MyExtendedObject *object =
647 qobject_cast<MyExtendedObject *>(component.create());
648 QVERIFY(object != 0);
649 QCOMPARE(object->baseProperty(), 13);
650 QCOMPARE(object->coreProperty(), 9);
651 object->setProperty("extendedProperty", QVariant(11));
652 object->setProperty("baseExtendedProperty", QVariant(92));
653 QCOMPARE(object->coreProperty(), 11);
654 QCOMPARE(object->baseProperty(), 92);
656 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
658 QCOMPARE(nested->baseProperty(), 13);
659 QCOMPARE(nested->coreProperty(), 9);
660 nested->setProperty("extendedProperty", QVariant(11));
661 nested->setProperty("baseExtendedProperty", QVariant(92));
662 QCOMPARE(nested->coreProperty(), 11);
663 QCOMPARE(nested->baseProperty(), 92);
668 void tst_qdeclarativeecmascript::overrideExtensionProperties()
670 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
671 OverrideDefaultPropertyObject *object =
672 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
673 QVERIFY(object != 0);
674 QVERIFY(object->secondProperty() != 0);
675 QVERIFY(object->firstProperty() == 0);
680 void tst_qdeclarativeecmascript::attachedProperties()
683 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
684 QObject *object = component.create();
685 QVERIFY(object != 0);
686 QCOMPARE(object->property("a").toInt(), 19);
687 QCOMPARE(object->property("b").toInt(), 19);
688 QCOMPARE(object->property("c").toInt(), 19);
689 QCOMPARE(object->property("d").toInt(), 19);
694 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
695 QObject *object = component.create();
696 QVERIFY(object != 0);
697 QCOMPARE(object->property("a").toInt(), 26);
698 QCOMPARE(object->property("b").toInt(), 26);
699 QCOMPARE(object->property("c").toInt(), 26);
700 QCOMPARE(object->property("d").toInt(), 26);
706 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
707 QObject *object = component.create();
708 QVERIFY(object != 0);
710 QMetaObject::invokeMethod(object, "writeValue2");
712 MyQmlAttachedObject *attached =
713 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
714 QVERIFY(attached != 0);
716 QCOMPARE(attached->value2(), 9);
721 void tst_qdeclarativeecmascript::enums()
725 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
726 QObject *object = component.create();
727 QVERIFY(object != 0);
729 QCOMPARE(object->property("a").toInt(), 0);
730 QCOMPARE(object->property("b").toInt(), 1);
731 QCOMPARE(object->property("c").toInt(), 2);
732 QCOMPARE(object->property("d").toInt(), 3);
733 QCOMPARE(object->property("e").toInt(), 0);
734 QCOMPARE(object->property("f").toInt(), 1);
735 QCOMPARE(object->property("g").toInt(), 2);
736 QCOMPARE(object->property("h").toInt(), 3);
737 QCOMPARE(object->property("i").toInt(), 19);
738 QCOMPARE(object->property("j").toInt(), 19);
742 // Non-existent enums
744 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
746 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int a";
747 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int b";
748 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
749 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
751 QObject *object = component.create();
752 QVERIFY(object != 0);
753 QCOMPARE(object->property("a").toInt(), 0);
754 QCOMPARE(object->property("b").toInt(), 0);
760 void tst_qdeclarativeecmascript::valueTypeFunctions()
762 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
763 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
765 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
766 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
772 Tests that writing a constant to a property with a binding on it disables the
775 void tst_qdeclarativeecmascript::constantsOverrideBindings()
779 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
780 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
781 QVERIFY(object != 0);
783 QCOMPARE(object->property("c2").toInt(), 0);
784 object->setProperty("c1", QVariant(9));
785 QCOMPARE(object->property("c2").toInt(), 9);
787 emit object->basicSignal();
789 QCOMPARE(object->property("c2").toInt(), 13);
790 object->setProperty("c1", QVariant(8));
791 QCOMPARE(object->property("c2").toInt(), 13);
796 // During construction
798 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
799 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
800 QVERIFY(object != 0);
802 QCOMPARE(object->property("c1").toInt(), 0);
803 QCOMPARE(object->property("c2").toInt(), 10);
804 object->setProperty("c1", QVariant(9));
805 QCOMPARE(object->property("c1").toInt(), 9);
806 QCOMPARE(object->property("c2").toInt(), 10);
814 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
815 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
816 QVERIFY(object != 0);
818 QCOMPARE(object->property("c2").toInt(), 0);
819 object->setProperty("c1", QVariant(9));
820 QCOMPARE(object->property("c2").toInt(), 9);
822 object->setProperty("c2", QVariant(13));
823 QCOMPARE(object->property("c2").toInt(), 13);
824 object->setProperty("c1", QVariant(7));
825 QCOMPARE(object->property("c1").toInt(), 7);
826 QCOMPARE(object->property("c2").toInt(), 13);
834 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
835 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
836 QVERIFY(object != 0);
838 QCOMPARE(object->property("c1").toInt(), 0);
839 QCOMPARE(object->property("c3").toInt(), 10);
840 object->setProperty("c1", QVariant(9));
841 QCOMPARE(object->property("c1").toInt(), 9);
842 QCOMPARE(object->property("c3").toInt(), 10);
849 Tests that assigning a binding to a property that already has a binding causes
850 the original binding to be disabled.
852 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
854 QDeclarativeComponent component(&engine,
855 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
856 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
857 QVERIFY(object != 0);
859 QCOMPARE(object->property("c1").toInt(), 0);
860 QCOMPARE(object->property("c2").toInt(), 0);
861 QCOMPARE(object->property("c3").toInt(), 0);
863 object->setProperty("c1", QVariant(9));
864 QCOMPARE(object->property("c1").toInt(), 9);
865 QCOMPARE(object->property("c2").toInt(), 0);
866 QCOMPARE(object->property("c3").toInt(), 0);
868 object->setProperty("c3", QVariant(8));
869 QCOMPARE(object->property("c1").toInt(), 9);
870 QCOMPARE(object->property("c2").toInt(), 8);
871 QCOMPARE(object->property("c3").toInt(), 8);
877 Access a non-existent attached object.
879 Tests for a regression where this used to crash.
881 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
883 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
885 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString stringProperty";
886 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
888 QObject *object = component.create();
889 QVERIFY(object != 0);
894 void tst_qdeclarativeecmascript::scope()
897 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
898 QObject *object = component.create();
899 QVERIFY(object != 0);
901 QCOMPARE(object->property("test1").toInt(), 1);
902 QCOMPARE(object->property("test2").toInt(), 2);
903 QCOMPARE(object->property("test3").toString(), QString("1Test"));
904 QCOMPARE(object->property("test4").toString(), QString("2Test"));
905 QCOMPARE(object->property("test5").toInt(), 1);
906 QCOMPARE(object->property("test6").toInt(), 1);
907 QCOMPARE(object->property("test7").toInt(), 2);
908 QCOMPARE(object->property("test8").toInt(), 2);
909 QCOMPARE(object->property("test9").toInt(), 1);
910 QCOMPARE(object->property("test10").toInt(), 3);
916 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
917 QObject *object = component.create();
918 QVERIFY(object != 0);
920 QCOMPARE(object->property("test1").toInt(), 19);
921 QCOMPARE(object->property("test2").toInt(), 19);
922 QCOMPARE(object->property("test3").toInt(), 14);
923 QCOMPARE(object->property("test4").toInt(), 14);
924 QCOMPARE(object->property("test5").toInt(), 24);
925 QCOMPARE(object->property("test6").toInt(), 24);
931 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
932 QObject *object = component.create();
933 QVERIFY(object != 0);
935 QCOMPARE(object->property("test1").toBool(), true);
936 QCOMPARE(object->property("test2").toBool(), true);
937 QCOMPARE(object->property("test3").toBool(), true);
942 // Signal argument scope
944 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
945 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
946 QVERIFY(object != 0);
948 QCOMPARE(object->property("test").toInt(), 0);
949 QCOMPARE(object->property("test2").toString(), QString());
951 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
953 QCOMPARE(object->property("test").toInt(), 13);
954 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
960 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
961 QObject *object = component.create();
962 QVERIFY(object != 0);
964 QCOMPARE(object->property("test1").toBool(), true);
965 QCOMPARE(object->property("test2").toBool(), true);
971 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
972 QObject *object = component.create();
973 QVERIFY(object != 0);
975 QCOMPARE(object->property("test").toBool(), true);
981 // In 4.7, non-library javascript files that had no imports shared the imports of their
983 void tst_qdeclarativeecmascript::importScope()
985 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
986 QObject *o = component.create();
989 QCOMPARE(o->property("test").toInt(), 240);
995 Tests that "any" type passes through a synthesized signal parameter. This
996 is essentially a test of QDeclarativeMetaType::copy()
998 void tst_qdeclarativeecmascript::signalParameterTypes()
1000 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
1001 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1002 QVERIFY(object != 0);
1004 emit object->basicSignal();
1006 QCOMPARE(object->property("intProperty").toInt(), 10);
1007 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1008 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1009 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1010 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1011 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1017 Test that two JS objects for the same QObject compare as equal.
1019 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1021 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1022 QObject *object = component.create();
1023 QVERIFY(object != 0);
1025 QCOMPARE(object->property("test1").toBool(), true);
1026 QCOMPARE(object->property("test2").toBool(), true);
1027 QCOMPARE(object->property("test3").toBool(), true);
1028 QCOMPARE(object->property("test4").toBool(), true);
1029 QCOMPARE(object->property("test5").toBool(), true);
1035 Confirm bindings and alias properties can coexist.
1037 Tests for a regression where the binding would not reevaluate.
1039 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1041 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1042 QObject *object = component.create();
1043 QVERIFY(object != 0);
1045 QCOMPARE(object->property("c2").toInt(), 3);
1046 QCOMPARE(object->property("c3").toInt(), 3);
1048 object->setProperty("c2", QVariant(19));
1050 QCOMPARE(object->property("c2").toInt(), 19);
1051 QCOMPARE(object->property("c3").toInt(), 19);
1057 Ensure that we can write undefined value to an alias property,
1058 and that the aliased property is reset correctly if possible.
1060 void tst_qdeclarativeecmascript::aliasPropertyReset()
1062 QObject *object = 0;
1064 // test that a manual write (of undefined) to a resettable aliased property succeeds
1065 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1066 object = c1.create();
1067 QVERIFY(object != 0);
1068 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1069 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1070 QMetaObject::invokeMethod(object, "resetAliased");
1071 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1072 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1075 // test that a manual write (of undefined) to a resettable alias property succeeds
1076 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1077 object = c2.create();
1078 QVERIFY(object != 0);
1079 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1080 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1081 QMetaObject::invokeMethod(object, "resetAlias");
1082 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1083 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1086 // test that an alias to a bound property works correctly
1087 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1088 object = c3.create();
1089 QVERIFY(object != 0);
1090 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1091 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1092 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1093 QMetaObject::invokeMethod(object, "resetAlias");
1094 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1095 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1096 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1099 // test that a manual write (of undefined) to a resettable alias property
1100 // whose aliased property's object has been deleted, does not crash.
1101 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1102 object = c4.create();
1103 QVERIFY(object != 0);
1104 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1105 QObject *loader = object->findChild<QObject*>("loader");
1106 QVERIFY(loader != 0);
1108 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1109 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1110 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1111 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1112 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1115 // test that binding an alias property to an undefined value works correctly
1116 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1117 object = c5.create();
1118 QVERIFY(object != 0);
1119 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1122 // test that a manual write (of undefined) to a non-resettable property fails properly
1123 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1124 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1125 QDeclarativeComponent e1(&engine, url);
1126 object = e1.create();
1127 QVERIFY(object != 0);
1128 QCOMPARE(object->property("intAlias").value<int>(), 12);
1129 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1130 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1131 QMetaObject::invokeMethod(object, "resetAlias");
1132 QCOMPARE(object->property("intAlias").value<int>(), 12);
1133 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1137 void tst_qdeclarativeecmascript::dynamicCreation_data()
1139 QTest::addColumn<QString>("method");
1140 QTest::addColumn<QString>("createdName");
1142 QTest::newRow("One") << "createOne" << "objectOne";
1143 QTest::newRow("Two") << "createTwo" << "objectTwo";
1144 QTest::newRow("Three") << "createThree" << "objectThree";
1148 Test using createQmlObject to dynamically generate an item
1149 Also using createComponent is tested.
1151 void tst_qdeclarativeecmascript::dynamicCreation()
1153 QFETCH(QString, method);
1154 QFETCH(QString, createdName);
1156 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1157 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1158 QVERIFY(object != 0);
1160 QMetaObject::invokeMethod(object, method.toUtf8());
1161 QObject *created = object->objectProperty();
1163 QCOMPARE(created->objectName(), createdName);
1169 Tests the destroy function
1171 void tst_qdeclarativeecmascript::dynamicDestruction()
1174 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1175 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1176 QVERIFY(object != 0);
1177 QDeclarativeGuard<QObject> createdQmlObject = 0;
1179 QMetaObject::invokeMethod(object, "create");
1180 createdQmlObject = object->objectProperty();
1181 QVERIFY(createdQmlObject);
1182 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1184 QMetaObject::invokeMethod(object, "killOther");
1185 QVERIFY(createdQmlObject);
1186 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1187 QVERIFY(createdQmlObject);
1188 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1189 if (createdQmlObject) {
1191 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1194 QVERIFY(!createdQmlObject);
1196 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1197 QMetaObject::invokeMethod(object, "killMe");
1200 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1205 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1206 QObject *o = component.create();
1209 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1211 QMetaObject::invokeMethod(o, "create");
1213 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1215 QMetaObject::invokeMethod(o, "destroy");
1217 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1219 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1226 tests that id.toString() works
1228 void tst_qdeclarativeecmascript::objectToString()
1230 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1231 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1232 QVERIFY(object != 0);
1233 QMetaObject::invokeMethod(object, "testToString");
1234 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1235 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1241 tests that id.hasOwnProperty() works
1243 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1245 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1246 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1247 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1248 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1250 QDeclarativeComponent component(&engine, url);
1251 QObject *object = component.create();
1252 QVERIFY(object != 0);
1254 // test QObjects in QML
1255 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1256 QVERIFY(object->property("result").value<bool>() == true);
1257 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1258 QVERIFY(object->property("result").value<bool>() == false);
1260 // now test other types in QML
1261 QObject *child = object->findChild<QObject*>("typeObj");
1262 QVERIFY(child != 0);
1263 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1264 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1265 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1266 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1267 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1268 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1269 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1270 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1271 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1272 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1273 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1274 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1276 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1277 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1278 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1279 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1280 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1281 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1282 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1283 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1284 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1290 Tests bindings that indirectly cause their own deletion work.
1292 This test is best run under valgrind to ensure no invalid memory access occur.
1294 void tst_qdeclarativeecmascript::selfDeletingBinding()
1297 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1298 QObject *object = component.create();
1299 QVERIFY(object != 0);
1300 object->setProperty("triggerDelete", true);
1305 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1306 QObject *object = component.create();
1307 QVERIFY(object != 0);
1308 object->setProperty("triggerDelete", true);
1314 Test that extended object properties can be accessed.
1316 This test a regression where this used to crash. The issue was specificially
1317 for extended objects that did not include a synthesized meta object (so non-root
1318 and no synthesiszed properties).
1320 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1322 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1323 QObject *object = component.create();
1324 QVERIFY(object != 0);
1329 Test file/lineNumbers for binding/Script errors.
1331 void tst_qdeclarativeecmascript::scriptErrors()
1333 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1334 QString url = component.url().toString();
1336 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1337 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1338 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1339 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1340 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1341 QString warning6 = url + ":7: Unable to assign [undefined] to int x";
1342 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1343 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1345 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1346 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1347 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1348 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1349 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1350 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1351 QVERIFY(object != 0);
1353 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1354 emit object->basicSignal();
1356 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1357 emit object->anotherBasicSignal();
1359 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1360 emit object->thirdBasicSignal();
1366 Test file/lineNumbers for inline functions.
1368 void tst_qdeclarativeecmascript::functionErrors()
1370 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1371 QString url = component.url().toString();
1373 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1375 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1377 QObject *object = component.create();
1378 QVERIFY(object != 0);
1381 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1382 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1383 url = componentTwo.url().toString();
1384 object = componentTwo.create();
1385 QVERIFY(object != 0);
1387 QString srpname = object->property("srp_name").toString();
1389 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1390 QLatin1String(" is not a function");
1391 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1392 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1397 Test various errors that can occur when assigning a property from script
1399 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1401 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1403 QString url = component.url().toString();
1405 QObject *object = component.create();
1406 QVERIFY(object != 0);
1408 QCOMPARE(object->property("test1").toBool(), true);
1409 QCOMPARE(object->property("test2").toBool(), true);
1415 Test bindings still work when the reeval is triggered from within
1418 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1420 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1421 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1422 QVERIFY(object != 0);
1424 QCOMPARE(object->property("base").toReal(), 50.);
1425 QCOMPARE(object->property("test1").toReal(), 50.);
1426 QCOMPARE(object->property("test2").toReal(), 50.);
1428 object->basicSignal();
1430 QCOMPARE(object->property("base").toReal(), 200.);
1431 QCOMPARE(object->property("test1").toReal(), 200.);
1432 QCOMPARE(object->property("test2").toReal(), 200.);
1434 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1436 QCOMPARE(object->property("base").toReal(), 400.);
1437 QCOMPARE(object->property("test1").toReal(), 400.);
1438 QCOMPARE(object->property("test2").toReal(), 400.);
1444 Test that list properties can be iterated from ECMAScript
1446 void tst_qdeclarativeecmascript::listProperties()
1448 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1449 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1450 QVERIFY(object != 0);
1452 QCOMPARE(object->property("test1").toInt(), 21);
1453 QCOMPARE(object->property("test2").toInt(), 2);
1454 QCOMPARE(object->property("test3").toBool(), true);
1455 QCOMPARE(object->property("test4").toBool(), true);
1460 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1462 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1463 QString url = component.url().toString();
1465 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1467 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1468 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1469 QVERIFY(object != 0);
1471 QCOMPARE(object->property("test").toBool(), false);
1473 MyQmlObject object2;
1474 MyQmlObject object3;
1475 object2.setObjectProperty(&object3);
1476 object->setObjectProperty(&object2);
1478 QCOMPARE(object->property("test").toBool(), true);
1483 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1485 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1486 QString url = component.url().toString();
1488 QString warning = component.url().toString() + ":6: Error: JS exception";
1490 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1491 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1492 QVERIFY(object != 0);
1496 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1498 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1499 QString url = component.url().toString();
1501 QString warning = component.url().toString() + ":5: Error: JS exception";
1503 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1504 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1505 QVERIFY(object != 0);
1509 static int transientErrorsMsgCount = 0;
1510 static void transientErrorsMsgHandler(QtMsgType, const char *)
1512 ++transientErrorsMsgCount;
1515 // Check that transient binding errors are not displayed
1516 void tst_qdeclarativeecmascript::transientErrors()
1519 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1521 transientErrorsMsgCount = 0;
1522 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1524 QObject *object = component.create();
1525 QVERIFY(object != 0);
1527 qInstallMsgHandler(old);
1529 QCOMPARE(transientErrorsMsgCount, 0);
1534 // One binding erroring multiple times, but then resolving
1536 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1538 transientErrorsMsgCount = 0;
1539 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1541 QObject *object = component.create();
1542 QVERIFY(object != 0);
1544 qInstallMsgHandler(old);
1546 QCOMPARE(transientErrorsMsgCount, 0);
1552 // Check that errors during shutdown are minimized
1553 void tst_qdeclarativeecmascript::shutdownErrors()
1555 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1556 QObject *object = component.create();
1557 QVERIFY(object != 0);
1559 transientErrorsMsgCount = 0;
1560 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1564 qInstallMsgHandler(old);
1565 QCOMPARE(transientErrorsMsgCount, 0);
1568 void tst_qdeclarativeecmascript::compositePropertyType()
1570 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1571 QTest::ignoreMessage(QtDebugMsg, "hello world");
1572 QObject *object = qobject_cast<QObject *>(component.create());
1577 void tst_qdeclarativeecmascript::jsObject()
1579 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1580 QObject *object = component.create();
1581 QVERIFY(object != 0);
1583 QCOMPARE(object->property("test").toInt(), 92);
1588 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1591 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1592 QObject *object = component.create();
1593 QVERIFY(object != 0);
1595 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1597 object->setProperty("setUndefined", true);
1599 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1601 object->setProperty("setUndefined", false);
1603 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1608 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1609 QObject *object = component.create();
1610 QVERIFY(object != 0);
1612 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1614 QMetaObject::invokeMethod(object, "doReset");
1616 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1623 void tst_qdeclarativeecmascript::bug1()
1625 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1626 QObject *object = component.create();
1627 QVERIFY(object != 0);
1629 QCOMPARE(object->property("test").toInt(), 14);
1631 object->setProperty("a", 11);
1633 QCOMPARE(object->property("test").toInt(), 3);
1635 object->setProperty("b", true);
1637 QCOMPARE(object->property("test").toInt(), 9);
1642 void tst_qdeclarativeecmascript::bug2()
1644 QDeclarativeComponent component(&engine);
1645 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1647 QObject *object = component.create();
1648 QVERIFY(object != 0);
1653 // Don't crash in createObject when the component has errors.
1654 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1656 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1657 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1658 QVERIFY(object != 0);
1660 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1661 QMetaObject::invokeMethod(object, "dontCrash");
1662 QObject *created = object->objectProperty();
1663 QVERIFY(created == 0);
1668 // ownership transferred to JS, ensure that GC runs the dtor
1669 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1672 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1674 // allow the engine to go out of scope too.
1676 QDeclarativeEngine dcoEngine;
1677 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1678 QObject *object = component.create();
1679 QVERIFY(object != 0);
1680 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1681 QVERIFY(mdcdo != 0);
1682 mdcdo->setDtorCount(&dtorCount);
1684 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1685 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1687 // we do this once manually, but it should be done automatically
1688 // when the engine goes out of scope (since it should gc in dtor)
1689 QMetaObject::invokeMethod(object, "performGc");
1692 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1698 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1699 QCOMPARE(dtorCount, expectedDtorCount);
1703 void tst_qdeclarativeecmascript::regExpBug()
1705 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1706 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1707 QVERIFY(object != 0);
1708 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1712 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1714 QString functionSource = QLatin1String("(function(object) { return ") +
1715 QLatin1String(source) + QLatin1String(" })");
1717 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1720 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1721 if (function.IsEmpty())
1723 v8::Handle<v8::Value> args[] = { o };
1724 function->Call(engine->global(), 1, args);
1725 return tc.HasCaught();
1728 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1729 const char *source, v8::Handle<v8::Value> result)
1731 QString functionSource = QLatin1String("(function(object) { return ") +
1732 QLatin1String(source) + QLatin1String(" })");
1734 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1737 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1738 if (function.IsEmpty())
1740 v8::Handle<v8::Value> args[] = { o };
1742 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1747 return value->StrictEquals(result);
1750 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1753 QString functionSource = QLatin1String("(function(object) { return ") +
1754 QLatin1String(source) + QLatin1String(" })");
1756 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1758 return v8::Handle<v8::Value>();
1759 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1760 if (function.IsEmpty())
1761 return v8::Handle<v8::Value>();
1762 v8::Handle<v8::Value> args[] = { o };
1764 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1767 return v8::Handle<v8::Value>();
1771 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1772 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1773 #define EVALUATE(source) evaluate(engine, object, source)
1775 void tst_qdeclarativeecmascript::callQtInvokables()
1777 MyInvokableObject o;
1779 QDeclarativeEngine qmlengine;
1780 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1782 QV8Engine *engine = ep->v8engine();
1784 v8::HandleScope handle_scope;
1785 v8::Context::Scope scope(engine->context());
1787 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1789 // Non-existent methods
1791 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1792 QCOMPARE(o.error(), false);
1793 QCOMPARE(o.invoked(), -1);
1794 QCOMPARE(o.actuals().count(), 0);
1797 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1798 QCOMPARE(o.error(), false);
1799 QCOMPARE(o.invoked(), -1);
1800 QCOMPARE(o.actuals().count(), 0);
1802 // Insufficient arguments
1804 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1805 QCOMPARE(o.error(), false);
1806 QCOMPARE(o.invoked(), -1);
1807 QCOMPARE(o.actuals().count(), 0);
1810 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1811 QCOMPARE(o.error(), false);
1812 QCOMPARE(o.invoked(), -1);
1813 QCOMPARE(o.actuals().count(), 0);
1815 // Excessive arguments
1817 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1818 QCOMPARE(o.error(), false);
1819 QCOMPARE(o.invoked(), 8);
1820 QCOMPARE(o.actuals().count(), 1);
1821 QCOMPARE(o.actuals().at(0), QVariant(10));
1824 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1825 QCOMPARE(o.error(), false);
1826 QCOMPARE(o.invoked(), 9);
1827 QCOMPARE(o.actuals().count(), 2);
1828 QCOMPARE(o.actuals().at(0), QVariant(10));
1829 QCOMPARE(o.actuals().at(1), QVariant(11));
1831 // Test return types
1833 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1834 QCOMPARE(o.error(), false);
1835 QCOMPARE(o.invoked(), 0);
1836 QCOMPARE(o.actuals().count(), 0);
1839 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1840 QCOMPARE(o.error(), false);
1841 QCOMPARE(o.invoked(), 1);
1842 QCOMPARE(o.actuals().count(), 0);
1845 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1846 QCOMPARE(o.error(), false);
1847 QCOMPARE(o.invoked(), 2);
1848 QCOMPARE(o.actuals().count(), 0);
1852 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1853 QVERIFY(!ret.IsEmpty());
1854 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1855 QCOMPARE(o.error(), false);
1856 QCOMPARE(o.invoked(), 3);
1857 QCOMPARE(o.actuals().count(), 0);
1862 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1863 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1864 QCOMPARE(o.error(), false);
1865 QCOMPARE(o.invoked(), 4);
1866 QCOMPARE(o.actuals().count(), 0);
1870 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1871 QCOMPARE(o.error(), false);
1872 QCOMPARE(o.invoked(), 5);
1873 QCOMPARE(o.actuals().count(), 0);
1877 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1878 QVERIFY(ret->IsString());
1879 QCOMPARE(engine->toString(ret), QString("Hello world"));
1880 QCOMPARE(o.error(), false);
1881 QCOMPARE(o.invoked(), 6);
1882 QCOMPARE(o.actuals().count(), 0);
1886 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1887 QCOMPARE(o.error(), false);
1888 QCOMPARE(o.invoked(), 7);
1889 QCOMPARE(o.actuals().count(), 0);
1893 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1894 QCOMPARE(o.error(), false);
1895 QCOMPARE(o.invoked(), 8);
1896 QCOMPARE(o.actuals().count(), 1);
1897 QCOMPARE(o.actuals().at(0), QVariant(94));
1900 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1901 QCOMPARE(o.error(), false);
1902 QCOMPARE(o.invoked(), 8);
1903 QCOMPARE(o.actuals().count(), 1);
1904 QCOMPARE(o.actuals().at(0), QVariant(94));
1907 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1908 QCOMPARE(o.error(), false);
1909 QCOMPARE(o.invoked(), 8);
1910 QCOMPARE(o.actuals().count(), 1);
1911 QCOMPARE(o.actuals().at(0), QVariant(0));
1914 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1915 QCOMPARE(o.error(), false);
1916 QCOMPARE(o.invoked(), 8);
1917 QCOMPARE(o.actuals().count(), 1);
1918 QCOMPARE(o.actuals().at(0), QVariant(0));
1921 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1922 QCOMPARE(o.error(), false);
1923 QCOMPARE(o.invoked(), 8);
1924 QCOMPARE(o.actuals().count(), 1);
1925 QCOMPARE(o.actuals().at(0), QVariant(0));
1928 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1929 QCOMPARE(o.error(), false);
1930 QCOMPARE(o.invoked(), 8);
1931 QCOMPARE(o.actuals().count(), 1);
1932 QCOMPARE(o.actuals().at(0), QVariant(0));
1935 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1936 QCOMPARE(o.error(), false);
1937 QCOMPARE(o.invoked(), 9);
1938 QCOMPARE(o.actuals().count(), 2);
1939 QCOMPARE(o.actuals().at(0), QVariant(122));
1940 QCOMPARE(o.actuals().at(1), QVariant(9));
1943 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1944 QCOMPARE(o.error(), false);
1945 QCOMPARE(o.invoked(), 10);
1946 QCOMPARE(o.actuals().count(), 1);
1947 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1950 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1951 QCOMPARE(o.error(), false);
1952 QCOMPARE(o.invoked(), 10);
1953 QCOMPARE(o.actuals().count(), 1);
1954 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1957 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1958 QCOMPARE(o.error(), false);
1959 QCOMPARE(o.invoked(), 10);
1960 QCOMPARE(o.actuals().count(), 1);
1961 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1964 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1965 QCOMPARE(o.error(), false);
1966 QCOMPARE(o.invoked(), 10);
1967 QCOMPARE(o.actuals().count(), 1);
1968 QCOMPARE(o.actuals().at(0), QVariant(0));
1971 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1972 QCOMPARE(o.error(), false);
1973 QCOMPARE(o.invoked(), 10);
1974 QCOMPARE(o.actuals().count(), 1);
1975 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1978 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
1979 QCOMPARE(o.error(), false);
1980 QCOMPARE(o.invoked(), 10);
1981 QCOMPARE(o.actuals().count(), 1);
1982 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1985 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
1986 QCOMPARE(o.error(), false);
1987 QCOMPARE(o.invoked(), 11);
1988 QCOMPARE(o.actuals().count(), 1);
1989 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
1992 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
1993 QCOMPARE(o.error(), false);
1994 QCOMPARE(o.invoked(), 11);
1995 QCOMPARE(o.actuals().count(), 1);
1996 QCOMPARE(o.actuals().at(0), QVariant("19"));
2000 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2001 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2002 QCOMPARE(o.error(), false);
2003 QCOMPARE(o.invoked(), 11);
2004 QCOMPARE(o.actuals().count(), 1);
2005 QCOMPARE(o.actuals().at(0), QVariant(expected));
2009 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2010 QCOMPARE(o.error(), false);
2011 QCOMPARE(o.invoked(), 11);
2012 QCOMPARE(o.actuals().count(), 1);
2013 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2016 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2017 QCOMPARE(o.error(), false);
2018 QCOMPARE(o.invoked(), 11);
2019 QCOMPARE(o.actuals().count(), 1);
2020 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2023 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2024 QCOMPARE(o.error(), false);
2025 QCOMPARE(o.invoked(), 12);
2026 QCOMPARE(o.actuals().count(), 1);
2027 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2030 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2031 QCOMPARE(o.error(), false);
2032 QCOMPARE(o.invoked(), 12);
2033 QCOMPARE(o.actuals().count(), 1);
2034 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2037 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2038 QCOMPARE(o.error(), false);
2039 QCOMPARE(o.invoked(), 12);
2040 QCOMPARE(o.actuals().count(), 1);
2041 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2044 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2045 QCOMPARE(o.error(), false);
2046 QCOMPARE(o.invoked(), 12);
2047 QCOMPARE(o.actuals().count(), 1);
2048 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2051 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2052 QCOMPARE(o.error(), false);
2053 QCOMPARE(o.invoked(), 12);
2054 QCOMPARE(o.actuals().count(), 1);
2055 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2058 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2059 QCOMPARE(o.error(), false);
2060 QCOMPARE(o.invoked(), 12);
2061 QCOMPARE(o.actuals().count(), 1);
2062 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2065 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2066 QCOMPARE(o.error(), false);
2067 QCOMPARE(o.invoked(), 13);
2068 QCOMPARE(o.actuals().count(), 1);
2069 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2072 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2073 QCOMPARE(o.error(), false);
2074 QCOMPARE(o.invoked(), 13);
2075 QCOMPARE(o.actuals().count(), 1);
2076 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2079 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2080 QCOMPARE(o.error(), false);
2081 QCOMPARE(o.invoked(), 13);
2082 QCOMPARE(o.actuals().count(), 1);
2083 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2086 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2087 QCOMPARE(o.error(), false);
2088 QCOMPARE(o.invoked(), 13);
2089 QCOMPARE(o.actuals().count(), 1);
2090 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2093 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2094 QCOMPARE(o.error(), false);
2095 QCOMPARE(o.invoked(), 13);
2096 QCOMPARE(o.actuals().count(), 1);
2097 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2100 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2101 QCOMPARE(o.error(), false);
2102 QCOMPARE(o.invoked(), 14);
2103 QCOMPARE(o.actuals().count(), 1);
2104 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2107 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2108 QCOMPARE(o.error(), false);
2109 QCOMPARE(o.invoked(), 14);
2110 QCOMPARE(o.actuals().count(), 1);
2111 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2114 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2115 QCOMPARE(o.error(), false);
2116 QCOMPARE(o.invoked(), 14);
2117 QCOMPARE(o.actuals().count(), 1);
2118 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2121 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2122 QCOMPARE(o.error(), false);
2123 QCOMPARE(o.invoked(), 14);
2124 QCOMPARE(o.actuals().count(), 1);
2125 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2128 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2129 QCOMPARE(o.error(), false);
2130 QCOMPARE(o.invoked(), 15);
2131 QCOMPARE(o.actuals().count(), 2);
2132 QCOMPARE(o.actuals().at(0), QVariant(4));
2133 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2136 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2137 QCOMPARE(o.error(), false);
2138 QCOMPARE(o.invoked(), 15);
2139 QCOMPARE(o.actuals().count(), 2);
2140 QCOMPARE(o.actuals().at(0), QVariant(8));
2141 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2144 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2145 QCOMPARE(o.error(), false);
2146 QCOMPARE(o.invoked(), 15);
2147 QCOMPARE(o.actuals().count(), 2);
2148 QCOMPARE(o.actuals().at(0), QVariant(3));
2149 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2152 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2153 QCOMPARE(o.error(), false);
2154 QCOMPARE(o.invoked(), 15);
2155 QCOMPARE(o.actuals().count(), 2);
2156 QCOMPARE(o.actuals().at(0), QVariant(44));
2157 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2160 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2161 QCOMPARE(o.error(), false);
2162 QCOMPARE(o.invoked(), -1);
2163 QCOMPARE(o.actuals().count(), 0);
2166 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2167 QCOMPARE(o.error(), false);
2168 QCOMPARE(o.invoked(), 16);
2169 QCOMPARE(o.actuals().count(), 1);
2170 QCOMPARE(o.actuals().at(0), QVariant(10));
2173 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2174 QCOMPARE(o.error(), false);
2175 QCOMPARE(o.invoked(), 17);
2176 QCOMPARE(o.actuals().count(), 2);
2177 QCOMPARE(o.actuals().at(0), QVariant(10));
2178 QCOMPARE(o.actuals().at(1), QVariant(11));
2181 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2182 QCOMPARE(o.error(), false);
2183 QCOMPARE(o.invoked(), 18);
2184 QCOMPARE(o.actuals().count(), 1);
2185 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2188 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2189 QCOMPARE(o.error(), false);
2190 QCOMPARE(o.invoked(), 19);
2191 QCOMPARE(o.actuals().count(), 1);
2192 QCOMPARE(o.actuals().at(0), QVariant(9));
2195 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2196 QCOMPARE(o.error(), false);
2197 QCOMPARE(o.invoked(), 20);
2198 QCOMPARE(o.actuals().count(), 2);
2199 QCOMPARE(o.actuals().at(0), QVariant(10));
2200 QCOMPARE(o.actuals().at(1), QVariant(19));
2203 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2204 QCOMPARE(o.error(), false);
2205 QCOMPARE(o.invoked(), 20);
2206 QCOMPARE(o.actuals().count(), 2);
2207 QCOMPARE(o.actuals().at(0), QVariant(10));
2208 QCOMPARE(o.actuals().at(1), QVariant(13));
2211 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2212 QCOMPARE(o.error(), false);
2213 QCOMPARE(o.invoked(), -3);
2214 QCOMPARE(o.actuals().count(), 1);
2215 QCOMPARE(o.actuals().at(0), QVariant(9));
2218 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2219 QCOMPARE(o.error(), false);
2220 QCOMPARE(o.invoked(), 21);
2221 QCOMPARE(o.actuals().count(), 2);
2222 QCOMPARE(o.actuals().at(0), QVariant(9));
2223 QCOMPARE(o.actuals().at(1), QVariant());
2226 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2227 QCOMPARE(o.error(), false);
2228 QCOMPARE(o.invoked(), 21);
2229 QCOMPARE(o.actuals().count(), 2);
2230 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2231 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2234 // QTBUG-13047 (check that you can pass registered object types as args)
2235 void tst_qdeclarativeecmascript::invokableObjectArg()
2237 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2239 QObject *o = component.create();
2241 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2243 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2248 // QTBUG-13047 (check that you can return registered object types from methods)
2249 void tst_qdeclarativeecmascript::invokableObjectRet()
2251 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2253 QObject *o = component.create();
2255 QCOMPARE(o->property("test").toBool(), true);
2260 void tst_qdeclarativeecmascript::listToVariant()
2262 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2264 MyQmlContainer container;
2266 QDeclarativeContext context(engine.rootContext());
2267 context.setContextObject(&container);
2269 QObject *object = component.create(&context);
2270 QVERIFY(object != 0);
2272 QVariant v = object->property("test");
2273 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2274 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2280 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2281 void tst_qdeclarativeecmascript::listAssignment()
2283 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2284 QObject *obj = component.create();
2285 QCOMPARE(obj->property("list1length").toInt(), 2);
2286 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2287 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2288 QCOMPARE(list1.count(&list1), list2.count(&list2));
2289 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2290 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2295 void tst_qdeclarativeecmascript::multiEngineObject()
2298 obj.setStringProperty("Howdy planet");
2300 QDeclarativeEngine e1;
2301 e1.rootContext()->setContextProperty("thing", &obj);
2302 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2304 QDeclarativeEngine e2;
2305 e2.rootContext()->setContextProperty("thing", &obj);
2306 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2308 QObject *o1 = c1.create();
2309 QObject *o2 = c2.create();
2311 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2312 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2318 // Test that references to QObjects are cleanup when the object is destroyed
2319 void tst_qdeclarativeecmascript::deletedObject()
2321 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2323 QObject *object = component.create();
2325 QCOMPARE(object->property("test1").toBool(), true);
2326 QCOMPARE(object->property("test2").toBool(), true);
2327 QCOMPARE(object->property("test3").toBool(), true);
2328 QCOMPARE(object->property("test4").toBool(), true);
2333 void tst_qdeclarativeecmascript::attachedPropertyScope()
2335 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2337 QObject *object = component.create();
2338 QVERIFY(object != 0);
2340 MyQmlAttachedObject *attached =
2341 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2342 QVERIFY(attached != 0);
2344 QCOMPARE(object->property("value2").toInt(), 0);
2346 attached->emitMySignal();
2348 QCOMPARE(object->property("value2").toInt(), 9);
2353 void tst_qdeclarativeecmascript::scriptConnect()
2356 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2358 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2359 QVERIFY(object != 0);
2361 QCOMPARE(object->property("test").toBool(), false);
2362 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2363 QCOMPARE(object->property("test").toBool(), true);
2369 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2371 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2372 QVERIFY(object != 0);
2374 QCOMPARE(object->property("test").toBool(), false);
2375 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2376 QCOMPARE(object->property("test").toBool(), true);
2382 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2384 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2385 QVERIFY(object != 0);
2387 QCOMPARE(object->property("test").toBool(), false);
2388 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2389 QCOMPARE(object->property("test").toBool(), true);
2395 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2397 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2398 QVERIFY(object != 0);
2400 QCOMPARE(object->methodCalled(), false);
2401 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2402 QCOMPARE(object->methodCalled(), true);
2408 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2410 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2411 QVERIFY(object != 0);
2413 QCOMPARE(object->methodCalled(), false);
2414 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2415 QCOMPARE(object->methodCalled(), true);
2421 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2423 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2424 QVERIFY(object != 0);
2426 QCOMPARE(object->property("test").toInt(), 0);
2427 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2428 QCOMPARE(object->property("test").toInt(), 2);
2434 void tst_qdeclarativeecmascript::scriptDisconnect()
2437 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2439 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2440 QVERIFY(object != 0);
2442 QCOMPARE(object->property("test").toInt(), 0);
2443 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2444 QCOMPARE(object->property("test").toInt(), 1);
2445 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2446 QCOMPARE(object->property("test").toInt(), 2);
2447 emit object->basicSignal();
2448 QCOMPARE(object->property("test").toInt(), 2);
2449 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2450 QCOMPARE(object->property("test").toInt(), 2);
2456 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2458 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2459 QVERIFY(object != 0);
2461 QCOMPARE(object->property("test").toInt(), 0);
2462 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2463 QCOMPARE(object->property("test").toInt(), 1);
2464 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2465 QCOMPARE(object->property("test").toInt(), 2);
2466 emit object->basicSignal();
2467 QCOMPARE(object->property("test").toInt(), 2);
2468 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2469 QCOMPARE(object->property("test").toInt(), 2);
2475 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2477 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2478 QVERIFY(object != 0);
2480 QCOMPARE(object->property("test").toInt(), 0);
2481 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2482 QCOMPARE(object->property("test").toInt(), 1);
2483 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2484 QCOMPARE(object->property("test").toInt(), 2);
2485 emit object->basicSignal();
2486 QCOMPARE(object->property("test").toInt(), 2);
2487 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2488 QCOMPARE(object->property("test").toInt(), 3);
2493 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2495 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2496 QVERIFY(object != 0);
2498 QCOMPARE(object->property("test").toInt(), 0);
2499 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2500 QCOMPARE(object->property("test").toInt(), 1);
2501 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2502 QCOMPARE(object->property("test").toInt(), 2);
2503 emit object->basicSignal();
2504 QCOMPARE(object->property("test").toInt(), 2);
2505 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2506 QCOMPARE(object->property("test").toInt(), 3);
2512 class OwnershipObject : public QObject
2516 OwnershipObject() { object = new QObject; }
2518 QPointer<QObject> object;
2521 QObject *getObject() { return object; }
2524 void tst_qdeclarativeecmascript::ownership()
2526 OwnershipObject own;
2527 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2528 context->setContextObject(&own);
2531 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2533 QVERIFY(own.object != 0);
2535 QObject *object = component.create(context);
2537 engine.collectGarbage();
2539 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2541 QVERIFY(own.object == 0);
2546 own.object = new QObject(&own);
2549 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2551 QVERIFY(own.object != 0);
2553 QObject *object = component.create(context);
2555 engine.collectGarbage();
2557 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2559 QVERIFY(own.object != 0);
2567 class CppOwnershipReturnValue : public QObject
2571 CppOwnershipReturnValue() : value(0) {}
2572 ~CppOwnershipReturnValue() { delete value; }
2574 Q_INVOKABLE QObject *create() {
2575 value = new QObject;
2576 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2580 Q_INVOKABLE MyQmlObject *createQmlObject() {
2581 MyQmlObject *rv = new MyQmlObject;
2586 QPointer<QObject> value;
2590 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2591 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2593 CppOwnershipReturnValue source;
2596 QDeclarativeEngine engine;
2597 engine.rootContext()->setContextProperty("source", &source);
2599 QVERIFY(source.value == 0);
2601 QDeclarativeComponent component(&engine);
2602 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2604 QObject *object = component.create();
2606 QVERIFY(object != 0);
2607 QVERIFY(source.value != 0);
2612 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2614 QVERIFY(source.value != 0);
2618 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2620 CppOwnershipReturnValue source;
2623 QDeclarativeEngine engine;
2624 engine.rootContext()->setContextProperty("source", &source);
2626 QVERIFY(source.value == 0);
2628 QDeclarativeComponent component(&engine);
2629 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2631 QObject *object = component.create();
2633 QVERIFY(object != 0);
2634 QVERIFY(source.value != 0);
2639 engine.collectGarbage();
2640 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2642 QVERIFY(source.value == 0);
2645 class QListQObjectMethodsObject : public QObject
2649 QListQObjectMethodsObject() {
2650 m_objects.append(new MyQmlObject());
2651 m_objects.append(new MyQmlObject());
2654 ~QListQObjectMethodsObject() {
2655 qDeleteAll(m_objects);
2659 QList<QObject *> getObjects() { return m_objects; }
2662 QList<QObject *> m_objects;
2665 // Tests that returning a QList<QObject*> from a method works
2666 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2668 QListQObjectMethodsObject obj;
2669 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2670 context->setContextObject(&obj);
2672 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2674 QObject *object = component.create(context);
2676 QCOMPARE(object->property("test").toInt(), 2);
2677 QCOMPARE(object->property("test2").toBool(), true);
2684 void tst_qdeclarativeecmascript::strictlyEquals()
2686 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2688 QObject *object = component.create();
2689 QVERIFY(object != 0);
2691 QCOMPARE(object->property("test1").toBool(), true);
2692 QCOMPARE(object->property("test2").toBool(), true);
2693 QCOMPARE(object->property("test3").toBool(), true);
2694 QCOMPARE(object->property("test4").toBool(), true);
2695 QCOMPARE(object->property("test5").toBool(), true);
2696 QCOMPARE(object->property("test6").toBool(), true);
2697 QCOMPARE(object->property("test7").toBool(), true);
2698 QCOMPARE(object->property("test8").toBool(), true);
2703 void tst_qdeclarativeecmascript::compiled()
2705 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2707 QObject *object = component.create();
2708 QVERIFY(object != 0);
2710 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2711 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2712 QCOMPARE(object->property("test3").toBool(), true);
2713 QCOMPARE(object->property("test4").toBool(), false);
2714 QCOMPARE(object->property("test5").toBool(), false);
2715 QCOMPARE(object->property("test6").toBool(), true);
2717 QCOMPARE(object->property("test7").toInt(), 185);
2718 QCOMPARE(object->property("test8").toInt(), 167);
2719 QCOMPARE(object->property("test9").toBool(), true);
2720 QCOMPARE(object->property("test10").toBool(), false);
2721 QCOMPARE(object->property("test11").toBool(), false);
2722 QCOMPARE(object->property("test12").toBool(), true);
2724 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2725 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2726 QCOMPARE(object->property("test15").toBool(), false);
2727 QCOMPARE(object->property("test16").toBool(), true);
2729 QCOMPARE(object->property("test17").toInt(), 5);
2730 QCOMPARE(object->property("test18").toReal(), qreal(176));
2731 QCOMPARE(object->property("test19").toInt(), 7);
2732 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2733 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2734 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2735 QCOMPARE(object->property("test23").toBool(), true);
2736 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2737 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2742 // Test that numbers assigned in bindings as strings work consistently
2743 void tst_qdeclarativeecmascript::numberAssignment()
2745 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2747 QObject *object = component.create();
2748 QVERIFY(object != 0);
2750 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2751 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2752 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2753 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2754 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2756 QCOMPARE(object->property("test5"), QVariant((int)7));
2757 QCOMPARE(object->property("test6"), QVariant((int)7));
2758 QCOMPARE(object->property("test7"), QVariant((int)6));
2759 QCOMPARE(object->property("test8"), QVariant((int)6));
2761 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2762 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2763 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2764 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2769 void tst_qdeclarativeecmascript::propertySplicing()
2771 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2773 QObject *object = component.create();
2774 QVERIFY(object != 0);
2776 QCOMPARE(object->property("test").toBool(), true);
2782 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2784 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2786 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2787 QVERIFY(object != 0);
2789 MyQmlObject::MyType type;
2790 type.value = 0x8971123;
2791 emit object->signalWithUnknownType(type);
2793 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2795 QCOMPARE(result.value, type.value);
2801 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2803 QTest::addColumn<QString>("expression");
2804 QTest::addColumn<QString>("compare");
2806 QString compareStrict("(function(a, b) { return a === b; })");
2807 QTest::newRow("true") << "true" << compareStrict;
2808 QTest::newRow("undefined") << "undefined" << compareStrict;
2809 QTest::newRow("null") << "null" << compareStrict;
2810 QTest::newRow("123") << "123" << compareStrict;
2811 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2813 QString comparePropertiesStrict(
2815 " if (typeof b != 'object')"
2817 " var props = Object.getOwnPropertyNames(b);"
2818 " for (var i = 0; i < props.length; ++i) {"
2819 " var p = props[i];"
2820 " return arguments.callee(a[p], b[p]);"
2823 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2824 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2827 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2829 QFETCH(QString, expression);
2830 QFETCH(QString, compare);
2832 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2833 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2834 QVERIFY(object != 0);
2836 QJSValue value = engine.evaluate(expression);
2837 QVERIFY(!engine.hasUncaughtException());
2838 object->setProperty("expression", expression);
2839 object->setProperty("compare", compare);
2840 object->setProperty("pass", false);
2842 emit object->signalWithVariant(QVariant::fromValue(value));
2843 QVERIFY(object->property("pass").toBool());
2846 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2848 signalWithJSValueInVariant_data();
2851 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2853 QFETCH(QString, expression);
2854 QFETCH(QString, compare);
2856 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2857 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2858 QVERIFY(object != 0);
2861 QJSValue value = engine2.evaluate(expression);
2862 QVERIFY(!engine2.hasUncaughtException());
2863 object->setProperty("expression", expression);
2864 object->setProperty("compare", compare);
2865 object->setProperty("pass", false);
2867 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2868 emit object->signalWithVariant(QVariant::fromValue(value));
2869 QVERIFY(!object->property("pass").toBool());
2872 void tst_qdeclarativeecmascript::moduleApi_data()
2874 QTest::addColumn<QUrl>("testfile");
2875 QTest::addColumn<QString>("errorMessage");
2876 QTest::addColumn<QStringList>("warningMessages");
2877 QTest::addColumn<QStringList>("readProperties");
2878 QTest::addColumn<QVariantList>("readExpectedValues");
2879 QTest::addColumn<QStringList>("writeProperties");
2880 QTest::addColumn<QVariantList>("writeValues");
2881 QTest::addColumn<QStringList>("readBackProperties");
2882 QTest::addColumn<QVariantList>("readBackExpectedValues");
2884 QTest::newRow("qobject, register + read + method")
2885 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2888 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2889 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2890 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2896 QTest::newRow("script, register + read")
2897 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2900 << (QStringList() << "scriptTest")
2901 << (QVariantList() << 13)
2907 QTest::newRow("qobject, caching + read")
2908 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2911 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2912 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2918 QTest::newRow("script, caching + read")
2919 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2922 << (QStringList() << "scriptTest")
2923 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2929 QTest::newRow("qobject, writing + readonly constraints")
2930 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2932 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2933 << (QStringList() << "readOnlyProperty" << "writableProperty")
2934 << (QVariantList() << 20 << 50)
2935 << (QStringList() << "firstProperty" << "writableProperty")
2936 << (QVariantList() << 30 << 30)
2937 << (QStringList() << "readOnlyProperty" << "writableProperty")
2938 << (QVariantList() << 20 << 30);
2940 QTest::newRow("script, writing + readonly constraints")
2941 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
2943 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
2944 << (QStringList() << "readBack" << "unchanged")
2945 << (QVariantList() << 13 << 42)
2946 << (QStringList() << "firstProperty" << "secondProperty")
2947 << (QVariantList() << 30 << 30)
2948 << (QStringList() << "readBack" << "unchanged")
2949 << (QVariantList() << 30 << 42);
2951 QTest::newRow("qobject module API enum values in JS")
2952 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
2955 << (QStringList() << "enumValue" << "enumMethod")
2956 << (QVariantList() << 42 << 30)
2962 QTest::newRow("qobject, invalid major version fail")
2963 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
2964 << QString("QDeclarativeComponent: Component is not ready")
2973 QTest::newRow("qobject, invalid minor version fail")
2974 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
2975 << QString("QDeclarativeComponent: Component is not ready")
2985 void tst_qdeclarativeecmascript::moduleApi()
2987 QFETCH(QUrl, testfile);
2988 QFETCH(QString, errorMessage);
2989 QFETCH(QStringList, warningMessages);
2990 QFETCH(QStringList, readProperties);
2991 QFETCH(QVariantList, readExpectedValues);
2992 QFETCH(QStringList, writeProperties);
2993 QFETCH(QVariantList, writeValues);
2994 QFETCH(QStringList, readBackProperties);
2995 QFETCH(QVariantList, readBackExpectedValues);
2997 QDeclarativeComponent component(&engine, testfile);
2999 if (!errorMessage.isEmpty())
3000 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3002 if (warningMessages.size())
3003 foreach (const QString &warning, warningMessages)
3004 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3006 QObject *object = component.create();
3007 if (!errorMessage.isEmpty()) {
3008 QVERIFY(object == 0);
3010 QVERIFY(object != 0);
3011 for (int i = 0; i < readProperties.size(); ++i)
3012 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3013 for (int i = 0; i < writeProperties.size(); ++i)
3014 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3015 for (int i = 0; i < readBackProperties.size(); ++i)
3016 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3021 void tst_qdeclarativeecmascript::importScripts()
3023 QObject *object = 0;
3025 // first, ensure that the required behaviour works.
3026 QDeclarativeComponent component(&engine, TEST_FILE("jsimport/testImport.qml"));
3027 object = component.create();
3028 QVERIFY(object != 0);
3029 QCOMPARE(object->property("importedScriptStringValue"), QVariant(QString(QLatin1String("Hello, World!"))));
3030 QCOMPARE(object->property("importedScriptFunctionValue"), QVariant(20));
3031 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(19));
3032 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(2));
3035 QDeclarativeComponent componentTwo(&engine, TEST_FILE("jsimport/testImportScoping.qml"));
3036 object = componentTwo.create();
3037 QVERIFY(object != 0);
3038 QCOMPARE(object->property("componentError"), QVariant(5));
3041 // then, ensure that unintended behaviour does not work.
3042 QDeclarativeComponent failOneComponent(&engine, TEST_FILE("jsimportfail/failOne.qml"));
3043 QString expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined");
3044 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
3045 object = failOneComponent.create();
3046 QVERIFY(object != 0);
3047 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
3049 QDeclarativeComponent failTwoComponent(&engine, TEST_FILE("jsimportfail/failTwo.qml"));
3050 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs");
3051 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
3052 object = failTwoComponent.create();
3053 QVERIFY(object != 0);
3054 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
3056 QDeclarativeComponent failThreeComponent(&engine, TEST_FILE("jsimportfail/failThree.qml"));
3057 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined");
3058 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
3059 object = failThreeComponent.create();
3060 QVERIFY(object != 0);
3061 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(false));
3063 QDeclarativeComponent failFourComponent(&engine, TEST_FILE("jsimportfail/failFour.qml"));
3064 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest");
3065 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
3066 object = failFourComponent.create();
3067 QVERIFY(object != 0);
3068 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(0));
3070 QDeclarativeComponent failFiveComponent(&engine, TEST_FILE("jsimportfail/failFive.qml"));
3071 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component");
3072 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
3073 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component");
3074 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
3075 object = failFiveComponent.create();
3076 QVERIFY(object != 0);
3077 QCOMPARE(object->property("componentError"), QVariant(0));
3080 // also, test that importing scripts with .pragma library works as required
3081 QDeclarativeComponent pragmaLibraryComponent(&engine, TEST_FILE("jsimport/testImportPragmaLibrary.qml"));
3082 object = pragmaLibraryComponent.create();
3083 QVERIFY(object != 0);
3084 QCOMPARE(object->property("testValue"), QVariant(31));
3087 // and that .pragma library scripts don't inherit imports from any .qml file
3088 QDeclarativeComponent pragmaLibraryComponentTwo(&engine, TEST_FILE("jsimportfail/testImportPragmaLibrary.qml"));
3089 object = pragmaLibraryComponentTwo.create();
3090 QVERIFY(object != 0);
3091 QCOMPARE(object->property("testValue"), QVariant(0));
3095 void tst_qdeclarativeecmascript::scarceResources()
3097 QPixmap origPixmap(100, 100);
3098 origPixmap.fill(Qt::blue);
3100 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3101 ScarceResourceObject *eo = 0;
3102 QObject *object = 0;
3104 // in the following three cases, the instance created from the component
3105 // has a property which is a copy of the scarce resource; hence, the
3106 // resource should NOT be detached prior to deletion of the object instance,
3107 // unless the resource is destroyed explicitly.
3108 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
3109 object = component.create();
3110 QVERIFY(object != 0);
3111 QVERIFY(object->property("scarceResourceCopy").isValid());
3112 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3113 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3114 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3115 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3118 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3119 object = componentTwo.create();
3120 QVERIFY(object != 0);
3121 QVERIFY(object->property("scarceResourceCopy").isValid());
3122 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3123 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3124 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3125 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3128 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3129 object = componentThree.create();
3130 QVERIFY(object != 0);
3131 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3132 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3133 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3134 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3137 // in the following three cases, no other copy should exist in memory,
3138 // and so it should be detached (unless explicitly preserved).
3139 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3140 object = componentFour.create();
3141 QVERIFY(object != 0);
3142 QVERIFY(object->property("scarceResourceTest").isValid());
3143 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3144 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3145 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3146 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3149 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3150 object = componentFive.create();
3151 QVERIFY(object != 0);
3152 QVERIFY(object->property("scarceResourceTest").isValid());
3153 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3154 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3155 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3156 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3159 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3160 object = componentSix.create();
3161 QVERIFY(object != 0);
3162 QVERIFY(object->property("scarceResourceTest").isValid());
3163 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3164 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3165 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3166 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3169 // test that scarce resources are handled correctly for imports
3170 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3171 object = componentSeven.create();
3172 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3173 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3176 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3177 object = componentEight.create();
3178 QVERIFY(object != 0);
3179 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3180 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3183 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3184 object = componentNine.create();
3185 QVERIFY(object != 0);
3186 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3187 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3188 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3189 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3190 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3191 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3194 // test that scarce resources are handled properly in signal invocation
3195 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3196 object = componentTen.create();
3197 QVERIFY(object != 0);
3198 QObject *srsc = object->findChild<QObject*>("srsc");
3200 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3201 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3202 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3203 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3204 QMetaObject::invokeMethod(srsc, "testSignal");
3205 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3206 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3207 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3208 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3209 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3210 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3211 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3212 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3213 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3214 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3217 // test that scarce resources are handled properly from js functions in qml files
3218 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3219 object = componentEleven.create();
3220 QVERIFY(object != 0);
3221 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3222 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3223 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3224 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3225 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3226 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3227 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3228 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3229 QMetaObject::invokeMethod(object, "releaseScarceResource");
3230 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3231 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3232 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3233 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3236 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3237 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3238 object = componentTwelve.create();
3239 QVERIFY(object != 0);
3240 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3241 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3242 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3243 QString srp_name = object->property("srp_name").toString();
3244 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3245 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3246 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3247 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3248 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3249 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3250 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3254 void tst_qdeclarativeecmascript::propertyChangeSlots()
3256 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3257 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3258 QObject *object = component.create();
3259 QVERIFY(object != 0);
3262 // ensure that invalid property names fail properly.
3263 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3264 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3265 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3266 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3267 object = e1.create();
3268 QVERIFY(object == 0);
3271 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3272 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3273 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3274 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3275 object = e2.create();
3276 QVERIFY(object == 0);
3279 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3280 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3281 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3282 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3283 object = e3.create();
3284 QVERIFY(object == 0);
3287 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3288 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3289 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3290 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3291 object = e4.create();
3292 QVERIFY(object == 0);
3296 // Ensure that QObject type conversion works on binding assignment
3297 void tst_qdeclarativeecmascript::elementAssign()
3299 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3301 QObject *object = component.create();
3302 QVERIFY(object != 0);
3304 QCOMPARE(object->property("test").toBool(), true);
3310 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3312 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3314 QObject *object = component.create();
3315 QVERIFY(object != 0);
3317 QCOMPARE(object->property("test").toBool(), true);
3323 void tst_qdeclarativeecmascript::booleanConversion()
3325 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3327 QObject *object = component.create();
3328 QVERIFY(object != 0);
3330 QCOMPARE(object->property("test_true1").toBool(), true);
3331 QCOMPARE(object->property("test_true2").toBool(), true);
3332 QCOMPARE(object->property("test_true3").toBool(), true);
3333 QCOMPARE(object->property("test_true4").toBool(), true);
3334 QCOMPARE(object->property("test_true5").toBool(), true);
3336 QCOMPARE(object->property("test_false1").toBool(), false);
3337 QCOMPARE(object->property("test_false2").toBool(), false);
3338 QCOMPARE(object->property("test_false3").toBool(), false);
3343 void tst_qdeclarativeecmascript::handleReferenceManagement()
3348 // Linear QObject reference
3349 QDeclarativeEngine hrmEngine;
3350 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3351 QObject *object = component.create();
3352 QVERIFY(object != 0);
3353 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3354 cro->setDtorCount(&dtorCount);
3355 QMetaObject::invokeMethod(object, "createReference");
3356 QMetaObject::invokeMethod(object, "performGc");
3357 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3358 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3360 hrmEngine.collectGarbage();
3361 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3362 QCOMPARE(dtorCount, 3);
3367 // Circular QObject reference
3368 QDeclarativeEngine hrmEngine;
3369 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3370 QObject *object = component.create();
3371 QVERIFY(object != 0);
3372 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3373 cro->setDtorCount(&dtorCount);
3374 QMetaObject::invokeMethod(object, "circularReference");
3375 QMetaObject::invokeMethod(object, "performGc");
3376 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3377 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3379 hrmEngine.collectGarbage();
3380 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3381 QCOMPARE(dtorCount, 3);
3386 // Linear handle reference
3387 QDeclarativeEngine hrmEngine;
3388 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3389 QObject *object = component.create();
3390 QVERIFY(object != 0);
3391 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3393 crh->setDtorCount(&dtorCount);
3394 QMetaObject::invokeMethod(object, "createReference");
3395 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3396 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3397 QVERIFY(first != 0);
3398 QVERIFY(second != 0);
3399 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3400 // now we have to reparent second and make second owned by JS.
3401 second->setParent(0);
3402 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3403 QMetaObject::invokeMethod(object, "performGc");
3404 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3405 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3407 hrmEngine.collectGarbage();
3408 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3409 QCOMPARE(dtorCount, 3);
3414 // Circular handle reference
3415 QDeclarativeEngine hrmEngine;
3416 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3417 QObject *object = component.create();
3418 QVERIFY(object != 0);
3419 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3421 crh->setDtorCount(&dtorCount);
3422 QMetaObject::invokeMethod(object, "circularReference");
3423 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3424 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3425 QVERIFY(first != 0);
3426 QVERIFY(second != 0);
3427 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3428 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3429 // now we have to reparent and change ownership.
3430 first->setParent(0);
3431 second->setParent(0);
3432 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3433 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3434 QMetaObject::invokeMethod(object, "performGc");
3435 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3436 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3438 hrmEngine.collectGarbage();
3439 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3440 QCOMPARE(dtorCount, 3);
3445 // multiple engine interaction - linear reference
3446 QDeclarativeEngine hrmEngine1;
3447 QDeclarativeEngine hrmEngine2;
3448 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3449 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3450 QObject *object1 = component1.create();
3451 QObject *object2 = component2.create();
3452 QVERIFY(object1 != 0);
3453 QVERIFY(object2 != 0);
3454 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3455 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3458 crh1->setDtorCount(&dtorCount);
3459 crh2->setDtorCount(&dtorCount);
3460 QMetaObject::invokeMethod(object1, "createReference");
3461 QMetaObject::invokeMethod(object2, "createReference");
3462 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3463 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3464 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3465 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3466 QVERIFY(first1 != 0);
3467 QVERIFY(second1 != 0);
3468 QVERIFY(first2 != 0);
3469 QVERIFY(second2 != 0);
3470 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3471 // now we have to reparent second2 and make second2 owned by JS.
3472 second2->setParent(0);
3473 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3474 QMetaObject::invokeMethod(object1, "performGc");
3475 QMetaObject::invokeMethod(object2, "performGc");
3476 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3477 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3480 hrmEngine1.collectGarbage();
3481 hrmEngine2.collectGarbage();
3482 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3483 QCOMPARE(dtorCount, 6);
3488 // multiple engine interaction - circular reference
3489 QDeclarativeEngine hrmEngine1;
3490 QDeclarativeEngine hrmEngine2;
3491 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3492 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3493 QObject *object1 = component1.create();
3494 QObject *object2 = component2.create();
3495 QVERIFY(object1 != 0);
3496 QVERIFY(object2 != 0);
3497 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3498 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3501 crh1->setDtorCount(&dtorCount);
3502 crh2->setDtorCount(&dtorCount);
3503 QMetaObject::invokeMethod(object1, "createReference");
3504 QMetaObject::invokeMethod(object2, "createReference");
3505 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3506 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3507 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3508 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3509 QVERIFY(first1 != 0);
3510 QVERIFY(second1 != 0);
3511 QVERIFY(first2 != 0);
3512 QVERIFY(second2 != 0);
3513 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3514 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3515 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3516 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3517 // now we have to reparent and change ownership to JS.
3518 first1->setParent(0);
3519 second1->setParent(0);
3520 first2->setParent(0);
3521 second2->setParent(0);
3522 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
3523 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3524 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3525 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3526 QMetaObject::invokeMethod(object1, "performGc");
3527 QMetaObject::invokeMethod(object2, "performGc");
3528 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3529 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
3532 hrmEngine1.collectGarbage();
3533 hrmEngine2.collectGarbage();
3534 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3535 QCOMPARE(dtorCount, 6);
3540 // multiple engine interaction - linear reference with engine deletion
3541 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
3542 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
3543 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3544 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3545 QObject *object1 = component1.create();
3546 QObject *object2 = component2.create();
3547 QVERIFY(object1 != 0);
3548 QVERIFY(object2 != 0);
3549 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3550 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3553 crh1->setDtorCount(&dtorCount);
3554 crh2->setDtorCount(&dtorCount);
3555 QMetaObject::invokeMethod(object1, "createReference");
3556 QMetaObject::invokeMethod(object2, "createReference");
3557 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3558 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3559 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3560 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3561 QVERIFY(first1 != 0);
3562 QVERIFY(second1 != 0);
3563 QVERIFY(first2 != 0);
3564 QVERIFY(second2 != 0);
3565 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3566 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3567 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3568 // now we have to reparent and change ownership to JS.
3569 first1->setParent(crh1);
3570 second1->setParent(0);
3571 first2->setParent(0);
3572 second2->setParent(0);
3573 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3574 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3575 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3576 QMetaObject::invokeMethod(object1, "performGc");
3577 QMetaObject::invokeMethod(object2, "performGc");
3578 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3579 QCOMPARE(dtorCount, 0);
3581 QMetaObject::invokeMethod(object1, "performGc");
3582 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3583 QCOMPARE(dtorCount, 0);
3586 hrmEngine1->collectGarbage();
3587 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3588 QCOMPARE(dtorCount, 6);
3593 void tst_qdeclarativeecmascript::stringArg()
3595 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
3596 QObject *object = component.create();
3597 QVERIFY(object != 0);
3598 QMetaObject::invokeMethod(object, "success");
3599 QVERIFY(object->property("returnValue").toBool());
3601 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
3602 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
3603 QMetaObject::invokeMethod(object, "failure");
3604 QVERIFY(object->property("returnValue").toBool());
3609 // Test that assigning a null object works
3610 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
3611 void tst_qdeclarativeecmascript::nullObjectBinding()
3613 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
3615 QObject *object = component.create();
3616 QVERIFY(object != 0);
3618 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
3623 // Test that bindings don't evaluate once the engine has been destroyed
3624 void tst_qdeclarativeecmascript::deletedEngine()
3626 QDeclarativeEngine *engine = new QDeclarativeEngine;
3627 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
3629 QObject *object = component.create();
3630 QVERIFY(object != 0);
3632 QCOMPARE(object->property("a").toInt(), 39);
3633 object->setProperty("b", QVariant(9));
3634 QCOMPARE(object->property("a").toInt(), 117);
3638 QCOMPARE(object->property("a").toInt(), 117);
3639 object->setProperty("b", QVariant(10));
3640 QCOMPARE(object->property("a").toInt(), 117);
3645 // Test the crashing part of QTBUG-9705
3646 void tst_qdeclarativeecmascript::libraryScriptAssert()
3648 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
3650 QObject *object = component.create();
3651 QVERIFY(object != 0);
3656 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
3658 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
3660 QObject *object = component.create();
3661 QVERIFY(object != 0);
3663 QCOMPARE(object->property("test1").toInt(), 10);
3664 QCOMPARE(object->property("test2").toInt(), 11);
3666 object->setProperty("runTest", true);
3668 QCOMPARE(object->property("test1"), QVariant());
3669 QCOMPARE(object->property("test2"), QVariant());
3675 void tst_qdeclarativeecmascript::qtbug_9792()
3677 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
3679 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
3681 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
3682 QVERIFY(object != 0);
3684 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
3685 object->basicSignal();
3689 transientErrorsMsgCount = 0;
3690 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3692 object->basicSignal();
3694 qInstallMsgHandler(old);
3696 QCOMPARE(transientErrorsMsgCount, 0);
3701 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
3702 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
3704 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
3706 QObject *o = component.create();
3709 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
3710 QVERIFY(nested != 0);
3712 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
3715 nested = qvariant_cast<QObject *>(o->property("object"));
3716 QVERIFY(nested == 0);
3718 // If the bug is present, the next line will crash
3722 // Test that we shut down without stupid warnings
3723 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
3726 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
3728 QObject *o = component.create();
3730 transientErrorsMsgCount = 0;
3731 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3735 qInstallMsgHandler(old);
3737 QCOMPARE(transientErrorsMsgCount, 0);
3742 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
3744 QObject *o = component.create();
3746 transientErrorsMsgCount = 0;
3747 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3751 qInstallMsgHandler(old);
3753 QCOMPARE(transientErrorsMsgCount, 0);
3757 void tst_qdeclarativeecmascript::canAssignNullToQObject()
3760 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
3762 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3765 QVERIFY(o->objectProperty() != 0);
3767 o->setProperty("runTest", true);
3769 QVERIFY(o->objectProperty() == 0);
3775 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
3777 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3780 QVERIFY(o->objectProperty() == 0);
3786 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
3788 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
3790 QString url = component.url().toString();
3791 QString warning = url + ":4: Unable to assign a function to a property.";
3792 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3794 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3797 QVERIFY(!o->property("a").isValid());
3802 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
3804 QFETCH(QString, triggerProperty);
3806 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3807 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3809 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3811 QVERIFY(!o->property("a").isValid());
3813 o->setProperty("aNumber", QVariant(5));
3814 o->setProperty(triggerProperty.toUtf8().constData(), true);
3815 QCOMPARE(o->property("a"), QVariant(50));
3817 o->setProperty("aNumber", QVariant(10));
3818 QCOMPARE(o->property("a"), QVariant(100));
3823 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
3825 QTest::addColumn<QString>("triggerProperty");
3827 QTest::newRow("assign to property") << "assignToProperty";
3828 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
3830 QTest::newRow("assign to value type") << "assignToValueType";
3832 QTest::newRow("use 'this'") << "assignWithThis";
3833 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
3836 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
3838 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3839 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3841 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3843 QVERIFY(!o->property("a").isValid());
3845 o->setProperty("assignFuncWithoutReturn", true);
3846 QVERIFY(!o->property("a").isValid());
3848 QString url = component.url().toString();
3849 QString warning = url + ":67: Unable to assign QString to int";
3850 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3851 o->setProperty("assignWrongType", true);
3853 warning = url + ":71: Unable to assign QString to int";
3854 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3855 o->setProperty("assignWrongTypeToValueType", true);
3860 void tst_qdeclarativeecmascript::eval()
3862 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
3864 QObject *o = component.create();
3867 QCOMPARE(o->property("test1").toBool(), true);
3868 QCOMPARE(o->property("test2").toBool(), true);
3869 QCOMPARE(o->property("test3").toBool(), true);
3870 QCOMPARE(o->property("test4").toBool(), true);
3871 QCOMPARE(o->property("test5").toBool(), true);
3876 void tst_qdeclarativeecmascript::function()
3878 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
3880 QObject *o = component.create();
3883 QCOMPARE(o->property("test1").toBool(), true);
3884 QCOMPARE(o->property("test2").toBool(), true);
3885 QCOMPARE(o->property("test3").toBool(), true);
3890 // Test the "Qt.include" method
3891 void tst_qdeclarativeecmascript::include()
3893 // Non-library relative include
3895 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
3896 QObject *o = component.create();
3899 QCOMPARE(o->property("test0").toInt(), 99);
3900 QCOMPARE(o->property("test1").toBool(), true);
3901 QCOMPARE(o->property("test2").toBool(), true);
3902 QCOMPARE(o->property("test2_1").toBool(), true);
3903 QCOMPARE(o->property("test3").toBool(), true);
3904 QCOMPARE(o->property("test3_1").toBool(), true);
3909 // Library relative include
3911 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
3912 QObject *o = component.create();
3915 QCOMPARE(o->property("test0").toInt(), 99);
3916 QCOMPARE(o->property("test1").toBool(), true);
3917 QCOMPARE(o->property("test2").toBool(), true);
3918 QCOMPARE(o->property("test2_1").toBool(), true);
3919 QCOMPARE(o->property("test3").toBool(), true);
3920 QCOMPARE(o->property("test3_1").toBool(), true);
3927 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
3928 QObject *o = component.create();
3931 QCOMPARE(o->property("test1").toBool(), true);
3932 QCOMPARE(o->property("test2").toBool(), true);
3933 QCOMPARE(o->property("test3").toBool(), true);
3934 QCOMPARE(o->property("test4").toBool(), true);
3935 QCOMPARE(o->property("test5").toBool(), true);
3936 QCOMPARE(o->property("test6").toBool(), true);
3941 // Including file with ".pragma library"
3943 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
3944 QObject *o = component.create();
3946 QCOMPARE(o->property("test1").toInt(), 100);
3953 TestHTTPServer server(8111);
3954 QVERIFY(server.isValid());
3955 server.serveDirectory(SRCDIR "/data");
3957 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
3958 QObject *o = component.create();
3961 QTRY_VERIFY(o->property("done").toBool() == true);
3962 QTRY_VERIFY(o->property("done2").toBool() == true);
3964 QCOMPARE(o->property("test1").toBool(), true);
3965 QCOMPARE(o->property("test2").toBool(), true);
3966 QCOMPARE(o->property("test3").toBool(), true);
3967 QCOMPARE(o->property("test4").toBool(), true);
3968 QCOMPARE(o->property("test5").toBool(), true);
3970 QCOMPARE(o->property("test6").toBool(), true);
3971 QCOMPARE(o->property("test7").toBool(), true);
3972 QCOMPARE(o->property("test8").toBool(), true);
3973 QCOMPARE(o->property("test9").toBool(), true);
3974 QCOMPARE(o->property("test10").toBool(), true);
3981 TestHTTPServer server(8111);
3982 QVERIFY(server.isValid());
3983 server.serveDirectory(SRCDIR "/data");
3985 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
3986 QObject *o = component.create();
3989 QTRY_VERIFY(o->property("done").toBool() == true);
3991 QCOMPARE(o->property("test1").toBool(), true);
3992 QCOMPARE(o->property("test2").toBool(), true);
3993 QCOMPARE(o->property("test3").toBool(), true);
3999 void tst_qdeclarativeecmascript::signalHandlers()
4001 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
4002 QObject *o = component.create();
4005 QVERIFY(o->property("count").toInt() == 0);
4006 QMetaObject::invokeMethod(o, "testSignalCall");
4007 QCOMPARE(o->property("count").toInt(), 1);
4009 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
4010 QCOMPARE(o->property("count").toInt(), 1);
4011 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
4013 QVERIFY(o->property("funcCount").toInt() == 0);
4014 QMetaObject::invokeMethod(o, "testSignalConnection");
4015 QCOMPARE(o->property("funcCount").toInt(), 1);
4017 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
4018 QCOMPARE(o->property("funcCount").toInt(), 2);
4020 QMetaObject::invokeMethod(o, "testSignalDefined");
4021 QCOMPARE(o->property("definedResult").toBool(), true);
4023 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
4024 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
4029 void tst_qdeclarativeecmascript::qtbug_10696()
4031 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
4032 QObject *o = component.create();
4037 void tst_qdeclarativeecmascript::qtbug_11606()
4039 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
4040 QObject *o = component.create();
4042 QCOMPARE(o->property("test").toBool(), true);
4046 void tst_qdeclarativeecmascript::qtbug_11600()
4048 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
4049 QObject *o = component.create();
4051 QCOMPARE(o->property("test").toBool(), true);
4055 // Reading and writing non-scriptable properties should fail
4056 void tst_qdeclarativeecmascript::nonscriptable()
4058 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
4059 QObject *o = component.create();
4061 QCOMPARE(o->property("readOk").toBool(), true);
4062 QCOMPARE(o->property("writeOk").toBool(), true);
4066 // deleteLater() should not be callable from QML
4067 void tst_qdeclarativeecmascript::deleteLater()
4069 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
4070 QObject *o = component.create();
4072 QCOMPARE(o->property("test").toBool(), true);
4076 void tst_qdeclarativeecmascript::in()
4078 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
4079 QObject *o = component.create();
4081 QCOMPARE(o->property("test1").toBool(), true);
4082 QCOMPARE(o->property("test2").toBool(), true);
4086 void tst_qdeclarativeecmascript::sharedAttachedObject()
4088 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
4089 QObject *o = component.create();
4091 QCOMPARE(o->property("test1").toBool(), true);
4092 QCOMPARE(o->property("test2").toBool(), true);
4097 void tst_qdeclarativeecmascript::objectName()
4099 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
4100 QObject *o = component.create();
4103 QCOMPARE(o->property("test1").toString(), QString("hello"));
4104 QCOMPARE(o->property("test2").toString(), QString("ell"));
4106 o->setObjectName("world");
4108 QCOMPARE(o->property("test1").toString(), QString("world"));
4109 QCOMPARE(o->property("test2").toString(), QString("orl"));
4114 void tst_qdeclarativeecmascript::writeRemovesBinding()
4116 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
4117 QObject *o = component.create();
4120 QCOMPARE(o->property("test").toBool(), true);
4125 // Test bindings assigned to alias properties actually assign to the alias' target
4126 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
4128 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4129 QObject *o = component.create();
4132 QCOMPARE(o->property("test").toBool(), true);
4137 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4138 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4141 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4142 QObject *o = component.create();
4145 QCOMPARE(o->property("test").toBool(), true);
4151 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4152 QObject *o = component.create();
4155 QCOMPARE(o->property("test").toBool(), true);
4161 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4162 QObject *o = component.create();
4165 QCOMPARE(o->property("test").toBool(), true);
4171 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4172 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4175 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4176 QObject *o = component.create();
4179 QCOMPARE(o->property("test").toBool(), true);
4185 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
4186 QObject *o = component.create();
4189 QCOMPARE(o->property("test").toBool(), true);
4195 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
4196 QObject *o = component.create();
4199 QCOMPARE(o->property("test").toBool(), true);
4205 // Allow an alais to a composite element
4207 void tst_qdeclarativeecmascript::aliasToCompositeElement()
4209 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
4211 QObject *object = component.create();
4212 QVERIFY(object != 0);
4217 void tst_qdeclarativeecmascript::revisionErrors()
4220 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
4221 QString url = component.url().toString();
4223 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4224 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
4225 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
4227 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4228 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4229 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4230 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4231 QVERIFY(object != 0);
4235 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
4236 QString url = component.url().toString();
4238 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
4239 // method2, prop2 from MyRevisionedClass not available
4240 // method4, prop4 from MyRevisionedSubclass not available
4241 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4242 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
4243 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
4244 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
4245 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
4247 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4248 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4249 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4250 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
4251 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
4252 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4253 QVERIFY(object != 0);
4257 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
4258 QString url = component.url().toString();
4260 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
4261 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
4262 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
4263 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
4264 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
4265 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4266 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4267 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4268 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4269 QVERIFY(object != 0);
4274 void tst_qdeclarativeecmascript::revision()
4277 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
4278 QString url = component.url().toString();
4280 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4281 QVERIFY(object != 0);
4285 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
4286 QString url = component.url().toString();
4288 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4289 QVERIFY(object != 0);
4293 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
4294 QString url = component.url().toString();
4296 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4297 QVERIFY(object != 0);
4300 // Test that non-root classes can resolve revisioned methods
4302 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
4304 QObject *object = component.create();
4305 QVERIFY(object != 0);
4306 QCOMPARE(object->property("test").toReal(), 11.);
4311 void tst_qdeclarativeecmascript::realToInt()
4313 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
4314 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
4315 QVERIFY(object != 0);
4317 QMetaObject::invokeMethod(object, "test1");
4318 QCOMPARE(object->value(), int(4));
4319 QMetaObject::invokeMethod(object, "test2");
4320 QCOMPARE(object->value(), int(8));
4322 void tst_qdeclarativeecmascript::dynamicString()
4324 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
4325 QObject *object = component.create();
4326 QVERIFY(object != 0);
4327 QCOMPARE(object->property("stringProperty").toString(),
4328 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
4331 void tst_qdeclarativeecmascript::automaticSemicolon()
4333 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
4334 QObject *object = component.create();
4335 QVERIFY(object != 0);
4338 QTEST_MAIN(tst_qdeclarativeecmascript)
4340 #include "tst_qdeclarativeecmascript.moc"