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();
155 void dynamicCreationCrash();
157 void nullObjectBinding();
158 void deletedEngine();
159 void libraryScriptAssert();
160 void variantsAssignedUndefined();
162 void qtcreatorbug_1289();
163 void noSpuriousWarningsAtShutdown();
164 void canAssignNullToQObject();
165 void functionAssignment_fromBinding();
166 void functionAssignment_fromJS();
167 void functionAssignment_fromJS_data();
168 void functionAssignmentfromJS_invalid();
174 void nonscriptable();
177 void sharedAttachedObject();
179 void writeRemovesBinding();
180 void aliasBindingsAssignCorrectly();
181 void aliasBindingsOverrideTarget();
182 void aliasWritesOverrideBindings();
187 void callQtInvokables();
188 void invokableObjectArg();
189 void invokableObjectRet();
191 void revisionErrors();
195 QDeclarativeEngine engine;
198 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
200 void tst_qdeclarativeecmascript::assignBasicTypes()
203 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
204 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
205 QVERIFY(object != 0);
206 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
207 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
208 QCOMPARE(object->stringProperty(), QString("Hello World!"));
209 QCOMPARE(object->uintProperty(), uint(10));
210 QCOMPARE(object->intProperty(), -19);
211 QCOMPARE((float)object->realProperty(), float(23.2));
212 QCOMPARE((float)object->doubleProperty(), float(-19.75));
213 QCOMPARE((float)object->floatProperty(), float(8.5));
214 QCOMPARE(object->colorProperty(), QColor("red"));
215 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
216 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
217 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
218 QCOMPARE(object->pointProperty(), QPoint(99,13));
219 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
220 QCOMPARE(object->sizeProperty(), QSize(99, 13));
221 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
222 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
223 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
224 QCOMPARE(object->boolProperty(), true);
225 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
226 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
227 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
231 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
232 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
233 QVERIFY(object != 0);
234 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
235 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
236 QCOMPARE(object->stringProperty(), QString("Hello World!"));
237 QCOMPARE(object->uintProperty(), uint(10));
238 QCOMPARE(object->intProperty(), -19);
239 QCOMPARE((float)object->realProperty(), float(23.2));
240 QCOMPARE((float)object->doubleProperty(), float(-19.75));
241 QCOMPARE((float)object->floatProperty(), float(8.5));
242 QCOMPARE(object->colorProperty(), QColor("red"));
243 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
244 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
245 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
246 QCOMPARE(object->pointProperty(), QPoint(99,13));
247 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
248 QCOMPARE(object->sizeProperty(), QSize(99, 13));
249 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
250 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
251 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
252 QCOMPARE(object->boolProperty(), true);
253 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
254 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
255 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
260 void tst_qdeclarativeecmascript::idShortcutInvalidates()
263 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
264 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
265 QVERIFY(object != 0);
266 QVERIFY(object->objectProperty() != 0);
267 delete object->objectProperty();
268 QVERIFY(object->objectProperty() == 0);
273 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
274 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
275 QVERIFY(object != 0);
276 QVERIFY(object->objectProperty() != 0);
277 delete object->objectProperty();
278 QVERIFY(object->objectProperty() == 0);
283 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
286 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
287 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
288 QVERIFY(object != 0);
289 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
293 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
294 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
295 QVERIFY(object != 0);
296 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
301 void tst_qdeclarativeecmascript::signalAssignment()
304 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
305 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
306 QVERIFY(object != 0);
307 QCOMPARE(object->string(), QString());
308 emit object->basicSignal();
309 QCOMPARE(object->string(), QString("pass"));
314 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
315 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
316 QVERIFY(object != 0);
317 QCOMPARE(object->string(), QString());
318 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
319 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
324 void tst_qdeclarativeecmascript::methods()
327 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
328 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
329 QVERIFY(object != 0);
330 QCOMPARE(object->methodCalled(), false);
331 QCOMPARE(object->methodIntCalled(), false);
332 emit object->basicSignal();
333 QCOMPARE(object->methodCalled(), true);
334 QCOMPARE(object->methodIntCalled(), false);
339 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
340 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
341 QVERIFY(object != 0);
342 QCOMPARE(object->methodCalled(), false);
343 QCOMPARE(object->methodIntCalled(), false);
344 emit object->basicSignal();
345 QCOMPARE(object->methodCalled(), false);
346 QCOMPARE(object->methodIntCalled(), true);
351 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
352 QObject *object = component.create();
353 QVERIFY(object != 0);
354 QCOMPARE(object->property("test").toInt(), 19);
359 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
360 QObject *object = component.create();
361 QVERIFY(object != 0);
362 QCOMPARE(object->property("test").toInt(), 19);
363 QCOMPARE(object->property("test2").toInt(), 17);
364 QCOMPARE(object->property("test3").toInt(), 16);
369 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
370 QObject *object = component.create();
371 QVERIFY(object != 0);
372 QCOMPARE(object->property("test").toInt(), 9);
377 void tst_qdeclarativeecmascript::bindingLoop()
379 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
380 QString warning = component.url().toString() + ":9:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
381 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
382 QObject *object = component.create();
383 QVERIFY(object != 0);
387 void tst_qdeclarativeecmascript::basicExpressions_data()
389 QTest::addColumn<QString>("expression");
390 QTest::addColumn<QVariant>("result");
391 QTest::addColumn<bool>("nest");
393 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
394 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
395 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
396 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
397 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
398 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
399 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
400 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
401 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
402 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
403 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
404 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
405 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
406 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
407 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
408 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
409 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
410 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
411 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
414 void tst_qdeclarativeecmascript::basicExpressions()
416 QFETCH(QString, expression);
417 QFETCH(QVariant, result);
423 MyDefaultObject1 default1;
424 MyDefaultObject3 default3;
425 object1.setStringProperty("Object1");
426 object2.setStringProperty("Object2");
427 object3.setStringProperty("Object3");
429 QDeclarativeContext context(engine.rootContext());
430 QDeclarativeContext nestedContext(&context);
432 context.setContextObject(&default1);
433 context.setContextProperty("a", QVariant(1944));
434 context.setContextProperty("b", QVariant("Milk"));
435 context.setContextProperty("object", &object1);
436 context.setContextProperty("objectOverride", &object2);
437 nestedContext.setContextObject(&default3);
438 nestedContext.setContextProperty("b", QVariant("Cow"));
439 nestedContext.setContextProperty("objectOverride", &object3);
440 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
442 MyExpression expr(nest?&nestedContext:&context, expression);
443 QCOMPARE(expr.evaluate(), result);
446 void tst_qdeclarativeecmascript::arrayExpressions()
452 QDeclarativeContext context(engine.rootContext());
453 context.setContextProperty("a", &obj1);
454 context.setContextProperty("b", &obj2);
455 context.setContextProperty("c", &obj3);
457 MyExpression expr(&context, "[a, b, c, 10]");
458 QVariant result = expr.evaluate();
459 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
460 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
461 QCOMPARE(list.count(), 4);
462 QCOMPARE(list.at(0), &obj1);
463 QCOMPARE(list.at(1), &obj2);
464 QCOMPARE(list.at(2), &obj3);
465 QCOMPARE(list.at(3), (QObject *)0);
468 // Tests that modifying a context property will reevaluate expressions
469 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
471 QDeclarativeContext context(engine.rootContext());
474 MyQmlObject *object3 = new MyQmlObject;
476 object1.setStringProperty("Hello");
477 object2.setStringProperty("World");
479 context.setContextProperty("testProp", QVariant(1));
480 context.setContextProperty("testObj", &object1);
481 context.setContextProperty("testObj2", object3);
484 MyExpression expr(&context, "testProp + 1");
485 QCOMPARE(expr.changed, false);
486 QCOMPARE(expr.evaluate(), QVariant(2));
488 context.setContextProperty("testProp", QVariant(2));
489 QCOMPARE(expr.changed, true);
490 QCOMPARE(expr.evaluate(), QVariant(3));
494 MyExpression expr(&context, "testProp + testProp + testProp");
495 QCOMPARE(expr.changed, false);
496 QCOMPARE(expr.evaluate(), QVariant(6));
498 context.setContextProperty("testProp", QVariant(4));
499 QCOMPARE(expr.changed, true);
500 QCOMPARE(expr.evaluate(), QVariant(12));
504 MyExpression expr(&context, "testObj.stringProperty");
505 QCOMPARE(expr.changed, false);
506 QCOMPARE(expr.evaluate(), QVariant("Hello"));
508 context.setContextProperty("testObj", &object2);
509 QCOMPARE(expr.changed, true);
510 QCOMPARE(expr.evaluate(), QVariant("World"));
514 MyExpression expr(&context, "testObj.stringProperty /**/");
515 QCOMPARE(expr.changed, false);
516 QCOMPARE(expr.evaluate(), QVariant("World"));
518 context.setContextProperty("testObj", &object1);
519 QCOMPARE(expr.changed, true);
520 QCOMPARE(expr.evaluate(), QVariant("Hello"));
524 MyExpression expr(&context, "testObj2");
525 QCOMPARE(expr.changed, false);
526 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
532 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
534 QDeclarativeContext context(engine.rootContext());
538 context.setContextProperty("testObj", &object1);
540 object1.setStringProperty(QLatin1String("Hello"));
541 object2.setStringProperty(QLatin1String("Dog"));
542 object3.setStringProperty(QLatin1String("Cat"));
545 MyExpression expr(&context, "testObj.stringProperty");
546 QCOMPARE(expr.changed, false);
547 QCOMPARE(expr.evaluate(), QVariant("Hello"));
549 object1.setStringProperty(QLatin1String("World"));
550 QCOMPARE(expr.changed, true);
551 QCOMPARE(expr.evaluate(), QVariant("World"));
555 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
556 QCOMPARE(expr.changed, false);
557 QCOMPARE(expr.evaluate(), QVariant());
559 object1.setObjectProperty(&object2);
560 QCOMPARE(expr.changed, true);
561 expr.changed = false;
562 QCOMPARE(expr.evaluate(), QVariant("Dog"));
564 object1.setObjectProperty(&object3);
565 QCOMPARE(expr.changed, true);
566 expr.changed = false;
567 QCOMPARE(expr.evaluate(), QVariant("Cat"));
569 object1.setObjectProperty(0);
570 QCOMPARE(expr.changed, true);
571 expr.changed = false;
572 QCOMPARE(expr.evaluate(), QVariant());
574 object1.setObjectProperty(&object3);
575 QCOMPARE(expr.changed, true);
576 expr.changed = false;
577 QCOMPARE(expr.evaluate(), QVariant("Cat"));
579 object3.setStringProperty("Donkey");
580 QCOMPARE(expr.changed, true);
581 expr.changed = false;
582 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
586 void tst_qdeclarativeecmascript::deferredProperties()
588 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
589 MyDeferredObject *object =
590 qobject_cast<MyDeferredObject *>(component.create());
591 QVERIFY(object != 0);
592 QCOMPARE(object->value(), 0);
593 QVERIFY(object->objectProperty() == 0);
594 QVERIFY(object->objectProperty2() != 0);
595 qmlExecuteDeferred(object);
596 QCOMPARE(object->value(), 10);
597 QVERIFY(object->objectProperty() != 0);
598 MyQmlObject *qmlObject =
599 qobject_cast<MyQmlObject *>(object->objectProperty());
600 QVERIFY(qmlObject != 0);
601 QCOMPARE(qmlObject->value(), 10);
602 object->setValue(19);
603 QCOMPARE(qmlObject->value(), 19);
608 // Check errors on deferred properties are correctly emitted
609 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
611 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
612 MyDeferredObject *object =
613 qobject_cast<MyDeferredObject *>(component.create());
614 QVERIFY(object != 0);
615 QCOMPARE(object->value(), 0);
616 QVERIFY(object->objectProperty() == 0);
617 QVERIFY(object->objectProperty2() == 0);
619 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject* objectProperty";
620 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
622 qmlExecuteDeferred(object);
627 void tst_qdeclarativeecmascript::extensionObjects()
629 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
630 MyExtendedObject *object =
631 qobject_cast<MyExtendedObject *>(component.create());
632 QVERIFY(object != 0);
633 QCOMPARE(object->baseProperty(), 13);
634 QCOMPARE(object->coreProperty(), 9);
635 object->setProperty("extendedProperty", QVariant(11));
636 object->setProperty("baseExtendedProperty", QVariant(92));
637 QCOMPARE(object->coreProperty(), 11);
638 QCOMPARE(object->baseProperty(), 92);
640 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
642 QCOMPARE(nested->baseProperty(), 13);
643 QCOMPARE(nested->coreProperty(), 9);
644 nested->setProperty("extendedProperty", QVariant(11));
645 nested->setProperty("baseExtendedProperty", QVariant(92));
646 QCOMPARE(nested->coreProperty(), 11);
647 QCOMPARE(nested->baseProperty(), 92);
652 void tst_qdeclarativeecmascript::overrideExtensionProperties()
654 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
655 OverrideDefaultPropertyObject *object =
656 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
657 QVERIFY(object != 0);
658 QVERIFY(object->secondProperty() != 0);
659 QVERIFY(object->firstProperty() == 0);
664 void tst_qdeclarativeecmascript::attachedProperties()
667 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
668 QObject *object = component.create();
669 QVERIFY(object != 0);
670 QCOMPARE(object->property("a").toInt(), 19);
671 QCOMPARE(object->property("b").toInt(), 19);
672 QCOMPARE(object->property("c").toInt(), 19);
673 QCOMPARE(object->property("d").toInt(), 19);
678 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
679 QObject *object = component.create();
680 QVERIFY(object != 0);
681 QCOMPARE(object->property("a").toInt(), 26);
682 QCOMPARE(object->property("b").toInt(), 26);
683 QCOMPARE(object->property("c").toInt(), 26);
684 QCOMPARE(object->property("d").toInt(), 26);
688 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
689 QObject *object = component.create();
690 QVERIFY(object != 0);
692 QMetaObject::invokeMethod(object, "writeValue2");
694 MyQmlAttachedObject *attached =
695 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
696 QVERIFY(attached != 0);
698 QCOMPARE(attached->value2(), 9);
703 void tst_qdeclarativeecmascript::enums()
707 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
708 QObject *object = component.create();
709 QVERIFY(object != 0);
711 QCOMPARE(object->property("a").toInt(), 0);
712 QCOMPARE(object->property("b").toInt(), 1);
713 QCOMPARE(object->property("c").toInt(), 2);
714 QCOMPARE(object->property("d").toInt(), 3);
715 QCOMPARE(object->property("e").toInt(), 0);
716 QCOMPARE(object->property("f").toInt(), 1);
717 QCOMPARE(object->property("g").toInt(), 2);
718 QCOMPARE(object->property("h").toInt(), 3);
719 QCOMPARE(object->property("i").toInt(), 19);
720 QCOMPARE(object->property("j").toInt(), 19);
724 // Non-existent enums
726 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
728 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int a";
729 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int b";
730 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
731 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
733 QObject *object = component.create();
734 QVERIFY(object != 0);
735 QCOMPARE(object->property("a").toInt(), 0);
736 QCOMPARE(object->property("b").toInt(), 0);
742 void tst_qdeclarativeecmascript::valueTypeFunctions()
744 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
745 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
747 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
748 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
754 Tests that writing a constant to a property with a binding on it disables the
757 void tst_qdeclarativeecmascript::constantsOverrideBindings()
761 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
762 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
763 QVERIFY(object != 0);
765 QCOMPARE(object->property("c2").toInt(), 0);
766 object->setProperty("c1", QVariant(9));
767 QCOMPARE(object->property("c2").toInt(), 9);
769 emit object->basicSignal();
771 QCOMPARE(object->property("c2").toInt(), 13);
772 object->setProperty("c1", QVariant(8));
773 QCOMPARE(object->property("c2").toInt(), 13);
778 // During construction
780 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
781 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
782 QVERIFY(object != 0);
784 QCOMPARE(object->property("c1").toInt(), 0);
785 QCOMPARE(object->property("c2").toInt(), 10);
786 object->setProperty("c1", QVariant(9));
787 QCOMPARE(object->property("c1").toInt(), 9);
788 QCOMPARE(object->property("c2").toInt(), 10);
796 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
797 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
798 QVERIFY(object != 0);
800 QCOMPARE(object->property("c2").toInt(), 0);
801 object->setProperty("c1", QVariant(9));
802 QCOMPARE(object->property("c2").toInt(), 9);
804 object->setProperty("c2", QVariant(13));
805 QCOMPARE(object->property("c2").toInt(), 13);
806 object->setProperty("c1", QVariant(7));
807 QCOMPARE(object->property("c1").toInt(), 7);
808 QCOMPARE(object->property("c2").toInt(), 13);
816 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
817 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
818 QVERIFY(object != 0);
820 QCOMPARE(object->property("c1").toInt(), 0);
821 QCOMPARE(object->property("c3").toInt(), 10);
822 object->setProperty("c1", QVariant(9));
823 QCOMPARE(object->property("c1").toInt(), 9);
824 QCOMPARE(object->property("c3").toInt(), 10);
831 Tests that assigning a binding to a property that already has a binding causes
832 the original binding to be disabled.
834 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
836 QDeclarativeComponent component(&engine,
837 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
838 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
839 QVERIFY(object != 0);
841 QCOMPARE(object->property("c1").toInt(), 0);
842 QCOMPARE(object->property("c2").toInt(), 0);
843 QCOMPARE(object->property("c3").toInt(), 0);
845 object->setProperty("c1", QVariant(9));
846 QCOMPARE(object->property("c1").toInt(), 9);
847 QCOMPARE(object->property("c2").toInt(), 0);
848 QCOMPARE(object->property("c3").toInt(), 0);
850 object->setProperty("c3", QVariant(8));
851 QCOMPARE(object->property("c1").toInt(), 9);
852 QCOMPARE(object->property("c2").toInt(), 8);
853 QCOMPARE(object->property("c3").toInt(), 8);
859 Access a non-existent attached object.
861 Tests for a regression where this used to crash.
863 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
865 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
867 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString stringProperty";
868 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
870 QObject *object = component.create();
871 QVERIFY(object != 0);
876 void tst_qdeclarativeecmascript::scope()
879 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
880 QObject *object = component.create();
881 QVERIFY(object != 0);
883 QCOMPARE(object->property("test1").toInt(), 1);
884 QCOMPARE(object->property("test2").toInt(), 2);
885 QCOMPARE(object->property("test3").toString(), QString("1Test"));
886 QCOMPARE(object->property("test4").toString(), QString("2Test"));
887 QCOMPARE(object->property("test5").toInt(), 1);
888 QCOMPARE(object->property("test6").toInt(), 1);
889 QCOMPARE(object->property("test7").toInt(), 2);
890 QCOMPARE(object->property("test8").toInt(), 2);
891 QCOMPARE(object->property("test9").toInt(), 1);
892 QCOMPARE(object->property("test10").toInt(), 3);
898 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
899 QObject *object = component.create();
900 QVERIFY(object != 0);
902 QCOMPARE(object->property("test1").toInt(), 19);
903 QCOMPARE(object->property("test2").toInt(), 19);
904 QCOMPARE(object->property("test3").toInt(), 14);
905 QCOMPARE(object->property("test4").toInt(), 14);
906 QCOMPARE(object->property("test5").toInt(), 24);
907 QCOMPARE(object->property("test6").toInt(), 24);
913 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
914 QObject *object = component.create();
915 QVERIFY(object != 0);
917 QCOMPARE(object->property("test1").toBool(), true);
918 QCOMPARE(object->property("test2").toBool(), true);
919 QCOMPARE(object->property("test3").toBool(), true);
924 // Signal argument scope
926 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
927 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
928 QVERIFY(object != 0);
930 QCOMPARE(object->property("test").toInt(), 0);
931 QCOMPARE(object->property("test2").toString(), QString());
933 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
935 QCOMPARE(object->property("test").toInt(), 13);
936 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
942 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
943 QObject *object = component.create();
944 QVERIFY(object != 0);
946 QCOMPARE(object->property("test1").toBool(), true);
947 QCOMPARE(object->property("test2").toBool(), true);
953 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
954 QObject *object = component.create();
955 QVERIFY(object != 0);
957 QCOMPARE(object->property("test").toBool(), true);
963 // In 4.7, non-library javascript files that had no imports shared the imports of their
965 void tst_qdeclarativeecmascript::importScope()
967 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
968 QObject *o = component.create();
971 QCOMPARE(o->property("test").toInt(), 240);
977 Tests that "any" type passes through a synthesized signal parameter. This
978 is essentially a test of QDeclarativeMetaType::copy()
980 void tst_qdeclarativeecmascript::signalParameterTypes()
982 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
983 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
984 QVERIFY(object != 0);
986 emit object->basicSignal();
988 QCOMPARE(object->property("intProperty").toInt(), 10);
989 QCOMPARE(object->property("realProperty").toReal(), 19.2);
990 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
991 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
992 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
993 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
999 Test that two JS objects for the same QObject compare as equal.
1001 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1003 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1004 QObject *object = component.create();
1005 QVERIFY(object != 0);
1007 QCOMPARE(object->property("test1").toBool(), true);
1008 QCOMPARE(object->property("test2").toBool(), true);
1009 QCOMPARE(object->property("test3").toBool(), true);
1010 QCOMPARE(object->property("test4").toBool(), true);
1011 QCOMPARE(object->property("test5").toBool(), true);
1017 Confirm bindings and alias properties can coexist.
1019 Tests for a regression where the binding would not reevaluate.
1021 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1023 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1024 QObject *object = component.create();
1025 QVERIFY(object != 0);
1027 QCOMPARE(object->property("c2").toInt(), 3);
1028 QCOMPARE(object->property("c3").toInt(), 3);
1030 object->setProperty("c2", QVariant(19));
1032 QCOMPARE(object->property("c2").toInt(), 19);
1033 QCOMPARE(object->property("c3").toInt(), 19);
1038 void tst_qdeclarativeecmascript::dynamicCreation_data()
1040 QTest::addColumn<QString>("method");
1041 QTest::addColumn<QString>("createdName");
1043 QTest::newRow("One") << "createOne" << "objectOne";
1044 QTest::newRow("Two") << "createTwo" << "objectTwo";
1045 QTest::newRow("Three") << "createThree" << "objectThree";
1049 Test using createQmlObject to dynamically generate an item
1050 Also using createComponent is tested.
1052 void tst_qdeclarativeecmascript::dynamicCreation()
1054 QFETCH(QString, method);
1055 QFETCH(QString, createdName);
1057 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1058 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1059 QVERIFY(object != 0);
1061 QMetaObject::invokeMethod(object, method.toUtf8());
1062 QObject *created = object->objectProperty();
1064 QCOMPARE(created->objectName(), createdName);
1070 Tests the destroy function
1072 void tst_qdeclarativeecmascript::dynamicDestruction()
1074 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1075 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1076 QVERIFY(object != 0);
1077 QDeclarativeGuard<QObject> createdQmlObject = 0;
1079 QMetaObject::invokeMethod(object, "create");
1080 createdQmlObject = object->objectProperty();
1081 QVERIFY(createdQmlObject);
1082 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1084 QMetaObject::invokeMethod(object, "killOther");
1085 QVERIFY(createdQmlObject);
1086 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1087 QVERIFY(createdQmlObject);
1088 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1089 if (createdQmlObject) {
1091 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1094 QVERIFY(!createdQmlObject);
1096 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1097 QMetaObject::invokeMethod(object, "killMe");
1100 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1105 tests that id.toString() works
1107 void tst_qdeclarativeecmascript::objectToString()
1109 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1110 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1111 QVERIFY(object != 0);
1112 QMetaObject::invokeMethod(object, "testToString");
1113 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1114 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1120 Tests bindings that indirectly cause their own deletion work.
1122 This test is best run under valgrind to ensure no invalid memory access occur.
1124 void tst_qdeclarativeecmascript::selfDeletingBinding()
1127 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1128 QObject *object = component.create();
1129 QVERIFY(object != 0);
1130 object->setProperty("triggerDelete", true);
1135 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1136 QObject *object = component.create();
1137 QVERIFY(object != 0);
1138 object->setProperty("triggerDelete", true);
1144 Test that extended object properties can be accessed.
1146 This test a regression where this used to crash. The issue was specificially
1147 for extended objects that did not include a synthesized meta object (so non-root
1148 and no synthesiszed properties).
1150 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1152 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1153 QObject *object = component.create();
1154 QVERIFY(object != 0);
1159 Test file/lineNumbers for binding/Script errors.
1161 void tst_qdeclarativeecmascript::scriptErrors()
1163 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1164 QString url = component.url().toString();
1166 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1167 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1168 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1169 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1170 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1171 QString warning6 = url + ":7: Unable to assign [undefined] to int x";
1172 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1173 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1175 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1176 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1177 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1178 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1179 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1180 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1181 QVERIFY(object != 0);
1183 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1184 emit object->basicSignal();
1186 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1187 emit object->anotherBasicSignal();
1189 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1190 emit object->thirdBasicSignal();
1196 Test file/lineNumbers for inline functions.
1198 void tst_qdeclarativeecmascript::functionErrors()
1200 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1201 QString url = component.url().toString();
1203 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1205 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1207 QObject *object = component.create();
1208 QVERIFY(object != 0);
1211 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1212 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1213 url = componentTwo.url().toString();
1214 object = componentTwo.create();
1215 QVERIFY(object != 0);
1217 QString srpname = object->property("srp_name").toString();
1219 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1220 QLatin1String(" is not a function");
1221 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1222 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1227 Test various errors that can occur when assigning a property from script
1229 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1231 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1233 QString url = component.url().toString();
1235 QObject *object = component.create();
1236 QVERIFY(object != 0);
1238 QCOMPARE(object->property("test1").toBool(), true);
1239 QCOMPARE(object->property("test2").toBool(), true);
1245 Test bindings still work when the reeval is triggered from within
1248 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1250 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1251 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1252 QVERIFY(object != 0);
1254 QCOMPARE(object->property("base").toReal(), 50.);
1255 QCOMPARE(object->property("test1").toReal(), 50.);
1256 QCOMPARE(object->property("test2").toReal(), 50.);
1258 object->basicSignal();
1260 QCOMPARE(object->property("base").toReal(), 200.);
1261 QCOMPARE(object->property("test1").toReal(), 200.);
1262 QCOMPARE(object->property("test2").toReal(), 200.);
1264 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1266 QCOMPARE(object->property("base").toReal(), 400.);
1267 QCOMPARE(object->property("test1").toReal(), 400.);
1268 QCOMPARE(object->property("test2").toReal(), 400.);
1274 Test that list properties can be iterated from ECMAScript
1276 void tst_qdeclarativeecmascript::listProperties()
1278 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1279 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1280 QVERIFY(object != 0);
1282 QCOMPARE(object->property("test1").toInt(), 21);
1283 QCOMPARE(object->property("test2").toInt(), 2);
1284 QCOMPARE(object->property("test3").toBool(), true);
1285 QCOMPARE(object->property("test4").toBool(), true);
1290 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1292 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1293 QString url = component.url().toString();
1295 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1297 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1298 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1299 QVERIFY(object != 0);
1301 QCOMPARE(object->property("test").toBool(), false);
1303 MyQmlObject object2;
1304 MyQmlObject object3;
1305 object2.setObjectProperty(&object3);
1306 object->setObjectProperty(&object2);
1308 QCOMPARE(object->property("test").toBool(), true);
1313 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1315 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1316 QString url = component.url().toString();
1318 QString warning = component.url().toString() + ":6: Error: JS exception";
1320 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1321 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1322 QVERIFY(object != 0);
1326 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1328 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1329 QString url = component.url().toString();
1331 QString warning = component.url().toString() + ":5: Error: JS exception";
1333 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1334 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1335 QVERIFY(object != 0);
1339 static int transientErrorsMsgCount = 0;
1340 static void transientErrorsMsgHandler(QtMsgType, const char *)
1342 ++transientErrorsMsgCount;
1345 // Check that transient binding errors are not displayed
1346 void tst_qdeclarativeecmascript::transientErrors()
1349 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1351 transientErrorsMsgCount = 0;
1352 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1354 QObject *object = component.create();
1355 QVERIFY(object != 0);
1357 qInstallMsgHandler(old);
1359 QCOMPARE(transientErrorsMsgCount, 0);
1364 // One binding erroring multiple times, but then resolving
1366 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1368 transientErrorsMsgCount = 0;
1369 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1371 QObject *object = component.create();
1372 QVERIFY(object != 0);
1374 qInstallMsgHandler(old);
1376 QCOMPARE(transientErrorsMsgCount, 0);
1382 // Check that errors during shutdown are minimized
1383 void tst_qdeclarativeecmascript::shutdownErrors()
1385 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1386 QObject *object = component.create();
1387 QVERIFY(object != 0);
1389 transientErrorsMsgCount = 0;
1390 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1394 qInstallMsgHandler(old);
1395 QCOMPARE(transientErrorsMsgCount, 0);
1398 void tst_qdeclarativeecmascript::compositePropertyType()
1400 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1401 QTest::ignoreMessage(QtDebugMsg, "hello world");
1402 QObject *object = qobject_cast<QObject *>(component.create());
1407 void tst_qdeclarativeecmascript::jsObject()
1409 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1410 QObject *object = component.create();
1411 QVERIFY(object != 0);
1413 QCOMPARE(object->property("test").toInt(), 92);
1418 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1421 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1422 QObject *object = component.create();
1423 QVERIFY(object != 0);
1425 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1427 object->setProperty("setUndefined", true);
1429 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1431 object->setProperty("setUndefined", false);
1433 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1438 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1439 QObject *object = component.create();
1440 QVERIFY(object != 0);
1442 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1444 QMetaObject::invokeMethod(object, "doReset");
1446 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1453 void tst_qdeclarativeecmascript::bug1()
1455 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1456 QObject *object = component.create();
1457 QVERIFY(object != 0);
1459 QCOMPARE(object->property("test").toInt(), 14);
1461 object->setProperty("a", 11);
1463 QCOMPARE(object->property("test").toInt(), 3);
1465 object->setProperty("b", true);
1467 QCOMPARE(object->property("test").toInt(), 9);
1472 void tst_qdeclarativeecmascript::bug2()
1474 QDeclarativeComponent component(&engine);
1475 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1477 QObject *object = component.create();
1478 QVERIFY(object != 0);
1483 // Don't crash in createObject when the component has errors.
1484 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1486 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1487 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1488 QVERIFY(object != 0);
1490 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1491 QMetaObject::invokeMethod(object, "dontCrash");
1492 QObject *created = object->objectProperty();
1493 QVERIFY(created == 0);
1499 void tst_qdeclarativeecmascript::regExpBug()
1501 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1502 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1503 QVERIFY(object != 0);
1504 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1508 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1510 QString functionSource = QLatin1String("(function(object) { return ") +
1511 QLatin1String(source) + QLatin1String(" })");
1513 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1516 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1517 if (function.IsEmpty())
1519 v8::Handle<v8::Value> args[] = { o };
1520 function->Call(engine->global(), 1, args);
1521 return tc.HasCaught();
1524 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1525 const char *source, v8::Handle<v8::Value> result)
1527 QString functionSource = QLatin1String("(function(object) { return ") +
1528 QLatin1String(source) + QLatin1String(" })");
1530 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1533 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1534 if (function.IsEmpty())
1536 v8::Handle<v8::Value> args[] = { o };
1538 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1543 return value->StrictEquals(result);
1546 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1549 QString functionSource = QLatin1String("(function(object) { return ") +
1550 QLatin1String(source) + QLatin1String(" })");
1552 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1554 return v8::Handle<v8::Value>();
1555 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1556 if (function.IsEmpty())
1557 return v8::Handle<v8::Value>();
1558 v8::Handle<v8::Value> args[] = { o };
1560 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1563 return v8::Handle<v8::Value>();
1567 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1568 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1569 #define EVALUATE(source) evaluate(engine, object, source)
1571 void tst_qdeclarativeecmascript::callQtInvokables()
1573 MyInvokableObject o;
1575 QDeclarativeEngine qmlengine;
1576 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1578 QV8Engine *engine = &ep->v8engine;
1580 v8::HandleScope handle_scope;
1581 v8::Context::Scope scope(engine->context());
1583 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1585 // Non-existent methods
1587 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1588 QCOMPARE(o.error(), false);
1589 QCOMPARE(o.invoked(), -1);
1590 QCOMPARE(o.actuals().count(), 0);
1593 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1594 QCOMPARE(o.error(), false);
1595 QCOMPARE(o.invoked(), -1);
1596 QCOMPARE(o.actuals().count(), 0);
1598 // Insufficient arguments
1600 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1601 QCOMPARE(o.error(), false);
1602 QCOMPARE(o.invoked(), -1);
1603 QCOMPARE(o.actuals().count(), 0);
1606 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1607 QCOMPARE(o.error(), false);
1608 QCOMPARE(o.invoked(), -1);
1609 QCOMPARE(o.actuals().count(), 0);
1611 // Excessive arguments
1613 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1614 QCOMPARE(o.error(), false);
1615 QCOMPARE(o.invoked(), 8);
1616 QCOMPARE(o.actuals().count(), 1);
1617 QCOMPARE(o.actuals().at(0), QVariant(10));
1620 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1621 QCOMPARE(o.error(), false);
1622 QCOMPARE(o.invoked(), 9);
1623 QCOMPARE(o.actuals().count(), 2);
1624 QCOMPARE(o.actuals().at(0), QVariant(10));
1625 QCOMPARE(o.actuals().at(1), QVariant(11));
1627 // Test return types
1629 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1630 QCOMPARE(o.error(), false);
1631 QCOMPARE(o.invoked(), 0);
1632 QCOMPARE(o.actuals().count(), 0);
1635 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1636 QCOMPARE(o.error(), false);
1637 QCOMPARE(o.invoked(), 1);
1638 QCOMPARE(o.actuals().count(), 0);
1641 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1642 QCOMPARE(o.error(), false);
1643 QCOMPARE(o.invoked(), 2);
1644 QCOMPARE(o.actuals().count(), 0);
1648 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1649 QVERIFY(!ret.IsEmpty());
1650 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1651 QCOMPARE(o.error(), false);
1652 QCOMPARE(o.invoked(), 3);
1653 QCOMPARE(o.actuals().count(), 0);
1658 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1659 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1660 QCOMPARE(o.error(), false);
1661 QCOMPARE(o.invoked(), 4);
1662 QCOMPARE(o.actuals().count(), 0);
1666 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1667 QCOMPARE(o.error(), false);
1668 QCOMPARE(o.invoked(), 5);
1669 QCOMPARE(o.actuals().count(), 0);
1671 // XXX enable once qml/qtscript integration is implemented
1675 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1676 QVERIFY(ret->IsString());
1677 QCOMPARE(engine->toString(ret), QString("Hello world"));
1678 QCOMPARE(o.error(), false);
1679 QCOMPARE(o.invoked(), 6);
1680 QCOMPARE(o.actuals().count(), 0);
1685 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1686 QCOMPARE(o.error(), false);
1687 QCOMPARE(o.invoked(), 7);
1688 QCOMPARE(o.actuals().count(), 0);
1692 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1693 QCOMPARE(o.error(), false);
1694 QCOMPARE(o.invoked(), 8);
1695 QCOMPARE(o.actuals().count(), 1);
1696 QCOMPARE(o.actuals().at(0), QVariant(94));
1699 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1700 QCOMPARE(o.error(), false);
1701 QCOMPARE(o.invoked(), 8);
1702 QCOMPARE(o.actuals().count(), 1);
1703 QCOMPARE(o.actuals().at(0), QVariant(94));
1706 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1707 QCOMPARE(o.error(), false);
1708 QCOMPARE(o.invoked(), 8);
1709 QCOMPARE(o.actuals().count(), 1);
1710 QCOMPARE(o.actuals().at(0), QVariant(0));
1713 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1714 QCOMPARE(o.error(), false);
1715 QCOMPARE(o.invoked(), 8);
1716 QCOMPARE(o.actuals().count(), 1);
1717 QCOMPARE(o.actuals().at(0), QVariant(0));
1720 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1721 QCOMPARE(o.error(), false);
1722 QCOMPARE(o.invoked(), 8);
1723 QCOMPARE(o.actuals().count(), 1);
1724 QCOMPARE(o.actuals().at(0), QVariant(0));
1727 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1728 QCOMPARE(o.error(), false);
1729 QCOMPARE(o.invoked(), 8);
1730 QCOMPARE(o.actuals().count(), 1);
1731 QCOMPARE(o.actuals().at(0), QVariant(0));
1734 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1735 QCOMPARE(o.error(), false);
1736 QCOMPARE(o.invoked(), 9);
1737 QCOMPARE(o.actuals().count(), 2);
1738 QCOMPARE(o.actuals().at(0), QVariant(122));
1739 QCOMPARE(o.actuals().at(1), QVariant(9));
1742 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1743 QCOMPARE(o.error(), false);
1744 QCOMPARE(o.invoked(), 10);
1745 QCOMPARE(o.actuals().count(), 1);
1746 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1749 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1750 QCOMPARE(o.error(), false);
1751 QCOMPARE(o.invoked(), 10);
1752 QCOMPARE(o.actuals().count(), 1);
1753 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1756 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1757 QCOMPARE(o.error(), false);
1758 QCOMPARE(o.invoked(), 10);
1759 QCOMPARE(o.actuals().count(), 1);
1760 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1763 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1764 QCOMPARE(o.error(), false);
1765 QCOMPARE(o.invoked(), 10);
1766 QCOMPARE(o.actuals().count(), 1);
1767 QCOMPARE(o.actuals().at(0), QVariant(0));
1770 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1771 QCOMPARE(o.error(), false);
1772 QCOMPARE(o.invoked(), 10);
1773 QCOMPARE(o.actuals().count(), 1);
1774 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1777 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
1778 QCOMPARE(o.error(), false);
1779 QCOMPARE(o.invoked(), 10);
1780 QCOMPARE(o.actuals().count(), 1);
1781 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1784 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
1785 QCOMPARE(o.error(), false);
1786 QCOMPARE(o.invoked(), 11);
1787 QCOMPARE(o.actuals().count(), 1);
1788 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
1791 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
1792 QCOMPARE(o.error(), false);
1793 QCOMPARE(o.invoked(), 11);
1794 QCOMPARE(o.actuals().count(), 1);
1795 QCOMPARE(o.actuals().at(0), QVariant("19"));
1799 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
1800 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
1801 QCOMPARE(o.error(), false);
1802 QCOMPARE(o.invoked(), 11);
1803 QCOMPARE(o.actuals().count(), 1);
1804 QCOMPARE(o.actuals().at(0), QVariant(expected));
1808 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
1809 QCOMPARE(o.error(), false);
1810 QCOMPARE(o.invoked(), 11);
1811 QCOMPARE(o.actuals().count(), 1);
1812 QCOMPARE(o.actuals().at(0), QVariant(QString()));
1815 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
1816 QCOMPARE(o.error(), false);
1817 QCOMPARE(o.invoked(), 11);
1818 QCOMPARE(o.actuals().count(), 1);
1819 QCOMPARE(o.actuals().at(0), QVariant(QString()));
1822 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
1823 QCOMPARE(o.error(), false);
1824 QCOMPARE(o.invoked(), 12);
1825 QCOMPARE(o.actuals().count(), 1);
1826 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1829 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
1830 QCOMPARE(o.error(), false);
1831 QCOMPARE(o.invoked(), 12);
1832 QCOMPARE(o.actuals().count(), 1);
1833 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1836 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
1837 QCOMPARE(o.error(), false);
1838 QCOMPARE(o.invoked(), 12);
1839 QCOMPARE(o.actuals().count(), 1);
1840 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1843 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
1844 QCOMPARE(o.error(), false);
1845 QCOMPARE(o.invoked(), 12);
1846 QCOMPARE(o.actuals().count(), 1);
1847 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1850 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
1851 QCOMPARE(o.error(), false);
1852 QCOMPARE(o.invoked(), 12);
1853 QCOMPARE(o.actuals().count(), 1);
1854 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
1857 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
1858 QCOMPARE(o.error(), false);
1859 QCOMPARE(o.invoked(), 12);
1860 QCOMPARE(o.actuals().count(), 1);
1861 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
1864 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
1865 QCOMPARE(o.error(), false);
1866 QCOMPARE(o.invoked(), 13);
1867 QCOMPARE(o.actuals().count(), 1);
1868 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1871 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
1872 QCOMPARE(o.error(), false);
1873 QCOMPARE(o.invoked(), 13);
1874 QCOMPARE(o.actuals().count(), 1);
1875 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1878 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
1879 QCOMPARE(o.error(), false);
1880 QCOMPARE(o.invoked(), 13);
1881 QCOMPARE(o.actuals().count(), 1);
1882 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1885 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
1886 QCOMPARE(o.error(), false);
1887 QCOMPARE(o.invoked(), 13);
1888 QCOMPARE(o.actuals().count(), 1);
1889 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1892 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
1893 QCOMPARE(o.error(), false);
1894 QCOMPARE(o.invoked(), 13);
1895 QCOMPARE(o.actuals().count(), 1);
1896 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
1898 // XXX enable once qml/qtscript integration is implemented
1901 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
1902 QCOMPARE(o.error(), false);
1903 QCOMPARE(o.invoked(), 14);
1904 QCOMPARE(o.actuals().count(), 1);
1905 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isNull());
1908 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
1909 QCOMPARE(o.error(), false);
1910 QCOMPARE(o.invoked(), 14);
1911 QCOMPARE(o.actuals().count(), 1);
1912 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isUndefined());
1915 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
1916 QCOMPARE(o.error(), false);
1917 QCOMPARE(o.invoked(), 14);
1918 QCOMPARE(o.actuals().count(), 1);
1919 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).strictlyEquals(QScriptValue(engine, 19)));
1922 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
1923 QCOMPARE(o.error(), false);
1924 QCOMPARE(o.invoked(), 14);
1925 QCOMPARE(o.actuals().count(), 1);
1926 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isArray());
1929 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
1930 QCOMPARE(o.error(), false);
1931 QCOMPARE(o.invoked(), 15);
1932 QCOMPARE(o.actuals().count(), 2);
1933 QCOMPARE(o.actuals().at(0), QVariant(4));
1934 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isNull());
1937 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
1938 QCOMPARE(o.error(), false);
1939 QCOMPARE(o.invoked(), 15);
1940 QCOMPARE(o.actuals().count(), 2);
1941 QCOMPARE(o.actuals().at(0), QVariant(8));
1942 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isUndefined());
1945 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
1946 QCOMPARE(o.error(), false);
1947 QCOMPARE(o.invoked(), 15);
1948 QCOMPARE(o.actuals().count(), 2);
1949 QCOMPARE(o.actuals().at(0), QVariant(3));
1950 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).strictlyEquals(QScriptValue(engine, 19)));
1953 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
1954 QCOMPARE(o.error(), false);
1955 QCOMPARE(o.invoked(), 15);
1956 QCOMPARE(o.actuals().count(), 2);
1957 QCOMPARE(o.actuals().at(0), QVariant(44));
1958 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isArray());
1962 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
1963 QCOMPARE(o.error(), false);
1964 QCOMPARE(o.invoked(), -1);
1965 QCOMPARE(o.actuals().count(), 0);
1968 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
1969 QCOMPARE(o.error(), false);
1970 QCOMPARE(o.invoked(), 16);
1971 QCOMPARE(o.actuals().count(), 1);
1972 QCOMPARE(o.actuals().at(0), QVariant(10));
1975 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
1976 QCOMPARE(o.error(), false);
1977 QCOMPARE(o.invoked(), 17);
1978 QCOMPARE(o.actuals().count(), 2);
1979 QCOMPARE(o.actuals().at(0), QVariant(10));
1980 QCOMPARE(o.actuals().at(1), QVariant(11));
1983 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
1984 QCOMPARE(o.error(), false);
1985 QCOMPARE(o.invoked(), 18);
1986 QCOMPARE(o.actuals().count(), 1);
1987 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
1990 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
1991 QCOMPARE(o.error(), false);
1992 QCOMPARE(o.invoked(), 19);
1993 QCOMPARE(o.actuals().count(), 1);
1994 QCOMPARE(o.actuals().at(0), QVariant(9));
1997 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
1998 QCOMPARE(o.error(), false);
1999 QCOMPARE(o.invoked(), 20);
2000 QCOMPARE(o.actuals().count(), 2);
2001 QCOMPARE(o.actuals().at(0), QVariant(10));
2002 QCOMPARE(o.actuals().at(1), QVariant(19));
2005 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2006 QCOMPARE(o.error(), false);
2007 QCOMPARE(o.invoked(), 20);
2008 QCOMPARE(o.actuals().count(), 2);
2009 QCOMPARE(o.actuals().at(0), QVariant(10));
2010 QCOMPARE(o.actuals().at(1), QVariant(13));
2013 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2014 QCOMPARE(o.error(), false);
2015 QCOMPARE(o.invoked(), -3);
2016 QCOMPARE(o.actuals().count(), 1);
2017 QCOMPARE(o.actuals().at(0), QVariant(9));
2020 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2021 QCOMPARE(o.error(), false);
2022 QCOMPARE(o.invoked(), 21);
2023 QCOMPARE(o.actuals().count(), 2);
2024 QCOMPARE(o.actuals().at(0), QVariant(9));
2025 QCOMPARE(o.actuals().at(1), QVariant());
2028 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2029 QCOMPARE(o.error(), false);
2030 QCOMPARE(o.invoked(), 21);
2031 QCOMPARE(o.actuals().count(), 2);
2032 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2033 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2036 // QTBUG-13047 (check that you can pass registered object types as args)
2037 void tst_qdeclarativeecmascript::invokableObjectArg()
2039 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2041 QObject *o = component.create();
2043 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2045 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2050 // QTBUG-13047 (check that you can return registered object types from methods)
2051 void tst_qdeclarativeecmascript::invokableObjectRet()
2053 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2055 QObject *o = component.create();
2057 QCOMPARE(o->property("test").toBool(), true);
2062 void tst_qdeclarativeecmascript::listToVariant()
2064 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2066 MyQmlContainer container;
2068 QDeclarativeContext context(engine.rootContext());
2069 context.setContextObject(&container);
2071 QObject *object = component.create(&context);
2072 QVERIFY(object != 0);
2074 QVariant v = object->property("test");
2075 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2076 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2082 void tst_qdeclarativeecmascript::multiEngineObject()
2085 obj.setStringProperty("Howdy planet");
2087 QDeclarativeEngine e1;
2088 e1.rootContext()->setContextProperty("thing", &obj);
2089 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2091 QDeclarativeEngine e2;
2092 e2.rootContext()->setContextProperty("thing", &obj);
2093 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2095 QObject *o1 = c1.create();
2096 QObject *o2 = c2.create();
2098 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2099 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2105 // Test that references to QObjects are cleanup when the object is destroyed
2106 void tst_qdeclarativeecmascript::deletedObject()
2108 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2110 QObject *object = component.create();
2112 QCOMPARE(object->property("test1").toBool(), true);
2113 QCOMPARE(object->property("test2").toBool(), true);
2114 QCOMPARE(object->property("test3").toBool(), true);
2115 QCOMPARE(object->property("test4").toBool(), true);
2120 void tst_qdeclarativeecmascript::attachedPropertyScope()
2122 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2124 QObject *object = component.create();
2125 QVERIFY(object != 0);
2127 MyQmlAttachedObject *attached =
2128 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2129 QVERIFY(attached != 0);
2131 QCOMPARE(object->property("value2").toInt(), 0);
2133 attached->emitMySignal();
2135 QCOMPARE(object->property("value2").toInt(), 9);
2140 void tst_qdeclarativeecmascript::scriptConnect()
2143 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2145 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2146 QVERIFY(object != 0);
2148 QCOMPARE(object->property("test").toBool(), false);
2149 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2150 QCOMPARE(object->property("test").toBool(), true);
2156 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2158 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2159 QVERIFY(object != 0);
2161 QCOMPARE(object->property("test").toBool(), false);
2162 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2163 QCOMPARE(object->property("test").toBool(), true);
2169 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2171 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2172 QVERIFY(object != 0);
2174 QCOMPARE(object->property("test").toBool(), false);
2175 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2176 QCOMPARE(object->property("test").toBool(), true);
2182 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2184 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2185 QVERIFY(object != 0);
2187 QCOMPARE(object->methodCalled(), false);
2188 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2189 QCOMPARE(object->methodCalled(), true);
2195 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2197 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2198 QVERIFY(object != 0);
2200 QCOMPARE(object->methodCalled(), false);
2201 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2202 QCOMPARE(object->methodCalled(), true);
2208 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2210 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2211 QVERIFY(object != 0);
2213 QCOMPARE(object->property("test").toInt(), 0);
2214 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2215 QCOMPARE(object->property("test").toInt(), 2);
2221 void tst_qdeclarativeecmascript::scriptDisconnect()
2224 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2226 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2227 QVERIFY(object != 0);
2229 QCOMPARE(object->property("test").toInt(), 0);
2230 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2231 QCOMPARE(object->property("test").toInt(), 1);
2232 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2233 QCOMPARE(object->property("test").toInt(), 2);
2234 emit object->basicSignal();
2235 QCOMPARE(object->property("test").toInt(), 2);
2236 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2237 QCOMPARE(object->property("test").toInt(), 2);
2243 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2245 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2246 QVERIFY(object != 0);
2248 QCOMPARE(object->property("test").toInt(), 0);
2249 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2250 QCOMPARE(object->property("test").toInt(), 1);
2251 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2252 QCOMPARE(object->property("test").toInt(), 2);
2253 emit object->basicSignal();
2254 QCOMPARE(object->property("test").toInt(), 2);
2255 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2256 QCOMPARE(object->property("test").toInt(), 2);
2262 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2264 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2265 QVERIFY(object != 0);
2267 QCOMPARE(object->property("test").toInt(), 0);
2268 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2269 QCOMPARE(object->property("test").toInt(), 1);
2270 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2271 QCOMPARE(object->property("test").toInt(), 2);
2272 emit object->basicSignal();
2273 QCOMPARE(object->property("test").toInt(), 2);
2274 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2275 QCOMPARE(object->property("test").toInt(), 3);
2280 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2282 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2283 QVERIFY(object != 0);
2285 QCOMPARE(object->property("test").toInt(), 0);
2286 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2287 QCOMPARE(object->property("test").toInt(), 1);
2288 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2289 QCOMPARE(object->property("test").toInt(), 2);
2290 emit object->basicSignal();
2291 QCOMPARE(object->property("test").toInt(), 2);
2292 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2293 QCOMPARE(object->property("test").toInt(), 3);
2299 class OwnershipObject : public QObject
2303 OwnershipObject() { object = new QObject; }
2305 QPointer<QObject> object;
2308 QObject *getObject() { return object; }
2311 void tst_qdeclarativeecmascript::ownership()
2313 OwnershipObject own;
2314 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2315 context->setContextObject(&own);
2318 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2320 QVERIFY(own.object != 0);
2322 QObject *object = component.create(context);
2324 engine.collectGarbage();
2326 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2328 QVERIFY(own.object == 0);
2333 own.object = new QObject(&own);
2336 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2338 QVERIFY(own.object != 0);
2340 QObject *object = component.create(context);
2342 engine.collectGarbage();
2344 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2346 QVERIFY(own.object != 0);
2354 class CppOwnershipReturnValue : public QObject
2358 CppOwnershipReturnValue() : value(0) {}
2359 ~CppOwnershipReturnValue() { delete value; }
2361 Q_INVOKABLE QObject *create() {
2362 value = new QObject;
2363 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2367 Q_INVOKABLE MyQmlObject *createQmlObject() {
2368 MyQmlObject *rv = new MyQmlObject;
2373 QPointer<QObject> value;
2377 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2378 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2380 CppOwnershipReturnValue source;
2383 QDeclarativeEngine engine;
2384 engine.rootContext()->setContextProperty("source", &source);
2386 QVERIFY(source.value == 0);
2388 QDeclarativeComponent component(&engine);
2389 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2391 QObject *object = component.create();
2393 QVERIFY(object != 0);
2394 QVERIFY(source.value != 0);
2399 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2401 QVERIFY(source.value != 0);
2405 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2407 CppOwnershipReturnValue source;
2410 QDeclarativeEngine engine;
2411 engine.rootContext()->setContextProperty("source", &source);
2413 QVERIFY(source.value == 0);
2415 QDeclarativeComponent component(&engine);
2416 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2418 QObject *object = component.create();
2420 QVERIFY(object != 0);
2421 QVERIFY(source.value != 0);
2426 engine.collectGarbage();
2427 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2429 QVERIFY(source.value == 0);
2432 class QListQObjectMethodsObject : public QObject
2436 QListQObjectMethodsObject() {
2437 m_objects.append(new MyQmlObject());
2438 m_objects.append(new MyQmlObject());
2441 ~QListQObjectMethodsObject() {
2442 qDeleteAll(m_objects);
2446 QList<QObject *> getObjects() { return m_objects; }
2449 QList<QObject *> m_objects;
2452 // Tests that returning a QList<QObject*> from a method works
2453 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2455 QListQObjectMethodsObject obj;
2456 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2457 context->setContextObject(&obj);
2459 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2461 QObject *object = component.create(context);
2463 QCOMPARE(object->property("test").toInt(), 2);
2464 QCOMPARE(object->property("test2").toBool(), true);
2471 void tst_qdeclarativeecmascript::strictlyEquals()
2473 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2475 QObject *object = component.create();
2476 QVERIFY(object != 0);
2478 QCOMPARE(object->property("test1").toBool(), true);
2479 QCOMPARE(object->property("test2").toBool(), true);
2480 QCOMPARE(object->property("test3").toBool(), true);
2481 QCOMPARE(object->property("test4").toBool(), true);
2482 QCOMPARE(object->property("test5").toBool(), true);
2483 QCOMPARE(object->property("test6").toBool(), true);
2484 QCOMPARE(object->property("test7").toBool(), true);
2485 QCOMPARE(object->property("test8").toBool(), true);
2490 void tst_qdeclarativeecmascript::compiled()
2492 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2494 QObject *object = component.create();
2495 QVERIFY(object != 0);
2497 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2498 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2499 QCOMPARE(object->property("test3").toBool(), true);
2500 QCOMPARE(object->property("test4").toBool(), false);
2501 QCOMPARE(object->property("test5").toBool(), false);
2502 QCOMPARE(object->property("test6").toBool(), true);
2504 QCOMPARE(object->property("test7").toInt(), 185);
2505 QCOMPARE(object->property("test8").toInt(), 167);
2506 QCOMPARE(object->property("test9").toBool(), true);
2507 QCOMPARE(object->property("test10").toBool(), false);
2508 QCOMPARE(object->property("test11").toBool(), false);
2509 QCOMPARE(object->property("test12").toBool(), true);
2511 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2512 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2513 QCOMPARE(object->property("test15").toBool(), false);
2514 QCOMPARE(object->property("test16").toBool(), true);
2516 QCOMPARE(object->property("test17").toInt(), 5);
2517 QCOMPARE(object->property("test18").toReal(), qreal(176));
2518 QCOMPARE(object->property("test19").toInt(), 7);
2519 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2520 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2521 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2522 QCOMPARE(object->property("test23").toBool(), true);
2523 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2524 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2529 // Test that numbers assigned in bindings as strings work consistently
2530 void tst_qdeclarativeecmascript::numberAssignment()
2532 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2534 QObject *object = component.create();
2535 QVERIFY(object != 0);
2537 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2538 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2539 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2540 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2541 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2543 QCOMPARE(object->property("test5"), QVariant((int)7));
2544 QCOMPARE(object->property("test6"), QVariant((int)7));
2545 QCOMPARE(object->property("test7"), QVariant((int)6));
2546 QCOMPARE(object->property("test8"), QVariant((int)6));
2548 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2549 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2550 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2551 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2556 void tst_qdeclarativeecmascript::propertySplicing()
2558 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2560 QObject *object = component.create();
2561 QVERIFY(object != 0);
2563 QCOMPARE(object->property("test").toBool(), true);
2569 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2571 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2573 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2574 QVERIFY(object != 0);
2576 MyQmlObject::MyType type;
2577 type.value = 0x8971123;
2578 emit object->signalWithUnknownType(type);
2580 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2582 QCOMPARE(result.value, type.value);
2588 void tst_qdeclarativeecmascript::moduleApi()
2590 QDeclarativeComponent component(&engine, TEST_FILE("moduleApi.qml"));
2591 QObject *object = component.create();
2592 QVERIFY(object != 0);
2593 QCOMPARE(object->property("existingUriTest").toInt(), 20);
2595 QEXPECT_FAIL("", "QTBUG-17318", Continue);
2596 QCOMPARE(object->property("scriptTest").toInt(), 13);
2597 QCOMPARE(object->property("qobjectTest").toInt(), 20);
2598 QCOMPARE(object->property("qobjectMethodTest").toInt(), 1); // first call of method, so count = 1.
2599 QCOMPARE(object->property("qobjectMinorVersionTest").toInt(), 20);
2600 QCOMPARE(object->property("qobjectMajorVersionTest").toInt(), 20);
2601 QCOMPARE(object->property("qobjectParentedTest").toInt(), 26);
2604 // test that caching of module apis works correctly.
2605 QDeclarativeComponent componentTwo(&engine, TEST_FILE("moduleApiCaching.qml"));
2606 object = componentTwo.create();
2607 QVERIFY(object != 0);
2608 QCOMPARE(object->property("existingUriTest").toInt(), 20);
2609 QEXPECT_FAIL("", "QTBUG-17318", Continue);
2610 QCOMPARE(object->property("scriptTest").toInt(), 13); // shouldn't have incremented.
2611 QCOMPARE(object->property("qobjectParentedTest").toInt(), 26); // shouldn't have incremented.
2614 // test that writing to a property of module apis works correctly.
2615 QDeclarativeComponent componentThree(&engine, TEST_FILE("moduleApiWriting.qml"));
2616 QString expectedWarning = QLatin1String("file://") + TEST_FILE("moduleApiWriting.qml").toLocalFile() + QLatin1String(":15: Error: Cannot assign to read-only property \"qobjectTestProperty\"");
2617 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2618 object = componentThree.create();
2619 QVERIFY(object != 0);
2620 QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
2621 QCOMPARE(object->property("writableProperty").toInt(), 50);
2622 QVERIFY(object->setProperty("firstProperty", QVariant(30))); // shouldn't affect value of readOnlyProperty
2623 QVERIFY(object->setProperty("writableProperty", QVariant(30))); // SHOULD affect value of writableProperty
2624 QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
2625 QCOMPARE(object->property("writableProperty").toInt(), 30);
2628 QDeclarativeComponent failOne(&engine, TEST_FILE("moduleApiMajorVersionFail.qml"));
2629 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2630 object = failOne.create();
2631 QVERIFY(object == 0); // should have failed: invalid major version
2633 QDeclarativeComponent failTwo(&engine, TEST_FILE("moduleApiMinorVersionFail.qml"));
2634 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2635 object = failTwo.create();
2636 QVERIFY(object == 0); // should have failed: invalid minor version
2639 void tst_qdeclarativeecmascript::importScripts()
2641 QObject *object = 0;
2643 // first, ensure that the required behaviour works.
2644 QDeclarativeComponent component(&engine, TEST_FILE("jsimport/testImport.qml"));
2645 object = component.create();
2646 QVERIFY(object != 0);
2647 QCOMPARE(object->property("importedScriptStringValue"), QVariant(QString(QLatin1String("Hello, World!"))));
2648 QCOMPARE(object->property("importedScriptFunctionValue"), QVariant(20));
2649 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(19));
2650 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(2));
2653 QDeclarativeComponent componentTwo(&engine, TEST_FILE("jsimport/testImportScoping.qml"));
2654 object = componentTwo.create();
2655 QVERIFY(object != 0);
2656 QCOMPARE(object->property("componentError"), QVariant(5));
2659 // then, ensure that unintended behaviour does not work.
2660 QDeclarativeComponent failOneComponent(&engine, TEST_FILE("jsimportfail/failOne.qml"));
2661 QString expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined");
2662 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2663 object = failOneComponent.create();
2664 QVERIFY(object != 0);
2665 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2667 QDeclarativeComponent failTwoComponent(&engine, TEST_FILE("jsimportfail/failTwo.qml"));
2668 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs");
2669 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2670 object = failTwoComponent.create();
2671 QVERIFY(object != 0);
2672 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2674 QDeclarativeComponent failThreeComponent(&engine, TEST_FILE("jsimportfail/failThree.qml"));
2675 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined");
2676 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2677 object = failThreeComponent.create();
2678 QVERIFY(object != 0);
2679 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(false));
2681 QDeclarativeComponent failFourComponent(&engine, TEST_FILE("jsimportfail/failFour.qml"));
2682 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest");
2683 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2684 object = failFourComponent.create();
2685 QVERIFY(object != 0);
2686 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(0));
2688 QDeclarativeComponent failFiveComponent(&engine, TEST_FILE("jsimportfail/failFive.qml"));
2689 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component");
2690 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2691 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component");
2692 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2693 object = failFiveComponent.create();
2694 QVERIFY(object != 0);
2695 QCOMPARE(object->property("componentError"), QVariant(0));
2698 // also, test that importing scripts with .pragma library works as required
2699 QDeclarativeComponent pragmaLibraryComponent(&engine, TEST_FILE("jsimport/testImportPragmaLibrary.qml"));
2700 object = pragmaLibraryComponent.create();
2701 QVERIFY(object != 0);
2702 QCOMPARE(object->property("testValue"), QVariant(31));
2705 // and that .pragma library scripts don't inherit imports from any .qml file
2706 QDeclarativeComponent pragmaLibraryComponentTwo(&engine, TEST_FILE("jsimportfail/testImportPragmaLibrary.qml"));
2707 object = pragmaLibraryComponentTwo.create();
2708 QVERIFY(object != 0);
2709 QCOMPARE(object->property("testValue"), QVariant(0));
2713 void tst_qdeclarativeecmascript::scarceResources()
2715 QPixmap origPixmap(100, 100);
2716 origPixmap.fill(Qt::blue);
2718 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
2719 ScarceResourceObject *eo = 0;
2720 QObject *object = 0;
2722 // in the following three cases, the instance created from the component
2723 // has a property which is a copy of the scarce resource; hence, the
2724 // resource should NOT be detached prior to deletion of the object instance,
2725 // unless the resource is destroyed explicitly.
2726 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
2727 object = component.create();
2728 QVERIFY(object != 0);
2729 QVERIFY(object->property("scarceResourceCopy").isValid());
2730 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2731 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2732 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2733 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
2736 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
2737 object = componentTwo.create();
2738 QVERIFY(object != 0);
2739 QVERIFY(object->property("scarceResourceCopy").isValid());
2740 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2741 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2742 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2743 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
2746 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
2747 object = componentThree.create();
2748 QVERIFY(object != 0);
2749 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
2750 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2751 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2752 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
2755 // in the following three cases, no other copy should exist in memory,
2756 // and so it should be detached (unless explicitly preserved).
2757 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
2758 object = componentFour.create();
2759 QVERIFY(object != 0);
2760 QVERIFY(object->property("scarceResourceTest").isValid());
2761 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2762 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2763 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2764 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
2767 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
2768 object = componentFive.create();
2769 QVERIFY(object != 0);
2770 QVERIFY(object->property("scarceResourceTest").isValid());
2771 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2772 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2773 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2774 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
2777 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
2778 object = componentSix.create();
2779 QVERIFY(object != 0);
2780 QVERIFY(object->property("scarceResourceTest").isValid());
2781 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2782 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2783 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2784 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
2787 // test that scarce resources are handled correctly for imports
2788 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
2789 object = componentSeven.create();
2790 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
2791 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
2794 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
2795 object = componentEight.create();
2796 QVERIFY(object != 0);
2797 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
2798 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2801 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
2802 object = componentNine.create();
2803 QVERIFY(object != 0);
2804 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
2805 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2806 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
2807 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
2808 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
2809 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
2812 // test that scarce resources are handled properly in signal invocation
2813 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
2814 object = componentTen.create();
2815 QVERIFY(object != 0);
2816 QObject *srsc = object->findChild<QObject*>("srsc");
2818 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
2819 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
2820 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2821 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2822 QMetaObject::invokeMethod(srsc, "testSignal");
2823 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
2824 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
2825 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2826 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
2827 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
2828 QVERIFY(srsc->property("scarceResourceCopy").isValid());
2829 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2830 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2831 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
2832 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2835 // test that scarce resources are handled properly from js functions in qml files
2836 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
2837 object = componentEleven.create();
2838 QVERIFY(object != 0);
2839 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
2840 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2841 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2842 QMetaObject::invokeMethod(object, "retrieveScarceResource");
2843 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
2844 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2845 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2846 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
2847 QMetaObject::invokeMethod(object, "releaseScarceResource");
2848 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
2849 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2850 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2851 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2854 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
2855 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
2856 object = componentTwelve.create();
2857 QVERIFY(object != 0);
2858 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
2859 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2860 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2861 QString srp_name = object->property("srp_name").toString();
2862 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
2863 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
2864 QMetaObject::invokeMethod(object, "retrieveScarceResource");
2865 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
2866 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2867 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2868 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2872 void tst_qdeclarativeecmascript::propertyChangeSlots()
2874 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
2875 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
2876 QObject *object = component.create();
2877 QVERIFY(object != 0);
2880 // ensure that invalid property names fail properly.
2881 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2882 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
2883 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
2884 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
2885 object = e1.create();
2886 QVERIFY(object == 0);
2889 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2890 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
2891 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
2892 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
2893 object = e2.create();
2894 QVERIFY(object == 0);
2897 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2898 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
2899 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
2900 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
2901 object = e3.create();
2902 QVERIFY(object == 0);
2905 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2906 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
2907 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
2908 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
2909 object = e4.create();
2910 QVERIFY(object == 0);
2914 // Ensure that QObject type conversion works on binding assignment
2915 void tst_qdeclarativeecmascript::elementAssign()
2917 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
2919 QObject *object = component.create();
2920 QVERIFY(object != 0);
2922 QCOMPARE(object->property("test").toBool(), true);
2927 // Test that assigning a null object works
2928 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
2929 void tst_qdeclarativeecmascript::nullObjectBinding()
2931 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
2933 QObject *object = component.create();
2934 QVERIFY(object != 0);
2936 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
2941 // Test that bindings don't evaluate once the engine has been destroyed
2942 void tst_qdeclarativeecmascript::deletedEngine()
2944 QDeclarativeEngine *engine = new QDeclarativeEngine;
2945 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
2947 QObject *object = component.create();
2948 QVERIFY(object != 0);
2950 QCOMPARE(object->property("a").toInt(), 39);
2951 object->setProperty("b", QVariant(9));
2952 QCOMPARE(object->property("a").toInt(), 117);
2956 QCOMPARE(object->property("a").toInt(), 117);
2957 object->setProperty("b", QVariant(10));
2958 QCOMPARE(object->property("a").toInt(), 117);
2963 // Test the crashing part of QTBUG-9705
2964 void tst_qdeclarativeecmascript::libraryScriptAssert()
2966 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
2968 QObject *object = component.create();
2969 QVERIFY(object != 0);
2974 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
2976 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
2978 QObject *object = component.create();
2979 QVERIFY(object != 0);
2981 QCOMPARE(object->property("test1").toInt(), 10);
2982 QCOMPARE(object->property("test2").toInt(), 11);
2984 object->setProperty("runTest", true);
2986 QCOMPARE(object->property("test1"), QVariant());
2987 QCOMPARE(object->property("test2"), QVariant());
2993 void tst_qdeclarativeecmascript::qtbug_9792()
2995 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
2997 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2999 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
3000 QVERIFY(object != 0);
3002 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
3003 object->basicSignal();
3007 transientErrorsMsgCount = 0;
3008 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3010 object->basicSignal();
3012 qInstallMsgHandler(old);
3014 QCOMPARE(transientErrorsMsgCount, 0);
3019 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
3020 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
3022 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
3024 QObject *o = component.create();
3027 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
3028 QVERIFY(nested != 0);
3030 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
3033 nested = qvariant_cast<QObject *>(o->property("object"));
3034 QVERIFY(nested == 0);
3036 // If the bug is present, the next line will crash
3040 // Test that we shut down without stupid warnings
3041 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
3044 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
3046 QObject *o = component.create();
3048 transientErrorsMsgCount = 0;
3049 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3053 qInstallMsgHandler(old);
3055 QCOMPARE(transientErrorsMsgCount, 0);
3060 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
3062 QObject *o = component.create();
3064 transientErrorsMsgCount = 0;
3065 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3069 qInstallMsgHandler(old);
3071 QCOMPARE(transientErrorsMsgCount, 0);
3075 void tst_qdeclarativeecmascript::canAssignNullToQObject()
3078 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
3080 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3083 QVERIFY(o->objectProperty() != 0);
3085 o->setProperty("runTest", true);
3087 QVERIFY(o->objectProperty() == 0);
3093 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
3095 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3098 QVERIFY(o->objectProperty() == 0);
3104 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
3106 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
3108 QString url = component.url().toString();
3109 QString warning = url + ":4: Unable to assign a function to a property.";
3110 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3112 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3115 QVERIFY(!o->property("a").isValid());
3120 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
3122 QFETCH(QString, triggerProperty);
3124 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3125 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3127 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3129 QVERIFY(!o->property("a").isValid());
3131 o->setProperty("aNumber", QVariant(5));
3132 o->setProperty(triggerProperty.toUtf8().constData(), true);
3133 QCOMPARE(o->property("a"), QVariant(50));
3135 o->setProperty("aNumber", QVariant(10));
3136 QCOMPARE(o->property("a"), QVariant(100));
3141 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
3143 QTest::addColumn<QString>("triggerProperty");
3145 QTest::newRow("assign to property") << "assignToProperty";
3146 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
3148 QTest::newRow("assign to value type") << "assignToValueType";
3150 QTest::newRow("use 'this'") << "assignWithThis";
3151 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
3154 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
3156 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3157 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3159 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3161 QVERIFY(!o->property("a").isValid());
3163 o->setProperty("assignFuncWithoutReturn", true);
3164 QVERIFY(!o->property("a").isValid());
3166 QString url = component.url().toString();
3167 QString warning = url + ":67: Unable to assign QString to int";
3168 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3169 o->setProperty("assignWrongType", true);
3171 warning = url + ":71: Unable to assign QString to int";
3172 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3173 o->setProperty("assignWrongTypeToValueType", true);
3178 void tst_qdeclarativeecmascript::eval()
3180 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
3182 QObject *o = component.create();
3185 QCOMPARE(o->property("test1").toBool(), true);
3186 QCOMPARE(o->property("test2").toBool(), true);
3187 QCOMPARE(o->property("test3").toBool(), true);
3188 QCOMPARE(o->property("test4").toBool(), true);
3189 QCOMPARE(o->property("test5").toBool(), true);
3194 void tst_qdeclarativeecmascript::function()
3196 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
3198 QObject *o = component.create();
3201 QCOMPARE(o->property("test1").toBool(), true);
3202 QCOMPARE(o->property("test2").toBool(), true);
3203 QCOMPARE(o->property("test3").toBool(), true);
3208 // Test the "Qt.include" method
3209 void tst_qdeclarativeecmascript::include()
3211 // Non-library relative include
3213 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
3214 QObject *o = component.create();
3217 QCOMPARE(o->property("test0").toInt(), 99);
3218 QCOMPARE(o->property("test1").toBool(), true);
3219 QCOMPARE(o->property("test2").toBool(), true);
3220 QCOMPARE(o->property("test2_1").toBool(), true);
3221 QCOMPARE(o->property("test3").toBool(), true);
3222 QCOMPARE(o->property("test3_1").toBool(), true);
3227 // Library relative include
3229 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
3230 QObject *o = component.create();
3233 QCOMPARE(o->property("test0").toInt(), 99);
3234 QCOMPARE(o->property("test1").toBool(), true);
3235 QCOMPARE(o->property("test2").toBool(), true);
3236 QCOMPARE(o->property("test2_1").toBool(), true);
3237 QCOMPARE(o->property("test3").toBool(), true);
3238 QCOMPARE(o->property("test3_1").toBool(), true);
3245 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
3246 QObject *o = component.create();
3249 QCOMPARE(o->property("test1").toBool(), true);
3250 QCOMPARE(o->property("test2").toBool(), true);
3251 QCOMPARE(o->property("test3").toBool(), true);
3252 QCOMPARE(o->property("test4").toBool(), true);
3253 QCOMPARE(o->property("test5").toBool(), true);
3254 QCOMPARE(o->property("test6").toBool(), true);
3259 // Including file with ".pragma library"
3261 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
3262 QObject *o = component.create();
3264 QCOMPARE(o->property("test1").toInt(), 100);
3271 TestHTTPServer server(8111);
3272 QVERIFY(server.isValid());
3273 server.serveDirectory(SRCDIR "/data");
3275 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
3276 QObject *o = component.create();
3279 QTRY_VERIFY(o->property("done").toBool() == true);
3280 QTRY_VERIFY(o->property("done2").toBool() == true);
3282 QCOMPARE(o->property("test1").toBool(), true);
3283 QCOMPARE(o->property("test2").toBool(), true);
3284 QCOMPARE(o->property("test3").toBool(), true);
3285 QCOMPARE(o->property("test4").toBool(), true);
3286 QCOMPARE(o->property("test5").toBool(), true);
3288 QCOMPARE(o->property("test6").toBool(), true);
3289 QCOMPARE(o->property("test7").toBool(), true);
3290 QCOMPARE(o->property("test8").toBool(), true);
3291 QCOMPARE(o->property("test9").toBool(), true);
3292 QCOMPARE(o->property("test10").toBool(), true);
3299 TestHTTPServer server(8111);
3300 QVERIFY(server.isValid());
3301 server.serveDirectory(SRCDIR "/data");
3303 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
3304 QObject *o = component.create();
3307 QTRY_VERIFY(o->property("done").toBool() == true);
3309 QCOMPARE(o->property("test1").toBool(), true);
3310 QCOMPARE(o->property("test2").toBool(), true);
3311 QCOMPARE(o->property("test3").toBool(), true);
3317 void tst_qdeclarativeecmascript::qtbug_10696()
3319 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
3320 QObject *o = component.create();
3325 void tst_qdeclarativeecmascript::qtbug_11606()
3327 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
3328 QObject *o = component.create();
3330 QCOMPARE(o->property("test").toBool(), true);
3334 void tst_qdeclarativeecmascript::qtbug_11600()
3336 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
3337 QObject *o = component.create();
3339 QCOMPARE(o->property("test").toBool(), true);
3343 // Reading and writing non-scriptable properties should fail
3344 void tst_qdeclarativeecmascript::nonscriptable()
3346 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
3347 QObject *o = component.create();
3349 QCOMPARE(o->property("readOk").toBool(), true);
3350 QCOMPARE(o->property("writeOk").toBool(), true);
3354 // deleteLater() should not be callable from QML
3355 void tst_qdeclarativeecmascript::deleteLater()
3357 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
3358 QObject *o = component.create();
3360 QCOMPARE(o->property("test").toBool(), true);
3364 void tst_qdeclarativeecmascript::in()
3366 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
3367 QObject *o = component.create();
3369 QCOMPARE(o->property("test1").toBool(), true);
3370 QCOMPARE(o->property("test2").toBool(), true);
3374 void tst_qdeclarativeecmascript::sharedAttachedObject()
3376 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
3377 QObject *o = component.create();
3379 QCOMPARE(o->property("test1").toBool(), true);
3380 QCOMPARE(o->property("test2").toBool(), true);
3385 void tst_qdeclarativeecmascript::objectName()
3387 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
3388 QObject *o = component.create();
3391 QCOMPARE(o->property("test1").toString(), QString("hello"));
3392 QCOMPARE(o->property("test2").toString(), QString("ell"));
3394 o->setObjectName("world");
3396 QCOMPARE(o->property("test1").toString(), QString("world"));
3397 QCOMPARE(o->property("test2").toString(), QString("orl"));
3402 void tst_qdeclarativeecmascript::writeRemovesBinding()
3404 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
3405 QObject *o = component.create();
3408 QCOMPARE(o->property("test").toBool(), true);
3413 // Test bindings assigned to alias properties actually assign to the alias' target
3414 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
3416 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
3417 QObject *o = component.create();
3420 QCOMPARE(o->property("test").toBool(), true);
3425 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
3426 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
3429 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
3430 QObject *o = component.create();
3433 QCOMPARE(o->property("test").toBool(), true);
3439 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
3440 QObject *o = component.create();
3443 QCOMPARE(o->property("test").toBool(), true);
3449 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
3450 QObject *o = component.create();
3453 QCOMPARE(o->property("test").toBool(), true);
3459 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
3460 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
3463 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
3464 QObject *o = component.create();
3467 QCOMPARE(o->property("test").toBool(), true);
3473 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
3474 QObject *o = component.create();
3477 QCOMPARE(o->property("test").toBool(), true);
3483 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
3484 QObject *o = component.create();
3487 QCOMPARE(o->property("test").toBool(), true);
3493 void tst_qdeclarativeecmascript::revisionErrors()
3496 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
3497 QString url = component.url().toString();
3499 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
3500 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
3501 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
3503 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3504 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3505 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3506 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3507 QVERIFY(object != 0);
3511 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
3512 QString url = component.url().toString();
3514 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
3515 // method2, prop2 from MyRevisionedClass not available
3516 // method4, prop4 from MyRevisionedSubclass not available
3517 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
3518 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
3519 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
3520 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
3521 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
3523 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3524 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3525 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3526 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
3527 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
3528 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3529 QVERIFY(object != 0);
3533 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
3534 QString url = component.url().toString();
3536 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
3537 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
3538 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
3539 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
3540 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
3541 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3542 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3543 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3544 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3545 QVERIFY(object != 0);
3550 void tst_qdeclarativeecmascript::revision()
3553 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
3554 QString url = component.url().toString();
3556 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3557 QVERIFY(object != 0);
3561 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
3562 QString url = component.url().toString();
3564 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3565 QVERIFY(object != 0);
3569 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
3570 QString url = component.url().toString();
3572 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3573 QVERIFY(object != 0);
3576 // Test that non-root classes can resolve revisioned methods
3578 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
3580 QObject *object = component.create();
3581 QVERIFY(object != 0);
3582 QCOMPARE(object->property("test").toReal(), 11.);
3587 void tst_qdeclarativeecmascript::realToInt()
3589 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
3590 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
3591 QVERIFY(object != 0);
3593 QMetaObject::invokeMethod(object, "test1");
3594 QCOMPARE(object->value(), int(4));
3595 QMetaObject::invokeMethod(object, "test2");
3596 QCOMPARE(object->value(), int(8));
3599 QTEST_MAIN(tst_qdeclarativeecmascript)
3601 #include "tst_qdeclarativeecmascript.moc"