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_data();
151 void importScripts();
152 void scarceResources();
153 void propertyChangeSlots();
154 void elementAssign();
155 void objectPassThroughSignals();
156 void objectConversion();
157 void booleanConversion();
158 void handleReferenceManagement();
163 void dynamicCreationCrash();
164 void dynamicCreationOwnership();
166 void nullObjectBinding();
167 void deletedEngine();
168 void libraryScriptAssert();
169 void variantsAssignedUndefined();
171 void qtcreatorbug_1289();
172 void noSpuriousWarningsAtShutdown();
173 void canAssignNullToQObject();
174 void functionAssignment_fromBinding();
175 void functionAssignment_fromJS();
176 void functionAssignment_fromJS_data();
177 void functionAssignmentfromJS_invalid();
183 void nonscriptable();
186 void sharedAttachedObject();
188 void writeRemovesBinding();
189 void aliasBindingsAssignCorrectly();
190 void aliasBindingsOverrideTarget();
191 void aliasWritesOverrideBindings();
192 void aliasToCompositeElement();
194 void dynamicString();
196 void signalHandlers();
198 void callQtInvokables();
199 void invokableObjectArg();
200 void invokableObjectRet();
202 void revisionErrors();
205 void automaticSemicolon();
208 QDeclarativeEngine engine;
211 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
213 void tst_qdeclarativeecmascript::assignBasicTypes()
216 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
217 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
218 QVERIFY(object != 0);
219 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
220 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
221 QCOMPARE(object->stringProperty(), QString("Hello World!"));
222 QCOMPARE(object->uintProperty(), uint(10));
223 QCOMPARE(object->intProperty(), -19);
224 QCOMPARE((float)object->realProperty(), float(23.2));
225 QCOMPARE((float)object->doubleProperty(), float(-19.75));
226 QCOMPARE((float)object->floatProperty(), float(8.5));
227 QCOMPARE(object->colorProperty(), QColor("red"));
228 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
229 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
230 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
231 QCOMPARE(object->pointProperty(), QPoint(99,13));
232 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
233 QCOMPARE(object->sizeProperty(), QSize(99, 13));
234 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
235 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
236 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
237 QCOMPARE(object->boolProperty(), true);
238 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
239 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
240 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
244 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
245 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
246 QVERIFY(object != 0);
247 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
248 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
249 QCOMPARE(object->stringProperty(), QString("Hello World!"));
250 QCOMPARE(object->uintProperty(), uint(10));
251 QCOMPARE(object->intProperty(), -19);
252 QCOMPARE((float)object->realProperty(), float(23.2));
253 QCOMPARE((float)object->doubleProperty(), float(-19.75));
254 QCOMPARE((float)object->floatProperty(), float(8.5));
255 QCOMPARE(object->colorProperty(), QColor("red"));
256 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
257 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
258 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
259 QCOMPARE(object->pointProperty(), QPoint(99,13));
260 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
261 QCOMPARE(object->sizeProperty(), QSize(99, 13));
262 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
263 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
264 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
265 QCOMPARE(object->boolProperty(), true);
266 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
267 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
268 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
273 void tst_qdeclarativeecmascript::idShortcutInvalidates()
276 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
277 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
278 QVERIFY(object != 0);
279 QVERIFY(object->objectProperty() != 0);
280 delete object->objectProperty();
281 QVERIFY(object->objectProperty() == 0);
286 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
287 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
288 QVERIFY(object != 0);
289 QVERIFY(object->objectProperty() != 0);
290 delete object->objectProperty();
291 QVERIFY(object->objectProperty() == 0);
296 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
299 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
300 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
301 QVERIFY(object != 0);
302 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
306 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
307 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
308 QVERIFY(object != 0);
309 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
314 void tst_qdeclarativeecmascript::signalAssignment()
317 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
318 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
319 QVERIFY(object != 0);
320 QCOMPARE(object->string(), QString());
321 emit object->basicSignal();
322 QCOMPARE(object->string(), QString("pass"));
327 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
328 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
329 QVERIFY(object != 0);
330 QCOMPARE(object->string(), QString());
331 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
332 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
337 void tst_qdeclarativeecmascript::methods()
340 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
341 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
342 QVERIFY(object != 0);
343 QCOMPARE(object->methodCalled(), false);
344 QCOMPARE(object->methodIntCalled(), false);
345 emit object->basicSignal();
346 QCOMPARE(object->methodCalled(), true);
347 QCOMPARE(object->methodIntCalled(), false);
352 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
353 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
354 QVERIFY(object != 0);
355 QCOMPARE(object->methodCalled(), false);
356 QCOMPARE(object->methodIntCalled(), false);
357 emit object->basicSignal();
358 QCOMPARE(object->methodCalled(), false);
359 QCOMPARE(object->methodIntCalled(), true);
364 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
365 QObject *object = component.create();
366 QVERIFY(object != 0);
367 QCOMPARE(object->property("test").toInt(), 19);
372 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
373 QObject *object = component.create();
374 QVERIFY(object != 0);
375 QCOMPARE(object->property("test").toInt(), 19);
376 QCOMPARE(object->property("test2").toInt(), 17);
377 QCOMPARE(object->property("test3").toInt(), 16);
382 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
383 QObject *object = component.create();
384 QVERIFY(object != 0);
385 QCOMPARE(object->property("test").toInt(), 9);
390 void tst_qdeclarativeecmascript::bindingLoop()
392 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
393 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
394 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
395 QObject *object = component.create();
396 QVERIFY(object != 0);
400 void tst_qdeclarativeecmascript::basicExpressions_data()
402 QTest::addColumn<QString>("expression");
403 QTest::addColumn<QVariant>("result");
404 QTest::addColumn<bool>("nest");
406 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
407 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
408 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
409 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
410 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
411 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
412 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
413 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
414 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
415 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
416 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
417 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
418 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
419 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
420 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
421 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
422 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
423 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
424 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
427 void tst_qdeclarativeecmascript::basicExpressions()
429 QFETCH(QString, expression);
430 QFETCH(QVariant, result);
436 MyDefaultObject1 default1;
437 MyDefaultObject3 default3;
438 object1.setStringProperty("Object1");
439 object2.setStringProperty("Object2");
440 object3.setStringProperty("Object3");
442 QDeclarativeContext context(engine.rootContext());
443 QDeclarativeContext nestedContext(&context);
445 context.setContextObject(&default1);
446 context.setContextProperty("a", QVariant(1944));
447 context.setContextProperty("b", QVariant("Milk"));
448 context.setContextProperty("object", &object1);
449 context.setContextProperty("objectOverride", &object2);
450 nestedContext.setContextObject(&default3);
451 nestedContext.setContextProperty("b", QVariant("Cow"));
452 nestedContext.setContextProperty("objectOverride", &object3);
453 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
455 MyExpression expr(nest?&nestedContext:&context, expression);
456 QCOMPARE(expr.evaluate(), result);
459 void tst_qdeclarativeecmascript::arrayExpressions()
465 QDeclarativeContext context(engine.rootContext());
466 context.setContextProperty("a", &obj1);
467 context.setContextProperty("b", &obj2);
468 context.setContextProperty("c", &obj3);
470 MyExpression expr(&context, "[a, b, c, 10]");
471 QVariant result = expr.evaluate();
472 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
473 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
474 QCOMPARE(list.count(), 4);
475 QCOMPARE(list.at(0), &obj1);
476 QCOMPARE(list.at(1), &obj2);
477 QCOMPARE(list.at(2), &obj3);
478 QCOMPARE(list.at(3), (QObject *)0);
481 // Tests that modifying a context property will reevaluate expressions
482 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
484 QDeclarativeContext context(engine.rootContext());
487 MyQmlObject *object3 = new MyQmlObject;
489 object1.setStringProperty("Hello");
490 object2.setStringProperty("World");
492 context.setContextProperty("testProp", QVariant(1));
493 context.setContextProperty("testObj", &object1);
494 context.setContextProperty("testObj2", object3);
497 MyExpression expr(&context, "testProp + 1");
498 QCOMPARE(expr.changed, false);
499 QCOMPARE(expr.evaluate(), QVariant(2));
501 context.setContextProperty("testProp", QVariant(2));
502 QCOMPARE(expr.changed, true);
503 QCOMPARE(expr.evaluate(), QVariant(3));
507 MyExpression expr(&context, "testProp + testProp + testProp");
508 QCOMPARE(expr.changed, false);
509 QCOMPARE(expr.evaluate(), QVariant(6));
511 context.setContextProperty("testProp", QVariant(4));
512 QCOMPARE(expr.changed, true);
513 QCOMPARE(expr.evaluate(), QVariant(12));
517 MyExpression expr(&context, "testObj.stringProperty");
518 QCOMPARE(expr.changed, false);
519 QCOMPARE(expr.evaluate(), QVariant("Hello"));
521 context.setContextProperty("testObj", &object2);
522 QCOMPARE(expr.changed, true);
523 QCOMPARE(expr.evaluate(), QVariant("World"));
527 MyExpression expr(&context, "testObj.stringProperty /**/");
528 QCOMPARE(expr.changed, false);
529 QCOMPARE(expr.evaluate(), QVariant("World"));
531 context.setContextProperty("testObj", &object1);
532 QCOMPARE(expr.changed, true);
533 QCOMPARE(expr.evaluate(), QVariant("Hello"));
537 MyExpression expr(&context, "testObj2");
538 QCOMPARE(expr.changed, false);
539 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
545 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
547 QDeclarativeContext context(engine.rootContext());
551 context.setContextProperty("testObj", &object1);
553 object1.setStringProperty(QLatin1String("Hello"));
554 object2.setStringProperty(QLatin1String("Dog"));
555 object3.setStringProperty(QLatin1String("Cat"));
558 MyExpression expr(&context, "testObj.stringProperty");
559 QCOMPARE(expr.changed, false);
560 QCOMPARE(expr.evaluate(), QVariant("Hello"));
562 object1.setStringProperty(QLatin1String("World"));
563 QCOMPARE(expr.changed, true);
564 QCOMPARE(expr.evaluate(), QVariant("World"));
568 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
569 QCOMPARE(expr.changed, false);
570 QCOMPARE(expr.evaluate(), QVariant());
572 object1.setObjectProperty(&object2);
573 QCOMPARE(expr.changed, true);
574 expr.changed = false;
575 QCOMPARE(expr.evaluate(), QVariant("Dog"));
577 object1.setObjectProperty(&object3);
578 QCOMPARE(expr.changed, true);
579 expr.changed = false;
580 QCOMPARE(expr.evaluate(), QVariant("Cat"));
582 object1.setObjectProperty(0);
583 QCOMPARE(expr.changed, true);
584 expr.changed = false;
585 QCOMPARE(expr.evaluate(), QVariant());
587 object1.setObjectProperty(&object3);
588 QCOMPARE(expr.changed, true);
589 expr.changed = false;
590 QCOMPARE(expr.evaluate(), QVariant("Cat"));
592 object3.setStringProperty("Donkey");
593 QCOMPARE(expr.changed, true);
594 expr.changed = false;
595 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
599 void tst_qdeclarativeecmascript::deferredProperties()
601 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
602 MyDeferredObject *object =
603 qobject_cast<MyDeferredObject *>(component.create());
604 QVERIFY(object != 0);
605 QCOMPARE(object->value(), 0);
606 QVERIFY(object->objectProperty() == 0);
607 QVERIFY(object->objectProperty2() != 0);
608 qmlExecuteDeferred(object);
609 QCOMPARE(object->value(), 10);
610 QVERIFY(object->objectProperty() != 0);
611 MyQmlObject *qmlObject =
612 qobject_cast<MyQmlObject *>(object->objectProperty());
613 QVERIFY(qmlObject != 0);
614 QCOMPARE(qmlObject->value(), 10);
615 object->setValue(19);
616 QCOMPARE(qmlObject->value(), 19);
621 // Check errors on deferred properties are correctly emitted
622 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
624 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
625 MyDeferredObject *object =
626 qobject_cast<MyDeferredObject *>(component.create());
627 QVERIFY(object != 0);
628 QCOMPARE(object->value(), 0);
629 QVERIFY(object->objectProperty() == 0);
630 QVERIFY(object->objectProperty2() == 0);
632 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject* objectProperty";
633 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
635 qmlExecuteDeferred(object);
640 void tst_qdeclarativeecmascript::extensionObjects()
642 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
643 MyExtendedObject *object =
644 qobject_cast<MyExtendedObject *>(component.create());
645 QVERIFY(object != 0);
646 QCOMPARE(object->baseProperty(), 13);
647 QCOMPARE(object->coreProperty(), 9);
648 object->setProperty("extendedProperty", QVariant(11));
649 object->setProperty("baseExtendedProperty", QVariant(92));
650 QCOMPARE(object->coreProperty(), 11);
651 QCOMPARE(object->baseProperty(), 92);
653 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
655 QCOMPARE(nested->baseProperty(), 13);
656 QCOMPARE(nested->coreProperty(), 9);
657 nested->setProperty("extendedProperty", QVariant(11));
658 nested->setProperty("baseExtendedProperty", QVariant(92));
659 QCOMPARE(nested->coreProperty(), 11);
660 QCOMPARE(nested->baseProperty(), 92);
665 void tst_qdeclarativeecmascript::overrideExtensionProperties()
667 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
668 OverrideDefaultPropertyObject *object =
669 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
670 QVERIFY(object != 0);
671 QVERIFY(object->secondProperty() != 0);
672 QVERIFY(object->firstProperty() == 0);
677 void tst_qdeclarativeecmascript::attachedProperties()
680 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
681 QObject *object = component.create();
682 QVERIFY(object != 0);
683 QCOMPARE(object->property("a").toInt(), 19);
684 QCOMPARE(object->property("b").toInt(), 19);
685 QCOMPARE(object->property("c").toInt(), 19);
686 QCOMPARE(object->property("d").toInt(), 19);
691 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
692 QObject *object = component.create();
693 QVERIFY(object != 0);
694 QCOMPARE(object->property("a").toInt(), 26);
695 QCOMPARE(object->property("b").toInt(), 26);
696 QCOMPARE(object->property("c").toInt(), 26);
697 QCOMPARE(object->property("d").toInt(), 26);
703 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
704 QObject *object = component.create();
705 QVERIFY(object != 0);
707 QMetaObject::invokeMethod(object, "writeValue2");
709 MyQmlAttachedObject *attached =
710 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
711 QVERIFY(attached != 0);
713 QCOMPARE(attached->value2(), 9);
718 void tst_qdeclarativeecmascript::enums()
722 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
723 QObject *object = component.create();
724 QVERIFY(object != 0);
726 QCOMPARE(object->property("a").toInt(), 0);
727 QCOMPARE(object->property("b").toInt(), 1);
728 QCOMPARE(object->property("c").toInt(), 2);
729 QCOMPARE(object->property("d").toInt(), 3);
730 QCOMPARE(object->property("e").toInt(), 0);
731 QCOMPARE(object->property("f").toInt(), 1);
732 QCOMPARE(object->property("g").toInt(), 2);
733 QCOMPARE(object->property("h").toInt(), 3);
734 QCOMPARE(object->property("i").toInt(), 19);
735 QCOMPARE(object->property("j").toInt(), 19);
739 // Non-existent enums
741 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
743 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int a";
744 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int b";
745 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
746 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
748 QObject *object = component.create();
749 QVERIFY(object != 0);
750 QCOMPARE(object->property("a").toInt(), 0);
751 QCOMPARE(object->property("b").toInt(), 0);
757 void tst_qdeclarativeecmascript::valueTypeFunctions()
759 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
760 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
762 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
763 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
769 Tests that writing a constant to a property with a binding on it disables the
772 void tst_qdeclarativeecmascript::constantsOverrideBindings()
776 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
777 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
778 QVERIFY(object != 0);
780 QCOMPARE(object->property("c2").toInt(), 0);
781 object->setProperty("c1", QVariant(9));
782 QCOMPARE(object->property("c2").toInt(), 9);
784 emit object->basicSignal();
786 QCOMPARE(object->property("c2").toInt(), 13);
787 object->setProperty("c1", QVariant(8));
788 QCOMPARE(object->property("c2").toInt(), 13);
793 // During construction
795 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
796 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
797 QVERIFY(object != 0);
799 QCOMPARE(object->property("c1").toInt(), 0);
800 QCOMPARE(object->property("c2").toInt(), 10);
801 object->setProperty("c1", QVariant(9));
802 QCOMPARE(object->property("c1").toInt(), 9);
803 QCOMPARE(object->property("c2").toInt(), 10);
811 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
812 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
813 QVERIFY(object != 0);
815 QCOMPARE(object->property("c2").toInt(), 0);
816 object->setProperty("c1", QVariant(9));
817 QCOMPARE(object->property("c2").toInt(), 9);
819 object->setProperty("c2", QVariant(13));
820 QCOMPARE(object->property("c2").toInt(), 13);
821 object->setProperty("c1", QVariant(7));
822 QCOMPARE(object->property("c1").toInt(), 7);
823 QCOMPARE(object->property("c2").toInt(), 13);
831 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
832 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
833 QVERIFY(object != 0);
835 QCOMPARE(object->property("c1").toInt(), 0);
836 QCOMPARE(object->property("c3").toInt(), 10);
837 object->setProperty("c1", QVariant(9));
838 QCOMPARE(object->property("c1").toInt(), 9);
839 QCOMPARE(object->property("c3").toInt(), 10);
846 Tests that assigning a binding to a property that already has a binding causes
847 the original binding to be disabled.
849 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
851 QDeclarativeComponent component(&engine,
852 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
853 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
854 QVERIFY(object != 0);
856 QCOMPARE(object->property("c1").toInt(), 0);
857 QCOMPARE(object->property("c2").toInt(), 0);
858 QCOMPARE(object->property("c3").toInt(), 0);
860 object->setProperty("c1", QVariant(9));
861 QCOMPARE(object->property("c1").toInt(), 9);
862 QCOMPARE(object->property("c2").toInt(), 0);
863 QCOMPARE(object->property("c3").toInt(), 0);
865 object->setProperty("c3", QVariant(8));
866 QCOMPARE(object->property("c1").toInt(), 9);
867 QCOMPARE(object->property("c2").toInt(), 8);
868 QCOMPARE(object->property("c3").toInt(), 8);
874 Access a non-existent attached object.
876 Tests for a regression where this used to crash.
878 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
880 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
882 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString stringProperty";
883 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
885 QObject *object = component.create();
886 QVERIFY(object != 0);
891 void tst_qdeclarativeecmascript::scope()
894 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
895 QObject *object = component.create();
896 QVERIFY(object != 0);
898 QCOMPARE(object->property("test1").toInt(), 1);
899 QCOMPARE(object->property("test2").toInt(), 2);
900 QCOMPARE(object->property("test3").toString(), QString("1Test"));
901 QCOMPARE(object->property("test4").toString(), QString("2Test"));
902 QCOMPARE(object->property("test5").toInt(), 1);
903 QCOMPARE(object->property("test6").toInt(), 1);
904 QCOMPARE(object->property("test7").toInt(), 2);
905 QCOMPARE(object->property("test8").toInt(), 2);
906 QCOMPARE(object->property("test9").toInt(), 1);
907 QCOMPARE(object->property("test10").toInt(), 3);
913 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
914 QObject *object = component.create();
915 QVERIFY(object != 0);
917 QCOMPARE(object->property("test1").toInt(), 19);
918 QCOMPARE(object->property("test2").toInt(), 19);
919 QCOMPARE(object->property("test3").toInt(), 14);
920 QCOMPARE(object->property("test4").toInt(), 14);
921 QCOMPARE(object->property("test5").toInt(), 24);
922 QCOMPARE(object->property("test6").toInt(), 24);
928 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
929 QObject *object = component.create();
930 QVERIFY(object != 0);
932 QCOMPARE(object->property("test1").toBool(), true);
933 QCOMPARE(object->property("test2").toBool(), true);
934 QCOMPARE(object->property("test3").toBool(), true);
939 // Signal argument scope
941 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
942 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
943 QVERIFY(object != 0);
945 QCOMPARE(object->property("test").toInt(), 0);
946 QCOMPARE(object->property("test2").toString(), QString());
948 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
950 QCOMPARE(object->property("test").toInt(), 13);
951 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
957 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
958 QObject *object = component.create();
959 QVERIFY(object != 0);
961 QCOMPARE(object->property("test1").toBool(), true);
962 QCOMPARE(object->property("test2").toBool(), true);
968 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
969 QObject *object = component.create();
970 QVERIFY(object != 0);
972 QCOMPARE(object->property("test").toBool(), true);
978 // In 4.7, non-library javascript files that had no imports shared the imports of their
980 void tst_qdeclarativeecmascript::importScope()
982 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
983 QObject *o = component.create();
986 QCOMPARE(o->property("test").toInt(), 240);
992 Tests that "any" type passes through a synthesized signal parameter. This
993 is essentially a test of QDeclarativeMetaType::copy()
995 void tst_qdeclarativeecmascript::signalParameterTypes()
997 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
998 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
999 QVERIFY(object != 0);
1001 emit object->basicSignal();
1003 QCOMPARE(object->property("intProperty").toInt(), 10);
1004 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1005 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1006 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1007 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1008 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1014 Test that two JS objects for the same QObject compare as equal.
1016 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1018 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1019 QObject *object = component.create();
1020 QVERIFY(object != 0);
1022 QCOMPARE(object->property("test1").toBool(), true);
1023 QCOMPARE(object->property("test2").toBool(), true);
1024 QCOMPARE(object->property("test3").toBool(), true);
1025 QCOMPARE(object->property("test4").toBool(), true);
1026 QCOMPARE(object->property("test5").toBool(), true);
1032 Confirm bindings and alias properties can coexist.
1034 Tests for a regression where the binding would not reevaluate.
1036 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1038 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1039 QObject *object = component.create();
1040 QVERIFY(object != 0);
1042 QCOMPARE(object->property("c2").toInt(), 3);
1043 QCOMPARE(object->property("c3").toInt(), 3);
1045 object->setProperty("c2", QVariant(19));
1047 QCOMPARE(object->property("c2").toInt(), 19);
1048 QCOMPARE(object->property("c3").toInt(), 19);
1054 Ensure that we can write undefined value to an alias property,
1055 and that the aliased property is reset correctly if possible.
1057 void tst_qdeclarativeecmascript::aliasPropertyReset()
1059 QObject *object = 0;
1061 // test that a manual write (of undefined) to a resettable aliased property succeeds
1062 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1063 object = c1.create();
1064 QVERIFY(object != 0);
1065 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1066 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1067 QMetaObject::invokeMethod(object, "resetAliased");
1068 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1069 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1072 // test that a manual write (of undefined) to a resettable alias property succeeds
1073 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1074 object = c2.create();
1075 QVERIFY(object != 0);
1076 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1077 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1078 QMetaObject::invokeMethod(object, "resetAlias");
1079 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1080 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1083 // test that an alias to a bound property works correctly
1084 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1085 object = c3.create();
1086 QVERIFY(object != 0);
1087 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1088 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1089 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1090 QMetaObject::invokeMethod(object, "resetAlias");
1091 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1092 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1093 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1096 // test that a manual write (of undefined) to a resettable alias property
1097 // whose aliased property's object has been deleted, does not crash.
1098 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1099 object = c4.create();
1100 QVERIFY(object != 0);
1101 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1102 QObject *loader = object->findChild<QObject*>("loader");
1103 QVERIFY(loader != 0);
1105 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1106 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1107 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1108 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1109 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1112 // test that binding an alias property to an undefined value works correctly
1113 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1114 object = c5.create();
1115 QVERIFY(object != 0);
1116 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1119 // test that a manual write (of undefined) to a non-resettable property fails properly
1120 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1121 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1122 QDeclarativeComponent e1(&engine, url);
1123 object = e1.create();
1124 QVERIFY(object != 0);
1125 QCOMPARE(object->property("intAlias").value<int>(), 12);
1126 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1127 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1128 QMetaObject::invokeMethod(object, "resetAlias");
1129 QCOMPARE(object->property("intAlias").value<int>(), 12);
1130 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1134 void tst_qdeclarativeecmascript::dynamicCreation_data()
1136 QTest::addColumn<QString>("method");
1137 QTest::addColumn<QString>("createdName");
1139 QTest::newRow("One") << "createOne" << "objectOne";
1140 QTest::newRow("Two") << "createTwo" << "objectTwo";
1141 QTest::newRow("Three") << "createThree" << "objectThree";
1145 Test using createQmlObject to dynamically generate an item
1146 Also using createComponent is tested.
1148 void tst_qdeclarativeecmascript::dynamicCreation()
1150 QFETCH(QString, method);
1151 QFETCH(QString, createdName);
1153 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1154 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1155 QVERIFY(object != 0);
1157 QMetaObject::invokeMethod(object, method.toUtf8());
1158 QObject *created = object->objectProperty();
1160 QCOMPARE(created->objectName(), createdName);
1166 Tests the destroy function
1168 void tst_qdeclarativeecmascript::dynamicDestruction()
1171 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1172 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1173 QVERIFY(object != 0);
1174 QDeclarativeGuard<QObject> createdQmlObject = 0;
1176 QMetaObject::invokeMethod(object, "create");
1177 createdQmlObject = object->objectProperty();
1178 QVERIFY(createdQmlObject);
1179 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1181 QMetaObject::invokeMethod(object, "killOther");
1182 QVERIFY(createdQmlObject);
1183 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1184 QVERIFY(createdQmlObject);
1185 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1186 if (createdQmlObject) {
1188 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1191 QVERIFY(!createdQmlObject);
1193 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1194 QMetaObject::invokeMethod(object, "killMe");
1197 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1202 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1203 QObject *o = component.create();
1206 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1208 QMetaObject::invokeMethod(o, "create");
1210 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1212 QMetaObject::invokeMethod(o, "destroy");
1214 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1216 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1223 tests that id.toString() works
1225 void tst_qdeclarativeecmascript::objectToString()
1227 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1228 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1229 QVERIFY(object != 0);
1230 QMetaObject::invokeMethod(object, "testToString");
1231 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1232 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1238 tests that id.hasOwnProperty() works
1240 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1242 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1243 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1244 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1245 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1247 QDeclarativeComponent component(&engine, url);
1248 QObject *object = component.create();
1249 QVERIFY(object != 0);
1251 // test QObjects in QML
1252 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1253 QVERIFY(object->property("result").value<bool>() == true);
1254 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1255 QVERIFY(object->property("result").value<bool>() == false);
1257 // now test other types in QML
1258 QObject *child = object->findChild<QObject*>("typeObj");
1259 QVERIFY(child != 0);
1260 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1261 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1262 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1263 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1264 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1265 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1266 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1267 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1268 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1269 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1270 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1271 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1273 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1274 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1275 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1276 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1277 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1278 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1279 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1280 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1281 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1287 Tests bindings that indirectly cause their own deletion work.
1289 This test is best run under valgrind to ensure no invalid memory access occur.
1291 void tst_qdeclarativeecmascript::selfDeletingBinding()
1294 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1295 QObject *object = component.create();
1296 QVERIFY(object != 0);
1297 object->setProperty("triggerDelete", true);
1302 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1303 QObject *object = component.create();
1304 QVERIFY(object != 0);
1305 object->setProperty("triggerDelete", true);
1311 Test that extended object properties can be accessed.
1313 This test a regression where this used to crash. The issue was specificially
1314 for extended objects that did not include a synthesized meta object (so non-root
1315 and no synthesiszed properties).
1317 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1319 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1320 QObject *object = component.create();
1321 QVERIFY(object != 0);
1326 Test file/lineNumbers for binding/Script errors.
1328 void tst_qdeclarativeecmascript::scriptErrors()
1330 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1331 QString url = component.url().toString();
1333 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1334 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1335 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1336 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1337 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1338 QString warning6 = url + ":7: Unable to assign [undefined] to int x";
1339 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1340 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1342 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1343 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1344 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1345 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1346 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1347 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1348 QVERIFY(object != 0);
1350 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1351 emit object->basicSignal();
1353 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1354 emit object->anotherBasicSignal();
1356 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1357 emit object->thirdBasicSignal();
1363 Test file/lineNumbers for inline functions.
1365 void tst_qdeclarativeecmascript::functionErrors()
1367 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1368 QString url = component.url().toString();
1370 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1372 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1374 QObject *object = component.create();
1375 QVERIFY(object != 0);
1378 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1379 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1380 url = componentTwo.url().toString();
1381 object = componentTwo.create();
1382 QVERIFY(object != 0);
1384 QString srpname = object->property("srp_name").toString();
1386 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1387 QLatin1String(" is not a function");
1388 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1389 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1394 Test various errors that can occur when assigning a property from script
1396 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1398 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1400 QString url = component.url().toString();
1402 QObject *object = component.create();
1403 QVERIFY(object != 0);
1405 QCOMPARE(object->property("test1").toBool(), true);
1406 QCOMPARE(object->property("test2").toBool(), true);
1412 Test bindings still work when the reeval is triggered from within
1415 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1417 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1418 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1419 QVERIFY(object != 0);
1421 QCOMPARE(object->property("base").toReal(), 50.);
1422 QCOMPARE(object->property("test1").toReal(), 50.);
1423 QCOMPARE(object->property("test2").toReal(), 50.);
1425 object->basicSignal();
1427 QCOMPARE(object->property("base").toReal(), 200.);
1428 QCOMPARE(object->property("test1").toReal(), 200.);
1429 QCOMPARE(object->property("test2").toReal(), 200.);
1431 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1433 QCOMPARE(object->property("base").toReal(), 400.);
1434 QCOMPARE(object->property("test1").toReal(), 400.);
1435 QCOMPARE(object->property("test2").toReal(), 400.);
1441 Test that list properties can be iterated from ECMAScript
1443 void tst_qdeclarativeecmascript::listProperties()
1445 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1446 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1447 QVERIFY(object != 0);
1449 QCOMPARE(object->property("test1").toInt(), 21);
1450 QCOMPARE(object->property("test2").toInt(), 2);
1451 QCOMPARE(object->property("test3").toBool(), true);
1452 QCOMPARE(object->property("test4").toBool(), true);
1457 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1459 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1460 QString url = component.url().toString();
1462 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1464 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1465 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1466 QVERIFY(object != 0);
1468 QCOMPARE(object->property("test").toBool(), false);
1470 MyQmlObject object2;
1471 MyQmlObject object3;
1472 object2.setObjectProperty(&object3);
1473 object->setObjectProperty(&object2);
1475 QCOMPARE(object->property("test").toBool(), true);
1480 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1482 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1483 QString url = component.url().toString();
1485 QString warning = component.url().toString() + ":6: Error: JS exception";
1487 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1488 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1489 QVERIFY(object != 0);
1493 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1495 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1496 QString url = component.url().toString();
1498 QString warning = component.url().toString() + ":5: Error: JS exception";
1500 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1501 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1502 QVERIFY(object != 0);
1506 static int transientErrorsMsgCount = 0;
1507 static void transientErrorsMsgHandler(QtMsgType, const char *)
1509 ++transientErrorsMsgCount;
1512 // Check that transient binding errors are not displayed
1513 void tst_qdeclarativeecmascript::transientErrors()
1516 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1518 transientErrorsMsgCount = 0;
1519 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1521 QObject *object = component.create();
1522 QVERIFY(object != 0);
1524 qInstallMsgHandler(old);
1526 QCOMPARE(transientErrorsMsgCount, 0);
1531 // One binding erroring multiple times, but then resolving
1533 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1535 transientErrorsMsgCount = 0;
1536 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1538 QObject *object = component.create();
1539 QVERIFY(object != 0);
1541 qInstallMsgHandler(old);
1543 QCOMPARE(transientErrorsMsgCount, 0);
1549 // Check that errors during shutdown are minimized
1550 void tst_qdeclarativeecmascript::shutdownErrors()
1552 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1553 QObject *object = component.create();
1554 QVERIFY(object != 0);
1556 transientErrorsMsgCount = 0;
1557 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1561 qInstallMsgHandler(old);
1562 QCOMPARE(transientErrorsMsgCount, 0);
1565 void tst_qdeclarativeecmascript::compositePropertyType()
1567 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1568 QTest::ignoreMessage(QtDebugMsg, "hello world");
1569 QObject *object = qobject_cast<QObject *>(component.create());
1574 void tst_qdeclarativeecmascript::jsObject()
1576 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1577 QObject *object = component.create();
1578 QVERIFY(object != 0);
1580 QCOMPARE(object->property("test").toInt(), 92);
1585 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1588 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1589 QObject *object = component.create();
1590 QVERIFY(object != 0);
1592 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1594 object->setProperty("setUndefined", true);
1596 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1598 object->setProperty("setUndefined", false);
1600 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1605 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1606 QObject *object = component.create();
1607 QVERIFY(object != 0);
1609 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1611 QMetaObject::invokeMethod(object, "doReset");
1613 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1620 void tst_qdeclarativeecmascript::bug1()
1622 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1623 QObject *object = component.create();
1624 QVERIFY(object != 0);
1626 QCOMPARE(object->property("test").toInt(), 14);
1628 object->setProperty("a", 11);
1630 QCOMPARE(object->property("test").toInt(), 3);
1632 object->setProperty("b", true);
1634 QCOMPARE(object->property("test").toInt(), 9);
1639 void tst_qdeclarativeecmascript::bug2()
1641 QDeclarativeComponent component(&engine);
1642 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1644 QObject *object = component.create();
1645 QVERIFY(object != 0);
1650 // Don't crash in createObject when the component has errors.
1651 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1653 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1654 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1655 QVERIFY(object != 0);
1657 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1658 QMetaObject::invokeMethod(object, "dontCrash");
1659 QObject *created = object->objectProperty();
1660 QVERIFY(created == 0);
1665 // ownership transferred to JS, ensure that GC runs the dtor
1666 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1669 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1671 // allow the engine to go out of scope too.
1673 QDeclarativeEngine dcoEngine;
1674 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1675 QObject *object = component.create();
1676 QVERIFY(object != 0);
1677 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1678 QVERIFY(mdcdo != 0);
1679 mdcdo->setDtorCount(&dtorCount);
1681 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1682 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1684 // we do this once manually, but it should be done automatically
1685 // when the engine goes out of scope (since it should gc in dtor)
1686 QMetaObject::invokeMethod(object, "performGc");
1689 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1695 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1696 QCOMPARE(dtorCount, expectedDtorCount);
1700 void tst_qdeclarativeecmascript::regExpBug()
1702 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1703 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1704 QVERIFY(object != 0);
1705 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1709 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1711 QString functionSource = QLatin1String("(function(object) { return ") +
1712 QLatin1String(source) + QLatin1String(" })");
1714 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1717 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1718 if (function.IsEmpty())
1720 v8::Handle<v8::Value> args[] = { o };
1721 function->Call(engine->global(), 1, args);
1722 return tc.HasCaught();
1725 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1726 const char *source, v8::Handle<v8::Value> result)
1728 QString functionSource = QLatin1String("(function(object) { return ") +
1729 QLatin1String(source) + QLatin1String(" })");
1731 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1734 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1735 if (function.IsEmpty())
1737 v8::Handle<v8::Value> args[] = { o };
1739 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1744 return value->StrictEquals(result);
1747 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1750 QString functionSource = QLatin1String("(function(object) { return ") +
1751 QLatin1String(source) + QLatin1String(" })");
1753 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1755 return v8::Handle<v8::Value>();
1756 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1757 if (function.IsEmpty())
1758 return v8::Handle<v8::Value>();
1759 v8::Handle<v8::Value> args[] = { o };
1761 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1764 return v8::Handle<v8::Value>();
1768 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1769 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1770 #define EVALUATE(source) evaluate(engine, object, source)
1772 void tst_qdeclarativeecmascript::callQtInvokables()
1774 MyInvokableObject o;
1776 QDeclarativeEngine qmlengine;
1777 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1779 QV8Engine *engine = ep->v8engine();
1781 v8::HandleScope handle_scope;
1782 v8::Context::Scope scope(engine->context());
1784 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1786 // Non-existent methods
1788 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1789 QCOMPARE(o.error(), false);
1790 QCOMPARE(o.invoked(), -1);
1791 QCOMPARE(o.actuals().count(), 0);
1794 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1795 QCOMPARE(o.error(), false);
1796 QCOMPARE(o.invoked(), -1);
1797 QCOMPARE(o.actuals().count(), 0);
1799 // Insufficient arguments
1801 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1802 QCOMPARE(o.error(), false);
1803 QCOMPARE(o.invoked(), -1);
1804 QCOMPARE(o.actuals().count(), 0);
1807 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1808 QCOMPARE(o.error(), false);
1809 QCOMPARE(o.invoked(), -1);
1810 QCOMPARE(o.actuals().count(), 0);
1812 // Excessive arguments
1814 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1815 QCOMPARE(o.error(), false);
1816 QCOMPARE(o.invoked(), 8);
1817 QCOMPARE(o.actuals().count(), 1);
1818 QCOMPARE(o.actuals().at(0), QVariant(10));
1821 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1822 QCOMPARE(o.error(), false);
1823 QCOMPARE(o.invoked(), 9);
1824 QCOMPARE(o.actuals().count(), 2);
1825 QCOMPARE(o.actuals().at(0), QVariant(10));
1826 QCOMPARE(o.actuals().at(1), QVariant(11));
1828 // Test return types
1830 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1831 QCOMPARE(o.error(), false);
1832 QCOMPARE(o.invoked(), 0);
1833 QCOMPARE(o.actuals().count(), 0);
1836 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1837 QCOMPARE(o.error(), false);
1838 QCOMPARE(o.invoked(), 1);
1839 QCOMPARE(o.actuals().count(), 0);
1842 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1843 QCOMPARE(o.error(), false);
1844 QCOMPARE(o.invoked(), 2);
1845 QCOMPARE(o.actuals().count(), 0);
1849 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1850 QVERIFY(!ret.IsEmpty());
1851 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1852 QCOMPARE(o.error(), false);
1853 QCOMPARE(o.invoked(), 3);
1854 QCOMPARE(o.actuals().count(), 0);
1859 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1860 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1861 QCOMPARE(o.error(), false);
1862 QCOMPARE(o.invoked(), 4);
1863 QCOMPARE(o.actuals().count(), 0);
1867 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1868 QCOMPARE(o.error(), false);
1869 QCOMPARE(o.invoked(), 5);
1870 QCOMPARE(o.actuals().count(), 0);
1874 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1875 QVERIFY(ret->IsString());
1876 QCOMPARE(engine->toString(ret), QString("Hello world"));
1877 QCOMPARE(o.error(), false);
1878 QCOMPARE(o.invoked(), 6);
1879 QCOMPARE(o.actuals().count(), 0);
1883 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1884 QCOMPARE(o.error(), false);
1885 QCOMPARE(o.invoked(), 7);
1886 QCOMPARE(o.actuals().count(), 0);
1890 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1891 QCOMPARE(o.error(), false);
1892 QCOMPARE(o.invoked(), 8);
1893 QCOMPARE(o.actuals().count(), 1);
1894 QCOMPARE(o.actuals().at(0), QVariant(94));
1897 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1898 QCOMPARE(o.error(), false);
1899 QCOMPARE(o.invoked(), 8);
1900 QCOMPARE(o.actuals().count(), 1);
1901 QCOMPARE(o.actuals().at(0), QVariant(94));
1904 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1905 QCOMPARE(o.error(), false);
1906 QCOMPARE(o.invoked(), 8);
1907 QCOMPARE(o.actuals().count(), 1);
1908 QCOMPARE(o.actuals().at(0), QVariant(0));
1911 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1912 QCOMPARE(o.error(), false);
1913 QCOMPARE(o.invoked(), 8);
1914 QCOMPARE(o.actuals().count(), 1);
1915 QCOMPARE(o.actuals().at(0), QVariant(0));
1918 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1919 QCOMPARE(o.error(), false);
1920 QCOMPARE(o.invoked(), 8);
1921 QCOMPARE(o.actuals().count(), 1);
1922 QCOMPARE(o.actuals().at(0), QVariant(0));
1925 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1926 QCOMPARE(o.error(), false);
1927 QCOMPARE(o.invoked(), 8);
1928 QCOMPARE(o.actuals().count(), 1);
1929 QCOMPARE(o.actuals().at(0), QVariant(0));
1932 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1933 QCOMPARE(o.error(), false);
1934 QCOMPARE(o.invoked(), 9);
1935 QCOMPARE(o.actuals().count(), 2);
1936 QCOMPARE(o.actuals().at(0), QVariant(122));
1937 QCOMPARE(o.actuals().at(1), QVariant(9));
1940 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1941 QCOMPARE(o.error(), false);
1942 QCOMPARE(o.invoked(), 10);
1943 QCOMPARE(o.actuals().count(), 1);
1944 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1947 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1948 QCOMPARE(o.error(), false);
1949 QCOMPARE(o.invoked(), 10);
1950 QCOMPARE(o.actuals().count(), 1);
1951 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1954 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1955 QCOMPARE(o.error(), false);
1956 QCOMPARE(o.invoked(), 10);
1957 QCOMPARE(o.actuals().count(), 1);
1958 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1961 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1962 QCOMPARE(o.error(), false);
1963 QCOMPARE(o.invoked(), 10);
1964 QCOMPARE(o.actuals().count(), 1);
1965 QCOMPARE(o.actuals().at(0), QVariant(0));
1968 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1969 QCOMPARE(o.error(), false);
1970 QCOMPARE(o.invoked(), 10);
1971 QCOMPARE(o.actuals().count(), 1);
1972 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1975 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
1976 QCOMPARE(o.error(), false);
1977 QCOMPARE(o.invoked(), 10);
1978 QCOMPARE(o.actuals().count(), 1);
1979 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1982 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
1983 QCOMPARE(o.error(), false);
1984 QCOMPARE(o.invoked(), 11);
1985 QCOMPARE(o.actuals().count(), 1);
1986 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
1989 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
1990 QCOMPARE(o.error(), false);
1991 QCOMPARE(o.invoked(), 11);
1992 QCOMPARE(o.actuals().count(), 1);
1993 QCOMPARE(o.actuals().at(0), QVariant("19"));
1997 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
1998 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
1999 QCOMPARE(o.error(), false);
2000 QCOMPARE(o.invoked(), 11);
2001 QCOMPARE(o.actuals().count(), 1);
2002 QCOMPARE(o.actuals().at(0), QVariant(expected));
2006 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2007 QCOMPARE(o.error(), false);
2008 QCOMPARE(o.invoked(), 11);
2009 QCOMPARE(o.actuals().count(), 1);
2010 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2013 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2014 QCOMPARE(o.error(), false);
2015 QCOMPARE(o.invoked(), 11);
2016 QCOMPARE(o.actuals().count(), 1);
2017 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2020 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2021 QCOMPARE(o.error(), false);
2022 QCOMPARE(o.invoked(), 12);
2023 QCOMPARE(o.actuals().count(), 1);
2024 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2027 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2028 QCOMPARE(o.error(), false);
2029 QCOMPARE(o.invoked(), 12);
2030 QCOMPARE(o.actuals().count(), 1);
2031 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2034 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2035 QCOMPARE(o.error(), false);
2036 QCOMPARE(o.invoked(), 12);
2037 QCOMPARE(o.actuals().count(), 1);
2038 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2041 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2042 QCOMPARE(o.error(), false);
2043 QCOMPARE(o.invoked(), 12);
2044 QCOMPARE(o.actuals().count(), 1);
2045 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2048 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2049 QCOMPARE(o.error(), false);
2050 QCOMPARE(o.invoked(), 12);
2051 QCOMPARE(o.actuals().count(), 1);
2052 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2055 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2056 QCOMPARE(o.error(), false);
2057 QCOMPARE(o.invoked(), 12);
2058 QCOMPARE(o.actuals().count(), 1);
2059 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2062 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2063 QCOMPARE(o.error(), false);
2064 QCOMPARE(o.invoked(), 13);
2065 QCOMPARE(o.actuals().count(), 1);
2066 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2069 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2070 QCOMPARE(o.error(), false);
2071 QCOMPARE(o.invoked(), 13);
2072 QCOMPARE(o.actuals().count(), 1);
2073 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2076 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2077 QCOMPARE(o.error(), false);
2078 QCOMPARE(o.invoked(), 13);
2079 QCOMPARE(o.actuals().count(), 1);
2080 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2083 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2084 QCOMPARE(o.error(), false);
2085 QCOMPARE(o.invoked(), 13);
2086 QCOMPARE(o.actuals().count(), 1);
2087 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2090 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2091 QCOMPARE(o.error(), false);
2092 QCOMPARE(o.invoked(), 13);
2093 QCOMPARE(o.actuals().count(), 1);
2094 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2097 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2098 QCOMPARE(o.error(), false);
2099 QCOMPARE(o.invoked(), 14);
2100 QCOMPARE(o.actuals().count(), 1);
2101 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2104 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2105 QCOMPARE(o.error(), false);
2106 QCOMPARE(o.invoked(), 14);
2107 QCOMPARE(o.actuals().count(), 1);
2108 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2111 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2112 QCOMPARE(o.error(), false);
2113 QCOMPARE(o.invoked(), 14);
2114 QCOMPARE(o.actuals().count(), 1);
2115 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2118 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2119 QCOMPARE(o.error(), false);
2120 QCOMPARE(o.invoked(), 14);
2121 QCOMPARE(o.actuals().count(), 1);
2122 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2125 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2126 QCOMPARE(o.error(), false);
2127 QCOMPARE(o.invoked(), 15);
2128 QCOMPARE(o.actuals().count(), 2);
2129 QCOMPARE(o.actuals().at(0), QVariant(4));
2130 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2133 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2134 QCOMPARE(o.error(), false);
2135 QCOMPARE(o.invoked(), 15);
2136 QCOMPARE(o.actuals().count(), 2);
2137 QCOMPARE(o.actuals().at(0), QVariant(8));
2138 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2141 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2142 QCOMPARE(o.error(), false);
2143 QCOMPARE(o.invoked(), 15);
2144 QCOMPARE(o.actuals().count(), 2);
2145 QCOMPARE(o.actuals().at(0), QVariant(3));
2146 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2149 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2150 QCOMPARE(o.error(), false);
2151 QCOMPARE(o.invoked(), 15);
2152 QCOMPARE(o.actuals().count(), 2);
2153 QCOMPARE(o.actuals().at(0), QVariant(44));
2154 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2157 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2158 QCOMPARE(o.error(), false);
2159 QCOMPARE(o.invoked(), -1);
2160 QCOMPARE(o.actuals().count(), 0);
2163 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2164 QCOMPARE(o.error(), false);
2165 QCOMPARE(o.invoked(), 16);
2166 QCOMPARE(o.actuals().count(), 1);
2167 QCOMPARE(o.actuals().at(0), QVariant(10));
2170 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2171 QCOMPARE(o.error(), false);
2172 QCOMPARE(o.invoked(), 17);
2173 QCOMPARE(o.actuals().count(), 2);
2174 QCOMPARE(o.actuals().at(0), QVariant(10));
2175 QCOMPARE(o.actuals().at(1), QVariant(11));
2178 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2179 QCOMPARE(o.error(), false);
2180 QCOMPARE(o.invoked(), 18);
2181 QCOMPARE(o.actuals().count(), 1);
2182 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2185 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2186 QCOMPARE(o.error(), false);
2187 QCOMPARE(o.invoked(), 19);
2188 QCOMPARE(o.actuals().count(), 1);
2189 QCOMPARE(o.actuals().at(0), QVariant(9));
2192 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2193 QCOMPARE(o.error(), false);
2194 QCOMPARE(o.invoked(), 20);
2195 QCOMPARE(o.actuals().count(), 2);
2196 QCOMPARE(o.actuals().at(0), QVariant(10));
2197 QCOMPARE(o.actuals().at(1), QVariant(19));
2200 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2201 QCOMPARE(o.error(), false);
2202 QCOMPARE(o.invoked(), 20);
2203 QCOMPARE(o.actuals().count(), 2);
2204 QCOMPARE(o.actuals().at(0), QVariant(10));
2205 QCOMPARE(o.actuals().at(1), QVariant(13));
2208 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2209 QCOMPARE(o.error(), false);
2210 QCOMPARE(o.invoked(), -3);
2211 QCOMPARE(o.actuals().count(), 1);
2212 QCOMPARE(o.actuals().at(0), QVariant(9));
2215 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2216 QCOMPARE(o.error(), false);
2217 QCOMPARE(o.invoked(), 21);
2218 QCOMPARE(o.actuals().count(), 2);
2219 QCOMPARE(o.actuals().at(0), QVariant(9));
2220 QCOMPARE(o.actuals().at(1), QVariant());
2223 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2224 QCOMPARE(o.error(), false);
2225 QCOMPARE(o.invoked(), 21);
2226 QCOMPARE(o.actuals().count(), 2);
2227 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2228 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2231 // QTBUG-13047 (check that you can pass registered object types as args)
2232 void tst_qdeclarativeecmascript::invokableObjectArg()
2234 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2236 QObject *o = component.create();
2238 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2240 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2245 // QTBUG-13047 (check that you can return registered object types from methods)
2246 void tst_qdeclarativeecmascript::invokableObjectRet()
2248 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2250 QObject *o = component.create();
2252 QCOMPARE(o->property("test").toBool(), true);
2257 void tst_qdeclarativeecmascript::listToVariant()
2259 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2261 MyQmlContainer container;
2263 QDeclarativeContext context(engine.rootContext());
2264 context.setContextObject(&container);
2266 QObject *object = component.create(&context);
2267 QVERIFY(object != 0);
2269 QVariant v = object->property("test");
2270 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2271 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2277 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2278 void tst_qdeclarativeecmascript::listAssignment()
2280 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2281 QObject *obj = component.create();
2282 QCOMPARE(obj->property("list1length").toInt(), 2);
2283 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2284 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2285 QCOMPARE(list1.count(&list1), list2.count(&list2));
2286 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2287 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2292 void tst_qdeclarativeecmascript::multiEngineObject()
2295 obj.setStringProperty("Howdy planet");
2297 QDeclarativeEngine e1;
2298 e1.rootContext()->setContextProperty("thing", &obj);
2299 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2301 QDeclarativeEngine e2;
2302 e2.rootContext()->setContextProperty("thing", &obj);
2303 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2305 QObject *o1 = c1.create();
2306 QObject *o2 = c2.create();
2308 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2309 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2315 // Test that references to QObjects are cleanup when the object is destroyed
2316 void tst_qdeclarativeecmascript::deletedObject()
2318 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2320 QObject *object = component.create();
2322 QCOMPARE(object->property("test1").toBool(), true);
2323 QCOMPARE(object->property("test2").toBool(), true);
2324 QCOMPARE(object->property("test3").toBool(), true);
2325 QCOMPARE(object->property("test4").toBool(), true);
2330 void tst_qdeclarativeecmascript::attachedPropertyScope()
2332 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2334 QObject *object = component.create();
2335 QVERIFY(object != 0);
2337 MyQmlAttachedObject *attached =
2338 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2339 QVERIFY(attached != 0);
2341 QCOMPARE(object->property("value2").toInt(), 0);
2343 attached->emitMySignal();
2345 QCOMPARE(object->property("value2").toInt(), 9);
2350 void tst_qdeclarativeecmascript::scriptConnect()
2353 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2355 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2356 QVERIFY(object != 0);
2358 QCOMPARE(object->property("test").toBool(), false);
2359 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2360 QCOMPARE(object->property("test").toBool(), true);
2366 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2368 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2369 QVERIFY(object != 0);
2371 QCOMPARE(object->property("test").toBool(), false);
2372 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2373 QCOMPARE(object->property("test").toBool(), true);
2379 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2381 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2382 QVERIFY(object != 0);
2384 QCOMPARE(object->property("test").toBool(), false);
2385 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2386 QCOMPARE(object->property("test").toBool(), true);
2392 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2394 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2395 QVERIFY(object != 0);
2397 QCOMPARE(object->methodCalled(), false);
2398 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2399 QCOMPARE(object->methodCalled(), true);
2405 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2407 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2408 QVERIFY(object != 0);
2410 QCOMPARE(object->methodCalled(), false);
2411 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2412 QCOMPARE(object->methodCalled(), true);
2418 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2420 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2421 QVERIFY(object != 0);
2423 QCOMPARE(object->property("test").toInt(), 0);
2424 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2425 QCOMPARE(object->property("test").toInt(), 2);
2431 void tst_qdeclarativeecmascript::scriptDisconnect()
2434 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2436 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2437 QVERIFY(object != 0);
2439 QCOMPARE(object->property("test").toInt(), 0);
2440 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2441 QCOMPARE(object->property("test").toInt(), 1);
2442 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2443 QCOMPARE(object->property("test").toInt(), 2);
2444 emit object->basicSignal();
2445 QCOMPARE(object->property("test").toInt(), 2);
2446 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2447 QCOMPARE(object->property("test").toInt(), 2);
2453 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2455 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2456 QVERIFY(object != 0);
2458 QCOMPARE(object->property("test").toInt(), 0);
2459 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2460 QCOMPARE(object->property("test").toInt(), 1);
2461 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2462 QCOMPARE(object->property("test").toInt(), 2);
2463 emit object->basicSignal();
2464 QCOMPARE(object->property("test").toInt(), 2);
2465 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2466 QCOMPARE(object->property("test").toInt(), 2);
2472 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2474 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2475 QVERIFY(object != 0);
2477 QCOMPARE(object->property("test").toInt(), 0);
2478 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2479 QCOMPARE(object->property("test").toInt(), 1);
2480 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2481 QCOMPARE(object->property("test").toInt(), 2);
2482 emit object->basicSignal();
2483 QCOMPARE(object->property("test").toInt(), 2);
2484 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2485 QCOMPARE(object->property("test").toInt(), 3);
2490 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2492 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2493 QVERIFY(object != 0);
2495 QCOMPARE(object->property("test").toInt(), 0);
2496 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2497 QCOMPARE(object->property("test").toInt(), 1);
2498 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2499 QCOMPARE(object->property("test").toInt(), 2);
2500 emit object->basicSignal();
2501 QCOMPARE(object->property("test").toInt(), 2);
2502 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2503 QCOMPARE(object->property("test").toInt(), 3);
2509 class OwnershipObject : public QObject
2513 OwnershipObject() { object = new QObject; }
2515 QPointer<QObject> object;
2518 QObject *getObject() { return object; }
2521 void tst_qdeclarativeecmascript::ownership()
2523 OwnershipObject own;
2524 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2525 context->setContextObject(&own);
2528 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2530 QVERIFY(own.object != 0);
2532 QObject *object = component.create(context);
2534 engine.collectGarbage();
2536 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2538 QVERIFY(own.object == 0);
2543 own.object = new QObject(&own);
2546 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2548 QVERIFY(own.object != 0);
2550 QObject *object = component.create(context);
2552 engine.collectGarbage();
2554 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2556 QVERIFY(own.object != 0);
2564 class CppOwnershipReturnValue : public QObject
2568 CppOwnershipReturnValue() : value(0) {}
2569 ~CppOwnershipReturnValue() { delete value; }
2571 Q_INVOKABLE QObject *create() {
2572 value = new QObject;
2573 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2577 Q_INVOKABLE MyQmlObject *createQmlObject() {
2578 MyQmlObject *rv = new MyQmlObject;
2583 QPointer<QObject> value;
2587 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2588 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2590 CppOwnershipReturnValue source;
2593 QDeclarativeEngine engine;
2594 engine.rootContext()->setContextProperty("source", &source);
2596 QVERIFY(source.value == 0);
2598 QDeclarativeComponent component(&engine);
2599 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2601 QObject *object = component.create();
2603 QVERIFY(object != 0);
2604 QVERIFY(source.value != 0);
2609 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2611 QVERIFY(source.value != 0);
2615 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2617 CppOwnershipReturnValue source;
2620 QDeclarativeEngine engine;
2621 engine.rootContext()->setContextProperty("source", &source);
2623 QVERIFY(source.value == 0);
2625 QDeclarativeComponent component(&engine);
2626 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2628 QObject *object = component.create();
2630 QVERIFY(object != 0);
2631 QVERIFY(source.value != 0);
2636 engine.collectGarbage();
2637 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2639 QVERIFY(source.value == 0);
2642 class QListQObjectMethodsObject : public QObject
2646 QListQObjectMethodsObject() {
2647 m_objects.append(new MyQmlObject());
2648 m_objects.append(new MyQmlObject());
2651 ~QListQObjectMethodsObject() {
2652 qDeleteAll(m_objects);
2656 QList<QObject *> getObjects() { return m_objects; }
2659 QList<QObject *> m_objects;
2662 // Tests that returning a QList<QObject*> from a method works
2663 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2665 QListQObjectMethodsObject obj;
2666 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2667 context->setContextObject(&obj);
2669 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2671 QObject *object = component.create(context);
2673 QCOMPARE(object->property("test").toInt(), 2);
2674 QCOMPARE(object->property("test2").toBool(), true);
2681 void tst_qdeclarativeecmascript::strictlyEquals()
2683 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2685 QObject *object = component.create();
2686 QVERIFY(object != 0);
2688 QCOMPARE(object->property("test1").toBool(), true);
2689 QCOMPARE(object->property("test2").toBool(), true);
2690 QCOMPARE(object->property("test3").toBool(), true);
2691 QCOMPARE(object->property("test4").toBool(), true);
2692 QCOMPARE(object->property("test5").toBool(), true);
2693 QCOMPARE(object->property("test6").toBool(), true);
2694 QCOMPARE(object->property("test7").toBool(), true);
2695 QCOMPARE(object->property("test8").toBool(), true);
2700 void tst_qdeclarativeecmascript::compiled()
2702 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2704 QObject *object = component.create();
2705 QVERIFY(object != 0);
2707 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2708 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2709 QCOMPARE(object->property("test3").toBool(), true);
2710 QCOMPARE(object->property("test4").toBool(), false);
2711 QCOMPARE(object->property("test5").toBool(), false);
2712 QCOMPARE(object->property("test6").toBool(), true);
2714 QCOMPARE(object->property("test7").toInt(), 185);
2715 QCOMPARE(object->property("test8").toInt(), 167);
2716 QCOMPARE(object->property("test9").toBool(), true);
2717 QCOMPARE(object->property("test10").toBool(), false);
2718 QCOMPARE(object->property("test11").toBool(), false);
2719 QCOMPARE(object->property("test12").toBool(), true);
2721 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2722 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2723 QCOMPARE(object->property("test15").toBool(), false);
2724 QCOMPARE(object->property("test16").toBool(), true);
2726 QCOMPARE(object->property("test17").toInt(), 5);
2727 QCOMPARE(object->property("test18").toReal(), qreal(176));
2728 QCOMPARE(object->property("test19").toInt(), 7);
2729 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2730 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2731 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2732 QCOMPARE(object->property("test23").toBool(), true);
2733 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2734 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2739 // Test that numbers assigned in bindings as strings work consistently
2740 void tst_qdeclarativeecmascript::numberAssignment()
2742 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2744 QObject *object = component.create();
2745 QVERIFY(object != 0);
2747 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2748 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2749 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2750 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2751 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2753 QCOMPARE(object->property("test5"), QVariant((int)7));
2754 QCOMPARE(object->property("test6"), QVariant((int)7));
2755 QCOMPARE(object->property("test7"), QVariant((int)6));
2756 QCOMPARE(object->property("test8"), QVariant((int)6));
2758 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2759 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2760 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2761 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2766 void tst_qdeclarativeecmascript::propertySplicing()
2768 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2770 QObject *object = component.create();
2771 QVERIFY(object != 0);
2773 QCOMPARE(object->property("test").toBool(), true);
2779 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2781 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2783 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2784 QVERIFY(object != 0);
2786 MyQmlObject::MyType type;
2787 type.value = 0x8971123;
2788 emit object->signalWithUnknownType(type);
2790 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2792 QCOMPARE(result.value, type.value);
2798 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2800 QTest::addColumn<QString>("expression");
2801 QTest::addColumn<QString>("compare");
2803 QString compareStrict("(function(a, b) { return a === b; })");
2804 QTest::newRow("true") << "true" << compareStrict;
2805 QTest::newRow("undefined") << "undefined" << compareStrict;
2806 QTest::newRow("null") << "null" << compareStrict;
2807 QTest::newRow("123") << "123" << compareStrict;
2808 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2810 QString comparePropertiesStrict(
2812 " if (typeof b != 'object')"
2814 " var props = Object.getOwnPropertyNames(b);"
2815 " for (var i = 0; i < props.length; ++i) {"
2816 " var p = props[i];"
2817 " return arguments.callee(a[p], b[p]);"
2820 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2821 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2824 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2826 QFETCH(QString, expression);
2827 QFETCH(QString, compare);
2829 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2830 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2831 QVERIFY(object != 0);
2833 QJSValue value = engine.evaluate(expression);
2834 QVERIFY(!engine.hasUncaughtException());
2835 object->setProperty("expression", expression);
2836 object->setProperty("compare", compare);
2837 object->setProperty("pass", false);
2839 emit object->signalWithVariant(QVariant::fromValue(value));
2840 QVERIFY(object->property("pass").toBool());
2843 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2845 signalWithJSValueInVariant_data();
2848 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2850 QFETCH(QString, expression);
2851 QFETCH(QString, compare);
2853 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2854 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2855 QVERIFY(object != 0);
2858 QJSValue value = engine2.evaluate(expression);
2859 QVERIFY(!engine2.hasUncaughtException());
2860 object->setProperty("expression", expression);
2861 object->setProperty("compare", compare);
2862 object->setProperty("pass", false);
2864 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2865 emit object->signalWithVariant(QVariant::fromValue(value));
2866 QVERIFY(!object->property("pass").toBool());
2869 void tst_qdeclarativeecmascript::moduleApi_data()
2871 QTest::addColumn<QUrl>("testfile");
2872 QTest::addColumn<QString>("errorMessage");
2873 QTest::addColumn<QStringList>("warningMessages");
2874 QTest::addColumn<QStringList>("readProperties");
2875 QTest::addColumn<QVariantList>("readExpectedValues");
2876 QTest::addColumn<QStringList>("writeProperties");
2877 QTest::addColumn<QVariantList>("writeValues");
2878 QTest::addColumn<QStringList>("readBackProperties");
2879 QTest::addColumn<QVariantList>("readBackExpectedValues");
2881 QTest::newRow("qobject, register + read + method")
2882 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2885 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2886 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2887 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2893 QTest::newRow("script, register + read")
2894 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2897 << (QStringList() << "scriptTest")
2898 << (QVariantList() << 13)
2904 QTest::newRow("qobject, caching + read")
2905 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2908 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2909 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2915 QTest::newRow("script, caching + read")
2916 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2919 << (QStringList() << "scriptTest")
2920 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2926 QTest::newRow("qobject, writing + readonly constraints")
2927 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2929 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2930 << (QStringList() << "readOnlyProperty" << "writableProperty")
2931 << (QVariantList() << 20 << 50)
2932 << (QStringList() << "firstProperty" << "writableProperty")
2933 << (QVariantList() << 30 << 30)
2934 << (QStringList() << "readOnlyProperty" << "writableProperty")
2935 << (QVariantList() << 20 << 30);
2937 QTest::newRow("script, writing + readonly constraints")
2938 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
2940 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
2941 << (QStringList() << "readBack" << "unchanged")
2942 << (QVariantList() << 13 << 42)
2943 << (QStringList() << "firstProperty" << "secondProperty")
2944 << (QVariantList() << 30 << 30)
2945 << (QStringList() << "readBack" << "unchanged")
2946 << (QVariantList() << 30 << 42);
2948 QTest::newRow("qobject module API enum values in JS")
2949 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
2952 << (QStringList() << "enumValue" << "enumMethod")
2953 << (QVariantList() << 42 << 30)
2959 QTest::newRow("qobject, invalid major version fail")
2960 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
2961 << QString("QDeclarativeComponent: Component is not ready")
2970 QTest::newRow("qobject, invalid minor version fail")
2971 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
2972 << QString("QDeclarativeComponent: Component is not ready")
2982 void tst_qdeclarativeecmascript::moduleApi()
2984 QFETCH(QUrl, testfile);
2985 QFETCH(QString, errorMessage);
2986 QFETCH(QStringList, warningMessages);
2987 QFETCH(QStringList, readProperties);
2988 QFETCH(QVariantList, readExpectedValues);
2989 QFETCH(QStringList, writeProperties);
2990 QFETCH(QVariantList, writeValues);
2991 QFETCH(QStringList, readBackProperties);
2992 QFETCH(QVariantList, readBackExpectedValues);
2994 QDeclarativeComponent component(&engine, testfile);
2996 if (!errorMessage.isEmpty())
2997 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
2999 if (warningMessages.size())
3000 foreach (const QString &warning, warningMessages)
3001 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3003 QObject *object = component.create();
3004 if (!errorMessage.isEmpty()) {
3005 QVERIFY(object == 0);
3007 QVERIFY(object != 0);
3008 for (int i = 0; i < readProperties.size(); ++i)
3009 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3010 for (int i = 0; i < writeProperties.size(); ++i)
3011 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3012 for (int i = 0; i < readBackProperties.size(); ++i)
3013 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3018 void tst_qdeclarativeecmascript::importScripts_data()
3020 QTest::addColumn<QUrl>("testfile");
3021 QTest::addColumn<QString>("errorMessage");
3022 QTest::addColumn<QStringList>("warningMessages");
3023 QTest::addColumn<QStringList>("propertyNames");
3024 QTest::addColumn<QVariantList>("propertyValues");
3026 QTest::newRow("basic functionality")
3027 << TEST_FILE("jsimport/testImport.qml")
3030 << (QStringList() << QLatin1String("importedScriptStringValue")
3031 << QLatin1String("importedScriptFunctionValue")
3032 << QLatin1String("importedModuleAttachedPropertyValue")
3033 << QLatin1String("importedModuleEnumValue"))
3034 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3039 QTest::newRow("import scoping")
3040 << TEST_FILE("jsimport/testImportScoping.qml")
3043 << (QStringList() << QLatin1String("componentError"))
3044 << (QVariantList() << QVariant(5));
3046 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3047 << TEST_FILE("jsimportfail/failOne.qml")
3049 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3050 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3051 << (QVariantList() << QVariant(QString()));
3053 QTest::newRow("javascript imports in an import should be private to the import scope")
3054 << TEST_FILE("jsimportfail/failTwo.qml")
3056 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3057 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3058 << (QVariantList() << QVariant(QString()));
3060 QTest::newRow("module imports in an import should be private to the import scope")
3061 << TEST_FILE("jsimportfail/failThree.qml")
3063 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3064 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3065 << (QVariantList() << QVariant(false));
3067 QTest::newRow("typenames in an import should be private to the import scope")
3068 << TEST_FILE("jsimportfail/failFour.qml")
3070 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3071 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3072 << (QVariantList() << QVariant(0));
3074 QTest::newRow("import with imports has it's own activation scope")
3075 << TEST_FILE("jsimportfail/failFive.qml")
3077 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3078 << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3079 << (QStringList() << QLatin1String("componentError"))
3080 << (QVariantList() << QVariant(0));
3082 QTest::newRow("import pragma library script")
3083 << TEST_FILE("jsimport/testImportPragmaLibrary.qml")
3086 << (QStringList() << QLatin1String("testValue"))
3087 << (QVariantList() << QVariant(31));
3089 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3090 << TEST_FILE("jsimportfail/testImportPragmaLibrary.qml")
3093 << (QStringList() << QLatin1String("testValue"))
3094 << (QVariantList() << QVariant(0));
3096 QTest::newRow("import pragma library script which has an import")
3097 << TEST_FILE("jsimport/testImportPragmaLibraryWithImports.qml")
3100 << (QStringList() << QLatin1String("testValue"))
3101 << (QVariantList() << QVariant(55));
3103 QTest::newRow("import pragma library script which has a pragma library import")
3104 << TEST_FILE("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3107 << (QStringList() << QLatin1String("testValue"))
3108 << (QVariantList() << QVariant(18));
3111 void tst_qdeclarativeecmascript::importScripts()
3113 QFETCH(QUrl, testfile);
3114 QFETCH(QString, errorMessage);
3115 QFETCH(QStringList, warningMessages);
3116 QFETCH(QStringList, propertyNames);
3117 QFETCH(QVariantList, propertyValues);
3119 QDeclarativeComponent component(&engine, testfile);
3121 if (!errorMessage.isEmpty())
3122 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3124 if (warningMessages.size())
3125 foreach (const QString &warning, warningMessages)
3126 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3128 QObject *object = component.create();
3129 if (!errorMessage.isEmpty()) {
3130 QVERIFY(object == 0);
3132 QVERIFY(object != 0);
3133 for (int i = 0; i < propertyNames.size(); ++i)
3134 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3139 void tst_qdeclarativeecmascript::scarceResources()
3141 QPixmap origPixmap(100, 100);
3142 origPixmap.fill(Qt::blue);
3144 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3145 ScarceResourceObject *eo = 0;
3146 QObject *object = 0;
3148 // in the following three cases, the instance created from the component
3149 // has a property which is a copy of the scarce resource; hence, the
3150 // resource should NOT be detached prior to deletion of the object instance,
3151 // unless the resource is destroyed explicitly.
3152 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
3153 object = component.create();
3154 QVERIFY(object != 0);
3155 QVERIFY(object->property("scarceResourceCopy").isValid());
3156 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3157 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3158 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3159 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3162 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3163 object = componentTwo.create();
3164 QVERIFY(object != 0);
3165 QVERIFY(object->property("scarceResourceCopy").isValid());
3166 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3167 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3168 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3169 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3172 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3173 object = componentThree.create();
3174 QVERIFY(object != 0);
3175 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3176 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3177 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3178 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3181 // in the following three cases, no other copy should exist in memory,
3182 // and so it should be detached (unless explicitly preserved).
3183 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3184 object = componentFour.create();
3185 QVERIFY(object != 0);
3186 QVERIFY(object->property("scarceResourceTest").isValid());
3187 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3188 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3189 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3190 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3193 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3194 object = componentFive.create();
3195 QVERIFY(object != 0);
3196 QVERIFY(object->property("scarceResourceTest").isValid());
3197 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3198 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3199 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3200 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3203 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3204 object = componentSix.create();
3205 QVERIFY(object != 0);
3206 QVERIFY(object->property("scarceResourceTest").isValid());
3207 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3208 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3209 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3210 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3213 // test that scarce resources are handled correctly for imports
3214 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3215 object = componentSeven.create();
3216 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3217 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3220 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3221 object = componentEight.create();
3222 QVERIFY(object != 0);
3223 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3224 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3227 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3228 object = componentNine.create();
3229 QVERIFY(object != 0);
3230 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3231 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3232 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3233 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3234 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3235 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3238 // test that scarce resources are handled properly in signal invocation
3239 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3240 object = componentTen.create();
3241 QVERIFY(object != 0);
3242 QObject *srsc = object->findChild<QObject*>("srsc");
3244 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3245 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3246 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3247 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3248 QMetaObject::invokeMethod(srsc, "testSignal");
3249 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3250 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3251 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3252 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3253 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3254 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3255 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3256 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3257 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3258 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3261 // test that scarce resources are handled properly from js functions in qml files
3262 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3263 object = componentEleven.create();
3264 QVERIFY(object != 0);
3265 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3266 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3267 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3268 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3269 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3270 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3271 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3272 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3273 QMetaObject::invokeMethod(object, "releaseScarceResource");
3274 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3275 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3276 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3277 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3280 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3281 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3282 object = componentTwelve.create();
3283 QVERIFY(object != 0);
3284 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3285 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3286 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3287 QString srp_name = object->property("srp_name").toString();
3288 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3289 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3290 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3291 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3292 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3293 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3294 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3298 void tst_qdeclarativeecmascript::propertyChangeSlots()
3300 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3301 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3302 QObject *object = component.create();
3303 QVERIFY(object != 0);
3306 // ensure that invalid property names fail properly.
3307 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3308 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3309 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3310 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3311 object = e1.create();
3312 QVERIFY(object == 0);
3315 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3316 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3317 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3318 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3319 object = e2.create();
3320 QVERIFY(object == 0);
3323 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3324 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3325 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3326 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3327 object = e3.create();
3328 QVERIFY(object == 0);
3331 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3332 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3333 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3334 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3335 object = e4.create();
3336 QVERIFY(object == 0);
3340 // Ensure that QObject type conversion works on binding assignment
3341 void tst_qdeclarativeecmascript::elementAssign()
3343 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3345 QObject *object = component.create();
3346 QVERIFY(object != 0);
3348 QCOMPARE(object->property("test").toBool(), true);
3354 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3356 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3358 QObject *object = component.create();
3359 QVERIFY(object != 0);
3361 QCOMPARE(object->property("test").toBool(), true);
3367 void tst_qdeclarativeecmascript::objectConversion()
3369 QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
3371 QObject *object = component.create();
3372 QVERIFY(object != 0);
3374 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
3375 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
3382 void tst_qdeclarativeecmascript::booleanConversion()
3384 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3386 QObject *object = component.create();
3387 QVERIFY(object != 0);
3389 QCOMPARE(object->property("test_true1").toBool(), true);
3390 QCOMPARE(object->property("test_true2").toBool(), true);
3391 QCOMPARE(object->property("test_true3").toBool(), true);
3392 QCOMPARE(object->property("test_true4").toBool(), true);
3393 QCOMPARE(object->property("test_true5").toBool(), true);
3395 QCOMPARE(object->property("test_false1").toBool(), false);
3396 QCOMPARE(object->property("test_false2").toBool(), false);
3397 QCOMPARE(object->property("test_false3").toBool(), false);
3402 void tst_qdeclarativeecmascript::handleReferenceManagement()
3407 // Linear QObject reference
3408 QDeclarativeEngine hrmEngine;
3409 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3410 QObject *object = component.create();
3411 QVERIFY(object != 0);
3412 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3413 cro->setDtorCount(&dtorCount);
3414 QMetaObject::invokeMethod(object, "createReference");
3415 QMetaObject::invokeMethod(object, "performGc");
3416 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3417 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3419 hrmEngine.collectGarbage();
3420 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3421 QCOMPARE(dtorCount, 3);
3426 // Circular QObject reference
3427 QDeclarativeEngine hrmEngine;
3428 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3429 QObject *object = component.create();
3430 QVERIFY(object != 0);
3431 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3432 cro->setDtorCount(&dtorCount);
3433 QMetaObject::invokeMethod(object, "circularReference");
3434 QMetaObject::invokeMethod(object, "performGc");
3435 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3436 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3438 hrmEngine.collectGarbage();
3439 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3440 QCOMPARE(dtorCount, 3);
3445 // Linear handle reference
3446 QDeclarativeEngine hrmEngine;
3447 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3448 QObject *object = component.create();
3449 QVERIFY(object != 0);
3450 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3452 crh->setDtorCount(&dtorCount);
3453 QMetaObject::invokeMethod(object, "createReference");
3454 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3455 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3456 QVERIFY(first != 0);
3457 QVERIFY(second != 0);
3458 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3459 // now we have to reparent second and make second owned by JS.
3460 second->setParent(0);
3461 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3462 QMetaObject::invokeMethod(object, "performGc");
3463 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3464 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3466 hrmEngine.collectGarbage();
3467 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3468 QCOMPARE(dtorCount, 3);
3473 // Circular handle reference
3474 QDeclarativeEngine hrmEngine;
3475 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3476 QObject *object = component.create();
3477 QVERIFY(object != 0);
3478 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3480 crh->setDtorCount(&dtorCount);
3481 QMetaObject::invokeMethod(object, "circularReference");
3482 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3483 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3484 QVERIFY(first != 0);
3485 QVERIFY(second != 0);
3486 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3487 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3488 // now we have to reparent and change ownership.
3489 first->setParent(0);
3490 second->setParent(0);
3491 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3492 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3493 QMetaObject::invokeMethod(object, "performGc");
3494 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3495 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3497 hrmEngine.collectGarbage();
3498 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3499 QCOMPARE(dtorCount, 3);
3504 // multiple engine interaction - linear reference
3505 QDeclarativeEngine hrmEngine1;
3506 QDeclarativeEngine hrmEngine2;
3507 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3508 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3509 QObject *object1 = component1.create();
3510 QObject *object2 = component2.create();
3511 QVERIFY(object1 != 0);
3512 QVERIFY(object2 != 0);
3513 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3514 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3517 crh1->setDtorCount(&dtorCount);
3518 crh2->setDtorCount(&dtorCount);
3519 QMetaObject::invokeMethod(object1, "createReference");
3520 QMetaObject::invokeMethod(object2, "createReference");
3521 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3522 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3523 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3524 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3525 QVERIFY(first1 != 0);
3526 QVERIFY(second1 != 0);
3527 QVERIFY(first2 != 0);
3528 QVERIFY(second2 != 0);
3529 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3530 // now we have to reparent second2 and make second2 owned by JS.
3531 second2->setParent(0);
3532 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3533 QMetaObject::invokeMethod(object1, "performGc");
3534 QMetaObject::invokeMethod(object2, "performGc");
3535 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3536 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3539 hrmEngine1.collectGarbage();
3540 hrmEngine2.collectGarbage();
3541 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3542 QCOMPARE(dtorCount, 6);
3547 // multiple engine interaction - circular reference
3548 QDeclarativeEngine hrmEngine1;
3549 QDeclarativeEngine hrmEngine2;
3550 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3551 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3552 QObject *object1 = component1.create();
3553 QObject *object2 = component2.create();
3554 QVERIFY(object1 != 0);
3555 QVERIFY(object2 != 0);
3556 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3557 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3560 crh1->setDtorCount(&dtorCount);
3561 crh2->setDtorCount(&dtorCount);
3562 QMetaObject::invokeMethod(object1, "createReference");
3563 QMetaObject::invokeMethod(object2, "createReference");
3564 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3565 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3566 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3567 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3568 QVERIFY(first1 != 0);
3569 QVERIFY(second1 != 0);
3570 QVERIFY(first2 != 0);
3571 QVERIFY(second2 != 0);
3572 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3573 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3574 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3575 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3576 // now we have to reparent and change ownership to JS.
3577 first1->setParent(0);
3578 second1->setParent(0);
3579 first2->setParent(0);
3580 second2->setParent(0);
3581 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
3582 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3583 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3584 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3585 QMetaObject::invokeMethod(object1, "performGc");
3586 QMetaObject::invokeMethod(object2, "performGc");
3587 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3588 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
3591 hrmEngine1.collectGarbage();
3592 hrmEngine2.collectGarbage();
3593 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3594 QCOMPARE(dtorCount, 6);
3599 // multiple engine interaction - linear reference with engine deletion
3600 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
3601 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
3602 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3603 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3604 QObject *object1 = component1.create();
3605 QObject *object2 = component2.create();
3606 QVERIFY(object1 != 0);
3607 QVERIFY(object2 != 0);
3608 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3609 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3612 crh1->setDtorCount(&dtorCount);
3613 crh2->setDtorCount(&dtorCount);
3614 QMetaObject::invokeMethod(object1, "createReference");
3615 QMetaObject::invokeMethod(object2, "createReference");
3616 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3617 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3618 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3619 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3620 QVERIFY(first1 != 0);
3621 QVERIFY(second1 != 0);
3622 QVERIFY(first2 != 0);
3623 QVERIFY(second2 != 0);
3624 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3625 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3626 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3627 // now we have to reparent and change ownership to JS.
3628 first1->setParent(crh1);
3629 second1->setParent(0);
3630 first2->setParent(0);
3631 second2->setParent(0);
3632 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3633 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3634 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3635 QMetaObject::invokeMethod(object1, "performGc");
3636 QMetaObject::invokeMethod(object2, "performGc");
3637 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3638 QCOMPARE(dtorCount, 0);
3640 QMetaObject::invokeMethod(object1, "performGc");
3641 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3642 QCOMPARE(dtorCount, 0);
3645 hrmEngine1->collectGarbage();
3646 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3647 QCOMPARE(dtorCount, 6);
3652 void tst_qdeclarativeecmascript::stringArg()
3654 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
3655 QObject *object = component.create();
3656 QVERIFY(object != 0);
3657 QMetaObject::invokeMethod(object, "success");
3658 QVERIFY(object->property("returnValue").toBool());
3660 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
3661 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
3662 QMetaObject::invokeMethod(object, "failure");
3663 QVERIFY(object->property("returnValue").toBool());
3668 // Test that assigning a null object works
3669 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
3670 void tst_qdeclarativeecmascript::nullObjectBinding()
3672 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
3674 QObject *object = component.create();
3675 QVERIFY(object != 0);
3677 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
3682 // Test that bindings don't evaluate once the engine has been destroyed
3683 void tst_qdeclarativeecmascript::deletedEngine()
3685 QDeclarativeEngine *engine = new QDeclarativeEngine;
3686 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
3688 QObject *object = component.create();
3689 QVERIFY(object != 0);
3691 QCOMPARE(object->property("a").toInt(), 39);
3692 object->setProperty("b", QVariant(9));
3693 QCOMPARE(object->property("a").toInt(), 117);
3697 QCOMPARE(object->property("a").toInt(), 117);
3698 object->setProperty("b", QVariant(10));
3699 QCOMPARE(object->property("a").toInt(), 117);
3704 // Test the crashing part of QTBUG-9705
3705 void tst_qdeclarativeecmascript::libraryScriptAssert()
3707 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
3709 QObject *object = component.create();
3710 QVERIFY(object != 0);
3715 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
3717 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
3719 QObject *object = component.create();
3720 QVERIFY(object != 0);
3722 QCOMPARE(object->property("test1").toInt(), 10);
3723 QCOMPARE(object->property("test2").toInt(), 11);
3725 object->setProperty("runTest", true);
3727 QCOMPARE(object->property("test1"), QVariant());
3728 QCOMPARE(object->property("test2"), QVariant());
3734 void tst_qdeclarativeecmascript::qtbug_9792()
3736 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
3738 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
3740 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
3741 QVERIFY(object != 0);
3743 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
3744 object->basicSignal();
3748 transientErrorsMsgCount = 0;
3749 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3751 object->basicSignal();
3753 qInstallMsgHandler(old);
3755 QCOMPARE(transientErrorsMsgCount, 0);
3760 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
3761 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
3763 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
3765 QObject *o = component.create();
3768 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
3769 QVERIFY(nested != 0);
3771 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
3774 nested = qvariant_cast<QObject *>(o->property("object"));
3775 QVERIFY(nested == 0);
3777 // If the bug is present, the next line will crash
3781 // Test that we shut down without stupid warnings
3782 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
3785 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
3787 QObject *o = component.create();
3789 transientErrorsMsgCount = 0;
3790 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3794 qInstallMsgHandler(old);
3796 QCOMPARE(transientErrorsMsgCount, 0);
3801 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
3803 QObject *o = component.create();
3805 transientErrorsMsgCount = 0;
3806 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3810 qInstallMsgHandler(old);
3812 QCOMPARE(transientErrorsMsgCount, 0);
3816 void tst_qdeclarativeecmascript::canAssignNullToQObject()
3819 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
3821 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3824 QVERIFY(o->objectProperty() != 0);
3826 o->setProperty("runTest", true);
3828 QVERIFY(o->objectProperty() == 0);
3834 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
3836 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3839 QVERIFY(o->objectProperty() == 0);
3845 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
3847 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
3849 QString url = component.url().toString();
3850 QString warning = url + ":4: Unable to assign a function to a property.";
3851 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3853 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3856 QVERIFY(!o->property("a").isValid());
3861 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
3863 QFETCH(QString, triggerProperty);
3865 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3866 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3868 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3870 QVERIFY(!o->property("a").isValid());
3872 o->setProperty("aNumber", QVariant(5));
3873 o->setProperty(triggerProperty.toUtf8().constData(), true);
3874 QCOMPARE(o->property("a"), QVariant(50));
3876 o->setProperty("aNumber", QVariant(10));
3877 QCOMPARE(o->property("a"), QVariant(100));
3882 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
3884 QTest::addColumn<QString>("triggerProperty");
3886 QTest::newRow("assign to property") << "assignToProperty";
3887 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
3889 QTest::newRow("assign to value type") << "assignToValueType";
3891 QTest::newRow("use 'this'") << "assignWithThis";
3892 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
3895 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
3897 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3898 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3900 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3902 QVERIFY(!o->property("a").isValid());
3904 o->setProperty("assignFuncWithoutReturn", true);
3905 QVERIFY(!o->property("a").isValid());
3907 QString url = component.url().toString();
3908 QString warning = url + ":67: Unable to assign QString to int";
3909 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3910 o->setProperty("assignWrongType", true);
3912 warning = url + ":71: Unable to assign QString to int";
3913 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3914 o->setProperty("assignWrongTypeToValueType", true);
3919 void tst_qdeclarativeecmascript::eval()
3921 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
3923 QObject *o = component.create();
3926 QCOMPARE(o->property("test1").toBool(), true);
3927 QCOMPARE(o->property("test2").toBool(), true);
3928 QCOMPARE(o->property("test3").toBool(), true);
3929 QCOMPARE(o->property("test4").toBool(), true);
3930 QCOMPARE(o->property("test5").toBool(), true);
3935 void tst_qdeclarativeecmascript::function()
3937 QDeclarativeComponent component(&engine, TEST_FILE("function.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);
3949 // Test the "Qt.include" method
3950 void tst_qdeclarativeecmascript::include()
3952 // Non-library relative include
3954 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
3955 QObject *o = component.create();
3958 QCOMPARE(o->property("test0").toInt(), 99);
3959 QCOMPARE(o->property("test1").toBool(), true);
3960 QCOMPARE(o->property("test2").toBool(), true);
3961 QCOMPARE(o->property("test2_1").toBool(), true);
3962 QCOMPARE(o->property("test3").toBool(), true);
3963 QCOMPARE(o->property("test3_1").toBool(), true);
3968 // Library relative include
3970 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
3971 QObject *o = component.create();
3974 QCOMPARE(o->property("test0").toInt(), 99);
3975 QCOMPARE(o->property("test1").toBool(), true);
3976 QCOMPARE(o->property("test2").toBool(), true);
3977 QCOMPARE(o->property("test2_1").toBool(), true);
3978 QCOMPARE(o->property("test3").toBool(), true);
3979 QCOMPARE(o->property("test3_1").toBool(), true);
3986 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
3987 QObject *o = component.create();
3990 QCOMPARE(o->property("test1").toBool(), true);
3991 QCOMPARE(o->property("test2").toBool(), true);
3992 QCOMPARE(o->property("test3").toBool(), true);
3993 QCOMPARE(o->property("test4").toBool(), true);
3994 QCOMPARE(o->property("test5").toBool(), true);
3995 QCOMPARE(o->property("test6").toBool(), true);
4000 // Including file with ".pragma library"
4002 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
4003 QObject *o = component.create();
4005 QCOMPARE(o->property("test1").toInt(), 100);
4012 TestHTTPServer server(8111);
4013 QVERIFY(server.isValid());
4014 server.serveDirectory(SRCDIR "/data");
4016 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
4017 QObject *o = component.create();
4020 QTRY_VERIFY(o->property("done").toBool() == true);
4021 QTRY_VERIFY(o->property("done2").toBool() == true);
4023 QCOMPARE(o->property("test1").toBool(), true);
4024 QCOMPARE(o->property("test2").toBool(), true);
4025 QCOMPARE(o->property("test3").toBool(), true);
4026 QCOMPARE(o->property("test4").toBool(), true);
4027 QCOMPARE(o->property("test5").toBool(), true);
4029 QCOMPARE(o->property("test6").toBool(), true);
4030 QCOMPARE(o->property("test7").toBool(), true);
4031 QCOMPARE(o->property("test8").toBool(), true);
4032 QCOMPARE(o->property("test9").toBool(), true);
4033 QCOMPARE(o->property("test10").toBool(), true);
4040 TestHTTPServer server(8111);
4041 QVERIFY(server.isValid());
4042 server.serveDirectory(SRCDIR "/data");
4044 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
4045 QObject *o = component.create();
4048 QTRY_VERIFY(o->property("done").toBool() == true);
4050 QCOMPARE(o->property("test1").toBool(), true);
4051 QCOMPARE(o->property("test2").toBool(), true);
4052 QCOMPARE(o->property("test3").toBool(), true);
4058 void tst_qdeclarativeecmascript::signalHandlers()
4060 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
4061 QObject *o = component.create();
4064 QVERIFY(o->property("count").toInt() == 0);
4065 QMetaObject::invokeMethod(o, "testSignalCall");
4066 QCOMPARE(o->property("count").toInt(), 1);
4068 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
4069 QCOMPARE(o->property("count").toInt(), 1);
4070 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
4072 QVERIFY(o->property("funcCount").toInt() == 0);
4073 QMetaObject::invokeMethod(o, "testSignalConnection");
4074 QCOMPARE(o->property("funcCount").toInt(), 1);
4076 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
4077 QCOMPARE(o->property("funcCount").toInt(), 2);
4079 QMetaObject::invokeMethod(o, "testSignalDefined");
4080 QCOMPARE(o->property("definedResult").toBool(), true);
4082 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
4083 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
4088 void tst_qdeclarativeecmascript::qtbug_10696()
4090 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
4091 QObject *o = component.create();
4096 void tst_qdeclarativeecmascript::qtbug_11606()
4098 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
4099 QObject *o = component.create();
4101 QCOMPARE(o->property("test").toBool(), true);
4105 void tst_qdeclarativeecmascript::qtbug_11600()
4107 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
4108 QObject *o = component.create();
4110 QCOMPARE(o->property("test").toBool(), true);
4114 // Reading and writing non-scriptable properties should fail
4115 void tst_qdeclarativeecmascript::nonscriptable()
4117 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
4118 QObject *o = component.create();
4120 QCOMPARE(o->property("readOk").toBool(), true);
4121 QCOMPARE(o->property("writeOk").toBool(), true);
4125 // deleteLater() should not be callable from QML
4126 void tst_qdeclarativeecmascript::deleteLater()
4128 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
4129 QObject *o = component.create();
4131 QCOMPARE(o->property("test").toBool(), true);
4135 void tst_qdeclarativeecmascript::in()
4137 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
4138 QObject *o = component.create();
4140 QCOMPARE(o->property("test1").toBool(), true);
4141 QCOMPARE(o->property("test2").toBool(), true);
4145 void tst_qdeclarativeecmascript::sharedAttachedObject()
4147 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
4148 QObject *o = component.create();
4150 QCOMPARE(o->property("test1").toBool(), true);
4151 QCOMPARE(o->property("test2").toBool(), true);
4156 void tst_qdeclarativeecmascript::objectName()
4158 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
4159 QObject *o = component.create();
4162 QCOMPARE(o->property("test1").toString(), QString("hello"));
4163 QCOMPARE(o->property("test2").toString(), QString("ell"));
4165 o->setObjectName("world");
4167 QCOMPARE(o->property("test1").toString(), QString("world"));
4168 QCOMPARE(o->property("test2").toString(), QString("orl"));
4173 void tst_qdeclarativeecmascript::writeRemovesBinding()
4175 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
4176 QObject *o = component.create();
4179 QCOMPARE(o->property("test").toBool(), true);
4184 // Test bindings assigned to alias properties actually assign to the alias' target
4185 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
4187 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4188 QObject *o = component.create();
4191 QCOMPARE(o->property("test").toBool(), true);
4196 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4197 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4200 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4201 QObject *o = component.create();
4204 QCOMPARE(o->property("test").toBool(), true);
4210 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4211 QObject *o = component.create();
4214 QCOMPARE(o->property("test").toBool(), true);
4220 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4221 QObject *o = component.create();
4224 QCOMPARE(o->property("test").toBool(), true);
4230 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4231 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4234 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4235 QObject *o = component.create();
4238 QCOMPARE(o->property("test").toBool(), true);
4244 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
4245 QObject *o = component.create();
4248 QCOMPARE(o->property("test").toBool(), true);
4254 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
4255 QObject *o = component.create();
4258 QCOMPARE(o->property("test").toBool(), true);
4264 // Allow an alais to a composite element
4266 void tst_qdeclarativeecmascript::aliasToCompositeElement()
4268 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
4270 QObject *object = component.create();
4271 QVERIFY(object != 0);
4276 void tst_qdeclarativeecmascript::revisionErrors()
4279 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
4280 QString url = component.url().toString();
4282 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4283 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
4284 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
4286 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4287 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4288 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4289 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4290 QVERIFY(object != 0);
4294 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
4295 QString url = component.url().toString();
4297 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
4298 // method2, prop2 from MyRevisionedClass not available
4299 // method4, prop4 from MyRevisionedSubclass not available
4300 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4301 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
4302 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
4303 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
4304 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
4306 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4307 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4308 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4309 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
4310 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
4311 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4312 QVERIFY(object != 0);
4316 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
4317 QString url = component.url().toString();
4319 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
4320 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
4321 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
4322 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
4323 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
4324 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4325 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4326 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4327 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4328 QVERIFY(object != 0);
4333 void tst_qdeclarativeecmascript::revision()
4336 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
4337 QString url = component.url().toString();
4339 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4340 QVERIFY(object != 0);
4344 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
4345 QString url = component.url().toString();
4347 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4348 QVERIFY(object != 0);
4352 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
4353 QString url = component.url().toString();
4355 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4356 QVERIFY(object != 0);
4359 // Test that non-root classes can resolve revisioned methods
4361 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
4363 QObject *object = component.create();
4364 QVERIFY(object != 0);
4365 QCOMPARE(object->property("test").toReal(), 11.);
4370 void tst_qdeclarativeecmascript::realToInt()
4372 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
4373 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
4374 QVERIFY(object != 0);
4376 QMetaObject::invokeMethod(object, "test1");
4377 QCOMPARE(object->value(), int(4));
4378 QMetaObject::invokeMethod(object, "test2");
4379 QCOMPARE(object->value(), int(8));
4381 void tst_qdeclarativeecmascript::dynamicString()
4383 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
4384 QObject *object = component.create();
4385 QVERIFY(object != 0);
4386 QCOMPARE(object->property("stringProperty").toString(),
4387 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
4390 void tst_qdeclarativeecmascript::automaticSemicolon()
4392 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
4393 QObject *object = component.create();
4394 QVERIFY(object != 0);
4397 QTEST_MAIN(tst_qdeclarativeecmascript)
4399 #include "tst_qdeclarativeecmascript.moc"