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 This test covers evaluation of ECMAScript expressions and bindings from within
58 QML. This does not include static QML language issues.
60 Static QML language issues are covered in qmllanguage
62 inline QUrl TEST_FILE(const QString &filename)
64 QFileInfo fileInfo(__FILE__);
65 return QUrl::fromLocalFile(fileInfo.absoluteDir().filePath("data/" + filename));
68 inline QUrl TEST_FILE(const char *filename)
70 return TEST_FILE(QLatin1String(filename));
73 class tst_qdeclarativeecmascript : public QObject
77 tst_qdeclarativeecmascript() {}
81 void assignBasicTypes();
82 void idShortcutInvalidates();
83 void boolPropertiesEvaluateAsBool();
85 void signalAssignment();
87 void basicExpressions();
88 void basicExpressions_data();
89 void arrayExpressions();
90 void contextPropertiesTriggerReeval();
91 void objectPropertiesTriggerReeval();
92 void deferredProperties();
93 void deferredPropertiesErrors();
94 void extensionObjects();
95 void overrideExtensionProperties();
96 void attachedProperties();
98 void valueTypeFunctions();
99 void constantsOverrideBindings();
100 void outerBindingOverridesInnerBinding();
101 void aliasPropertyAndBinding();
102 void aliasPropertyReset();
103 void nonExistentAttachedObject();
106 void signalParameterTypes();
107 void objectsCompareAsEqual();
108 void dynamicCreation_data();
109 void dynamicCreation();
110 void dynamicDestruction();
111 void objectToString();
112 void objectHasOwnProperty();
113 void selfDeletingBinding();
114 void extendedObjectPropertyLookup();
116 void functionErrors();
117 void propertyAssignmentErrors();
118 void signalTriggeredBindings();
119 void listProperties();
120 void exceptionClearsOnReeval();
121 void exceptionSlotProducesWarning();
122 void exceptionBindingProducesWarning();
123 void transientErrors();
124 void shutdownErrors();
125 void compositePropertyType();
127 void undefinedResetsProperty();
128 void listToVariant();
129 void listAssignment();
130 void multiEngineObject();
131 void deletedObject();
132 void attachedPropertyScope();
133 void scriptConnect();
134 void scriptDisconnect();
136 void cppOwnershipReturnValue();
137 void ownershipCustomReturnValue();
138 void qlistqobjectMethods();
139 void strictlyEquals();
141 void numberAssignment();
142 void propertySplicing();
143 void signalWithUnknownTypes();
144 void signalWithJSValueInVariant_data();
145 void signalWithJSValueInVariant();
146 void signalWithJSValueInVariant_twoEngines_data();
147 void signalWithJSValueInVariant_twoEngines();
148 void moduleApi_data();
150 void importScripts();
151 void scarceResources();
152 void propertyChangeSlots();
153 void elementAssign();
154 void objectPassThroughSignals();
155 void booleanConversion();
156 void handleReferenceManagement();
161 void dynamicCreationCrash();
162 void dynamicCreationOwnership();
164 void nullObjectBinding();
165 void deletedEngine();
166 void libraryScriptAssert();
167 void variantsAssignedUndefined();
169 void qtcreatorbug_1289();
170 void noSpuriousWarningsAtShutdown();
171 void canAssignNullToQObject();
172 void functionAssignment_fromBinding();
173 void functionAssignment_fromJS();
174 void functionAssignment_fromJS_data();
175 void functionAssignmentfromJS_invalid();
181 void nonscriptable();
184 void sharedAttachedObject();
186 void writeRemovesBinding();
187 void aliasBindingsAssignCorrectly();
188 void aliasBindingsOverrideTarget();
189 void aliasWritesOverrideBindings();
190 void aliasToCompositeElement();
192 void dynamicString();
194 void signalHandlers();
196 void callQtInvokables();
197 void invokableObjectArg();
198 void invokableObjectRet();
200 void revisionErrors();
203 void automaticSemicolon();
206 QDeclarativeEngine engine;
209 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
211 void tst_qdeclarativeecmascript::assignBasicTypes()
214 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
215 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
216 QVERIFY(object != 0);
217 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
218 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
219 QCOMPARE(object->stringProperty(), QString("Hello World!"));
220 QCOMPARE(object->uintProperty(), uint(10));
221 QCOMPARE(object->intProperty(), -19);
222 QCOMPARE((float)object->realProperty(), float(23.2));
223 QCOMPARE((float)object->doubleProperty(), float(-19.75));
224 QCOMPARE((float)object->floatProperty(), float(8.5));
225 QCOMPARE(object->colorProperty(), QColor("red"));
226 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
227 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
228 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
229 QCOMPARE(object->pointProperty(), QPoint(99,13));
230 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
231 QCOMPARE(object->sizeProperty(), QSize(99, 13));
232 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
233 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
234 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
235 QCOMPARE(object->boolProperty(), true);
236 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
237 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
238 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
242 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
243 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
244 QVERIFY(object != 0);
245 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
246 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
247 QCOMPARE(object->stringProperty(), QString("Hello World!"));
248 QCOMPARE(object->uintProperty(), uint(10));
249 QCOMPARE(object->intProperty(), -19);
250 QCOMPARE((float)object->realProperty(), float(23.2));
251 QCOMPARE((float)object->doubleProperty(), float(-19.75));
252 QCOMPARE((float)object->floatProperty(), float(8.5));
253 QCOMPARE(object->colorProperty(), QColor("red"));
254 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
255 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
256 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
257 QCOMPARE(object->pointProperty(), QPoint(99,13));
258 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
259 QCOMPARE(object->sizeProperty(), QSize(99, 13));
260 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
261 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
262 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
263 QCOMPARE(object->boolProperty(), true);
264 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
265 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
266 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
271 void tst_qdeclarativeecmascript::idShortcutInvalidates()
274 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
275 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
276 QVERIFY(object != 0);
277 QVERIFY(object->objectProperty() != 0);
278 delete object->objectProperty();
279 QVERIFY(object->objectProperty() == 0);
284 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
285 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
286 QVERIFY(object != 0);
287 QVERIFY(object->objectProperty() != 0);
288 delete object->objectProperty();
289 QVERIFY(object->objectProperty() == 0);
294 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
297 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
298 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
299 QVERIFY(object != 0);
300 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
304 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
305 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
306 QVERIFY(object != 0);
307 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
312 void tst_qdeclarativeecmascript::signalAssignment()
315 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
316 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
317 QVERIFY(object != 0);
318 QCOMPARE(object->string(), QString());
319 emit object->basicSignal();
320 QCOMPARE(object->string(), QString("pass"));
325 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
326 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
327 QVERIFY(object != 0);
328 QCOMPARE(object->string(), QString());
329 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
330 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
335 void tst_qdeclarativeecmascript::methods()
338 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
339 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
340 QVERIFY(object != 0);
341 QCOMPARE(object->methodCalled(), false);
342 QCOMPARE(object->methodIntCalled(), false);
343 emit object->basicSignal();
344 QCOMPARE(object->methodCalled(), true);
345 QCOMPARE(object->methodIntCalled(), false);
350 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
351 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
352 QVERIFY(object != 0);
353 QCOMPARE(object->methodCalled(), false);
354 QCOMPARE(object->methodIntCalled(), false);
355 emit object->basicSignal();
356 QCOMPARE(object->methodCalled(), false);
357 QCOMPARE(object->methodIntCalled(), true);
362 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
363 QObject *object = component.create();
364 QVERIFY(object != 0);
365 QCOMPARE(object->property("test").toInt(), 19);
370 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
371 QObject *object = component.create();
372 QVERIFY(object != 0);
373 QCOMPARE(object->property("test").toInt(), 19);
374 QCOMPARE(object->property("test2").toInt(), 17);
375 QCOMPARE(object->property("test3").toInt(), 16);
380 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
381 QObject *object = component.create();
382 QVERIFY(object != 0);
383 QCOMPARE(object->property("test").toInt(), 9);
388 void tst_qdeclarativeecmascript::bindingLoop()
390 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
391 QString warning = component.url().toString() + ":9:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
392 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
393 QObject *object = component.create();
394 QVERIFY(object != 0);
398 void tst_qdeclarativeecmascript::basicExpressions_data()
400 QTest::addColumn<QString>("expression");
401 QTest::addColumn<QVariant>("result");
402 QTest::addColumn<bool>("nest");
404 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
405 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
406 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
407 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
408 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
409 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
410 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
411 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
412 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
413 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
414 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
415 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
416 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
417 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
418 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
419 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
420 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
421 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
422 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
425 void tst_qdeclarativeecmascript::basicExpressions()
427 QFETCH(QString, expression);
428 QFETCH(QVariant, result);
434 MyDefaultObject1 default1;
435 MyDefaultObject3 default3;
436 object1.setStringProperty("Object1");
437 object2.setStringProperty("Object2");
438 object3.setStringProperty("Object3");
440 QDeclarativeContext context(engine.rootContext());
441 QDeclarativeContext nestedContext(&context);
443 context.setContextObject(&default1);
444 context.setContextProperty("a", QVariant(1944));
445 context.setContextProperty("b", QVariant("Milk"));
446 context.setContextProperty("object", &object1);
447 context.setContextProperty("objectOverride", &object2);
448 nestedContext.setContextObject(&default3);
449 nestedContext.setContextProperty("b", QVariant("Cow"));
450 nestedContext.setContextProperty("objectOverride", &object3);
451 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
453 MyExpression expr(nest?&nestedContext:&context, expression);
454 QCOMPARE(expr.evaluate(), result);
457 void tst_qdeclarativeecmascript::arrayExpressions()
463 QDeclarativeContext context(engine.rootContext());
464 context.setContextProperty("a", &obj1);
465 context.setContextProperty("b", &obj2);
466 context.setContextProperty("c", &obj3);
468 MyExpression expr(&context, "[a, b, c, 10]");
469 QVariant result = expr.evaluate();
470 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
471 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
472 QCOMPARE(list.count(), 4);
473 QCOMPARE(list.at(0), &obj1);
474 QCOMPARE(list.at(1), &obj2);
475 QCOMPARE(list.at(2), &obj3);
476 QCOMPARE(list.at(3), (QObject *)0);
479 // Tests that modifying a context property will reevaluate expressions
480 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
482 QDeclarativeContext context(engine.rootContext());
485 MyQmlObject *object3 = new MyQmlObject;
487 object1.setStringProperty("Hello");
488 object2.setStringProperty("World");
490 context.setContextProperty("testProp", QVariant(1));
491 context.setContextProperty("testObj", &object1);
492 context.setContextProperty("testObj2", object3);
495 MyExpression expr(&context, "testProp + 1");
496 QCOMPARE(expr.changed, false);
497 QCOMPARE(expr.evaluate(), QVariant(2));
499 context.setContextProperty("testProp", QVariant(2));
500 QCOMPARE(expr.changed, true);
501 QCOMPARE(expr.evaluate(), QVariant(3));
505 MyExpression expr(&context, "testProp + testProp + testProp");
506 QCOMPARE(expr.changed, false);
507 QCOMPARE(expr.evaluate(), QVariant(6));
509 context.setContextProperty("testProp", QVariant(4));
510 QCOMPARE(expr.changed, true);
511 QCOMPARE(expr.evaluate(), QVariant(12));
515 MyExpression expr(&context, "testObj.stringProperty");
516 QCOMPARE(expr.changed, false);
517 QCOMPARE(expr.evaluate(), QVariant("Hello"));
519 context.setContextProperty("testObj", &object2);
520 QCOMPARE(expr.changed, true);
521 QCOMPARE(expr.evaluate(), QVariant("World"));
525 MyExpression expr(&context, "testObj.stringProperty /**/");
526 QCOMPARE(expr.changed, false);
527 QCOMPARE(expr.evaluate(), QVariant("World"));
529 context.setContextProperty("testObj", &object1);
530 QCOMPARE(expr.changed, true);
531 QCOMPARE(expr.evaluate(), QVariant("Hello"));
535 MyExpression expr(&context, "testObj2");
536 QCOMPARE(expr.changed, false);
537 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
543 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
545 QDeclarativeContext context(engine.rootContext());
549 context.setContextProperty("testObj", &object1);
551 object1.setStringProperty(QLatin1String("Hello"));
552 object2.setStringProperty(QLatin1String("Dog"));
553 object3.setStringProperty(QLatin1String("Cat"));
556 MyExpression expr(&context, "testObj.stringProperty");
557 QCOMPARE(expr.changed, false);
558 QCOMPARE(expr.evaluate(), QVariant("Hello"));
560 object1.setStringProperty(QLatin1String("World"));
561 QCOMPARE(expr.changed, true);
562 QCOMPARE(expr.evaluate(), QVariant("World"));
566 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
567 QCOMPARE(expr.changed, false);
568 QCOMPARE(expr.evaluate(), QVariant());
570 object1.setObjectProperty(&object2);
571 QCOMPARE(expr.changed, true);
572 expr.changed = false;
573 QCOMPARE(expr.evaluate(), QVariant("Dog"));
575 object1.setObjectProperty(&object3);
576 QCOMPARE(expr.changed, true);
577 expr.changed = false;
578 QCOMPARE(expr.evaluate(), QVariant("Cat"));
580 object1.setObjectProperty(0);
581 QCOMPARE(expr.changed, true);
582 expr.changed = false;
583 QCOMPARE(expr.evaluate(), QVariant());
585 object1.setObjectProperty(&object3);
586 QCOMPARE(expr.changed, true);
587 expr.changed = false;
588 QCOMPARE(expr.evaluate(), QVariant("Cat"));
590 object3.setStringProperty("Donkey");
591 QCOMPARE(expr.changed, true);
592 expr.changed = false;
593 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
597 void tst_qdeclarativeecmascript::deferredProperties()
599 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
600 MyDeferredObject *object =
601 qobject_cast<MyDeferredObject *>(component.create());
602 QVERIFY(object != 0);
603 QCOMPARE(object->value(), 0);
604 QVERIFY(object->objectProperty() == 0);
605 QVERIFY(object->objectProperty2() != 0);
606 qmlExecuteDeferred(object);
607 QCOMPARE(object->value(), 10);
608 QVERIFY(object->objectProperty() != 0);
609 MyQmlObject *qmlObject =
610 qobject_cast<MyQmlObject *>(object->objectProperty());
611 QVERIFY(qmlObject != 0);
612 QCOMPARE(qmlObject->value(), 10);
613 object->setValue(19);
614 QCOMPARE(qmlObject->value(), 19);
619 // Check errors on deferred properties are correctly emitted
620 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
622 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
623 MyDeferredObject *object =
624 qobject_cast<MyDeferredObject *>(component.create());
625 QVERIFY(object != 0);
626 QCOMPARE(object->value(), 0);
627 QVERIFY(object->objectProperty() == 0);
628 QVERIFY(object->objectProperty2() == 0);
630 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject* objectProperty";
631 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
633 qmlExecuteDeferred(object);
638 void tst_qdeclarativeecmascript::extensionObjects()
640 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
641 MyExtendedObject *object =
642 qobject_cast<MyExtendedObject *>(component.create());
643 QVERIFY(object != 0);
644 QCOMPARE(object->baseProperty(), 13);
645 QCOMPARE(object->coreProperty(), 9);
646 object->setProperty("extendedProperty", QVariant(11));
647 object->setProperty("baseExtendedProperty", QVariant(92));
648 QCOMPARE(object->coreProperty(), 11);
649 QCOMPARE(object->baseProperty(), 92);
651 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
653 QCOMPARE(nested->baseProperty(), 13);
654 QCOMPARE(nested->coreProperty(), 9);
655 nested->setProperty("extendedProperty", QVariant(11));
656 nested->setProperty("baseExtendedProperty", QVariant(92));
657 QCOMPARE(nested->coreProperty(), 11);
658 QCOMPARE(nested->baseProperty(), 92);
663 void tst_qdeclarativeecmascript::overrideExtensionProperties()
665 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
666 OverrideDefaultPropertyObject *object =
667 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
668 QVERIFY(object != 0);
669 QVERIFY(object->secondProperty() != 0);
670 QVERIFY(object->firstProperty() == 0);
675 void tst_qdeclarativeecmascript::attachedProperties()
678 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
679 QObject *object = component.create();
680 QVERIFY(object != 0);
681 QCOMPARE(object->property("a").toInt(), 19);
682 QCOMPARE(object->property("b").toInt(), 19);
683 QCOMPARE(object->property("c").toInt(), 19);
684 QCOMPARE(object->property("d").toInt(), 19);
689 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
690 QObject *object = component.create();
691 QVERIFY(object != 0);
692 QCOMPARE(object->property("a").toInt(), 26);
693 QCOMPARE(object->property("b").toInt(), 26);
694 QCOMPARE(object->property("c").toInt(), 26);
695 QCOMPARE(object->property("d").toInt(), 26);
701 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
702 QObject *object = component.create();
703 QVERIFY(object != 0);
705 QMetaObject::invokeMethod(object, "writeValue2");
707 MyQmlAttachedObject *attached =
708 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
709 QVERIFY(attached != 0);
711 QCOMPARE(attached->value2(), 9);
716 void tst_qdeclarativeecmascript::enums()
720 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
721 QObject *object = component.create();
722 QVERIFY(object != 0);
724 QCOMPARE(object->property("a").toInt(), 0);
725 QCOMPARE(object->property("b").toInt(), 1);
726 QCOMPARE(object->property("c").toInt(), 2);
727 QCOMPARE(object->property("d").toInt(), 3);
728 QCOMPARE(object->property("e").toInt(), 0);
729 QCOMPARE(object->property("f").toInt(), 1);
730 QCOMPARE(object->property("g").toInt(), 2);
731 QCOMPARE(object->property("h").toInt(), 3);
732 QCOMPARE(object->property("i").toInt(), 19);
733 QCOMPARE(object->property("j").toInt(), 19);
737 // Non-existent enums
739 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
741 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int a";
742 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int b";
743 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
744 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
746 QObject *object = component.create();
747 QVERIFY(object != 0);
748 QCOMPARE(object->property("a").toInt(), 0);
749 QCOMPARE(object->property("b").toInt(), 0);
755 void tst_qdeclarativeecmascript::valueTypeFunctions()
757 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
758 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
760 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
761 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
767 Tests that writing a constant to a property with a binding on it disables the
770 void tst_qdeclarativeecmascript::constantsOverrideBindings()
774 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
775 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
776 QVERIFY(object != 0);
778 QCOMPARE(object->property("c2").toInt(), 0);
779 object->setProperty("c1", QVariant(9));
780 QCOMPARE(object->property("c2").toInt(), 9);
782 emit object->basicSignal();
784 QCOMPARE(object->property("c2").toInt(), 13);
785 object->setProperty("c1", QVariant(8));
786 QCOMPARE(object->property("c2").toInt(), 13);
791 // During construction
793 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
794 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
795 QVERIFY(object != 0);
797 QCOMPARE(object->property("c1").toInt(), 0);
798 QCOMPARE(object->property("c2").toInt(), 10);
799 object->setProperty("c1", QVariant(9));
800 QCOMPARE(object->property("c1").toInt(), 9);
801 QCOMPARE(object->property("c2").toInt(), 10);
809 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
810 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
811 QVERIFY(object != 0);
813 QCOMPARE(object->property("c2").toInt(), 0);
814 object->setProperty("c1", QVariant(9));
815 QCOMPARE(object->property("c2").toInt(), 9);
817 object->setProperty("c2", QVariant(13));
818 QCOMPARE(object->property("c2").toInt(), 13);
819 object->setProperty("c1", QVariant(7));
820 QCOMPARE(object->property("c1").toInt(), 7);
821 QCOMPARE(object->property("c2").toInt(), 13);
829 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
830 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
831 QVERIFY(object != 0);
833 QCOMPARE(object->property("c1").toInt(), 0);
834 QCOMPARE(object->property("c3").toInt(), 10);
835 object->setProperty("c1", QVariant(9));
836 QCOMPARE(object->property("c1").toInt(), 9);
837 QCOMPARE(object->property("c3").toInt(), 10);
844 Tests that assigning a binding to a property that already has a binding causes
845 the original binding to be disabled.
847 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
849 QDeclarativeComponent component(&engine,
850 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
851 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
852 QVERIFY(object != 0);
854 QCOMPARE(object->property("c1").toInt(), 0);
855 QCOMPARE(object->property("c2").toInt(), 0);
856 QCOMPARE(object->property("c3").toInt(), 0);
858 object->setProperty("c1", QVariant(9));
859 QCOMPARE(object->property("c1").toInt(), 9);
860 QCOMPARE(object->property("c2").toInt(), 0);
861 QCOMPARE(object->property("c3").toInt(), 0);
863 object->setProperty("c3", QVariant(8));
864 QCOMPARE(object->property("c1").toInt(), 9);
865 QCOMPARE(object->property("c2").toInt(), 8);
866 QCOMPARE(object->property("c3").toInt(), 8);
872 Access a non-existent attached object.
874 Tests for a regression where this used to crash.
876 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
878 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
880 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString stringProperty";
881 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
883 QObject *object = component.create();
884 QVERIFY(object != 0);
889 void tst_qdeclarativeecmascript::scope()
892 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
893 QObject *object = component.create();
894 QVERIFY(object != 0);
896 QCOMPARE(object->property("test1").toInt(), 1);
897 QCOMPARE(object->property("test2").toInt(), 2);
898 QCOMPARE(object->property("test3").toString(), QString("1Test"));
899 QCOMPARE(object->property("test4").toString(), QString("2Test"));
900 QCOMPARE(object->property("test5").toInt(), 1);
901 QCOMPARE(object->property("test6").toInt(), 1);
902 QCOMPARE(object->property("test7").toInt(), 2);
903 QCOMPARE(object->property("test8").toInt(), 2);
904 QCOMPARE(object->property("test9").toInt(), 1);
905 QCOMPARE(object->property("test10").toInt(), 3);
911 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
912 QObject *object = component.create();
913 QVERIFY(object != 0);
915 QCOMPARE(object->property("test1").toInt(), 19);
916 QCOMPARE(object->property("test2").toInt(), 19);
917 QCOMPARE(object->property("test3").toInt(), 14);
918 QCOMPARE(object->property("test4").toInt(), 14);
919 QCOMPARE(object->property("test5").toInt(), 24);
920 QCOMPARE(object->property("test6").toInt(), 24);
926 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
927 QObject *object = component.create();
928 QVERIFY(object != 0);
930 QCOMPARE(object->property("test1").toBool(), true);
931 QCOMPARE(object->property("test2").toBool(), true);
932 QCOMPARE(object->property("test3").toBool(), true);
937 // Signal argument scope
939 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
940 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
941 QVERIFY(object != 0);
943 QCOMPARE(object->property("test").toInt(), 0);
944 QCOMPARE(object->property("test2").toString(), QString());
946 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
948 QCOMPARE(object->property("test").toInt(), 13);
949 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
955 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
956 QObject *object = component.create();
957 QVERIFY(object != 0);
959 QCOMPARE(object->property("test1").toBool(), true);
960 QCOMPARE(object->property("test2").toBool(), true);
966 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
967 QObject *object = component.create();
968 QVERIFY(object != 0);
970 QCOMPARE(object->property("test").toBool(), true);
976 // In 4.7, non-library javascript files that had no imports shared the imports of their
978 void tst_qdeclarativeecmascript::importScope()
980 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
981 QObject *o = component.create();
984 QCOMPARE(o->property("test").toInt(), 240);
990 Tests that "any" type passes through a synthesized signal parameter. This
991 is essentially a test of QDeclarativeMetaType::copy()
993 void tst_qdeclarativeecmascript::signalParameterTypes()
995 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
996 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
997 QVERIFY(object != 0);
999 emit object->basicSignal();
1001 QCOMPARE(object->property("intProperty").toInt(), 10);
1002 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1003 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1004 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1005 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1006 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1012 Test that two JS objects for the same QObject compare as equal.
1014 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1016 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1017 QObject *object = component.create();
1018 QVERIFY(object != 0);
1020 QCOMPARE(object->property("test1").toBool(), true);
1021 QCOMPARE(object->property("test2").toBool(), true);
1022 QCOMPARE(object->property("test3").toBool(), true);
1023 QCOMPARE(object->property("test4").toBool(), true);
1024 QCOMPARE(object->property("test5").toBool(), true);
1030 Confirm bindings and alias properties can coexist.
1032 Tests for a regression where the binding would not reevaluate.
1034 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1036 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1037 QObject *object = component.create();
1038 QVERIFY(object != 0);
1040 QCOMPARE(object->property("c2").toInt(), 3);
1041 QCOMPARE(object->property("c3").toInt(), 3);
1043 object->setProperty("c2", QVariant(19));
1045 QCOMPARE(object->property("c2").toInt(), 19);
1046 QCOMPARE(object->property("c3").toInt(), 19);
1052 Ensure that we can write undefined value to an alias property,
1053 and that the aliased property is reset correctly if possible.
1055 void tst_qdeclarativeecmascript::aliasPropertyReset()
1057 QObject *object = 0;
1059 // test that a manual write (of undefined) to a resettable aliased property succeeds
1060 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1061 object = c1.create();
1062 QVERIFY(object != 0);
1063 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1064 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1065 QMetaObject::invokeMethod(object, "resetAliased");
1066 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1067 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1070 // test that a manual write (of undefined) to a resettable alias property succeeds
1071 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1072 object = c2.create();
1073 QVERIFY(object != 0);
1074 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1075 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1076 QMetaObject::invokeMethod(object, "resetAlias");
1077 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1078 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1081 // test that an alias to a bound property works correctly
1082 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1083 object = c3.create();
1084 QVERIFY(object != 0);
1085 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1086 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1087 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1088 QMetaObject::invokeMethod(object, "resetAlias");
1089 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1090 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1091 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1094 // test that a manual write (of undefined) to a resettable alias property
1095 // whose aliased property's object has been deleted, does not crash.
1096 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1097 object = c4.create();
1098 QVERIFY(object != 0);
1099 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1100 QObject *loader = object->findChild<QObject*>("loader");
1101 QVERIFY(loader != 0);
1103 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1104 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1105 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1106 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1107 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1110 // test that binding an alias property to an undefined value works correctly
1111 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1112 object = c5.create();
1113 QVERIFY(object != 0);
1114 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1117 // test that a manual write (of undefined) to a non-resettable property fails properly
1118 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1119 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1120 QDeclarativeComponent e1(&engine, url);
1121 object = e1.create();
1122 QVERIFY(object != 0);
1123 QCOMPARE(object->property("intAlias").value<int>(), 12);
1124 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1125 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1126 QMetaObject::invokeMethod(object, "resetAlias");
1127 QCOMPARE(object->property("intAlias").value<int>(), 12);
1128 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1132 void tst_qdeclarativeecmascript::dynamicCreation_data()
1134 QTest::addColumn<QString>("method");
1135 QTest::addColumn<QString>("createdName");
1137 QTest::newRow("One") << "createOne" << "objectOne";
1138 QTest::newRow("Two") << "createTwo" << "objectTwo";
1139 QTest::newRow("Three") << "createThree" << "objectThree";
1143 Test using createQmlObject to dynamically generate an item
1144 Also using createComponent is tested.
1146 void tst_qdeclarativeecmascript::dynamicCreation()
1148 QFETCH(QString, method);
1149 QFETCH(QString, createdName);
1151 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1152 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1153 QVERIFY(object != 0);
1155 QMetaObject::invokeMethod(object, method.toUtf8());
1156 QObject *created = object->objectProperty();
1158 QCOMPARE(created->objectName(), createdName);
1164 Tests the destroy function
1166 void tst_qdeclarativeecmascript::dynamicDestruction()
1169 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1170 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1171 QVERIFY(object != 0);
1172 QDeclarativeGuard<QObject> createdQmlObject = 0;
1174 QMetaObject::invokeMethod(object, "create");
1175 createdQmlObject = object->objectProperty();
1176 QVERIFY(createdQmlObject);
1177 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1179 QMetaObject::invokeMethod(object, "killOther");
1180 QVERIFY(createdQmlObject);
1181 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1182 QVERIFY(createdQmlObject);
1183 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1184 if (createdQmlObject) {
1186 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1189 QVERIFY(!createdQmlObject);
1191 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1192 QMetaObject::invokeMethod(object, "killMe");
1195 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1200 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1201 QObject *o = component.create();
1204 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1206 QMetaObject::invokeMethod(o, "create");
1208 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1210 QMetaObject::invokeMethod(o, "destroy");
1212 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1214 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1221 tests that id.toString() works
1223 void tst_qdeclarativeecmascript::objectToString()
1225 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1226 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1227 QVERIFY(object != 0);
1228 QMetaObject::invokeMethod(object, "testToString");
1229 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1230 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1236 tests that id.hasOwnProperty() works
1238 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1240 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1241 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1242 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1243 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1245 QDeclarativeComponent component(&engine, url);
1246 QObject *object = component.create();
1247 QVERIFY(object != 0);
1249 // test QObjects in QML
1250 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1251 QVERIFY(object->property("result").value<bool>() == true);
1252 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1253 QVERIFY(object->property("result").value<bool>() == false);
1255 // now test other types in QML
1256 QObject *child = object->findChild<QObject*>("typeObj");
1257 QVERIFY(child != 0);
1258 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1259 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1260 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1261 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1262 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1263 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1264 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1265 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1266 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1267 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1268 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1269 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1271 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1272 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1273 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1274 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1275 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1276 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1277 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1278 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1279 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1285 Tests bindings that indirectly cause their own deletion work.
1287 This test is best run under valgrind to ensure no invalid memory access occur.
1289 void tst_qdeclarativeecmascript::selfDeletingBinding()
1292 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1293 QObject *object = component.create();
1294 QVERIFY(object != 0);
1295 object->setProperty("triggerDelete", true);
1300 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1301 QObject *object = component.create();
1302 QVERIFY(object != 0);
1303 object->setProperty("triggerDelete", true);
1309 Test that extended object properties can be accessed.
1311 This test a regression where this used to crash. The issue was specificially
1312 for extended objects that did not include a synthesized meta object (so non-root
1313 and no synthesiszed properties).
1315 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1317 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1318 QObject *object = component.create();
1319 QVERIFY(object != 0);
1324 Test file/lineNumbers for binding/Script errors.
1326 void tst_qdeclarativeecmascript::scriptErrors()
1328 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1329 QString url = component.url().toString();
1331 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1332 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1333 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1334 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1335 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1336 QString warning6 = url + ":7: Unable to assign [undefined] to int x";
1337 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1338 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1340 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1341 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1342 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1343 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1344 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1345 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1346 QVERIFY(object != 0);
1348 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1349 emit object->basicSignal();
1351 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1352 emit object->anotherBasicSignal();
1354 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1355 emit object->thirdBasicSignal();
1361 Test file/lineNumbers for inline functions.
1363 void tst_qdeclarativeecmascript::functionErrors()
1365 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1366 QString url = component.url().toString();
1368 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1370 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1372 QObject *object = component.create();
1373 QVERIFY(object != 0);
1376 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1377 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1378 url = componentTwo.url().toString();
1379 object = componentTwo.create();
1380 QVERIFY(object != 0);
1382 QString srpname = object->property("srp_name").toString();
1384 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1385 QLatin1String(" is not a function");
1386 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1387 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1392 Test various errors that can occur when assigning a property from script
1394 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1396 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1398 QString url = component.url().toString();
1400 QObject *object = component.create();
1401 QVERIFY(object != 0);
1403 QCOMPARE(object->property("test1").toBool(), true);
1404 QCOMPARE(object->property("test2").toBool(), true);
1410 Test bindings still work when the reeval is triggered from within
1413 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1415 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1416 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1417 QVERIFY(object != 0);
1419 QCOMPARE(object->property("base").toReal(), 50.);
1420 QCOMPARE(object->property("test1").toReal(), 50.);
1421 QCOMPARE(object->property("test2").toReal(), 50.);
1423 object->basicSignal();
1425 QCOMPARE(object->property("base").toReal(), 200.);
1426 QCOMPARE(object->property("test1").toReal(), 200.);
1427 QCOMPARE(object->property("test2").toReal(), 200.);
1429 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1431 QCOMPARE(object->property("base").toReal(), 400.);
1432 QCOMPARE(object->property("test1").toReal(), 400.);
1433 QCOMPARE(object->property("test2").toReal(), 400.);
1439 Test that list properties can be iterated from ECMAScript
1441 void tst_qdeclarativeecmascript::listProperties()
1443 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1444 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1445 QVERIFY(object != 0);
1447 QCOMPARE(object->property("test1").toInt(), 21);
1448 QCOMPARE(object->property("test2").toInt(), 2);
1449 QCOMPARE(object->property("test3").toBool(), true);
1450 QCOMPARE(object->property("test4").toBool(), true);
1455 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1457 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1458 QString url = component.url().toString();
1460 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1462 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1463 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1464 QVERIFY(object != 0);
1466 QCOMPARE(object->property("test").toBool(), false);
1468 MyQmlObject object2;
1469 MyQmlObject object3;
1470 object2.setObjectProperty(&object3);
1471 object->setObjectProperty(&object2);
1473 QCOMPARE(object->property("test").toBool(), true);
1478 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1480 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1481 QString url = component.url().toString();
1483 QString warning = component.url().toString() + ":6: Error: JS exception";
1485 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1486 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1487 QVERIFY(object != 0);
1491 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1493 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1494 QString url = component.url().toString();
1496 QString warning = component.url().toString() + ":5: Error: JS exception";
1498 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1499 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1500 QVERIFY(object != 0);
1504 static int transientErrorsMsgCount = 0;
1505 static void transientErrorsMsgHandler(QtMsgType, const char *)
1507 ++transientErrorsMsgCount;
1510 // Check that transient binding errors are not displayed
1511 void tst_qdeclarativeecmascript::transientErrors()
1514 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1516 transientErrorsMsgCount = 0;
1517 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1519 QObject *object = component.create();
1520 QVERIFY(object != 0);
1522 qInstallMsgHandler(old);
1524 QCOMPARE(transientErrorsMsgCount, 0);
1529 // One binding erroring multiple times, but then resolving
1531 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1533 transientErrorsMsgCount = 0;
1534 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1536 QObject *object = component.create();
1537 QVERIFY(object != 0);
1539 qInstallMsgHandler(old);
1541 QCOMPARE(transientErrorsMsgCount, 0);
1547 // Check that errors during shutdown are minimized
1548 void tst_qdeclarativeecmascript::shutdownErrors()
1550 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1551 QObject *object = component.create();
1552 QVERIFY(object != 0);
1554 transientErrorsMsgCount = 0;
1555 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1559 qInstallMsgHandler(old);
1560 QCOMPARE(transientErrorsMsgCount, 0);
1563 void tst_qdeclarativeecmascript::compositePropertyType()
1565 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1566 QTest::ignoreMessage(QtDebugMsg, "hello world");
1567 QObject *object = qobject_cast<QObject *>(component.create());
1572 void tst_qdeclarativeecmascript::jsObject()
1574 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1575 QObject *object = component.create();
1576 QVERIFY(object != 0);
1578 QCOMPARE(object->property("test").toInt(), 92);
1583 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1586 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1587 QObject *object = component.create();
1588 QVERIFY(object != 0);
1590 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1592 object->setProperty("setUndefined", true);
1594 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1596 object->setProperty("setUndefined", false);
1598 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1603 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1604 QObject *object = component.create();
1605 QVERIFY(object != 0);
1607 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1609 QMetaObject::invokeMethod(object, "doReset");
1611 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1618 void tst_qdeclarativeecmascript::bug1()
1620 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1621 QObject *object = component.create();
1622 QVERIFY(object != 0);
1624 QCOMPARE(object->property("test").toInt(), 14);
1626 object->setProperty("a", 11);
1628 QCOMPARE(object->property("test").toInt(), 3);
1630 object->setProperty("b", true);
1632 QCOMPARE(object->property("test").toInt(), 9);
1637 void tst_qdeclarativeecmascript::bug2()
1639 QDeclarativeComponent component(&engine);
1640 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1642 QObject *object = component.create();
1643 QVERIFY(object != 0);
1648 // Don't crash in createObject when the component has errors.
1649 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1651 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1652 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1653 QVERIFY(object != 0);
1655 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1656 QMetaObject::invokeMethod(object, "dontCrash");
1657 QObject *created = object->objectProperty();
1658 QVERIFY(created == 0);
1663 // ownership transferred to JS, ensure that GC runs the dtor
1664 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1667 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1669 // allow the engine to go out of scope too.
1671 QDeclarativeEngine dcoEngine;
1672 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1673 QObject *object = component.create();
1674 QVERIFY(object != 0);
1675 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1676 QVERIFY(mdcdo != 0);
1677 mdcdo->setDtorCount(&dtorCount);
1679 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1680 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1682 // we do this once manually, but it should be done automatically
1683 // when the engine goes out of scope (since it should gc in dtor)
1684 QMetaObject::invokeMethod(object, "performGc");
1687 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1693 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1694 QCOMPARE(dtorCount, expectedDtorCount);
1698 void tst_qdeclarativeecmascript::regExpBug()
1700 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1701 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1702 QVERIFY(object != 0);
1703 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1707 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1709 QString functionSource = QLatin1String("(function(object) { return ") +
1710 QLatin1String(source) + QLatin1String(" })");
1712 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1715 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1716 if (function.IsEmpty())
1718 v8::Handle<v8::Value> args[] = { o };
1719 function->Call(engine->global(), 1, args);
1720 return tc.HasCaught();
1723 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1724 const char *source, v8::Handle<v8::Value> result)
1726 QString functionSource = QLatin1String("(function(object) { return ") +
1727 QLatin1String(source) + QLatin1String(" })");
1729 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1732 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1733 if (function.IsEmpty())
1735 v8::Handle<v8::Value> args[] = { o };
1737 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1742 return value->StrictEquals(result);
1745 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1748 QString functionSource = QLatin1String("(function(object) { return ") +
1749 QLatin1String(source) + QLatin1String(" })");
1751 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1753 return v8::Handle<v8::Value>();
1754 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1755 if (function.IsEmpty())
1756 return v8::Handle<v8::Value>();
1757 v8::Handle<v8::Value> args[] = { o };
1759 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1762 return v8::Handle<v8::Value>();
1766 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1767 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1768 #define EVALUATE(source) evaluate(engine, object, source)
1770 void tst_qdeclarativeecmascript::callQtInvokables()
1772 MyInvokableObject o;
1774 QDeclarativeEngine qmlengine;
1775 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1777 QV8Engine *engine = ep->v8engine();
1779 v8::HandleScope handle_scope;
1780 v8::Context::Scope scope(engine->context());
1782 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1784 // Non-existent methods
1786 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1787 QCOMPARE(o.error(), false);
1788 QCOMPARE(o.invoked(), -1);
1789 QCOMPARE(o.actuals().count(), 0);
1792 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1793 QCOMPARE(o.error(), false);
1794 QCOMPARE(o.invoked(), -1);
1795 QCOMPARE(o.actuals().count(), 0);
1797 // Insufficient arguments
1799 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1800 QCOMPARE(o.error(), false);
1801 QCOMPARE(o.invoked(), -1);
1802 QCOMPARE(o.actuals().count(), 0);
1805 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1806 QCOMPARE(o.error(), false);
1807 QCOMPARE(o.invoked(), -1);
1808 QCOMPARE(o.actuals().count(), 0);
1810 // Excessive arguments
1812 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1813 QCOMPARE(o.error(), false);
1814 QCOMPARE(o.invoked(), 8);
1815 QCOMPARE(o.actuals().count(), 1);
1816 QCOMPARE(o.actuals().at(0), QVariant(10));
1819 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1820 QCOMPARE(o.error(), false);
1821 QCOMPARE(o.invoked(), 9);
1822 QCOMPARE(o.actuals().count(), 2);
1823 QCOMPARE(o.actuals().at(0), QVariant(10));
1824 QCOMPARE(o.actuals().at(1), QVariant(11));
1826 // Test return types
1828 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1829 QCOMPARE(o.error(), false);
1830 QCOMPARE(o.invoked(), 0);
1831 QCOMPARE(o.actuals().count(), 0);
1834 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1835 QCOMPARE(o.error(), false);
1836 QCOMPARE(o.invoked(), 1);
1837 QCOMPARE(o.actuals().count(), 0);
1840 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1841 QCOMPARE(o.error(), false);
1842 QCOMPARE(o.invoked(), 2);
1843 QCOMPARE(o.actuals().count(), 0);
1847 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1848 QVERIFY(!ret.IsEmpty());
1849 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1850 QCOMPARE(o.error(), false);
1851 QCOMPARE(o.invoked(), 3);
1852 QCOMPARE(o.actuals().count(), 0);
1857 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1858 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1859 QCOMPARE(o.error(), false);
1860 QCOMPARE(o.invoked(), 4);
1861 QCOMPARE(o.actuals().count(), 0);
1865 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1866 QCOMPARE(o.error(), false);
1867 QCOMPARE(o.invoked(), 5);
1868 QCOMPARE(o.actuals().count(), 0);
1872 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1873 QVERIFY(ret->IsString());
1874 QCOMPARE(engine->toString(ret), QString("Hello world"));
1875 QCOMPARE(o.error(), false);
1876 QCOMPARE(o.invoked(), 6);
1877 QCOMPARE(o.actuals().count(), 0);
1881 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1882 QCOMPARE(o.error(), false);
1883 QCOMPARE(o.invoked(), 7);
1884 QCOMPARE(o.actuals().count(), 0);
1888 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1889 QCOMPARE(o.error(), false);
1890 QCOMPARE(o.invoked(), 8);
1891 QCOMPARE(o.actuals().count(), 1);
1892 QCOMPARE(o.actuals().at(0), QVariant(94));
1895 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1896 QCOMPARE(o.error(), false);
1897 QCOMPARE(o.invoked(), 8);
1898 QCOMPARE(o.actuals().count(), 1);
1899 QCOMPARE(o.actuals().at(0), QVariant(94));
1902 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1903 QCOMPARE(o.error(), false);
1904 QCOMPARE(o.invoked(), 8);
1905 QCOMPARE(o.actuals().count(), 1);
1906 QCOMPARE(o.actuals().at(0), QVariant(0));
1909 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1910 QCOMPARE(o.error(), false);
1911 QCOMPARE(o.invoked(), 8);
1912 QCOMPARE(o.actuals().count(), 1);
1913 QCOMPARE(o.actuals().at(0), QVariant(0));
1916 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1917 QCOMPARE(o.error(), false);
1918 QCOMPARE(o.invoked(), 8);
1919 QCOMPARE(o.actuals().count(), 1);
1920 QCOMPARE(o.actuals().at(0), QVariant(0));
1923 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1924 QCOMPARE(o.error(), false);
1925 QCOMPARE(o.invoked(), 8);
1926 QCOMPARE(o.actuals().count(), 1);
1927 QCOMPARE(o.actuals().at(0), QVariant(0));
1930 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1931 QCOMPARE(o.error(), false);
1932 QCOMPARE(o.invoked(), 9);
1933 QCOMPARE(o.actuals().count(), 2);
1934 QCOMPARE(o.actuals().at(0), QVariant(122));
1935 QCOMPARE(o.actuals().at(1), QVariant(9));
1938 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1939 QCOMPARE(o.error(), false);
1940 QCOMPARE(o.invoked(), 10);
1941 QCOMPARE(o.actuals().count(), 1);
1942 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1945 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1946 QCOMPARE(o.error(), false);
1947 QCOMPARE(o.invoked(), 10);
1948 QCOMPARE(o.actuals().count(), 1);
1949 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1952 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1953 QCOMPARE(o.error(), false);
1954 QCOMPARE(o.invoked(), 10);
1955 QCOMPARE(o.actuals().count(), 1);
1956 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1959 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1960 QCOMPARE(o.error(), false);
1961 QCOMPARE(o.invoked(), 10);
1962 QCOMPARE(o.actuals().count(), 1);
1963 QCOMPARE(o.actuals().at(0), QVariant(0));
1966 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1967 QCOMPARE(o.error(), false);
1968 QCOMPARE(o.invoked(), 10);
1969 QCOMPARE(o.actuals().count(), 1);
1970 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1973 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
1974 QCOMPARE(o.error(), false);
1975 QCOMPARE(o.invoked(), 10);
1976 QCOMPARE(o.actuals().count(), 1);
1977 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1980 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
1981 QCOMPARE(o.error(), false);
1982 QCOMPARE(o.invoked(), 11);
1983 QCOMPARE(o.actuals().count(), 1);
1984 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
1987 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
1988 QCOMPARE(o.error(), false);
1989 QCOMPARE(o.invoked(), 11);
1990 QCOMPARE(o.actuals().count(), 1);
1991 QCOMPARE(o.actuals().at(0), QVariant("19"));
1995 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
1996 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
1997 QCOMPARE(o.error(), false);
1998 QCOMPARE(o.invoked(), 11);
1999 QCOMPARE(o.actuals().count(), 1);
2000 QCOMPARE(o.actuals().at(0), QVariant(expected));
2004 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2005 QCOMPARE(o.error(), false);
2006 QCOMPARE(o.invoked(), 11);
2007 QCOMPARE(o.actuals().count(), 1);
2008 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2011 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2012 QCOMPARE(o.error(), false);
2013 QCOMPARE(o.invoked(), 11);
2014 QCOMPARE(o.actuals().count(), 1);
2015 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2018 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2019 QCOMPARE(o.error(), false);
2020 QCOMPARE(o.invoked(), 12);
2021 QCOMPARE(o.actuals().count(), 1);
2022 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2025 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2026 QCOMPARE(o.error(), false);
2027 QCOMPARE(o.invoked(), 12);
2028 QCOMPARE(o.actuals().count(), 1);
2029 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2032 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2033 QCOMPARE(o.error(), false);
2034 QCOMPARE(o.invoked(), 12);
2035 QCOMPARE(o.actuals().count(), 1);
2036 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2039 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2040 QCOMPARE(o.error(), false);
2041 QCOMPARE(o.invoked(), 12);
2042 QCOMPARE(o.actuals().count(), 1);
2043 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2046 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2047 QCOMPARE(o.error(), false);
2048 QCOMPARE(o.invoked(), 12);
2049 QCOMPARE(o.actuals().count(), 1);
2050 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2053 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2054 QCOMPARE(o.error(), false);
2055 QCOMPARE(o.invoked(), 12);
2056 QCOMPARE(o.actuals().count(), 1);
2057 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2060 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2061 QCOMPARE(o.error(), false);
2062 QCOMPARE(o.invoked(), 13);
2063 QCOMPARE(o.actuals().count(), 1);
2064 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2067 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2068 QCOMPARE(o.error(), false);
2069 QCOMPARE(o.invoked(), 13);
2070 QCOMPARE(o.actuals().count(), 1);
2071 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2074 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2075 QCOMPARE(o.error(), false);
2076 QCOMPARE(o.invoked(), 13);
2077 QCOMPARE(o.actuals().count(), 1);
2078 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2081 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2082 QCOMPARE(o.error(), false);
2083 QCOMPARE(o.invoked(), 13);
2084 QCOMPARE(o.actuals().count(), 1);
2085 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2088 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2089 QCOMPARE(o.error(), false);
2090 QCOMPARE(o.invoked(), 13);
2091 QCOMPARE(o.actuals().count(), 1);
2092 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2095 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2096 QCOMPARE(o.error(), false);
2097 QCOMPARE(o.invoked(), 14);
2098 QCOMPARE(o.actuals().count(), 1);
2099 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2102 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2103 QCOMPARE(o.error(), false);
2104 QCOMPARE(o.invoked(), 14);
2105 QCOMPARE(o.actuals().count(), 1);
2106 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2109 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2110 QCOMPARE(o.error(), false);
2111 QCOMPARE(o.invoked(), 14);
2112 QCOMPARE(o.actuals().count(), 1);
2113 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2116 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2117 QCOMPARE(o.error(), false);
2118 QCOMPARE(o.invoked(), 14);
2119 QCOMPARE(o.actuals().count(), 1);
2120 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2123 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2124 QCOMPARE(o.error(), false);
2125 QCOMPARE(o.invoked(), 15);
2126 QCOMPARE(o.actuals().count(), 2);
2127 QCOMPARE(o.actuals().at(0), QVariant(4));
2128 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2131 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2132 QCOMPARE(o.error(), false);
2133 QCOMPARE(o.invoked(), 15);
2134 QCOMPARE(o.actuals().count(), 2);
2135 QCOMPARE(o.actuals().at(0), QVariant(8));
2136 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2139 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2140 QCOMPARE(o.error(), false);
2141 QCOMPARE(o.invoked(), 15);
2142 QCOMPARE(o.actuals().count(), 2);
2143 QCOMPARE(o.actuals().at(0), QVariant(3));
2144 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2147 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2148 QCOMPARE(o.error(), false);
2149 QCOMPARE(o.invoked(), 15);
2150 QCOMPARE(o.actuals().count(), 2);
2151 QCOMPARE(o.actuals().at(0), QVariant(44));
2152 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2155 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2156 QCOMPARE(o.error(), false);
2157 QCOMPARE(o.invoked(), -1);
2158 QCOMPARE(o.actuals().count(), 0);
2161 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2162 QCOMPARE(o.error(), false);
2163 QCOMPARE(o.invoked(), 16);
2164 QCOMPARE(o.actuals().count(), 1);
2165 QCOMPARE(o.actuals().at(0), QVariant(10));
2168 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2169 QCOMPARE(o.error(), false);
2170 QCOMPARE(o.invoked(), 17);
2171 QCOMPARE(o.actuals().count(), 2);
2172 QCOMPARE(o.actuals().at(0), QVariant(10));
2173 QCOMPARE(o.actuals().at(1), QVariant(11));
2176 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2177 QCOMPARE(o.error(), false);
2178 QCOMPARE(o.invoked(), 18);
2179 QCOMPARE(o.actuals().count(), 1);
2180 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2183 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2184 QCOMPARE(o.error(), false);
2185 QCOMPARE(o.invoked(), 19);
2186 QCOMPARE(o.actuals().count(), 1);
2187 QCOMPARE(o.actuals().at(0), QVariant(9));
2190 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2191 QCOMPARE(o.error(), false);
2192 QCOMPARE(o.invoked(), 20);
2193 QCOMPARE(o.actuals().count(), 2);
2194 QCOMPARE(o.actuals().at(0), QVariant(10));
2195 QCOMPARE(o.actuals().at(1), QVariant(19));
2198 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2199 QCOMPARE(o.error(), false);
2200 QCOMPARE(o.invoked(), 20);
2201 QCOMPARE(o.actuals().count(), 2);
2202 QCOMPARE(o.actuals().at(0), QVariant(10));
2203 QCOMPARE(o.actuals().at(1), QVariant(13));
2206 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2207 QCOMPARE(o.error(), false);
2208 QCOMPARE(o.invoked(), -3);
2209 QCOMPARE(o.actuals().count(), 1);
2210 QCOMPARE(o.actuals().at(0), QVariant(9));
2213 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2214 QCOMPARE(o.error(), false);
2215 QCOMPARE(o.invoked(), 21);
2216 QCOMPARE(o.actuals().count(), 2);
2217 QCOMPARE(o.actuals().at(0), QVariant(9));
2218 QCOMPARE(o.actuals().at(1), QVariant());
2221 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2222 QCOMPARE(o.error(), false);
2223 QCOMPARE(o.invoked(), 21);
2224 QCOMPARE(o.actuals().count(), 2);
2225 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2226 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2229 // QTBUG-13047 (check that you can pass registered object types as args)
2230 void tst_qdeclarativeecmascript::invokableObjectArg()
2232 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2234 QObject *o = component.create();
2236 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2238 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2243 // QTBUG-13047 (check that you can return registered object types from methods)
2244 void tst_qdeclarativeecmascript::invokableObjectRet()
2246 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2248 QObject *o = component.create();
2250 QCOMPARE(o->property("test").toBool(), true);
2255 void tst_qdeclarativeecmascript::listToVariant()
2257 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2259 MyQmlContainer container;
2261 QDeclarativeContext context(engine.rootContext());
2262 context.setContextObject(&container);
2264 QObject *object = component.create(&context);
2265 QVERIFY(object != 0);
2267 QVariant v = object->property("test");
2268 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2269 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2275 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2276 void tst_qdeclarativeecmascript::listAssignment()
2278 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2279 QObject *obj = component.create();
2280 QCOMPARE(obj->property("list1length").toInt(), 2);
2281 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2282 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2283 QCOMPARE(list1.count(&list1), list2.count(&list2));
2284 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2285 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2290 void tst_qdeclarativeecmascript::multiEngineObject()
2293 obj.setStringProperty("Howdy planet");
2295 QDeclarativeEngine e1;
2296 e1.rootContext()->setContextProperty("thing", &obj);
2297 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2299 QDeclarativeEngine e2;
2300 e2.rootContext()->setContextProperty("thing", &obj);
2301 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2303 QObject *o1 = c1.create();
2304 QObject *o2 = c2.create();
2306 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2307 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2313 // Test that references to QObjects are cleanup when the object is destroyed
2314 void tst_qdeclarativeecmascript::deletedObject()
2316 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2318 QObject *object = component.create();
2320 QCOMPARE(object->property("test1").toBool(), true);
2321 QCOMPARE(object->property("test2").toBool(), true);
2322 QCOMPARE(object->property("test3").toBool(), true);
2323 QCOMPARE(object->property("test4").toBool(), true);
2328 void tst_qdeclarativeecmascript::attachedPropertyScope()
2330 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2332 QObject *object = component.create();
2333 QVERIFY(object != 0);
2335 MyQmlAttachedObject *attached =
2336 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2337 QVERIFY(attached != 0);
2339 QCOMPARE(object->property("value2").toInt(), 0);
2341 attached->emitMySignal();
2343 QCOMPARE(object->property("value2").toInt(), 9);
2348 void tst_qdeclarativeecmascript::scriptConnect()
2351 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2353 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2354 QVERIFY(object != 0);
2356 QCOMPARE(object->property("test").toBool(), false);
2357 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2358 QCOMPARE(object->property("test").toBool(), true);
2364 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2366 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2367 QVERIFY(object != 0);
2369 QCOMPARE(object->property("test").toBool(), false);
2370 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2371 QCOMPARE(object->property("test").toBool(), true);
2377 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2379 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2380 QVERIFY(object != 0);
2382 QCOMPARE(object->property("test").toBool(), false);
2383 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2384 QCOMPARE(object->property("test").toBool(), true);
2390 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2392 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2393 QVERIFY(object != 0);
2395 QCOMPARE(object->methodCalled(), false);
2396 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2397 QCOMPARE(object->methodCalled(), true);
2403 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2405 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2406 QVERIFY(object != 0);
2408 QCOMPARE(object->methodCalled(), false);
2409 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2410 QCOMPARE(object->methodCalled(), true);
2416 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2418 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2419 QVERIFY(object != 0);
2421 QCOMPARE(object->property("test").toInt(), 0);
2422 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2423 QCOMPARE(object->property("test").toInt(), 2);
2429 void tst_qdeclarativeecmascript::scriptDisconnect()
2432 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2434 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2435 QVERIFY(object != 0);
2437 QCOMPARE(object->property("test").toInt(), 0);
2438 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2439 QCOMPARE(object->property("test").toInt(), 1);
2440 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2441 QCOMPARE(object->property("test").toInt(), 2);
2442 emit object->basicSignal();
2443 QCOMPARE(object->property("test").toInt(), 2);
2444 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2445 QCOMPARE(object->property("test").toInt(), 2);
2451 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2453 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2454 QVERIFY(object != 0);
2456 QCOMPARE(object->property("test").toInt(), 0);
2457 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2458 QCOMPARE(object->property("test").toInt(), 1);
2459 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2460 QCOMPARE(object->property("test").toInt(), 2);
2461 emit object->basicSignal();
2462 QCOMPARE(object->property("test").toInt(), 2);
2463 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2464 QCOMPARE(object->property("test").toInt(), 2);
2470 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2472 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2473 QVERIFY(object != 0);
2475 QCOMPARE(object->property("test").toInt(), 0);
2476 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2477 QCOMPARE(object->property("test").toInt(), 1);
2478 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2479 QCOMPARE(object->property("test").toInt(), 2);
2480 emit object->basicSignal();
2481 QCOMPARE(object->property("test").toInt(), 2);
2482 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2483 QCOMPARE(object->property("test").toInt(), 3);
2488 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2490 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2491 QVERIFY(object != 0);
2493 QCOMPARE(object->property("test").toInt(), 0);
2494 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2495 QCOMPARE(object->property("test").toInt(), 1);
2496 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2497 QCOMPARE(object->property("test").toInt(), 2);
2498 emit object->basicSignal();
2499 QCOMPARE(object->property("test").toInt(), 2);
2500 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2501 QCOMPARE(object->property("test").toInt(), 3);
2507 class OwnershipObject : public QObject
2511 OwnershipObject() { object = new QObject; }
2513 QPointer<QObject> object;
2516 QObject *getObject() { return object; }
2519 void tst_qdeclarativeecmascript::ownership()
2521 OwnershipObject own;
2522 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2523 context->setContextObject(&own);
2526 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2528 QVERIFY(own.object != 0);
2530 QObject *object = component.create(context);
2532 engine.collectGarbage();
2534 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2536 QVERIFY(own.object == 0);
2541 own.object = new QObject(&own);
2544 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2546 QVERIFY(own.object != 0);
2548 QObject *object = component.create(context);
2550 engine.collectGarbage();
2552 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2554 QVERIFY(own.object != 0);
2562 class CppOwnershipReturnValue : public QObject
2566 CppOwnershipReturnValue() : value(0) {}
2567 ~CppOwnershipReturnValue() { delete value; }
2569 Q_INVOKABLE QObject *create() {
2570 value = new QObject;
2571 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2575 Q_INVOKABLE MyQmlObject *createQmlObject() {
2576 MyQmlObject *rv = new MyQmlObject;
2581 QPointer<QObject> value;
2585 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2586 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2588 CppOwnershipReturnValue source;
2591 QDeclarativeEngine engine;
2592 engine.rootContext()->setContextProperty("source", &source);
2594 QVERIFY(source.value == 0);
2596 QDeclarativeComponent component(&engine);
2597 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2599 QObject *object = component.create();
2601 QVERIFY(object != 0);
2602 QVERIFY(source.value != 0);
2607 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2609 QVERIFY(source.value != 0);
2613 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2615 CppOwnershipReturnValue source;
2618 QDeclarativeEngine engine;
2619 engine.rootContext()->setContextProperty("source", &source);
2621 QVERIFY(source.value == 0);
2623 QDeclarativeComponent component(&engine);
2624 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2626 QObject *object = component.create();
2628 QVERIFY(object != 0);
2629 QVERIFY(source.value != 0);
2634 engine.collectGarbage();
2635 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2637 QVERIFY(source.value == 0);
2640 class QListQObjectMethodsObject : public QObject
2644 QListQObjectMethodsObject() {
2645 m_objects.append(new MyQmlObject());
2646 m_objects.append(new MyQmlObject());
2649 ~QListQObjectMethodsObject() {
2650 qDeleteAll(m_objects);
2654 QList<QObject *> getObjects() { return m_objects; }
2657 QList<QObject *> m_objects;
2660 // Tests that returning a QList<QObject*> from a method works
2661 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2663 QListQObjectMethodsObject obj;
2664 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2665 context->setContextObject(&obj);
2667 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2669 QObject *object = component.create(context);
2671 QCOMPARE(object->property("test").toInt(), 2);
2672 QCOMPARE(object->property("test2").toBool(), true);
2679 void tst_qdeclarativeecmascript::strictlyEquals()
2681 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2683 QObject *object = component.create();
2684 QVERIFY(object != 0);
2686 QCOMPARE(object->property("test1").toBool(), true);
2687 QCOMPARE(object->property("test2").toBool(), true);
2688 QCOMPARE(object->property("test3").toBool(), true);
2689 QCOMPARE(object->property("test4").toBool(), true);
2690 QCOMPARE(object->property("test5").toBool(), true);
2691 QCOMPARE(object->property("test6").toBool(), true);
2692 QCOMPARE(object->property("test7").toBool(), true);
2693 QCOMPARE(object->property("test8").toBool(), true);
2698 void tst_qdeclarativeecmascript::compiled()
2700 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2702 QObject *object = component.create();
2703 QVERIFY(object != 0);
2705 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2706 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2707 QCOMPARE(object->property("test3").toBool(), true);
2708 QCOMPARE(object->property("test4").toBool(), false);
2709 QCOMPARE(object->property("test5").toBool(), false);
2710 QCOMPARE(object->property("test6").toBool(), true);
2712 QCOMPARE(object->property("test7").toInt(), 185);
2713 QCOMPARE(object->property("test8").toInt(), 167);
2714 QCOMPARE(object->property("test9").toBool(), true);
2715 QCOMPARE(object->property("test10").toBool(), false);
2716 QCOMPARE(object->property("test11").toBool(), false);
2717 QCOMPARE(object->property("test12").toBool(), true);
2719 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2720 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2721 QCOMPARE(object->property("test15").toBool(), false);
2722 QCOMPARE(object->property("test16").toBool(), true);
2724 QCOMPARE(object->property("test17").toInt(), 5);
2725 QCOMPARE(object->property("test18").toReal(), qreal(176));
2726 QCOMPARE(object->property("test19").toInt(), 7);
2727 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2728 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2729 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2730 QCOMPARE(object->property("test23").toBool(), true);
2731 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2732 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2737 // Test that numbers assigned in bindings as strings work consistently
2738 void tst_qdeclarativeecmascript::numberAssignment()
2740 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2742 QObject *object = component.create();
2743 QVERIFY(object != 0);
2745 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2746 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2747 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2748 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2749 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2751 QCOMPARE(object->property("test5"), QVariant((int)7));
2752 QCOMPARE(object->property("test6"), QVariant((int)7));
2753 QCOMPARE(object->property("test7"), QVariant((int)6));
2754 QCOMPARE(object->property("test8"), QVariant((int)6));
2756 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2757 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2758 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2759 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2764 void tst_qdeclarativeecmascript::propertySplicing()
2766 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2768 QObject *object = component.create();
2769 QVERIFY(object != 0);
2771 QCOMPARE(object->property("test").toBool(), true);
2777 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2779 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2781 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2782 QVERIFY(object != 0);
2784 MyQmlObject::MyType type;
2785 type.value = 0x8971123;
2786 emit object->signalWithUnknownType(type);
2788 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2790 QCOMPARE(result.value, type.value);
2796 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2798 QTest::addColumn<QString>("expression");
2799 QTest::addColumn<QString>("compare");
2801 QString compareStrict("(function(a, b) { return a === b; })");
2802 QTest::newRow("true") << "true" << compareStrict;
2803 QTest::newRow("undefined") << "undefined" << compareStrict;
2804 QTest::newRow("null") << "null" << compareStrict;
2805 QTest::newRow("123") << "123" << compareStrict;
2806 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2808 QString comparePropertiesStrict(
2810 " if (typeof b != 'object')"
2812 " var props = Object.getOwnPropertyNames(b);"
2813 " for (var i = 0; i < props.length; ++i) {"
2814 " var p = props[i];"
2815 " return arguments.callee(a[p], b[p]);"
2818 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2819 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2822 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2824 QFETCH(QString, expression);
2825 QFETCH(QString, compare);
2827 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2828 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2829 QVERIFY(object != 0);
2831 QJSValue value = engine.evaluate(expression);
2832 QVERIFY(!engine.hasUncaughtException());
2833 object->setProperty("expression", expression);
2834 object->setProperty("compare", compare);
2835 object->setProperty("pass", false);
2837 emit object->signalWithVariant(QVariant::fromValue(value));
2838 QVERIFY(object->property("pass").toBool());
2841 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2843 signalWithJSValueInVariant_data();
2846 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2848 QFETCH(QString, expression);
2849 QFETCH(QString, compare);
2851 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2852 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2853 QVERIFY(object != 0);
2856 QJSValue value = engine2.evaluate(expression);
2857 QVERIFY(!engine2.hasUncaughtException());
2858 object->setProperty("expression", expression);
2859 object->setProperty("compare", compare);
2860 object->setProperty("pass", false);
2862 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2863 emit object->signalWithVariant(QVariant::fromValue(value));
2864 QVERIFY(!object->property("pass").toBool());
2867 void tst_qdeclarativeecmascript::moduleApi_data()
2869 QTest::addColumn<QUrl>("testfile");
2870 QTest::addColumn<QString>("errorMessage");
2871 QTest::addColumn<QStringList>("warningMessages");
2872 QTest::addColumn<QStringList>("readProperties");
2873 QTest::addColumn<QVariantList>("readExpectedValues");
2874 QTest::addColumn<QStringList>("writeProperties");
2875 QTest::addColumn<QVariantList>("writeValues");
2876 QTest::addColumn<QStringList>("readBackProperties");
2877 QTest::addColumn<QVariantList>("readBackExpectedValues");
2879 QTest::newRow("qobject, register + read + method")
2880 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2883 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2884 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2885 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2891 QTest::newRow("script, register + read")
2892 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2895 << (QStringList() << "scriptTest")
2896 << (QVariantList() << 13)
2902 QTest::newRow("qobject, caching + read")
2903 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2906 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2907 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2913 QTest::newRow("script, caching + read")
2914 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2917 << (QStringList() << "scriptTest")
2918 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2924 QTest::newRow("qobject, writing + readonly constraints")
2925 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2927 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2928 << (QStringList() << "readOnlyProperty" << "writableProperty")
2929 << (QVariantList() << 20 << 50)
2930 << (QStringList() << "firstProperty" << "writableProperty")
2931 << (QVariantList() << 30 << 30)
2932 << (QStringList() << "readOnlyProperty" << "writableProperty")
2933 << (QVariantList() << 20 << 30);
2935 QTest::newRow("script, writing + readonly constraints")
2936 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
2938 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
2939 << (QStringList() << "readBack" << "unchanged")
2940 << (QVariantList() << 13 << 42)
2941 << (QStringList() << "firstProperty" << "secondProperty")
2942 << (QVariantList() << 30 << 30)
2943 << (QStringList() << "readBack" << "unchanged")
2944 << (QVariantList() << 30 << 42);
2946 QTest::newRow("qobject module API enum values in JS")
2947 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
2950 << (QStringList() << "enumValue" << "enumMethod")
2951 << (QVariantList() << 42 << 30)
2957 QTest::newRow("qobject, invalid major version fail")
2958 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
2959 << QString("QDeclarativeComponent: Component is not ready")
2968 QTest::newRow("qobject, invalid minor version fail")
2969 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
2970 << QString("QDeclarativeComponent: Component is not ready")
2980 void tst_qdeclarativeecmascript::moduleApi()
2982 QFETCH(QUrl, testfile);
2983 QFETCH(QString, errorMessage);
2984 QFETCH(QStringList, warningMessages);
2985 QFETCH(QStringList, readProperties);
2986 QFETCH(QVariantList, readExpectedValues);
2987 QFETCH(QStringList, writeProperties);
2988 QFETCH(QVariantList, writeValues);
2989 QFETCH(QStringList, readBackProperties);
2990 QFETCH(QVariantList, readBackExpectedValues);
2992 QDeclarativeComponent component(&engine, testfile);
2994 if (!errorMessage.isEmpty())
2995 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
2997 if (warningMessages.size())
2998 foreach (const QString &warning, warningMessages)
2999 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3001 QObject *object = component.create();
3002 if (!errorMessage.isEmpty()) {
3003 QVERIFY(object == 0);
3005 QVERIFY(object != 0);
3006 for (int i = 0; i < readProperties.size(); ++i)
3007 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3008 for (int i = 0; i < writeProperties.size(); ++i)
3009 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3010 for (int i = 0; i < readBackProperties.size(); ++i)
3011 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3016 void tst_qdeclarativeecmascript::importScripts()
3018 QObject *object = 0;
3020 // first, ensure that the required behaviour works.
3021 QDeclarativeComponent component(&engine, TEST_FILE("jsimport/testImport.qml"));
3022 object = component.create();
3023 QVERIFY(object != 0);
3024 QCOMPARE(object->property("importedScriptStringValue"), QVariant(QString(QLatin1String("Hello, World!"))));
3025 QCOMPARE(object->property("importedScriptFunctionValue"), QVariant(20));
3026 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(19));
3027 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(2));
3030 QDeclarativeComponent componentTwo(&engine, TEST_FILE("jsimport/testImportScoping.qml"));
3031 object = componentTwo.create();
3032 QVERIFY(object != 0);
3033 QCOMPARE(object->property("componentError"), QVariant(5));
3036 // then, ensure that unintended behaviour does not work.
3037 QDeclarativeComponent failOneComponent(&engine, TEST_FILE("jsimportfail/failOne.qml"));
3038 QString expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined");
3039 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
3040 object = failOneComponent.create();
3041 QVERIFY(object != 0);
3042 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
3044 QDeclarativeComponent failTwoComponent(&engine, TEST_FILE("jsimportfail/failTwo.qml"));
3045 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs");
3046 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
3047 object = failTwoComponent.create();
3048 QVERIFY(object != 0);
3049 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
3051 QDeclarativeComponent failThreeComponent(&engine, TEST_FILE("jsimportfail/failThree.qml"));
3052 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined");
3053 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
3054 object = failThreeComponent.create();
3055 QVERIFY(object != 0);
3056 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(false));
3058 QDeclarativeComponent failFourComponent(&engine, TEST_FILE("jsimportfail/failFour.qml"));
3059 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest");
3060 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
3061 object = failFourComponent.create();
3062 QVERIFY(object != 0);
3063 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(0));
3065 QDeclarativeComponent failFiveComponent(&engine, TEST_FILE("jsimportfail/failFive.qml"));
3066 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component");
3067 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
3068 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component");
3069 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
3070 object = failFiveComponent.create();
3071 QVERIFY(object != 0);
3072 QCOMPARE(object->property("componentError"), QVariant(0));
3075 // also, test that importing scripts with .pragma library works as required
3076 QDeclarativeComponent pragmaLibraryComponent(&engine, TEST_FILE("jsimport/testImportPragmaLibrary.qml"));
3077 object = pragmaLibraryComponent.create();
3078 QVERIFY(object != 0);
3079 QCOMPARE(object->property("testValue"), QVariant(31));
3082 // and that .pragma library scripts don't inherit imports from any .qml file
3083 QDeclarativeComponent pragmaLibraryComponentTwo(&engine, TEST_FILE("jsimportfail/testImportPragmaLibrary.qml"));
3084 object = pragmaLibraryComponentTwo.create();
3085 QVERIFY(object != 0);
3086 QCOMPARE(object->property("testValue"), QVariant(0));
3090 void tst_qdeclarativeecmascript::scarceResources()
3092 QPixmap origPixmap(100, 100);
3093 origPixmap.fill(Qt::blue);
3095 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3096 ScarceResourceObject *eo = 0;
3097 QObject *object = 0;
3099 // in the following three cases, the instance created from the component
3100 // has a property which is a copy of the scarce resource; hence, the
3101 // resource should NOT be detached prior to deletion of the object instance,
3102 // unless the resource is destroyed explicitly.
3103 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
3104 object = component.create();
3105 QVERIFY(object != 0);
3106 QVERIFY(object->property("scarceResourceCopy").isValid());
3107 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3108 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3109 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3110 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3113 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3114 object = componentTwo.create();
3115 QVERIFY(object != 0);
3116 QVERIFY(object->property("scarceResourceCopy").isValid());
3117 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3118 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3119 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3120 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3123 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3124 object = componentThree.create();
3125 QVERIFY(object != 0);
3126 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3127 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3128 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3129 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3132 // in the following three cases, no other copy should exist in memory,
3133 // and so it should be detached (unless explicitly preserved).
3134 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3135 object = componentFour.create();
3136 QVERIFY(object != 0);
3137 QVERIFY(object->property("scarceResourceTest").isValid());
3138 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3139 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3140 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3141 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3144 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3145 object = componentFive.create();
3146 QVERIFY(object != 0);
3147 QVERIFY(object->property("scarceResourceTest").isValid());
3148 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3149 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3150 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3151 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3154 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3155 object = componentSix.create();
3156 QVERIFY(object != 0);
3157 QVERIFY(object->property("scarceResourceTest").isValid());
3158 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3159 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3160 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3161 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3164 // test that scarce resources are handled correctly for imports
3165 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3166 object = componentSeven.create();
3167 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3168 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3171 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3172 object = componentEight.create();
3173 QVERIFY(object != 0);
3174 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3175 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3178 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3179 object = componentNine.create();
3180 QVERIFY(object != 0);
3181 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3182 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3183 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3184 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3185 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3186 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3189 // test that scarce resources are handled properly in signal invocation
3190 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3191 object = componentTen.create();
3192 QVERIFY(object != 0);
3193 QObject *srsc = object->findChild<QObject*>("srsc");
3195 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3196 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3197 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3198 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3199 QMetaObject::invokeMethod(srsc, "testSignal");
3200 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3201 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3202 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3203 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3204 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3205 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3206 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3207 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3208 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3209 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3212 // test that scarce resources are handled properly from js functions in qml files
3213 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3214 object = componentEleven.create();
3215 QVERIFY(object != 0);
3216 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3217 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3218 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3219 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3220 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3221 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3222 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3223 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3224 QMetaObject::invokeMethod(object, "releaseScarceResource");
3225 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3226 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3227 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3228 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3231 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3232 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3233 object = componentTwelve.create();
3234 QVERIFY(object != 0);
3235 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3236 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3237 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3238 QString srp_name = object->property("srp_name").toString();
3239 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3240 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3241 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3242 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3243 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3244 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3245 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3249 void tst_qdeclarativeecmascript::propertyChangeSlots()
3251 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3252 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3253 QObject *object = component.create();
3254 QVERIFY(object != 0);
3257 // ensure that invalid property names fail properly.
3258 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3259 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3260 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3261 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3262 object = e1.create();
3263 QVERIFY(object == 0);
3266 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3267 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3268 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3269 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3270 object = e2.create();
3271 QVERIFY(object == 0);
3274 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3275 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3276 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3277 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3278 object = e3.create();
3279 QVERIFY(object == 0);
3282 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3283 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3284 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3285 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3286 object = e4.create();
3287 QVERIFY(object == 0);
3291 // Ensure that QObject type conversion works on binding assignment
3292 void tst_qdeclarativeecmascript::elementAssign()
3294 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3296 QObject *object = component.create();
3297 QVERIFY(object != 0);
3299 QCOMPARE(object->property("test").toBool(), true);
3305 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3307 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3309 QObject *object = component.create();
3310 QVERIFY(object != 0);
3312 QCOMPARE(object->property("test").toBool(), true);
3318 void tst_qdeclarativeecmascript::booleanConversion()
3320 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3322 QObject *object = component.create();
3323 QVERIFY(object != 0);
3325 QCOMPARE(object->property("test_true1").toBool(), true);
3326 QCOMPARE(object->property("test_true2").toBool(), true);
3327 QCOMPARE(object->property("test_true3").toBool(), true);
3328 QCOMPARE(object->property("test_true4").toBool(), true);
3329 QCOMPARE(object->property("test_true5").toBool(), true);
3331 QCOMPARE(object->property("test_false1").toBool(), false);
3332 QCOMPARE(object->property("test_false2").toBool(), false);
3333 QCOMPARE(object->property("test_false3").toBool(), false);
3338 void tst_qdeclarativeecmascript::handleReferenceManagement()
3343 // Linear QObject reference
3344 QDeclarativeEngine hrmEngine;
3345 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3346 QObject *object = component.create();
3347 QVERIFY(object != 0);
3348 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3349 cro->setDtorCount(&dtorCount);
3350 QMetaObject::invokeMethod(object, "createReference");
3351 QMetaObject::invokeMethod(object, "performGc");
3352 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3353 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3355 hrmEngine.collectGarbage();
3356 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3357 QCOMPARE(dtorCount, 3);
3362 // Circular QObject reference
3363 QDeclarativeEngine hrmEngine;
3364 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3365 QObject *object = component.create();
3366 QVERIFY(object != 0);
3367 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3368 cro->setDtorCount(&dtorCount);
3369 QMetaObject::invokeMethod(object, "circularReference");
3370 QMetaObject::invokeMethod(object, "performGc");
3371 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3372 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3374 hrmEngine.collectGarbage();
3375 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3376 QCOMPARE(dtorCount, 3);
3381 // Linear handle reference
3382 QDeclarativeEngine hrmEngine;
3383 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3384 QObject *object = component.create();
3385 QVERIFY(object != 0);
3386 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3388 crh->setDtorCount(&dtorCount);
3389 QMetaObject::invokeMethod(object, "createReference");
3390 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3391 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3392 QVERIFY(first != 0);
3393 QVERIFY(second != 0);
3394 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3395 // now we have to reparent second and make second owned by JS.
3396 second->setParent(0);
3397 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3398 QMetaObject::invokeMethod(object, "performGc");
3399 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3400 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3402 hrmEngine.collectGarbage();
3403 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3404 QCOMPARE(dtorCount, 3);
3409 // Circular handle reference
3410 QDeclarativeEngine hrmEngine;
3411 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3412 QObject *object = component.create();
3413 QVERIFY(object != 0);
3414 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3416 crh->setDtorCount(&dtorCount);
3417 QMetaObject::invokeMethod(object, "circularReference");
3418 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3419 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3420 QVERIFY(first != 0);
3421 QVERIFY(second != 0);
3422 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3423 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3424 // now we have to reparent and change ownership.
3425 first->setParent(0);
3426 second->setParent(0);
3427 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3428 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3429 QMetaObject::invokeMethod(object, "performGc");
3430 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3431 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3433 hrmEngine.collectGarbage();
3434 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3435 QCOMPARE(dtorCount, 3);
3440 // multiple engine interaction - linear reference
3441 QDeclarativeEngine hrmEngine1;
3442 QDeclarativeEngine hrmEngine2;
3443 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3444 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3445 QObject *object1 = component1.create();
3446 QObject *object2 = component2.create();
3447 QVERIFY(object1 != 0);
3448 QVERIFY(object2 != 0);
3449 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3450 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3453 crh1->setDtorCount(&dtorCount);
3454 crh2->setDtorCount(&dtorCount);
3455 QMetaObject::invokeMethod(object1, "createReference");
3456 QMetaObject::invokeMethod(object2, "createReference");
3457 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3458 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3459 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3460 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3461 QVERIFY(first1 != 0);
3462 QVERIFY(second1 != 0);
3463 QVERIFY(first2 != 0);
3464 QVERIFY(second2 != 0);
3465 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3466 // now we have to reparent second2 and make second2 owned by JS.
3467 second2->setParent(0);
3468 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3469 QMetaObject::invokeMethod(object1, "performGc");
3470 QMetaObject::invokeMethod(object2, "performGc");
3471 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3472 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3475 hrmEngine1.collectGarbage();
3476 hrmEngine2.collectGarbage();
3477 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3478 QCOMPARE(dtorCount, 6);
3483 // multiple engine interaction - circular reference
3484 QDeclarativeEngine hrmEngine1;
3485 QDeclarativeEngine hrmEngine2;
3486 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3487 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3488 QObject *object1 = component1.create();
3489 QObject *object2 = component2.create();
3490 QVERIFY(object1 != 0);
3491 QVERIFY(object2 != 0);
3492 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3493 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3496 crh1->setDtorCount(&dtorCount);
3497 crh2->setDtorCount(&dtorCount);
3498 QMetaObject::invokeMethod(object1, "createReference");
3499 QMetaObject::invokeMethod(object2, "createReference");
3500 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3501 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3502 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3503 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3504 QVERIFY(first1 != 0);
3505 QVERIFY(second1 != 0);
3506 QVERIFY(first2 != 0);
3507 QVERIFY(second2 != 0);
3508 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3509 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3510 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3511 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3512 // now we have to reparent and change ownership to JS.
3513 first1->setParent(0);
3514 second1->setParent(0);
3515 first2->setParent(0);
3516 second2->setParent(0);
3517 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
3518 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3519 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3520 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3521 QMetaObject::invokeMethod(object1, "performGc");
3522 QMetaObject::invokeMethod(object2, "performGc");
3523 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3524 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
3527 hrmEngine1.collectGarbage();
3528 hrmEngine2.collectGarbage();
3529 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3530 QCOMPARE(dtorCount, 6);
3535 // multiple engine interaction - linear reference with engine deletion
3536 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
3537 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
3538 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3539 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3540 QObject *object1 = component1.create();
3541 QObject *object2 = component2.create();
3542 QVERIFY(object1 != 0);
3543 QVERIFY(object2 != 0);
3544 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3545 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3548 crh1->setDtorCount(&dtorCount);
3549 crh2->setDtorCount(&dtorCount);
3550 QMetaObject::invokeMethod(object1, "createReference");
3551 QMetaObject::invokeMethod(object2, "createReference");
3552 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3553 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3554 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3555 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3556 QVERIFY(first1 != 0);
3557 QVERIFY(second1 != 0);
3558 QVERIFY(first2 != 0);
3559 QVERIFY(second2 != 0);
3560 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3561 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3562 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3563 // now we have to reparent and change ownership to JS.
3564 first1->setParent(crh1);
3565 second1->setParent(0);
3566 first2->setParent(0);
3567 second2->setParent(0);
3568 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3569 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3570 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3571 QMetaObject::invokeMethod(object1, "performGc");
3572 QMetaObject::invokeMethod(object2, "performGc");
3573 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3574 QCOMPARE(dtorCount, 0);
3576 QMetaObject::invokeMethod(object1, "performGc");
3577 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3578 QCOMPARE(dtorCount, 0);
3581 hrmEngine1->collectGarbage();
3582 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3583 QCOMPARE(dtorCount, 6);
3588 void tst_qdeclarativeecmascript::stringArg()
3590 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
3591 QObject *object = component.create();
3592 QVERIFY(object != 0);
3593 QMetaObject::invokeMethod(object, "success");
3594 QVERIFY(object->property("returnValue").toBool());
3596 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
3597 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
3598 QMetaObject::invokeMethod(object, "failure");
3599 QVERIFY(object->property("returnValue").toBool());
3604 // Test that assigning a null object works
3605 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
3606 void tst_qdeclarativeecmascript::nullObjectBinding()
3608 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
3610 QObject *object = component.create();
3611 QVERIFY(object != 0);
3613 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
3618 // Test that bindings don't evaluate once the engine has been destroyed
3619 void tst_qdeclarativeecmascript::deletedEngine()
3621 QDeclarativeEngine *engine = new QDeclarativeEngine;
3622 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
3624 QObject *object = component.create();
3625 QVERIFY(object != 0);
3627 QCOMPARE(object->property("a").toInt(), 39);
3628 object->setProperty("b", QVariant(9));
3629 QCOMPARE(object->property("a").toInt(), 117);
3633 QCOMPARE(object->property("a").toInt(), 117);
3634 object->setProperty("b", QVariant(10));
3635 QCOMPARE(object->property("a").toInt(), 117);
3640 // Test the crashing part of QTBUG-9705
3641 void tst_qdeclarativeecmascript::libraryScriptAssert()
3643 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
3645 QObject *object = component.create();
3646 QVERIFY(object != 0);
3651 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
3653 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
3655 QObject *object = component.create();
3656 QVERIFY(object != 0);
3658 QCOMPARE(object->property("test1").toInt(), 10);
3659 QCOMPARE(object->property("test2").toInt(), 11);
3661 object->setProperty("runTest", true);
3663 QCOMPARE(object->property("test1"), QVariant());
3664 QCOMPARE(object->property("test2"), QVariant());
3670 void tst_qdeclarativeecmascript::qtbug_9792()
3672 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
3674 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
3676 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
3677 QVERIFY(object != 0);
3679 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
3680 object->basicSignal();
3684 transientErrorsMsgCount = 0;
3685 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3687 object->basicSignal();
3689 qInstallMsgHandler(old);
3691 QCOMPARE(transientErrorsMsgCount, 0);
3696 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
3697 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
3699 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
3701 QObject *o = component.create();
3704 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
3705 QVERIFY(nested != 0);
3707 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
3710 nested = qvariant_cast<QObject *>(o->property("object"));
3711 QVERIFY(nested == 0);
3713 // If the bug is present, the next line will crash
3717 // Test that we shut down without stupid warnings
3718 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
3721 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
3723 QObject *o = component.create();
3725 transientErrorsMsgCount = 0;
3726 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3730 qInstallMsgHandler(old);
3732 QCOMPARE(transientErrorsMsgCount, 0);
3737 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
3739 QObject *o = component.create();
3741 transientErrorsMsgCount = 0;
3742 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3746 qInstallMsgHandler(old);
3748 QCOMPARE(transientErrorsMsgCount, 0);
3752 void tst_qdeclarativeecmascript::canAssignNullToQObject()
3755 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
3757 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3760 QVERIFY(o->objectProperty() != 0);
3762 o->setProperty("runTest", true);
3764 QVERIFY(o->objectProperty() == 0);
3770 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
3772 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3775 QVERIFY(o->objectProperty() == 0);
3781 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
3783 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
3785 QString url = component.url().toString();
3786 QString warning = url + ":4: Unable to assign a function to a property.";
3787 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3789 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3792 QVERIFY(!o->property("a").isValid());
3797 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
3799 QFETCH(QString, triggerProperty);
3801 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3802 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3804 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3806 QVERIFY(!o->property("a").isValid());
3808 o->setProperty("aNumber", QVariant(5));
3809 o->setProperty(triggerProperty.toUtf8().constData(), true);
3810 QCOMPARE(o->property("a"), QVariant(50));
3812 o->setProperty("aNumber", QVariant(10));
3813 QCOMPARE(o->property("a"), QVariant(100));
3818 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
3820 QTest::addColumn<QString>("triggerProperty");
3822 QTest::newRow("assign to property") << "assignToProperty";
3823 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
3825 QTest::newRow("assign to value type") << "assignToValueType";
3827 QTest::newRow("use 'this'") << "assignWithThis";
3828 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
3831 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
3833 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3834 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3836 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3838 QVERIFY(!o->property("a").isValid());
3840 o->setProperty("assignFuncWithoutReturn", true);
3841 QVERIFY(!o->property("a").isValid());
3843 QString url = component.url().toString();
3844 QString warning = url + ":67: Unable to assign QString to int";
3845 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3846 o->setProperty("assignWrongType", true);
3848 warning = url + ":71: Unable to assign QString to int";
3849 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3850 o->setProperty("assignWrongTypeToValueType", true);
3855 void tst_qdeclarativeecmascript::eval()
3857 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
3859 QObject *o = component.create();
3862 QCOMPARE(o->property("test1").toBool(), true);
3863 QCOMPARE(o->property("test2").toBool(), true);
3864 QCOMPARE(o->property("test3").toBool(), true);
3865 QCOMPARE(o->property("test4").toBool(), true);
3866 QCOMPARE(o->property("test5").toBool(), true);
3871 void tst_qdeclarativeecmascript::function()
3873 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
3875 QObject *o = component.create();
3878 QCOMPARE(o->property("test1").toBool(), true);
3879 QCOMPARE(o->property("test2").toBool(), true);
3880 QCOMPARE(o->property("test3").toBool(), true);
3885 // Test the "Qt.include" method
3886 void tst_qdeclarativeecmascript::include()
3888 // Non-library relative include
3890 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
3891 QObject *o = component.create();
3894 QCOMPARE(o->property("test0").toInt(), 99);
3895 QCOMPARE(o->property("test1").toBool(), true);
3896 QCOMPARE(o->property("test2").toBool(), true);
3897 QCOMPARE(o->property("test2_1").toBool(), true);
3898 QCOMPARE(o->property("test3").toBool(), true);
3899 QCOMPARE(o->property("test3_1").toBool(), true);
3904 // Library relative include
3906 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
3907 QObject *o = component.create();
3910 QCOMPARE(o->property("test0").toInt(), 99);
3911 QCOMPARE(o->property("test1").toBool(), true);
3912 QCOMPARE(o->property("test2").toBool(), true);
3913 QCOMPARE(o->property("test2_1").toBool(), true);
3914 QCOMPARE(o->property("test3").toBool(), true);
3915 QCOMPARE(o->property("test3_1").toBool(), true);
3922 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
3923 QObject *o = component.create();
3926 QCOMPARE(o->property("test1").toBool(), true);
3927 QCOMPARE(o->property("test2").toBool(), true);
3928 QCOMPARE(o->property("test3").toBool(), true);
3929 QCOMPARE(o->property("test4").toBool(), true);
3930 QCOMPARE(o->property("test5").toBool(), true);
3931 QCOMPARE(o->property("test6").toBool(), true);
3936 // Including file with ".pragma library"
3938 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
3939 QObject *o = component.create();
3941 QCOMPARE(o->property("test1").toInt(), 100);
3948 TestHTTPServer server(8111);
3949 QVERIFY(server.isValid());
3950 server.serveDirectory(SRCDIR "/data");
3952 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
3953 QObject *o = component.create();
3956 QTRY_VERIFY(o->property("done").toBool() == true);
3957 QTRY_VERIFY(o->property("done2").toBool() == true);
3959 QCOMPARE(o->property("test1").toBool(), true);
3960 QCOMPARE(o->property("test2").toBool(), true);
3961 QCOMPARE(o->property("test3").toBool(), true);
3962 QCOMPARE(o->property("test4").toBool(), true);
3963 QCOMPARE(o->property("test5").toBool(), true);
3965 QCOMPARE(o->property("test6").toBool(), true);
3966 QCOMPARE(o->property("test7").toBool(), true);
3967 QCOMPARE(o->property("test8").toBool(), true);
3968 QCOMPARE(o->property("test9").toBool(), true);
3969 QCOMPARE(o->property("test10").toBool(), true);
3976 TestHTTPServer server(8111);
3977 QVERIFY(server.isValid());
3978 server.serveDirectory(SRCDIR "/data");
3980 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
3981 QObject *o = component.create();
3984 QTRY_VERIFY(o->property("done").toBool() == true);
3986 QCOMPARE(o->property("test1").toBool(), true);
3987 QCOMPARE(o->property("test2").toBool(), true);
3988 QCOMPARE(o->property("test3").toBool(), true);
3994 void tst_qdeclarativeecmascript::signalHandlers()
3996 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
3997 QObject *o = component.create();
4000 QVERIFY(o->property("count").toInt() == 0);
4001 QMetaObject::invokeMethod(o, "testSignalCall");
4002 QCOMPARE(o->property("count").toInt(), 1);
4004 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
4005 QCOMPARE(o->property("count").toInt(), 1);
4006 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
4008 QVERIFY(o->property("funcCount").toInt() == 0);
4009 QMetaObject::invokeMethod(o, "testSignalConnection");
4010 QCOMPARE(o->property("funcCount").toInt(), 1);
4012 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
4013 QCOMPARE(o->property("funcCount").toInt(), 2);
4015 QMetaObject::invokeMethod(o, "testSignalDefined");
4016 QCOMPARE(o->property("definedResult").toBool(), true);
4018 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
4019 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
4024 void tst_qdeclarativeecmascript::qtbug_10696()
4026 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
4027 QObject *o = component.create();
4032 void tst_qdeclarativeecmascript::qtbug_11606()
4034 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
4035 QObject *o = component.create();
4037 QCOMPARE(o->property("test").toBool(), true);
4041 void tst_qdeclarativeecmascript::qtbug_11600()
4043 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
4044 QObject *o = component.create();
4046 QCOMPARE(o->property("test").toBool(), true);
4050 // Reading and writing non-scriptable properties should fail
4051 void tst_qdeclarativeecmascript::nonscriptable()
4053 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
4054 QObject *o = component.create();
4056 QCOMPARE(o->property("readOk").toBool(), true);
4057 QCOMPARE(o->property("writeOk").toBool(), true);
4061 // deleteLater() should not be callable from QML
4062 void tst_qdeclarativeecmascript::deleteLater()
4064 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
4065 QObject *o = component.create();
4067 QCOMPARE(o->property("test").toBool(), true);
4071 void tst_qdeclarativeecmascript::in()
4073 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
4074 QObject *o = component.create();
4076 QCOMPARE(o->property("test1").toBool(), true);
4077 QCOMPARE(o->property("test2").toBool(), true);
4081 void tst_qdeclarativeecmascript::sharedAttachedObject()
4083 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
4084 QObject *o = component.create();
4086 QCOMPARE(o->property("test1").toBool(), true);
4087 QCOMPARE(o->property("test2").toBool(), true);
4092 void tst_qdeclarativeecmascript::objectName()
4094 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
4095 QObject *o = component.create();
4098 QCOMPARE(o->property("test1").toString(), QString("hello"));
4099 QCOMPARE(o->property("test2").toString(), QString("ell"));
4101 o->setObjectName("world");
4103 QCOMPARE(o->property("test1").toString(), QString("world"));
4104 QCOMPARE(o->property("test2").toString(), QString("orl"));
4109 void tst_qdeclarativeecmascript::writeRemovesBinding()
4111 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
4112 QObject *o = component.create();
4115 QCOMPARE(o->property("test").toBool(), true);
4120 // Test bindings assigned to alias properties actually assign to the alias' target
4121 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
4123 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4124 QObject *o = component.create();
4127 QCOMPARE(o->property("test").toBool(), true);
4132 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4133 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4136 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4137 QObject *o = component.create();
4140 QCOMPARE(o->property("test").toBool(), true);
4146 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4147 QObject *o = component.create();
4150 QCOMPARE(o->property("test").toBool(), true);
4156 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4157 QObject *o = component.create();
4160 QCOMPARE(o->property("test").toBool(), true);
4166 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4167 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4170 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4171 QObject *o = component.create();
4174 QCOMPARE(o->property("test").toBool(), true);
4180 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
4181 QObject *o = component.create();
4184 QCOMPARE(o->property("test").toBool(), true);
4190 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
4191 QObject *o = component.create();
4194 QCOMPARE(o->property("test").toBool(), true);
4200 // Allow an alais to a composite element
4202 void tst_qdeclarativeecmascript::aliasToCompositeElement()
4204 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
4206 QObject *object = component.create();
4207 QVERIFY(object != 0);
4212 void tst_qdeclarativeecmascript::revisionErrors()
4215 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
4216 QString url = component.url().toString();
4218 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4219 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
4220 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
4222 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4223 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4224 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4225 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4226 QVERIFY(object != 0);
4230 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
4231 QString url = component.url().toString();
4233 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
4234 // method2, prop2 from MyRevisionedClass not available
4235 // method4, prop4 from MyRevisionedSubclass not available
4236 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4237 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
4238 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
4239 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
4240 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
4242 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4243 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4244 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4245 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
4246 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
4247 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4248 QVERIFY(object != 0);
4252 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
4253 QString url = component.url().toString();
4255 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
4256 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
4257 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
4258 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
4259 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
4260 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4261 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4262 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4263 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4264 QVERIFY(object != 0);
4269 void tst_qdeclarativeecmascript::revision()
4272 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
4273 QString url = component.url().toString();
4275 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4276 QVERIFY(object != 0);
4280 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
4281 QString url = component.url().toString();
4283 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4284 QVERIFY(object != 0);
4288 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
4289 QString url = component.url().toString();
4291 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4292 QVERIFY(object != 0);
4295 // Test that non-root classes can resolve revisioned methods
4297 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
4299 QObject *object = component.create();
4300 QVERIFY(object != 0);
4301 QCOMPARE(object->property("test").toReal(), 11.);
4306 void tst_qdeclarativeecmascript::realToInt()
4308 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
4309 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
4310 QVERIFY(object != 0);
4312 QMetaObject::invokeMethod(object, "test1");
4313 QCOMPARE(object->value(), int(4));
4314 QMetaObject::invokeMethod(object, "test2");
4315 QCOMPARE(object->value(), int(8));
4317 void tst_qdeclarativeecmascript::dynamicString()
4319 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
4320 QObject *object = component.create();
4321 QVERIFY(object != 0);
4322 QCOMPARE(object->property("stringProperty").toString(),
4323 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
4326 void tst_qdeclarativeecmascript::automaticSemicolon()
4328 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
4329 QObject *object = component.create();
4330 QVERIFY(object != 0);
4333 QTEST_MAIN(tst_qdeclarativeecmascript)
4335 #include "tst_qdeclarativeecmascript.moc"