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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file. Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights. These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
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();
181 void pushCleanContext();
186 void callQtInvokables();
187 void invokableObjectArg();
188 void invokableObjectRet();
190 void revisionErrors();
193 QDeclarativeEngine engine;
196 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
198 void tst_qdeclarativeecmascript::assignBasicTypes()
201 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
202 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
203 QVERIFY(object != 0);
204 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
205 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
206 QCOMPARE(object->stringProperty(), QString("Hello World!"));
207 QCOMPARE(object->uintProperty(), uint(10));
208 QCOMPARE(object->intProperty(), -19);
209 QCOMPARE((float)object->realProperty(), float(23.2));
210 QCOMPARE((float)object->doubleProperty(), float(-19.75));
211 QCOMPARE((float)object->floatProperty(), float(8.5));
212 QCOMPARE(object->colorProperty(), QColor("red"));
213 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
214 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
215 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
216 QCOMPARE(object->pointProperty(), QPoint(99,13));
217 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
218 QCOMPARE(object->sizeProperty(), QSize(99, 13));
219 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
220 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
221 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
222 QCOMPARE(object->boolProperty(), true);
223 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
224 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
225 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
229 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
230 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
231 QVERIFY(object != 0);
232 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
233 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
234 QCOMPARE(object->stringProperty(), QString("Hello World!"));
235 QCOMPARE(object->uintProperty(), uint(10));
236 QCOMPARE(object->intProperty(), -19);
237 QCOMPARE((float)object->realProperty(), float(23.2));
238 QCOMPARE((float)object->doubleProperty(), float(-19.75));
239 QCOMPARE((float)object->floatProperty(), float(8.5));
240 QCOMPARE(object->colorProperty(), QColor("red"));
241 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
242 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
243 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
244 QCOMPARE(object->pointProperty(), QPoint(99,13));
245 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
246 QCOMPARE(object->sizeProperty(), QSize(99, 13));
247 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
248 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
249 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
250 QCOMPARE(object->boolProperty(), true);
251 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
252 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
253 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
258 void tst_qdeclarativeecmascript::idShortcutInvalidates()
261 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
262 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
263 QVERIFY(object != 0);
264 QVERIFY(object->objectProperty() != 0);
265 delete object->objectProperty();
266 QVERIFY(object->objectProperty() == 0);
271 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
272 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
273 QVERIFY(object != 0);
274 QVERIFY(object->objectProperty() != 0);
275 delete object->objectProperty();
276 QVERIFY(object->objectProperty() == 0);
281 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
284 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
285 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
286 QVERIFY(object != 0);
287 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
291 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
292 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
293 QVERIFY(object != 0);
294 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
299 void tst_qdeclarativeecmascript::signalAssignment()
302 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
303 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
304 QVERIFY(object != 0);
305 QCOMPARE(object->string(), QString());
306 emit object->basicSignal();
307 QCOMPARE(object->string(), QString("pass"));
312 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
313 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
314 QVERIFY(object != 0);
315 QCOMPARE(object->string(), QString());
316 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
317 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
322 void tst_qdeclarativeecmascript::methods()
325 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
326 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
327 QVERIFY(object != 0);
328 QCOMPARE(object->methodCalled(), false);
329 QCOMPARE(object->methodIntCalled(), false);
330 emit object->basicSignal();
331 QCOMPARE(object->methodCalled(), true);
332 QCOMPARE(object->methodIntCalled(), false);
337 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
338 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
339 QVERIFY(object != 0);
340 QCOMPARE(object->methodCalled(), false);
341 QCOMPARE(object->methodIntCalled(), false);
342 emit object->basicSignal();
343 QCOMPARE(object->methodCalled(), false);
344 QCOMPARE(object->methodIntCalled(), true);
349 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
350 QObject *object = component.create();
351 QVERIFY(object != 0);
352 QCOMPARE(object->property("test").toInt(), 19);
357 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
358 QObject *object = component.create();
359 QVERIFY(object != 0);
360 QCOMPARE(object->property("test").toInt(), 19);
361 QCOMPARE(object->property("test2").toInt(), 17);
362 QCOMPARE(object->property("test3").toInt(), 16);
367 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
368 QObject *object = component.create();
369 QVERIFY(object != 0);
370 QCOMPARE(object->property("test").toInt(), 9);
375 void tst_qdeclarativeecmascript::bindingLoop()
377 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
378 QString warning = component.url().toString() + ":9:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
379 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
380 QObject *object = component.create();
381 QVERIFY(object != 0);
385 void tst_qdeclarativeecmascript::basicExpressions_data()
387 QTest::addColumn<QString>("expression");
388 QTest::addColumn<QVariant>("result");
389 QTest::addColumn<bool>("nest");
391 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
392 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
393 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
394 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
395 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
396 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
397 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
398 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
399 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
400 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
401 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
402 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
403 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
404 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
405 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
406 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
407 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
408 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
409 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
412 void tst_qdeclarativeecmascript::basicExpressions()
414 QFETCH(QString, expression);
415 QFETCH(QVariant, result);
421 MyDefaultObject1 default1;
422 MyDefaultObject3 default3;
423 object1.setStringProperty("Object1");
424 object2.setStringProperty("Object2");
425 object3.setStringProperty("Object3");
427 QDeclarativeContext context(engine.rootContext());
428 QDeclarativeContext nestedContext(&context);
430 context.setContextObject(&default1);
431 context.setContextProperty("a", QVariant(1944));
432 context.setContextProperty("b", QVariant("Milk"));
433 context.setContextProperty("object", &object1);
434 context.setContextProperty("objectOverride", &object2);
435 nestedContext.setContextObject(&default3);
436 nestedContext.setContextProperty("b", QVariant("Cow"));
437 nestedContext.setContextProperty("objectOverride", &object3);
438 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
440 MyExpression expr(nest?&nestedContext:&context, expression);
441 QCOMPARE(expr.evaluate(), result);
444 void tst_qdeclarativeecmascript::arrayExpressions()
450 QDeclarativeContext context(engine.rootContext());
451 context.setContextProperty("a", &obj1);
452 context.setContextProperty("b", &obj2);
453 context.setContextProperty("c", &obj3);
455 MyExpression expr(&context, "[a, b, c, 10]");
456 QVariant result = expr.evaluate();
457 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
458 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
459 QCOMPARE(list.count(), 4);
460 QCOMPARE(list.at(0), &obj1);
461 QCOMPARE(list.at(1), &obj2);
462 QCOMPARE(list.at(2), &obj3);
463 QCOMPARE(list.at(3), (QObject *)0);
466 // Tests that modifying a context property will reevaluate expressions
467 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
469 QDeclarativeContext context(engine.rootContext());
472 MyQmlObject *object3 = new MyQmlObject;
474 object1.setStringProperty("Hello");
475 object2.setStringProperty("World");
477 context.setContextProperty("testProp", QVariant(1));
478 context.setContextProperty("testObj", &object1);
479 context.setContextProperty("testObj2", object3);
482 MyExpression expr(&context, "testProp + 1");
483 QCOMPARE(expr.changed, false);
484 QCOMPARE(expr.evaluate(), QVariant(2));
486 context.setContextProperty("testProp", QVariant(2));
487 QCOMPARE(expr.changed, true);
488 QCOMPARE(expr.evaluate(), QVariant(3));
492 MyExpression expr(&context, "testProp + testProp + testProp");
493 QCOMPARE(expr.changed, false);
494 QCOMPARE(expr.evaluate(), QVariant(6));
496 context.setContextProperty("testProp", QVariant(4));
497 QCOMPARE(expr.changed, true);
498 QCOMPARE(expr.evaluate(), QVariant(12));
502 MyExpression expr(&context, "testObj.stringProperty");
503 QCOMPARE(expr.changed, false);
504 QCOMPARE(expr.evaluate(), QVariant("Hello"));
506 context.setContextProperty("testObj", &object2);
507 QCOMPARE(expr.changed, true);
508 QCOMPARE(expr.evaluate(), QVariant("World"));
512 MyExpression expr(&context, "testObj.stringProperty /**/");
513 QCOMPARE(expr.changed, false);
514 QCOMPARE(expr.evaluate(), QVariant("World"));
516 context.setContextProperty("testObj", &object1);
517 QCOMPARE(expr.changed, true);
518 QCOMPARE(expr.evaluate(), QVariant("Hello"));
522 MyExpression expr(&context, "testObj2");
523 QCOMPARE(expr.changed, false);
524 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
530 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
532 QDeclarativeContext context(engine.rootContext());
536 context.setContextProperty("testObj", &object1);
538 object1.setStringProperty(QLatin1String("Hello"));
539 object2.setStringProperty(QLatin1String("Dog"));
540 object3.setStringProperty(QLatin1String("Cat"));
543 MyExpression expr(&context, "testObj.stringProperty");
544 QCOMPARE(expr.changed, false);
545 QCOMPARE(expr.evaluate(), QVariant("Hello"));
547 object1.setStringProperty(QLatin1String("World"));
548 QCOMPARE(expr.changed, true);
549 QCOMPARE(expr.evaluate(), QVariant("World"));
553 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
554 QCOMPARE(expr.changed, false);
555 QCOMPARE(expr.evaluate(), QVariant());
557 object1.setObjectProperty(&object2);
558 QCOMPARE(expr.changed, true);
559 expr.changed = false;
560 QCOMPARE(expr.evaluate(), QVariant("Dog"));
562 object1.setObjectProperty(&object3);
563 QCOMPARE(expr.changed, true);
564 expr.changed = false;
565 QCOMPARE(expr.evaluate(), QVariant("Cat"));
567 object1.setObjectProperty(0);
568 QCOMPARE(expr.changed, true);
569 expr.changed = false;
570 QCOMPARE(expr.evaluate(), QVariant());
572 object1.setObjectProperty(&object3);
573 QCOMPARE(expr.changed, true);
574 expr.changed = false;
575 QCOMPARE(expr.evaluate(), QVariant("Cat"));
577 object3.setStringProperty("Donkey");
578 QCOMPARE(expr.changed, true);
579 expr.changed = false;
580 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
584 void tst_qdeclarativeecmascript::deferredProperties()
586 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
587 MyDeferredObject *object =
588 qobject_cast<MyDeferredObject *>(component.create());
589 QVERIFY(object != 0);
590 QCOMPARE(object->value(), 0);
591 QVERIFY(object->objectProperty() == 0);
592 QVERIFY(object->objectProperty2() != 0);
593 qmlExecuteDeferred(object);
594 QCOMPARE(object->value(), 10);
595 QVERIFY(object->objectProperty() != 0);
596 MyQmlObject *qmlObject =
597 qobject_cast<MyQmlObject *>(object->objectProperty());
598 QVERIFY(qmlObject != 0);
599 QCOMPARE(qmlObject->value(), 10);
600 object->setValue(19);
601 QCOMPARE(qmlObject->value(), 19);
606 // Check errors on deferred properties are correctly emitted
607 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
609 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
610 MyDeferredObject *object =
611 qobject_cast<MyDeferredObject *>(component.create());
612 QVERIFY(object != 0);
613 QCOMPARE(object->value(), 0);
614 QVERIFY(object->objectProperty() == 0);
615 QVERIFY(object->objectProperty2() == 0);
617 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject* objectProperty";
618 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
620 qmlExecuteDeferred(object);
625 void tst_qdeclarativeecmascript::extensionObjects()
627 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
628 MyExtendedObject *object =
629 qobject_cast<MyExtendedObject *>(component.create());
630 QVERIFY(object != 0);
631 QCOMPARE(object->baseProperty(), 13);
632 QCOMPARE(object->coreProperty(), 9);
633 object->setProperty("extendedProperty", QVariant(11));
634 object->setProperty("baseExtendedProperty", QVariant(92));
635 QCOMPARE(object->coreProperty(), 11);
636 QCOMPARE(object->baseProperty(), 92);
638 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
640 QCOMPARE(nested->baseProperty(), 13);
641 QCOMPARE(nested->coreProperty(), 9);
642 nested->setProperty("extendedProperty", QVariant(11));
643 nested->setProperty("baseExtendedProperty", QVariant(92));
644 QCOMPARE(nested->coreProperty(), 11);
645 QCOMPARE(nested->baseProperty(), 92);
650 void tst_qdeclarativeecmascript::overrideExtensionProperties()
652 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
653 OverrideDefaultPropertyObject *object =
654 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
655 QVERIFY(object != 0);
656 QVERIFY(object->secondProperty() != 0);
657 QVERIFY(object->firstProperty() == 0);
662 void tst_qdeclarativeecmascript::attachedProperties()
665 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
666 QObject *object = component.create();
667 QVERIFY(object != 0);
668 QCOMPARE(object->property("a").toInt(), 19);
669 QCOMPARE(object->property("b").toInt(), 19);
670 QCOMPARE(object->property("c").toInt(), 19);
671 QCOMPARE(object->property("d").toInt(), 19);
676 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
677 QObject *object = component.create();
678 QVERIFY(object != 0);
679 QCOMPARE(object->property("a").toInt(), 26);
680 QCOMPARE(object->property("b").toInt(), 26);
681 QCOMPARE(object->property("c").toInt(), 26);
682 QCOMPARE(object->property("d").toInt(), 26);
686 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
687 QObject *object = component.create();
688 QVERIFY(object != 0);
690 QMetaObject::invokeMethod(object, "writeValue2");
692 MyQmlAttachedObject *attached =
693 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
694 QVERIFY(attached != 0);
696 QCOMPARE(attached->value2(), 9);
701 void tst_qdeclarativeecmascript::enums()
705 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
706 QObject *object = component.create();
707 QVERIFY(object != 0);
709 QCOMPARE(object->property("a").toInt(), 0);
710 QCOMPARE(object->property("b").toInt(), 1);
711 QCOMPARE(object->property("c").toInt(), 2);
712 QCOMPARE(object->property("d").toInt(), 3);
713 QCOMPARE(object->property("e").toInt(), 0);
714 QCOMPARE(object->property("f").toInt(), 1);
715 QCOMPARE(object->property("g").toInt(), 2);
716 QCOMPARE(object->property("h").toInt(), 3);
717 QCOMPARE(object->property("i").toInt(), 19);
718 QCOMPARE(object->property("j").toInt(), 19);
722 // Non-existent enums
724 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
726 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int a";
727 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int b";
728 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
729 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
731 QObject *object = component.create();
732 QVERIFY(object != 0);
733 QCOMPARE(object->property("a").toInt(), 0);
734 QCOMPARE(object->property("b").toInt(), 0);
740 void tst_qdeclarativeecmascript::valueTypeFunctions()
742 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
743 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
745 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
746 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
752 Tests that writing a constant to a property with a binding on it disables the
755 void tst_qdeclarativeecmascript::constantsOverrideBindings()
759 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
760 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
761 QVERIFY(object != 0);
763 QCOMPARE(object->property("c2").toInt(), 0);
764 object->setProperty("c1", QVariant(9));
765 QCOMPARE(object->property("c2").toInt(), 9);
767 emit object->basicSignal();
769 QCOMPARE(object->property("c2").toInt(), 13);
770 object->setProperty("c1", QVariant(8));
771 QCOMPARE(object->property("c2").toInt(), 13);
776 // During construction
778 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
779 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
780 QVERIFY(object != 0);
782 QCOMPARE(object->property("c1").toInt(), 0);
783 QCOMPARE(object->property("c2").toInt(), 10);
784 object->setProperty("c1", QVariant(9));
785 QCOMPARE(object->property("c1").toInt(), 9);
786 QCOMPARE(object->property("c2").toInt(), 10);
794 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
795 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
796 QVERIFY(object != 0);
798 QCOMPARE(object->property("c2").toInt(), 0);
799 object->setProperty("c1", QVariant(9));
800 QCOMPARE(object->property("c2").toInt(), 9);
802 object->setProperty("c2", QVariant(13));
803 QCOMPARE(object->property("c2").toInt(), 13);
804 object->setProperty("c1", QVariant(7));
805 QCOMPARE(object->property("c1").toInt(), 7);
806 QCOMPARE(object->property("c2").toInt(), 13);
814 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
815 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
816 QVERIFY(object != 0);
818 QCOMPARE(object->property("c1").toInt(), 0);
819 QCOMPARE(object->property("c3").toInt(), 10);
820 object->setProperty("c1", QVariant(9));
821 QCOMPARE(object->property("c1").toInt(), 9);
822 QCOMPARE(object->property("c3").toInt(), 10);
829 Tests that assigning a binding to a property that already has a binding causes
830 the original binding to be disabled.
832 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
834 QDeclarativeComponent component(&engine,
835 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
836 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
837 QVERIFY(object != 0);
839 QCOMPARE(object->property("c1").toInt(), 0);
840 QCOMPARE(object->property("c2").toInt(), 0);
841 QCOMPARE(object->property("c3").toInt(), 0);
843 object->setProperty("c1", QVariant(9));
844 QCOMPARE(object->property("c1").toInt(), 9);
845 QCOMPARE(object->property("c2").toInt(), 0);
846 QCOMPARE(object->property("c3").toInt(), 0);
848 object->setProperty("c3", QVariant(8));
849 QCOMPARE(object->property("c1").toInt(), 9);
850 QCOMPARE(object->property("c2").toInt(), 8);
851 QCOMPARE(object->property("c3").toInt(), 8);
857 Access a non-existent attached object.
859 Tests for a regression where this used to crash.
861 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
863 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
865 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString stringProperty";
866 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
868 QObject *object = component.create();
869 QVERIFY(object != 0);
874 void tst_qdeclarativeecmascript::scope()
877 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
878 QObject *object = component.create();
879 QVERIFY(object != 0);
881 QCOMPARE(object->property("test1").toInt(), 1);
882 QCOMPARE(object->property("test2").toInt(), 2);
883 QCOMPARE(object->property("test3").toString(), QString("1Test"));
884 QCOMPARE(object->property("test4").toString(), QString("2Test"));
885 QCOMPARE(object->property("test5").toInt(), 1);
886 QCOMPARE(object->property("test6").toInt(), 1);
887 QCOMPARE(object->property("test7").toInt(), 2);
888 QCOMPARE(object->property("test8").toInt(), 2);
889 QCOMPARE(object->property("test9").toInt(), 1);
890 QCOMPARE(object->property("test10").toInt(), 3);
896 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
897 QObject *object = component.create();
898 QVERIFY(object != 0);
900 QCOMPARE(object->property("test1").toInt(), 19);
901 QCOMPARE(object->property("test2").toInt(), 19);
902 QCOMPARE(object->property("test3").toInt(), 14);
903 QCOMPARE(object->property("test4").toInt(), 14);
904 QCOMPARE(object->property("test5").toInt(), 24);
905 QCOMPARE(object->property("test6").toInt(), 24);
911 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
912 QObject *object = component.create();
913 QVERIFY(object != 0);
915 QCOMPARE(object->property("test1").toBool(), true);
916 QCOMPARE(object->property("test2").toBool(), true);
917 QCOMPARE(object->property("test3").toBool(), true);
922 // Signal argument scope
924 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
925 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
926 QVERIFY(object != 0);
928 QCOMPARE(object->property("test").toInt(), 0);
929 QCOMPARE(object->property("test2").toString(), QString());
931 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
933 QCOMPARE(object->property("test").toInt(), 13);
934 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
940 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
941 QObject *object = component.create();
942 QVERIFY(object != 0);
944 QCOMPARE(object->property("test1").toBool(), true);
945 QCOMPARE(object->property("test2").toBool(), true);
951 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
952 QObject *object = component.create();
953 QVERIFY(object != 0);
955 QCOMPARE(object->property("test").toBool(), true);
962 Tests that "any" type passes through a synthesized signal parameter. This
963 is essentially a test of QDeclarativeMetaType::copy()
965 void tst_qdeclarativeecmascript::signalParameterTypes()
967 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
968 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
969 QVERIFY(object != 0);
971 emit object->basicSignal();
973 QCOMPARE(object->property("intProperty").toInt(), 10);
974 QCOMPARE(object->property("realProperty").toReal(), 19.2);
975 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
976 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
977 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
978 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
984 Test that two JS objects for the same QObject compare as equal.
986 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
988 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
989 QObject *object = component.create();
990 QVERIFY(object != 0);
992 QCOMPARE(object->property("test1").toBool(), true);
993 QCOMPARE(object->property("test2").toBool(), true);
994 QCOMPARE(object->property("test3").toBool(), true);
995 QCOMPARE(object->property("test4").toBool(), true);
996 QCOMPARE(object->property("test5").toBool(), true);
1002 Confirm bindings and alias properties can coexist.
1004 Tests for a regression where the binding would not reevaluate.
1006 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1008 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1009 QObject *object = component.create();
1010 QVERIFY(object != 0);
1012 QCOMPARE(object->property("c2").toInt(), 3);
1013 QCOMPARE(object->property("c3").toInt(), 3);
1015 object->setProperty("c2", QVariant(19));
1017 QCOMPARE(object->property("c2").toInt(), 19);
1018 QCOMPARE(object->property("c3").toInt(), 19);
1023 void tst_qdeclarativeecmascript::dynamicCreation_data()
1025 QTest::addColumn<QString>("method");
1026 QTest::addColumn<QString>("createdName");
1028 QTest::newRow("One") << "createOne" << "objectOne";
1029 QTest::newRow("Two") << "createTwo" << "objectTwo";
1030 QTest::newRow("Three") << "createThree" << "objectThree";
1034 Test using createQmlObject to dynamically generate an item
1035 Also using createComponent is tested.
1037 void tst_qdeclarativeecmascript::dynamicCreation()
1039 QFETCH(QString, method);
1040 QFETCH(QString, createdName);
1042 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1043 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1044 QVERIFY(object != 0);
1046 QMetaObject::invokeMethod(object, method.toUtf8());
1047 QObject *created = object->objectProperty();
1049 QCOMPARE(created->objectName(), createdName);
1055 Tests the destroy function
1057 void tst_qdeclarativeecmascript::dynamicDestruction()
1059 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1060 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1061 QVERIFY(object != 0);
1062 QDeclarativeGuard<QObject> createdQmlObject = 0;
1064 QMetaObject::invokeMethod(object, "create");
1065 createdQmlObject = object->objectProperty();
1066 QVERIFY(createdQmlObject);
1067 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1069 QMetaObject::invokeMethod(object, "killOther");
1070 QVERIFY(createdQmlObject);
1071 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1072 QVERIFY(createdQmlObject);
1073 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1074 if (createdQmlObject) {
1076 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1079 QVERIFY(!createdQmlObject);
1081 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1082 QMetaObject::invokeMethod(object, "killMe");
1085 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1090 tests that id.toString() works
1092 void tst_qdeclarativeecmascript::objectToString()
1094 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1095 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1096 QVERIFY(object != 0);
1097 QMetaObject::invokeMethod(object, "testToString");
1098 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1099 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1105 Tests bindings that indirectly cause their own deletion work.
1107 This test is best run under valgrind to ensure no invalid memory access occur.
1109 void tst_qdeclarativeecmascript::selfDeletingBinding()
1112 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1113 QObject *object = component.create();
1114 QVERIFY(object != 0);
1115 object->setProperty("triggerDelete", true);
1120 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1121 QObject *object = component.create();
1122 QVERIFY(object != 0);
1123 object->setProperty("triggerDelete", true);
1129 Test that extended object properties can be accessed.
1131 This test a regression where this used to crash. The issue was specificially
1132 for extended objects that did not include a synthesized meta object (so non-root
1133 and no synthesiszed properties).
1135 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1137 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1138 QObject *object = component.create();
1139 QVERIFY(object != 0);
1144 Test file/lineNumbers for binding/Script errors.
1146 void tst_qdeclarativeecmascript::scriptErrors()
1148 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1149 QString url = component.url().toString();
1151 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1152 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1153 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1154 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1155 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1156 QString warning6 = url + ":7: Unable to assign [undefined] to int x";
1157 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1158 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1160 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1161 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1162 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1163 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1164 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1165 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1166 QVERIFY(object != 0);
1168 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1169 emit object->basicSignal();
1171 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1172 emit object->anotherBasicSignal();
1174 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1175 emit object->thirdBasicSignal();
1181 Test file/lineNumbers for inline functions.
1183 void tst_qdeclarativeecmascript::functionErrors()
1185 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1186 QString url = component.url().toString();
1188 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1190 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1192 QObject *object = component.create();
1193 QVERIFY(object != 0);
1196 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1197 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1198 url = componentTwo.url().toString();
1199 object = componentTwo.create();
1200 QVERIFY(object != 0);
1202 QString srpname = object->property("srp_name").toString();
1204 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1205 QLatin1String(" is not a function");
1206 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1207 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1212 Test various errors that can occur when assigning a property from script
1214 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1216 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1218 QString url = component.url().toString();
1220 QObject *object = component.create();
1221 QVERIFY(object != 0);
1223 QCOMPARE(object->property("test1").toBool(), true);
1224 QCOMPARE(object->property("test2").toBool(), true);
1230 Test bindings still work when the reeval is triggered from within
1233 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1235 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1236 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1237 QVERIFY(object != 0);
1239 QCOMPARE(object->property("base").toReal(), 50.);
1240 QCOMPARE(object->property("test1").toReal(), 50.);
1241 QCOMPARE(object->property("test2").toReal(), 50.);
1243 object->basicSignal();
1245 QCOMPARE(object->property("base").toReal(), 200.);
1246 QCOMPARE(object->property("test1").toReal(), 200.);
1247 QCOMPARE(object->property("test2").toReal(), 200.);
1249 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1251 QCOMPARE(object->property("base").toReal(), 400.);
1252 QCOMPARE(object->property("test1").toReal(), 400.);
1253 QCOMPARE(object->property("test2").toReal(), 400.);
1259 Test that list properties can be iterated from ECMAScript
1261 void tst_qdeclarativeecmascript::listProperties()
1263 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1264 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1265 QVERIFY(object != 0);
1267 QCOMPARE(object->property("test1").toInt(), 21);
1268 QCOMPARE(object->property("test2").toInt(), 2);
1269 QCOMPARE(object->property("test3").toBool(), true);
1270 QCOMPARE(object->property("test4").toBool(), true);
1275 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1277 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1278 QString url = component.url().toString();
1280 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1282 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1283 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1284 QVERIFY(object != 0);
1286 QCOMPARE(object->property("test").toBool(), false);
1288 MyQmlObject object2;
1289 MyQmlObject object3;
1290 object2.setObjectProperty(&object3);
1291 object->setObjectProperty(&object2);
1293 QCOMPARE(object->property("test").toBool(), true);
1298 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1300 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1301 QString url = component.url().toString();
1303 QString warning = component.url().toString() + ":6: Error: JS exception";
1305 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1306 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1307 QVERIFY(object != 0);
1311 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1313 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1314 QString url = component.url().toString();
1316 QString warning = component.url().toString() + ":5: Error: JS exception";
1318 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1319 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1320 QVERIFY(object != 0);
1324 static int transientErrorsMsgCount = 0;
1325 static void transientErrorsMsgHandler(QtMsgType, const char *)
1327 ++transientErrorsMsgCount;
1330 // Check that transient binding errors are not displayed
1331 void tst_qdeclarativeecmascript::transientErrors()
1334 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1336 transientErrorsMsgCount = 0;
1337 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1339 QObject *object = component.create();
1340 QVERIFY(object != 0);
1342 qInstallMsgHandler(old);
1344 QCOMPARE(transientErrorsMsgCount, 0);
1349 // One binding erroring multiple times, but then resolving
1351 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1353 transientErrorsMsgCount = 0;
1354 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1356 QObject *object = component.create();
1357 QVERIFY(object != 0);
1359 qInstallMsgHandler(old);
1361 QCOMPARE(transientErrorsMsgCount, 0);
1367 // Check that errors during shutdown are minimized
1368 void tst_qdeclarativeecmascript::shutdownErrors()
1370 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1371 QObject *object = component.create();
1372 QVERIFY(object != 0);
1374 transientErrorsMsgCount = 0;
1375 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1379 qInstallMsgHandler(old);
1380 QCOMPARE(transientErrorsMsgCount, 0);
1383 void tst_qdeclarativeecmascript::compositePropertyType()
1385 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1386 QTest::ignoreMessage(QtDebugMsg, "hello world");
1387 QObject *object = qobject_cast<QObject *>(component.create());
1392 void tst_qdeclarativeecmascript::jsObject()
1394 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1395 QObject *object = component.create();
1396 QVERIFY(object != 0);
1398 QCOMPARE(object->property("test").toInt(), 92);
1403 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1406 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1407 QObject *object = component.create();
1408 QVERIFY(object != 0);
1410 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1412 object->setProperty("setUndefined", true);
1414 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1416 object->setProperty("setUndefined", false);
1418 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1423 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1424 QObject *object = component.create();
1425 QVERIFY(object != 0);
1427 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1429 QMetaObject::invokeMethod(object, "doReset");
1431 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1438 void tst_qdeclarativeecmascript::bug1()
1440 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1441 QObject *object = component.create();
1442 QVERIFY(object != 0);
1444 QCOMPARE(object->property("test").toInt(), 14);
1446 object->setProperty("a", 11);
1448 QCOMPARE(object->property("test").toInt(), 3);
1450 object->setProperty("b", true);
1452 QCOMPARE(object->property("test").toInt(), 9);
1457 void tst_qdeclarativeecmascript::bug2()
1459 QDeclarativeComponent component(&engine);
1460 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1462 QObject *object = component.create();
1463 QVERIFY(object != 0);
1468 // Don't crash in createObject when the component has errors.
1469 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1471 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1472 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1473 QVERIFY(object != 0);
1475 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1476 QMetaObject::invokeMethod(object, "dontCrash");
1477 QObject *created = object->objectProperty();
1478 QVERIFY(created == 0);
1484 void tst_qdeclarativeecmascript::regExpBug()
1486 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1487 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1488 QVERIFY(object != 0);
1489 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1493 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1495 QString functionSource = QLatin1String("(function(object) { return ") +
1496 QLatin1String(source) + QLatin1String(" })");
1498 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1501 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1502 if (function.IsEmpty())
1504 v8::Handle<v8::Value> args[] = { o };
1505 function->Call(engine->global(), 1, args);
1506 return tc.HasCaught();
1509 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1510 const char *source, v8::Handle<v8::Value> result)
1512 QString functionSource = QLatin1String("(function(object) { return ") +
1513 QLatin1String(source) + QLatin1String(" })");
1515 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1518 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1519 if (function.IsEmpty())
1521 v8::Handle<v8::Value> args[] = { o };
1523 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1528 return value->StrictEquals(result);
1531 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1534 QString functionSource = QLatin1String("(function(object) { return ") +
1535 QLatin1String(source) + QLatin1String(" })");
1537 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1539 return v8::Handle<v8::Value>();
1540 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1541 if (function.IsEmpty())
1542 return v8::Handle<v8::Value>();
1543 v8::Handle<v8::Value> args[] = { o };
1545 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1548 return v8::Handle<v8::Value>();
1552 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1553 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1554 #define EVALUATE(source) evaluate(engine, object, source)
1556 void tst_qdeclarativeecmascript::callQtInvokables()
1558 MyInvokableObject o;
1560 QDeclarativeEngine qmlengine;
1561 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1563 QV8Engine *engine = &ep->v8engine;
1565 v8::HandleScope handle_scope;
1566 v8::Context::Scope scope(engine->context());
1568 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1570 // Non-existent methods
1572 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1573 QCOMPARE(o.error(), false);
1574 QCOMPARE(o.invoked(), -1);
1575 QCOMPARE(o.actuals().count(), 0);
1578 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1579 QCOMPARE(o.error(), false);
1580 QCOMPARE(o.invoked(), -1);
1581 QCOMPARE(o.actuals().count(), 0);
1583 // Insufficient arguments
1585 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1586 QCOMPARE(o.error(), false);
1587 QCOMPARE(o.invoked(), -1);
1588 QCOMPARE(o.actuals().count(), 0);
1591 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1592 QCOMPARE(o.error(), false);
1593 QCOMPARE(o.invoked(), -1);
1594 QCOMPARE(o.actuals().count(), 0);
1596 // Excessive arguments
1598 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1599 QCOMPARE(o.error(), false);
1600 QCOMPARE(o.invoked(), 8);
1601 QCOMPARE(o.actuals().count(), 1);
1602 QCOMPARE(o.actuals().at(0), QVariant(10));
1605 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1606 QCOMPARE(o.error(), false);
1607 QCOMPARE(o.invoked(), 9);
1608 QCOMPARE(o.actuals().count(), 2);
1609 QCOMPARE(o.actuals().at(0), QVariant(10));
1610 QCOMPARE(o.actuals().at(1), QVariant(11));
1612 // Test return types
1614 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1615 QCOMPARE(o.error(), false);
1616 QCOMPARE(o.invoked(), 0);
1617 QCOMPARE(o.actuals().count(), 0);
1620 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1621 QCOMPARE(o.error(), false);
1622 QCOMPARE(o.invoked(), 1);
1623 QCOMPARE(o.actuals().count(), 0);
1626 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1627 QCOMPARE(o.error(), false);
1628 QCOMPARE(o.invoked(), 2);
1629 QCOMPARE(o.actuals().count(), 0);
1633 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1634 QVERIFY(!ret.IsEmpty());
1635 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1636 QCOMPARE(o.error(), false);
1637 QCOMPARE(o.invoked(), 3);
1638 QCOMPARE(o.actuals().count(), 0);
1643 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1644 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1645 QCOMPARE(o.error(), false);
1646 QCOMPARE(o.invoked(), 4);
1647 QCOMPARE(o.actuals().count(), 0);
1651 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1652 QCOMPARE(o.error(), false);
1653 QCOMPARE(o.invoked(), 5);
1654 QCOMPARE(o.actuals().count(), 0);
1656 // XXX enable once qml/qtscript integration is implemented
1660 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1661 QVERIFY(ret->IsString());
1662 QCOMPARE(engine->toString(ret), QString("Hello world"));
1663 QCOMPARE(o.error(), false);
1664 QCOMPARE(o.invoked(), 6);
1665 QCOMPARE(o.actuals().count(), 0);
1670 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1671 QCOMPARE(o.error(), false);
1672 QCOMPARE(o.invoked(), 7);
1673 QCOMPARE(o.actuals().count(), 0);
1677 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1678 QCOMPARE(o.error(), false);
1679 QCOMPARE(o.invoked(), 8);
1680 QCOMPARE(o.actuals().count(), 1);
1681 QCOMPARE(o.actuals().at(0), QVariant(94));
1684 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1685 QCOMPARE(o.error(), false);
1686 QCOMPARE(o.invoked(), 8);
1687 QCOMPARE(o.actuals().count(), 1);
1688 QCOMPARE(o.actuals().at(0), QVariant(94));
1691 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1692 QCOMPARE(o.error(), false);
1693 QCOMPARE(o.invoked(), 8);
1694 QCOMPARE(o.actuals().count(), 1);
1695 QCOMPARE(o.actuals().at(0), QVariant(0));
1698 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1699 QCOMPARE(o.error(), false);
1700 QCOMPARE(o.invoked(), 8);
1701 QCOMPARE(o.actuals().count(), 1);
1702 QCOMPARE(o.actuals().at(0), QVariant(0));
1705 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1706 QCOMPARE(o.error(), false);
1707 QCOMPARE(o.invoked(), 8);
1708 QCOMPARE(o.actuals().count(), 1);
1709 QCOMPARE(o.actuals().at(0), QVariant(0));
1712 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1713 QCOMPARE(o.error(), false);
1714 QCOMPARE(o.invoked(), 8);
1715 QCOMPARE(o.actuals().count(), 1);
1716 QCOMPARE(o.actuals().at(0), QVariant(0));
1719 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1720 QCOMPARE(o.error(), false);
1721 QCOMPARE(o.invoked(), 9);
1722 QCOMPARE(o.actuals().count(), 2);
1723 QCOMPARE(o.actuals().at(0), QVariant(122));
1724 QCOMPARE(o.actuals().at(1), QVariant(9));
1727 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1728 QCOMPARE(o.error(), false);
1729 QCOMPARE(o.invoked(), 10);
1730 QCOMPARE(o.actuals().count(), 1);
1731 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1734 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1735 QCOMPARE(o.error(), false);
1736 QCOMPARE(o.invoked(), 10);
1737 QCOMPARE(o.actuals().count(), 1);
1738 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1741 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1742 QCOMPARE(o.error(), false);
1743 QCOMPARE(o.invoked(), 10);
1744 QCOMPARE(o.actuals().count(), 1);
1745 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1748 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1749 QCOMPARE(o.error(), false);
1750 QCOMPARE(o.invoked(), 10);
1751 QCOMPARE(o.actuals().count(), 1);
1752 QCOMPARE(o.actuals().at(0), QVariant(0));
1755 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1756 QCOMPARE(o.error(), false);
1757 QCOMPARE(o.invoked(), 10);
1758 QCOMPARE(o.actuals().count(), 1);
1759 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1762 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
1763 QCOMPARE(o.error(), false);
1764 QCOMPARE(o.invoked(), 10);
1765 QCOMPARE(o.actuals().count(), 1);
1766 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1769 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
1770 QCOMPARE(o.error(), false);
1771 QCOMPARE(o.invoked(), 11);
1772 QCOMPARE(o.actuals().count(), 1);
1773 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
1776 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
1777 QCOMPARE(o.error(), false);
1778 QCOMPARE(o.invoked(), 11);
1779 QCOMPARE(o.actuals().count(), 1);
1780 QCOMPARE(o.actuals().at(0), QVariant("19"));
1784 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
1785 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
1786 QCOMPARE(o.error(), false);
1787 QCOMPARE(o.invoked(), 11);
1788 QCOMPARE(o.actuals().count(), 1);
1789 QCOMPARE(o.actuals().at(0), QVariant(expected));
1793 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
1794 QCOMPARE(o.error(), false);
1795 QCOMPARE(o.invoked(), 11);
1796 QCOMPARE(o.actuals().count(), 1);
1797 QCOMPARE(o.actuals().at(0), QVariant(QString()));
1800 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
1801 QCOMPARE(o.error(), false);
1802 QCOMPARE(o.invoked(), 11);
1803 QCOMPARE(o.actuals().count(), 1);
1804 QCOMPARE(o.actuals().at(0), QVariant(QString()));
1807 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
1808 QCOMPARE(o.error(), false);
1809 QCOMPARE(o.invoked(), 12);
1810 QCOMPARE(o.actuals().count(), 1);
1811 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1814 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
1815 QCOMPARE(o.error(), false);
1816 QCOMPARE(o.invoked(), 12);
1817 QCOMPARE(o.actuals().count(), 1);
1818 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1821 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
1822 QCOMPARE(o.error(), false);
1823 QCOMPARE(o.invoked(), 12);
1824 QCOMPARE(o.actuals().count(), 1);
1825 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1828 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
1829 QCOMPARE(o.error(), false);
1830 QCOMPARE(o.invoked(), 12);
1831 QCOMPARE(o.actuals().count(), 1);
1832 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1835 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
1836 QCOMPARE(o.error(), false);
1837 QCOMPARE(o.invoked(), 12);
1838 QCOMPARE(o.actuals().count(), 1);
1839 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
1842 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
1843 QCOMPARE(o.error(), false);
1844 QCOMPARE(o.invoked(), 12);
1845 QCOMPARE(o.actuals().count(), 1);
1846 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
1849 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
1850 QCOMPARE(o.error(), false);
1851 QCOMPARE(o.invoked(), 13);
1852 QCOMPARE(o.actuals().count(), 1);
1853 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1856 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
1857 QCOMPARE(o.error(), false);
1858 QCOMPARE(o.invoked(), 13);
1859 QCOMPARE(o.actuals().count(), 1);
1860 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1863 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
1864 QCOMPARE(o.error(), false);
1865 QCOMPARE(o.invoked(), 13);
1866 QCOMPARE(o.actuals().count(), 1);
1867 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1870 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
1871 QCOMPARE(o.error(), false);
1872 QCOMPARE(o.invoked(), 13);
1873 QCOMPARE(o.actuals().count(), 1);
1874 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1877 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
1878 QCOMPARE(o.error(), false);
1879 QCOMPARE(o.invoked(), 13);
1880 QCOMPARE(o.actuals().count(), 1);
1881 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
1883 // XXX enable once qml/qtscript integration is implemented
1886 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
1887 QCOMPARE(o.error(), false);
1888 QCOMPARE(o.invoked(), 14);
1889 QCOMPARE(o.actuals().count(), 1);
1890 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isNull());
1893 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
1894 QCOMPARE(o.error(), false);
1895 QCOMPARE(o.invoked(), 14);
1896 QCOMPARE(o.actuals().count(), 1);
1897 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isUndefined());
1900 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
1901 QCOMPARE(o.error(), false);
1902 QCOMPARE(o.invoked(), 14);
1903 QCOMPARE(o.actuals().count(), 1);
1904 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).strictlyEquals(QScriptValue(engine, 19)));
1907 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
1908 QCOMPARE(o.error(), false);
1909 QCOMPARE(o.invoked(), 14);
1910 QCOMPARE(o.actuals().count(), 1);
1911 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isArray());
1914 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
1915 QCOMPARE(o.error(), false);
1916 QCOMPARE(o.invoked(), 15);
1917 QCOMPARE(o.actuals().count(), 2);
1918 QCOMPARE(o.actuals().at(0), QVariant(4));
1919 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isNull());
1922 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
1923 QCOMPARE(o.error(), false);
1924 QCOMPARE(o.invoked(), 15);
1925 QCOMPARE(o.actuals().count(), 2);
1926 QCOMPARE(o.actuals().at(0), QVariant(8));
1927 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isUndefined());
1930 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
1931 QCOMPARE(o.error(), false);
1932 QCOMPARE(o.invoked(), 15);
1933 QCOMPARE(o.actuals().count(), 2);
1934 QCOMPARE(o.actuals().at(0), QVariant(3));
1935 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).strictlyEquals(QScriptValue(engine, 19)));
1938 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
1939 QCOMPARE(o.error(), false);
1940 QCOMPARE(o.invoked(), 15);
1941 QCOMPARE(o.actuals().count(), 2);
1942 QCOMPARE(o.actuals().at(0), QVariant(44));
1943 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isArray());
1947 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
1948 QCOMPARE(o.error(), false);
1949 QCOMPARE(o.invoked(), -1);
1950 QCOMPARE(o.actuals().count(), 0);
1953 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
1954 QCOMPARE(o.error(), false);
1955 QCOMPARE(o.invoked(), 16);
1956 QCOMPARE(o.actuals().count(), 1);
1957 QCOMPARE(o.actuals().at(0), QVariant(10));
1960 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
1961 QCOMPARE(o.error(), false);
1962 QCOMPARE(o.invoked(), 17);
1963 QCOMPARE(o.actuals().count(), 2);
1964 QCOMPARE(o.actuals().at(0), QVariant(10));
1965 QCOMPARE(o.actuals().at(1), QVariant(11));
1968 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
1969 QCOMPARE(o.error(), false);
1970 QCOMPARE(o.invoked(), 18);
1971 QCOMPARE(o.actuals().count(), 1);
1972 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
1975 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
1976 QCOMPARE(o.error(), false);
1977 QCOMPARE(o.invoked(), 19);
1978 QCOMPARE(o.actuals().count(), 1);
1979 QCOMPARE(o.actuals().at(0), QVariant(9));
1982 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
1983 QCOMPARE(o.error(), false);
1984 QCOMPARE(o.invoked(), 20);
1985 QCOMPARE(o.actuals().count(), 2);
1986 QCOMPARE(o.actuals().at(0), QVariant(10));
1987 QCOMPARE(o.actuals().at(1), QVariant(19));
1990 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
1991 QCOMPARE(o.error(), false);
1992 QCOMPARE(o.invoked(), 20);
1993 QCOMPARE(o.actuals().count(), 2);
1994 QCOMPARE(o.actuals().at(0), QVariant(10));
1995 QCOMPARE(o.actuals().at(1), QVariant(13));
1998 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
1999 QCOMPARE(o.error(), false);
2000 QCOMPARE(o.invoked(), -3);
2001 QCOMPARE(o.actuals().count(), 1);
2002 QCOMPARE(o.actuals().at(0), QVariant(9));
2005 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2006 QCOMPARE(o.error(), false);
2007 QCOMPARE(o.invoked(), 21);
2008 QCOMPARE(o.actuals().count(), 2);
2009 QCOMPARE(o.actuals().at(0), QVariant(9));
2010 QCOMPARE(o.actuals().at(1), QVariant());
2013 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2014 QCOMPARE(o.error(), false);
2015 QCOMPARE(o.invoked(), 21);
2016 QCOMPARE(o.actuals().count(), 2);
2017 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2018 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2021 // QTBUG-13047 (check that you can pass registered object types as args)
2022 void tst_qdeclarativeecmascript::invokableObjectArg()
2024 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2026 QObject *o = component.create();
2028 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2030 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2035 // QTBUG-13047 (check that you can return registered object types from methods)
2036 void tst_qdeclarativeecmascript::invokableObjectRet()
2038 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2040 QObject *o = component.create();
2042 QCOMPARE(o->property("test").toBool(), true);
2047 void tst_qdeclarativeecmascript::listToVariant()
2049 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2051 MyQmlContainer container;
2053 QDeclarativeContext context(engine.rootContext());
2054 context.setContextObject(&container);
2056 QObject *object = component.create(&context);
2057 QVERIFY(object != 0);
2059 QVariant v = object->property("test");
2060 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2061 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2067 void tst_qdeclarativeecmascript::multiEngineObject()
2070 obj.setStringProperty("Howdy planet");
2072 QDeclarativeEngine e1;
2073 e1.rootContext()->setContextProperty("thing", &obj);
2074 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2076 QDeclarativeEngine e2;
2077 e2.rootContext()->setContextProperty("thing", &obj);
2078 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2080 QObject *o1 = c1.create();
2081 QObject *o2 = c2.create();
2083 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2084 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2090 // Test that references to QObjects are cleanup when the object is destroyed
2091 void tst_qdeclarativeecmascript::deletedObject()
2093 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2095 QObject *object = component.create();
2097 QCOMPARE(object->property("test1").toBool(), true);
2098 QCOMPARE(object->property("test2").toBool(), true);
2099 QCOMPARE(object->property("test3").toBool(), true);
2100 QCOMPARE(object->property("test4").toBool(), true);
2105 void tst_qdeclarativeecmascript::attachedPropertyScope()
2107 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2109 QObject *object = component.create();
2110 QVERIFY(object != 0);
2112 MyQmlAttachedObject *attached =
2113 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2114 QVERIFY(attached != 0);
2116 QCOMPARE(object->property("value2").toInt(), 0);
2118 attached->emitMySignal();
2120 QCOMPARE(object->property("value2").toInt(), 9);
2125 void tst_qdeclarativeecmascript::scriptConnect()
2128 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2130 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2131 QVERIFY(object != 0);
2133 QCOMPARE(object->property("test").toBool(), false);
2134 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2135 QCOMPARE(object->property("test").toBool(), true);
2141 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2143 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2144 QVERIFY(object != 0);
2146 QCOMPARE(object->property("test").toBool(), false);
2147 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2148 QCOMPARE(object->property("test").toBool(), true);
2154 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2156 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2157 QVERIFY(object != 0);
2159 QCOMPARE(object->property("test").toBool(), false);
2160 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2161 QCOMPARE(object->property("test").toBool(), true);
2167 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2169 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2170 QVERIFY(object != 0);
2172 QCOMPARE(object->methodCalled(), false);
2173 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2174 QCOMPARE(object->methodCalled(), true);
2180 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2182 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2183 QVERIFY(object != 0);
2185 QCOMPARE(object->methodCalled(), false);
2186 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2187 QCOMPARE(object->methodCalled(), true);
2193 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2195 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2196 QVERIFY(object != 0);
2198 QCOMPARE(object->property("test").toInt(), 0);
2199 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2200 QCOMPARE(object->property("test").toInt(), 2);
2206 void tst_qdeclarativeecmascript::scriptDisconnect()
2209 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2211 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2212 QVERIFY(object != 0);
2214 QCOMPARE(object->property("test").toInt(), 0);
2215 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2216 QCOMPARE(object->property("test").toInt(), 1);
2217 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2218 QCOMPARE(object->property("test").toInt(), 2);
2219 emit object->basicSignal();
2220 QCOMPARE(object->property("test").toInt(), 2);
2221 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2222 QCOMPARE(object->property("test").toInt(), 2);
2228 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2230 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2231 QVERIFY(object != 0);
2233 QCOMPARE(object->property("test").toInt(), 0);
2234 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2235 QCOMPARE(object->property("test").toInt(), 1);
2236 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2237 QCOMPARE(object->property("test").toInt(), 2);
2238 emit object->basicSignal();
2239 QCOMPARE(object->property("test").toInt(), 2);
2240 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2241 QCOMPARE(object->property("test").toInt(), 2);
2247 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2249 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2250 QVERIFY(object != 0);
2252 QCOMPARE(object->property("test").toInt(), 0);
2253 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2254 QCOMPARE(object->property("test").toInt(), 1);
2255 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2256 QCOMPARE(object->property("test").toInt(), 2);
2257 emit object->basicSignal();
2258 QCOMPARE(object->property("test").toInt(), 2);
2259 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2260 QCOMPARE(object->property("test").toInt(), 3);
2265 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2267 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2268 QVERIFY(object != 0);
2270 QCOMPARE(object->property("test").toInt(), 0);
2271 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2272 QCOMPARE(object->property("test").toInt(), 1);
2273 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2274 QCOMPARE(object->property("test").toInt(), 2);
2275 emit object->basicSignal();
2276 QCOMPARE(object->property("test").toInt(), 2);
2277 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2278 QCOMPARE(object->property("test").toInt(), 3);
2284 class OwnershipObject : public QObject
2288 OwnershipObject() { object = new QObject; }
2290 QPointer<QObject> object;
2293 QObject *getObject() { return object; }
2296 void tst_qdeclarativeecmascript::ownership()
2298 OwnershipObject own;
2299 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2300 context->setContextObject(&own);
2303 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2305 QVERIFY(own.object != 0);
2307 QObject *object = component.create(context);
2309 engine.collectGarbage();
2311 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2313 QVERIFY(own.object == 0);
2318 own.object = new QObject(&own);
2321 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2323 QVERIFY(own.object != 0);
2325 QObject *object = component.create(context);
2327 engine.collectGarbage();
2329 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2331 QVERIFY(own.object != 0);
2339 class CppOwnershipReturnValue : public QObject
2343 CppOwnershipReturnValue() : value(0) {}
2344 ~CppOwnershipReturnValue() { delete value; }
2346 Q_INVOKABLE QObject *create() {
2347 value = new QObject;
2348 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2352 Q_INVOKABLE MyQmlObject *createQmlObject() {
2353 MyQmlObject *rv = new MyQmlObject;
2358 QPointer<QObject> value;
2362 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2363 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2365 CppOwnershipReturnValue source;
2368 QDeclarativeEngine engine;
2369 engine.rootContext()->setContextProperty("source", &source);
2371 QVERIFY(source.value == 0);
2373 QDeclarativeComponent component(&engine);
2374 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2376 QObject *object = component.create();
2378 QVERIFY(object != 0);
2379 QVERIFY(source.value != 0);
2384 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2386 QVERIFY(source.value != 0);
2390 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2392 CppOwnershipReturnValue source;
2395 QDeclarativeEngine engine;
2396 engine.rootContext()->setContextProperty("source", &source);
2398 QVERIFY(source.value == 0);
2400 QDeclarativeComponent component(&engine);
2401 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2403 QObject *object = component.create();
2405 QVERIFY(object != 0);
2406 QVERIFY(source.value != 0);
2411 engine.collectGarbage();
2412 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2414 QVERIFY(source.value == 0);
2417 class QListQObjectMethodsObject : public QObject
2421 QListQObjectMethodsObject() {
2422 m_objects.append(new MyQmlObject());
2423 m_objects.append(new MyQmlObject());
2426 ~QListQObjectMethodsObject() {
2427 qDeleteAll(m_objects);
2431 QList<QObject *> getObjects() { return m_objects; }
2434 QList<QObject *> m_objects;
2437 // Tests that returning a QList<QObject*> from a method works
2438 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2440 QListQObjectMethodsObject obj;
2441 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2442 context->setContextObject(&obj);
2444 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2446 QObject *object = component.create(context);
2448 QCOMPARE(object->property("test").toInt(), 2);
2449 QCOMPARE(object->property("test2").toBool(), true);
2456 void tst_qdeclarativeecmascript::strictlyEquals()
2458 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2460 QObject *object = component.create();
2461 QVERIFY(object != 0);
2463 QCOMPARE(object->property("test1").toBool(), true);
2464 QCOMPARE(object->property("test2").toBool(), true);
2465 QCOMPARE(object->property("test3").toBool(), true);
2466 QCOMPARE(object->property("test4").toBool(), true);
2467 QCOMPARE(object->property("test5").toBool(), true);
2468 QCOMPARE(object->property("test6").toBool(), true);
2469 QCOMPARE(object->property("test7").toBool(), true);
2470 QCOMPARE(object->property("test8").toBool(), true);
2475 void tst_qdeclarativeecmascript::compiled()
2477 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2479 QObject *object = component.create();
2480 QVERIFY(object != 0);
2482 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2483 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2484 QCOMPARE(object->property("test3").toBool(), true);
2485 QCOMPARE(object->property("test4").toBool(), false);
2486 QCOMPARE(object->property("test5").toBool(), false);
2487 QCOMPARE(object->property("test6").toBool(), true);
2489 QCOMPARE(object->property("test7").toInt(), 185);
2490 QCOMPARE(object->property("test8").toInt(), 167);
2491 QCOMPARE(object->property("test9").toBool(), true);
2492 QCOMPARE(object->property("test10").toBool(), false);
2493 QCOMPARE(object->property("test11").toBool(), false);
2494 QCOMPARE(object->property("test12").toBool(), true);
2496 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2497 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2498 QCOMPARE(object->property("test15").toBool(), false);
2499 QCOMPARE(object->property("test16").toBool(), true);
2501 QCOMPARE(object->property("test17").toInt(), 5);
2502 QCOMPARE(object->property("test18").toReal(), qreal(176));
2503 QCOMPARE(object->property("test19").toInt(), 7);
2504 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2505 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2506 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2507 QCOMPARE(object->property("test23").toBool(), true);
2508 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2509 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2514 // Test that numbers assigned in bindings as strings work consistently
2515 void tst_qdeclarativeecmascript::numberAssignment()
2517 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2519 QObject *object = component.create();
2520 QVERIFY(object != 0);
2522 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2523 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2524 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2525 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2526 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2528 QCOMPARE(object->property("test5"), QVariant((int)7));
2529 QCOMPARE(object->property("test6"), QVariant((int)7));
2530 QCOMPARE(object->property("test7"), QVariant((int)6));
2531 QCOMPARE(object->property("test8"), QVariant((int)6));
2533 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2534 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2535 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2536 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2541 void tst_qdeclarativeecmascript::propertySplicing()
2543 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2545 QObject *object = component.create();
2546 QVERIFY(object != 0);
2548 QCOMPARE(object->property("test").toBool(), true);
2554 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2556 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2558 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2559 QVERIFY(object != 0);
2561 MyQmlObject::MyType type;
2562 type.value = 0x8971123;
2563 emit object->signalWithUnknownType(type);
2565 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2567 QCOMPARE(result.value, type.value);
2573 void tst_qdeclarativeecmascript::moduleApi()
2575 QDeclarativeComponent component(&engine, TEST_FILE("moduleApi.qml"));
2576 QObject *object = component.create();
2577 QVERIFY(object != 0);
2578 QCOMPARE(object->property("existingUriTest").toInt(), 20);
2579 QCOMPARE(object->property("scriptTest").toInt(), 13);
2580 QCOMPARE(object->property("qobjectTest").toInt(), 20);
2581 QCOMPARE(object->property("qobjectMethodTest").toInt(), 1); // first call of method, so count = 1.
2582 QCOMPARE(object->property("qobjectMinorVersionTest").toInt(), 20);
2583 QCOMPARE(object->property("qobjectMajorVersionTest").toInt(), 20);
2584 QCOMPARE(object->property("qobjectParentedTest").toInt(), 26);
2587 // test that caching of module apis works correctly.
2588 QDeclarativeComponent componentTwo(&engine, TEST_FILE("moduleApiCaching.qml"));
2589 object = componentTwo.create();
2590 QVERIFY(object != 0);
2591 QCOMPARE(object->property("existingUriTest").toInt(), 20);
2592 QCOMPARE(object->property("scriptTest").toInt(), 13); // shouldn't have incremented.
2593 QCOMPARE(object->property("qobjectParentedTest").toInt(), 26); // shouldn't have incremented.
2596 // test that writing to a property of module apis works correctly.
2597 QDeclarativeComponent componentThree(&engine, TEST_FILE("moduleApiWriting.qml"));
2598 QString expectedWarning = QLatin1String("file://") + TEST_FILE("moduleApiWriting.qml").toLocalFile() + QLatin1String(":15: Error: Cannot assign to read-only property \"qobjectTestProperty\"");
2599 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2600 object = componentThree.create();
2601 QVERIFY(object != 0);
2602 QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
2603 QCOMPARE(object->property("writableProperty").toInt(), 50);
2604 QVERIFY(object->setProperty("firstProperty", QVariant(30))); // shouldn't affect value of readOnlyProperty
2605 QVERIFY(object->setProperty("writableProperty", QVariant(30))); // SHOULD affect value of writableProperty
2606 QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
2607 QCOMPARE(object->property("writableProperty").toInt(), 30);
2610 QDeclarativeComponent failOne(&engine, TEST_FILE("moduleApiMajorVersionFail.qml"));
2611 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2612 object = failOne.create();
2613 QVERIFY(object == 0); // should have failed: invalid major version
2615 QDeclarativeComponent failTwo(&engine, TEST_FILE("moduleApiMinorVersionFail.qml"));
2616 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2617 object = failTwo.create();
2618 QVERIFY(object == 0); // should have failed: invalid minor version
2621 void tst_qdeclarativeecmascript::importScripts()
2623 QObject *object = 0;
2625 // first, ensure that the required behaviour works.
2626 QDeclarativeComponent component(&engine, TEST_FILE("jsimport/testImport.qml"));
2627 object = component.create();
2628 QVERIFY(object != 0);
2629 QCOMPARE(object->property("importedScriptStringValue"), QVariant(QString(QLatin1String("Hello, World!"))));
2630 QCOMPARE(object->property("importedScriptFunctionValue"), QVariant(20));
2631 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(19));
2632 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(2));
2635 QDeclarativeComponent componentTwo(&engine, TEST_FILE("jsimport/testImportScoping.qml"));
2636 object = componentTwo.create();
2637 QVERIFY(object != 0);
2638 QCOMPARE(object->property("componentError"), QVariant(5));
2641 // then, ensure that unintended behaviour does not work.
2642 QDeclarativeComponent failOneComponent(&engine, TEST_FILE("jsimportfail/failOne.qml"));
2643 QString expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Result of expression 'TestScriptImport.ImportOneJs' [undefined] is not an object.");
2644 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2645 object = failOneComponent.create();
2646 QVERIFY(object != 0);
2647 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2649 QDeclarativeComponent failTwoComponent(&engine, TEST_FILE("jsimportfail/failTwo.qml"));
2650 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs");
2651 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2652 object = failTwoComponent.create();
2653 QVERIFY(object != 0);
2654 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2656 QDeclarativeComponent failThreeComponent(&engine, TEST_FILE("jsimportfail/failThree.qml"));
2657 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Result of expression 'testQtObject.TestModuleImport.JsQtTest' [undefined] is not an object.");
2658 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2659 object = failThreeComponent.create();
2660 QVERIFY(object != 0);
2661 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(false));
2663 QDeclarativeComponent failFourComponent(&engine, TEST_FILE("jsimportfail/failFour.qml"));
2664 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest");
2665 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2666 object = failFourComponent.create();
2667 QVERIFY(object != 0);
2668 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(0));
2670 QDeclarativeComponent failFiveComponent(&engine, TEST_FILE("jsimportfail/failFive.qml"));
2671 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component");
2672 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2673 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component");
2674 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2675 object = failFiveComponent.create();
2676 QVERIFY(object != 0);
2677 QCOMPARE(object->property("componentError"), QVariant(0));
2680 // also, test that importing scripts with .pragma library works as required
2681 QDeclarativeComponent pragmaLibraryComponent(&engine, TEST_FILE("jsimport/testImportPragmaLibrary.qml"));
2682 object = pragmaLibraryComponent.create();
2683 QVERIFY(object != 0);
2684 QCOMPARE(object->property("testValue"), QVariant(31));
2687 // and that .pragma library scripts don't inherit imports from any .qml file
2688 QDeclarativeComponent pragmaLibraryComponentTwo(&engine, TEST_FILE("jsimportfail/testImportPragmaLibrary.qml"));
2689 object = pragmaLibraryComponentTwo.create();
2690 QVERIFY(object != 0);
2691 QCOMPARE(object->property("testValue"), QVariant(0));
2695 void tst_qdeclarativeecmascript::scarceResources()
2697 QPixmap origPixmap(100, 100);
2698 origPixmap.fill(Qt::blue);
2700 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
2701 ScarceResourceObject *eo = 0;
2702 QObject *object = 0;
2704 // in the following three cases, the instance created from the component
2705 // has a property which is a copy of the scarce resource; hence, the
2706 // resource should NOT be detached prior to deletion of the object instance,
2707 // unless the resource is destroyed explicitly.
2708 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
2709 object = component.create();
2710 QVERIFY(object != 0);
2711 QVERIFY(object->property("scarceResourceCopy").isValid());
2712 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2713 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2714 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2715 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
2718 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
2719 object = componentTwo.create();
2720 QVERIFY(object != 0);
2721 QVERIFY(object->property("scarceResourceCopy").isValid());
2722 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2723 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2724 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2725 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
2728 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
2729 object = componentThree.create();
2730 QVERIFY(object != 0);
2731 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
2732 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2733 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2734 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
2737 // in the following three cases, no other copy should exist in memory,
2738 // and so it should be detached (unless explicitly preserved).
2739 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
2740 object = componentFour.create();
2741 QVERIFY(object != 0);
2742 QVERIFY(object->property("scarceResourceTest").isValid());
2743 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2744 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2745 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2746 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
2749 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
2750 object = componentFive.create();
2751 QVERIFY(object != 0);
2752 QVERIFY(object->property("scarceResourceTest").isValid());
2753 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2754 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2755 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2756 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
2759 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
2760 object = componentSix.create();
2761 QVERIFY(object != 0);
2762 QVERIFY(object->property("scarceResourceTest").isValid());
2763 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2764 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2765 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2766 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
2769 // test that scarce resources are handled correctly for imports
2770 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
2771 object = componentSeven.create();
2772 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
2773 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
2776 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
2777 object = componentEight.create();
2778 QVERIFY(object != 0);
2779 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
2780 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2783 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
2784 object = componentNine.create();
2785 QVERIFY(object != 0);
2786 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
2787 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2788 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
2789 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
2790 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
2791 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
2794 // test that scarce resources are handled properly in signal invocation
2795 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
2796 object = componentTen.create();
2797 QVERIFY(object != 0);
2798 QObject *srsc = object->findChild<QObject*>("srsc");
2800 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
2801 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
2802 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2803 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2804 QMetaObject::invokeMethod(srsc, "testSignal");
2805 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
2806 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
2807 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2808 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
2809 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
2810 QVERIFY(srsc->property("scarceResourceCopy").isValid());
2811 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2812 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2813 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
2814 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2817 // test that scarce resources are handled properly from js functions in qml files
2818 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
2819 object = componentEleven.create();
2820 QVERIFY(object != 0);
2821 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
2822 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2823 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2824 QMetaObject::invokeMethod(object, "retrieveScarceResource");
2825 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
2826 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2827 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2828 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
2829 QMetaObject::invokeMethod(object, "releaseScarceResource");
2830 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
2831 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2832 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2833 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2836 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
2837 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
2838 object = componentTwelve.create();
2839 QVERIFY(object != 0);
2840 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
2841 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2842 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2843 QString srp_name = object->property("srp_name").toString();
2844 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
2845 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
2846 QMetaObject::invokeMethod(object, "retrieveScarceResource");
2847 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
2848 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2849 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2850 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2854 void tst_qdeclarativeecmascript::propertyChangeSlots()
2856 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
2857 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
2858 QObject *object = component.create();
2859 QVERIFY(object != 0);
2862 // ensure that invalid property names fail properly.
2863 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2864 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
2865 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
2866 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
2867 object = e1.create();
2868 QVERIFY(object == 0);
2871 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2872 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
2873 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
2874 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
2875 object = e2.create();
2876 QVERIFY(object == 0);
2879 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2880 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
2881 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
2882 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
2883 object = e3.create();
2884 QVERIFY(object == 0);
2887 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2888 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
2889 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
2890 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
2891 object = e4.create();
2892 QVERIFY(object == 0);
2896 // Test that assigning a null object works
2897 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
2898 void tst_qdeclarativeecmascript::nullObjectBinding()
2900 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
2902 QObject *object = component.create();
2903 QVERIFY(object != 0);
2905 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
2910 // Test that bindings don't evaluate once the engine has been destroyed
2911 void tst_qdeclarativeecmascript::deletedEngine()
2913 QDeclarativeEngine *engine = new QDeclarativeEngine;
2914 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
2916 QObject *object = component.create();
2917 QVERIFY(object != 0);
2919 QCOMPARE(object->property("a").toInt(), 39);
2920 object->setProperty("b", QVariant(9));
2921 QCOMPARE(object->property("a").toInt(), 117);
2925 QCOMPARE(object->property("a").toInt(), 117);
2926 object->setProperty("b", QVariant(10));
2927 QCOMPARE(object->property("a").toInt(), 117);
2932 // Test the crashing part of QTBUG-9705
2933 void tst_qdeclarativeecmascript::libraryScriptAssert()
2935 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
2937 QObject *object = component.create();
2938 QVERIFY(object != 0);
2943 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
2945 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
2947 QObject *object = component.create();
2948 QVERIFY(object != 0);
2950 QCOMPARE(object->property("test1").toInt(), 10);
2951 QCOMPARE(object->property("test2").toInt(), 11);
2953 object->setProperty("runTest", true);
2955 QCOMPARE(object->property("test1"), QVariant());
2956 QCOMPARE(object->property("test2"), QVariant());
2962 void tst_qdeclarativeecmascript::qtbug_9792()
2964 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
2966 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2968 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
2969 QVERIFY(object != 0);
2971 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
2972 object->basicSignal();
2976 transientErrorsMsgCount = 0;
2977 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
2979 object->basicSignal();
2981 qInstallMsgHandler(old);
2983 QCOMPARE(transientErrorsMsgCount, 0);
2988 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
2989 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
2991 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
2993 QObject *o = component.create();
2996 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
2997 QVERIFY(nested != 0);
2999 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
3002 nested = qvariant_cast<QObject *>(o->property("object"));
3003 QVERIFY(nested == 0);
3005 // If the bug is present, the next line will crash
3009 // Test that we shut down without stupid warnings
3010 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
3013 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
3015 QObject *o = component.create();
3017 transientErrorsMsgCount = 0;
3018 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3022 qInstallMsgHandler(old);
3024 QCOMPARE(transientErrorsMsgCount, 0);
3029 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
3031 QObject *o = component.create();
3033 transientErrorsMsgCount = 0;
3034 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3038 qInstallMsgHandler(old);
3040 QCOMPARE(transientErrorsMsgCount, 0);
3044 void tst_qdeclarativeecmascript::canAssignNullToQObject()
3047 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
3049 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3052 QVERIFY(o->objectProperty() != 0);
3054 o->setProperty("runTest", true);
3056 QVERIFY(o->objectProperty() == 0);
3062 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
3064 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3067 QVERIFY(o->objectProperty() == 0);
3073 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
3075 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
3077 QString url = component.url().toString();
3078 QString warning = url + ":4: Unable to assign a function to a property.";
3079 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3081 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3084 QVERIFY(!o->property("a").isValid());
3089 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
3091 QFETCH(QString, triggerProperty);
3093 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3094 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3096 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3098 QVERIFY(!o->property("a").isValid());
3100 o->setProperty("aNumber", QVariant(5));
3101 o->setProperty(triggerProperty.toUtf8().constData(), true);
3102 QCOMPARE(o->property("a"), QVariant(50));
3104 o->setProperty("aNumber", QVariant(10));
3105 QCOMPARE(o->property("a"), QVariant(100));
3110 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
3112 QTest::addColumn<QString>("triggerProperty");
3114 QTest::newRow("assign to property") << "assignToProperty";
3115 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
3117 QTest::newRow("assign to value type") << "assignToValueType";
3119 QTest::newRow("use 'this'") << "assignWithThis";
3120 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
3123 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
3125 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3126 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3128 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3130 QVERIFY(!o->property("a").isValid());
3132 o->setProperty("assignFuncWithoutReturn", true);
3133 QVERIFY(!o->property("a").isValid());
3135 QString url = component.url().toString();
3136 QString warning = url + ":67: Unable to assign QString to int";
3137 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3138 o->setProperty("assignWrongType", true);
3140 warning = url + ":71: Unable to assign QString to int";
3141 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3142 o->setProperty("assignWrongTypeToValueType", true);
3147 void tst_qdeclarativeecmascript::eval()
3149 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
3151 QObject *o = component.create();
3154 QCOMPARE(o->property("test1").toBool(), true);
3155 QCOMPARE(o->property("test2").toBool(), true);
3156 QCOMPARE(o->property("test3").toBool(), true);
3157 QCOMPARE(o->property("test4").toBool(), true);
3158 QCOMPARE(o->property("test5").toBool(), true);
3163 void tst_qdeclarativeecmascript::function()
3165 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
3167 QObject *o = component.create();
3170 QCOMPARE(o->property("test1").toBool(), true);
3171 QCOMPARE(o->property("test2").toBool(), true);
3172 QCOMPARE(o->property("test3").toBool(), true);
3177 // Test the "Qt.include" method
3178 void tst_qdeclarativeecmascript::include()
3180 // Non-library relative include
3182 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
3183 QObject *o = component.create();
3186 QCOMPARE(o->property("test0").toInt(), 99);
3187 QCOMPARE(o->property("test1").toBool(), true);
3188 QCOMPARE(o->property("test2").toBool(), true);
3189 QCOMPARE(o->property("test2_1").toBool(), true);
3190 QCOMPARE(o->property("test3").toBool(), true);
3191 QCOMPARE(o->property("test3_1").toBool(), true);
3196 // Library relative include
3198 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
3199 QObject *o = component.create();
3202 QCOMPARE(o->property("test0").toInt(), 99);
3203 QCOMPARE(o->property("test1").toBool(), true);
3204 QCOMPARE(o->property("test2").toBool(), true);
3205 QCOMPARE(o->property("test2_1").toBool(), true);
3206 QCOMPARE(o->property("test3").toBool(), true);
3207 QCOMPARE(o->property("test3_1").toBool(), true);
3214 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
3215 QObject *o = component.create();
3218 QCOMPARE(o->property("test1").toBool(), true);
3219 QCOMPARE(o->property("test2").toBool(), true);
3220 QCOMPARE(o->property("test3").toBool(), true);
3221 QCOMPARE(o->property("test4").toBool(), true);
3222 QCOMPARE(o->property("test5").toBool(), true);
3223 QCOMPARE(o->property("test6").toBool(), true);
3228 // Including file with ".pragma library"
3230 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
3231 QObject *o = component.create();
3233 QCOMPARE(o->property("test1").toInt(), 100);
3240 TestHTTPServer server(8111);
3241 QVERIFY(server.isValid());
3242 server.serveDirectory(SRCDIR "/data");
3244 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
3245 QObject *o = component.create();
3248 QTRY_VERIFY(o->property("done").toBool() == true);
3249 QTRY_VERIFY(o->property("done2").toBool() == true);
3251 QCOMPARE(o->property("test1").toBool(), true);
3252 QCOMPARE(o->property("test2").toBool(), true);
3253 QCOMPARE(o->property("test3").toBool(), true);
3254 QCOMPARE(o->property("test4").toBool(), true);
3255 QCOMPARE(o->property("test5").toBool(), true);
3257 QCOMPARE(o->property("test6").toBool(), true);
3258 QCOMPARE(o->property("test7").toBool(), true);
3259 QCOMPARE(o->property("test8").toBool(), true);
3260 QCOMPARE(o->property("test9").toBool(), true);
3261 QCOMPARE(o->property("test10").toBool(), true);
3268 TestHTTPServer server(8111);
3269 QVERIFY(server.isValid());
3270 server.serveDirectory(SRCDIR "/data");
3272 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
3273 QObject *o = component.create();
3276 QTRY_VERIFY(o->property("done").toBool() == true);
3278 QCOMPARE(o->property("test1").toBool(), true);
3279 QCOMPARE(o->property("test2").toBool(), true);
3280 QCOMPARE(o->property("test3").toBool(), true);
3286 void tst_qdeclarativeecmascript::qtbug_10696()
3288 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
3289 QObject *o = component.create();
3294 void tst_qdeclarativeecmascript::qtbug_11606()
3296 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
3297 QObject *o = component.create();
3299 QCOMPARE(o->property("test").toBool(), true);
3303 void tst_qdeclarativeecmascript::qtbug_11600()
3305 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
3306 QObject *o = component.create();
3308 QCOMPARE(o->property("test").toBool(), true);
3312 // Reading and writing non-scriptable properties should fail
3313 void tst_qdeclarativeecmascript::nonscriptable()
3315 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
3316 QObject *o = component.create();
3318 QCOMPARE(o->property("readOk").toBool(), true);
3319 QCOMPARE(o->property("writeOk").toBool(), true);
3323 // deleteLater() should not be callable from QML
3324 void tst_qdeclarativeecmascript::deleteLater()
3326 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
3327 QObject *o = component.create();
3329 QCOMPARE(o->property("test").toBool(), true);
3333 void tst_qdeclarativeecmascript::in()
3335 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
3336 QObject *o = component.create();
3338 QCOMPARE(o->property("test1").toBool(), true);
3339 QCOMPARE(o->property("test2").toBool(), true);
3343 void tst_qdeclarativeecmascript::sharedAttachedObject()
3345 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
3346 QObject *o = component.create();
3348 QCOMPARE(o->property("test1").toBool(), true);
3349 QCOMPARE(o->property("test2").toBool(), true);
3354 void tst_qdeclarativeecmascript::objectName()
3356 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
3357 QObject *o = component.create();
3360 QCOMPARE(o->property("test1").toString(), QString("hello"));
3361 QCOMPARE(o->property("test2").toString(), QString("ell"));
3363 o->setObjectName("world");
3365 QCOMPARE(o->property("test1").toString(), QString("world"));
3366 QCOMPARE(o->property("test2").toString(), QString("orl"));
3371 void tst_qdeclarativeecmascript::writeRemovesBinding()
3373 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
3374 QObject *o = component.create();
3377 QCOMPARE(o->property("test").toBool(), true);
3382 // Test bindings assigned to alias properties actually assign to the alias' target
3383 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
3385 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
3386 QObject *o = component.create();
3389 QCOMPARE(o->property("test").toBool(), true);
3394 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
3395 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
3398 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
3399 QObject *o = component.create();
3402 QCOMPARE(o->property("test").toBool(), true);
3408 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
3409 QObject *o = component.create();
3412 QCOMPARE(o->property("test").toBool(), true);
3418 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
3419 QObject *o = component.create();
3422 QCOMPARE(o->property("test").toBool(), true);
3428 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
3429 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
3432 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
3433 QObject *o = component.create();
3436 QCOMPARE(o->property("test").toBool(), true);
3442 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
3443 QObject *o = component.create();
3446 QCOMPARE(o->property("test").toBool(), true);
3452 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
3453 QObject *o = component.create();
3456 QCOMPARE(o->property("test").toBool(), true);
3462 void tst_qdeclarativeecmascript::revisionErrors()
3465 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
3466 QString url = component.url().toString();
3468 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
3469 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
3470 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
3472 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3473 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3474 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3475 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3476 QVERIFY(object != 0);
3480 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
3481 QString url = component.url().toString();
3483 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
3484 // method2, prop2 from MyRevisionedClass not available
3485 // method4, prop4 from MyRevisionedSubclass not available
3486 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
3487 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
3488 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
3489 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
3490 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
3492 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3493 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3494 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3495 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
3496 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
3497 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3498 QVERIFY(object != 0);
3502 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
3503 QString url = component.url().toString();
3505 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
3506 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
3507 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
3508 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
3509 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
3510 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3511 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3512 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3513 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3514 QVERIFY(object != 0);
3519 void tst_qdeclarativeecmascript::revision()
3522 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
3523 QString url = component.url().toString();
3525 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3526 QVERIFY(object != 0);
3530 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
3531 QString url = component.url().toString();
3533 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3534 QVERIFY(object != 0);
3538 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
3539 QString url = component.url().toString();
3541 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3542 QVERIFY(object != 0);
3545 // Test that non-root classes can resolve revisioned methods
3547 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
3549 QObject *object = component.create();
3550 QVERIFY(object != 0);
3551 QCOMPARE(object->property("test").toReal(), 11.);
3556 // Test for QScriptDeclarativeClass::pushCleanContext()
3557 void tst_qdeclarativeecmascript::pushCleanContext()
3559 QScriptEngine engine;
3560 engine.globalObject().setProperty("a", 6);
3561 QCOMPARE(engine.evaluate("a").toInt32(), 6);
3563 // First confirm pushContext() behaves as we expect
3564 QScriptValue object = engine.newObject();
3565 object.setProperty("a", 15);
3566 QScriptContext *context1 = engine.pushContext();
3567 context1->pushScope(object);
3568 QCOMPARE(engine.evaluate("a").toInt32(), 15);
3570 QScriptContext *context2 = engine.pushContext();
3572 QCOMPARE(engine.evaluate("a").toInt32(), 15);
3573 QScriptValue func1 = engine.evaluate("(function() { return a; })");
3575 // Now check that pushCleanContext() works
3576 QScriptDeclarativeClass::pushCleanContext(&engine);
3577 QCOMPARE(engine.evaluate("a").toInt32(), 6);
3578 QScriptValue func2 = engine.evaluate("(function() { return a; })");
3580 engine.popContext();
3581 QCOMPARE(engine.evaluate("a").toInt32(), 15);
3583 engine.popContext();
3584 QCOMPARE(engine.evaluate("a").toInt32(), 15);
3586 engine.popContext();
3587 QCOMPARE(engine.evaluate("a").toInt32(), 6);
3589 // Check that function objects created in these contexts work
3590 QCOMPARE(func1.call().toInt32(), 15);
3591 QCOMPARE(func2.call().toInt32(), 6);
3594 void tst_qdeclarativeecmascript::realToInt()
3596 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
3597 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
3598 QVERIFY(object != 0);
3600 QMetaObject::invokeMethod(object, "test1");
3601 QCOMPARE(object->value(), int(4));
3602 QMetaObject::invokeMethod(object, "test2");
3603 QCOMPARE(object->value(), int(8));
3606 QTEST_MAIN(tst_qdeclarativeecmascript)
3608 #include "tst_qdeclarativeecmascript.moc"