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 objectConversion();
156 void booleanConversion();
157 void handleReferenceManagement();
162 void dynamicCreationCrash();
163 void dynamicCreationOwnership();
165 void nullObjectBinding();
166 void deletedEngine();
167 void libraryScriptAssert();
168 void variantsAssignedUndefined();
170 void qtcreatorbug_1289();
171 void noSpuriousWarningsAtShutdown();
172 void canAssignNullToQObject();
173 void functionAssignment_fromBinding();
174 void functionAssignment_fromJS();
175 void functionAssignment_fromJS_data();
176 void functionAssignmentfromJS_invalid();
182 void nonscriptable();
185 void sharedAttachedObject();
187 void writeRemovesBinding();
188 void aliasBindingsAssignCorrectly();
189 void aliasBindingsOverrideTarget();
190 void aliasWritesOverrideBindings();
191 void aliasToCompositeElement();
193 void dynamicString();
195 void signalHandlers();
197 void callQtInvokables();
198 void invokableObjectArg();
199 void invokableObjectRet();
201 void revisionErrors();
204 void automaticSemicolon();
207 QDeclarativeEngine engine;
210 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
212 void tst_qdeclarativeecmascript::assignBasicTypes()
215 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
216 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
217 QVERIFY(object != 0);
218 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
219 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
220 QCOMPARE(object->stringProperty(), QString("Hello World!"));
221 QCOMPARE(object->uintProperty(), uint(10));
222 QCOMPARE(object->intProperty(), -19);
223 QCOMPARE((float)object->realProperty(), float(23.2));
224 QCOMPARE((float)object->doubleProperty(), float(-19.75));
225 QCOMPARE((float)object->floatProperty(), float(8.5));
226 QCOMPARE(object->colorProperty(), QColor("red"));
227 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
228 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
229 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
230 QCOMPARE(object->pointProperty(), QPoint(99,13));
231 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
232 QCOMPARE(object->sizeProperty(), QSize(99, 13));
233 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
234 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
235 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
236 QCOMPARE(object->boolProperty(), true);
237 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
238 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
239 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
243 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
244 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
245 QVERIFY(object != 0);
246 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
247 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
248 QCOMPARE(object->stringProperty(), QString("Hello World!"));
249 QCOMPARE(object->uintProperty(), uint(10));
250 QCOMPARE(object->intProperty(), -19);
251 QCOMPARE((float)object->realProperty(), float(23.2));
252 QCOMPARE((float)object->doubleProperty(), float(-19.75));
253 QCOMPARE((float)object->floatProperty(), float(8.5));
254 QCOMPARE(object->colorProperty(), QColor("red"));
255 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
256 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
257 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
258 QCOMPARE(object->pointProperty(), QPoint(99,13));
259 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
260 QCOMPARE(object->sizeProperty(), QSize(99, 13));
261 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
262 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
263 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
264 QCOMPARE(object->boolProperty(), true);
265 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
266 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
267 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
272 void tst_qdeclarativeecmascript::idShortcutInvalidates()
275 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
276 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
277 QVERIFY(object != 0);
278 QVERIFY(object->objectProperty() != 0);
279 delete object->objectProperty();
280 QVERIFY(object->objectProperty() == 0);
285 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
286 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
287 QVERIFY(object != 0);
288 QVERIFY(object->objectProperty() != 0);
289 delete object->objectProperty();
290 QVERIFY(object->objectProperty() == 0);
295 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
298 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
299 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
300 QVERIFY(object != 0);
301 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
305 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
306 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
307 QVERIFY(object != 0);
308 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
313 void tst_qdeclarativeecmascript::signalAssignment()
316 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
317 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
318 QVERIFY(object != 0);
319 QCOMPARE(object->string(), QString());
320 emit object->basicSignal();
321 QCOMPARE(object->string(), QString("pass"));
326 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
327 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
328 QVERIFY(object != 0);
329 QCOMPARE(object->string(), QString());
330 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
331 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
336 void tst_qdeclarativeecmascript::methods()
339 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
340 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
341 QVERIFY(object != 0);
342 QCOMPARE(object->methodCalled(), false);
343 QCOMPARE(object->methodIntCalled(), false);
344 emit object->basicSignal();
345 QCOMPARE(object->methodCalled(), true);
346 QCOMPARE(object->methodIntCalled(), false);
351 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
352 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
353 QVERIFY(object != 0);
354 QCOMPARE(object->methodCalled(), false);
355 QCOMPARE(object->methodIntCalled(), false);
356 emit object->basicSignal();
357 QCOMPARE(object->methodCalled(), false);
358 QCOMPARE(object->methodIntCalled(), true);
363 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
364 QObject *object = component.create();
365 QVERIFY(object != 0);
366 QCOMPARE(object->property("test").toInt(), 19);
371 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
372 QObject *object = component.create();
373 QVERIFY(object != 0);
374 QCOMPARE(object->property("test").toInt(), 19);
375 QCOMPARE(object->property("test2").toInt(), 17);
376 QCOMPARE(object->property("test3").toInt(), 16);
381 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
382 QObject *object = component.create();
383 QVERIFY(object != 0);
384 QCOMPARE(object->property("test").toInt(), 9);
389 void tst_qdeclarativeecmascript::bindingLoop()
391 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
392 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
393 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
394 QObject *object = component.create();
395 QVERIFY(object != 0);
399 void tst_qdeclarativeecmascript::basicExpressions_data()
401 QTest::addColumn<QString>("expression");
402 QTest::addColumn<QVariant>("result");
403 QTest::addColumn<bool>("nest");
405 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
406 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
407 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
408 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
409 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
410 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
411 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
412 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
413 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
414 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
415 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
416 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
417 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
418 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
419 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
420 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
421 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
422 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
423 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
426 void tst_qdeclarativeecmascript::basicExpressions()
428 QFETCH(QString, expression);
429 QFETCH(QVariant, result);
435 MyDefaultObject1 default1;
436 MyDefaultObject3 default3;
437 object1.setStringProperty("Object1");
438 object2.setStringProperty("Object2");
439 object3.setStringProperty("Object3");
441 QDeclarativeContext context(engine.rootContext());
442 QDeclarativeContext nestedContext(&context);
444 context.setContextObject(&default1);
445 context.setContextProperty("a", QVariant(1944));
446 context.setContextProperty("b", QVariant("Milk"));
447 context.setContextProperty("object", &object1);
448 context.setContextProperty("objectOverride", &object2);
449 nestedContext.setContextObject(&default3);
450 nestedContext.setContextProperty("b", QVariant("Cow"));
451 nestedContext.setContextProperty("objectOverride", &object3);
452 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
454 MyExpression expr(nest?&nestedContext:&context, expression);
455 QCOMPARE(expr.evaluate(), result);
458 void tst_qdeclarativeecmascript::arrayExpressions()
464 QDeclarativeContext context(engine.rootContext());
465 context.setContextProperty("a", &obj1);
466 context.setContextProperty("b", &obj2);
467 context.setContextProperty("c", &obj3);
469 MyExpression expr(&context, "[a, b, c, 10]");
470 QVariant result = expr.evaluate();
471 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
472 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
473 QCOMPARE(list.count(), 4);
474 QCOMPARE(list.at(0), &obj1);
475 QCOMPARE(list.at(1), &obj2);
476 QCOMPARE(list.at(2), &obj3);
477 QCOMPARE(list.at(3), (QObject *)0);
480 // Tests that modifying a context property will reevaluate expressions
481 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
483 QDeclarativeContext context(engine.rootContext());
486 MyQmlObject *object3 = new MyQmlObject;
488 object1.setStringProperty("Hello");
489 object2.setStringProperty("World");
491 context.setContextProperty("testProp", QVariant(1));
492 context.setContextProperty("testObj", &object1);
493 context.setContextProperty("testObj2", object3);
496 MyExpression expr(&context, "testProp + 1");
497 QCOMPARE(expr.changed, false);
498 QCOMPARE(expr.evaluate(), QVariant(2));
500 context.setContextProperty("testProp", QVariant(2));
501 QCOMPARE(expr.changed, true);
502 QCOMPARE(expr.evaluate(), QVariant(3));
506 MyExpression expr(&context, "testProp + testProp + testProp");
507 QCOMPARE(expr.changed, false);
508 QCOMPARE(expr.evaluate(), QVariant(6));
510 context.setContextProperty("testProp", QVariant(4));
511 QCOMPARE(expr.changed, true);
512 QCOMPARE(expr.evaluate(), QVariant(12));
516 MyExpression expr(&context, "testObj.stringProperty");
517 QCOMPARE(expr.changed, false);
518 QCOMPARE(expr.evaluate(), QVariant("Hello"));
520 context.setContextProperty("testObj", &object2);
521 QCOMPARE(expr.changed, true);
522 QCOMPARE(expr.evaluate(), QVariant("World"));
526 MyExpression expr(&context, "testObj.stringProperty /**/");
527 QCOMPARE(expr.changed, false);
528 QCOMPARE(expr.evaluate(), QVariant("World"));
530 context.setContextProperty("testObj", &object1);
531 QCOMPARE(expr.changed, true);
532 QCOMPARE(expr.evaluate(), QVariant("Hello"));
536 MyExpression expr(&context, "testObj2");
537 QCOMPARE(expr.changed, false);
538 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
544 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
546 QDeclarativeContext context(engine.rootContext());
550 context.setContextProperty("testObj", &object1);
552 object1.setStringProperty(QLatin1String("Hello"));
553 object2.setStringProperty(QLatin1String("Dog"));
554 object3.setStringProperty(QLatin1String("Cat"));
557 MyExpression expr(&context, "testObj.stringProperty");
558 QCOMPARE(expr.changed, false);
559 QCOMPARE(expr.evaluate(), QVariant("Hello"));
561 object1.setStringProperty(QLatin1String("World"));
562 QCOMPARE(expr.changed, true);
563 QCOMPARE(expr.evaluate(), QVariant("World"));
567 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
568 QCOMPARE(expr.changed, false);
569 QCOMPARE(expr.evaluate(), QVariant());
571 object1.setObjectProperty(&object2);
572 QCOMPARE(expr.changed, true);
573 expr.changed = false;
574 QCOMPARE(expr.evaluate(), QVariant("Dog"));
576 object1.setObjectProperty(&object3);
577 QCOMPARE(expr.changed, true);
578 expr.changed = false;
579 QCOMPARE(expr.evaluate(), QVariant("Cat"));
581 object1.setObjectProperty(0);
582 QCOMPARE(expr.changed, true);
583 expr.changed = false;
584 QCOMPARE(expr.evaluate(), QVariant());
586 object1.setObjectProperty(&object3);
587 QCOMPARE(expr.changed, true);
588 expr.changed = false;
589 QCOMPARE(expr.evaluate(), QVariant("Cat"));
591 object3.setStringProperty("Donkey");
592 QCOMPARE(expr.changed, true);
593 expr.changed = false;
594 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
598 void tst_qdeclarativeecmascript::deferredProperties()
600 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
601 MyDeferredObject *object =
602 qobject_cast<MyDeferredObject *>(component.create());
603 QVERIFY(object != 0);
604 QCOMPARE(object->value(), 0);
605 QVERIFY(object->objectProperty() == 0);
606 QVERIFY(object->objectProperty2() != 0);
607 qmlExecuteDeferred(object);
608 QCOMPARE(object->value(), 10);
609 QVERIFY(object->objectProperty() != 0);
610 MyQmlObject *qmlObject =
611 qobject_cast<MyQmlObject *>(object->objectProperty());
612 QVERIFY(qmlObject != 0);
613 QCOMPARE(qmlObject->value(), 10);
614 object->setValue(19);
615 QCOMPARE(qmlObject->value(), 19);
620 // Check errors on deferred properties are correctly emitted
621 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
623 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
624 MyDeferredObject *object =
625 qobject_cast<MyDeferredObject *>(component.create());
626 QVERIFY(object != 0);
627 QCOMPARE(object->value(), 0);
628 QVERIFY(object->objectProperty() == 0);
629 QVERIFY(object->objectProperty2() == 0);
631 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject* objectProperty";
632 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
634 qmlExecuteDeferred(object);
639 void tst_qdeclarativeecmascript::extensionObjects()
641 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
642 MyExtendedObject *object =
643 qobject_cast<MyExtendedObject *>(component.create());
644 QVERIFY(object != 0);
645 QCOMPARE(object->baseProperty(), 13);
646 QCOMPARE(object->coreProperty(), 9);
647 object->setProperty("extendedProperty", QVariant(11));
648 object->setProperty("baseExtendedProperty", QVariant(92));
649 QCOMPARE(object->coreProperty(), 11);
650 QCOMPARE(object->baseProperty(), 92);
652 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
654 QCOMPARE(nested->baseProperty(), 13);
655 QCOMPARE(nested->coreProperty(), 9);
656 nested->setProperty("extendedProperty", QVariant(11));
657 nested->setProperty("baseExtendedProperty", QVariant(92));
658 QCOMPARE(nested->coreProperty(), 11);
659 QCOMPARE(nested->baseProperty(), 92);
664 void tst_qdeclarativeecmascript::overrideExtensionProperties()
666 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
667 OverrideDefaultPropertyObject *object =
668 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
669 QVERIFY(object != 0);
670 QVERIFY(object->secondProperty() != 0);
671 QVERIFY(object->firstProperty() == 0);
676 void tst_qdeclarativeecmascript::attachedProperties()
679 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
680 QObject *object = component.create();
681 QVERIFY(object != 0);
682 QCOMPARE(object->property("a").toInt(), 19);
683 QCOMPARE(object->property("b").toInt(), 19);
684 QCOMPARE(object->property("c").toInt(), 19);
685 QCOMPARE(object->property("d").toInt(), 19);
690 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
691 QObject *object = component.create();
692 QVERIFY(object != 0);
693 QCOMPARE(object->property("a").toInt(), 26);
694 QCOMPARE(object->property("b").toInt(), 26);
695 QCOMPARE(object->property("c").toInt(), 26);
696 QCOMPARE(object->property("d").toInt(), 26);
702 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
703 QObject *object = component.create();
704 QVERIFY(object != 0);
706 QMetaObject::invokeMethod(object, "writeValue2");
708 MyQmlAttachedObject *attached =
709 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
710 QVERIFY(attached != 0);
712 QCOMPARE(attached->value2(), 9);
717 void tst_qdeclarativeecmascript::enums()
721 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
722 QObject *object = component.create();
723 QVERIFY(object != 0);
725 QCOMPARE(object->property("a").toInt(), 0);
726 QCOMPARE(object->property("b").toInt(), 1);
727 QCOMPARE(object->property("c").toInt(), 2);
728 QCOMPARE(object->property("d").toInt(), 3);
729 QCOMPARE(object->property("e").toInt(), 0);
730 QCOMPARE(object->property("f").toInt(), 1);
731 QCOMPARE(object->property("g").toInt(), 2);
732 QCOMPARE(object->property("h").toInt(), 3);
733 QCOMPARE(object->property("i").toInt(), 19);
734 QCOMPARE(object->property("j").toInt(), 19);
738 // Non-existent enums
740 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
742 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int a";
743 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int b";
744 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
745 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
747 QObject *object = component.create();
748 QVERIFY(object != 0);
749 QCOMPARE(object->property("a").toInt(), 0);
750 QCOMPARE(object->property("b").toInt(), 0);
756 void tst_qdeclarativeecmascript::valueTypeFunctions()
758 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
759 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
761 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
762 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
768 Tests that writing a constant to a property with a binding on it disables the
771 void tst_qdeclarativeecmascript::constantsOverrideBindings()
775 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
776 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
777 QVERIFY(object != 0);
779 QCOMPARE(object->property("c2").toInt(), 0);
780 object->setProperty("c1", QVariant(9));
781 QCOMPARE(object->property("c2").toInt(), 9);
783 emit object->basicSignal();
785 QCOMPARE(object->property("c2").toInt(), 13);
786 object->setProperty("c1", QVariant(8));
787 QCOMPARE(object->property("c2").toInt(), 13);
792 // During construction
794 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
795 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
796 QVERIFY(object != 0);
798 QCOMPARE(object->property("c1").toInt(), 0);
799 QCOMPARE(object->property("c2").toInt(), 10);
800 object->setProperty("c1", QVariant(9));
801 QCOMPARE(object->property("c1").toInt(), 9);
802 QCOMPARE(object->property("c2").toInt(), 10);
810 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
811 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
812 QVERIFY(object != 0);
814 QCOMPARE(object->property("c2").toInt(), 0);
815 object->setProperty("c1", QVariant(9));
816 QCOMPARE(object->property("c2").toInt(), 9);
818 object->setProperty("c2", QVariant(13));
819 QCOMPARE(object->property("c2").toInt(), 13);
820 object->setProperty("c1", QVariant(7));
821 QCOMPARE(object->property("c1").toInt(), 7);
822 QCOMPARE(object->property("c2").toInt(), 13);
830 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
831 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
832 QVERIFY(object != 0);
834 QCOMPARE(object->property("c1").toInt(), 0);
835 QCOMPARE(object->property("c3").toInt(), 10);
836 object->setProperty("c1", QVariant(9));
837 QCOMPARE(object->property("c1").toInt(), 9);
838 QCOMPARE(object->property("c3").toInt(), 10);
845 Tests that assigning a binding to a property that already has a binding causes
846 the original binding to be disabled.
848 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
850 QDeclarativeComponent component(&engine,
851 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
852 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
853 QVERIFY(object != 0);
855 QCOMPARE(object->property("c1").toInt(), 0);
856 QCOMPARE(object->property("c2").toInt(), 0);
857 QCOMPARE(object->property("c3").toInt(), 0);
859 object->setProperty("c1", QVariant(9));
860 QCOMPARE(object->property("c1").toInt(), 9);
861 QCOMPARE(object->property("c2").toInt(), 0);
862 QCOMPARE(object->property("c3").toInt(), 0);
864 object->setProperty("c3", QVariant(8));
865 QCOMPARE(object->property("c1").toInt(), 9);
866 QCOMPARE(object->property("c2").toInt(), 8);
867 QCOMPARE(object->property("c3").toInt(), 8);
873 Access a non-existent attached object.
875 Tests for a regression where this used to crash.
877 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
879 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
881 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString stringProperty";
882 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
884 QObject *object = component.create();
885 QVERIFY(object != 0);
890 void tst_qdeclarativeecmascript::scope()
893 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
894 QObject *object = component.create();
895 QVERIFY(object != 0);
897 QCOMPARE(object->property("test1").toInt(), 1);
898 QCOMPARE(object->property("test2").toInt(), 2);
899 QCOMPARE(object->property("test3").toString(), QString("1Test"));
900 QCOMPARE(object->property("test4").toString(), QString("2Test"));
901 QCOMPARE(object->property("test5").toInt(), 1);
902 QCOMPARE(object->property("test6").toInt(), 1);
903 QCOMPARE(object->property("test7").toInt(), 2);
904 QCOMPARE(object->property("test8").toInt(), 2);
905 QCOMPARE(object->property("test9").toInt(), 1);
906 QCOMPARE(object->property("test10").toInt(), 3);
912 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
913 QObject *object = component.create();
914 QVERIFY(object != 0);
916 QCOMPARE(object->property("test1").toInt(), 19);
917 QCOMPARE(object->property("test2").toInt(), 19);
918 QCOMPARE(object->property("test3").toInt(), 14);
919 QCOMPARE(object->property("test4").toInt(), 14);
920 QCOMPARE(object->property("test5").toInt(), 24);
921 QCOMPARE(object->property("test6").toInt(), 24);
927 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
928 QObject *object = component.create();
929 QVERIFY(object != 0);
931 QCOMPARE(object->property("test1").toBool(), true);
932 QCOMPARE(object->property("test2").toBool(), true);
933 QCOMPARE(object->property("test3").toBool(), true);
938 // Signal argument scope
940 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
941 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
942 QVERIFY(object != 0);
944 QCOMPARE(object->property("test").toInt(), 0);
945 QCOMPARE(object->property("test2").toString(), QString());
947 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
949 QCOMPARE(object->property("test").toInt(), 13);
950 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
956 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
957 QObject *object = component.create();
958 QVERIFY(object != 0);
960 QCOMPARE(object->property("test1").toBool(), true);
961 QCOMPARE(object->property("test2").toBool(), true);
967 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
968 QObject *object = component.create();
969 QVERIFY(object != 0);
971 QCOMPARE(object->property("test").toBool(), true);
977 // In 4.7, non-library javascript files that had no imports shared the imports of their
979 void tst_qdeclarativeecmascript::importScope()
981 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
982 QObject *o = component.create();
985 QCOMPARE(o->property("test").toInt(), 240);
991 Tests that "any" type passes through a synthesized signal parameter. This
992 is essentially a test of QDeclarativeMetaType::copy()
994 void tst_qdeclarativeecmascript::signalParameterTypes()
996 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
997 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
998 QVERIFY(object != 0);
1000 emit object->basicSignal();
1002 QCOMPARE(object->property("intProperty").toInt(), 10);
1003 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1004 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1005 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1006 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1007 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1013 Test that two JS objects for the same QObject compare as equal.
1015 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1017 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1018 QObject *object = component.create();
1019 QVERIFY(object != 0);
1021 QCOMPARE(object->property("test1").toBool(), true);
1022 QCOMPARE(object->property("test2").toBool(), true);
1023 QCOMPARE(object->property("test3").toBool(), true);
1024 QCOMPARE(object->property("test4").toBool(), true);
1025 QCOMPARE(object->property("test5").toBool(), true);
1031 Confirm bindings and alias properties can coexist.
1033 Tests for a regression where the binding would not reevaluate.
1035 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1037 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1038 QObject *object = component.create();
1039 QVERIFY(object != 0);
1041 QCOMPARE(object->property("c2").toInt(), 3);
1042 QCOMPARE(object->property("c3").toInt(), 3);
1044 object->setProperty("c2", QVariant(19));
1046 QCOMPARE(object->property("c2").toInt(), 19);
1047 QCOMPARE(object->property("c3").toInt(), 19);
1053 Ensure that we can write undefined value to an alias property,
1054 and that the aliased property is reset correctly if possible.
1056 void tst_qdeclarativeecmascript::aliasPropertyReset()
1058 QObject *object = 0;
1060 // test that a manual write (of undefined) to a resettable aliased property succeeds
1061 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1062 object = c1.create();
1063 QVERIFY(object != 0);
1064 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1065 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1066 QMetaObject::invokeMethod(object, "resetAliased");
1067 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1068 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1071 // test that a manual write (of undefined) to a resettable alias property succeeds
1072 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1073 object = c2.create();
1074 QVERIFY(object != 0);
1075 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1076 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1077 QMetaObject::invokeMethod(object, "resetAlias");
1078 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1079 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1082 // test that an alias to a bound property works correctly
1083 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1084 object = c3.create();
1085 QVERIFY(object != 0);
1086 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1087 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1088 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1089 QMetaObject::invokeMethod(object, "resetAlias");
1090 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1091 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1092 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1095 // test that a manual write (of undefined) to a resettable alias property
1096 // whose aliased property's object has been deleted, does not crash.
1097 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1098 object = c4.create();
1099 QVERIFY(object != 0);
1100 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1101 QObject *loader = object->findChild<QObject*>("loader");
1102 QVERIFY(loader != 0);
1104 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1105 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1106 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1107 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1108 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1111 // test that binding an alias property to an undefined value works correctly
1112 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1113 object = c5.create();
1114 QVERIFY(object != 0);
1115 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1118 // test that a manual write (of undefined) to a non-resettable property fails properly
1119 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1120 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1121 QDeclarativeComponent e1(&engine, url);
1122 object = e1.create();
1123 QVERIFY(object != 0);
1124 QCOMPARE(object->property("intAlias").value<int>(), 12);
1125 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1126 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1127 QMetaObject::invokeMethod(object, "resetAlias");
1128 QCOMPARE(object->property("intAlias").value<int>(), 12);
1129 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1133 void tst_qdeclarativeecmascript::dynamicCreation_data()
1135 QTest::addColumn<QString>("method");
1136 QTest::addColumn<QString>("createdName");
1138 QTest::newRow("One") << "createOne" << "objectOne";
1139 QTest::newRow("Two") << "createTwo" << "objectTwo";
1140 QTest::newRow("Three") << "createThree" << "objectThree";
1144 Test using createQmlObject to dynamically generate an item
1145 Also using createComponent is tested.
1147 void tst_qdeclarativeecmascript::dynamicCreation()
1149 QFETCH(QString, method);
1150 QFETCH(QString, createdName);
1152 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1153 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1154 QVERIFY(object != 0);
1156 QMetaObject::invokeMethod(object, method.toUtf8());
1157 QObject *created = object->objectProperty();
1159 QCOMPARE(created->objectName(), createdName);
1165 Tests the destroy function
1167 void tst_qdeclarativeecmascript::dynamicDestruction()
1170 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1171 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1172 QVERIFY(object != 0);
1173 QDeclarativeGuard<QObject> createdQmlObject = 0;
1175 QMetaObject::invokeMethod(object, "create");
1176 createdQmlObject = object->objectProperty();
1177 QVERIFY(createdQmlObject);
1178 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1180 QMetaObject::invokeMethod(object, "killOther");
1181 QVERIFY(createdQmlObject);
1182 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1183 QVERIFY(createdQmlObject);
1184 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1185 if (createdQmlObject) {
1187 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1190 QVERIFY(!createdQmlObject);
1192 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1193 QMetaObject::invokeMethod(object, "killMe");
1196 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1201 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1202 QObject *o = component.create();
1205 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1207 QMetaObject::invokeMethod(o, "create");
1209 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1211 QMetaObject::invokeMethod(o, "destroy");
1213 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1215 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1222 tests that id.toString() works
1224 void tst_qdeclarativeecmascript::objectToString()
1226 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1227 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1228 QVERIFY(object != 0);
1229 QMetaObject::invokeMethod(object, "testToString");
1230 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1231 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1237 tests that id.hasOwnProperty() works
1239 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1241 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1242 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1243 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1244 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1246 QDeclarativeComponent component(&engine, url);
1247 QObject *object = component.create();
1248 QVERIFY(object != 0);
1250 // test QObjects in QML
1251 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1252 QVERIFY(object->property("result").value<bool>() == true);
1253 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1254 QVERIFY(object->property("result").value<bool>() == false);
1256 // now test other types in QML
1257 QObject *child = object->findChild<QObject*>("typeObj");
1258 QVERIFY(child != 0);
1259 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1260 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1261 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1262 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1263 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1264 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1265 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1266 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1267 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1268 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1269 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1270 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1272 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1273 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1274 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1275 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1276 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1277 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1278 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1279 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1280 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1286 Tests bindings that indirectly cause their own deletion work.
1288 This test is best run under valgrind to ensure no invalid memory access occur.
1290 void tst_qdeclarativeecmascript::selfDeletingBinding()
1293 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1294 QObject *object = component.create();
1295 QVERIFY(object != 0);
1296 object->setProperty("triggerDelete", true);
1301 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1302 QObject *object = component.create();
1303 QVERIFY(object != 0);
1304 object->setProperty("triggerDelete", true);
1310 Test that extended object properties can be accessed.
1312 This test a regression where this used to crash. The issue was specificially
1313 for extended objects that did not include a synthesized meta object (so non-root
1314 and no synthesiszed properties).
1316 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1318 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1319 QObject *object = component.create();
1320 QVERIFY(object != 0);
1325 Test file/lineNumbers for binding/Script errors.
1327 void tst_qdeclarativeecmascript::scriptErrors()
1329 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1330 QString url = component.url().toString();
1332 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1333 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1334 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1335 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1336 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1337 QString warning6 = url + ":7: Unable to assign [undefined] to int x";
1338 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1339 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1341 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1342 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1343 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1344 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1345 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1346 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1347 QVERIFY(object != 0);
1349 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1350 emit object->basicSignal();
1352 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1353 emit object->anotherBasicSignal();
1355 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1356 emit object->thirdBasicSignal();
1362 Test file/lineNumbers for inline functions.
1364 void tst_qdeclarativeecmascript::functionErrors()
1366 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1367 QString url = component.url().toString();
1369 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1371 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1373 QObject *object = component.create();
1374 QVERIFY(object != 0);
1377 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1378 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1379 url = componentTwo.url().toString();
1380 object = componentTwo.create();
1381 QVERIFY(object != 0);
1383 QString srpname = object->property("srp_name").toString();
1385 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1386 QLatin1String(" is not a function");
1387 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1388 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1393 Test various errors that can occur when assigning a property from script
1395 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1397 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1399 QString url = component.url().toString();
1401 QObject *object = component.create();
1402 QVERIFY(object != 0);
1404 QCOMPARE(object->property("test1").toBool(), true);
1405 QCOMPARE(object->property("test2").toBool(), true);
1411 Test bindings still work when the reeval is triggered from within
1414 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1416 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1417 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1418 QVERIFY(object != 0);
1420 QCOMPARE(object->property("base").toReal(), 50.);
1421 QCOMPARE(object->property("test1").toReal(), 50.);
1422 QCOMPARE(object->property("test2").toReal(), 50.);
1424 object->basicSignal();
1426 QCOMPARE(object->property("base").toReal(), 200.);
1427 QCOMPARE(object->property("test1").toReal(), 200.);
1428 QCOMPARE(object->property("test2").toReal(), 200.);
1430 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1432 QCOMPARE(object->property("base").toReal(), 400.);
1433 QCOMPARE(object->property("test1").toReal(), 400.);
1434 QCOMPARE(object->property("test2").toReal(), 400.);
1440 Test that list properties can be iterated from ECMAScript
1442 void tst_qdeclarativeecmascript::listProperties()
1444 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1445 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1446 QVERIFY(object != 0);
1448 QCOMPARE(object->property("test1").toInt(), 21);
1449 QCOMPARE(object->property("test2").toInt(), 2);
1450 QCOMPARE(object->property("test3").toBool(), true);
1451 QCOMPARE(object->property("test4").toBool(), true);
1456 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1458 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1459 QString url = component.url().toString();
1461 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1463 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1464 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1465 QVERIFY(object != 0);
1467 QCOMPARE(object->property("test").toBool(), false);
1469 MyQmlObject object2;
1470 MyQmlObject object3;
1471 object2.setObjectProperty(&object3);
1472 object->setObjectProperty(&object2);
1474 QCOMPARE(object->property("test").toBool(), true);
1479 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1481 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1482 QString url = component.url().toString();
1484 QString warning = component.url().toString() + ":6: Error: JS exception";
1486 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1487 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1488 QVERIFY(object != 0);
1492 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1494 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1495 QString url = component.url().toString();
1497 QString warning = component.url().toString() + ":5: Error: JS exception";
1499 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1500 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1501 QVERIFY(object != 0);
1505 static int transientErrorsMsgCount = 0;
1506 static void transientErrorsMsgHandler(QtMsgType, const char *)
1508 ++transientErrorsMsgCount;
1511 // Check that transient binding errors are not displayed
1512 void tst_qdeclarativeecmascript::transientErrors()
1515 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1517 transientErrorsMsgCount = 0;
1518 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1520 QObject *object = component.create();
1521 QVERIFY(object != 0);
1523 qInstallMsgHandler(old);
1525 QCOMPARE(transientErrorsMsgCount, 0);
1530 // One binding erroring multiple times, but then resolving
1532 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1534 transientErrorsMsgCount = 0;
1535 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1537 QObject *object = component.create();
1538 QVERIFY(object != 0);
1540 qInstallMsgHandler(old);
1542 QCOMPARE(transientErrorsMsgCount, 0);
1548 // Check that errors during shutdown are minimized
1549 void tst_qdeclarativeecmascript::shutdownErrors()
1551 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1552 QObject *object = component.create();
1553 QVERIFY(object != 0);
1555 transientErrorsMsgCount = 0;
1556 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1560 qInstallMsgHandler(old);
1561 QCOMPARE(transientErrorsMsgCount, 0);
1564 void tst_qdeclarativeecmascript::compositePropertyType()
1566 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1567 QTest::ignoreMessage(QtDebugMsg, "hello world");
1568 QObject *object = qobject_cast<QObject *>(component.create());
1573 void tst_qdeclarativeecmascript::jsObject()
1575 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1576 QObject *object = component.create();
1577 QVERIFY(object != 0);
1579 QCOMPARE(object->property("test").toInt(), 92);
1584 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1587 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1588 QObject *object = component.create();
1589 QVERIFY(object != 0);
1591 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1593 object->setProperty("setUndefined", true);
1595 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1597 object->setProperty("setUndefined", false);
1599 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1604 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1605 QObject *object = component.create();
1606 QVERIFY(object != 0);
1608 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1610 QMetaObject::invokeMethod(object, "doReset");
1612 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1619 void tst_qdeclarativeecmascript::bug1()
1621 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1622 QObject *object = component.create();
1623 QVERIFY(object != 0);
1625 QCOMPARE(object->property("test").toInt(), 14);
1627 object->setProperty("a", 11);
1629 QCOMPARE(object->property("test").toInt(), 3);
1631 object->setProperty("b", true);
1633 QCOMPARE(object->property("test").toInt(), 9);
1638 void tst_qdeclarativeecmascript::bug2()
1640 QDeclarativeComponent component(&engine);
1641 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1643 QObject *object = component.create();
1644 QVERIFY(object != 0);
1649 // Don't crash in createObject when the component has errors.
1650 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1652 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1653 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1654 QVERIFY(object != 0);
1656 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1657 QMetaObject::invokeMethod(object, "dontCrash");
1658 QObject *created = object->objectProperty();
1659 QVERIFY(created == 0);
1664 // ownership transferred to JS, ensure that GC runs the dtor
1665 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1668 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1670 // allow the engine to go out of scope too.
1672 QDeclarativeEngine dcoEngine;
1673 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1674 QObject *object = component.create();
1675 QVERIFY(object != 0);
1676 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1677 QVERIFY(mdcdo != 0);
1678 mdcdo->setDtorCount(&dtorCount);
1680 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1681 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1683 // we do this once manually, but it should be done automatically
1684 // when the engine goes out of scope (since it should gc in dtor)
1685 QMetaObject::invokeMethod(object, "performGc");
1688 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1694 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1695 QCOMPARE(dtorCount, expectedDtorCount);
1699 void tst_qdeclarativeecmascript::regExpBug()
1701 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1702 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1703 QVERIFY(object != 0);
1704 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1708 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1710 QString functionSource = QLatin1String("(function(object) { return ") +
1711 QLatin1String(source) + QLatin1String(" })");
1713 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1716 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1717 if (function.IsEmpty())
1719 v8::Handle<v8::Value> args[] = { o };
1720 function->Call(engine->global(), 1, args);
1721 return tc.HasCaught();
1724 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1725 const char *source, v8::Handle<v8::Value> result)
1727 QString functionSource = QLatin1String("(function(object) { return ") +
1728 QLatin1String(source) + QLatin1String(" })");
1730 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1733 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1734 if (function.IsEmpty())
1736 v8::Handle<v8::Value> args[] = { o };
1738 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1743 return value->StrictEquals(result);
1746 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1749 QString functionSource = QLatin1String("(function(object) { return ") +
1750 QLatin1String(source) + QLatin1String(" })");
1752 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1754 return v8::Handle<v8::Value>();
1755 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1756 if (function.IsEmpty())
1757 return v8::Handle<v8::Value>();
1758 v8::Handle<v8::Value> args[] = { o };
1760 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1763 return v8::Handle<v8::Value>();
1767 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1768 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1769 #define EVALUATE(source) evaluate(engine, object, source)
1771 void tst_qdeclarativeecmascript::callQtInvokables()
1773 MyInvokableObject o;
1775 QDeclarativeEngine qmlengine;
1776 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1778 QV8Engine *engine = ep->v8engine();
1780 v8::HandleScope handle_scope;
1781 v8::Context::Scope scope(engine->context());
1783 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1785 // Non-existent methods
1787 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1788 QCOMPARE(o.error(), false);
1789 QCOMPARE(o.invoked(), -1);
1790 QCOMPARE(o.actuals().count(), 0);
1793 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1794 QCOMPARE(o.error(), false);
1795 QCOMPARE(o.invoked(), -1);
1796 QCOMPARE(o.actuals().count(), 0);
1798 // Insufficient arguments
1800 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1801 QCOMPARE(o.error(), false);
1802 QCOMPARE(o.invoked(), -1);
1803 QCOMPARE(o.actuals().count(), 0);
1806 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1807 QCOMPARE(o.error(), false);
1808 QCOMPARE(o.invoked(), -1);
1809 QCOMPARE(o.actuals().count(), 0);
1811 // Excessive arguments
1813 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1814 QCOMPARE(o.error(), false);
1815 QCOMPARE(o.invoked(), 8);
1816 QCOMPARE(o.actuals().count(), 1);
1817 QCOMPARE(o.actuals().at(0), QVariant(10));
1820 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1821 QCOMPARE(o.error(), false);
1822 QCOMPARE(o.invoked(), 9);
1823 QCOMPARE(o.actuals().count(), 2);
1824 QCOMPARE(o.actuals().at(0), QVariant(10));
1825 QCOMPARE(o.actuals().at(1), QVariant(11));
1827 // Test return types
1829 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1830 QCOMPARE(o.error(), false);
1831 QCOMPARE(o.invoked(), 0);
1832 QCOMPARE(o.actuals().count(), 0);
1835 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1836 QCOMPARE(o.error(), false);
1837 QCOMPARE(o.invoked(), 1);
1838 QCOMPARE(o.actuals().count(), 0);
1841 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1842 QCOMPARE(o.error(), false);
1843 QCOMPARE(o.invoked(), 2);
1844 QCOMPARE(o.actuals().count(), 0);
1848 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1849 QVERIFY(!ret.IsEmpty());
1850 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1851 QCOMPARE(o.error(), false);
1852 QCOMPARE(o.invoked(), 3);
1853 QCOMPARE(o.actuals().count(), 0);
1858 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1859 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1860 QCOMPARE(o.error(), false);
1861 QCOMPARE(o.invoked(), 4);
1862 QCOMPARE(o.actuals().count(), 0);
1866 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1867 QCOMPARE(o.error(), false);
1868 QCOMPARE(o.invoked(), 5);
1869 QCOMPARE(o.actuals().count(), 0);
1873 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1874 QVERIFY(ret->IsString());
1875 QCOMPARE(engine->toString(ret), QString("Hello world"));
1876 QCOMPARE(o.error(), false);
1877 QCOMPARE(o.invoked(), 6);
1878 QCOMPARE(o.actuals().count(), 0);
1882 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1883 QCOMPARE(o.error(), false);
1884 QCOMPARE(o.invoked(), 7);
1885 QCOMPARE(o.actuals().count(), 0);
1889 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1890 QCOMPARE(o.error(), false);
1891 QCOMPARE(o.invoked(), 8);
1892 QCOMPARE(o.actuals().count(), 1);
1893 QCOMPARE(o.actuals().at(0), QVariant(94));
1896 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1897 QCOMPARE(o.error(), false);
1898 QCOMPARE(o.invoked(), 8);
1899 QCOMPARE(o.actuals().count(), 1);
1900 QCOMPARE(o.actuals().at(0), QVariant(94));
1903 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1904 QCOMPARE(o.error(), false);
1905 QCOMPARE(o.invoked(), 8);
1906 QCOMPARE(o.actuals().count(), 1);
1907 QCOMPARE(o.actuals().at(0), QVariant(0));
1910 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1911 QCOMPARE(o.error(), false);
1912 QCOMPARE(o.invoked(), 8);
1913 QCOMPARE(o.actuals().count(), 1);
1914 QCOMPARE(o.actuals().at(0), QVariant(0));
1917 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1918 QCOMPARE(o.error(), false);
1919 QCOMPARE(o.invoked(), 8);
1920 QCOMPARE(o.actuals().count(), 1);
1921 QCOMPARE(o.actuals().at(0), QVariant(0));
1924 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1925 QCOMPARE(o.error(), false);
1926 QCOMPARE(o.invoked(), 8);
1927 QCOMPARE(o.actuals().count(), 1);
1928 QCOMPARE(o.actuals().at(0), QVariant(0));
1931 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1932 QCOMPARE(o.error(), false);
1933 QCOMPARE(o.invoked(), 9);
1934 QCOMPARE(o.actuals().count(), 2);
1935 QCOMPARE(o.actuals().at(0), QVariant(122));
1936 QCOMPARE(o.actuals().at(1), QVariant(9));
1939 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1940 QCOMPARE(o.error(), false);
1941 QCOMPARE(o.invoked(), 10);
1942 QCOMPARE(o.actuals().count(), 1);
1943 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1946 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1947 QCOMPARE(o.error(), false);
1948 QCOMPARE(o.invoked(), 10);
1949 QCOMPARE(o.actuals().count(), 1);
1950 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1953 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1954 QCOMPARE(o.error(), false);
1955 QCOMPARE(o.invoked(), 10);
1956 QCOMPARE(o.actuals().count(), 1);
1957 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1960 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1961 QCOMPARE(o.error(), false);
1962 QCOMPARE(o.invoked(), 10);
1963 QCOMPARE(o.actuals().count(), 1);
1964 QCOMPARE(o.actuals().at(0), QVariant(0));
1967 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1968 QCOMPARE(o.error(), false);
1969 QCOMPARE(o.invoked(), 10);
1970 QCOMPARE(o.actuals().count(), 1);
1971 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1974 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
1975 QCOMPARE(o.error(), false);
1976 QCOMPARE(o.invoked(), 10);
1977 QCOMPARE(o.actuals().count(), 1);
1978 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1981 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
1982 QCOMPARE(o.error(), false);
1983 QCOMPARE(o.invoked(), 11);
1984 QCOMPARE(o.actuals().count(), 1);
1985 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
1988 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
1989 QCOMPARE(o.error(), false);
1990 QCOMPARE(o.invoked(), 11);
1991 QCOMPARE(o.actuals().count(), 1);
1992 QCOMPARE(o.actuals().at(0), QVariant("19"));
1996 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
1997 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
1998 QCOMPARE(o.error(), false);
1999 QCOMPARE(o.invoked(), 11);
2000 QCOMPARE(o.actuals().count(), 1);
2001 QCOMPARE(o.actuals().at(0), QVariant(expected));
2005 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2006 QCOMPARE(o.error(), false);
2007 QCOMPARE(o.invoked(), 11);
2008 QCOMPARE(o.actuals().count(), 1);
2009 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2012 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2013 QCOMPARE(o.error(), false);
2014 QCOMPARE(o.invoked(), 11);
2015 QCOMPARE(o.actuals().count(), 1);
2016 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2019 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2020 QCOMPARE(o.error(), false);
2021 QCOMPARE(o.invoked(), 12);
2022 QCOMPARE(o.actuals().count(), 1);
2023 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2026 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2027 QCOMPARE(o.error(), false);
2028 QCOMPARE(o.invoked(), 12);
2029 QCOMPARE(o.actuals().count(), 1);
2030 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2033 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2034 QCOMPARE(o.error(), false);
2035 QCOMPARE(o.invoked(), 12);
2036 QCOMPARE(o.actuals().count(), 1);
2037 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2040 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2041 QCOMPARE(o.error(), false);
2042 QCOMPARE(o.invoked(), 12);
2043 QCOMPARE(o.actuals().count(), 1);
2044 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2047 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2048 QCOMPARE(o.error(), false);
2049 QCOMPARE(o.invoked(), 12);
2050 QCOMPARE(o.actuals().count(), 1);
2051 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2054 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2055 QCOMPARE(o.error(), false);
2056 QCOMPARE(o.invoked(), 12);
2057 QCOMPARE(o.actuals().count(), 1);
2058 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2061 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2062 QCOMPARE(o.error(), false);
2063 QCOMPARE(o.invoked(), 13);
2064 QCOMPARE(o.actuals().count(), 1);
2065 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2068 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2069 QCOMPARE(o.error(), false);
2070 QCOMPARE(o.invoked(), 13);
2071 QCOMPARE(o.actuals().count(), 1);
2072 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2075 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2076 QCOMPARE(o.error(), false);
2077 QCOMPARE(o.invoked(), 13);
2078 QCOMPARE(o.actuals().count(), 1);
2079 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2082 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2083 QCOMPARE(o.error(), false);
2084 QCOMPARE(o.invoked(), 13);
2085 QCOMPARE(o.actuals().count(), 1);
2086 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2089 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2090 QCOMPARE(o.error(), false);
2091 QCOMPARE(o.invoked(), 13);
2092 QCOMPARE(o.actuals().count(), 1);
2093 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2096 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2097 QCOMPARE(o.error(), false);
2098 QCOMPARE(o.invoked(), 14);
2099 QCOMPARE(o.actuals().count(), 1);
2100 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2103 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2104 QCOMPARE(o.error(), false);
2105 QCOMPARE(o.invoked(), 14);
2106 QCOMPARE(o.actuals().count(), 1);
2107 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2110 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2111 QCOMPARE(o.error(), false);
2112 QCOMPARE(o.invoked(), 14);
2113 QCOMPARE(o.actuals().count(), 1);
2114 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2117 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2118 QCOMPARE(o.error(), false);
2119 QCOMPARE(o.invoked(), 14);
2120 QCOMPARE(o.actuals().count(), 1);
2121 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2124 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2125 QCOMPARE(o.error(), false);
2126 QCOMPARE(o.invoked(), 15);
2127 QCOMPARE(o.actuals().count(), 2);
2128 QCOMPARE(o.actuals().at(0), QVariant(4));
2129 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2132 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2133 QCOMPARE(o.error(), false);
2134 QCOMPARE(o.invoked(), 15);
2135 QCOMPARE(o.actuals().count(), 2);
2136 QCOMPARE(o.actuals().at(0), QVariant(8));
2137 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2140 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2141 QCOMPARE(o.error(), false);
2142 QCOMPARE(o.invoked(), 15);
2143 QCOMPARE(o.actuals().count(), 2);
2144 QCOMPARE(o.actuals().at(0), QVariant(3));
2145 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2148 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2149 QCOMPARE(o.error(), false);
2150 QCOMPARE(o.invoked(), 15);
2151 QCOMPARE(o.actuals().count(), 2);
2152 QCOMPARE(o.actuals().at(0), QVariant(44));
2153 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2156 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2157 QCOMPARE(o.error(), false);
2158 QCOMPARE(o.invoked(), -1);
2159 QCOMPARE(o.actuals().count(), 0);
2162 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2163 QCOMPARE(o.error(), false);
2164 QCOMPARE(o.invoked(), 16);
2165 QCOMPARE(o.actuals().count(), 1);
2166 QCOMPARE(o.actuals().at(0), QVariant(10));
2169 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2170 QCOMPARE(o.error(), false);
2171 QCOMPARE(o.invoked(), 17);
2172 QCOMPARE(o.actuals().count(), 2);
2173 QCOMPARE(o.actuals().at(0), QVariant(10));
2174 QCOMPARE(o.actuals().at(1), QVariant(11));
2177 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2178 QCOMPARE(o.error(), false);
2179 QCOMPARE(o.invoked(), 18);
2180 QCOMPARE(o.actuals().count(), 1);
2181 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2184 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2185 QCOMPARE(o.error(), false);
2186 QCOMPARE(o.invoked(), 19);
2187 QCOMPARE(o.actuals().count(), 1);
2188 QCOMPARE(o.actuals().at(0), QVariant(9));
2191 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2192 QCOMPARE(o.error(), false);
2193 QCOMPARE(o.invoked(), 20);
2194 QCOMPARE(o.actuals().count(), 2);
2195 QCOMPARE(o.actuals().at(0), QVariant(10));
2196 QCOMPARE(o.actuals().at(1), QVariant(19));
2199 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2200 QCOMPARE(o.error(), false);
2201 QCOMPARE(o.invoked(), 20);
2202 QCOMPARE(o.actuals().count(), 2);
2203 QCOMPARE(o.actuals().at(0), QVariant(10));
2204 QCOMPARE(o.actuals().at(1), QVariant(13));
2207 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2208 QCOMPARE(o.error(), false);
2209 QCOMPARE(o.invoked(), -3);
2210 QCOMPARE(o.actuals().count(), 1);
2211 QCOMPARE(o.actuals().at(0), QVariant(9));
2214 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2215 QCOMPARE(o.error(), false);
2216 QCOMPARE(o.invoked(), 21);
2217 QCOMPARE(o.actuals().count(), 2);
2218 QCOMPARE(o.actuals().at(0), QVariant(9));
2219 QCOMPARE(o.actuals().at(1), QVariant());
2222 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2223 QCOMPARE(o.error(), false);
2224 QCOMPARE(o.invoked(), 21);
2225 QCOMPARE(o.actuals().count(), 2);
2226 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2227 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2230 // QTBUG-13047 (check that you can pass registered object types as args)
2231 void tst_qdeclarativeecmascript::invokableObjectArg()
2233 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2235 QObject *o = component.create();
2237 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2239 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2244 // QTBUG-13047 (check that you can return registered object types from methods)
2245 void tst_qdeclarativeecmascript::invokableObjectRet()
2247 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2249 QObject *o = component.create();
2251 QCOMPARE(o->property("test").toBool(), true);
2256 void tst_qdeclarativeecmascript::listToVariant()
2258 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2260 MyQmlContainer container;
2262 QDeclarativeContext context(engine.rootContext());
2263 context.setContextObject(&container);
2265 QObject *object = component.create(&context);
2266 QVERIFY(object != 0);
2268 QVariant v = object->property("test");
2269 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2270 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2276 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2277 void tst_qdeclarativeecmascript::listAssignment()
2279 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2280 QObject *obj = component.create();
2281 QCOMPARE(obj->property("list1length").toInt(), 2);
2282 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2283 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2284 QCOMPARE(list1.count(&list1), list2.count(&list2));
2285 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2286 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2291 void tst_qdeclarativeecmascript::multiEngineObject()
2294 obj.setStringProperty("Howdy planet");
2296 QDeclarativeEngine e1;
2297 e1.rootContext()->setContextProperty("thing", &obj);
2298 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2300 QDeclarativeEngine e2;
2301 e2.rootContext()->setContextProperty("thing", &obj);
2302 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2304 QObject *o1 = c1.create();
2305 QObject *o2 = c2.create();
2307 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2308 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2314 // Test that references to QObjects are cleanup when the object is destroyed
2315 void tst_qdeclarativeecmascript::deletedObject()
2317 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2319 QObject *object = component.create();
2321 QCOMPARE(object->property("test1").toBool(), true);
2322 QCOMPARE(object->property("test2").toBool(), true);
2323 QCOMPARE(object->property("test3").toBool(), true);
2324 QCOMPARE(object->property("test4").toBool(), true);
2329 void tst_qdeclarativeecmascript::attachedPropertyScope()
2331 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2333 QObject *object = component.create();
2334 QVERIFY(object != 0);
2336 MyQmlAttachedObject *attached =
2337 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2338 QVERIFY(attached != 0);
2340 QCOMPARE(object->property("value2").toInt(), 0);
2342 attached->emitMySignal();
2344 QCOMPARE(object->property("value2").toInt(), 9);
2349 void tst_qdeclarativeecmascript::scriptConnect()
2352 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2354 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2355 QVERIFY(object != 0);
2357 QCOMPARE(object->property("test").toBool(), false);
2358 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2359 QCOMPARE(object->property("test").toBool(), true);
2365 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2367 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2368 QVERIFY(object != 0);
2370 QCOMPARE(object->property("test").toBool(), false);
2371 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2372 QCOMPARE(object->property("test").toBool(), true);
2378 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2380 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2381 QVERIFY(object != 0);
2383 QCOMPARE(object->property("test").toBool(), false);
2384 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2385 QCOMPARE(object->property("test").toBool(), true);
2391 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2393 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2394 QVERIFY(object != 0);
2396 QCOMPARE(object->methodCalled(), false);
2397 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2398 QCOMPARE(object->methodCalled(), true);
2404 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2406 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2407 QVERIFY(object != 0);
2409 QCOMPARE(object->methodCalled(), false);
2410 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2411 QCOMPARE(object->methodCalled(), true);
2417 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2419 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2420 QVERIFY(object != 0);
2422 QCOMPARE(object->property("test").toInt(), 0);
2423 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2424 QCOMPARE(object->property("test").toInt(), 2);
2430 void tst_qdeclarativeecmascript::scriptDisconnect()
2433 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2435 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2436 QVERIFY(object != 0);
2438 QCOMPARE(object->property("test").toInt(), 0);
2439 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2440 QCOMPARE(object->property("test").toInt(), 1);
2441 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2442 QCOMPARE(object->property("test").toInt(), 2);
2443 emit object->basicSignal();
2444 QCOMPARE(object->property("test").toInt(), 2);
2445 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2446 QCOMPARE(object->property("test").toInt(), 2);
2452 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2454 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2455 QVERIFY(object != 0);
2457 QCOMPARE(object->property("test").toInt(), 0);
2458 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2459 QCOMPARE(object->property("test").toInt(), 1);
2460 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2461 QCOMPARE(object->property("test").toInt(), 2);
2462 emit object->basicSignal();
2463 QCOMPARE(object->property("test").toInt(), 2);
2464 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2465 QCOMPARE(object->property("test").toInt(), 2);
2471 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2473 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2474 QVERIFY(object != 0);
2476 QCOMPARE(object->property("test").toInt(), 0);
2477 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2478 QCOMPARE(object->property("test").toInt(), 1);
2479 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2480 QCOMPARE(object->property("test").toInt(), 2);
2481 emit object->basicSignal();
2482 QCOMPARE(object->property("test").toInt(), 2);
2483 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2484 QCOMPARE(object->property("test").toInt(), 3);
2489 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2491 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2492 QVERIFY(object != 0);
2494 QCOMPARE(object->property("test").toInt(), 0);
2495 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2496 QCOMPARE(object->property("test").toInt(), 1);
2497 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2498 QCOMPARE(object->property("test").toInt(), 2);
2499 emit object->basicSignal();
2500 QCOMPARE(object->property("test").toInt(), 2);
2501 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2502 QCOMPARE(object->property("test").toInt(), 3);
2508 class OwnershipObject : public QObject
2512 OwnershipObject() { object = new QObject; }
2514 QPointer<QObject> object;
2517 QObject *getObject() { return object; }
2520 void tst_qdeclarativeecmascript::ownership()
2522 OwnershipObject own;
2523 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2524 context->setContextObject(&own);
2527 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2529 QVERIFY(own.object != 0);
2531 QObject *object = component.create(context);
2533 engine.collectGarbage();
2535 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2537 QVERIFY(own.object == 0);
2542 own.object = new QObject(&own);
2545 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2547 QVERIFY(own.object != 0);
2549 QObject *object = component.create(context);
2551 engine.collectGarbage();
2553 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2555 QVERIFY(own.object != 0);
2563 class CppOwnershipReturnValue : public QObject
2567 CppOwnershipReturnValue() : value(0) {}
2568 ~CppOwnershipReturnValue() { delete value; }
2570 Q_INVOKABLE QObject *create() {
2571 value = new QObject;
2572 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2576 Q_INVOKABLE MyQmlObject *createQmlObject() {
2577 MyQmlObject *rv = new MyQmlObject;
2582 QPointer<QObject> value;
2586 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2587 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2589 CppOwnershipReturnValue source;
2592 QDeclarativeEngine engine;
2593 engine.rootContext()->setContextProperty("source", &source);
2595 QVERIFY(source.value == 0);
2597 QDeclarativeComponent component(&engine);
2598 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2600 QObject *object = component.create();
2602 QVERIFY(object != 0);
2603 QVERIFY(source.value != 0);
2608 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2610 QVERIFY(source.value != 0);
2614 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2616 CppOwnershipReturnValue source;
2619 QDeclarativeEngine engine;
2620 engine.rootContext()->setContextProperty("source", &source);
2622 QVERIFY(source.value == 0);
2624 QDeclarativeComponent component(&engine);
2625 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2627 QObject *object = component.create();
2629 QVERIFY(object != 0);
2630 QVERIFY(source.value != 0);
2635 engine.collectGarbage();
2636 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2638 QVERIFY(source.value == 0);
2641 class QListQObjectMethodsObject : public QObject
2645 QListQObjectMethodsObject() {
2646 m_objects.append(new MyQmlObject());
2647 m_objects.append(new MyQmlObject());
2650 ~QListQObjectMethodsObject() {
2651 qDeleteAll(m_objects);
2655 QList<QObject *> getObjects() { return m_objects; }
2658 QList<QObject *> m_objects;
2661 // Tests that returning a QList<QObject*> from a method works
2662 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2664 QListQObjectMethodsObject obj;
2665 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2666 context->setContextObject(&obj);
2668 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2670 QObject *object = component.create(context);
2672 QCOMPARE(object->property("test").toInt(), 2);
2673 QCOMPARE(object->property("test2").toBool(), true);
2680 void tst_qdeclarativeecmascript::strictlyEquals()
2682 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2684 QObject *object = component.create();
2685 QVERIFY(object != 0);
2687 QCOMPARE(object->property("test1").toBool(), true);
2688 QCOMPARE(object->property("test2").toBool(), true);
2689 QCOMPARE(object->property("test3").toBool(), true);
2690 QCOMPARE(object->property("test4").toBool(), true);
2691 QCOMPARE(object->property("test5").toBool(), true);
2692 QCOMPARE(object->property("test6").toBool(), true);
2693 QCOMPARE(object->property("test7").toBool(), true);
2694 QCOMPARE(object->property("test8").toBool(), true);
2699 void tst_qdeclarativeecmascript::compiled()
2701 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2703 QObject *object = component.create();
2704 QVERIFY(object != 0);
2706 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2707 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2708 QCOMPARE(object->property("test3").toBool(), true);
2709 QCOMPARE(object->property("test4").toBool(), false);
2710 QCOMPARE(object->property("test5").toBool(), false);
2711 QCOMPARE(object->property("test6").toBool(), true);
2713 QCOMPARE(object->property("test7").toInt(), 185);
2714 QCOMPARE(object->property("test8").toInt(), 167);
2715 QCOMPARE(object->property("test9").toBool(), true);
2716 QCOMPARE(object->property("test10").toBool(), false);
2717 QCOMPARE(object->property("test11").toBool(), false);
2718 QCOMPARE(object->property("test12").toBool(), true);
2720 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2721 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2722 QCOMPARE(object->property("test15").toBool(), false);
2723 QCOMPARE(object->property("test16").toBool(), true);
2725 QCOMPARE(object->property("test17").toInt(), 5);
2726 QCOMPARE(object->property("test18").toReal(), qreal(176));
2727 QCOMPARE(object->property("test19").toInt(), 7);
2728 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2729 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2730 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2731 QCOMPARE(object->property("test23").toBool(), true);
2732 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2733 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2738 // Test that numbers assigned in bindings as strings work consistently
2739 void tst_qdeclarativeecmascript::numberAssignment()
2741 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2743 QObject *object = component.create();
2744 QVERIFY(object != 0);
2746 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2747 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2748 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2749 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2750 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2752 QCOMPARE(object->property("test5"), QVariant((int)7));
2753 QCOMPARE(object->property("test6"), QVariant((int)7));
2754 QCOMPARE(object->property("test7"), QVariant((int)6));
2755 QCOMPARE(object->property("test8"), QVariant((int)6));
2757 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2758 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2759 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2760 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2765 void tst_qdeclarativeecmascript::propertySplicing()
2767 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2769 QObject *object = component.create();
2770 QVERIFY(object != 0);
2772 QCOMPARE(object->property("test").toBool(), true);
2778 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2780 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2782 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2783 QVERIFY(object != 0);
2785 MyQmlObject::MyType type;
2786 type.value = 0x8971123;
2787 emit object->signalWithUnknownType(type);
2789 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2791 QCOMPARE(result.value, type.value);
2797 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2799 QTest::addColumn<QString>("expression");
2800 QTest::addColumn<QString>("compare");
2802 QString compareStrict("(function(a, b) { return a === b; })");
2803 QTest::newRow("true") << "true" << compareStrict;
2804 QTest::newRow("undefined") << "undefined" << compareStrict;
2805 QTest::newRow("null") << "null" << compareStrict;
2806 QTest::newRow("123") << "123" << compareStrict;
2807 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2809 QString comparePropertiesStrict(
2811 " if (typeof b != 'object')"
2813 " var props = Object.getOwnPropertyNames(b);"
2814 " for (var i = 0; i < props.length; ++i) {"
2815 " var p = props[i];"
2816 " return arguments.callee(a[p], b[p]);"
2819 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2820 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2823 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2825 QFETCH(QString, expression);
2826 QFETCH(QString, compare);
2828 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2829 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2830 QVERIFY(object != 0);
2832 QJSValue value = engine.evaluate(expression);
2833 QVERIFY(!engine.hasUncaughtException());
2834 object->setProperty("expression", expression);
2835 object->setProperty("compare", compare);
2836 object->setProperty("pass", false);
2838 emit object->signalWithVariant(QVariant::fromValue(value));
2839 QVERIFY(object->property("pass").toBool());
2842 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2844 signalWithJSValueInVariant_data();
2847 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2849 QFETCH(QString, expression);
2850 QFETCH(QString, compare);
2852 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2853 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2854 QVERIFY(object != 0);
2857 QJSValue value = engine2.evaluate(expression);
2858 QVERIFY(!engine2.hasUncaughtException());
2859 object->setProperty("expression", expression);
2860 object->setProperty("compare", compare);
2861 object->setProperty("pass", false);
2863 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2864 emit object->signalWithVariant(QVariant::fromValue(value));
2865 QVERIFY(!object->property("pass").toBool());
2868 void tst_qdeclarativeecmascript::moduleApi_data()
2870 QTest::addColumn<QUrl>("testfile");
2871 QTest::addColumn<QString>("errorMessage");
2872 QTest::addColumn<QStringList>("warningMessages");
2873 QTest::addColumn<QStringList>("readProperties");
2874 QTest::addColumn<QVariantList>("readExpectedValues");
2875 QTest::addColumn<QStringList>("writeProperties");
2876 QTest::addColumn<QVariantList>("writeValues");
2877 QTest::addColumn<QStringList>("readBackProperties");
2878 QTest::addColumn<QVariantList>("readBackExpectedValues");
2880 QTest::newRow("qobject, register + read + method")
2881 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2884 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2885 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2886 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2892 QTest::newRow("script, register + read")
2893 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2896 << (QStringList() << "scriptTest")
2897 << (QVariantList() << 13)
2903 QTest::newRow("qobject, caching + read")
2904 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2907 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2908 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2914 QTest::newRow("script, caching + read")
2915 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2918 << (QStringList() << "scriptTest")
2919 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2925 QTest::newRow("qobject, writing + readonly constraints")
2926 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2928 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2929 << (QStringList() << "readOnlyProperty" << "writableProperty")
2930 << (QVariantList() << 20 << 50)
2931 << (QStringList() << "firstProperty" << "writableProperty")
2932 << (QVariantList() << 30 << 30)
2933 << (QStringList() << "readOnlyProperty" << "writableProperty")
2934 << (QVariantList() << 20 << 30);
2936 QTest::newRow("script, writing + readonly constraints")
2937 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
2939 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
2940 << (QStringList() << "readBack" << "unchanged")
2941 << (QVariantList() << 13 << 42)
2942 << (QStringList() << "firstProperty" << "secondProperty")
2943 << (QVariantList() << 30 << 30)
2944 << (QStringList() << "readBack" << "unchanged")
2945 << (QVariantList() << 30 << 42);
2947 QTest::newRow("qobject module API enum values in JS")
2948 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
2951 << (QStringList() << "enumValue" << "enumMethod")
2952 << (QVariantList() << 42 << 30)
2958 QTest::newRow("qobject, invalid major version fail")
2959 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
2960 << QString("QDeclarativeComponent: Component is not ready")
2969 QTest::newRow("qobject, invalid minor version fail")
2970 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
2971 << QString("QDeclarativeComponent: Component is not ready")
2981 void tst_qdeclarativeecmascript::moduleApi()
2983 QFETCH(QUrl, testfile);
2984 QFETCH(QString, errorMessage);
2985 QFETCH(QStringList, warningMessages);
2986 QFETCH(QStringList, readProperties);
2987 QFETCH(QVariantList, readExpectedValues);
2988 QFETCH(QStringList, writeProperties);
2989 QFETCH(QVariantList, writeValues);
2990 QFETCH(QStringList, readBackProperties);
2991 QFETCH(QVariantList, readBackExpectedValues);
2993 QDeclarativeComponent component(&engine, testfile);
2995 if (!errorMessage.isEmpty())
2996 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
2998 if (warningMessages.size())
2999 foreach (const QString &warning, warningMessages)
3000 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3002 QObject *object = component.create();
3003 if (!errorMessage.isEmpty()) {
3004 QVERIFY(object == 0);
3006 QVERIFY(object != 0);
3007 for (int i = 0; i < readProperties.size(); ++i)
3008 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3009 for (int i = 0; i < writeProperties.size(); ++i)
3010 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3011 for (int i = 0; i < readBackProperties.size(); ++i)
3012 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3017 void tst_qdeclarativeecmascript::importScripts()
3019 QObject *object = 0;
3021 // first, ensure that the required behaviour works.
3022 QDeclarativeComponent component(&engine, TEST_FILE("jsimport/testImport.qml"));
3023 object = component.create();
3024 QVERIFY(object != 0);
3025 QCOMPARE(object->property("importedScriptStringValue"), QVariant(QString(QLatin1String("Hello, World!"))));
3026 QCOMPARE(object->property("importedScriptFunctionValue"), QVariant(20));
3027 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(19));
3028 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(2));
3031 QDeclarativeComponent componentTwo(&engine, TEST_FILE("jsimport/testImportScoping.qml"));
3032 object = componentTwo.create();
3033 QVERIFY(object != 0);
3034 QCOMPARE(object->property("componentError"), QVariant(5));
3037 // then, ensure that unintended behaviour does not work.
3038 QDeclarativeComponent failOneComponent(&engine, TEST_FILE("jsimportfail/failOne.qml"));
3039 QString expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined");
3040 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
3041 object = failOneComponent.create();
3042 QVERIFY(object != 0);
3043 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
3045 QDeclarativeComponent failTwoComponent(&engine, TEST_FILE("jsimportfail/failTwo.qml"));
3046 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs");
3047 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
3048 object = failTwoComponent.create();
3049 QVERIFY(object != 0);
3050 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
3052 QDeclarativeComponent failThreeComponent(&engine, TEST_FILE("jsimportfail/failThree.qml"));
3053 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined");
3054 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
3055 object = failThreeComponent.create();
3056 QVERIFY(object != 0);
3057 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(false));
3059 QDeclarativeComponent failFourComponent(&engine, TEST_FILE("jsimportfail/failFour.qml"));
3060 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest");
3061 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
3062 object = failFourComponent.create();
3063 QVERIFY(object != 0);
3064 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(0));
3066 QDeclarativeComponent failFiveComponent(&engine, TEST_FILE("jsimportfail/failFive.qml"));
3067 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component");
3068 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
3069 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component");
3070 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
3071 object = failFiveComponent.create();
3072 QVERIFY(object != 0);
3073 QCOMPARE(object->property("componentError"), QVariant(0));
3076 // also, test that importing scripts with .pragma library works as required
3077 QDeclarativeComponent pragmaLibraryComponent(&engine, TEST_FILE("jsimport/testImportPragmaLibrary.qml"));
3078 object = pragmaLibraryComponent.create();
3079 QVERIFY(object != 0);
3080 QCOMPARE(object->property("testValue"), QVariant(31));
3083 // and that .pragma library scripts don't inherit imports from any .qml file
3084 QDeclarativeComponent pragmaLibraryComponentTwo(&engine, TEST_FILE("jsimportfail/testImportPragmaLibrary.qml"));
3085 object = pragmaLibraryComponentTwo.create();
3086 QVERIFY(object != 0);
3087 QCOMPARE(object->property("testValue"), QVariant(0));
3091 void tst_qdeclarativeecmascript::scarceResources()
3093 QPixmap origPixmap(100, 100);
3094 origPixmap.fill(Qt::blue);
3096 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3097 ScarceResourceObject *eo = 0;
3098 QObject *object = 0;
3100 // in the following three cases, the instance created from the component
3101 // has a property which is a copy of the scarce resource; hence, the
3102 // resource should NOT be detached prior to deletion of the object instance,
3103 // unless the resource is destroyed explicitly.
3104 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
3105 object = component.create();
3106 QVERIFY(object != 0);
3107 QVERIFY(object->property("scarceResourceCopy").isValid());
3108 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3109 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3110 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3111 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3114 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3115 object = componentTwo.create();
3116 QVERIFY(object != 0);
3117 QVERIFY(object->property("scarceResourceCopy").isValid());
3118 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3119 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3120 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3121 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3124 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3125 object = componentThree.create();
3126 QVERIFY(object != 0);
3127 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3128 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3129 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3130 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3133 // in the following three cases, no other copy should exist in memory,
3134 // and so it should be detached (unless explicitly preserved).
3135 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3136 object = componentFour.create();
3137 QVERIFY(object != 0);
3138 QVERIFY(object->property("scarceResourceTest").isValid());
3139 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3140 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3141 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3142 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3145 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3146 object = componentFive.create();
3147 QVERIFY(object != 0);
3148 QVERIFY(object->property("scarceResourceTest").isValid());
3149 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3150 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3151 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3152 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3155 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3156 object = componentSix.create();
3157 QVERIFY(object != 0);
3158 QVERIFY(object->property("scarceResourceTest").isValid());
3159 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3160 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3161 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3162 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3165 // test that scarce resources are handled correctly for imports
3166 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3167 object = componentSeven.create();
3168 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3169 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3172 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3173 object = componentEight.create();
3174 QVERIFY(object != 0);
3175 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3176 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3179 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3180 object = componentNine.create();
3181 QVERIFY(object != 0);
3182 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3183 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3184 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3185 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3186 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3187 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3190 // test that scarce resources are handled properly in signal invocation
3191 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3192 object = componentTen.create();
3193 QVERIFY(object != 0);
3194 QObject *srsc = object->findChild<QObject*>("srsc");
3196 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3197 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3198 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3199 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3200 QMetaObject::invokeMethod(srsc, "testSignal");
3201 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3202 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3203 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3204 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3205 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3206 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3207 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3208 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3209 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3210 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3213 // test that scarce resources are handled properly from js functions in qml files
3214 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3215 object = componentEleven.create();
3216 QVERIFY(object != 0);
3217 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3218 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3219 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3220 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3221 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3222 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3223 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3224 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3225 QMetaObject::invokeMethod(object, "releaseScarceResource");
3226 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3227 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3228 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3229 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3232 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3233 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3234 object = componentTwelve.create();
3235 QVERIFY(object != 0);
3236 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3237 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3238 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3239 QString srp_name = object->property("srp_name").toString();
3240 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3241 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3242 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3243 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3244 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3245 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3246 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3250 void tst_qdeclarativeecmascript::propertyChangeSlots()
3252 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3253 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3254 QObject *object = component.create();
3255 QVERIFY(object != 0);
3258 // ensure that invalid property names fail properly.
3259 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3260 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3261 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3262 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3263 object = e1.create();
3264 QVERIFY(object == 0);
3267 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3268 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3269 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3270 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3271 object = e2.create();
3272 QVERIFY(object == 0);
3275 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3276 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3277 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3278 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3279 object = e3.create();
3280 QVERIFY(object == 0);
3283 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3284 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3285 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3286 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3287 object = e4.create();
3288 QVERIFY(object == 0);
3292 // Ensure that QObject type conversion works on binding assignment
3293 void tst_qdeclarativeecmascript::elementAssign()
3295 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3297 QObject *object = component.create();
3298 QVERIFY(object != 0);
3300 QCOMPARE(object->property("test").toBool(), true);
3306 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3308 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3310 QObject *object = component.create();
3311 QVERIFY(object != 0);
3313 QCOMPARE(object->property("test").toBool(), true);
3319 void tst_qdeclarativeecmascript::objectConversion()
3321 QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
3323 QObject *object = component.create();
3324 QVERIFY(object != 0);
3326 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
3327 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
3334 void tst_qdeclarativeecmascript::booleanConversion()
3336 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3338 QObject *object = component.create();
3339 QVERIFY(object != 0);
3341 QCOMPARE(object->property("test_true1").toBool(), true);
3342 QCOMPARE(object->property("test_true2").toBool(), true);
3343 QCOMPARE(object->property("test_true3").toBool(), true);
3344 QCOMPARE(object->property("test_true4").toBool(), true);
3345 QCOMPARE(object->property("test_true5").toBool(), true);
3347 QCOMPARE(object->property("test_false1").toBool(), false);
3348 QCOMPARE(object->property("test_false2").toBool(), false);
3349 QCOMPARE(object->property("test_false3").toBool(), false);
3354 void tst_qdeclarativeecmascript::handleReferenceManagement()
3359 // Linear QObject reference
3360 QDeclarativeEngine hrmEngine;
3361 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3362 QObject *object = component.create();
3363 QVERIFY(object != 0);
3364 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3365 cro->setDtorCount(&dtorCount);
3366 QMetaObject::invokeMethod(object, "createReference");
3367 QMetaObject::invokeMethod(object, "performGc");
3368 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3369 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3371 hrmEngine.collectGarbage();
3372 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3373 QCOMPARE(dtorCount, 3);
3378 // Circular QObject reference
3379 QDeclarativeEngine hrmEngine;
3380 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3381 QObject *object = component.create();
3382 QVERIFY(object != 0);
3383 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3384 cro->setDtorCount(&dtorCount);
3385 QMetaObject::invokeMethod(object, "circularReference");
3386 QMetaObject::invokeMethod(object, "performGc");
3387 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3388 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3390 hrmEngine.collectGarbage();
3391 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3392 QCOMPARE(dtorCount, 3);
3397 // Linear handle reference
3398 QDeclarativeEngine hrmEngine;
3399 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3400 QObject *object = component.create();
3401 QVERIFY(object != 0);
3402 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3404 crh->setDtorCount(&dtorCount);
3405 QMetaObject::invokeMethod(object, "createReference");
3406 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3407 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3408 QVERIFY(first != 0);
3409 QVERIFY(second != 0);
3410 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3411 // now we have to reparent second and make second owned by JS.
3412 second->setParent(0);
3413 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3414 QMetaObject::invokeMethod(object, "performGc");
3415 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3416 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3418 hrmEngine.collectGarbage();
3419 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3420 QCOMPARE(dtorCount, 3);
3425 // Circular handle reference
3426 QDeclarativeEngine hrmEngine;
3427 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3428 QObject *object = component.create();
3429 QVERIFY(object != 0);
3430 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3432 crh->setDtorCount(&dtorCount);
3433 QMetaObject::invokeMethod(object, "circularReference");
3434 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3435 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3436 QVERIFY(first != 0);
3437 QVERIFY(second != 0);
3438 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3439 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3440 // now we have to reparent and change ownership.
3441 first->setParent(0);
3442 second->setParent(0);
3443 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3444 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3445 QMetaObject::invokeMethod(object, "performGc");
3446 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3447 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3449 hrmEngine.collectGarbage();
3450 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3451 QCOMPARE(dtorCount, 3);
3456 // multiple engine interaction - linear reference
3457 QDeclarativeEngine hrmEngine1;
3458 QDeclarativeEngine hrmEngine2;
3459 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3460 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3461 QObject *object1 = component1.create();
3462 QObject *object2 = component2.create();
3463 QVERIFY(object1 != 0);
3464 QVERIFY(object2 != 0);
3465 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3466 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3469 crh1->setDtorCount(&dtorCount);
3470 crh2->setDtorCount(&dtorCount);
3471 QMetaObject::invokeMethod(object1, "createReference");
3472 QMetaObject::invokeMethod(object2, "createReference");
3473 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3474 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3475 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3476 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3477 QVERIFY(first1 != 0);
3478 QVERIFY(second1 != 0);
3479 QVERIFY(first2 != 0);
3480 QVERIFY(second2 != 0);
3481 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3482 // now we have to reparent second2 and make second2 owned by JS.
3483 second2->setParent(0);
3484 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3485 QMetaObject::invokeMethod(object1, "performGc");
3486 QMetaObject::invokeMethod(object2, "performGc");
3487 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3488 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3491 hrmEngine1.collectGarbage();
3492 hrmEngine2.collectGarbage();
3493 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3494 QCOMPARE(dtorCount, 6);
3499 // multiple engine interaction - circular reference
3500 QDeclarativeEngine hrmEngine1;
3501 QDeclarativeEngine hrmEngine2;
3502 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3503 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3504 QObject *object1 = component1.create();
3505 QObject *object2 = component2.create();
3506 QVERIFY(object1 != 0);
3507 QVERIFY(object2 != 0);
3508 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3509 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3512 crh1->setDtorCount(&dtorCount);
3513 crh2->setDtorCount(&dtorCount);
3514 QMetaObject::invokeMethod(object1, "createReference");
3515 QMetaObject::invokeMethod(object2, "createReference");
3516 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3517 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3518 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3519 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3520 QVERIFY(first1 != 0);
3521 QVERIFY(second1 != 0);
3522 QVERIFY(first2 != 0);
3523 QVERIFY(second2 != 0);
3524 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3525 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3526 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3527 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3528 // now we have to reparent and change ownership to JS.
3529 first1->setParent(0);
3530 second1->setParent(0);
3531 first2->setParent(0);
3532 second2->setParent(0);
3533 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
3534 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3535 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3536 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3537 QMetaObject::invokeMethod(object1, "performGc");
3538 QMetaObject::invokeMethod(object2, "performGc");
3539 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3540 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
3543 hrmEngine1.collectGarbage();
3544 hrmEngine2.collectGarbage();
3545 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3546 QCOMPARE(dtorCount, 6);
3551 // multiple engine interaction - linear reference with engine deletion
3552 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
3553 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
3554 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3555 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3556 QObject *object1 = component1.create();
3557 QObject *object2 = component2.create();
3558 QVERIFY(object1 != 0);
3559 QVERIFY(object2 != 0);
3560 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3561 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3564 crh1->setDtorCount(&dtorCount);
3565 crh2->setDtorCount(&dtorCount);
3566 QMetaObject::invokeMethod(object1, "createReference");
3567 QMetaObject::invokeMethod(object2, "createReference");
3568 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3569 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3570 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3571 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3572 QVERIFY(first1 != 0);
3573 QVERIFY(second1 != 0);
3574 QVERIFY(first2 != 0);
3575 QVERIFY(second2 != 0);
3576 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3577 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3578 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3579 // now we have to reparent and change ownership to JS.
3580 first1->setParent(crh1);
3581 second1->setParent(0);
3582 first2->setParent(0);
3583 second2->setParent(0);
3584 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3585 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3586 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3587 QMetaObject::invokeMethod(object1, "performGc");
3588 QMetaObject::invokeMethod(object2, "performGc");
3589 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3590 QCOMPARE(dtorCount, 0);
3592 QMetaObject::invokeMethod(object1, "performGc");
3593 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3594 QCOMPARE(dtorCount, 0);
3597 hrmEngine1->collectGarbage();
3598 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3599 QCOMPARE(dtorCount, 6);
3604 void tst_qdeclarativeecmascript::stringArg()
3606 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
3607 QObject *object = component.create();
3608 QVERIFY(object != 0);
3609 QMetaObject::invokeMethod(object, "success");
3610 QVERIFY(object->property("returnValue").toBool());
3612 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
3613 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
3614 QMetaObject::invokeMethod(object, "failure");
3615 QVERIFY(object->property("returnValue").toBool());
3620 // Test that assigning a null object works
3621 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
3622 void tst_qdeclarativeecmascript::nullObjectBinding()
3624 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
3626 QObject *object = component.create();
3627 QVERIFY(object != 0);
3629 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
3634 // Test that bindings don't evaluate once the engine has been destroyed
3635 void tst_qdeclarativeecmascript::deletedEngine()
3637 QDeclarativeEngine *engine = new QDeclarativeEngine;
3638 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
3640 QObject *object = component.create();
3641 QVERIFY(object != 0);
3643 QCOMPARE(object->property("a").toInt(), 39);
3644 object->setProperty("b", QVariant(9));
3645 QCOMPARE(object->property("a").toInt(), 117);
3649 QCOMPARE(object->property("a").toInt(), 117);
3650 object->setProperty("b", QVariant(10));
3651 QCOMPARE(object->property("a").toInt(), 117);
3656 // Test the crashing part of QTBUG-9705
3657 void tst_qdeclarativeecmascript::libraryScriptAssert()
3659 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
3661 QObject *object = component.create();
3662 QVERIFY(object != 0);
3667 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
3669 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
3671 QObject *object = component.create();
3672 QVERIFY(object != 0);
3674 QCOMPARE(object->property("test1").toInt(), 10);
3675 QCOMPARE(object->property("test2").toInt(), 11);
3677 object->setProperty("runTest", true);
3679 QCOMPARE(object->property("test1"), QVariant());
3680 QCOMPARE(object->property("test2"), QVariant());
3686 void tst_qdeclarativeecmascript::qtbug_9792()
3688 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
3690 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
3692 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
3693 QVERIFY(object != 0);
3695 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
3696 object->basicSignal();
3700 transientErrorsMsgCount = 0;
3701 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3703 object->basicSignal();
3705 qInstallMsgHandler(old);
3707 QCOMPARE(transientErrorsMsgCount, 0);
3712 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
3713 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
3715 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
3717 QObject *o = component.create();
3720 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
3721 QVERIFY(nested != 0);
3723 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
3726 nested = qvariant_cast<QObject *>(o->property("object"));
3727 QVERIFY(nested == 0);
3729 // If the bug is present, the next line will crash
3733 // Test that we shut down without stupid warnings
3734 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
3737 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
3739 QObject *o = component.create();
3741 transientErrorsMsgCount = 0;
3742 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3746 qInstallMsgHandler(old);
3748 QCOMPARE(transientErrorsMsgCount, 0);
3753 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
3755 QObject *o = component.create();
3757 transientErrorsMsgCount = 0;
3758 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3762 qInstallMsgHandler(old);
3764 QCOMPARE(transientErrorsMsgCount, 0);
3768 void tst_qdeclarativeecmascript::canAssignNullToQObject()
3771 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
3773 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3776 QVERIFY(o->objectProperty() != 0);
3778 o->setProperty("runTest", true);
3780 QVERIFY(o->objectProperty() == 0);
3786 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
3788 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3791 QVERIFY(o->objectProperty() == 0);
3797 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
3799 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
3801 QString url = component.url().toString();
3802 QString warning = url + ":4: Unable to assign a function to a property.";
3803 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3805 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3808 QVERIFY(!o->property("a").isValid());
3813 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
3815 QFETCH(QString, triggerProperty);
3817 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3818 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3820 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3822 QVERIFY(!o->property("a").isValid());
3824 o->setProperty("aNumber", QVariant(5));
3825 o->setProperty(triggerProperty.toUtf8().constData(), true);
3826 QCOMPARE(o->property("a"), QVariant(50));
3828 o->setProperty("aNumber", QVariant(10));
3829 QCOMPARE(o->property("a"), QVariant(100));
3834 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
3836 QTest::addColumn<QString>("triggerProperty");
3838 QTest::newRow("assign to property") << "assignToProperty";
3839 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
3841 QTest::newRow("assign to value type") << "assignToValueType";
3843 QTest::newRow("use 'this'") << "assignWithThis";
3844 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
3847 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
3849 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3850 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3852 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3854 QVERIFY(!o->property("a").isValid());
3856 o->setProperty("assignFuncWithoutReturn", true);
3857 QVERIFY(!o->property("a").isValid());
3859 QString url = component.url().toString();
3860 QString warning = url + ":67: Unable to assign QString to int";
3861 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3862 o->setProperty("assignWrongType", true);
3864 warning = url + ":71: Unable to assign QString to int";
3865 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3866 o->setProperty("assignWrongTypeToValueType", true);
3871 void tst_qdeclarativeecmascript::eval()
3873 QDeclarativeComponent component(&engine, TEST_FILE("eval.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);
3881 QCOMPARE(o->property("test4").toBool(), true);
3882 QCOMPARE(o->property("test5").toBool(), true);
3887 void tst_qdeclarativeecmascript::function()
3889 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
3891 QObject *o = component.create();
3894 QCOMPARE(o->property("test1").toBool(), true);
3895 QCOMPARE(o->property("test2").toBool(), true);
3896 QCOMPARE(o->property("test3").toBool(), true);
3901 // Test the "Qt.include" method
3902 void tst_qdeclarativeecmascript::include()
3904 // Non-library relative include
3906 QDeclarativeComponent component(&engine, TEST_FILE("include.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);
3920 // Library relative include
3922 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
3923 QObject *o = component.create();
3926 QCOMPARE(o->property("test0").toInt(), 99);
3927 QCOMPARE(o->property("test1").toBool(), true);
3928 QCOMPARE(o->property("test2").toBool(), true);
3929 QCOMPARE(o->property("test2_1").toBool(), true);
3930 QCOMPARE(o->property("test3").toBool(), true);
3931 QCOMPARE(o->property("test3_1").toBool(), true);
3938 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
3939 QObject *o = component.create();
3942 QCOMPARE(o->property("test1").toBool(), true);
3943 QCOMPARE(o->property("test2").toBool(), true);
3944 QCOMPARE(o->property("test3").toBool(), true);
3945 QCOMPARE(o->property("test4").toBool(), true);
3946 QCOMPARE(o->property("test5").toBool(), true);
3947 QCOMPARE(o->property("test6").toBool(), true);
3952 // Including file with ".pragma library"
3954 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
3955 QObject *o = component.create();
3957 QCOMPARE(o->property("test1").toInt(), 100);
3964 TestHTTPServer server(8111);
3965 QVERIFY(server.isValid());
3966 server.serveDirectory(SRCDIR "/data");
3968 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
3969 QObject *o = component.create();
3972 QTRY_VERIFY(o->property("done").toBool() == true);
3973 QTRY_VERIFY(o->property("done2").toBool() == true);
3975 QCOMPARE(o->property("test1").toBool(), true);
3976 QCOMPARE(o->property("test2").toBool(), true);
3977 QCOMPARE(o->property("test3").toBool(), true);
3978 QCOMPARE(o->property("test4").toBool(), true);
3979 QCOMPARE(o->property("test5").toBool(), true);
3981 QCOMPARE(o->property("test6").toBool(), true);
3982 QCOMPARE(o->property("test7").toBool(), true);
3983 QCOMPARE(o->property("test8").toBool(), true);
3984 QCOMPARE(o->property("test9").toBool(), true);
3985 QCOMPARE(o->property("test10").toBool(), true);
3992 TestHTTPServer server(8111);
3993 QVERIFY(server.isValid());
3994 server.serveDirectory(SRCDIR "/data");
3996 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
3997 QObject *o = component.create();
4000 QTRY_VERIFY(o->property("done").toBool() == true);
4002 QCOMPARE(o->property("test1").toBool(), true);
4003 QCOMPARE(o->property("test2").toBool(), true);
4004 QCOMPARE(o->property("test3").toBool(), true);
4010 void tst_qdeclarativeecmascript::signalHandlers()
4012 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
4013 QObject *o = component.create();
4016 QVERIFY(o->property("count").toInt() == 0);
4017 QMetaObject::invokeMethod(o, "testSignalCall");
4018 QCOMPARE(o->property("count").toInt(), 1);
4020 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
4021 QCOMPARE(o->property("count").toInt(), 1);
4022 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
4024 QVERIFY(o->property("funcCount").toInt() == 0);
4025 QMetaObject::invokeMethod(o, "testSignalConnection");
4026 QCOMPARE(o->property("funcCount").toInt(), 1);
4028 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
4029 QCOMPARE(o->property("funcCount").toInt(), 2);
4031 QMetaObject::invokeMethod(o, "testSignalDefined");
4032 QCOMPARE(o->property("definedResult").toBool(), true);
4034 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
4035 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
4040 void tst_qdeclarativeecmascript::qtbug_10696()
4042 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
4043 QObject *o = component.create();
4048 void tst_qdeclarativeecmascript::qtbug_11606()
4050 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
4051 QObject *o = component.create();
4053 QCOMPARE(o->property("test").toBool(), true);
4057 void tst_qdeclarativeecmascript::qtbug_11600()
4059 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
4060 QObject *o = component.create();
4062 QCOMPARE(o->property("test").toBool(), true);
4066 // Reading and writing non-scriptable properties should fail
4067 void tst_qdeclarativeecmascript::nonscriptable()
4069 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
4070 QObject *o = component.create();
4072 QCOMPARE(o->property("readOk").toBool(), true);
4073 QCOMPARE(o->property("writeOk").toBool(), true);
4077 // deleteLater() should not be callable from QML
4078 void tst_qdeclarativeecmascript::deleteLater()
4080 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
4081 QObject *o = component.create();
4083 QCOMPARE(o->property("test").toBool(), true);
4087 void tst_qdeclarativeecmascript::in()
4089 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
4090 QObject *o = component.create();
4092 QCOMPARE(o->property("test1").toBool(), true);
4093 QCOMPARE(o->property("test2").toBool(), true);
4097 void tst_qdeclarativeecmascript::sharedAttachedObject()
4099 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
4100 QObject *o = component.create();
4102 QCOMPARE(o->property("test1").toBool(), true);
4103 QCOMPARE(o->property("test2").toBool(), true);
4108 void tst_qdeclarativeecmascript::objectName()
4110 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
4111 QObject *o = component.create();
4114 QCOMPARE(o->property("test1").toString(), QString("hello"));
4115 QCOMPARE(o->property("test2").toString(), QString("ell"));
4117 o->setObjectName("world");
4119 QCOMPARE(o->property("test1").toString(), QString("world"));
4120 QCOMPARE(o->property("test2").toString(), QString("orl"));
4125 void tst_qdeclarativeecmascript::writeRemovesBinding()
4127 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
4128 QObject *o = component.create();
4131 QCOMPARE(o->property("test").toBool(), true);
4136 // Test bindings assigned to alias properties actually assign to the alias' target
4137 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
4139 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4140 QObject *o = component.create();
4143 QCOMPARE(o->property("test").toBool(), true);
4148 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4149 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4152 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4153 QObject *o = component.create();
4156 QCOMPARE(o->property("test").toBool(), true);
4162 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4163 QObject *o = component.create();
4166 QCOMPARE(o->property("test").toBool(), true);
4172 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4173 QObject *o = component.create();
4176 QCOMPARE(o->property("test").toBool(), true);
4182 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4183 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4186 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4187 QObject *o = component.create();
4190 QCOMPARE(o->property("test").toBool(), true);
4196 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
4197 QObject *o = component.create();
4200 QCOMPARE(o->property("test").toBool(), true);
4206 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
4207 QObject *o = component.create();
4210 QCOMPARE(o->property("test").toBool(), true);
4216 // Allow an alais to a composite element
4218 void tst_qdeclarativeecmascript::aliasToCompositeElement()
4220 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
4222 QObject *object = component.create();
4223 QVERIFY(object != 0);
4228 void tst_qdeclarativeecmascript::revisionErrors()
4231 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
4232 QString url = component.url().toString();
4234 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4235 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
4236 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
4238 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4239 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4240 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4241 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4242 QVERIFY(object != 0);
4246 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
4247 QString url = component.url().toString();
4249 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
4250 // method2, prop2 from MyRevisionedClass not available
4251 // method4, prop4 from MyRevisionedSubclass not available
4252 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4253 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
4254 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
4255 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
4256 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
4258 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4259 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4260 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4261 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
4262 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
4263 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4264 QVERIFY(object != 0);
4268 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
4269 QString url = component.url().toString();
4271 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
4272 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
4273 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
4274 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
4275 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
4276 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4277 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4278 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4279 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4280 QVERIFY(object != 0);
4285 void tst_qdeclarativeecmascript::revision()
4288 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
4289 QString url = component.url().toString();
4291 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4292 QVERIFY(object != 0);
4296 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
4297 QString url = component.url().toString();
4299 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4300 QVERIFY(object != 0);
4304 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
4305 QString url = component.url().toString();
4307 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4308 QVERIFY(object != 0);
4311 // Test that non-root classes can resolve revisioned methods
4313 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
4315 QObject *object = component.create();
4316 QVERIFY(object != 0);
4317 QCOMPARE(object->property("test").toReal(), 11.);
4322 void tst_qdeclarativeecmascript::realToInt()
4324 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
4325 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
4326 QVERIFY(object != 0);
4328 QMetaObject::invokeMethod(object, "test1");
4329 QCOMPARE(object->value(), int(4));
4330 QMetaObject::invokeMethod(object, "test2");
4331 QCOMPARE(object->value(), int(8));
4333 void tst_qdeclarativeecmascript::dynamicString()
4335 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
4336 QObject *object = component.create();
4337 QVERIFY(object != 0);
4338 QCOMPARE(object->property("stringProperty").toString(),
4339 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
4342 void tst_qdeclarativeecmascript::automaticSemicolon()
4344 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
4345 QObject *object = component.create();
4346 QVERIFY(object != 0);
4349 QTEST_MAIN(tst_qdeclarativeecmascript)
4351 #include "tst_qdeclarativeecmascript.moc"