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();
110 void signalParameterTypes();
111 void objectsCompareAsEqual();
112 void dynamicCreation_data();
113 void dynamicCreation();
114 void dynamicDestruction();
115 void objectToString();
116 void selfDeletingBinding();
117 void extendedObjectPropertyLookup();
119 void functionErrors();
120 void propertyAssignmentErrors();
121 void signalTriggeredBindings();
122 void listProperties();
123 void exceptionClearsOnReeval();
124 void exceptionSlotProducesWarning();
125 void exceptionBindingProducesWarning();
126 void transientErrors();
127 void shutdownErrors();
128 void compositePropertyType();
130 void undefinedResetsProperty();
131 void listToVariant();
132 void multiEngineObject();
133 void deletedObject();
134 void attachedPropertyScope();
135 void scriptConnect();
136 void scriptDisconnect();
138 void cppOwnershipReturnValue();
139 void ownershipCustomReturnValue();
140 void qlistqobjectMethods();
141 void strictlyEquals();
143 void numberAssignment();
144 void propertySplicing();
145 void signalWithUnknownTypes();
147 void importScripts();
148 void scarceResources();
149 void propertyChangeSlots();
153 void dynamicCreationCrash();
155 void nullObjectBinding();
156 void deletedEngine();
157 void libraryScriptAssert();
158 void variantsAssignedUndefined();
160 void qtcreatorbug_1289();
161 void noSpuriousWarningsAtShutdown();
162 void canAssignNullToQObject();
163 void functionAssignment_fromBinding();
164 void functionAssignment_fromJS();
165 void functionAssignment_fromJS_data();
166 void functionAssignmentfromJS_invalid();
172 void nonscriptable();
175 void sharedAttachedObject();
177 void writeRemovesBinding();
178 void aliasBindingsAssignCorrectly();
179 void aliasBindingsOverrideTarget();
180 void aliasWritesOverrideBindings();
185 void callQtInvokables();
186 void invokableObjectArg();
187 void invokableObjectRet();
189 void revisionErrors();
192 QDeclarativeEngine engine;
195 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
197 void tst_qdeclarativeecmascript::assignBasicTypes()
200 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
201 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
202 QVERIFY(object != 0);
203 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
204 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
205 QCOMPARE(object->stringProperty(), QString("Hello World!"));
206 QCOMPARE(object->uintProperty(), uint(10));
207 QCOMPARE(object->intProperty(), -19);
208 QCOMPARE((float)object->realProperty(), float(23.2));
209 QCOMPARE((float)object->doubleProperty(), float(-19.75));
210 QCOMPARE((float)object->floatProperty(), float(8.5));
211 QCOMPARE(object->colorProperty(), QColor("red"));
212 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
213 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
214 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
215 QCOMPARE(object->pointProperty(), QPoint(99,13));
216 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
217 QCOMPARE(object->sizeProperty(), QSize(99, 13));
218 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
219 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
220 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
221 QCOMPARE(object->boolProperty(), true);
222 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
223 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
224 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
228 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
229 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
230 QVERIFY(object != 0);
231 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
232 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
233 QCOMPARE(object->stringProperty(), QString("Hello World!"));
234 QCOMPARE(object->uintProperty(), uint(10));
235 QCOMPARE(object->intProperty(), -19);
236 QCOMPARE((float)object->realProperty(), float(23.2));
237 QCOMPARE((float)object->doubleProperty(), float(-19.75));
238 QCOMPARE((float)object->floatProperty(), float(8.5));
239 QCOMPARE(object->colorProperty(), QColor("red"));
240 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
241 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
242 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
243 QCOMPARE(object->pointProperty(), QPoint(99,13));
244 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
245 QCOMPARE(object->sizeProperty(), QSize(99, 13));
246 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
247 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
248 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
249 QCOMPARE(object->boolProperty(), true);
250 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
251 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
252 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
257 void tst_qdeclarativeecmascript::idShortcutInvalidates()
260 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
261 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
262 QVERIFY(object != 0);
263 QVERIFY(object->objectProperty() != 0);
264 delete object->objectProperty();
265 QVERIFY(object->objectProperty() == 0);
270 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
271 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
272 QVERIFY(object != 0);
273 QVERIFY(object->objectProperty() != 0);
274 delete object->objectProperty();
275 QVERIFY(object->objectProperty() == 0);
280 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
283 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
284 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
285 QVERIFY(object != 0);
286 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
290 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
291 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
292 QVERIFY(object != 0);
293 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
298 void tst_qdeclarativeecmascript::signalAssignment()
301 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
302 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
303 QVERIFY(object != 0);
304 QCOMPARE(object->string(), QString());
305 emit object->basicSignal();
306 QCOMPARE(object->string(), QString("pass"));
311 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
312 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
313 QVERIFY(object != 0);
314 QCOMPARE(object->string(), QString());
315 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
316 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
321 void tst_qdeclarativeecmascript::methods()
324 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
325 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
326 QVERIFY(object != 0);
327 QCOMPARE(object->methodCalled(), false);
328 QCOMPARE(object->methodIntCalled(), false);
329 emit object->basicSignal();
330 QCOMPARE(object->methodCalled(), true);
331 QCOMPARE(object->methodIntCalled(), false);
336 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
337 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
338 QVERIFY(object != 0);
339 QCOMPARE(object->methodCalled(), false);
340 QCOMPARE(object->methodIntCalled(), false);
341 emit object->basicSignal();
342 QCOMPARE(object->methodCalled(), false);
343 QCOMPARE(object->methodIntCalled(), true);
348 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
349 QObject *object = component.create();
350 QVERIFY(object != 0);
351 QCOMPARE(object->property("test").toInt(), 19);
356 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
357 QObject *object = component.create();
358 QVERIFY(object != 0);
359 QCOMPARE(object->property("test").toInt(), 19);
360 QCOMPARE(object->property("test2").toInt(), 17);
361 QCOMPARE(object->property("test3").toInt(), 16);
366 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
367 QObject *object = component.create();
368 QVERIFY(object != 0);
369 QCOMPARE(object->property("test").toInt(), 9);
374 void tst_qdeclarativeecmascript::bindingLoop()
376 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
377 QString warning = component.url().toString() + ":9:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
378 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
379 QObject *object = component.create();
380 QVERIFY(object != 0);
384 void tst_qdeclarativeecmascript::basicExpressions_data()
386 QTest::addColumn<QString>("expression");
387 QTest::addColumn<QVariant>("result");
388 QTest::addColumn<bool>("nest");
390 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
391 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
392 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
393 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
394 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
395 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
396 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
397 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
398 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
399 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
400 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
401 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
402 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
403 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
404 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
405 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
406 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
407 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
408 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
411 void tst_qdeclarativeecmascript::basicExpressions()
413 QFETCH(QString, expression);
414 QFETCH(QVariant, result);
420 MyDefaultObject1 default1;
421 MyDefaultObject3 default3;
422 object1.setStringProperty("Object1");
423 object2.setStringProperty("Object2");
424 object3.setStringProperty("Object3");
426 QDeclarativeContext context(engine.rootContext());
427 QDeclarativeContext nestedContext(&context);
429 context.setContextObject(&default1);
430 context.setContextProperty("a", QVariant(1944));
431 context.setContextProperty("b", QVariant("Milk"));
432 context.setContextProperty("object", &object1);
433 context.setContextProperty("objectOverride", &object2);
434 nestedContext.setContextObject(&default3);
435 nestedContext.setContextProperty("b", QVariant("Cow"));
436 nestedContext.setContextProperty("objectOverride", &object3);
437 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
439 MyExpression expr(nest?&nestedContext:&context, expression);
440 QCOMPARE(expr.evaluate(), result);
443 void tst_qdeclarativeecmascript::arrayExpressions()
449 QDeclarativeContext context(engine.rootContext());
450 context.setContextProperty("a", &obj1);
451 context.setContextProperty("b", &obj2);
452 context.setContextProperty("c", &obj3);
454 MyExpression expr(&context, "[a, b, c, 10]");
455 QVariant result = expr.evaluate();
456 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
457 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
458 QCOMPARE(list.count(), 4);
459 QCOMPARE(list.at(0), &obj1);
460 QCOMPARE(list.at(1), &obj2);
461 QCOMPARE(list.at(2), &obj3);
462 QCOMPARE(list.at(3), (QObject *)0);
465 // Tests that modifying a context property will reevaluate expressions
466 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
468 QDeclarativeContext context(engine.rootContext());
471 MyQmlObject *object3 = new MyQmlObject;
473 object1.setStringProperty("Hello");
474 object2.setStringProperty("World");
476 context.setContextProperty("testProp", QVariant(1));
477 context.setContextProperty("testObj", &object1);
478 context.setContextProperty("testObj2", object3);
481 MyExpression expr(&context, "testProp + 1");
482 QCOMPARE(expr.changed, false);
483 QCOMPARE(expr.evaluate(), QVariant(2));
485 context.setContextProperty("testProp", QVariant(2));
486 QCOMPARE(expr.changed, true);
487 QCOMPARE(expr.evaluate(), QVariant(3));
491 MyExpression expr(&context, "testProp + testProp + testProp");
492 QCOMPARE(expr.changed, false);
493 QCOMPARE(expr.evaluate(), QVariant(6));
495 context.setContextProperty("testProp", QVariant(4));
496 QCOMPARE(expr.changed, true);
497 QCOMPARE(expr.evaluate(), QVariant(12));
501 MyExpression expr(&context, "testObj.stringProperty");
502 QCOMPARE(expr.changed, false);
503 QCOMPARE(expr.evaluate(), QVariant("Hello"));
505 context.setContextProperty("testObj", &object2);
506 QCOMPARE(expr.changed, true);
507 QCOMPARE(expr.evaluate(), QVariant("World"));
511 MyExpression expr(&context, "testObj.stringProperty /**/");
512 QCOMPARE(expr.changed, false);
513 QCOMPARE(expr.evaluate(), QVariant("World"));
515 context.setContextProperty("testObj", &object1);
516 QCOMPARE(expr.changed, true);
517 QCOMPARE(expr.evaluate(), QVariant("Hello"));
521 MyExpression expr(&context, "testObj2");
522 QCOMPARE(expr.changed, false);
523 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
529 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
531 QDeclarativeContext context(engine.rootContext());
535 context.setContextProperty("testObj", &object1);
537 object1.setStringProperty(QLatin1String("Hello"));
538 object2.setStringProperty(QLatin1String("Dog"));
539 object3.setStringProperty(QLatin1String("Cat"));
542 MyExpression expr(&context, "testObj.stringProperty");
543 QCOMPARE(expr.changed, false);
544 QCOMPARE(expr.evaluate(), QVariant("Hello"));
546 object1.setStringProperty(QLatin1String("World"));
547 QCOMPARE(expr.changed, true);
548 QCOMPARE(expr.evaluate(), QVariant("World"));
552 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
553 QCOMPARE(expr.changed, false);
554 QCOMPARE(expr.evaluate(), QVariant());
556 object1.setObjectProperty(&object2);
557 QCOMPARE(expr.changed, true);
558 expr.changed = false;
559 QCOMPARE(expr.evaluate(), QVariant("Dog"));
561 object1.setObjectProperty(&object3);
562 QCOMPARE(expr.changed, true);
563 expr.changed = false;
564 QCOMPARE(expr.evaluate(), QVariant("Cat"));
566 object1.setObjectProperty(0);
567 QCOMPARE(expr.changed, true);
568 expr.changed = false;
569 QCOMPARE(expr.evaluate(), QVariant());
571 object1.setObjectProperty(&object3);
572 QCOMPARE(expr.changed, true);
573 expr.changed = false;
574 QCOMPARE(expr.evaluate(), QVariant("Cat"));
576 object3.setStringProperty("Donkey");
577 QCOMPARE(expr.changed, true);
578 expr.changed = false;
579 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
583 void tst_qdeclarativeecmascript::deferredProperties()
585 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
586 MyDeferredObject *object =
587 qobject_cast<MyDeferredObject *>(component.create());
588 QVERIFY(object != 0);
589 QCOMPARE(object->value(), 0);
590 QVERIFY(object->objectProperty() == 0);
591 QVERIFY(object->objectProperty2() != 0);
592 qmlExecuteDeferred(object);
593 QCOMPARE(object->value(), 10);
594 QVERIFY(object->objectProperty() != 0);
595 MyQmlObject *qmlObject =
596 qobject_cast<MyQmlObject *>(object->objectProperty());
597 QVERIFY(qmlObject != 0);
598 QCOMPARE(qmlObject->value(), 10);
599 object->setValue(19);
600 QCOMPARE(qmlObject->value(), 19);
605 // Check errors on deferred properties are correctly emitted
606 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
608 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
609 MyDeferredObject *object =
610 qobject_cast<MyDeferredObject *>(component.create());
611 QVERIFY(object != 0);
612 QCOMPARE(object->value(), 0);
613 QVERIFY(object->objectProperty() == 0);
614 QVERIFY(object->objectProperty2() == 0);
616 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject* objectProperty";
617 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
619 qmlExecuteDeferred(object);
624 void tst_qdeclarativeecmascript::extensionObjects()
626 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
627 MyExtendedObject *object =
628 qobject_cast<MyExtendedObject *>(component.create());
629 QVERIFY(object != 0);
630 QCOMPARE(object->baseProperty(), 13);
631 QCOMPARE(object->coreProperty(), 9);
632 object->setProperty("extendedProperty", QVariant(11));
633 object->setProperty("baseExtendedProperty", QVariant(92));
634 QCOMPARE(object->coreProperty(), 11);
635 QCOMPARE(object->baseProperty(), 92);
637 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
639 QCOMPARE(nested->baseProperty(), 13);
640 QCOMPARE(nested->coreProperty(), 9);
641 nested->setProperty("extendedProperty", QVariant(11));
642 nested->setProperty("baseExtendedProperty", QVariant(92));
643 QCOMPARE(nested->coreProperty(), 11);
644 QCOMPARE(nested->baseProperty(), 92);
649 void tst_qdeclarativeecmascript::overrideExtensionProperties()
651 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
652 OverrideDefaultPropertyObject *object =
653 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
654 QVERIFY(object != 0);
655 QVERIFY(object->secondProperty() != 0);
656 QVERIFY(object->firstProperty() == 0);
661 void tst_qdeclarativeecmascript::attachedProperties()
664 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
665 QObject *object = component.create();
666 QVERIFY(object != 0);
667 QCOMPARE(object->property("a").toInt(), 19);
668 QCOMPARE(object->property("b").toInt(), 19);
669 QCOMPARE(object->property("c").toInt(), 19);
670 QCOMPARE(object->property("d").toInt(), 19);
675 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
676 QObject *object = component.create();
677 QVERIFY(object != 0);
678 QCOMPARE(object->property("a").toInt(), 26);
679 QCOMPARE(object->property("b").toInt(), 26);
680 QCOMPARE(object->property("c").toInt(), 26);
681 QCOMPARE(object->property("d").toInt(), 26);
685 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
686 QObject *object = component.create();
687 QVERIFY(object != 0);
689 QMetaObject::invokeMethod(object, "writeValue2");
691 MyQmlAttachedObject *attached =
692 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
693 QVERIFY(attached != 0);
695 QCOMPARE(attached->value2(), 9);
700 void tst_qdeclarativeecmascript::enums()
704 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
705 QObject *object = component.create();
706 QVERIFY(object != 0);
708 QCOMPARE(object->property("a").toInt(), 0);
709 QCOMPARE(object->property("b").toInt(), 1);
710 QCOMPARE(object->property("c").toInt(), 2);
711 QCOMPARE(object->property("d").toInt(), 3);
712 QCOMPARE(object->property("e").toInt(), 0);
713 QCOMPARE(object->property("f").toInt(), 1);
714 QCOMPARE(object->property("g").toInt(), 2);
715 QCOMPARE(object->property("h").toInt(), 3);
716 QCOMPARE(object->property("i").toInt(), 19);
717 QCOMPARE(object->property("j").toInt(), 19);
721 // Non-existent enums
723 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
725 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int a";
726 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int b";
727 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
728 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
730 QObject *object = component.create();
731 QVERIFY(object != 0);
732 QCOMPARE(object->property("a").toInt(), 0);
733 QCOMPARE(object->property("b").toInt(), 0);
739 void tst_qdeclarativeecmascript::valueTypeFunctions()
741 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
742 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
744 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
745 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
751 Tests that writing a constant to a property with a binding on it disables the
754 void tst_qdeclarativeecmascript::constantsOverrideBindings()
758 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
759 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
760 QVERIFY(object != 0);
762 QCOMPARE(object->property("c2").toInt(), 0);
763 object->setProperty("c1", QVariant(9));
764 QCOMPARE(object->property("c2").toInt(), 9);
766 emit object->basicSignal();
768 QCOMPARE(object->property("c2").toInt(), 13);
769 object->setProperty("c1", QVariant(8));
770 QCOMPARE(object->property("c2").toInt(), 13);
775 // During construction
777 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
778 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
779 QVERIFY(object != 0);
781 QCOMPARE(object->property("c1").toInt(), 0);
782 QCOMPARE(object->property("c2").toInt(), 10);
783 object->setProperty("c1", QVariant(9));
784 QCOMPARE(object->property("c1").toInt(), 9);
785 QCOMPARE(object->property("c2").toInt(), 10);
793 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
794 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
795 QVERIFY(object != 0);
797 QCOMPARE(object->property("c2").toInt(), 0);
798 object->setProperty("c1", QVariant(9));
799 QCOMPARE(object->property("c2").toInt(), 9);
801 object->setProperty("c2", QVariant(13));
802 QCOMPARE(object->property("c2").toInt(), 13);
803 object->setProperty("c1", QVariant(7));
804 QCOMPARE(object->property("c1").toInt(), 7);
805 QCOMPARE(object->property("c2").toInt(), 13);
813 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
814 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
815 QVERIFY(object != 0);
817 QCOMPARE(object->property("c1").toInt(), 0);
818 QCOMPARE(object->property("c3").toInt(), 10);
819 object->setProperty("c1", QVariant(9));
820 QCOMPARE(object->property("c1").toInt(), 9);
821 QCOMPARE(object->property("c3").toInt(), 10);
828 Tests that assigning a binding to a property that already has a binding causes
829 the original binding to be disabled.
831 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
833 QDeclarativeComponent component(&engine,
834 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
835 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
836 QVERIFY(object != 0);
838 QCOMPARE(object->property("c1").toInt(), 0);
839 QCOMPARE(object->property("c2").toInt(), 0);
840 QCOMPARE(object->property("c3").toInt(), 0);
842 object->setProperty("c1", QVariant(9));
843 QCOMPARE(object->property("c1").toInt(), 9);
844 QCOMPARE(object->property("c2").toInt(), 0);
845 QCOMPARE(object->property("c3").toInt(), 0);
847 object->setProperty("c3", QVariant(8));
848 QCOMPARE(object->property("c1").toInt(), 9);
849 QCOMPARE(object->property("c2").toInt(), 8);
850 QCOMPARE(object->property("c3").toInt(), 8);
856 Access a non-existent attached object.
858 Tests for a regression where this used to crash.
860 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
862 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
864 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString stringProperty";
865 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
867 QObject *object = component.create();
868 QVERIFY(object != 0);
873 void tst_qdeclarativeecmascript::scope()
876 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
877 QObject *object = component.create();
878 QVERIFY(object != 0);
880 QCOMPARE(object->property("test1").toInt(), 1);
881 QCOMPARE(object->property("test2").toInt(), 2);
882 QCOMPARE(object->property("test3").toString(), QString("1Test"));
883 QCOMPARE(object->property("test4").toString(), QString("2Test"));
884 QCOMPARE(object->property("test5").toInt(), 1);
885 QCOMPARE(object->property("test6").toInt(), 1);
886 QCOMPARE(object->property("test7").toInt(), 2);
887 QCOMPARE(object->property("test8").toInt(), 2);
888 QCOMPARE(object->property("test9").toInt(), 1);
889 QCOMPARE(object->property("test10").toInt(), 3);
895 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
896 QObject *object = component.create();
897 QVERIFY(object != 0);
899 QCOMPARE(object->property("test1").toInt(), 19);
900 QCOMPARE(object->property("test2").toInt(), 19);
901 QCOMPARE(object->property("test3").toInt(), 14);
902 QCOMPARE(object->property("test4").toInt(), 14);
903 QCOMPARE(object->property("test5").toInt(), 24);
904 QCOMPARE(object->property("test6").toInt(), 24);
910 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
911 QObject *object = component.create();
912 QVERIFY(object != 0);
914 QCOMPARE(object->property("test1").toBool(), true);
915 QCOMPARE(object->property("test2").toBool(), true);
916 QCOMPARE(object->property("test3").toBool(), true);
921 // Signal argument scope
923 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
924 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
925 QVERIFY(object != 0);
927 QCOMPARE(object->property("test").toInt(), 0);
928 QCOMPARE(object->property("test2").toString(), QString());
930 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
932 QCOMPARE(object->property("test").toInt(), 13);
933 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
939 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
940 QObject *object = component.create();
941 QVERIFY(object != 0);
943 QCOMPARE(object->property("test1").toBool(), true);
944 QCOMPARE(object->property("test2").toBool(), true);
950 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
951 QObject *object = component.create();
952 QVERIFY(object != 0);
954 QCOMPARE(object->property("test").toBool(), true);
961 Tests that "any" type passes through a synthesized signal parameter. This
962 is essentially a test of QDeclarativeMetaType::copy()
964 void tst_qdeclarativeecmascript::signalParameterTypes()
966 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
967 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
968 QVERIFY(object != 0);
970 emit object->basicSignal();
972 QCOMPARE(object->property("intProperty").toInt(), 10);
973 QCOMPARE(object->property("realProperty").toReal(), 19.2);
974 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
975 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
976 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
977 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
983 Test that two JS objects for the same QObject compare as equal.
985 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
987 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
988 QObject *object = component.create();
989 QVERIFY(object != 0);
991 QCOMPARE(object->property("test1").toBool(), true);
992 QCOMPARE(object->property("test2").toBool(), true);
993 QCOMPARE(object->property("test3").toBool(), true);
994 QCOMPARE(object->property("test4").toBool(), true);
995 QCOMPARE(object->property("test5").toBool(), true);
1001 Confirm bindings and alias properties can coexist.
1003 Tests for a regression where the binding would not reevaluate.
1005 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1007 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1008 QObject *object = component.create();
1009 QVERIFY(object != 0);
1011 QCOMPARE(object->property("c2").toInt(), 3);
1012 QCOMPARE(object->property("c3").toInt(), 3);
1014 object->setProperty("c2", QVariant(19));
1016 QCOMPARE(object->property("c2").toInt(), 19);
1017 QCOMPARE(object->property("c3").toInt(), 19);
1022 void tst_qdeclarativeecmascript::dynamicCreation_data()
1024 QTest::addColumn<QString>("method");
1025 QTest::addColumn<QString>("createdName");
1027 QTest::newRow("One") << "createOne" << "objectOne";
1028 QTest::newRow("Two") << "createTwo" << "objectTwo";
1029 QTest::newRow("Three") << "createThree" << "objectThree";
1033 Test using createQmlObject to dynamically generate an item
1034 Also using createComponent is tested.
1036 void tst_qdeclarativeecmascript::dynamicCreation()
1038 QFETCH(QString, method);
1039 QFETCH(QString, createdName);
1041 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1042 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1043 QVERIFY(object != 0);
1045 QMetaObject::invokeMethod(object, method.toUtf8());
1046 QObject *created = object->objectProperty();
1048 QCOMPARE(created->objectName(), createdName);
1054 Tests the destroy function
1056 void tst_qdeclarativeecmascript::dynamicDestruction()
1058 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1059 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1060 QVERIFY(object != 0);
1061 QDeclarativeGuard<QObject> createdQmlObject = 0;
1063 QMetaObject::invokeMethod(object, "create");
1064 createdQmlObject = object->objectProperty();
1065 QVERIFY(createdQmlObject);
1066 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1068 QMetaObject::invokeMethod(object, "killOther");
1069 QVERIFY(createdQmlObject);
1070 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1071 QVERIFY(createdQmlObject);
1072 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1073 if (createdQmlObject) {
1075 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1078 QVERIFY(!createdQmlObject);
1080 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1081 QMetaObject::invokeMethod(object, "killMe");
1084 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1089 tests that id.toString() works
1091 void tst_qdeclarativeecmascript::objectToString()
1093 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1094 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1095 QVERIFY(object != 0);
1096 QMetaObject::invokeMethod(object, "testToString");
1097 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1098 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1104 Tests bindings that indirectly cause their own deletion work.
1106 This test is best run under valgrind to ensure no invalid memory access occur.
1108 void tst_qdeclarativeecmascript::selfDeletingBinding()
1111 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1112 QObject *object = component.create();
1113 QVERIFY(object != 0);
1114 object->setProperty("triggerDelete", true);
1119 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1120 QObject *object = component.create();
1121 QVERIFY(object != 0);
1122 object->setProperty("triggerDelete", true);
1128 Test that extended object properties can be accessed.
1130 This test a regression where this used to crash. The issue was specificially
1131 for extended objects that did not include a synthesized meta object (so non-root
1132 and no synthesiszed properties).
1134 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1136 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1137 QObject *object = component.create();
1138 QVERIFY(object != 0);
1143 Test file/lineNumbers for binding/Script errors.
1145 void tst_qdeclarativeecmascript::scriptErrors()
1147 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1148 QString url = component.url().toString();
1150 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1151 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1152 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1153 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1154 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1155 QString warning6 = url + ":7: Unable to assign [undefined] to int x";
1156 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1157 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1159 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1160 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1161 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1162 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1163 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1164 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1165 QVERIFY(object != 0);
1167 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1168 emit object->basicSignal();
1170 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1171 emit object->anotherBasicSignal();
1173 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1174 emit object->thirdBasicSignal();
1180 Test file/lineNumbers for inline functions.
1182 void tst_qdeclarativeecmascript::functionErrors()
1184 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1185 QString url = component.url().toString();
1187 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1189 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1191 QObject *object = component.create();
1192 QVERIFY(object != 0);
1195 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1196 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1197 url = componentTwo.url().toString();
1198 object = componentTwo.create();
1199 QVERIFY(object != 0);
1201 QString srpname = object->property("srp_name").toString();
1203 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1204 QLatin1String(" is not a function");
1205 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1206 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1211 Test various errors that can occur when assigning a property from script
1213 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1215 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1217 QString url = component.url().toString();
1219 QObject *object = component.create();
1220 QVERIFY(object != 0);
1222 QCOMPARE(object->property("test1").toBool(), true);
1223 QCOMPARE(object->property("test2").toBool(), true);
1229 Test bindings still work when the reeval is triggered from within
1232 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1234 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1235 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1236 QVERIFY(object != 0);
1238 QCOMPARE(object->property("base").toReal(), 50.);
1239 QCOMPARE(object->property("test1").toReal(), 50.);
1240 QCOMPARE(object->property("test2").toReal(), 50.);
1242 object->basicSignal();
1244 QCOMPARE(object->property("base").toReal(), 200.);
1245 QCOMPARE(object->property("test1").toReal(), 200.);
1246 QCOMPARE(object->property("test2").toReal(), 200.);
1248 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1250 QCOMPARE(object->property("base").toReal(), 400.);
1251 QCOMPARE(object->property("test1").toReal(), 400.);
1252 QCOMPARE(object->property("test2").toReal(), 400.);
1258 Test that list properties can be iterated from ECMAScript
1260 void tst_qdeclarativeecmascript::listProperties()
1262 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1263 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1264 QVERIFY(object != 0);
1266 QCOMPARE(object->property("test1").toInt(), 21);
1267 QCOMPARE(object->property("test2").toInt(), 2);
1268 QCOMPARE(object->property("test3").toBool(), true);
1269 QCOMPARE(object->property("test4").toBool(), true);
1274 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1276 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1277 QString url = component.url().toString();
1279 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1281 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1282 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1283 QVERIFY(object != 0);
1285 QCOMPARE(object->property("test").toBool(), false);
1287 MyQmlObject object2;
1288 MyQmlObject object3;
1289 object2.setObjectProperty(&object3);
1290 object->setObjectProperty(&object2);
1292 QCOMPARE(object->property("test").toBool(), true);
1297 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1299 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1300 QString url = component.url().toString();
1302 QString warning = component.url().toString() + ":6: Error: JS exception";
1304 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1305 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1306 QVERIFY(object != 0);
1310 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1312 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1313 QString url = component.url().toString();
1315 QString warning = component.url().toString() + ":5: Error: JS exception";
1317 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1318 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1319 QVERIFY(object != 0);
1323 static int transientErrorsMsgCount = 0;
1324 static void transientErrorsMsgHandler(QtMsgType, const char *)
1326 ++transientErrorsMsgCount;
1329 // Check that transient binding errors are not displayed
1330 void tst_qdeclarativeecmascript::transientErrors()
1333 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1335 transientErrorsMsgCount = 0;
1336 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1338 QObject *object = component.create();
1339 QVERIFY(object != 0);
1341 qInstallMsgHandler(old);
1343 QCOMPARE(transientErrorsMsgCount, 0);
1348 // One binding erroring multiple times, but then resolving
1350 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1352 transientErrorsMsgCount = 0;
1353 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1355 QObject *object = component.create();
1356 QVERIFY(object != 0);
1358 qInstallMsgHandler(old);
1360 QCOMPARE(transientErrorsMsgCount, 0);
1366 // Check that errors during shutdown are minimized
1367 void tst_qdeclarativeecmascript::shutdownErrors()
1369 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1370 QObject *object = component.create();
1371 QVERIFY(object != 0);
1373 transientErrorsMsgCount = 0;
1374 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1378 qInstallMsgHandler(old);
1379 QCOMPARE(transientErrorsMsgCount, 0);
1382 void tst_qdeclarativeecmascript::compositePropertyType()
1384 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1385 QTest::ignoreMessage(QtDebugMsg, "hello world");
1386 QObject *object = qobject_cast<QObject *>(component.create());
1391 void tst_qdeclarativeecmascript::jsObject()
1393 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1394 QObject *object = component.create();
1395 QVERIFY(object != 0);
1397 QCOMPARE(object->property("test").toInt(), 92);
1402 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1405 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1406 QObject *object = component.create();
1407 QVERIFY(object != 0);
1409 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1411 object->setProperty("setUndefined", true);
1413 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1415 object->setProperty("setUndefined", false);
1417 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1422 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1423 QObject *object = component.create();
1424 QVERIFY(object != 0);
1426 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1428 QMetaObject::invokeMethod(object, "doReset");
1430 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1437 void tst_qdeclarativeecmascript::bug1()
1439 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1440 QObject *object = component.create();
1441 QVERIFY(object != 0);
1443 QCOMPARE(object->property("test").toInt(), 14);
1445 object->setProperty("a", 11);
1447 QCOMPARE(object->property("test").toInt(), 3);
1449 object->setProperty("b", true);
1451 QCOMPARE(object->property("test").toInt(), 9);
1456 void tst_qdeclarativeecmascript::bug2()
1458 QDeclarativeComponent component(&engine);
1459 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1461 QObject *object = component.create();
1462 QVERIFY(object != 0);
1467 // Don't crash in createObject when the component has errors.
1468 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1470 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1471 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1472 QVERIFY(object != 0);
1474 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1475 QMetaObject::invokeMethod(object, "dontCrash");
1476 QObject *created = object->objectProperty();
1477 QVERIFY(created == 0);
1483 void tst_qdeclarativeecmascript::regExpBug()
1485 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1486 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1487 QVERIFY(object != 0);
1488 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1492 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1494 QString functionSource = QLatin1String("(function(object) { return ") +
1495 QLatin1String(source) + QLatin1String(" })");
1497 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1500 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1501 if (function.IsEmpty())
1503 v8::Handle<v8::Value> args[] = { o };
1504 function->Call(engine->global(), 1, args);
1505 return tc.HasCaught();
1508 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1509 const char *source, v8::Handle<v8::Value> result)
1511 QString functionSource = QLatin1String("(function(object) { return ") +
1512 QLatin1String(source) + QLatin1String(" })");
1514 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1517 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1518 if (function.IsEmpty())
1520 v8::Handle<v8::Value> args[] = { o };
1522 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1527 return value->StrictEquals(result);
1530 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1533 QString functionSource = QLatin1String("(function(object) { return ") +
1534 QLatin1String(source) + QLatin1String(" })");
1536 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1538 return v8::Handle<v8::Value>();
1539 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1540 if (function.IsEmpty())
1541 return v8::Handle<v8::Value>();
1542 v8::Handle<v8::Value> args[] = { o };
1544 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1547 return v8::Handle<v8::Value>();
1551 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1552 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1553 #define EVALUATE(source) evaluate(engine, object, source)
1555 void tst_qdeclarativeecmascript::callQtInvokables()
1557 MyInvokableObject o;
1559 QDeclarativeEngine qmlengine;
1560 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1562 QV8Engine *engine = &ep->v8engine;
1564 v8::HandleScope handle_scope;
1565 v8::Context::Scope scope(engine->context());
1567 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1569 // Non-existent methods
1571 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1572 QCOMPARE(o.error(), false);
1573 QCOMPARE(o.invoked(), -1);
1574 QCOMPARE(o.actuals().count(), 0);
1577 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1578 QCOMPARE(o.error(), false);
1579 QCOMPARE(o.invoked(), -1);
1580 QCOMPARE(o.actuals().count(), 0);
1582 // Insufficient arguments
1584 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1585 QCOMPARE(o.error(), false);
1586 QCOMPARE(o.invoked(), -1);
1587 QCOMPARE(o.actuals().count(), 0);
1590 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1591 QCOMPARE(o.error(), false);
1592 QCOMPARE(o.invoked(), -1);
1593 QCOMPARE(o.actuals().count(), 0);
1595 // Excessive arguments
1597 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1598 QCOMPARE(o.error(), false);
1599 QCOMPARE(o.invoked(), 8);
1600 QCOMPARE(o.actuals().count(), 1);
1601 QCOMPARE(o.actuals().at(0), QVariant(10));
1604 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1605 QCOMPARE(o.error(), false);
1606 QCOMPARE(o.invoked(), 9);
1607 QCOMPARE(o.actuals().count(), 2);
1608 QCOMPARE(o.actuals().at(0), QVariant(10));
1609 QCOMPARE(o.actuals().at(1), QVariant(11));
1611 // Test return types
1613 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1614 QCOMPARE(o.error(), false);
1615 QCOMPARE(o.invoked(), 0);
1616 QCOMPARE(o.actuals().count(), 0);
1619 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1620 QCOMPARE(o.error(), false);
1621 QCOMPARE(o.invoked(), 1);
1622 QCOMPARE(o.actuals().count(), 0);
1625 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1626 QCOMPARE(o.error(), false);
1627 QCOMPARE(o.invoked(), 2);
1628 QCOMPARE(o.actuals().count(), 0);
1632 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1633 QVERIFY(!ret.IsEmpty());
1634 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1635 QCOMPARE(o.error(), false);
1636 QCOMPARE(o.invoked(), 3);
1637 QCOMPARE(o.actuals().count(), 0);
1642 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1643 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1644 QCOMPARE(o.error(), false);
1645 QCOMPARE(o.invoked(), 4);
1646 QCOMPARE(o.actuals().count(), 0);
1650 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1651 QCOMPARE(o.error(), false);
1652 QCOMPARE(o.invoked(), 5);
1653 QCOMPARE(o.actuals().count(), 0);
1655 // XXX enable once qml/qtscript integration is implemented
1659 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1660 QVERIFY(ret->IsString());
1661 QCOMPARE(engine->toString(ret), QString("Hello world"));
1662 QCOMPARE(o.error(), false);
1663 QCOMPARE(o.invoked(), 6);
1664 QCOMPARE(o.actuals().count(), 0);
1669 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1670 QCOMPARE(o.error(), false);
1671 QCOMPARE(o.invoked(), 7);
1672 QCOMPARE(o.actuals().count(), 0);
1676 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1677 QCOMPARE(o.error(), false);
1678 QCOMPARE(o.invoked(), 8);
1679 QCOMPARE(o.actuals().count(), 1);
1680 QCOMPARE(o.actuals().at(0), QVariant(94));
1683 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1684 QCOMPARE(o.error(), false);
1685 QCOMPARE(o.invoked(), 8);
1686 QCOMPARE(o.actuals().count(), 1);
1687 QCOMPARE(o.actuals().at(0), QVariant(94));
1690 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1691 QCOMPARE(o.error(), false);
1692 QCOMPARE(o.invoked(), 8);
1693 QCOMPARE(o.actuals().count(), 1);
1694 QCOMPARE(o.actuals().at(0), QVariant(0));
1697 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1698 QCOMPARE(o.error(), false);
1699 QCOMPARE(o.invoked(), 8);
1700 QCOMPARE(o.actuals().count(), 1);
1701 QCOMPARE(o.actuals().at(0), QVariant(0));
1704 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1705 QCOMPARE(o.error(), false);
1706 QCOMPARE(o.invoked(), 8);
1707 QCOMPARE(o.actuals().count(), 1);
1708 QCOMPARE(o.actuals().at(0), QVariant(0));
1711 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1712 QCOMPARE(o.error(), false);
1713 QCOMPARE(o.invoked(), 8);
1714 QCOMPARE(o.actuals().count(), 1);
1715 QCOMPARE(o.actuals().at(0), QVariant(0));
1718 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1719 QCOMPARE(o.error(), false);
1720 QCOMPARE(o.invoked(), 9);
1721 QCOMPARE(o.actuals().count(), 2);
1722 QCOMPARE(o.actuals().at(0), QVariant(122));
1723 QCOMPARE(o.actuals().at(1), QVariant(9));
1726 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1727 QCOMPARE(o.error(), false);
1728 QCOMPARE(o.invoked(), 10);
1729 QCOMPARE(o.actuals().count(), 1);
1730 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1733 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1734 QCOMPARE(o.error(), false);
1735 QCOMPARE(o.invoked(), 10);
1736 QCOMPARE(o.actuals().count(), 1);
1737 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1740 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1741 QCOMPARE(o.error(), false);
1742 QCOMPARE(o.invoked(), 10);
1743 QCOMPARE(o.actuals().count(), 1);
1744 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1747 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1748 QCOMPARE(o.error(), false);
1749 QCOMPARE(o.invoked(), 10);
1750 QCOMPARE(o.actuals().count(), 1);
1751 QCOMPARE(o.actuals().at(0), QVariant(0));
1754 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1755 QCOMPARE(o.error(), false);
1756 QCOMPARE(o.invoked(), 10);
1757 QCOMPARE(o.actuals().count(), 1);
1758 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1761 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
1762 QCOMPARE(o.error(), false);
1763 QCOMPARE(o.invoked(), 10);
1764 QCOMPARE(o.actuals().count(), 1);
1765 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1768 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
1769 QCOMPARE(o.error(), false);
1770 QCOMPARE(o.invoked(), 11);
1771 QCOMPARE(o.actuals().count(), 1);
1772 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
1775 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
1776 QCOMPARE(o.error(), false);
1777 QCOMPARE(o.invoked(), 11);
1778 QCOMPARE(o.actuals().count(), 1);
1779 QCOMPARE(o.actuals().at(0), QVariant("19"));
1783 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
1784 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", 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(expected));
1792 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
1793 QCOMPARE(o.error(), false);
1794 QCOMPARE(o.invoked(), 11);
1795 QCOMPARE(o.actuals().count(), 1);
1796 QCOMPARE(o.actuals().at(0), QVariant(QString()));
1799 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
1800 QCOMPARE(o.error(), false);
1801 QCOMPARE(o.invoked(), 11);
1802 QCOMPARE(o.actuals().count(), 1);
1803 QCOMPARE(o.actuals().at(0), QVariant(QString()));
1806 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
1807 QCOMPARE(o.error(), false);
1808 QCOMPARE(o.invoked(), 12);
1809 QCOMPARE(o.actuals().count(), 1);
1810 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1813 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
1814 QCOMPARE(o.error(), false);
1815 QCOMPARE(o.invoked(), 12);
1816 QCOMPARE(o.actuals().count(), 1);
1817 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1820 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
1821 QCOMPARE(o.error(), false);
1822 QCOMPARE(o.invoked(), 12);
1823 QCOMPARE(o.actuals().count(), 1);
1824 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1827 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
1828 QCOMPARE(o.error(), false);
1829 QCOMPARE(o.invoked(), 12);
1830 QCOMPARE(o.actuals().count(), 1);
1831 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1834 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
1835 QCOMPARE(o.error(), false);
1836 QCOMPARE(o.invoked(), 12);
1837 QCOMPARE(o.actuals().count(), 1);
1838 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
1841 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
1842 QCOMPARE(o.error(), false);
1843 QCOMPARE(o.invoked(), 12);
1844 QCOMPARE(o.actuals().count(), 1);
1845 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
1848 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
1849 QCOMPARE(o.error(), false);
1850 QCOMPARE(o.invoked(), 13);
1851 QCOMPARE(o.actuals().count(), 1);
1852 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1855 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
1856 QCOMPARE(o.error(), false);
1857 QCOMPARE(o.invoked(), 13);
1858 QCOMPARE(o.actuals().count(), 1);
1859 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1862 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
1863 QCOMPARE(o.error(), false);
1864 QCOMPARE(o.invoked(), 13);
1865 QCOMPARE(o.actuals().count(), 1);
1866 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1869 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
1870 QCOMPARE(o.error(), false);
1871 QCOMPARE(o.invoked(), 13);
1872 QCOMPARE(o.actuals().count(), 1);
1873 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1876 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
1877 QCOMPARE(o.error(), false);
1878 QCOMPARE(o.invoked(), 13);
1879 QCOMPARE(o.actuals().count(), 1);
1880 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
1882 // XXX enable once qml/qtscript integration is implemented
1885 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
1886 QCOMPARE(o.error(), false);
1887 QCOMPARE(o.invoked(), 14);
1888 QCOMPARE(o.actuals().count(), 1);
1889 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isNull());
1892 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
1893 QCOMPARE(o.error(), false);
1894 QCOMPARE(o.invoked(), 14);
1895 QCOMPARE(o.actuals().count(), 1);
1896 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isUndefined());
1899 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
1900 QCOMPARE(o.error(), false);
1901 QCOMPARE(o.invoked(), 14);
1902 QCOMPARE(o.actuals().count(), 1);
1903 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).strictlyEquals(QScriptValue(engine, 19)));
1906 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
1907 QCOMPARE(o.error(), false);
1908 QCOMPARE(o.invoked(), 14);
1909 QCOMPARE(o.actuals().count(), 1);
1910 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isArray());
1913 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
1914 QCOMPARE(o.error(), false);
1915 QCOMPARE(o.invoked(), 15);
1916 QCOMPARE(o.actuals().count(), 2);
1917 QCOMPARE(o.actuals().at(0), QVariant(4));
1918 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isNull());
1921 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
1922 QCOMPARE(o.error(), false);
1923 QCOMPARE(o.invoked(), 15);
1924 QCOMPARE(o.actuals().count(), 2);
1925 QCOMPARE(o.actuals().at(0), QVariant(8));
1926 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isUndefined());
1929 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", 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(3));
1934 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).strictlyEquals(QScriptValue(engine, 19)));
1937 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", 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(44));
1942 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isArray());
1946 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
1947 QCOMPARE(o.error(), false);
1948 QCOMPARE(o.invoked(), -1);
1949 QCOMPARE(o.actuals().count(), 0);
1952 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
1953 QCOMPARE(o.error(), false);
1954 QCOMPARE(o.invoked(), 16);
1955 QCOMPARE(o.actuals().count(), 1);
1956 QCOMPARE(o.actuals().at(0), QVariant(10));
1959 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
1960 QCOMPARE(o.error(), false);
1961 QCOMPARE(o.invoked(), 17);
1962 QCOMPARE(o.actuals().count(), 2);
1963 QCOMPARE(o.actuals().at(0), QVariant(10));
1964 QCOMPARE(o.actuals().at(1), QVariant(11));
1967 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
1968 QCOMPARE(o.error(), false);
1969 QCOMPARE(o.invoked(), 18);
1970 QCOMPARE(o.actuals().count(), 1);
1971 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
1974 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
1975 QCOMPARE(o.error(), false);
1976 QCOMPARE(o.invoked(), 19);
1977 QCOMPARE(o.actuals().count(), 1);
1978 QCOMPARE(o.actuals().at(0), QVariant(9));
1981 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
1982 QCOMPARE(o.error(), false);
1983 QCOMPARE(o.invoked(), 20);
1984 QCOMPARE(o.actuals().count(), 2);
1985 QCOMPARE(o.actuals().at(0), QVariant(10));
1986 QCOMPARE(o.actuals().at(1), QVariant(19));
1989 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
1990 QCOMPARE(o.error(), false);
1991 QCOMPARE(o.invoked(), 20);
1992 QCOMPARE(o.actuals().count(), 2);
1993 QCOMPARE(o.actuals().at(0), QVariant(10));
1994 QCOMPARE(o.actuals().at(1), QVariant(13));
1997 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
1998 QCOMPARE(o.error(), false);
1999 QCOMPARE(o.invoked(), -3);
2000 QCOMPARE(o.actuals().count(), 1);
2001 QCOMPARE(o.actuals().at(0), QVariant(9));
2004 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2005 QCOMPARE(o.error(), false);
2006 QCOMPARE(o.invoked(), 21);
2007 QCOMPARE(o.actuals().count(), 2);
2008 QCOMPARE(o.actuals().at(0), QVariant(9));
2009 QCOMPARE(o.actuals().at(1), QVariant());
2012 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2013 QCOMPARE(o.error(), false);
2014 QCOMPARE(o.invoked(), 21);
2015 QCOMPARE(o.actuals().count(), 2);
2016 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2017 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2020 // QTBUG-13047 (check that you can pass registered object types as args)
2021 void tst_qdeclarativeecmascript::invokableObjectArg()
2023 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2025 QObject *o = component.create();
2027 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2029 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2034 // QTBUG-13047 (check that you can return registered object types from methods)
2035 void tst_qdeclarativeecmascript::invokableObjectRet()
2037 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2039 QObject *o = component.create();
2041 QCOMPARE(o->property("test").toBool(), true);
2046 void tst_qdeclarativeecmascript::listToVariant()
2048 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2050 MyQmlContainer container;
2052 QDeclarativeContext context(engine.rootContext());
2053 context.setContextObject(&container);
2055 QObject *object = component.create(&context);
2056 QVERIFY(object != 0);
2058 QVariant v = object->property("test");
2059 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2060 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2066 void tst_qdeclarativeecmascript::multiEngineObject()
2069 obj.setStringProperty("Howdy planet");
2071 QDeclarativeEngine e1;
2072 e1.rootContext()->setContextProperty("thing", &obj);
2073 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2075 QDeclarativeEngine e2;
2076 e2.rootContext()->setContextProperty("thing", &obj);
2077 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2079 QObject *o1 = c1.create();
2080 QObject *o2 = c2.create();
2082 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2083 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2089 // Test that references to QObjects are cleanup when the object is destroyed
2090 void tst_qdeclarativeecmascript::deletedObject()
2092 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2094 QObject *object = component.create();
2096 QCOMPARE(object->property("test1").toBool(), true);
2097 QCOMPARE(object->property("test2").toBool(), true);
2098 QCOMPARE(object->property("test3").toBool(), true);
2099 QCOMPARE(object->property("test4").toBool(), true);
2104 void tst_qdeclarativeecmascript::attachedPropertyScope()
2106 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2108 QObject *object = component.create();
2109 QVERIFY(object != 0);
2111 MyQmlAttachedObject *attached =
2112 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2113 QVERIFY(attached != 0);
2115 QCOMPARE(object->property("value2").toInt(), 0);
2117 attached->emitMySignal();
2119 QCOMPARE(object->property("value2").toInt(), 9);
2124 void tst_qdeclarativeecmascript::scriptConnect()
2127 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2129 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2130 QVERIFY(object != 0);
2132 QCOMPARE(object->property("test").toBool(), false);
2133 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2134 QCOMPARE(object->property("test").toBool(), true);
2140 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2142 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2143 QVERIFY(object != 0);
2145 QCOMPARE(object->property("test").toBool(), false);
2146 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2147 QCOMPARE(object->property("test").toBool(), true);
2153 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2155 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2156 QVERIFY(object != 0);
2158 QCOMPARE(object->property("test").toBool(), false);
2159 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2160 QCOMPARE(object->property("test").toBool(), true);
2166 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2168 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2169 QVERIFY(object != 0);
2171 QCOMPARE(object->methodCalled(), false);
2172 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2173 QCOMPARE(object->methodCalled(), true);
2179 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2181 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2182 QVERIFY(object != 0);
2184 QCOMPARE(object->methodCalled(), false);
2185 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2186 QCOMPARE(object->methodCalled(), true);
2192 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2194 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2195 QVERIFY(object != 0);
2197 QCOMPARE(object->property("test").toInt(), 0);
2198 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2199 QCOMPARE(object->property("test").toInt(), 2);
2205 void tst_qdeclarativeecmascript::scriptDisconnect()
2208 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.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(), 1);
2216 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2217 QCOMPARE(object->property("test").toInt(), 2);
2218 emit object->basicSignal();
2219 QCOMPARE(object->property("test").toInt(), 2);
2220 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2221 QCOMPARE(object->property("test").toInt(), 2);
2227 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2229 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2230 QVERIFY(object != 0);
2232 QCOMPARE(object->property("test").toInt(), 0);
2233 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2234 QCOMPARE(object->property("test").toInt(), 1);
2235 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2236 QCOMPARE(object->property("test").toInt(), 2);
2237 emit object->basicSignal();
2238 QCOMPARE(object->property("test").toInt(), 2);
2239 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2240 QCOMPARE(object->property("test").toInt(), 2);
2246 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2248 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2249 QVERIFY(object != 0);
2251 QCOMPARE(object->property("test").toInt(), 0);
2252 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2253 QCOMPARE(object->property("test").toInt(), 1);
2254 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2255 QCOMPARE(object->property("test").toInt(), 2);
2256 emit object->basicSignal();
2257 QCOMPARE(object->property("test").toInt(), 2);
2258 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2259 QCOMPARE(object->property("test").toInt(), 3);
2264 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2266 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2267 QVERIFY(object != 0);
2269 QCOMPARE(object->property("test").toInt(), 0);
2270 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2271 QCOMPARE(object->property("test").toInt(), 1);
2272 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2273 QCOMPARE(object->property("test").toInt(), 2);
2274 emit object->basicSignal();
2275 QCOMPARE(object->property("test").toInt(), 2);
2276 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2277 QCOMPARE(object->property("test").toInt(), 3);
2283 class OwnershipObject : public QObject
2287 OwnershipObject() { object = new QObject; }
2289 QPointer<QObject> object;
2292 QObject *getObject() { return object; }
2295 void tst_qdeclarativeecmascript::ownership()
2297 OwnershipObject own;
2298 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2299 context->setContextObject(&own);
2302 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2304 QVERIFY(own.object != 0);
2306 QObject *object = component.create(context);
2308 engine.collectGarbage();
2310 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2312 QVERIFY(own.object == 0);
2317 own.object = new QObject(&own);
2320 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2322 QVERIFY(own.object != 0);
2324 QObject *object = component.create(context);
2326 engine.collectGarbage();
2328 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2330 QVERIFY(own.object != 0);
2338 class CppOwnershipReturnValue : public QObject
2342 CppOwnershipReturnValue() : value(0) {}
2343 ~CppOwnershipReturnValue() { delete value; }
2345 Q_INVOKABLE QObject *create() {
2346 value = new QObject;
2347 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2351 Q_INVOKABLE MyQmlObject *createQmlObject() {
2352 MyQmlObject *rv = new MyQmlObject;
2357 QPointer<QObject> value;
2361 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2362 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2364 CppOwnershipReturnValue source;
2367 QDeclarativeEngine engine;
2368 engine.rootContext()->setContextProperty("source", &source);
2370 QVERIFY(source.value == 0);
2372 QDeclarativeComponent component(&engine);
2373 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2375 QObject *object = component.create();
2377 QVERIFY(object != 0);
2378 QVERIFY(source.value != 0);
2383 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2385 QVERIFY(source.value != 0);
2389 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2391 CppOwnershipReturnValue source;
2394 QDeclarativeEngine engine;
2395 engine.rootContext()->setContextProperty("source", &source);
2397 QVERIFY(source.value == 0);
2399 QDeclarativeComponent component(&engine);
2400 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2402 QObject *object = component.create();
2404 QVERIFY(object != 0);
2405 QVERIFY(source.value != 0);
2410 engine.collectGarbage();
2411 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2413 QVERIFY(source.value == 0);
2416 class QListQObjectMethodsObject : public QObject
2420 QListQObjectMethodsObject() {
2421 m_objects.append(new MyQmlObject());
2422 m_objects.append(new MyQmlObject());
2425 ~QListQObjectMethodsObject() {
2426 qDeleteAll(m_objects);
2430 QList<QObject *> getObjects() { return m_objects; }
2433 QList<QObject *> m_objects;
2436 // Tests that returning a QList<QObject*> from a method works
2437 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2439 QListQObjectMethodsObject obj;
2440 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2441 context->setContextObject(&obj);
2443 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2445 QObject *object = component.create(context);
2447 QCOMPARE(object->property("test").toInt(), 2);
2448 QCOMPARE(object->property("test2").toBool(), true);
2455 void tst_qdeclarativeecmascript::strictlyEquals()
2457 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2459 QObject *object = component.create();
2460 QVERIFY(object != 0);
2462 QCOMPARE(object->property("test1").toBool(), true);
2463 QCOMPARE(object->property("test2").toBool(), true);
2464 QCOMPARE(object->property("test3").toBool(), true);
2465 QCOMPARE(object->property("test4").toBool(), true);
2466 QCOMPARE(object->property("test5").toBool(), true);
2467 QCOMPARE(object->property("test6").toBool(), true);
2468 QCOMPARE(object->property("test7").toBool(), true);
2469 QCOMPARE(object->property("test8").toBool(), true);
2474 void tst_qdeclarativeecmascript::compiled()
2476 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2478 QObject *object = component.create();
2479 QVERIFY(object != 0);
2481 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2482 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2483 QCOMPARE(object->property("test3").toBool(), true);
2484 QCOMPARE(object->property("test4").toBool(), false);
2485 QCOMPARE(object->property("test5").toBool(), false);
2486 QCOMPARE(object->property("test6").toBool(), true);
2488 QCOMPARE(object->property("test7").toInt(), 185);
2489 QCOMPARE(object->property("test8").toInt(), 167);
2490 QCOMPARE(object->property("test9").toBool(), true);
2491 QCOMPARE(object->property("test10").toBool(), false);
2492 QCOMPARE(object->property("test11").toBool(), false);
2493 QCOMPARE(object->property("test12").toBool(), true);
2495 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2496 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2497 QCOMPARE(object->property("test15").toBool(), false);
2498 QCOMPARE(object->property("test16").toBool(), true);
2500 QCOMPARE(object->property("test17").toInt(), 5);
2501 QCOMPARE(object->property("test18").toReal(), qreal(176));
2502 QCOMPARE(object->property("test19").toInt(), 7);
2503 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2504 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2505 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2506 QCOMPARE(object->property("test23").toBool(), true);
2507 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2508 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2513 // Test that numbers assigned in bindings as strings work consistently
2514 void tst_qdeclarativeecmascript::numberAssignment()
2516 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2518 QObject *object = component.create();
2519 QVERIFY(object != 0);
2521 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2522 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2523 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2524 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2525 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2527 QCOMPARE(object->property("test5"), QVariant((int)7));
2528 QCOMPARE(object->property("test6"), QVariant((int)7));
2529 QCOMPARE(object->property("test7"), QVariant((int)6));
2530 QCOMPARE(object->property("test8"), QVariant((int)6));
2532 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2533 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2534 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2535 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2540 void tst_qdeclarativeecmascript::propertySplicing()
2542 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2544 QObject *object = component.create();
2545 QVERIFY(object != 0);
2547 QCOMPARE(object->property("test").toBool(), true);
2553 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2555 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2557 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2558 QVERIFY(object != 0);
2560 MyQmlObject::MyType type;
2561 type.value = 0x8971123;
2562 emit object->signalWithUnknownType(type);
2564 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2566 QCOMPARE(result.value, type.value);
2572 void tst_qdeclarativeecmascript::moduleApi()
2574 QSKIP("Module API not supported with V8", SkipAll);
2576 QDeclarativeComponent component(&engine, TEST_FILE("moduleApi.qml"));
2577 QObject *object = component.create();
2578 QVERIFY(object != 0);
2579 QCOMPARE(object->property("existingUriTest").toInt(), 20);
2580 QCOMPARE(object->property("scriptTest").toInt(), 13);
2581 QCOMPARE(object->property("qobjectTest").toInt(), 20);
2582 QCOMPARE(object->property("qobjectMethodTest").toInt(), 1); // first call of method, so count = 1.
2583 QCOMPARE(object->property("qobjectMinorVersionTest").toInt(), 20);
2584 QCOMPARE(object->property("qobjectMajorVersionTest").toInt(), 20);
2585 QCOMPARE(object->property("qobjectParentedTest").toInt(), 26);
2588 // test that caching of module apis works correctly.
2589 QDeclarativeComponent componentTwo(&engine, TEST_FILE("moduleApiCaching.qml"));
2590 object = componentTwo.create();
2591 QVERIFY(object != 0);
2592 QCOMPARE(object->property("existingUriTest").toInt(), 20);
2593 QCOMPARE(object->property("scriptTest").toInt(), 13); // shouldn't have incremented.
2594 QCOMPARE(object->property("qobjectParentedTest").toInt(), 26); // shouldn't have incremented.
2597 // test that writing to a property of module apis works correctly.
2598 QDeclarativeComponent componentThree(&engine, TEST_FILE("moduleApiWriting.qml"));
2599 QString expectedWarning = QLatin1String("file://") + TEST_FILE("moduleApiWriting.qml").toLocalFile() + QLatin1String(":15: Error: Cannot assign to read-only property \"qobjectTestProperty\"");
2600 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2601 object = componentThree.create();
2602 QVERIFY(object != 0);
2603 QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
2604 QCOMPARE(object->property("writableProperty").toInt(), 50);
2605 QVERIFY(object->setProperty("firstProperty", QVariant(30))); // shouldn't affect value of readOnlyProperty
2606 QVERIFY(object->setProperty("writableProperty", QVariant(30))); // SHOULD affect value of writableProperty
2607 QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
2608 QCOMPARE(object->property("writableProperty").toInt(), 30);
2611 QDeclarativeComponent failOne(&engine, TEST_FILE("moduleApiMajorVersionFail.qml"));
2612 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2613 object = failOne.create();
2614 QVERIFY(object == 0); // should have failed: invalid major version
2616 QDeclarativeComponent failTwo(&engine, TEST_FILE("moduleApiMinorVersionFail.qml"));
2617 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2618 object = failTwo.create();
2619 QVERIFY(object == 0); // should have failed: invalid minor version
2622 void tst_qdeclarativeecmascript::importScripts()
2624 QObject *object = 0;
2626 // first, ensure that the required behaviour works.
2627 QDeclarativeComponent component(&engine, TEST_FILE("jsimport/testImport.qml"));
2628 object = component.create();
2629 QVERIFY(object != 0);
2630 QCOMPARE(object->property("importedScriptStringValue"), QVariant(QString(QLatin1String("Hello, World!"))));
2631 QCOMPARE(object->property("importedScriptFunctionValue"), QVariant(20));
2632 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(19));
2633 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(2));
2636 QDeclarativeComponent componentTwo(&engine, TEST_FILE("jsimport/testImportScoping.qml"));
2637 object = componentTwo.create();
2638 QVERIFY(object != 0);
2639 QCOMPARE(object->property("componentError"), QVariant(5));
2642 // then, ensure that unintended behaviour does not work.
2643 QDeclarativeComponent failOneComponent(&engine, TEST_FILE("jsimportfail/failOne.qml"));
2644 QString expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined");
2645 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2646 object = failOneComponent.create();
2647 QVERIFY(object != 0);
2648 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2650 QDeclarativeComponent failTwoComponent(&engine, TEST_FILE("jsimportfail/failTwo.qml"));
2651 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs");
2652 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2653 object = failTwoComponent.create();
2654 QVERIFY(object != 0);
2655 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2657 QDeclarativeComponent failThreeComponent(&engine, TEST_FILE("jsimportfail/failThree.qml"));
2658 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined");
2659 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2660 object = failThreeComponent.create();
2661 QVERIFY(object != 0);
2662 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(false));
2664 QDeclarativeComponent failFourComponent(&engine, TEST_FILE("jsimportfail/failFour.qml"));
2665 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest");
2666 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2667 object = failFourComponent.create();
2668 QVERIFY(object != 0);
2669 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(0));
2671 QDeclarativeComponent failFiveComponent(&engine, TEST_FILE("jsimportfail/failFive.qml"));
2672 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component");
2673 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2674 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component");
2675 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2676 object = failFiveComponent.create();
2677 QVERIFY(object != 0);
2678 QCOMPARE(object->property("componentError"), QVariant(0));
2681 // also, test that importing scripts with .pragma library works as required
2682 QDeclarativeComponent pragmaLibraryComponent(&engine, TEST_FILE("jsimport/testImportPragmaLibrary.qml"));
2683 object = pragmaLibraryComponent.create();
2684 QVERIFY(object != 0);
2685 QCOMPARE(object->property("testValue"), QVariant(31));
2688 // and that .pragma library scripts don't inherit imports from any .qml file
2689 QDeclarativeComponent pragmaLibraryComponentTwo(&engine, TEST_FILE("jsimportfail/testImportPragmaLibrary.qml"));
2690 object = pragmaLibraryComponentTwo.create();
2691 QVERIFY(object != 0);
2692 QCOMPARE(object->property("testValue"), QVariant(0));
2696 void tst_qdeclarativeecmascript::scarceResources()
2698 QPixmap origPixmap(100, 100);
2699 origPixmap.fill(Qt::blue);
2701 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
2702 ScarceResourceObject *eo = 0;
2703 QObject *object = 0;
2705 // in the following three cases, the instance created from the component
2706 // has a property which is a copy of the scarce resource; hence, the
2707 // resource should NOT be detached prior to deletion of the object instance,
2708 // unless the resource is destroyed explicitly.
2709 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
2710 object = component.create();
2711 QVERIFY(object != 0);
2712 QVERIFY(object->property("scarceResourceCopy").isValid());
2713 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2714 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2715 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2716 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
2719 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
2720 object = componentTwo.create();
2721 QVERIFY(object != 0);
2722 QVERIFY(object->property("scarceResourceCopy").isValid());
2723 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2724 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2725 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2726 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
2729 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
2730 object = componentThree.create();
2731 QVERIFY(object != 0);
2732 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
2733 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2734 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2735 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
2738 // in the following three cases, no other copy should exist in memory,
2739 // and so it should be detached (unless explicitly preserved).
2740 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
2741 object = componentFour.create();
2742 QVERIFY(object != 0);
2743 QVERIFY(object->property("scarceResourceTest").isValid());
2744 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2745 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2746 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2747 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
2750 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
2751 object = componentFive.create();
2752 QVERIFY(object != 0);
2753 QVERIFY(object->property("scarceResourceTest").isValid());
2754 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2755 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2756 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2757 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
2760 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
2761 object = componentSix.create();
2762 QVERIFY(object != 0);
2763 QVERIFY(object->property("scarceResourceTest").isValid());
2764 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2765 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2766 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2767 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
2770 // test that scarce resources are handled correctly for imports
2771 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
2772 object = componentSeven.create();
2773 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
2774 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
2777 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
2778 object = componentEight.create();
2779 QVERIFY(object != 0);
2780 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
2781 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2784 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
2785 object = componentNine.create();
2786 QVERIFY(object != 0);
2787 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
2788 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2789 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
2790 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
2791 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
2792 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
2795 // test that scarce resources are handled properly in signal invocation
2796 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
2797 object = componentTen.create();
2798 QVERIFY(object != 0);
2799 QObject *srsc = object->findChild<QObject*>("srsc");
2801 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
2802 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
2803 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2804 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2805 QMetaObject::invokeMethod(srsc, "testSignal");
2806 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
2807 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
2808 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2809 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
2810 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
2811 QVERIFY(srsc->property("scarceResourceCopy").isValid());
2812 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2813 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2814 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
2815 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2818 // test that scarce resources are handled properly from js functions in qml files
2819 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
2820 object = componentEleven.create();
2821 QVERIFY(object != 0);
2822 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
2823 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2824 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2825 QMetaObject::invokeMethod(object, "retrieveScarceResource");
2826 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
2827 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2828 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2829 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
2830 QMetaObject::invokeMethod(object, "releaseScarceResource");
2831 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
2832 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2833 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2834 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2837 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
2838 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
2839 object = componentTwelve.create();
2840 QVERIFY(object != 0);
2841 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
2842 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2843 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2844 QString srp_name = object->property("srp_name").toString();
2845 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
2846 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
2847 QMetaObject::invokeMethod(object, "retrieveScarceResource");
2848 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
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.
2855 void tst_qdeclarativeecmascript::propertyChangeSlots()
2857 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
2858 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
2859 QObject *object = component.create();
2860 QVERIFY(object != 0);
2863 // ensure that invalid property names fail properly.
2864 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2865 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
2866 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
2867 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
2868 object = e1.create();
2869 QVERIFY(object == 0);
2872 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2873 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
2874 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
2875 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
2876 object = e2.create();
2877 QVERIFY(object == 0);
2880 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2881 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
2882 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
2883 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
2884 object = e3.create();
2885 QVERIFY(object == 0);
2888 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2889 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
2890 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
2891 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
2892 object = e4.create();
2893 QVERIFY(object == 0);
2897 // Test that assigning a null object works
2898 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
2899 void tst_qdeclarativeecmascript::nullObjectBinding()
2901 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
2903 QObject *object = component.create();
2904 QVERIFY(object != 0);
2906 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
2911 // Test that bindings don't evaluate once the engine has been destroyed
2912 void tst_qdeclarativeecmascript::deletedEngine()
2914 QDeclarativeEngine *engine = new QDeclarativeEngine;
2915 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
2917 QObject *object = component.create();
2918 QVERIFY(object != 0);
2920 QCOMPARE(object->property("a").toInt(), 39);
2921 object->setProperty("b", QVariant(9));
2922 QCOMPARE(object->property("a").toInt(), 117);
2926 QCOMPARE(object->property("a").toInt(), 117);
2927 object->setProperty("b", QVariant(10));
2928 QCOMPARE(object->property("a").toInt(), 117);
2933 // Test the crashing part of QTBUG-9705
2934 void tst_qdeclarativeecmascript::libraryScriptAssert()
2936 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
2938 QObject *object = component.create();
2939 QVERIFY(object != 0);
2944 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
2946 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
2948 QObject *object = component.create();
2949 QVERIFY(object != 0);
2951 QCOMPARE(object->property("test1").toInt(), 10);
2952 QCOMPARE(object->property("test2").toInt(), 11);
2954 object->setProperty("runTest", true);
2956 QCOMPARE(object->property("test1"), QVariant());
2957 QCOMPARE(object->property("test2"), QVariant());
2963 void tst_qdeclarativeecmascript::qtbug_9792()
2965 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
2967 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2969 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
2970 QVERIFY(object != 0);
2972 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
2973 object->basicSignal();
2977 transientErrorsMsgCount = 0;
2978 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
2980 object->basicSignal();
2982 qInstallMsgHandler(old);
2984 QCOMPARE(transientErrorsMsgCount, 0);
2989 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
2990 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
2992 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
2994 QObject *o = component.create();
2997 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
2998 QVERIFY(nested != 0);
3000 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
3003 nested = qvariant_cast<QObject *>(o->property("object"));
3004 QVERIFY(nested == 0);
3006 // If the bug is present, the next line will crash
3010 // Test that we shut down without stupid warnings
3011 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
3014 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
3016 QObject *o = component.create();
3018 transientErrorsMsgCount = 0;
3019 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3023 qInstallMsgHandler(old);
3025 QCOMPARE(transientErrorsMsgCount, 0);
3030 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
3032 QObject *o = component.create();
3034 transientErrorsMsgCount = 0;
3035 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3039 qInstallMsgHandler(old);
3041 QCOMPARE(transientErrorsMsgCount, 0);
3045 void tst_qdeclarativeecmascript::canAssignNullToQObject()
3048 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
3050 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3053 QVERIFY(o->objectProperty() != 0);
3055 o->setProperty("runTest", true);
3057 QVERIFY(o->objectProperty() == 0);
3063 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
3065 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3068 QVERIFY(o->objectProperty() == 0);
3074 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
3076 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
3078 QString url = component.url().toString();
3079 QString warning = url + ":4: Unable to assign a function to a property.";
3080 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3082 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3085 QVERIFY(!o->property("a").isValid());
3090 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
3092 QFETCH(QString, triggerProperty);
3094 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3095 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3097 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3099 QVERIFY(!o->property("a").isValid());
3101 o->setProperty("aNumber", QVariant(5));
3102 o->setProperty(triggerProperty.toUtf8().constData(), true);
3103 QCOMPARE(o->property("a"), QVariant(50));
3105 o->setProperty("aNumber", QVariant(10));
3106 QCOMPARE(o->property("a"), QVariant(100));
3111 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
3113 QTest::addColumn<QString>("triggerProperty");
3115 QTest::newRow("assign to property") << "assignToProperty";
3116 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
3118 QTest::newRow("assign to value type") << "assignToValueType";
3120 QTest::newRow("use 'this'") << "assignWithThis";
3121 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
3124 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
3126 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3127 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3129 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3131 QVERIFY(!o->property("a").isValid());
3133 o->setProperty("assignFuncWithoutReturn", true);
3134 QVERIFY(!o->property("a").isValid());
3136 QString url = component.url().toString();
3137 QString warning = url + ":67: Unable to assign QString to int";
3138 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3139 o->setProperty("assignWrongType", true);
3141 warning = url + ":71: Unable to assign QString to int";
3142 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3143 o->setProperty("assignWrongTypeToValueType", true);
3148 void tst_qdeclarativeecmascript::eval()
3150 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
3152 QObject *o = component.create();
3155 QCOMPARE(o->property("test1").toBool(), true);
3156 QCOMPARE(o->property("test2").toBool(), true);
3157 QCOMPARE(o->property("test3").toBool(), true);
3158 QCOMPARE(o->property("test4").toBool(), true);
3159 QCOMPARE(o->property("test5").toBool(), true);
3164 void tst_qdeclarativeecmascript::function()
3166 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
3168 QObject *o = component.create();
3171 QCOMPARE(o->property("test1").toBool(), true);
3172 QCOMPARE(o->property("test2").toBool(), true);
3173 QCOMPARE(o->property("test3").toBool(), true);
3178 // Test the "Qt.include" method
3179 void tst_qdeclarativeecmascript::include()
3181 // Non-library relative include
3183 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
3184 QObject *o = component.create();
3187 QCOMPARE(o->property("test0").toInt(), 99);
3188 QCOMPARE(o->property("test1").toBool(), true);
3189 QCOMPARE(o->property("test2").toBool(), true);
3190 QCOMPARE(o->property("test2_1").toBool(), true);
3191 QCOMPARE(o->property("test3").toBool(), true);
3192 QCOMPARE(o->property("test3_1").toBool(), true);
3197 // Library relative include
3199 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
3200 QObject *o = component.create();
3203 QCOMPARE(o->property("test0").toInt(), 99);
3204 QCOMPARE(o->property("test1").toBool(), true);
3205 QCOMPARE(o->property("test2").toBool(), true);
3206 QCOMPARE(o->property("test2_1").toBool(), true);
3207 QCOMPARE(o->property("test3").toBool(), true);
3208 QCOMPARE(o->property("test3_1").toBool(), true);
3215 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
3216 QObject *o = component.create();
3219 QCOMPARE(o->property("test1").toBool(), true);
3220 QCOMPARE(o->property("test2").toBool(), true);
3221 QCOMPARE(o->property("test3").toBool(), true);
3222 QCOMPARE(o->property("test4").toBool(), true);
3223 QCOMPARE(o->property("test5").toBool(), true);
3224 QCOMPARE(o->property("test6").toBool(), true);
3229 // Including file with ".pragma library"
3231 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
3232 QObject *o = component.create();
3234 QCOMPARE(o->property("test1").toInt(), 100);
3241 TestHTTPServer server(8111);
3242 QVERIFY(server.isValid());
3243 server.serveDirectory(SRCDIR "/data");
3245 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
3246 QObject *o = component.create();
3249 QTRY_VERIFY(o->property("done").toBool() == true);
3250 QTRY_VERIFY(o->property("done2").toBool() == true);
3252 QCOMPARE(o->property("test1").toBool(), true);
3253 QCOMPARE(o->property("test2").toBool(), true);
3254 QCOMPARE(o->property("test3").toBool(), true);
3255 QCOMPARE(o->property("test4").toBool(), true);
3256 QCOMPARE(o->property("test5").toBool(), true);
3258 QCOMPARE(o->property("test6").toBool(), true);
3259 QCOMPARE(o->property("test7").toBool(), true);
3260 QCOMPARE(o->property("test8").toBool(), true);
3261 QCOMPARE(o->property("test9").toBool(), true);
3262 QCOMPARE(o->property("test10").toBool(), true);
3269 TestHTTPServer server(8111);
3270 QVERIFY(server.isValid());
3271 server.serveDirectory(SRCDIR "/data");
3273 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
3274 QObject *o = component.create();
3277 QTRY_VERIFY(o->property("done").toBool() == true);
3279 QCOMPARE(o->property("test1").toBool(), true);
3280 QCOMPARE(o->property("test2").toBool(), true);
3281 QCOMPARE(o->property("test3").toBool(), true);
3287 void tst_qdeclarativeecmascript::qtbug_10696()
3289 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
3290 QObject *o = component.create();
3295 void tst_qdeclarativeecmascript::qtbug_11606()
3297 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
3298 QObject *o = component.create();
3300 QCOMPARE(o->property("test").toBool(), true);
3304 void tst_qdeclarativeecmascript::qtbug_11600()
3306 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
3307 QObject *o = component.create();
3309 QCOMPARE(o->property("test").toBool(), true);
3313 // Reading and writing non-scriptable properties should fail
3314 void tst_qdeclarativeecmascript::nonscriptable()
3316 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
3317 QObject *o = component.create();
3319 QCOMPARE(o->property("readOk").toBool(), true);
3320 QCOMPARE(o->property("writeOk").toBool(), true);
3324 // deleteLater() should not be callable from QML
3325 void tst_qdeclarativeecmascript::deleteLater()
3327 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
3328 QObject *o = component.create();
3330 QCOMPARE(o->property("test").toBool(), true);
3334 void tst_qdeclarativeecmascript::in()
3336 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
3337 QObject *o = component.create();
3339 QCOMPARE(o->property("test1").toBool(), true);
3340 QCOMPARE(o->property("test2").toBool(), true);
3344 void tst_qdeclarativeecmascript::sharedAttachedObject()
3346 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
3347 QObject *o = component.create();
3349 QCOMPARE(o->property("test1").toBool(), true);
3350 QCOMPARE(o->property("test2").toBool(), true);
3355 void tst_qdeclarativeecmascript::objectName()
3357 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
3358 QObject *o = component.create();
3361 QCOMPARE(o->property("test1").toString(), QString("hello"));
3362 QCOMPARE(o->property("test2").toString(), QString("ell"));
3364 o->setObjectName("world");
3366 QCOMPARE(o->property("test1").toString(), QString("world"));
3367 QCOMPARE(o->property("test2").toString(), QString("orl"));
3372 void tst_qdeclarativeecmascript::writeRemovesBinding()
3374 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
3375 QObject *o = component.create();
3378 QCOMPARE(o->property("test").toBool(), true);
3383 // Test bindings assigned to alias properties actually assign to the alias' target
3384 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
3386 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
3387 QObject *o = component.create();
3390 QCOMPARE(o->property("test").toBool(), true);
3395 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
3396 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
3399 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
3400 QObject *o = component.create();
3403 QCOMPARE(o->property("test").toBool(), true);
3409 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
3410 QObject *o = component.create();
3413 QCOMPARE(o->property("test").toBool(), true);
3419 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
3420 QObject *o = component.create();
3423 QCOMPARE(o->property("test").toBool(), true);
3429 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
3430 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
3433 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
3434 QObject *o = component.create();
3437 QCOMPARE(o->property("test").toBool(), true);
3443 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
3444 QObject *o = component.create();
3447 QCOMPARE(o->property("test").toBool(), true);
3453 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
3454 QObject *o = component.create();
3457 QCOMPARE(o->property("test").toBool(), true);
3463 void tst_qdeclarativeecmascript::revisionErrors()
3466 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
3467 QString url = component.url().toString();
3469 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
3470 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
3471 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
3473 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3474 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3475 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3476 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3477 QVERIFY(object != 0);
3481 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
3482 QString url = component.url().toString();
3484 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
3485 // method2, prop2 from MyRevisionedClass not available
3486 // method4, prop4 from MyRevisionedSubclass not available
3487 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
3488 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
3489 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
3490 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
3491 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
3493 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3494 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3495 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3496 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
3497 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
3498 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3499 QVERIFY(object != 0);
3503 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
3504 QString url = component.url().toString();
3506 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
3507 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
3508 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
3509 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
3510 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
3511 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3512 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3513 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3514 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3515 QVERIFY(object != 0);
3520 void tst_qdeclarativeecmascript::revision()
3523 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
3524 QString url = component.url().toString();
3526 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3527 QVERIFY(object != 0);
3531 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
3532 QString url = component.url().toString();
3534 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3535 QVERIFY(object != 0);
3539 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
3540 QString url = component.url().toString();
3542 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3543 QVERIFY(object != 0);
3546 // Test that non-root classes can resolve revisioned methods
3548 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
3550 QObject *object = component.create();
3551 QVERIFY(object != 0);
3552 QCOMPARE(object->property("test").toReal(), 11.);
3557 void tst_qdeclarativeecmascript::realToInt()
3559 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
3560 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
3561 QVERIFY(object != 0);
3563 QMetaObject::invokeMethod(object, "test1");
3564 QCOMPARE(object->value(), int(4));
3565 QMetaObject::invokeMethod(object, "test2");
3566 QCOMPARE(object->value(), int(8));
3569 QTEST_MAIN(tst_qdeclarativeecmascript)
3571 #include "tst_qdeclarativeecmascript.moc"