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 <private/qscriptdeclarativeclass_p.h>
53 #include "testtypes.h"
54 #include "testhttpserver.h"
55 #include "../../../shared/util.h"
58 // In Symbian OS test data is located in applications private dir
63 This test covers evaluation of ECMAScript expressions and bindings from within
64 QML. This does not include static QML language issues.
66 Static QML language issues are covered in qmllanguage
68 inline QUrl TEST_FILE(const QString &filename)
70 QFileInfo fileInfo(__FILE__);
71 return QUrl::fromLocalFile(fileInfo.absoluteDir().filePath("data/" + filename));
74 inline QUrl TEST_FILE(const char *filename)
76 return TEST_FILE(QLatin1String(filename));
79 class tst_qdeclarativeecmascript : public QObject
83 tst_qdeclarativeecmascript() {}
87 void assignBasicTypes();
88 void idShortcutInvalidates();
89 void boolPropertiesEvaluateAsBool();
91 void signalAssignment();
93 void basicExpressions();
94 void basicExpressions_data();
95 void arrayExpressions();
96 void contextPropertiesTriggerReeval();
97 void objectPropertiesTriggerReeval();
98 void deferredProperties();
99 void deferredPropertiesErrors();
100 void extensionObjects();
101 void overrideExtensionProperties();
102 void attachedProperties();
104 void valueTypeFunctions();
105 void constantsOverrideBindings();
106 void outerBindingOverridesInnerBinding();
107 void aliasPropertyAndBinding();
108 void nonExistentAttachedObject();
111 void signalParameterTypes();
112 void objectsCompareAsEqual();
113 void dynamicCreation_data();
114 void dynamicCreation();
115 void dynamicDestruction();
116 void objectToString();
117 void selfDeletingBinding();
118 void extendedObjectPropertyLookup();
120 void functionErrors();
121 void propertyAssignmentErrors();
122 void signalTriggeredBindings();
123 void listProperties();
124 void exceptionClearsOnReeval();
125 void exceptionSlotProducesWarning();
126 void exceptionBindingProducesWarning();
127 void transientErrors();
128 void shutdownErrors();
129 void compositePropertyType();
131 void undefinedResetsProperty();
132 void listToVariant();
133 void multiEngineObject();
134 void deletedObject();
135 void attachedPropertyScope();
136 void scriptConnect();
137 void scriptDisconnect();
139 void cppOwnershipReturnValue();
140 void ownershipCustomReturnValue();
141 void qlistqobjectMethods();
142 void strictlyEquals();
144 void numberAssignment();
145 void propertySplicing();
146 void signalWithUnknownTypes();
148 void importScripts();
149 void scarceResources();
150 void propertyChangeSlots();
151 void elementAssign();
152 void objectPassThroughSignals();
153 void booleanConversion();
157 void dynamicCreationCrash();
159 void nullObjectBinding();
160 void deletedEngine();
161 void libraryScriptAssert();
162 void variantsAssignedUndefined();
164 void qtcreatorbug_1289();
165 void noSpuriousWarningsAtShutdown();
166 void canAssignNullToQObject();
167 void functionAssignment_fromBinding();
168 void functionAssignment_fromJS();
169 void functionAssignment_fromJS_data();
170 void functionAssignmentfromJS_invalid();
176 void nonscriptable();
179 void sharedAttachedObject();
181 void writeRemovesBinding();
182 void aliasBindingsAssignCorrectly();
183 void aliasBindingsOverrideTarget();
184 void aliasWritesOverrideBindings();
189 void callQtInvokables();
190 void invokableObjectArg();
191 void invokableObjectRet();
193 void revisionErrors();
197 QDeclarativeEngine engine;
200 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
202 void tst_qdeclarativeecmascript::assignBasicTypes()
205 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
206 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
207 QVERIFY(object != 0);
208 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
209 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
210 QCOMPARE(object->stringProperty(), QString("Hello World!"));
211 QCOMPARE(object->uintProperty(), uint(10));
212 QCOMPARE(object->intProperty(), -19);
213 QCOMPARE((float)object->realProperty(), float(23.2));
214 QCOMPARE((float)object->doubleProperty(), float(-19.75));
215 QCOMPARE((float)object->floatProperty(), float(8.5));
216 QCOMPARE(object->colorProperty(), QColor("red"));
217 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
218 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
219 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
220 QCOMPARE(object->pointProperty(), QPoint(99,13));
221 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
222 QCOMPARE(object->sizeProperty(), QSize(99, 13));
223 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
224 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
225 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
226 QCOMPARE(object->boolProperty(), true);
227 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
228 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
229 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
233 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
234 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
235 QVERIFY(object != 0);
236 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
237 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
238 QCOMPARE(object->stringProperty(), QString("Hello World!"));
239 QCOMPARE(object->uintProperty(), uint(10));
240 QCOMPARE(object->intProperty(), -19);
241 QCOMPARE((float)object->realProperty(), float(23.2));
242 QCOMPARE((float)object->doubleProperty(), float(-19.75));
243 QCOMPARE((float)object->floatProperty(), float(8.5));
244 QCOMPARE(object->colorProperty(), QColor("red"));
245 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
246 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
247 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
248 QCOMPARE(object->pointProperty(), QPoint(99,13));
249 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
250 QCOMPARE(object->sizeProperty(), QSize(99, 13));
251 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
252 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
253 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
254 QCOMPARE(object->boolProperty(), true);
255 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
256 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
257 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
262 void tst_qdeclarativeecmascript::idShortcutInvalidates()
265 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
266 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
267 QVERIFY(object != 0);
268 QVERIFY(object->objectProperty() != 0);
269 delete object->objectProperty();
270 QVERIFY(object->objectProperty() == 0);
275 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
276 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
277 QVERIFY(object != 0);
278 QVERIFY(object->objectProperty() != 0);
279 delete object->objectProperty();
280 QVERIFY(object->objectProperty() == 0);
285 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
288 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
289 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
290 QVERIFY(object != 0);
291 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
295 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
296 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
297 QVERIFY(object != 0);
298 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
303 void tst_qdeclarativeecmascript::signalAssignment()
306 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
307 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
308 QVERIFY(object != 0);
309 QCOMPARE(object->string(), QString());
310 emit object->basicSignal();
311 QCOMPARE(object->string(), QString("pass"));
316 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
317 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
318 QVERIFY(object != 0);
319 QCOMPARE(object->string(), QString());
320 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
321 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
326 void tst_qdeclarativeecmascript::methods()
329 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
330 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
331 QVERIFY(object != 0);
332 QCOMPARE(object->methodCalled(), false);
333 QCOMPARE(object->methodIntCalled(), false);
334 emit object->basicSignal();
335 QCOMPARE(object->methodCalled(), true);
336 QCOMPARE(object->methodIntCalled(), false);
341 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
342 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
343 QVERIFY(object != 0);
344 QCOMPARE(object->methodCalled(), false);
345 QCOMPARE(object->methodIntCalled(), false);
346 emit object->basicSignal();
347 QCOMPARE(object->methodCalled(), false);
348 QCOMPARE(object->methodIntCalled(), true);
353 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
354 QObject *object = component.create();
355 QVERIFY(object != 0);
356 QCOMPARE(object->property("test").toInt(), 19);
361 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
362 QObject *object = component.create();
363 QVERIFY(object != 0);
364 QCOMPARE(object->property("test").toInt(), 19);
365 QCOMPARE(object->property("test2").toInt(), 17);
366 QCOMPARE(object->property("test3").toInt(), 16);
371 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
372 QObject *object = component.create();
373 QVERIFY(object != 0);
374 QCOMPARE(object->property("test").toInt(), 9);
379 void tst_qdeclarativeecmascript::bindingLoop()
381 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
382 QString warning = component.url().toString() + ":9:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
383 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
384 QObject *object = component.create();
385 QVERIFY(object != 0);
389 void tst_qdeclarativeecmascript::basicExpressions_data()
391 QTest::addColumn<QString>("expression");
392 QTest::addColumn<QVariant>("result");
393 QTest::addColumn<bool>("nest");
395 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
396 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
397 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
398 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
399 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
400 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
401 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
402 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
403 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
404 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
405 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
406 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
407 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
408 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
409 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
410 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
411 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
412 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
413 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
416 void tst_qdeclarativeecmascript::basicExpressions()
418 QFETCH(QString, expression);
419 QFETCH(QVariant, result);
425 MyDefaultObject1 default1;
426 MyDefaultObject3 default3;
427 object1.setStringProperty("Object1");
428 object2.setStringProperty("Object2");
429 object3.setStringProperty("Object3");
431 QDeclarativeContext context(engine.rootContext());
432 QDeclarativeContext nestedContext(&context);
434 context.setContextObject(&default1);
435 context.setContextProperty("a", QVariant(1944));
436 context.setContextProperty("b", QVariant("Milk"));
437 context.setContextProperty("object", &object1);
438 context.setContextProperty("objectOverride", &object2);
439 nestedContext.setContextObject(&default3);
440 nestedContext.setContextProperty("b", QVariant("Cow"));
441 nestedContext.setContextProperty("objectOverride", &object3);
442 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
444 MyExpression expr(nest?&nestedContext:&context, expression);
445 QCOMPARE(expr.evaluate(), result);
448 void tst_qdeclarativeecmascript::arrayExpressions()
454 QDeclarativeContext context(engine.rootContext());
455 context.setContextProperty("a", &obj1);
456 context.setContextProperty("b", &obj2);
457 context.setContextProperty("c", &obj3);
459 MyExpression expr(&context, "[a, b, c, 10]");
460 QVariant result = expr.evaluate();
461 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
462 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
463 QCOMPARE(list.count(), 4);
464 QCOMPARE(list.at(0), &obj1);
465 QCOMPARE(list.at(1), &obj2);
466 QCOMPARE(list.at(2), &obj3);
467 QCOMPARE(list.at(3), (QObject *)0);
470 // Tests that modifying a context property will reevaluate expressions
471 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
473 QDeclarativeContext context(engine.rootContext());
476 MyQmlObject *object3 = new MyQmlObject;
478 object1.setStringProperty("Hello");
479 object2.setStringProperty("World");
481 context.setContextProperty("testProp", QVariant(1));
482 context.setContextProperty("testObj", &object1);
483 context.setContextProperty("testObj2", object3);
486 MyExpression expr(&context, "testProp + 1");
487 QCOMPARE(expr.changed, false);
488 QCOMPARE(expr.evaluate(), QVariant(2));
490 context.setContextProperty("testProp", QVariant(2));
491 QCOMPARE(expr.changed, true);
492 QCOMPARE(expr.evaluate(), QVariant(3));
496 MyExpression expr(&context, "testProp + testProp + testProp");
497 QCOMPARE(expr.changed, false);
498 QCOMPARE(expr.evaluate(), QVariant(6));
500 context.setContextProperty("testProp", QVariant(4));
501 QCOMPARE(expr.changed, true);
502 QCOMPARE(expr.evaluate(), QVariant(12));
506 MyExpression expr(&context, "testObj.stringProperty");
507 QCOMPARE(expr.changed, false);
508 QCOMPARE(expr.evaluate(), QVariant("Hello"));
510 context.setContextProperty("testObj", &object2);
511 QCOMPARE(expr.changed, true);
512 QCOMPARE(expr.evaluate(), QVariant("World"));
516 MyExpression expr(&context, "testObj.stringProperty /**/");
517 QCOMPARE(expr.changed, false);
518 QCOMPARE(expr.evaluate(), QVariant("World"));
520 context.setContextProperty("testObj", &object1);
521 QCOMPARE(expr.changed, true);
522 QCOMPARE(expr.evaluate(), QVariant("Hello"));
526 MyExpression expr(&context, "testObj2");
527 QCOMPARE(expr.changed, false);
528 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
534 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
536 QDeclarativeContext context(engine.rootContext());
540 context.setContextProperty("testObj", &object1);
542 object1.setStringProperty(QLatin1String("Hello"));
543 object2.setStringProperty(QLatin1String("Dog"));
544 object3.setStringProperty(QLatin1String("Cat"));
547 MyExpression expr(&context, "testObj.stringProperty");
548 QCOMPARE(expr.changed, false);
549 QCOMPARE(expr.evaluate(), QVariant("Hello"));
551 object1.setStringProperty(QLatin1String("World"));
552 QCOMPARE(expr.changed, true);
553 QCOMPARE(expr.evaluate(), QVariant("World"));
557 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
558 QCOMPARE(expr.changed, false);
559 QCOMPARE(expr.evaluate(), QVariant());
561 object1.setObjectProperty(&object2);
562 QCOMPARE(expr.changed, true);
563 expr.changed = false;
564 QCOMPARE(expr.evaluate(), QVariant("Dog"));
566 object1.setObjectProperty(&object3);
567 QCOMPARE(expr.changed, true);
568 expr.changed = false;
569 QCOMPARE(expr.evaluate(), QVariant("Cat"));
571 object1.setObjectProperty(0);
572 QCOMPARE(expr.changed, true);
573 expr.changed = false;
574 QCOMPARE(expr.evaluate(), QVariant());
576 object1.setObjectProperty(&object3);
577 QCOMPARE(expr.changed, true);
578 expr.changed = false;
579 QCOMPARE(expr.evaluate(), QVariant("Cat"));
581 object3.setStringProperty("Donkey");
582 QCOMPARE(expr.changed, true);
583 expr.changed = false;
584 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
588 void tst_qdeclarativeecmascript::deferredProperties()
590 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
591 MyDeferredObject *object =
592 qobject_cast<MyDeferredObject *>(component.create());
593 QVERIFY(object != 0);
594 QCOMPARE(object->value(), 0);
595 QVERIFY(object->objectProperty() == 0);
596 QVERIFY(object->objectProperty2() != 0);
597 qmlExecuteDeferred(object);
598 QCOMPARE(object->value(), 10);
599 QVERIFY(object->objectProperty() != 0);
600 MyQmlObject *qmlObject =
601 qobject_cast<MyQmlObject *>(object->objectProperty());
602 QVERIFY(qmlObject != 0);
603 QCOMPARE(qmlObject->value(), 10);
604 object->setValue(19);
605 QCOMPARE(qmlObject->value(), 19);
610 // Check errors on deferred properties are correctly emitted
611 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
613 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
614 MyDeferredObject *object =
615 qobject_cast<MyDeferredObject *>(component.create());
616 QVERIFY(object != 0);
617 QCOMPARE(object->value(), 0);
618 QVERIFY(object->objectProperty() == 0);
619 QVERIFY(object->objectProperty2() == 0);
621 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject* objectProperty";
622 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
624 qmlExecuteDeferred(object);
629 void tst_qdeclarativeecmascript::extensionObjects()
631 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
632 MyExtendedObject *object =
633 qobject_cast<MyExtendedObject *>(component.create());
634 QVERIFY(object != 0);
635 QCOMPARE(object->baseProperty(), 13);
636 QCOMPARE(object->coreProperty(), 9);
637 object->setProperty("extendedProperty", QVariant(11));
638 object->setProperty("baseExtendedProperty", QVariant(92));
639 QCOMPARE(object->coreProperty(), 11);
640 QCOMPARE(object->baseProperty(), 92);
642 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
644 QCOMPARE(nested->baseProperty(), 13);
645 QCOMPARE(nested->coreProperty(), 9);
646 nested->setProperty("extendedProperty", QVariant(11));
647 nested->setProperty("baseExtendedProperty", QVariant(92));
648 QCOMPARE(nested->coreProperty(), 11);
649 QCOMPARE(nested->baseProperty(), 92);
654 void tst_qdeclarativeecmascript::overrideExtensionProperties()
656 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
657 OverrideDefaultPropertyObject *object =
658 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
659 QVERIFY(object != 0);
660 QVERIFY(object->secondProperty() != 0);
661 QVERIFY(object->firstProperty() == 0);
666 void tst_qdeclarativeecmascript::attachedProperties()
669 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
670 QObject *object = component.create();
671 QVERIFY(object != 0);
672 QCOMPARE(object->property("a").toInt(), 19);
673 QCOMPARE(object->property("b").toInt(), 19);
674 QCOMPARE(object->property("c").toInt(), 19);
675 QCOMPARE(object->property("d").toInt(), 19);
680 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
681 QObject *object = component.create();
682 QVERIFY(object != 0);
683 QCOMPARE(object->property("a").toInt(), 26);
684 QCOMPARE(object->property("b").toInt(), 26);
685 QCOMPARE(object->property("c").toInt(), 26);
686 QCOMPARE(object->property("d").toInt(), 26);
690 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
691 QObject *object = component.create();
692 QVERIFY(object != 0);
694 QMetaObject::invokeMethod(object, "writeValue2");
696 MyQmlAttachedObject *attached =
697 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
698 QVERIFY(attached != 0);
700 QCOMPARE(attached->value2(), 9);
705 void tst_qdeclarativeecmascript::enums()
709 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
710 QObject *object = component.create();
711 QVERIFY(object != 0);
713 QCOMPARE(object->property("a").toInt(), 0);
714 QCOMPARE(object->property("b").toInt(), 1);
715 QCOMPARE(object->property("c").toInt(), 2);
716 QCOMPARE(object->property("d").toInt(), 3);
717 QCOMPARE(object->property("e").toInt(), 0);
718 QCOMPARE(object->property("f").toInt(), 1);
719 QCOMPARE(object->property("g").toInt(), 2);
720 QCOMPARE(object->property("h").toInt(), 3);
721 QCOMPARE(object->property("i").toInt(), 19);
722 QCOMPARE(object->property("j").toInt(), 19);
726 // Non-existent enums
728 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
730 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int a";
731 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int b";
732 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
733 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
735 QObject *object = component.create();
736 QVERIFY(object != 0);
737 QCOMPARE(object->property("a").toInt(), 0);
738 QCOMPARE(object->property("b").toInt(), 0);
744 void tst_qdeclarativeecmascript::valueTypeFunctions()
746 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
747 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
749 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
750 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
756 Tests that writing a constant to a property with a binding on it disables the
759 void tst_qdeclarativeecmascript::constantsOverrideBindings()
763 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
764 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
765 QVERIFY(object != 0);
767 QCOMPARE(object->property("c2").toInt(), 0);
768 object->setProperty("c1", QVariant(9));
769 QCOMPARE(object->property("c2").toInt(), 9);
771 emit object->basicSignal();
773 QCOMPARE(object->property("c2").toInt(), 13);
774 object->setProperty("c1", QVariant(8));
775 QCOMPARE(object->property("c2").toInt(), 13);
780 // During construction
782 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
783 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
784 QVERIFY(object != 0);
786 QCOMPARE(object->property("c1").toInt(), 0);
787 QCOMPARE(object->property("c2").toInt(), 10);
788 object->setProperty("c1", QVariant(9));
789 QCOMPARE(object->property("c1").toInt(), 9);
790 QCOMPARE(object->property("c2").toInt(), 10);
798 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
799 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
800 QVERIFY(object != 0);
802 QCOMPARE(object->property("c2").toInt(), 0);
803 object->setProperty("c1", QVariant(9));
804 QCOMPARE(object->property("c2").toInt(), 9);
806 object->setProperty("c2", QVariant(13));
807 QCOMPARE(object->property("c2").toInt(), 13);
808 object->setProperty("c1", QVariant(7));
809 QCOMPARE(object->property("c1").toInt(), 7);
810 QCOMPARE(object->property("c2").toInt(), 13);
818 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
819 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
820 QVERIFY(object != 0);
822 QCOMPARE(object->property("c1").toInt(), 0);
823 QCOMPARE(object->property("c3").toInt(), 10);
824 object->setProperty("c1", QVariant(9));
825 QCOMPARE(object->property("c1").toInt(), 9);
826 QCOMPARE(object->property("c3").toInt(), 10);
833 Tests that assigning a binding to a property that already has a binding causes
834 the original binding to be disabled.
836 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
838 QDeclarativeComponent component(&engine,
839 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
840 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
841 QVERIFY(object != 0);
843 QCOMPARE(object->property("c1").toInt(), 0);
844 QCOMPARE(object->property("c2").toInt(), 0);
845 QCOMPARE(object->property("c3").toInt(), 0);
847 object->setProperty("c1", QVariant(9));
848 QCOMPARE(object->property("c1").toInt(), 9);
849 QCOMPARE(object->property("c2").toInt(), 0);
850 QCOMPARE(object->property("c3").toInt(), 0);
852 object->setProperty("c3", QVariant(8));
853 QCOMPARE(object->property("c1").toInt(), 9);
854 QCOMPARE(object->property("c2").toInt(), 8);
855 QCOMPARE(object->property("c3").toInt(), 8);
861 Access a non-existent attached object.
863 Tests for a regression where this used to crash.
865 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
867 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
869 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString stringProperty";
870 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
872 QObject *object = component.create();
873 QVERIFY(object != 0);
878 void tst_qdeclarativeecmascript::scope()
881 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
882 QObject *object = component.create();
883 QVERIFY(object != 0);
885 QCOMPARE(object->property("test1").toInt(), 1);
886 QCOMPARE(object->property("test2").toInt(), 2);
887 QCOMPARE(object->property("test3").toString(), QString("1Test"));
888 QCOMPARE(object->property("test4").toString(), QString("2Test"));
889 QCOMPARE(object->property("test5").toInt(), 1);
890 QCOMPARE(object->property("test6").toInt(), 1);
891 QCOMPARE(object->property("test7").toInt(), 2);
892 QCOMPARE(object->property("test8").toInt(), 2);
893 QCOMPARE(object->property("test9").toInt(), 1);
894 QCOMPARE(object->property("test10").toInt(), 3);
900 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
901 QObject *object = component.create();
902 QVERIFY(object != 0);
904 QCOMPARE(object->property("test1").toInt(), 19);
905 QCOMPARE(object->property("test2").toInt(), 19);
906 QCOMPARE(object->property("test3").toInt(), 14);
907 QCOMPARE(object->property("test4").toInt(), 14);
908 QCOMPARE(object->property("test5").toInt(), 24);
909 QCOMPARE(object->property("test6").toInt(), 24);
915 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
916 QObject *object = component.create();
917 QVERIFY(object != 0);
919 QCOMPARE(object->property("test1").toBool(), true);
920 QCOMPARE(object->property("test2").toBool(), true);
921 QCOMPARE(object->property("test3").toBool(), true);
926 // Signal argument scope
928 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
929 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
930 QVERIFY(object != 0);
932 QCOMPARE(object->property("test").toInt(), 0);
933 QCOMPARE(object->property("test2").toString(), QString());
935 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
937 QCOMPARE(object->property("test").toInt(), 13);
938 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
944 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
945 QObject *object = component.create();
946 QVERIFY(object != 0);
948 QCOMPARE(object->property("test1").toBool(), true);
949 QCOMPARE(object->property("test2").toBool(), true);
955 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
956 QObject *object = component.create();
957 QVERIFY(object != 0);
959 QCOMPARE(object->property("test").toBool(), true);
965 // In 4.7, non-library javascript files that had no imports shared the imports of their
967 void tst_qdeclarativeecmascript::importScope()
969 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
970 QObject *o = component.create();
973 QCOMPARE(o->property("test").toInt(), 240);
979 Tests that "any" type passes through a synthesized signal parameter. This
980 is essentially a test of QDeclarativeMetaType::copy()
982 void tst_qdeclarativeecmascript::signalParameterTypes()
984 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
985 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
986 QVERIFY(object != 0);
988 emit object->basicSignal();
990 QCOMPARE(object->property("intProperty").toInt(), 10);
991 QCOMPARE(object->property("realProperty").toReal(), 19.2);
992 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
993 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
994 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
995 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1001 Test that two JS objects for the same QObject compare as equal.
1003 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1005 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1006 QObject *object = component.create();
1007 QVERIFY(object != 0);
1009 QCOMPARE(object->property("test1").toBool(), true);
1010 QCOMPARE(object->property("test2").toBool(), true);
1011 QCOMPARE(object->property("test3").toBool(), true);
1012 QCOMPARE(object->property("test4").toBool(), true);
1013 QCOMPARE(object->property("test5").toBool(), true);
1019 Confirm bindings and alias properties can coexist.
1021 Tests for a regression where the binding would not reevaluate.
1023 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1025 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1026 QObject *object = component.create();
1027 QVERIFY(object != 0);
1029 QCOMPARE(object->property("c2").toInt(), 3);
1030 QCOMPARE(object->property("c3").toInt(), 3);
1032 object->setProperty("c2", QVariant(19));
1034 QCOMPARE(object->property("c2").toInt(), 19);
1035 QCOMPARE(object->property("c3").toInt(), 19);
1040 void tst_qdeclarativeecmascript::dynamicCreation_data()
1042 QTest::addColumn<QString>("method");
1043 QTest::addColumn<QString>("createdName");
1045 QTest::newRow("One") << "createOne" << "objectOne";
1046 QTest::newRow("Two") << "createTwo" << "objectTwo";
1047 QTest::newRow("Three") << "createThree" << "objectThree";
1051 Test using createQmlObject to dynamically generate an item
1052 Also using createComponent is tested.
1054 void tst_qdeclarativeecmascript::dynamicCreation()
1056 QFETCH(QString, method);
1057 QFETCH(QString, createdName);
1059 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1060 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1061 QVERIFY(object != 0);
1063 QMetaObject::invokeMethod(object, method.toUtf8());
1064 QObject *created = object->objectProperty();
1066 QCOMPARE(created->objectName(), createdName);
1072 Tests the destroy function
1074 void tst_qdeclarativeecmascript::dynamicDestruction()
1076 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1077 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1078 QVERIFY(object != 0);
1079 QDeclarativeGuard<QObject> createdQmlObject = 0;
1081 QMetaObject::invokeMethod(object, "create");
1082 createdQmlObject = object->objectProperty();
1083 QVERIFY(createdQmlObject);
1084 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1086 QMetaObject::invokeMethod(object, "killOther");
1087 QVERIFY(createdQmlObject);
1088 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1089 QVERIFY(createdQmlObject);
1090 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1091 if (createdQmlObject) {
1093 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1096 QVERIFY(!createdQmlObject);
1098 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1099 QMetaObject::invokeMethod(object, "killMe");
1102 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1107 tests that id.toString() works
1109 void tst_qdeclarativeecmascript::objectToString()
1111 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1112 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1113 QVERIFY(object != 0);
1114 QMetaObject::invokeMethod(object, "testToString");
1115 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1116 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1122 Tests bindings that indirectly cause their own deletion work.
1124 This test is best run under valgrind to ensure no invalid memory access occur.
1126 void tst_qdeclarativeecmascript::selfDeletingBinding()
1129 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1130 QObject *object = component.create();
1131 QVERIFY(object != 0);
1132 object->setProperty("triggerDelete", true);
1137 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1138 QObject *object = component.create();
1139 QVERIFY(object != 0);
1140 object->setProperty("triggerDelete", true);
1146 Test that extended object properties can be accessed.
1148 This test a regression where this used to crash. The issue was specificially
1149 for extended objects that did not include a synthesized meta object (so non-root
1150 and no synthesiszed properties).
1152 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1154 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1155 QObject *object = component.create();
1156 QVERIFY(object != 0);
1161 Test file/lineNumbers for binding/Script errors.
1163 void tst_qdeclarativeecmascript::scriptErrors()
1165 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1166 QString url = component.url().toString();
1168 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1169 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1170 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1171 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1172 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1173 QString warning6 = url + ":7: Unable to assign [undefined] to int x";
1174 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1175 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1177 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1178 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1179 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1180 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1181 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1182 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1183 QVERIFY(object != 0);
1185 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1186 emit object->basicSignal();
1188 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1189 emit object->anotherBasicSignal();
1191 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1192 emit object->thirdBasicSignal();
1198 Test file/lineNumbers for inline functions.
1200 void tst_qdeclarativeecmascript::functionErrors()
1202 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1203 QString url = component.url().toString();
1205 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1207 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1209 QObject *object = component.create();
1210 QVERIFY(object != 0);
1213 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1214 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1215 url = componentTwo.url().toString();
1216 object = componentTwo.create();
1217 QVERIFY(object != 0);
1219 QString srpname = object->property("srp_name").toString();
1221 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1222 QLatin1String(" is not a function");
1223 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1224 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1229 Test various errors that can occur when assigning a property from script
1231 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1233 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1235 QString url = component.url().toString();
1237 QObject *object = component.create();
1238 QVERIFY(object != 0);
1240 QCOMPARE(object->property("test1").toBool(), true);
1241 QCOMPARE(object->property("test2").toBool(), true);
1247 Test bindings still work when the reeval is triggered from within
1250 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1252 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1253 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1254 QVERIFY(object != 0);
1256 QCOMPARE(object->property("base").toReal(), 50.);
1257 QCOMPARE(object->property("test1").toReal(), 50.);
1258 QCOMPARE(object->property("test2").toReal(), 50.);
1260 object->basicSignal();
1262 QCOMPARE(object->property("base").toReal(), 200.);
1263 QCOMPARE(object->property("test1").toReal(), 200.);
1264 QCOMPARE(object->property("test2").toReal(), 200.);
1266 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1268 QCOMPARE(object->property("base").toReal(), 400.);
1269 QCOMPARE(object->property("test1").toReal(), 400.);
1270 QCOMPARE(object->property("test2").toReal(), 400.);
1276 Test that list properties can be iterated from ECMAScript
1278 void tst_qdeclarativeecmascript::listProperties()
1280 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1281 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1282 QVERIFY(object != 0);
1284 QCOMPARE(object->property("test1").toInt(), 21);
1285 QCOMPARE(object->property("test2").toInt(), 2);
1286 QCOMPARE(object->property("test3").toBool(), true);
1287 QCOMPARE(object->property("test4").toBool(), true);
1292 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1294 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1295 QString url = component.url().toString();
1297 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1299 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1300 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1301 QVERIFY(object != 0);
1303 QCOMPARE(object->property("test").toBool(), false);
1305 MyQmlObject object2;
1306 MyQmlObject object3;
1307 object2.setObjectProperty(&object3);
1308 object->setObjectProperty(&object2);
1310 QCOMPARE(object->property("test").toBool(), true);
1315 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1317 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1318 QString url = component.url().toString();
1320 QString warning = component.url().toString() + ":6: Error: JS exception";
1322 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1323 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1324 QVERIFY(object != 0);
1328 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1330 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1331 QString url = component.url().toString();
1333 QString warning = component.url().toString() + ":5: Error: JS exception";
1335 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1336 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1337 QVERIFY(object != 0);
1341 static int transientErrorsMsgCount = 0;
1342 static void transientErrorsMsgHandler(QtMsgType, const char *)
1344 ++transientErrorsMsgCount;
1347 // Check that transient binding errors are not displayed
1348 void tst_qdeclarativeecmascript::transientErrors()
1351 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1353 transientErrorsMsgCount = 0;
1354 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1356 QObject *object = component.create();
1357 QVERIFY(object != 0);
1359 qInstallMsgHandler(old);
1361 QCOMPARE(transientErrorsMsgCount, 0);
1366 // One binding erroring multiple times, but then resolving
1368 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1370 transientErrorsMsgCount = 0;
1371 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1373 QObject *object = component.create();
1374 QVERIFY(object != 0);
1376 qInstallMsgHandler(old);
1378 QCOMPARE(transientErrorsMsgCount, 0);
1384 // Check that errors during shutdown are minimized
1385 void tst_qdeclarativeecmascript::shutdownErrors()
1387 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1388 QObject *object = component.create();
1389 QVERIFY(object != 0);
1391 transientErrorsMsgCount = 0;
1392 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1396 qInstallMsgHandler(old);
1397 QCOMPARE(transientErrorsMsgCount, 0);
1400 void tst_qdeclarativeecmascript::compositePropertyType()
1402 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1403 QTest::ignoreMessage(QtDebugMsg, "hello world");
1404 QObject *object = qobject_cast<QObject *>(component.create());
1409 void tst_qdeclarativeecmascript::jsObject()
1411 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1412 QObject *object = component.create();
1413 QVERIFY(object != 0);
1415 QCOMPARE(object->property("test").toInt(), 92);
1420 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1423 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1424 QObject *object = component.create();
1425 QVERIFY(object != 0);
1427 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1429 object->setProperty("setUndefined", true);
1431 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1433 object->setProperty("setUndefined", false);
1435 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1440 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1441 QObject *object = component.create();
1442 QVERIFY(object != 0);
1444 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1446 QMetaObject::invokeMethod(object, "doReset");
1448 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1455 void tst_qdeclarativeecmascript::bug1()
1457 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1458 QObject *object = component.create();
1459 QVERIFY(object != 0);
1461 QCOMPARE(object->property("test").toInt(), 14);
1463 object->setProperty("a", 11);
1465 QCOMPARE(object->property("test").toInt(), 3);
1467 object->setProperty("b", true);
1469 QCOMPARE(object->property("test").toInt(), 9);
1474 void tst_qdeclarativeecmascript::bug2()
1476 QDeclarativeComponent component(&engine);
1477 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1479 QObject *object = component.create();
1480 QVERIFY(object != 0);
1485 // Don't crash in createObject when the component has errors.
1486 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1488 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1489 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1490 QVERIFY(object != 0);
1492 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1493 QMetaObject::invokeMethod(object, "dontCrash");
1494 QObject *created = object->objectProperty();
1495 QVERIFY(created == 0);
1501 void tst_qdeclarativeecmascript::regExpBug()
1503 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1504 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1505 QVERIFY(object != 0);
1506 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1510 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1512 QString functionSource = QLatin1String("(function(object) { return ") +
1513 QLatin1String(source) + QLatin1String(" })");
1515 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1518 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1519 if (function.IsEmpty())
1521 v8::Handle<v8::Value> args[] = { o };
1522 function->Call(engine->global(), 1, args);
1523 return tc.HasCaught();
1526 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1527 const char *source, v8::Handle<v8::Value> result)
1529 QString functionSource = QLatin1String("(function(object) { return ") +
1530 QLatin1String(source) + QLatin1String(" })");
1532 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1535 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1536 if (function.IsEmpty())
1538 v8::Handle<v8::Value> args[] = { o };
1540 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1545 return value->StrictEquals(result);
1548 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1551 QString functionSource = QLatin1String("(function(object) { return ") +
1552 QLatin1String(source) + QLatin1String(" })");
1554 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1556 return v8::Handle<v8::Value>();
1557 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1558 if (function.IsEmpty())
1559 return v8::Handle<v8::Value>();
1560 v8::Handle<v8::Value> args[] = { o };
1562 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1565 return v8::Handle<v8::Value>();
1569 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1570 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1571 #define EVALUATE(source) evaluate(engine, object, source)
1573 void tst_qdeclarativeecmascript::callQtInvokables()
1575 MyInvokableObject o;
1577 QDeclarativeEngine qmlengine;
1578 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1580 QV8Engine *engine = &ep->v8engine;
1582 v8::HandleScope handle_scope;
1583 v8::Context::Scope scope(engine->context());
1585 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1587 // Non-existent methods
1589 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1590 QCOMPARE(o.error(), false);
1591 QCOMPARE(o.invoked(), -1);
1592 QCOMPARE(o.actuals().count(), 0);
1595 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1596 QCOMPARE(o.error(), false);
1597 QCOMPARE(o.invoked(), -1);
1598 QCOMPARE(o.actuals().count(), 0);
1600 // Insufficient arguments
1602 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1603 QCOMPARE(o.error(), false);
1604 QCOMPARE(o.invoked(), -1);
1605 QCOMPARE(o.actuals().count(), 0);
1608 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1609 QCOMPARE(o.error(), false);
1610 QCOMPARE(o.invoked(), -1);
1611 QCOMPARE(o.actuals().count(), 0);
1613 // Excessive arguments
1615 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1616 QCOMPARE(o.error(), false);
1617 QCOMPARE(o.invoked(), 8);
1618 QCOMPARE(o.actuals().count(), 1);
1619 QCOMPARE(o.actuals().at(0), QVariant(10));
1622 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1623 QCOMPARE(o.error(), false);
1624 QCOMPARE(o.invoked(), 9);
1625 QCOMPARE(o.actuals().count(), 2);
1626 QCOMPARE(o.actuals().at(0), QVariant(10));
1627 QCOMPARE(o.actuals().at(1), QVariant(11));
1629 // Test return types
1631 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1632 QCOMPARE(o.error(), false);
1633 QCOMPARE(o.invoked(), 0);
1634 QCOMPARE(o.actuals().count(), 0);
1637 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1638 QCOMPARE(o.error(), false);
1639 QCOMPARE(o.invoked(), 1);
1640 QCOMPARE(o.actuals().count(), 0);
1643 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1644 QCOMPARE(o.error(), false);
1645 QCOMPARE(o.invoked(), 2);
1646 QCOMPARE(o.actuals().count(), 0);
1650 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1651 QVERIFY(!ret.IsEmpty());
1652 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1653 QCOMPARE(o.error(), false);
1654 QCOMPARE(o.invoked(), 3);
1655 QCOMPARE(o.actuals().count(), 0);
1660 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1661 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1662 QCOMPARE(o.error(), false);
1663 QCOMPARE(o.invoked(), 4);
1664 QCOMPARE(o.actuals().count(), 0);
1668 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1669 QCOMPARE(o.error(), false);
1670 QCOMPARE(o.invoked(), 5);
1671 QCOMPARE(o.actuals().count(), 0);
1673 // XXX enable once qml/qtscript integration is implemented
1677 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1678 QVERIFY(ret->IsString());
1679 QCOMPARE(engine->toString(ret), QString("Hello world"));
1680 QCOMPARE(o.error(), false);
1681 QCOMPARE(o.invoked(), 6);
1682 QCOMPARE(o.actuals().count(), 0);
1687 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1688 QCOMPARE(o.error(), false);
1689 QCOMPARE(o.invoked(), 7);
1690 QCOMPARE(o.actuals().count(), 0);
1694 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1695 QCOMPARE(o.error(), false);
1696 QCOMPARE(o.invoked(), 8);
1697 QCOMPARE(o.actuals().count(), 1);
1698 QCOMPARE(o.actuals().at(0), QVariant(94));
1701 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1702 QCOMPARE(o.error(), false);
1703 QCOMPARE(o.invoked(), 8);
1704 QCOMPARE(o.actuals().count(), 1);
1705 QCOMPARE(o.actuals().at(0), QVariant(94));
1708 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1709 QCOMPARE(o.error(), false);
1710 QCOMPARE(o.invoked(), 8);
1711 QCOMPARE(o.actuals().count(), 1);
1712 QCOMPARE(o.actuals().at(0), QVariant(0));
1715 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1716 QCOMPARE(o.error(), false);
1717 QCOMPARE(o.invoked(), 8);
1718 QCOMPARE(o.actuals().count(), 1);
1719 QCOMPARE(o.actuals().at(0), QVariant(0));
1722 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1723 QCOMPARE(o.error(), false);
1724 QCOMPARE(o.invoked(), 8);
1725 QCOMPARE(o.actuals().count(), 1);
1726 QCOMPARE(o.actuals().at(0), QVariant(0));
1729 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1730 QCOMPARE(o.error(), false);
1731 QCOMPARE(o.invoked(), 8);
1732 QCOMPARE(o.actuals().count(), 1);
1733 QCOMPARE(o.actuals().at(0), QVariant(0));
1736 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1737 QCOMPARE(o.error(), false);
1738 QCOMPARE(o.invoked(), 9);
1739 QCOMPARE(o.actuals().count(), 2);
1740 QCOMPARE(o.actuals().at(0), QVariant(122));
1741 QCOMPARE(o.actuals().at(1), QVariant(9));
1744 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1745 QCOMPARE(o.error(), false);
1746 QCOMPARE(o.invoked(), 10);
1747 QCOMPARE(o.actuals().count(), 1);
1748 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1751 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1752 QCOMPARE(o.error(), false);
1753 QCOMPARE(o.invoked(), 10);
1754 QCOMPARE(o.actuals().count(), 1);
1755 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1758 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1759 QCOMPARE(o.error(), false);
1760 QCOMPARE(o.invoked(), 10);
1761 QCOMPARE(o.actuals().count(), 1);
1762 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1765 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1766 QCOMPARE(o.error(), false);
1767 QCOMPARE(o.invoked(), 10);
1768 QCOMPARE(o.actuals().count(), 1);
1769 QCOMPARE(o.actuals().at(0), QVariant(0));
1772 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1773 QCOMPARE(o.error(), false);
1774 QCOMPARE(o.invoked(), 10);
1775 QCOMPARE(o.actuals().count(), 1);
1776 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1779 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
1780 QCOMPARE(o.error(), false);
1781 QCOMPARE(o.invoked(), 10);
1782 QCOMPARE(o.actuals().count(), 1);
1783 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1786 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
1787 QCOMPARE(o.error(), false);
1788 QCOMPARE(o.invoked(), 11);
1789 QCOMPARE(o.actuals().count(), 1);
1790 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
1793 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
1794 QCOMPARE(o.error(), false);
1795 QCOMPARE(o.invoked(), 11);
1796 QCOMPARE(o.actuals().count(), 1);
1797 QCOMPARE(o.actuals().at(0), QVariant("19"));
1801 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
1802 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
1803 QCOMPARE(o.error(), false);
1804 QCOMPARE(o.invoked(), 11);
1805 QCOMPARE(o.actuals().count(), 1);
1806 QCOMPARE(o.actuals().at(0), QVariant(expected));
1810 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
1811 QCOMPARE(o.error(), false);
1812 QCOMPARE(o.invoked(), 11);
1813 QCOMPARE(o.actuals().count(), 1);
1814 QCOMPARE(o.actuals().at(0), QVariant(QString()));
1817 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
1818 QCOMPARE(o.error(), false);
1819 QCOMPARE(o.invoked(), 11);
1820 QCOMPARE(o.actuals().count(), 1);
1821 QCOMPARE(o.actuals().at(0), QVariant(QString()));
1824 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
1825 QCOMPARE(o.error(), false);
1826 QCOMPARE(o.invoked(), 12);
1827 QCOMPARE(o.actuals().count(), 1);
1828 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1831 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
1832 QCOMPARE(o.error(), false);
1833 QCOMPARE(o.invoked(), 12);
1834 QCOMPARE(o.actuals().count(), 1);
1835 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1838 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
1839 QCOMPARE(o.error(), false);
1840 QCOMPARE(o.invoked(), 12);
1841 QCOMPARE(o.actuals().count(), 1);
1842 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1845 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
1846 QCOMPARE(o.error(), false);
1847 QCOMPARE(o.invoked(), 12);
1848 QCOMPARE(o.actuals().count(), 1);
1849 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1852 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
1853 QCOMPARE(o.error(), false);
1854 QCOMPARE(o.invoked(), 12);
1855 QCOMPARE(o.actuals().count(), 1);
1856 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
1859 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
1860 QCOMPARE(o.error(), false);
1861 QCOMPARE(o.invoked(), 12);
1862 QCOMPARE(o.actuals().count(), 1);
1863 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
1866 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
1867 QCOMPARE(o.error(), false);
1868 QCOMPARE(o.invoked(), 13);
1869 QCOMPARE(o.actuals().count(), 1);
1870 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1873 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
1874 QCOMPARE(o.error(), false);
1875 QCOMPARE(o.invoked(), 13);
1876 QCOMPARE(o.actuals().count(), 1);
1877 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1880 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
1881 QCOMPARE(o.error(), false);
1882 QCOMPARE(o.invoked(), 13);
1883 QCOMPARE(o.actuals().count(), 1);
1884 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1887 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
1888 QCOMPARE(o.error(), false);
1889 QCOMPARE(o.invoked(), 13);
1890 QCOMPARE(o.actuals().count(), 1);
1891 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1894 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
1895 QCOMPARE(o.error(), false);
1896 QCOMPARE(o.invoked(), 13);
1897 QCOMPARE(o.actuals().count(), 1);
1898 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
1900 // XXX enable once qml/qtscript integration is implemented
1903 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
1904 QCOMPARE(o.error(), false);
1905 QCOMPARE(o.invoked(), 14);
1906 QCOMPARE(o.actuals().count(), 1);
1907 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isNull());
1910 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
1911 QCOMPARE(o.error(), false);
1912 QCOMPARE(o.invoked(), 14);
1913 QCOMPARE(o.actuals().count(), 1);
1914 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isUndefined());
1917 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
1918 QCOMPARE(o.error(), false);
1919 QCOMPARE(o.invoked(), 14);
1920 QCOMPARE(o.actuals().count(), 1);
1921 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).strictlyEquals(QScriptValue(engine, 19)));
1924 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
1925 QCOMPARE(o.error(), false);
1926 QCOMPARE(o.invoked(), 14);
1927 QCOMPARE(o.actuals().count(), 1);
1928 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isArray());
1931 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
1932 QCOMPARE(o.error(), false);
1933 QCOMPARE(o.invoked(), 15);
1934 QCOMPARE(o.actuals().count(), 2);
1935 QCOMPARE(o.actuals().at(0), QVariant(4));
1936 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isNull());
1939 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
1940 QCOMPARE(o.error(), false);
1941 QCOMPARE(o.invoked(), 15);
1942 QCOMPARE(o.actuals().count(), 2);
1943 QCOMPARE(o.actuals().at(0), QVariant(8));
1944 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isUndefined());
1947 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
1948 QCOMPARE(o.error(), false);
1949 QCOMPARE(o.invoked(), 15);
1950 QCOMPARE(o.actuals().count(), 2);
1951 QCOMPARE(o.actuals().at(0), QVariant(3));
1952 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).strictlyEquals(QScriptValue(engine, 19)));
1955 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
1956 QCOMPARE(o.error(), false);
1957 QCOMPARE(o.invoked(), 15);
1958 QCOMPARE(o.actuals().count(), 2);
1959 QCOMPARE(o.actuals().at(0), QVariant(44));
1960 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isArray());
1964 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
1965 QCOMPARE(o.error(), false);
1966 QCOMPARE(o.invoked(), -1);
1967 QCOMPARE(o.actuals().count(), 0);
1970 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
1971 QCOMPARE(o.error(), false);
1972 QCOMPARE(o.invoked(), 16);
1973 QCOMPARE(o.actuals().count(), 1);
1974 QCOMPARE(o.actuals().at(0), QVariant(10));
1977 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
1978 QCOMPARE(o.error(), false);
1979 QCOMPARE(o.invoked(), 17);
1980 QCOMPARE(o.actuals().count(), 2);
1981 QCOMPARE(o.actuals().at(0), QVariant(10));
1982 QCOMPARE(o.actuals().at(1), QVariant(11));
1985 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
1986 QCOMPARE(o.error(), false);
1987 QCOMPARE(o.invoked(), 18);
1988 QCOMPARE(o.actuals().count(), 1);
1989 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
1992 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
1993 QCOMPARE(o.error(), false);
1994 QCOMPARE(o.invoked(), 19);
1995 QCOMPARE(o.actuals().count(), 1);
1996 QCOMPARE(o.actuals().at(0), QVariant(9));
1999 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2000 QCOMPARE(o.error(), false);
2001 QCOMPARE(o.invoked(), 20);
2002 QCOMPARE(o.actuals().count(), 2);
2003 QCOMPARE(o.actuals().at(0), QVariant(10));
2004 QCOMPARE(o.actuals().at(1), QVariant(19));
2007 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2008 QCOMPARE(o.error(), false);
2009 QCOMPARE(o.invoked(), 20);
2010 QCOMPARE(o.actuals().count(), 2);
2011 QCOMPARE(o.actuals().at(0), QVariant(10));
2012 QCOMPARE(o.actuals().at(1), QVariant(13));
2015 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2016 QCOMPARE(o.error(), false);
2017 QCOMPARE(o.invoked(), -3);
2018 QCOMPARE(o.actuals().count(), 1);
2019 QCOMPARE(o.actuals().at(0), QVariant(9));
2022 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2023 QCOMPARE(o.error(), false);
2024 QCOMPARE(o.invoked(), 21);
2025 QCOMPARE(o.actuals().count(), 2);
2026 QCOMPARE(o.actuals().at(0), QVariant(9));
2027 QCOMPARE(o.actuals().at(1), QVariant());
2030 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2031 QCOMPARE(o.error(), false);
2032 QCOMPARE(o.invoked(), 21);
2033 QCOMPARE(o.actuals().count(), 2);
2034 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2035 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2038 // QTBUG-13047 (check that you can pass registered object types as args)
2039 void tst_qdeclarativeecmascript::invokableObjectArg()
2041 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2043 QObject *o = component.create();
2045 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2047 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2052 // QTBUG-13047 (check that you can return registered object types from methods)
2053 void tst_qdeclarativeecmascript::invokableObjectRet()
2055 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2057 QObject *o = component.create();
2059 QCOMPARE(o->property("test").toBool(), true);
2064 void tst_qdeclarativeecmascript::listToVariant()
2066 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2068 MyQmlContainer container;
2070 QDeclarativeContext context(engine.rootContext());
2071 context.setContextObject(&container);
2073 QObject *object = component.create(&context);
2074 QVERIFY(object != 0);
2076 QVariant v = object->property("test");
2077 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2078 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2084 void tst_qdeclarativeecmascript::multiEngineObject()
2087 obj.setStringProperty("Howdy planet");
2089 QDeclarativeEngine e1;
2090 e1.rootContext()->setContextProperty("thing", &obj);
2091 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2093 QDeclarativeEngine e2;
2094 e2.rootContext()->setContextProperty("thing", &obj);
2095 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2097 QObject *o1 = c1.create();
2098 QObject *o2 = c2.create();
2100 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2101 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2107 // Test that references to QObjects are cleanup when the object is destroyed
2108 void tst_qdeclarativeecmascript::deletedObject()
2110 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2112 QObject *object = component.create();
2114 QCOMPARE(object->property("test1").toBool(), true);
2115 QCOMPARE(object->property("test2").toBool(), true);
2116 QCOMPARE(object->property("test3").toBool(), true);
2117 QCOMPARE(object->property("test4").toBool(), true);
2122 void tst_qdeclarativeecmascript::attachedPropertyScope()
2124 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2126 QObject *object = component.create();
2127 QVERIFY(object != 0);
2129 MyQmlAttachedObject *attached =
2130 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2131 QVERIFY(attached != 0);
2133 QCOMPARE(object->property("value2").toInt(), 0);
2135 attached->emitMySignal();
2137 QCOMPARE(object->property("value2").toInt(), 9);
2142 void tst_qdeclarativeecmascript::scriptConnect()
2145 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2147 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2148 QVERIFY(object != 0);
2150 QCOMPARE(object->property("test").toBool(), false);
2151 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2152 QCOMPARE(object->property("test").toBool(), true);
2158 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2160 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2161 QVERIFY(object != 0);
2163 QCOMPARE(object->property("test").toBool(), false);
2164 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2165 QCOMPARE(object->property("test").toBool(), true);
2171 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2173 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2174 QVERIFY(object != 0);
2176 QCOMPARE(object->property("test").toBool(), false);
2177 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2178 QCOMPARE(object->property("test").toBool(), true);
2184 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2186 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2187 QVERIFY(object != 0);
2189 QCOMPARE(object->methodCalled(), false);
2190 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2191 QCOMPARE(object->methodCalled(), true);
2197 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2199 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2200 QVERIFY(object != 0);
2202 QCOMPARE(object->methodCalled(), false);
2203 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2204 QCOMPARE(object->methodCalled(), true);
2210 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2212 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2213 QVERIFY(object != 0);
2215 QCOMPARE(object->property("test").toInt(), 0);
2216 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2217 QCOMPARE(object->property("test").toInt(), 2);
2223 void tst_qdeclarativeecmascript::scriptDisconnect()
2226 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2228 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2229 QVERIFY(object != 0);
2231 QCOMPARE(object->property("test").toInt(), 0);
2232 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2233 QCOMPARE(object->property("test").toInt(), 1);
2234 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2235 QCOMPARE(object->property("test").toInt(), 2);
2236 emit object->basicSignal();
2237 QCOMPARE(object->property("test").toInt(), 2);
2238 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2239 QCOMPARE(object->property("test").toInt(), 2);
2245 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2247 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2248 QVERIFY(object != 0);
2250 QCOMPARE(object->property("test").toInt(), 0);
2251 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2252 QCOMPARE(object->property("test").toInt(), 1);
2253 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2254 QCOMPARE(object->property("test").toInt(), 2);
2255 emit object->basicSignal();
2256 QCOMPARE(object->property("test").toInt(), 2);
2257 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2258 QCOMPARE(object->property("test").toInt(), 2);
2264 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2266 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2267 QVERIFY(object != 0);
2269 QCOMPARE(object->property("test").toInt(), 0);
2270 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2271 QCOMPARE(object->property("test").toInt(), 1);
2272 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2273 QCOMPARE(object->property("test").toInt(), 2);
2274 emit object->basicSignal();
2275 QCOMPARE(object->property("test").toInt(), 2);
2276 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2277 QCOMPARE(object->property("test").toInt(), 3);
2282 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2284 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2285 QVERIFY(object != 0);
2287 QCOMPARE(object->property("test").toInt(), 0);
2288 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2289 QCOMPARE(object->property("test").toInt(), 1);
2290 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2291 QCOMPARE(object->property("test").toInt(), 2);
2292 emit object->basicSignal();
2293 QCOMPARE(object->property("test").toInt(), 2);
2294 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2295 QCOMPARE(object->property("test").toInt(), 3);
2301 class OwnershipObject : public QObject
2305 OwnershipObject() { object = new QObject; }
2307 QPointer<QObject> object;
2310 QObject *getObject() { return object; }
2313 void tst_qdeclarativeecmascript::ownership()
2315 OwnershipObject own;
2316 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2317 context->setContextObject(&own);
2320 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2322 QVERIFY(own.object != 0);
2324 QObject *object = component.create(context);
2326 engine.collectGarbage();
2328 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2330 QVERIFY(own.object == 0);
2335 own.object = new QObject(&own);
2338 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2340 QVERIFY(own.object != 0);
2342 QObject *object = component.create(context);
2344 engine.collectGarbage();
2346 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2348 QVERIFY(own.object != 0);
2356 class CppOwnershipReturnValue : public QObject
2360 CppOwnershipReturnValue() : value(0) {}
2361 ~CppOwnershipReturnValue() { delete value; }
2363 Q_INVOKABLE QObject *create() {
2364 value = new QObject;
2365 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2369 Q_INVOKABLE MyQmlObject *createQmlObject() {
2370 MyQmlObject *rv = new MyQmlObject;
2375 QPointer<QObject> value;
2379 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2380 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2382 CppOwnershipReturnValue source;
2385 QDeclarativeEngine engine;
2386 engine.rootContext()->setContextProperty("source", &source);
2388 QVERIFY(source.value == 0);
2390 QDeclarativeComponent component(&engine);
2391 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2393 QObject *object = component.create();
2395 QVERIFY(object != 0);
2396 QVERIFY(source.value != 0);
2401 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2403 QVERIFY(source.value != 0);
2407 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2409 CppOwnershipReturnValue source;
2412 QDeclarativeEngine engine;
2413 engine.rootContext()->setContextProperty("source", &source);
2415 QVERIFY(source.value == 0);
2417 QDeclarativeComponent component(&engine);
2418 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2420 QObject *object = component.create();
2422 QVERIFY(object != 0);
2423 QVERIFY(source.value != 0);
2428 engine.collectGarbage();
2429 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2431 QVERIFY(source.value == 0);
2434 class QListQObjectMethodsObject : public QObject
2438 QListQObjectMethodsObject() {
2439 m_objects.append(new MyQmlObject());
2440 m_objects.append(new MyQmlObject());
2443 ~QListQObjectMethodsObject() {
2444 qDeleteAll(m_objects);
2448 QList<QObject *> getObjects() { return m_objects; }
2451 QList<QObject *> m_objects;
2454 // Tests that returning a QList<QObject*> from a method works
2455 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2457 QListQObjectMethodsObject obj;
2458 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2459 context->setContextObject(&obj);
2461 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2463 QObject *object = component.create(context);
2465 QCOMPARE(object->property("test").toInt(), 2);
2466 QCOMPARE(object->property("test2").toBool(), true);
2473 void tst_qdeclarativeecmascript::strictlyEquals()
2475 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2477 QObject *object = component.create();
2478 QVERIFY(object != 0);
2480 QCOMPARE(object->property("test1").toBool(), true);
2481 QCOMPARE(object->property("test2").toBool(), true);
2482 QCOMPARE(object->property("test3").toBool(), true);
2483 QCOMPARE(object->property("test4").toBool(), true);
2484 QCOMPARE(object->property("test5").toBool(), true);
2485 QCOMPARE(object->property("test6").toBool(), true);
2486 QCOMPARE(object->property("test7").toBool(), true);
2487 QCOMPARE(object->property("test8").toBool(), true);
2492 void tst_qdeclarativeecmascript::compiled()
2494 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2496 QObject *object = component.create();
2497 QVERIFY(object != 0);
2499 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2500 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2501 QCOMPARE(object->property("test3").toBool(), true);
2502 QCOMPARE(object->property("test4").toBool(), false);
2503 QCOMPARE(object->property("test5").toBool(), false);
2504 QCOMPARE(object->property("test6").toBool(), true);
2506 QCOMPARE(object->property("test7").toInt(), 185);
2507 QCOMPARE(object->property("test8").toInt(), 167);
2508 QCOMPARE(object->property("test9").toBool(), true);
2509 QCOMPARE(object->property("test10").toBool(), false);
2510 QCOMPARE(object->property("test11").toBool(), false);
2511 QCOMPARE(object->property("test12").toBool(), true);
2513 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2514 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2515 QCOMPARE(object->property("test15").toBool(), false);
2516 QCOMPARE(object->property("test16").toBool(), true);
2518 QCOMPARE(object->property("test17").toInt(), 5);
2519 QCOMPARE(object->property("test18").toReal(), qreal(176));
2520 QCOMPARE(object->property("test19").toInt(), 7);
2521 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2522 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2523 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2524 QCOMPARE(object->property("test23").toBool(), true);
2525 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2526 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2531 // Test that numbers assigned in bindings as strings work consistently
2532 void tst_qdeclarativeecmascript::numberAssignment()
2534 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2536 QObject *object = component.create();
2537 QVERIFY(object != 0);
2539 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2540 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2541 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2542 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2543 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2545 QCOMPARE(object->property("test5"), QVariant((int)7));
2546 QCOMPARE(object->property("test6"), QVariant((int)7));
2547 QCOMPARE(object->property("test7"), QVariant((int)6));
2548 QCOMPARE(object->property("test8"), QVariant((int)6));
2550 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2551 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2552 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2553 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2558 void tst_qdeclarativeecmascript::propertySplicing()
2560 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2562 QObject *object = component.create();
2563 QVERIFY(object != 0);
2565 QCOMPARE(object->property("test").toBool(), true);
2571 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2573 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2575 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2576 QVERIFY(object != 0);
2578 MyQmlObject::MyType type;
2579 type.value = 0x8971123;
2580 emit object->signalWithUnknownType(type);
2582 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2584 QCOMPARE(result.value, type.value);
2590 void tst_qdeclarativeecmascript::moduleApi()
2592 QDeclarativeComponent component(&engine, TEST_FILE("moduleApi.qml"));
2593 QObject *object = component.create();
2594 QVERIFY(object != 0);
2595 QCOMPARE(object->property("existingUriTest").toInt(), 20);
2597 QEXPECT_FAIL("", "QTBUG-17318", Continue);
2598 QCOMPARE(object->property("scriptTest").toInt(), 13);
2599 QCOMPARE(object->property("qobjectTest").toInt(), 20);
2600 QCOMPARE(object->property("qobjectMethodTest").toInt(), 1); // first call of method, so count = 1.
2601 QCOMPARE(object->property("qobjectMinorVersionTest").toInt(), 20);
2602 QCOMPARE(object->property("qobjectMajorVersionTest").toInt(), 20);
2603 QCOMPARE(object->property("qobjectParentedTest").toInt(), 26);
2606 // test that caching of module apis works correctly.
2607 QDeclarativeComponent componentTwo(&engine, TEST_FILE("moduleApiCaching.qml"));
2608 object = componentTwo.create();
2609 QVERIFY(object != 0);
2610 QCOMPARE(object->property("existingUriTest").toInt(), 20);
2611 QEXPECT_FAIL("", "QTBUG-17318", Continue);
2612 QCOMPARE(object->property("scriptTest").toInt(), 13); // shouldn't have incremented.
2613 QCOMPARE(object->property("qobjectParentedTest").toInt(), 26); // shouldn't have incremented.
2616 // test that writing to a property of module apis works correctly.
2617 QDeclarativeComponent componentThree(&engine, TEST_FILE("moduleApiWriting.qml"));
2618 QString expectedWarning = QLatin1String("file://") + TEST_FILE("moduleApiWriting.qml").toLocalFile() + QLatin1String(":15: Error: Cannot assign to read-only property \"qobjectTestProperty\"");
2619 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2620 object = componentThree.create();
2621 QVERIFY(object != 0);
2622 QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
2623 QCOMPARE(object->property("writableProperty").toInt(), 50);
2624 QVERIFY(object->setProperty("firstProperty", QVariant(30))); // shouldn't affect value of readOnlyProperty
2625 QVERIFY(object->setProperty("writableProperty", QVariant(30))); // SHOULD affect value of writableProperty
2626 QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
2627 QCOMPARE(object->property("writableProperty").toInt(), 30);
2630 QDeclarativeComponent failOne(&engine, TEST_FILE("moduleApiMajorVersionFail.qml"));
2631 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2632 object = failOne.create();
2633 QVERIFY(object == 0); // should have failed: invalid major version
2635 QDeclarativeComponent failTwo(&engine, TEST_FILE("moduleApiMinorVersionFail.qml"));
2636 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2637 object = failTwo.create();
2638 QVERIFY(object == 0); // should have failed: invalid minor version
2641 void tst_qdeclarativeecmascript::importScripts()
2643 QObject *object = 0;
2645 // first, ensure that the required behaviour works.
2646 QDeclarativeComponent component(&engine, TEST_FILE("jsimport/testImport.qml"));
2647 object = component.create();
2648 QVERIFY(object != 0);
2649 QCOMPARE(object->property("importedScriptStringValue"), QVariant(QString(QLatin1String("Hello, World!"))));
2650 QCOMPARE(object->property("importedScriptFunctionValue"), QVariant(20));
2651 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(19));
2652 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(2));
2655 QDeclarativeComponent componentTwo(&engine, TEST_FILE("jsimport/testImportScoping.qml"));
2656 object = componentTwo.create();
2657 QVERIFY(object != 0);
2658 QCOMPARE(object->property("componentError"), QVariant(5));
2661 // then, ensure that unintended behaviour does not work.
2662 QDeclarativeComponent failOneComponent(&engine, TEST_FILE("jsimportfail/failOne.qml"));
2663 QString expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined");
2664 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2665 object = failOneComponent.create();
2666 QVERIFY(object != 0);
2667 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2669 QDeclarativeComponent failTwoComponent(&engine, TEST_FILE("jsimportfail/failTwo.qml"));
2670 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs");
2671 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2672 object = failTwoComponent.create();
2673 QVERIFY(object != 0);
2674 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2676 QDeclarativeComponent failThreeComponent(&engine, TEST_FILE("jsimportfail/failThree.qml"));
2677 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined");
2678 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2679 object = failThreeComponent.create();
2680 QVERIFY(object != 0);
2681 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(false));
2683 QDeclarativeComponent failFourComponent(&engine, TEST_FILE("jsimportfail/failFour.qml"));
2684 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest");
2685 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2686 object = failFourComponent.create();
2687 QVERIFY(object != 0);
2688 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(0));
2690 QDeclarativeComponent failFiveComponent(&engine, TEST_FILE("jsimportfail/failFive.qml"));
2691 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component");
2692 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2693 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component");
2694 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2695 object = failFiveComponent.create();
2696 QVERIFY(object != 0);
2697 QCOMPARE(object->property("componentError"), QVariant(0));
2700 // also, test that importing scripts with .pragma library works as required
2701 QDeclarativeComponent pragmaLibraryComponent(&engine, TEST_FILE("jsimport/testImportPragmaLibrary.qml"));
2702 object = pragmaLibraryComponent.create();
2703 QVERIFY(object != 0);
2704 QCOMPARE(object->property("testValue"), QVariant(31));
2707 // and that .pragma library scripts don't inherit imports from any .qml file
2708 QDeclarativeComponent pragmaLibraryComponentTwo(&engine, TEST_FILE("jsimportfail/testImportPragmaLibrary.qml"));
2709 object = pragmaLibraryComponentTwo.create();
2710 QVERIFY(object != 0);
2711 QCOMPARE(object->property("testValue"), QVariant(0));
2715 void tst_qdeclarativeecmascript::scarceResources()
2717 QPixmap origPixmap(100, 100);
2718 origPixmap.fill(Qt::blue);
2720 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
2721 ScarceResourceObject *eo = 0;
2722 QObject *object = 0;
2724 // in the following three cases, the instance created from the component
2725 // has a property which is a copy of the scarce resource; hence, the
2726 // resource should NOT be detached prior to deletion of the object instance,
2727 // unless the resource is destroyed explicitly.
2728 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
2729 object = component.create();
2730 QVERIFY(object != 0);
2731 QVERIFY(object->property("scarceResourceCopy").isValid());
2732 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2733 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2734 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2735 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
2738 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
2739 object = componentTwo.create();
2740 QVERIFY(object != 0);
2741 QVERIFY(object->property("scarceResourceCopy").isValid());
2742 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2743 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2744 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2745 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
2748 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
2749 object = componentThree.create();
2750 QVERIFY(object != 0);
2751 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
2752 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2753 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2754 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
2757 // in the following three cases, no other copy should exist in memory,
2758 // and so it should be detached (unless explicitly preserved).
2759 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
2760 object = componentFour.create();
2761 QVERIFY(object != 0);
2762 QVERIFY(object->property("scarceResourceTest").isValid());
2763 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2764 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2765 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2766 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
2769 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
2770 object = componentFive.create();
2771 QVERIFY(object != 0);
2772 QVERIFY(object->property("scarceResourceTest").isValid());
2773 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2774 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2775 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2776 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
2779 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
2780 object = componentSix.create();
2781 QVERIFY(object != 0);
2782 QVERIFY(object->property("scarceResourceTest").isValid());
2783 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2784 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2785 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2786 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
2789 // test that scarce resources are handled correctly for imports
2790 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
2791 object = componentSeven.create();
2792 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
2793 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
2796 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
2797 object = componentEight.create();
2798 QVERIFY(object != 0);
2799 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
2800 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2803 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
2804 object = componentNine.create();
2805 QVERIFY(object != 0);
2806 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
2807 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2808 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
2809 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
2810 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
2811 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
2814 // test that scarce resources are handled properly in signal invocation
2815 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
2816 object = componentTen.create();
2817 QVERIFY(object != 0);
2818 QObject *srsc = object->findChild<QObject*>("srsc");
2820 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
2821 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
2822 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2823 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2824 QMetaObject::invokeMethod(srsc, "testSignal");
2825 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
2826 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
2827 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2828 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
2829 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
2830 QVERIFY(srsc->property("scarceResourceCopy").isValid());
2831 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2832 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2833 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
2834 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2837 // test that scarce resources are handled properly from js functions in qml files
2838 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
2839 object = componentEleven.create();
2840 QVERIFY(object != 0);
2841 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
2842 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2843 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2844 QMetaObject::invokeMethod(object, "retrieveScarceResource");
2845 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
2846 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2847 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2848 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
2849 QMetaObject::invokeMethod(object, "releaseScarceResource");
2850 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
2851 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2852 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2853 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2856 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
2857 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
2858 object = componentTwelve.create();
2859 QVERIFY(object != 0);
2860 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
2861 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2862 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2863 QString srp_name = object->property("srp_name").toString();
2864 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
2865 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
2866 QMetaObject::invokeMethod(object, "retrieveScarceResource");
2867 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
2868 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2869 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2870 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2874 void tst_qdeclarativeecmascript::propertyChangeSlots()
2876 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
2877 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
2878 QObject *object = component.create();
2879 QVERIFY(object != 0);
2882 // ensure that invalid property names fail properly.
2883 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2884 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
2885 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
2886 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
2887 object = e1.create();
2888 QVERIFY(object == 0);
2891 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2892 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
2893 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
2894 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
2895 object = e2.create();
2896 QVERIFY(object == 0);
2899 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2900 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
2901 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
2902 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
2903 object = e3.create();
2904 QVERIFY(object == 0);
2907 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2908 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
2909 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
2910 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
2911 object = e4.create();
2912 QVERIFY(object == 0);
2916 // Ensure that QObject type conversion works on binding assignment
2917 void tst_qdeclarativeecmascript::elementAssign()
2919 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
2921 QObject *object = component.create();
2922 QVERIFY(object != 0);
2924 QCOMPARE(object->property("test").toBool(), true);
2930 void tst_qdeclarativeecmascript::objectPassThroughSignals()
2932 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
2934 QObject *object = component.create();
2935 QVERIFY(object != 0);
2937 QCOMPARE(object->property("test").toBool(), true);
2943 void tst_qdeclarativeecmascript::booleanConversion()
2945 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
2947 QObject *object = component.create();
2948 QVERIFY(object != 0);
2950 QCOMPARE(object->property("test_true1").toBool(), true);
2951 QCOMPARE(object->property("test_true2").toBool(), true);
2952 QCOMPARE(object->property("test_true3").toBool(), true);
2953 QCOMPARE(object->property("test_true4").toBool(), true);
2954 QCOMPARE(object->property("test_true5").toBool(), true);
2956 QCOMPARE(object->property("test_false1").toBool(), false);
2957 QCOMPARE(object->property("test_false2").toBool(), false);
2958 QCOMPARE(object->property("test_false3").toBool(), false);
2963 // Test that assigning a null object works
2964 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
2965 void tst_qdeclarativeecmascript::nullObjectBinding()
2967 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
2969 QObject *object = component.create();
2970 QVERIFY(object != 0);
2972 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
2977 // Test that bindings don't evaluate once the engine has been destroyed
2978 void tst_qdeclarativeecmascript::deletedEngine()
2980 QDeclarativeEngine *engine = new QDeclarativeEngine;
2981 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
2983 QObject *object = component.create();
2984 QVERIFY(object != 0);
2986 QCOMPARE(object->property("a").toInt(), 39);
2987 object->setProperty("b", QVariant(9));
2988 QCOMPARE(object->property("a").toInt(), 117);
2992 QCOMPARE(object->property("a").toInt(), 117);
2993 object->setProperty("b", QVariant(10));
2994 QCOMPARE(object->property("a").toInt(), 117);
2999 // Test the crashing part of QTBUG-9705
3000 void tst_qdeclarativeecmascript::libraryScriptAssert()
3002 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
3004 QObject *object = component.create();
3005 QVERIFY(object != 0);
3010 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
3012 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
3014 QObject *object = component.create();
3015 QVERIFY(object != 0);
3017 QCOMPARE(object->property("test1").toInt(), 10);
3018 QCOMPARE(object->property("test2").toInt(), 11);
3020 object->setProperty("runTest", true);
3022 QCOMPARE(object->property("test1"), QVariant());
3023 QCOMPARE(object->property("test2"), QVariant());
3029 void tst_qdeclarativeecmascript::qtbug_9792()
3031 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
3033 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
3035 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
3036 QVERIFY(object != 0);
3038 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
3039 object->basicSignal();
3043 transientErrorsMsgCount = 0;
3044 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3046 object->basicSignal();
3048 qInstallMsgHandler(old);
3050 QCOMPARE(transientErrorsMsgCount, 0);
3055 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
3056 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
3058 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
3060 QObject *o = component.create();
3063 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
3064 QVERIFY(nested != 0);
3066 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
3069 nested = qvariant_cast<QObject *>(o->property("object"));
3070 QVERIFY(nested == 0);
3072 // If the bug is present, the next line will crash
3076 // Test that we shut down without stupid warnings
3077 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
3080 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
3082 QObject *o = component.create();
3084 transientErrorsMsgCount = 0;
3085 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3089 qInstallMsgHandler(old);
3091 QCOMPARE(transientErrorsMsgCount, 0);
3096 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
3098 QObject *o = component.create();
3100 transientErrorsMsgCount = 0;
3101 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3105 qInstallMsgHandler(old);
3107 QCOMPARE(transientErrorsMsgCount, 0);
3111 void tst_qdeclarativeecmascript::canAssignNullToQObject()
3114 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
3116 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3119 QVERIFY(o->objectProperty() != 0);
3121 o->setProperty("runTest", true);
3123 QVERIFY(o->objectProperty() == 0);
3129 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
3131 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3134 QVERIFY(o->objectProperty() == 0);
3140 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
3142 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
3144 QString url = component.url().toString();
3145 QString warning = url + ":4: Unable to assign a function to a property.";
3146 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3148 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3151 QVERIFY(!o->property("a").isValid());
3156 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
3158 QFETCH(QString, triggerProperty);
3160 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3161 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3163 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3165 QVERIFY(!o->property("a").isValid());
3167 o->setProperty("aNumber", QVariant(5));
3168 o->setProperty(triggerProperty.toUtf8().constData(), true);
3169 QCOMPARE(o->property("a"), QVariant(50));
3171 o->setProperty("aNumber", QVariant(10));
3172 QCOMPARE(o->property("a"), QVariant(100));
3177 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
3179 QTest::addColumn<QString>("triggerProperty");
3181 QTest::newRow("assign to property") << "assignToProperty";
3182 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
3184 QTest::newRow("assign to value type") << "assignToValueType";
3186 QTest::newRow("use 'this'") << "assignWithThis";
3187 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
3190 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
3192 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3193 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3195 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3197 QVERIFY(!o->property("a").isValid());
3199 o->setProperty("assignFuncWithoutReturn", true);
3200 QVERIFY(!o->property("a").isValid());
3202 QString url = component.url().toString();
3203 QString warning = url + ":67: Unable to assign QString to int";
3204 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3205 o->setProperty("assignWrongType", true);
3207 warning = url + ":71: Unable to assign QString to int";
3208 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3209 o->setProperty("assignWrongTypeToValueType", true);
3214 void tst_qdeclarativeecmascript::eval()
3216 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
3218 QObject *o = component.create();
3221 QCOMPARE(o->property("test1").toBool(), true);
3222 QCOMPARE(o->property("test2").toBool(), true);
3223 QCOMPARE(o->property("test3").toBool(), true);
3224 QCOMPARE(o->property("test4").toBool(), true);
3225 QCOMPARE(o->property("test5").toBool(), true);
3230 void tst_qdeclarativeecmascript::function()
3232 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
3234 QObject *o = component.create();
3237 QCOMPARE(o->property("test1").toBool(), true);
3238 QCOMPARE(o->property("test2").toBool(), true);
3239 QCOMPARE(o->property("test3").toBool(), true);
3244 // Test the "Qt.include" method
3245 void tst_qdeclarativeecmascript::include()
3247 // Non-library relative include
3249 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
3250 QObject *o = component.create();
3253 QCOMPARE(o->property("test0").toInt(), 99);
3254 QCOMPARE(o->property("test1").toBool(), true);
3255 QCOMPARE(o->property("test2").toBool(), true);
3256 QCOMPARE(o->property("test2_1").toBool(), true);
3257 QCOMPARE(o->property("test3").toBool(), true);
3258 QCOMPARE(o->property("test3_1").toBool(), true);
3263 // Library relative include
3265 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
3266 QObject *o = component.create();
3269 QCOMPARE(o->property("test0").toInt(), 99);
3270 QCOMPARE(o->property("test1").toBool(), true);
3271 QCOMPARE(o->property("test2").toBool(), true);
3272 QCOMPARE(o->property("test2_1").toBool(), true);
3273 QCOMPARE(o->property("test3").toBool(), true);
3274 QCOMPARE(o->property("test3_1").toBool(), true);
3281 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
3282 QObject *o = component.create();
3285 QCOMPARE(o->property("test1").toBool(), true);
3286 QCOMPARE(o->property("test2").toBool(), true);
3287 QCOMPARE(o->property("test3").toBool(), true);
3288 QCOMPARE(o->property("test4").toBool(), true);
3289 QCOMPARE(o->property("test5").toBool(), true);
3290 QCOMPARE(o->property("test6").toBool(), true);
3295 // Including file with ".pragma library"
3297 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
3298 QObject *o = component.create();
3300 QCOMPARE(o->property("test1").toInt(), 100);
3307 TestHTTPServer server(8111);
3308 QVERIFY(server.isValid());
3309 server.serveDirectory(SRCDIR "/data");
3311 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
3312 QObject *o = component.create();
3315 QTRY_VERIFY(o->property("done").toBool() == true);
3316 QTRY_VERIFY(o->property("done2").toBool() == true);
3318 QCOMPARE(o->property("test1").toBool(), true);
3319 QCOMPARE(o->property("test2").toBool(), true);
3320 QCOMPARE(o->property("test3").toBool(), true);
3321 QCOMPARE(o->property("test4").toBool(), true);
3322 QCOMPARE(o->property("test5").toBool(), true);
3324 QCOMPARE(o->property("test6").toBool(), true);
3325 QCOMPARE(o->property("test7").toBool(), true);
3326 QCOMPARE(o->property("test8").toBool(), true);
3327 QCOMPARE(o->property("test9").toBool(), true);
3328 QCOMPARE(o->property("test10").toBool(), true);
3335 TestHTTPServer server(8111);
3336 QVERIFY(server.isValid());
3337 server.serveDirectory(SRCDIR "/data");
3339 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
3340 QObject *o = component.create();
3343 QTRY_VERIFY(o->property("done").toBool() == true);
3345 QCOMPARE(o->property("test1").toBool(), true);
3346 QCOMPARE(o->property("test2").toBool(), true);
3347 QCOMPARE(o->property("test3").toBool(), true);
3353 void tst_qdeclarativeecmascript::qtbug_10696()
3355 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
3356 QObject *o = component.create();
3361 void tst_qdeclarativeecmascript::qtbug_11606()
3363 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
3364 QObject *o = component.create();
3366 QCOMPARE(o->property("test").toBool(), true);
3370 void tst_qdeclarativeecmascript::qtbug_11600()
3372 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
3373 QObject *o = component.create();
3375 QCOMPARE(o->property("test").toBool(), true);
3379 // Reading and writing non-scriptable properties should fail
3380 void tst_qdeclarativeecmascript::nonscriptable()
3382 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
3383 QObject *o = component.create();
3385 QCOMPARE(o->property("readOk").toBool(), true);
3386 QCOMPARE(o->property("writeOk").toBool(), true);
3390 // deleteLater() should not be callable from QML
3391 void tst_qdeclarativeecmascript::deleteLater()
3393 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
3394 QObject *o = component.create();
3396 QCOMPARE(o->property("test").toBool(), true);
3400 void tst_qdeclarativeecmascript::in()
3402 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
3403 QObject *o = component.create();
3405 QCOMPARE(o->property("test1").toBool(), true);
3406 QCOMPARE(o->property("test2").toBool(), true);
3410 void tst_qdeclarativeecmascript::sharedAttachedObject()
3412 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
3413 QObject *o = component.create();
3415 QCOMPARE(o->property("test1").toBool(), true);
3416 QCOMPARE(o->property("test2").toBool(), true);
3421 void tst_qdeclarativeecmascript::objectName()
3423 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
3424 QObject *o = component.create();
3427 QCOMPARE(o->property("test1").toString(), QString("hello"));
3428 QCOMPARE(o->property("test2").toString(), QString("ell"));
3430 o->setObjectName("world");
3432 QCOMPARE(o->property("test1").toString(), QString("world"));
3433 QCOMPARE(o->property("test2").toString(), QString("orl"));
3438 void tst_qdeclarativeecmascript::writeRemovesBinding()
3440 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
3441 QObject *o = component.create();
3444 QCOMPARE(o->property("test").toBool(), true);
3449 // Test bindings assigned to alias properties actually assign to the alias' target
3450 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
3452 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
3453 QObject *o = component.create();
3456 QCOMPARE(o->property("test").toBool(), true);
3461 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
3462 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
3465 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
3466 QObject *o = component.create();
3469 QCOMPARE(o->property("test").toBool(), true);
3475 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
3476 QObject *o = component.create();
3479 QCOMPARE(o->property("test").toBool(), true);
3485 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
3486 QObject *o = component.create();
3489 QCOMPARE(o->property("test").toBool(), true);
3495 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
3496 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
3499 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
3500 QObject *o = component.create();
3503 QCOMPARE(o->property("test").toBool(), true);
3509 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
3510 QObject *o = component.create();
3513 QCOMPARE(o->property("test").toBool(), true);
3519 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
3520 QObject *o = component.create();
3523 QCOMPARE(o->property("test").toBool(), true);
3529 void tst_qdeclarativeecmascript::revisionErrors()
3532 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
3533 QString url = component.url().toString();
3535 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
3536 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
3537 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
3539 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3540 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3541 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3542 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3543 QVERIFY(object != 0);
3547 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
3548 QString url = component.url().toString();
3550 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
3551 // method2, prop2 from MyRevisionedClass not available
3552 // method4, prop4 from MyRevisionedSubclass not available
3553 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
3554 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
3555 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
3556 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
3557 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
3559 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3560 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3561 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3562 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
3563 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
3564 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3565 QVERIFY(object != 0);
3569 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
3570 QString url = component.url().toString();
3572 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
3573 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
3574 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
3575 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
3576 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
3577 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3578 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3579 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3580 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3581 QVERIFY(object != 0);
3586 void tst_qdeclarativeecmascript::revision()
3589 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
3590 QString url = component.url().toString();
3592 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3593 QVERIFY(object != 0);
3597 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
3598 QString url = component.url().toString();
3600 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3601 QVERIFY(object != 0);
3605 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
3606 QString url = component.url().toString();
3608 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3609 QVERIFY(object != 0);
3612 // Test that non-root classes can resolve revisioned methods
3614 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
3616 QObject *object = component.create();
3617 QVERIFY(object != 0);
3618 QCOMPARE(object->property("test").toReal(), 11.);
3623 void tst_qdeclarativeecmascript::realToInt()
3625 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
3626 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
3627 QVERIFY(object != 0);
3629 QMetaObject::invokeMethod(object, "test1");
3630 QCOMPARE(object->value(), int(4));
3631 QMetaObject::invokeMethod(object, "test2");
3632 QCOMPARE(object->value(), int(8));
3635 QTEST_MAIN(tst_qdeclarativeecmascript)
3637 #include "tst_qdeclarativeecmascript.moc"