1 /****************************************************************************
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
7 ** This file is part of the test suite of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <QtDeclarative/qdeclarativecomponent.h>
43 #include <QtDeclarative/qdeclarativeengine.h>
44 #include <QtDeclarative/qdeclarativeexpression.h>
45 #include <QtDeclarative/qdeclarativecontext.h>
46 #include <QtCore/qfileinfo.h>
47 #include <QtCore/qdebug.h>
48 #include <QtDeclarative/private/qdeclarativeguard_p.h>
49 #include <QtCore/qdir.h>
50 #include <QtCore/qnumeric.h>
51 #include <private/qdeclarativeengine_p.h>
52 #include <private/qscriptdeclarativeclass_p.h>
53 #include "testtypes.h"
54 #include "testhttpserver.h"
55 #include "../../../shared/util.h"
58 // In Symbian OS test data is located in applications private dir
63 This test covers evaluation of ECMAScript expressions and bindings from within
64 QML. This does not include static QML language issues.
66 Static QML language issues are covered in qmllanguage
68 inline QUrl TEST_FILE(const QString &filename)
70 QFileInfo fileInfo(__FILE__);
71 return QUrl::fromLocalFile(fileInfo.absoluteDir().filePath("data/" + filename));
74 inline QUrl TEST_FILE(const char *filename)
76 return TEST_FILE(QLatin1String(filename));
79 class tst_qdeclarativeecmascript : public QObject
83 tst_qdeclarativeecmascript() {}
87 void assignBasicTypes();
88 void idShortcutInvalidates();
89 void boolPropertiesEvaluateAsBool();
91 void signalAssignment();
93 void basicExpressions();
94 void basicExpressions_data();
95 void arrayExpressions();
96 void contextPropertiesTriggerReeval();
97 void objectPropertiesTriggerReeval();
98 void deferredProperties();
99 void deferredPropertiesErrors();
100 void extensionObjects();
101 void overrideExtensionProperties();
102 void attachedProperties();
104 void valueTypeFunctions();
105 void constantsOverrideBindings();
106 void outerBindingOverridesInnerBinding();
107 void aliasPropertyAndBinding();
108 void nonExistentAttachedObject();
111 void signalParameterTypes();
112 void objectsCompareAsEqual();
113 void dynamicCreation_data();
114 void dynamicCreation();
115 void dynamicDestruction();
116 void objectToString();
117 void selfDeletingBinding();
118 void extendedObjectPropertyLookup();
120 void functionErrors();
121 void propertyAssignmentErrors();
122 void signalTriggeredBindings();
123 void listProperties();
124 void exceptionClearsOnReeval();
125 void exceptionSlotProducesWarning();
126 void exceptionBindingProducesWarning();
127 void transientErrors();
128 void shutdownErrors();
129 void compositePropertyType();
131 void undefinedResetsProperty();
132 void listToVariant();
133 void multiEngineObject();
134 void deletedObject();
135 void attachedPropertyScope();
136 void scriptConnect();
137 void scriptDisconnect();
139 void cppOwnershipReturnValue();
140 void ownershipCustomReturnValue();
141 void qlistqobjectMethods();
142 void strictlyEquals();
144 void numberAssignment();
145 void propertySplicing();
146 void signalWithUnknownTypes();
148 void importScripts();
149 void scarceResources();
150 void propertyChangeSlots();
151 void elementAssign();
152 void objectPassThroughSignals();
153 void booleanConversion();
157 void dynamicCreationCrash();
159 void nullObjectBinding();
160 void deletedEngine();
161 void libraryScriptAssert();
162 void variantsAssignedUndefined();
164 void qtcreatorbug_1289();
165 void noSpuriousWarningsAtShutdown();
166 void canAssignNullToQObject();
167 void functionAssignment_fromBinding();
168 void functionAssignment_fromJS();
169 void functionAssignment_fromJS_data();
170 void functionAssignmentfromJS_invalid();
176 void nonscriptable();
179 void sharedAttachedObject();
181 void writeRemovesBinding();
182 void aliasBindingsAssignCorrectly();
183 void aliasBindingsOverrideTarget();
184 void aliasWritesOverrideBindings();
185 void aliasToCompositeElement();
190 void callQtInvokables();
191 void invokableObjectArg();
192 void invokableObjectRet();
194 void revisionErrors();
198 QDeclarativeEngine engine;
201 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
203 void tst_qdeclarativeecmascript::assignBasicTypes()
206 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
207 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
208 QVERIFY(object != 0);
209 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
210 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
211 QCOMPARE(object->stringProperty(), QString("Hello World!"));
212 QCOMPARE(object->uintProperty(), uint(10));
213 QCOMPARE(object->intProperty(), -19);
214 QCOMPARE((float)object->realProperty(), float(23.2));
215 QCOMPARE((float)object->doubleProperty(), float(-19.75));
216 QCOMPARE((float)object->floatProperty(), float(8.5));
217 QCOMPARE(object->colorProperty(), QColor("red"));
218 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
219 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
220 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
221 QCOMPARE(object->pointProperty(), QPoint(99,13));
222 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
223 QCOMPARE(object->sizeProperty(), QSize(99, 13));
224 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
225 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
226 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
227 QCOMPARE(object->boolProperty(), true);
228 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
229 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
230 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
234 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
235 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
236 QVERIFY(object != 0);
237 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
238 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
239 QCOMPARE(object->stringProperty(), QString("Hello World!"));
240 QCOMPARE(object->uintProperty(), uint(10));
241 QCOMPARE(object->intProperty(), -19);
242 QCOMPARE((float)object->realProperty(), float(23.2));
243 QCOMPARE((float)object->doubleProperty(), float(-19.75));
244 QCOMPARE((float)object->floatProperty(), float(8.5));
245 QCOMPARE(object->colorProperty(), QColor("red"));
246 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
247 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
248 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
249 QCOMPARE(object->pointProperty(), QPoint(99,13));
250 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
251 QCOMPARE(object->sizeProperty(), QSize(99, 13));
252 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
253 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
254 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
255 QCOMPARE(object->boolProperty(), true);
256 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
257 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
258 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
263 void tst_qdeclarativeecmascript::idShortcutInvalidates()
266 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
267 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
268 QVERIFY(object != 0);
269 QVERIFY(object->objectProperty() != 0);
270 delete object->objectProperty();
271 QVERIFY(object->objectProperty() == 0);
276 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
277 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
278 QVERIFY(object != 0);
279 QVERIFY(object->objectProperty() != 0);
280 delete object->objectProperty();
281 QVERIFY(object->objectProperty() == 0);
286 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
289 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
290 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
291 QVERIFY(object != 0);
292 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
296 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
297 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
298 QVERIFY(object != 0);
299 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
304 void tst_qdeclarativeecmascript::signalAssignment()
307 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
308 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
309 QVERIFY(object != 0);
310 QCOMPARE(object->string(), QString());
311 emit object->basicSignal();
312 QCOMPARE(object->string(), QString("pass"));
317 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
318 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
319 QVERIFY(object != 0);
320 QCOMPARE(object->string(), QString());
321 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
322 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
327 void tst_qdeclarativeecmascript::methods()
330 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
331 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
332 QVERIFY(object != 0);
333 QCOMPARE(object->methodCalled(), false);
334 QCOMPARE(object->methodIntCalled(), false);
335 emit object->basicSignal();
336 QCOMPARE(object->methodCalled(), true);
337 QCOMPARE(object->methodIntCalled(), false);
342 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
343 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
344 QVERIFY(object != 0);
345 QCOMPARE(object->methodCalled(), false);
346 QCOMPARE(object->methodIntCalled(), false);
347 emit object->basicSignal();
348 QCOMPARE(object->methodCalled(), false);
349 QCOMPARE(object->methodIntCalled(), true);
354 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
355 QObject *object = component.create();
356 QVERIFY(object != 0);
357 QCOMPARE(object->property("test").toInt(), 19);
362 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
363 QObject *object = component.create();
364 QVERIFY(object != 0);
365 QCOMPARE(object->property("test").toInt(), 19);
366 QCOMPARE(object->property("test2").toInt(), 17);
367 QCOMPARE(object->property("test3").toInt(), 16);
372 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
373 QObject *object = component.create();
374 QVERIFY(object != 0);
375 QCOMPARE(object->property("test").toInt(), 9);
380 void tst_qdeclarativeecmascript::bindingLoop()
382 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
383 QString warning = component.url().toString() + ":9:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
384 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
385 QObject *object = component.create();
386 QVERIFY(object != 0);
390 void tst_qdeclarativeecmascript::basicExpressions_data()
392 QTest::addColumn<QString>("expression");
393 QTest::addColumn<QVariant>("result");
394 QTest::addColumn<bool>("nest");
396 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
397 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
398 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
399 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
400 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
401 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
402 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
403 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
404 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
405 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
406 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
407 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
408 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
409 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
410 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
411 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
412 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
413 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
414 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
417 void tst_qdeclarativeecmascript::basicExpressions()
419 QFETCH(QString, expression);
420 QFETCH(QVariant, result);
426 MyDefaultObject1 default1;
427 MyDefaultObject3 default3;
428 object1.setStringProperty("Object1");
429 object2.setStringProperty("Object2");
430 object3.setStringProperty("Object3");
432 QDeclarativeContext context(engine.rootContext());
433 QDeclarativeContext nestedContext(&context);
435 context.setContextObject(&default1);
436 context.setContextProperty("a", QVariant(1944));
437 context.setContextProperty("b", QVariant("Milk"));
438 context.setContextProperty("object", &object1);
439 context.setContextProperty("objectOverride", &object2);
440 nestedContext.setContextObject(&default3);
441 nestedContext.setContextProperty("b", QVariant("Cow"));
442 nestedContext.setContextProperty("objectOverride", &object3);
443 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
445 MyExpression expr(nest?&nestedContext:&context, expression);
446 QCOMPARE(expr.evaluate(), result);
449 void tst_qdeclarativeecmascript::arrayExpressions()
455 QDeclarativeContext context(engine.rootContext());
456 context.setContextProperty("a", &obj1);
457 context.setContextProperty("b", &obj2);
458 context.setContextProperty("c", &obj3);
460 MyExpression expr(&context, "[a, b, c, 10]");
461 QVariant result = expr.evaluate();
462 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
463 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
464 QCOMPARE(list.count(), 4);
465 QCOMPARE(list.at(0), &obj1);
466 QCOMPARE(list.at(1), &obj2);
467 QCOMPARE(list.at(2), &obj3);
468 QCOMPARE(list.at(3), (QObject *)0);
471 // Tests that modifying a context property will reevaluate expressions
472 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
474 QDeclarativeContext context(engine.rootContext());
477 MyQmlObject *object3 = new MyQmlObject;
479 object1.setStringProperty("Hello");
480 object2.setStringProperty("World");
482 context.setContextProperty("testProp", QVariant(1));
483 context.setContextProperty("testObj", &object1);
484 context.setContextProperty("testObj2", object3);
487 MyExpression expr(&context, "testProp + 1");
488 QCOMPARE(expr.changed, false);
489 QCOMPARE(expr.evaluate(), QVariant(2));
491 context.setContextProperty("testProp", QVariant(2));
492 QCOMPARE(expr.changed, true);
493 QCOMPARE(expr.evaluate(), QVariant(3));
497 MyExpression expr(&context, "testProp + testProp + testProp");
498 QCOMPARE(expr.changed, false);
499 QCOMPARE(expr.evaluate(), QVariant(6));
501 context.setContextProperty("testProp", QVariant(4));
502 QCOMPARE(expr.changed, true);
503 QCOMPARE(expr.evaluate(), QVariant(12));
507 MyExpression expr(&context, "testObj.stringProperty");
508 QCOMPARE(expr.changed, false);
509 QCOMPARE(expr.evaluate(), QVariant("Hello"));
511 context.setContextProperty("testObj", &object2);
512 QCOMPARE(expr.changed, true);
513 QCOMPARE(expr.evaluate(), QVariant("World"));
517 MyExpression expr(&context, "testObj.stringProperty /**/");
518 QCOMPARE(expr.changed, false);
519 QCOMPARE(expr.evaluate(), QVariant("World"));
521 context.setContextProperty("testObj", &object1);
522 QCOMPARE(expr.changed, true);
523 QCOMPARE(expr.evaluate(), QVariant("Hello"));
527 MyExpression expr(&context, "testObj2");
528 QCOMPARE(expr.changed, false);
529 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
535 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
537 QDeclarativeContext context(engine.rootContext());
541 context.setContextProperty("testObj", &object1);
543 object1.setStringProperty(QLatin1String("Hello"));
544 object2.setStringProperty(QLatin1String("Dog"));
545 object3.setStringProperty(QLatin1String("Cat"));
548 MyExpression expr(&context, "testObj.stringProperty");
549 QCOMPARE(expr.changed, false);
550 QCOMPARE(expr.evaluate(), QVariant("Hello"));
552 object1.setStringProperty(QLatin1String("World"));
553 QCOMPARE(expr.changed, true);
554 QCOMPARE(expr.evaluate(), QVariant("World"));
558 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
559 QCOMPARE(expr.changed, false);
560 QCOMPARE(expr.evaluate(), QVariant());
562 object1.setObjectProperty(&object2);
563 QCOMPARE(expr.changed, true);
564 expr.changed = false;
565 QCOMPARE(expr.evaluate(), QVariant("Dog"));
567 object1.setObjectProperty(&object3);
568 QCOMPARE(expr.changed, true);
569 expr.changed = false;
570 QCOMPARE(expr.evaluate(), QVariant("Cat"));
572 object1.setObjectProperty(0);
573 QCOMPARE(expr.changed, true);
574 expr.changed = false;
575 QCOMPARE(expr.evaluate(), QVariant());
577 object1.setObjectProperty(&object3);
578 QCOMPARE(expr.changed, true);
579 expr.changed = false;
580 QCOMPARE(expr.evaluate(), QVariant("Cat"));
582 object3.setStringProperty("Donkey");
583 QCOMPARE(expr.changed, true);
584 expr.changed = false;
585 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
589 void tst_qdeclarativeecmascript::deferredProperties()
591 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
592 MyDeferredObject *object =
593 qobject_cast<MyDeferredObject *>(component.create());
594 QVERIFY(object != 0);
595 QCOMPARE(object->value(), 0);
596 QVERIFY(object->objectProperty() == 0);
597 QVERIFY(object->objectProperty2() != 0);
598 qmlExecuteDeferred(object);
599 QCOMPARE(object->value(), 10);
600 QVERIFY(object->objectProperty() != 0);
601 MyQmlObject *qmlObject =
602 qobject_cast<MyQmlObject *>(object->objectProperty());
603 QVERIFY(qmlObject != 0);
604 QCOMPARE(qmlObject->value(), 10);
605 object->setValue(19);
606 QCOMPARE(qmlObject->value(), 19);
611 // Check errors on deferred properties are correctly emitted
612 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
614 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
615 MyDeferredObject *object =
616 qobject_cast<MyDeferredObject *>(component.create());
617 QVERIFY(object != 0);
618 QCOMPARE(object->value(), 0);
619 QVERIFY(object->objectProperty() == 0);
620 QVERIFY(object->objectProperty2() == 0);
622 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject* objectProperty";
623 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
625 qmlExecuteDeferred(object);
630 void tst_qdeclarativeecmascript::extensionObjects()
632 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
633 MyExtendedObject *object =
634 qobject_cast<MyExtendedObject *>(component.create());
635 QVERIFY(object != 0);
636 QCOMPARE(object->baseProperty(), 13);
637 QCOMPARE(object->coreProperty(), 9);
638 object->setProperty("extendedProperty", QVariant(11));
639 object->setProperty("baseExtendedProperty", QVariant(92));
640 QCOMPARE(object->coreProperty(), 11);
641 QCOMPARE(object->baseProperty(), 92);
643 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
645 QCOMPARE(nested->baseProperty(), 13);
646 QCOMPARE(nested->coreProperty(), 9);
647 nested->setProperty("extendedProperty", QVariant(11));
648 nested->setProperty("baseExtendedProperty", QVariant(92));
649 QCOMPARE(nested->coreProperty(), 11);
650 QCOMPARE(nested->baseProperty(), 92);
655 void tst_qdeclarativeecmascript::overrideExtensionProperties()
657 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
658 OverrideDefaultPropertyObject *object =
659 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
660 QVERIFY(object != 0);
661 QVERIFY(object->secondProperty() != 0);
662 QVERIFY(object->firstProperty() == 0);
667 void tst_qdeclarativeecmascript::attachedProperties()
670 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
671 QObject *object = component.create();
672 QVERIFY(object != 0);
673 QCOMPARE(object->property("a").toInt(), 19);
674 QCOMPARE(object->property("b").toInt(), 19);
675 QCOMPARE(object->property("c").toInt(), 19);
676 QCOMPARE(object->property("d").toInt(), 19);
681 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
682 QObject *object = component.create();
683 QVERIFY(object != 0);
684 QCOMPARE(object->property("a").toInt(), 26);
685 QCOMPARE(object->property("b").toInt(), 26);
686 QCOMPARE(object->property("c").toInt(), 26);
687 QCOMPARE(object->property("d").toInt(), 26);
691 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
692 QObject *object = component.create();
693 QVERIFY(object != 0);
695 QMetaObject::invokeMethod(object, "writeValue2");
697 MyQmlAttachedObject *attached =
698 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
699 QVERIFY(attached != 0);
701 QCOMPARE(attached->value2(), 9);
706 void tst_qdeclarativeecmascript::enums()
710 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
711 QObject *object = component.create();
712 QVERIFY(object != 0);
714 QCOMPARE(object->property("a").toInt(), 0);
715 QCOMPARE(object->property("b").toInt(), 1);
716 QCOMPARE(object->property("c").toInt(), 2);
717 QCOMPARE(object->property("d").toInt(), 3);
718 QCOMPARE(object->property("e").toInt(), 0);
719 QCOMPARE(object->property("f").toInt(), 1);
720 QCOMPARE(object->property("g").toInt(), 2);
721 QCOMPARE(object->property("h").toInt(), 3);
722 QCOMPARE(object->property("i").toInt(), 19);
723 QCOMPARE(object->property("j").toInt(), 19);
727 // Non-existent enums
729 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
731 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int a";
732 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int b";
733 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
734 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
736 QObject *object = component.create();
737 QVERIFY(object != 0);
738 QCOMPARE(object->property("a").toInt(), 0);
739 QCOMPARE(object->property("b").toInt(), 0);
745 void tst_qdeclarativeecmascript::valueTypeFunctions()
747 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
748 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
750 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
751 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
757 Tests that writing a constant to a property with a binding on it disables the
760 void tst_qdeclarativeecmascript::constantsOverrideBindings()
764 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
765 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
766 QVERIFY(object != 0);
768 QCOMPARE(object->property("c2").toInt(), 0);
769 object->setProperty("c1", QVariant(9));
770 QCOMPARE(object->property("c2").toInt(), 9);
772 emit object->basicSignal();
774 QCOMPARE(object->property("c2").toInt(), 13);
775 object->setProperty("c1", QVariant(8));
776 QCOMPARE(object->property("c2").toInt(), 13);
781 // During construction
783 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
784 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
785 QVERIFY(object != 0);
787 QCOMPARE(object->property("c1").toInt(), 0);
788 QCOMPARE(object->property("c2").toInt(), 10);
789 object->setProperty("c1", QVariant(9));
790 QCOMPARE(object->property("c1").toInt(), 9);
791 QCOMPARE(object->property("c2").toInt(), 10);
799 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
800 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
801 QVERIFY(object != 0);
803 QCOMPARE(object->property("c2").toInt(), 0);
804 object->setProperty("c1", QVariant(9));
805 QCOMPARE(object->property("c2").toInt(), 9);
807 object->setProperty("c2", QVariant(13));
808 QCOMPARE(object->property("c2").toInt(), 13);
809 object->setProperty("c1", QVariant(7));
810 QCOMPARE(object->property("c1").toInt(), 7);
811 QCOMPARE(object->property("c2").toInt(), 13);
819 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
820 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
821 QVERIFY(object != 0);
823 QCOMPARE(object->property("c1").toInt(), 0);
824 QCOMPARE(object->property("c3").toInt(), 10);
825 object->setProperty("c1", QVariant(9));
826 QCOMPARE(object->property("c1").toInt(), 9);
827 QCOMPARE(object->property("c3").toInt(), 10);
834 Tests that assigning a binding to a property that already has a binding causes
835 the original binding to be disabled.
837 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
839 QDeclarativeComponent component(&engine,
840 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
841 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
842 QVERIFY(object != 0);
844 QCOMPARE(object->property("c1").toInt(), 0);
845 QCOMPARE(object->property("c2").toInt(), 0);
846 QCOMPARE(object->property("c3").toInt(), 0);
848 object->setProperty("c1", QVariant(9));
849 QCOMPARE(object->property("c1").toInt(), 9);
850 QCOMPARE(object->property("c2").toInt(), 0);
851 QCOMPARE(object->property("c3").toInt(), 0);
853 object->setProperty("c3", QVariant(8));
854 QCOMPARE(object->property("c1").toInt(), 9);
855 QCOMPARE(object->property("c2").toInt(), 8);
856 QCOMPARE(object->property("c3").toInt(), 8);
862 Access a non-existent attached object.
864 Tests for a regression where this used to crash.
866 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
868 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
870 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString stringProperty";
871 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
873 QObject *object = component.create();
874 QVERIFY(object != 0);
879 void tst_qdeclarativeecmascript::scope()
882 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
883 QObject *object = component.create();
884 QVERIFY(object != 0);
886 QCOMPARE(object->property("test1").toInt(), 1);
887 QCOMPARE(object->property("test2").toInt(), 2);
888 QCOMPARE(object->property("test3").toString(), QString("1Test"));
889 QCOMPARE(object->property("test4").toString(), QString("2Test"));
890 QCOMPARE(object->property("test5").toInt(), 1);
891 QCOMPARE(object->property("test6").toInt(), 1);
892 QCOMPARE(object->property("test7").toInt(), 2);
893 QCOMPARE(object->property("test8").toInt(), 2);
894 QCOMPARE(object->property("test9").toInt(), 1);
895 QCOMPARE(object->property("test10").toInt(), 3);
901 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
902 QObject *object = component.create();
903 QVERIFY(object != 0);
905 QCOMPARE(object->property("test1").toInt(), 19);
906 QCOMPARE(object->property("test2").toInt(), 19);
907 QCOMPARE(object->property("test3").toInt(), 14);
908 QCOMPARE(object->property("test4").toInt(), 14);
909 QCOMPARE(object->property("test5").toInt(), 24);
910 QCOMPARE(object->property("test6").toInt(), 24);
916 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
917 QObject *object = component.create();
918 QVERIFY(object != 0);
920 QCOMPARE(object->property("test1").toBool(), true);
921 QCOMPARE(object->property("test2").toBool(), true);
922 QCOMPARE(object->property("test3").toBool(), true);
927 // Signal argument scope
929 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
930 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
931 QVERIFY(object != 0);
933 QCOMPARE(object->property("test").toInt(), 0);
934 QCOMPARE(object->property("test2").toString(), QString());
936 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
938 QCOMPARE(object->property("test").toInt(), 13);
939 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
945 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
946 QObject *object = component.create();
947 QVERIFY(object != 0);
949 QCOMPARE(object->property("test1").toBool(), true);
950 QCOMPARE(object->property("test2").toBool(), true);
956 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
957 QObject *object = component.create();
958 QVERIFY(object != 0);
960 QCOMPARE(object->property("test").toBool(), true);
966 // In 4.7, non-library javascript files that had no imports shared the imports of their
968 void tst_qdeclarativeecmascript::importScope()
970 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
971 QObject *o = component.create();
974 QCOMPARE(o->property("test").toInt(), 240);
980 Tests that "any" type passes through a synthesized signal parameter. This
981 is essentially a test of QDeclarativeMetaType::copy()
983 void tst_qdeclarativeecmascript::signalParameterTypes()
985 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
986 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
987 QVERIFY(object != 0);
989 emit object->basicSignal();
991 QCOMPARE(object->property("intProperty").toInt(), 10);
992 QCOMPARE(object->property("realProperty").toReal(), 19.2);
993 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
994 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
995 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
996 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1002 Test that two JS objects for the same QObject compare as equal.
1004 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1006 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1007 QObject *object = component.create();
1008 QVERIFY(object != 0);
1010 QCOMPARE(object->property("test1").toBool(), true);
1011 QCOMPARE(object->property("test2").toBool(), true);
1012 QCOMPARE(object->property("test3").toBool(), true);
1013 QCOMPARE(object->property("test4").toBool(), true);
1014 QCOMPARE(object->property("test5").toBool(), true);
1020 Confirm bindings and alias properties can coexist.
1022 Tests for a regression where the binding would not reevaluate.
1024 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1026 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1027 QObject *object = component.create();
1028 QVERIFY(object != 0);
1030 QCOMPARE(object->property("c2").toInt(), 3);
1031 QCOMPARE(object->property("c3").toInt(), 3);
1033 object->setProperty("c2", QVariant(19));
1035 QCOMPARE(object->property("c2").toInt(), 19);
1036 QCOMPARE(object->property("c3").toInt(), 19);
1041 void tst_qdeclarativeecmascript::dynamicCreation_data()
1043 QTest::addColumn<QString>("method");
1044 QTest::addColumn<QString>("createdName");
1046 QTest::newRow("One") << "createOne" << "objectOne";
1047 QTest::newRow("Two") << "createTwo" << "objectTwo";
1048 QTest::newRow("Three") << "createThree" << "objectThree";
1052 Test using createQmlObject to dynamically generate an item
1053 Also using createComponent is tested.
1055 void tst_qdeclarativeecmascript::dynamicCreation()
1057 QFETCH(QString, method);
1058 QFETCH(QString, createdName);
1060 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1061 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1062 QVERIFY(object != 0);
1064 QMetaObject::invokeMethod(object, method.toUtf8());
1065 QObject *created = object->objectProperty();
1067 QCOMPARE(created->objectName(), createdName);
1073 Tests the destroy function
1075 void tst_qdeclarativeecmascript::dynamicDestruction()
1077 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1078 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1079 QVERIFY(object != 0);
1080 QDeclarativeGuard<QObject> createdQmlObject = 0;
1082 QMetaObject::invokeMethod(object, "create");
1083 createdQmlObject = object->objectProperty();
1084 QVERIFY(createdQmlObject);
1085 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1087 QMetaObject::invokeMethod(object, "killOther");
1088 QVERIFY(createdQmlObject);
1089 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1090 QVERIFY(createdQmlObject);
1091 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1092 if (createdQmlObject) {
1094 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1097 QVERIFY(!createdQmlObject);
1099 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1100 QMetaObject::invokeMethod(object, "killMe");
1103 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1108 tests that id.toString() works
1110 void tst_qdeclarativeecmascript::objectToString()
1112 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1113 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1114 QVERIFY(object != 0);
1115 QMetaObject::invokeMethod(object, "testToString");
1116 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1117 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1123 Tests bindings that indirectly cause their own deletion work.
1125 This test is best run under valgrind to ensure no invalid memory access occur.
1127 void tst_qdeclarativeecmascript::selfDeletingBinding()
1130 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1131 QObject *object = component.create();
1132 QVERIFY(object != 0);
1133 object->setProperty("triggerDelete", true);
1138 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1139 QObject *object = component.create();
1140 QVERIFY(object != 0);
1141 object->setProperty("triggerDelete", true);
1147 Test that extended object properties can be accessed.
1149 This test a regression where this used to crash. The issue was specificially
1150 for extended objects that did not include a synthesized meta object (so non-root
1151 and no synthesiszed properties).
1153 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1155 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1156 QObject *object = component.create();
1157 QVERIFY(object != 0);
1162 Test file/lineNumbers for binding/Script errors.
1164 void tst_qdeclarativeecmascript::scriptErrors()
1166 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1167 QString url = component.url().toString();
1169 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1170 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1171 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1172 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1173 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1174 QString warning6 = url + ":7: Unable to assign [undefined] to int x";
1175 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1176 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1178 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1179 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1180 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1181 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1182 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1183 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1184 QVERIFY(object != 0);
1186 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1187 emit object->basicSignal();
1189 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1190 emit object->anotherBasicSignal();
1192 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1193 emit object->thirdBasicSignal();
1199 Test file/lineNumbers for inline functions.
1201 void tst_qdeclarativeecmascript::functionErrors()
1203 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1204 QString url = component.url().toString();
1206 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1208 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1210 QObject *object = component.create();
1211 QVERIFY(object != 0);
1214 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1215 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1216 url = componentTwo.url().toString();
1217 object = componentTwo.create();
1218 QVERIFY(object != 0);
1220 QString srpname = object->property("srp_name").toString();
1222 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1223 QLatin1String(" is not a function");
1224 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1225 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1230 Test various errors that can occur when assigning a property from script
1232 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1234 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1236 QString url = component.url().toString();
1238 QObject *object = component.create();
1239 QVERIFY(object != 0);
1241 QCOMPARE(object->property("test1").toBool(), true);
1242 QCOMPARE(object->property("test2").toBool(), true);
1248 Test bindings still work when the reeval is triggered from within
1251 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1253 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1254 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1255 QVERIFY(object != 0);
1257 QCOMPARE(object->property("base").toReal(), 50.);
1258 QCOMPARE(object->property("test1").toReal(), 50.);
1259 QCOMPARE(object->property("test2").toReal(), 50.);
1261 object->basicSignal();
1263 QCOMPARE(object->property("base").toReal(), 200.);
1264 QCOMPARE(object->property("test1").toReal(), 200.);
1265 QCOMPARE(object->property("test2").toReal(), 200.);
1267 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1269 QCOMPARE(object->property("base").toReal(), 400.);
1270 QCOMPARE(object->property("test1").toReal(), 400.);
1271 QCOMPARE(object->property("test2").toReal(), 400.);
1277 Test that list properties can be iterated from ECMAScript
1279 void tst_qdeclarativeecmascript::listProperties()
1281 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1282 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1283 QVERIFY(object != 0);
1285 QCOMPARE(object->property("test1").toInt(), 21);
1286 QCOMPARE(object->property("test2").toInt(), 2);
1287 QCOMPARE(object->property("test3").toBool(), true);
1288 QCOMPARE(object->property("test4").toBool(), true);
1293 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1295 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1296 QString url = component.url().toString();
1298 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1300 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1301 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1302 QVERIFY(object != 0);
1304 QCOMPARE(object->property("test").toBool(), false);
1306 MyQmlObject object2;
1307 MyQmlObject object3;
1308 object2.setObjectProperty(&object3);
1309 object->setObjectProperty(&object2);
1311 QCOMPARE(object->property("test").toBool(), true);
1316 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1318 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1319 QString url = component.url().toString();
1321 QString warning = component.url().toString() + ":6: Error: JS exception";
1323 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1324 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1325 QVERIFY(object != 0);
1329 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1331 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1332 QString url = component.url().toString();
1334 QString warning = component.url().toString() + ":5: Error: JS exception";
1336 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1337 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1338 QVERIFY(object != 0);
1342 static int transientErrorsMsgCount = 0;
1343 static void transientErrorsMsgHandler(QtMsgType, const char *)
1345 ++transientErrorsMsgCount;
1348 // Check that transient binding errors are not displayed
1349 void tst_qdeclarativeecmascript::transientErrors()
1352 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1354 transientErrorsMsgCount = 0;
1355 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1357 QObject *object = component.create();
1358 QVERIFY(object != 0);
1360 qInstallMsgHandler(old);
1362 QCOMPARE(transientErrorsMsgCount, 0);
1367 // One binding erroring multiple times, but then resolving
1369 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1371 transientErrorsMsgCount = 0;
1372 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1374 QObject *object = component.create();
1375 QVERIFY(object != 0);
1377 qInstallMsgHandler(old);
1379 QCOMPARE(transientErrorsMsgCount, 0);
1385 // Check that errors during shutdown are minimized
1386 void tst_qdeclarativeecmascript::shutdownErrors()
1388 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1389 QObject *object = component.create();
1390 QVERIFY(object != 0);
1392 transientErrorsMsgCount = 0;
1393 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1397 qInstallMsgHandler(old);
1398 QCOMPARE(transientErrorsMsgCount, 0);
1401 void tst_qdeclarativeecmascript::compositePropertyType()
1403 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1404 QTest::ignoreMessage(QtDebugMsg, "hello world");
1405 QObject *object = qobject_cast<QObject *>(component.create());
1410 void tst_qdeclarativeecmascript::jsObject()
1412 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1413 QObject *object = component.create();
1414 QVERIFY(object != 0);
1416 QCOMPARE(object->property("test").toInt(), 92);
1421 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1424 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1425 QObject *object = component.create();
1426 QVERIFY(object != 0);
1428 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1430 object->setProperty("setUndefined", true);
1432 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1434 object->setProperty("setUndefined", false);
1436 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1441 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1442 QObject *object = component.create();
1443 QVERIFY(object != 0);
1445 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1447 QMetaObject::invokeMethod(object, "doReset");
1449 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1456 void tst_qdeclarativeecmascript::bug1()
1458 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1459 QObject *object = component.create();
1460 QVERIFY(object != 0);
1462 QCOMPARE(object->property("test").toInt(), 14);
1464 object->setProperty("a", 11);
1466 QCOMPARE(object->property("test").toInt(), 3);
1468 object->setProperty("b", true);
1470 QCOMPARE(object->property("test").toInt(), 9);
1475 void tst_qdeclarativeecmascript::bug2()
1477 QDeclarativeComponent component(&engine);
1478 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1480 QObject *object = component.create();
1481 QVERIFY(object != 0);
1486 // Don't crash in createObject when the component has errors.
1487 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1489 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1490 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1491 QVERIFY(object != 0);
1493 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1494 QMetaObject::invokeMethod(object, "dontCrash");
1495 QObject *created = object->objectProperty();
1496 QVERIFY(created == 0);
1502 void tst_qdeclarativeecmascript::regExpBug()
1504 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1505 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1506 QVERIFY(object != 0);
1507 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1511 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1513 QString functionSource = QLatin1String("(function(object) { return ") +
1514 QLatin1String(source) + QLatin1String(" })");
1516 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1519 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1520 if (function.IsEmpty())
1522 v8::Handle<v8::Value> args[] = { o };
1523 function->Call(engine->global(), 1, args);
1524 return tc.HasCaught();
1527 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1528 const char *source, v8::Handle<v8::Value> result)
1530 QString functionSource = QLatin1String("(function(object) { return ") +
1531 QLatin1String(source) + QLatin1String(" })");
1533 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1536 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1537 if (function.IsEmpty())
1539 v8::Handle<v8::Value> args[] = { o };
1541 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1546 return value->StrictEquals(result);
1549 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1552 QString functionSource = QLatin1String("(function(object) { return ") +
1553 QLatin1String(source) + QLatin1String(" })");
1555 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1557 return v8::Handle<v8::Value>();
1558 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1559 if (function.IsEmpty())
1560 return v8::Handle<v8::Value>();
1561 v8::Handle<v8::Value> args[] = { o };
1563 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1566 return v8::Handle<v8::Value>();
1570 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1571 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1572 #define EVALUATE(source) evaluate(engine, object, source)
1574 void tst_qdeclarativeecmascript::callQtInvokables()
1576 MyInvokableObject o;
1578 QDeclarativeEngine qmlengine;
1579 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1581 QV8Engine *engine = &ep->v8engine;
1583 v8::HandleScope handle_scope;
1584 v8::Context::Scope scope(engine->context());
1586 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1588 // Non-existent methods
1590 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1591 QCOMPARE(o.error(), false);
1592 QCOMPARE(o.invoked(), -1);
1593 QCOMPARE(o.actuals().count(), 0);
1596 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1597 QCOMPARE(o.error(), false);
1598 QCOMPARE(o.invoked(), -1);
1599 QCOMPARE(o.actuals().count(), 0);
1601 // Insufficient arguments
1603 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1604 QCOMPARE(o.error(), false);
1605 QCOMPARE(o.invoked(), -1);
1606 QCOMPARE(o.actuals().count(), 0);
1609 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1610 QCOMPARE(o.error(), false);
1611 QCOMPARE(o.invoked(), -1);
1612 QCOMPARE(o.actuals().count(), 0);
1614 // Excessive arguments
1616 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1617 QCOMPARE(o.error(), false);
1618 QCOMPARE(o.invoked(), 8);
1619 QCOMPARE(o.actuals().count(), 1);
1620 QCOMPARE(o.actuals().at(0), QVariant(10));
1623 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1624 QCOMPARE(o.error(), false);
1625 QCOMPARE(o.invoked(), 9);
1626 QCOMPARE(o.actuals().count(), 2);
1627 QCOMPARE(o.actuals().at(0), QVariant(10));
1628 QCOMPARE(o.actuals().at(1), QVariant(11));
1630 // Test return types
1632 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1633 QCOMPARE(o.error(), false);
1634 QCOMPARE(o.invoked(), 0);
1635 QCOMPARE(o.actuals().count(), 0);
1638 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1639 QCOMPARE(o.error(), false);
1640 QCOMPARE(o.invoked(), 1);
1641 QCOMPARE(o.actuals().count(), 0);
1644 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1645 QCOMPARE(o.error(), false);
1646 QCOMPARE(o.invoked(), 2);
1647 QCOMPARE(o.actuals().count(), 0);
1651 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1652 QVERIFY(!ret.IsEmpty());
1653 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1654 QCOMPARE(o.error(), false);
1655 QCOMPARE(o.invoked(), 3);
1656 QCOMPARE(o.actuals().count(), 0);
1661 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1662 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1663 QCOMPARE(o.error(), false);
1664 QCOMPARE(o.invoked(), 4);
1665 QCOMPARE(o.actuals().count(), 0);
1669 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1670 QCOMPARE(o.error(), false);
1671 QCOMPARE(o.invoked(), 5);
1672 QCOMPARE(o.actuals().count(), 0);
1674 // XXX enable once qml/qtscript integration is implemented
1678 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1679 QVERIFY(ret->IsString());
1680 QCOMPARE(engine->toString(ret), QString("Hello world"));
1681 QCOMPARE(o.error(), false);
1682 QCOMPARE(o.invoked(), 6);
1683 QCOMPARE(o.actuals().count(), 0);
1688 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1689 QCOMPARE(o.error(), false);
1690 QCOMPARE(o.invoked(), 7);
1691 QCOMPARE(o.actuals().count(), 0);
1695 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1696 QCOMPARE(o.error(), false);
1697 QCOMPARE(o.invoked(), 8);
1698 QCOMPARE(o.actuals().count(), 1);
1699 QCOMPARE(o.actuals().at(0), QVariant(94));
1702 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1703 QCOMPARE(o.error(), false);
1704 QCOMPARE(o.invoked(), 8);
1705 QCOMPARE(o.actuals().count(), 1);
1706 QCOMPARE(o.actuals().at(0), QVariant(94));
1709 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1710 QCOMPARE(o.error(), false);
1711 QCOMPARE(o.invoked(), 8);
1712 QCOMPARE(o.actuals().count(), 1);
1713 QCOMPARE(o.actuals().at(0), QVariant(0));
1716 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1717 QCOMPARE(o.error(), false);
1718 QCOMPARE(o.invoked(), 8);
1719 QCOMPARE(o.actuals().count(), 1);
1720 QCOMPARE(o.actuals().at(0), QVariant(0));
1723 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1724 QCOMPARE(o.error(), false);
1725 QCOMPARE(o.invoked(), 8);
1726 QCOMPARE(o.actuals().count(), 1);
1727 QCOMPARE(o.actuals().at(0), QVariant(0));
1730 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1731 QCOMPARE(o.error(), false);
1732 QCOMPARE(o.invoked(), 8);
1733 QCOMPARE(o.actuals().count(), 1);
1734 QCOMPARE(o.actuals().at(0), QVariant(0));
1737 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1738 QCOMPARE(o.error(), false);
1739 QCOMPARE(o.invoked(), 9);
1740 QCOMPARE(o.actuals().count(), 2);
1741 QCOMPARE(o.actuals().at(0), QVariant(122));
1742 QCOMPARE(o.actuals().at(1), QVariant(9));
1745 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1746 QCOMPARE(o.error(), false);
1747 QCOMPARE(o.invoked(), 10);
1748 QCOMPARE(o.actuals().count(), 1);
1749 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1752 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1753 QCOMPARE(o.error(), false);
1754 QCOMPARE(o.invoked(), 10);
1755 QCOMPARE(o.actuals().count(), 1);
1756 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1759 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1760 QCOMPARE(o.error(), false);
1761 QCOMPARE(o.invoked(), 10);
1762 QCOMPARE(o.actuals().count(), 1);
1763 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1766 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
1767 QCOMPARE(o.error(), false);
1768 QCOMPARE(o.invoked(), 10);
1769 QCOMPARE(o.actuals().count(), 1);
1770 QCOMPARE(o.actuals().at(0), QVariant(0));
1773 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
1774 QCOMPARE(o.error(), false);
1775 QCOMPARE(o.invoked(), 10);
1776 QCOMPARE(o.actuals().count(), 1);
1777 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1780 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
1781 QCOMPARE(o.error(), false);
1782 QCOMPARE(o.invoked(), 10);
1783 QCOMPARE(o.actuals().count(), 1);
1784 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
1787 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
1788 QCOMPARE(o.error(), false);
1789 QCOMPARE(o.invoked(), 11);
1790 QCOMPARE(o.actuals().count(), 1);
1791 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
1794 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
1795 QCOMPARE(o.error(), false);
1796 QCOMPARE(o.invoked(), 11);
1797 QCOMPARE(o.actuals().count(), 1);
1798 QCOMPARE(o.actuals().at(0), QVariant("19"));
1802 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
1803 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
1804 QCOMPARE(o.error(), false);
1805 QCOMPARE(o.invoked(), 11);
1806 QCOMPARE(o.actuals().count(), 1);
1807 QCOMPARE(o.actuals().at(0), QVariant(expected));
1811 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
1812 QCOMPARE(o.error(), false);
1813 QCOMPARE(o.invoked(), 11);
1814 QCOMPARE(o.actuals().count(), 1);
1815 QCOMPARE(o.actuals().at(0), QVariant(QString()));
1818 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
1819 QCOMPARE(o.error(), false);
1820 QCOMPARE(o.invoked(), 11);
1821 QCOMPARE(o.actuals().count(), 1);
1822 QCOMPARE(o.actuals().at(0), QVariant(QString()));
1825 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
1826 QCOMPARE(o.error(), false);
1827 QCOMPARE(o.invoked(), 12);
1828 QCOMPARE(o.actuals().count(), 1);
1829 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1832 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
1833 QCOMPARE(o.error(), false);
1834 QCOMPARE(o.invoked(), 12);
1835 QCOMPARE(o.actuals().count(), 1);
1836 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1839 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
1840 QCOMPARE(o.error(), false);
1841 QCOMPARE(o.invoked(), 12);
1842 QCOMPARE(o.actuals().count(), 1);
1843 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1846 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
1847 QCOMPARE(o.error(), false);
1848 QCOMPARE(o.invoked(), 12);
1849 QCOMPARE(o.actuals().count(), 1);
1850 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
1853 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
1854 QCOMPARE(o.error(), false);
1855 QCOMPARE(o.invoked(), 12);
1856 QCOMPARE(o.actuals().count(), 1);
1857 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
1860 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
1861 QCOMPARE(o.error(), false);
1862 QCOMPARE(o.invoked(), 12);
1863 QCOMPARE(o.actuals().count(), 1);
1864 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
1867 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
1868 QCOMPARE(o.error(), false);
1869 QCOMPARE(o.invoked(), 13);
1870 QCOMPARE(o.actuals().count(), 1);
1871 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1874 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
1875 QCOMPARE(o.error(), false);
1876 QCOMPARE(o.invoked(), 13);
1877 QCOMPARE(o.actuals().count(), 1);
1878 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1881 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
1882 QCOMPARE(o.error(), false);
1883 QCOMPARE(o.invoked(), 13);
1884 QCOMPARE(o.actuals().count(), 1);
1885 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1888 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
1889 QCOMPARE(o.error(), false);
1890 QCOMPARE(o.invoked(), 13);
1891 QCOMPARE(o.actuals().count(), 1);
1892 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
1895 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
1896 QCOMPARE(o.error(), false);
1897 QCOMPARE(o.invoked(), 13);
1898 QCOMPARE(o.actuals().count(), 1);
1899 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
1901 // XXX enable once qml/qtscript integration is implemented
1904 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
1905 QCOMPARE(o.error(), false);
1906 QCOMPARE(o.invoked(), 14);
1907 QCOMPARE(o.actuals().count(), 1);
1908 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isNull());
1911 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
1912 QCOMPARE(o.error(), false);
1913 QCOMPARE(o.invoked(), 14);
1914 QCOMPARE(o.actuals().count(), 1);
1915 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isUndefined());
1918 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
1919 QCOMPARE(o.error(), false);
1920 QCOMPARE(o.invoked(), 14);
1921 QCOMPARE(o.actuals().count(), 1);
1922 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).strictlyEquals(QScriptValue(engine, 19)));
1925 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
1926 QCOMPARE(o.error(), false);
1927 QCOMPARE(o.invoked(), 14);
1928 QCOMPARE(o.actuals().count(), 1);
1929 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(0)).isArray());
1932 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
1933 QCOMPARE(o.error(), false);
1934 QCOMPARE(o.invoked(), 15);
1935 QCOMPARE(o.actuals().count(), 2);
1936 QCOMPARE(o.actuals().at(0), QVariant(4));
1937 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isNull());
1940 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
1941 QCOMPARE(o.error(), false);
1942 QCOMPARE(o.invoked(), 15);
1943 QCOMPARE(o.actuals().count(), 2);
1944 QCOMPARE(o.actuals().at(0), QVariant(8));
1945 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isUndefined());
1948 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
1949 QCOMPARE(o.error(), false);
1950 QCOMPARE(o.invoked(), 15);
1951 QCOMPARE(o.actuals().count(), 2);
1952 QCOMPARE(o.actuals().at(0), QVariant(3));
1953 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).strictlyEquals(QScriptValue(engine, 19)));
1956 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
1957 QCOMPARE(o.error(), false);
1958 QCOMPARE(o.invoked(), 15);
1959 QCOMPARE(o.actuals().count(), 2);
1960 QCOMPARE(o.actuals().at(0), QVariant(44));
1961 QVERIFY(qvariant_cast<QScriptValue>(o.actuals().at(1)).isArray());
1965 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
1966 QCOMPARE(o.error(), false);
1967 QCOMPARE(o.invoked(), -1);
1968 QCOMPARE(o.actuals().count(), 0);
1971 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
1972 QCOMPARE(o.error(), false);
1973 QCOMPARE(o.invoked(), 16);
1974 QCOMPARE(o.actuals().count(), 1);
1975 QCOMPARE(o.actuals().at(0), QVariant(10));
1978 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
1979 QCOMPARE(o.error(), false);
1980 QCOMPARE(o.invoked(), 17);
1981 QCOMPARE(o.actuals().count(), 2);
1982 QCOMPARE(o.actuals().at(0), QVariant(10));
1983 QCOMPARE(o.actuals().at(1), QVariant(11));
1986 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
1987 QCOMPARE(o.error(), false);
1988 QCOMPARE(o.invoked(), 18);
1989 QCOMPARE(o.actuals().count(), 1);
1990 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
1993 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
1994 QCOMPARE(o.error(), false);
1995 QCOMPARE(o.invoked(), 19);
1996 QCOMPARE(o.actuals().count(), 1);
1997 QCOMPARE(o.actuals().at(0), QVariant(9));
2000 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2001 QCOMPARE(o.error(), false);
2002 QCOMPARE(o.invoked(), 20);
2003 QCOMPARE(o.actuals().count(), 2);
2004 QCOMPARE(o.actuals().at(0), QVariant(10));
2005 QCOMPARE(o.actuals().at(1), QVariant(19));
2008 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2009 QCOMPARE(o.error(), false);
2010 QCOMPARE(o.invoked(), 20);
2011 QCOMPARE(o.actuals().count(), 2);
2012 QCOMPARE(o.actuals().at(0), QVariant(10));
2013 QCOMPARE(o.actuals().at(1), QVariant(13));
2016 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2017 QCOMPARE(o.error(), false);
2018 QCOMPARE(o.invoked(), -3);
2019 QCOMPARE(o.actuals().count(), 1);
2020 QCOMPARE(o.actuals().at(0), QVariant(9));
2023 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2024 QCOMPARE(o.error(), false);
2025 QCOMPARE(o.invoked(), 21);
2026 QCOMPARE(o.actuals().count(), 2);
2027 QCOMPARE(o.actuals().at(0), QVariant(9));
2028 QCOMPARE(o.actuals().at(1), QVariant());
2031 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2032 QCOMPARE(o.error(), false);
2033 QCOMPARE(o.invoked(), 21);
2034 QCOMPARE(o.actuals().count(), 2);
2035 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2036 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2039 // QTBUG-13047 (check that you can pass registered object types as args)
2040 void tst_qdeclarativeecmascript::invokableObjectArg()
2042 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2044 QObject *o = component.create();
2046 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2048 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2053 // QTBUG-13047 (check that you can return registered object types from methods)
2054 void tst_qdeclarativeecmascript::invokableObjectRet()
2056 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2058 QObject *o = component.create();
2060 QCOMPARE(o->property("test").toBool(), true);
2065 void tst_qdeclarativeecmascript::listToVariant()
2067 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2069 MyQmlContainer container;
2071 QDeclarativeContext context(engine.rootContext());
2072 context.setContextObject(&container);
2074 QObject *object = component.create(&context);
2075 QVERIFY(object != 0);
2077 QVariant v = object->property("test");
2078 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2079 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2085 void tst_qdeclarativeecmascript::multiEngineObject()
2088 obj.setStringProperty("Howdy planet");
2090 QDeclarativeEngine e1;
2091 e1.rootContext()->setContextProperty("thing", &obj);
2092 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2094 QDeclarativeEngine e2;
2095 e2.rootContext()->setContextProperty("thing", &obj);
2096 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2098 QObject *o1 = c1.create();
2099 QObject *o2 = c2.create();
2101 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2102 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2108 // Test that references to QObjects are cleanup when the object is destroyed
2109 void tst_qdeclarativeecmascript::deletedObject()
2111 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2113 QObject *object = component.create();
2115 QCOMPARE(object->property("test1").toBool(), true);
2116 QCOMPARE(object->property("test2").toBool(), true);
2117 QCOMPARE(object->property("test3").toBool(), true);
2118 QCOMPARE(object->property("test4").toBool(), true);
2123 void tst_qdeclarativeecmascript::attachedPropertyScope()
2125 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2127 QObject *object = component.create();
2128 QVERIFY(object != 0);
2130 MyQmlAttachedObject *attached =
2131 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2132 QVERIFY(attached != 0);
2134 QCOMPARE(object->property("value2").toInt(), 0);
2136 attached->emitMySignal();
2138 QCOMPARE(object->property("value2").toInt(), 9);
2143 void tst_qdeclarativeecmascript::scriptConnect()
2146 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2148 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2149 QVERIFY(object != 0);
2151 QCOMPARE(object->property("test").toBool(), false);
2152 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2153 QCOMPARE(object->property("test").toBool(), true);
2159 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2161 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2162 QVERIFY(object != 0);
2164 QCOMPARE(object->property("test").toBool(), false);
2165 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2166 QCOMPARE(object->property("test").toBool(), true);
2172 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2174 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2175 QVERIFY(object != 0);
2177 QCOMPARE(object->property("test").toBool(), false);
2178 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2179 QCOMPARE(object->property("test").toBool(), true);
2185 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2187 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2188 QVERIFY(object != 0);
2190 QCOMPARE(object->methodCalled(), false);
2191 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2192 QCOMPARE(object->methodCalled(), true);
2198 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2200 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2201 QVERIFY(object != 0);
2203 QCOMPARE(object->methodCalled(), false);
2204 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2205 QCOMPARE(object->methodCalled(), true);
2211 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2213 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2214 QVERIFY(object != 0);
2216 QCOMPARE(object->property("test").toInt(), 0);
2217 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2218 QCOMPARE(object->property("test").toInt(), 2);
2224 void tst_qdeclarativeecmascript::scriptDisconnect()
2227 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2229 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2230 QVERIFY(object != 0);
2232 QCOMPARE(object->property("test").toInt(), 0);
2233 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2234 QCOMPARE(object->property("test").toInt(), 1);
2235 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2236 QCOMPARE(object->property("test").toInt(), 2);
2237 emit object->basicSignal();
2238 QCOMPARE(object->property("test").toInt(), 2);
2239 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2240 QCOMPARE(object->property("test").toInt(), 2);
2246 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2248 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2249 QVERIFY(object != 0);
2251 QCOMPARE(object->property("test").toInt(), 0);
2252 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2253 QCOMPARE(object->property("test").toInt(), 1);
2254 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2255 QCOMPARE(object->property("test").toInt(), 2);
2256 emit object->basicSignal();
2257 QCOMPARE(object->property("test").toInt(), 2);
2258 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2259 QCOMPARE(object->property("test").toInt(), 2);
2265 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.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);
2283 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2285 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2286 QVERIFY(object != 0);
2288 QCOMPARE(object->property("test").toInt(), 0);
2289 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2290 QCOMPARE(object->property("test").toInt(), 1);
2291 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2292 QCOMPARE(object->property("test").toInt(), 2);
2293 emit object->basicSignal();
2294 QCOMPARE(object->property("test").toInt(), 2);
2295 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2296 QCOMPARE(object->property("test").toInt(), 3);
2302 class OwnershipObject : public QObject
2306 OwnershipObject() { object = new QObject; }
2308 QPointer<QObject> object;
2311 QObject *getObject() { return object; }
2314 void tst_qdeclarativeecmascript::ownership()
2316 OwnershipObject own;
2317 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2318 context->setContextObject(&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);
2336 own.object = new QObject(&own);
2339 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2341 QVERIFY(own.object != 0);
2343 QObject *object = component.create(context);
2345 engine.collectGarbage();
2347 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2349 QVERIFY(own.object != 0);
2357 class CppOwnershipReturnValue : public QObject
2361 CppOwnershipReturnValue() : value(0) {}
2362 ~CppOwnershipReturnValue() { delete value; }
2364 Q_INVOKABLE QObject *create() {
2365 value = new QObject;
2366 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2370 Q_INVOKABLE MyQmlObject *createQmlObject() {
2371 MyQmlObject *rv = new MyQmlObject;
2376 QPointer<QObject> value;
2380 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2381 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2383 CppOwnershipReturnValue source;
2386 QDeclarativeEngine engine;
2387 engine.rootContext()->setContextProperty("source", &source);
2389 QVERIFY(source.value == 0);
2391 QDeclarativeComponent component(&engine);
2392 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2394 QObject *object = component.create();
2396 QVERIFY(object != 0);
2397 QVERIFY(source.value != 0);
2402 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2404 QVERIFY(source.value != 0);
2408 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2410 CppOwnershipReturnValue source;
2413 QDeclarativeEngine engine;
2414 engine.rootContext()->setContextProperty("source", &source);
2416 QVERIFY(source.value == 0);
2418 QDeclarativeComponent component(&engine);
2419 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2421 QObject *object = component.create();
2423 QVERIFY(object != 0);
2424 QVERIFY(source.value != 0);
2429 engine.collectGarbage();
2430 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2432 QVERIFY(source.value == 0);
2435 class QListQObjectMethodsObject : public QObject
2439 QListQObjectMethodsObject() {
2440 m_objects.append(new MyQmlObject());
2441 m_objects.append(new MyQmlObject());
2444 ~QListQObjectMethodsObject() {
2445 qDeleteAll(m_objects);
2449 QList<QObject *> getObjects() { return m_objects; }
2452 QList<QObject *> m_objects;
2455 // Tests that returning a QList<QObject*> from a method works
2456 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2458 QListQObjectMethodsObject obj;
2459 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2460 context->setContextObject(&obj);
2462 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2464 QObject *object = component.create(context);
2466 QCOMPARE(object->property("test").toInt(), 2);
2467 QCOMPARE(object->property("test2").toBool(), true);
2474 void tst_qdeclarativeecmascript::strictlyEquals()
2476 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2478 QObject *object = component.create();
2479 QVERIFY(object != 0);
2481 QCOMPARE(object->property("test1").toBool(), true);
2482 QCOMPARE(object->property("test2").toBool(), true);
2483 QCOMPARE(object->property("test3").toBool(), true);
2484 QCOMPARE(object->property("test4").toBool(), true);
2485 QCOMPARE(object->property("test5").toBool(), true);
2486 QCOMPARE(object->property("test6").toBool(), true);
2487 QCOMPARE(object->property("test7").toBool(), true);
2488 QCOMPARE(object->property("test8").toBool(), true);
2493 void tst_qdeclarativeecmascript::compiled()
2495 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2497 QObject *object = component.create();
2498 QVERIFY(object != 0);
2500 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2501 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2502 QCOMPARE(object->property("test3").toBool(), true);
2503 QCOMPARE(object->property("test4").toBool(), false);
2504 QCOMPARE(object->property("test5").toBool(), false);
2505 QCOMPARE(object->property("test6").toBool(), true);
2507 QCOMPARE(object->property("test7").toInt(), 185);
2508 QCOMPARE(object->property("test8").toInt(), 167);
2509 QCOMPARE(object->property("test9").toBool(), true);
2510 QCOMPARE(object->property("test10").toBool(), false);
2511 QCOMPARE(object->property("test11").toBool(), false);
2512 QCOMPARE(object->property("test12").toBool(), true);
2514 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2515 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2516 QCOMPARE(object->property("test15").toBool(), false);
2517 QCOMPARE(object->property("test16").toBool(), true);
2519 QCOMPARE(object->property("test17").toInt(), 5);
2520 QCOMPARE(object->property("test18").toReal(), qreal(176));
2521 QCOMPARE(object->property("test19").toInt(), 7);
2522 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2523 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2524 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2525 QCOMPARE(object->property("test23").toBool(), true);
2526 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2527 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2532 // Test that numbers assigned in bindings as strings work consistently
2533 void tst_qdeclarativeecmascript::numberAssignment()
2535 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2537 QObject *object = component.create();
2538 QVERIFY(object != 0);
2540 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2541 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2542 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2543 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2544 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2546 QCOMPARE(object->property("test5"), QVariant((int)7));
2547 QCOMPARE(object->property("test6"), QVariant((int)7));
2548 QCOMPARE(object->property("test7"), QVariant((int)6));
2549 QCOMPARE(object->property("test8"), QVariant((int)6));
2551 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2552 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2553 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2554 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2559 void tst_qdeclarativeecmascript::propertySplicing()
2561 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2563 QObject *object = component.create();
2564 QVERIFY(object != 0);
2566 QCOMPARE(object->property("test").toBool(), true);
2572 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2574 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2576 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2577 QVERIFY(object != 0);
2579 MyQmlObject::MyType type;
2580 type.value = 0x8971123;
2581 emit object->signalWithUnknownType(type);
2583 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2585 QCOMPARE(result.value, type.value);
2591 void tst_qdeclarativeecmascript::moduleApi()
2593 QDeclarativeComponent component(&engine, TEST_FILE("moduleApi.qml"));
2594 QObject *object = component.create();
2595 QVERIFY(object != 0);
2596 QCOMPARE(object->property("existingUriTest").toInt(), 20);
2598 QEXPECT_FAIL("", "QTBUG-17318", Continue);
2599 QCOMPARE(object->property("scriptTest").toInt(), 13);
2600 QCOMPARE(object->property("qobjectTest").toInt(), 20);
2601 QCOMPARE(object->property("qobjectMethodTest").toInt(), 1); // first call of method, so count = 1.
2602 QCOMPARE(object->property("qobjectMinorVersionTest").toInt(), 20);
2603 QCOMPARE(object->property("qobjectMajorVersionTest").toInt(), 20);
2604 QCOMPARE(object->property("qobjectParentedTest").toInt(), 26);
2607 // test that caching of module apis works correctly.
2608 QDeclarativeComponent componentTwo(&engine, TEST_FILE("moduleApiCaching.qml"));
2609 object = componentTwo.create();
2610 QVERIFY(object != 0);
2611 QCOMPARE(object->property("existingUriTest").toInt(), 20);
2612 QEXPECT_FAIL("", "QTBUG-17318", Continue);
2613 QCOMPARE(object->property("scriptTest").toInt(), 13); // shouldn't have incremented.
2614 QCOMPARE(object->property("qobjectParentedTest").toInt(), 26); // shouldn't have incremented.
2617 // test that writing to a property of module apis works correctly.
2618 QDeclarativeComponent componentThree(&engine, TEST_FILE("moduleApiWriting.qml"));
2619 QString expectedWarning = QLatin1String("file://") + TEST_FILE("moduleApiWriting.qml").toLocalFile() + QLatin1String(":15: Error: Cannot assign to read-only property \"qobjectTestProperty\"");
2620 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2621 object = componentThree.create();
2622 QVERIFY(object != 0);
2623 QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
2624 QCOMPARE(object->property("writableProperty").toInt(), 50);
2625 QVERIFY(object->setProperty("firstProperty", QVariant(30))); // shouldn't affect value of readOnlyProperty
2626 QVERIFY(object->setProperty("writableProperty", QVariant(30))); // SHOULD affect value of writableProperty
2627 QCOMPARE(object->property("readOnlyProperty").toInt(), 20);
2628 QCOMPARE(object->property("writableProperty").toInt(), 30);
2631 QDeclarativeComponent failOne(&engine, TEST_FILE("moduleApiMajorVersionFail.qml"));
2632 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2633 object = failOne.create();
2634 QVERIFY(object == 0); // should have failed: invalid major version
2636 QDeclarativeComponent failTwo(&engine, TEST_FILE("moduleApiMinorVersionFail.qml"));
2637 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2638 object = failTwo.create();
2639 QVERIFY(object == 0); // should have failed: invalid minor version
2642 void tst_qdeclarativeecmascript::importScripts()
2644 QObject *object = 0;
2646 // first, ensure that the required behaviour works.
2647 QDeclarativeComponent component(&engine, TEST_FILE("jsimport/testImport.qml"));
2648 object = component.create();
2649 QVERIFY(object != 0);
2650 QCOMPARE(object->property("importedScriptStringValue"), QVariant(QString(QLatin1String("Hello, World!"))));
2651 QCOMPARE(object->property("importedScriptFunctionValue"), QVariant(20));
2652 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(19));
2653 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(2));
2656 QDeclarativeComponent componentTwo(&engine, TEST_FILE("jsimport/testImportScoping.qml"));
2657 object = componentTwo.create();
2658 QVERIFY(object != 0);
2659 QCOMPARE(object->property("componentError"), QVariant(5));
2662 // then, ensure that unintended behaviour does not work.
2663 QDeclarativeComponent failOneComponent(&engine, TEST_FILE("jsimportfail/failOne.qml"));
2664 QString expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined");
2665 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2666 object = failOneComponent.create();
2667 QVERIFY(object != 0);
2668 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2670 QDeclarativeComponent failTwoComponent(&engine, TEST_FILE("jsimportfail/failTwo.qml"));
2671 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs");
2672 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2673 object = failTwoComponent.create();
2674 QVERIFY(object != 0);
2675 QVERIFY(object->property("importScriptFunctionValue").toString().isEmpty());
2677 QDeclarativeComponent failThreeComponent(&engine, TEST_FILE("jsimportfail/failThree.qml"));
2678 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined");
2679 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2680 object = failThreeComponent.create();
2681 QVERIFY(object != 0);
2682 QCOMPARE(object->property("importedModuleAttachedPropertyValue"), QVariant(false));
2684 QDeclarativeComponent failFourComponent(&engine, TEST_FILE("jsimportfail/failFour.qml"));
2685 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest");
2686 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2687 object = failFourComponent.create();
2688 QVERIFY(object != 0);
2689 QCOMPARE(object->property("importedModuleEnumValue"), QVariant(0));
2691 QDeclarativeComponent failFiveComponent(&engine, TEST_FILE("jsimportfail/failFive.qml"));
2692 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component");
2693 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2694 expectedWarning = QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component");
2695 QTest::ignoreMessage(QtWarningMsg, expectedWarning.toAscii().constData());
2696 object = failFiveComponent.create();
2697 QVERIFY(object != 0);
2698 QCOMPARE(object->property("componentError"), QVariant(0));
2701 // also, test that importing scripts with .pragma library works as required
2702 QDeclarativeComponent pragmaLibraryComponent(&engine, TEST_FILE("jsimport/testImportPragmaLibrary.qml"));
2703 object = pragmaLibraryComponent.create();
2704 QVERIFY(object != 0);
2705 QCOMPARE(object->property("testValue"), QVariant(31));
2708 // and that .pragma library scripts don't inherit imports from any .qml file
2709 QDeclarativeComponent pragmaLibraryComponentTwo(&engine, TEST_FILE("jsimportfail/testImportPragmaLibrary.qml"));
2710 object = pragmaLibraryComponentTwo.create();
2711 QVERIFY(object != 0);
2712 QCOMPARE(object->property("testValue"), QVariant(0));
2716 void tst_qdeclarativeecmascript::scarceResources()
2718 QPixmap origPixmap(100, 100);
2719 origPixmap.fill(Qt::blue);
2721 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
2722 ScarceResourceObject *eo = 0;
2723 QObject *object = 0;
2725 // in the following three cases, the instance created from the component
2726 // has a property which is a copy of the scarce resource; hence, the
2727 // resource should NOT be detached prior to deletion of the object instance,
2728 // unless the resource is destroyed explicitly.
2729 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
2730 object = component.create();
2731 QVERIFY(object != 0);
2732 QVERIFY(object->property("scarceResourceCopy").isValid());
2733 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2734 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2735 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2736 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
2739 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
2740 object = componentTwo.create();
2741 QVERIFY(object != 0);
2742 QVERIFY(object->property("scarceResourceCopy").isValid());
2743 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
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()); // there are two copies of it in existence: the property of object, and the property of eo.
2749 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
2750 object = componentThree.create();
2751 QVERIFY(object != 0);
2752 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
2753 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2754 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2755 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
2758 // in the following three cases, no other copy should exist in memory,
2759 // and so it should be detached (unless explicitly preserved).
2760 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
2761 object = componentFour.create();
2762 QVERIFY(object != 0);
2763 QVERIFY(object->property("scarceResourceTest").isValid());
2764 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2765 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2766 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2767 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
2770 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
2771 object = componentFive.create();
2772 QVERIFY(object != 0);
2773 QVERIFY(object->property("scarceResourceTest").isValid());
2774 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2775 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2776 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2777 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
2780 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
2781 object = componentSix.create();
2782 QVERIFY(object != 0);
2783 QVERIFY(object->property("scarceResourceTest").isValid());
2784 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
2785 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2786 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2787 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
2790 // test that scarce resources are handled correctly for imports
2791 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
2792 object = componentSeven.create();
2793 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
2794 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
2797 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
2798 object = componentEight.create();
2799 QVERIFY(object != 0);
2800 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
2801 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2804 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
2805 object = componentNine.create();
2806 QVERIFY(object != 0);
2807 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
2808 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2809 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
2810 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
2811 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
2812 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
2815 // test that scarce resources are handled properly in signal invocation
2816 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
2817 object = componentTen.create();
2818 QVERIFY(object != 0);
2819 QObject *srsc = object->findChild<QObject*>("srsc");
2821 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
2822 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
2823 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2824 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2825 QMetaObject::invokeMethod(srsc, "testSignal");
2826 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
2827 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
2828 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2829 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
2830 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
2831 QVERIFY(srsc->property("scarceResourceCopy").isValid());
2832 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2833 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2834 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
2835 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2838 // test that scarce resources are handled properly from js functions in qml files
2839 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
2840 object = componentEleven.create();
2841 QVERIFY(object != 0);
2842 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
2843 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2844 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2845 QMetaObject::invokeMethod(object, "retrieveScarceResource");
2846 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
2847 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
2848 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2849 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
2850 QMetaObject::invokeMethod(object, "releaseScarceResource");
2851 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
2852 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2853 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2854 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2857 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
2858 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
2859 object = componentTwelve.create();
2860 QVERIFY(object != 0);
2861 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
2862 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2863 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2864 QString srp_name = object->property("srp_name").toString();
2865 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
2866 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
2867 QMetaObject::invokeMethod(object, "retrieveScarceResource");
2868 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
2869 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
2870 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
2871 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
2875 void tst_qdeclarativeecmascript::propertyChangeSlots()
2877 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
2878 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
2879 QObject *object = component.create();
2880 QVERIFY(object != 0);
2883 // ensure that invalid property names fail properly.
2884 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2885 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
2886 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
2887 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
2888 object = e1.create();
2889 QVERIFY(object == 0);
2892 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2893 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
2894 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
2895 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
2896 object = e2.create();
2897 QVERIFY(object == 0);
2900 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2901 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
2902 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
2903 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
2904 object = e3.create();
2905 QVERIFY(object == 0);
2908 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
2909 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
2910 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
2911 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
2912 object = e4.create();
2913 QVERIFY(object == 0);
2917 // Ensure that QObject type conversion works on binding assignment
2918 void tst_qdeclarativeecmascript::elementAssign()
2920 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
2922 QObject *object = component.create();
2923 QVERIFY(object != 0);
2925 QCOMPARE(object->property("test").toBool(), true);
2931 void tst_qdeclarativeecmascript::objectPassThroughSignals()
2933 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
2935 QObject *object = component.create();
2936 QVERIFY(object != 0);
2938 QCOMPARE(object->property("test").toBool(), true);
2944 void tst_qdeclarativeecmascript::booleanConversion()
2946 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
2948 QObject *object = component.create();
2949 QVERIFY(object != 0);
2951 QCOMPARE(object->property("test_true1").toBool(), true);
2952 QCOMPARE(object->property("test_true2").toBool(), true);
2953 QCOMPARE(object->property("test_true3").toBool(), true);
2954 QCOMPARE(object->property("test_true4").toBool(), true);
2955 QCOMPARE(object->property("test_true5").toBool(), true);
2957 QCOMPARE(object->property("test_false1").toBool(), false);
2958 QCOMPARE(object->property("test_false2").toBool(), false);
2959 QCOMPARE(object->property("test_false3").toBool(), false);
2964 // Test that assigning a null object works
2965 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
2966 void tst_qdeclarativeecmascript::nullObjectBinding()
2968 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
2970 QObject *object = component.create();
2971 QVERIFY(object != 0);
2973 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
2978 // Test that bindings don't evaluate once the engine has been destroyed
2979 void tst_qdeclarativeecmascript::deletedEngine()
2981 QDeclarativeEngine *engine = new QDeclarativeEngine;
2982 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
2984 QObject *object = component.create();
2985 QVERIFY(object != 0);
2987 QCOMPARE(object->property("a").toInt(), 39);
2988 object->setProperty("b", QVariant(9));
2989 QCOMPARE(object->property("a").toInt(), 117);
2993 QCOMPARE(object->property("a").toInt(), 117);
2994 object->setProperty("b", QVariant(10));
2995 QCOMPARE(object->property("a").toInt(), 117);
3000 // Test the crashing part of QTBUG-9705
3001 void tst_qdeclarativeecmascript::libraryScriptAssert()
3003 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
3005 QObject *object = component.create();
3006 QVERIFY(object != 0);
3011 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
3013 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
3015 QObject *object = component.create();
3016 QVERIFY(object != 0);
3018 QCOMPARE(object->property("test1").toInt(), 10);
3019 QCOMPARE(object->property("test2").toInt(), 11);
3021 object->setProperty("runTest", true);
3023 QCOMPARE(object->property("test1"), QVariant());
3024 QCOMPARE(object->property("test2"), QVariant());
3030 void tst_qdeclarativeecmascript::qtbug_9792()
3032 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
3034 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
3036 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
3037 QVERIFY(object != 0);
3039 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
3040 object->basicSignal();
3044 transientErrorsMsgCount = 0;
3045 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3047 object->basicSignal();
3049 qInstallMsgHandler(old);
3051 QCOMPARE(transientErrorsMsgCount, 0);
3056 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
3057 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
3059 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
3061 QObject *o = component.create();
3064 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
3065 QVERIFY(nested != 0);
3067 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
3070 nested = qvariant_cast<QObject *>(o->property("object"));
3071 QVERIFY(nested == 0);
3073 // If the bug is present, the next line will crash
3077 // Test that we shut down without stupid warnings
3078 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
3081 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
3083 QObject *o = component.create();
3085 transientErrorsMsgCount = 0;
3086 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3090 qInstallMsgHandler(old);
3092 QCOMPARE(transientErrorsMsgCount, 0);
3097 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
3099 QObject *o = component.create();
3101 transientErrorsMsgCount = 0;
3102 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
3106 qInstallMsgHandler(old);
3108 QCOMPARE(transientErrorsMsgCount, 0);
3112 void tst_qdeclarativeecmascript::canAssignNullToQObject()
3115 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
3117 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3120 QVERIFY(o->objectProperty() != 0);
3122 o->setProperty("runTest", true);
3124 QVERIFY(o->objectProperty() == 0);
3130 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
3132 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3135 QVERIFY(o->objectProperty() == 0);
3141 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
3143 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
3145 QString url = component.url().toString();
3146 QString warning = url + ":4: Unable to assign a function to a property.";
3147 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3149 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3152 QVERIFY(!o->property("a").isValid());
3157 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
3159 QFETCH(QString, triggerProperty);
3161 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3162 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3164 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3166 QVERIFY(!o->property("a").isValid());
3168 o->setProperty("aNumber", QVariant(5));
3169 o->setProperty(triggerProperty.toUtf8().constData(), true);
3170 QCOMPARE(o->property("a"), QVariant(50));
3172 o->setProperty("aNumber", QVariant(10));
3173 QCOMPARE(o->property("a"), QVariant(100));
3178 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
3180 QTest::addColumn<QString>("triggerProperty");
3182 QTest::newRow("assign to property") << "assignToProperty";
3183 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
3185 QTest::newRow("assign to value type") << "assignToValueType";
3187 QTest::newRow("use 'this'") << "assignWithThis";
3188 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
3191 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
3193 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
3194 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
3196 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
3198 QVERIFY(!o->property("a").isValid());
3200 o->setProperty("assignFuncWithoutReturn", true);
3201 QVERIFY(!o->property("a").isValid());
3203 QString url = component.url().toString();
3204 QString warning = url + ":67: Unable to assign QString to int";
3205 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3206 o->setProperty("assignWrongType", true);
3208 warning = url + ":71: Unable to assign QString to int";
3209 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
3210 o->setProperty("assignWrongTypeToValueType", true);
3215 void tst_qdeclarativeecmascript::eval()
3217 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
3219 QObject *o = component.create();
3222 QCOMPARE(o->property("test1").toBool(), true);
3223 QCOMPARE(o->property("test2").toBool(), true);
3224 QCOMPARE(o->property("test3").toBool(), true);
3225 QCOMPARE(o->property("test4").toBool(), true);
3226 QCOMPARE(o->property("test5").toBool(), true);
3231 void tst_qdeclarativeecmascript::function()
3233 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
3235 QObject *o = component.create();
3238 QCOMPARE(o->property("test1").toBool(), true);
3239 QCOMPARE(o->property("test2").toBool(), true);
3240 QCOMPARE(o->property("test3").toBool(), true);
3245 // Test the "Qt.include" method
3246 void tst_qdeclarativeecmascript::include()
3248 // Non-library relative include
3250 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
3251 QObject *o = component.create();
3254 QCOMPARE(o->property("test0").toInt(), 99);
3255 QCOMPARE(o->property("test1").toBool(), true);
3256 QCOMPARE(o->property("test2").toBool(), true);
3257 QCOMPARE(o->property("test2_1").toBool(), true);
3258 QCOMPARE(o->property("test3").toBool(), true);
3259 QCOMPARE(o->property("test3_1").toBool(), true);
3264 // Library relative include
3266 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
3267 QObject *o = component.create();
3270 QCOMPARE(o->property("test0").toInt(), 99);
3271 QCOMPARE(o->property("test1").toBool(), true);
3272 QCOMPARE(o->property("test2").toBool(), true);
3273 QCOMPARE(o->property("test2_1").toBool(), true);
3274 QCOMPARE(o->property("test3").toBool(), true);
3275 QCOMPARE(o->property("test3_1").toBool(), true);
3282 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
3283 QObject *o = component.create();
3286 QCOMPARE(o->property("test1").toBool(), true);
3287 QCOMPARE(o->property("test2").toBool(), true);
3288 QCOMPARE(o->property("test3").toBool(), true);
3289 QCOMPARE(o->property("test4").toBool(), true);
3290 QCOMPARE(o->property("test5").toBool(), true);
3291 QCOMPARE(o->property("test6").toBool(), true);
3296 // Including file with ".pragma library"
3298 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
3299 QObject *o = component.create();
3301 QCOMPARE(o->property("test1").toInt(), 100);
3308 TestHTTPServer server(8111);
3309 QVERIFY(server.isValid());
3310 server.serveDirectory(SRCDIR "/data");
3312 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
3313 QObject *o = component.create();
3316 QTRY_VERIFY(o->property("done").toBool() == true);
3317 QTRY_VERIFY(o->property("done2").toBool() == true);
3319 QCOMPARE(o->property("test1").toBool(), true);
3320 QCOMPARE(o->property("test2").toBool(), true);
3321 QCOMPARE(o->property("test3").toBool(), true);
3322 QCOMPARE(o->property("test4").toBool(), true);
3323 QCOMPARE(o->property("test5").toBool(), true);
3325 QCOMPARE(o->property("test6").toBool(), true);
3326 QCOMPARE(o->property("test7").toBool(), true);
3327 QCOMPARE(o->property("test8").toBool(), true);
3328 QCOMPARE(o->property("test9").toBool(), true);
3329 QCOMPARE(o->property("test10").toBool(), true);
3336 TestHTTPServer server(8111);
3337 QVERIFY(server.isValid());
3338 server.serveDirectory(SRCDIR "/data");
3340 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
3341 QObject *o = component.create();
3344 QTRY_VERIFY(o->property("done").toBool() == true);
3346 QCOMPARE(o->property("test1").toBool(), true);
3347 QCOMPARE(o->property("test2").toBool(), true);
3348 QCOMPARE(o->property("test3").toBool(), true);
3354 void tst_qdeclarativeecmascript::qtbug_10696()
3356 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
3357 QObject *o = component.create();
3362 void tst_qdeclarativeecmascript::qtbug_11606()
3364 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
3365 QObject *o = component.create();
3367 QCOMPARE(o->property("test").toBool(), true);
3371 void tst_qdeclarativeecmascript::qtbug_11600()
3373 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
3374 QObject *o = component.create();
3376 QCOMPARE(o->property("test").toBool(), true);
3380 // Reading and writing non-scriptable properties should fail
3381 void tst_qdeclarativeecmascript::nonscriptable()
3383 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
3384 QObject *o = component.create();
3386 QCOMPARE(o->property("readOk").toBool(), true);
3387 QCOMPARE(o->property("writeOk").toBool(), true);
3391 // deleteLater() should not be callable from QML
3392 void tst_qdeclarativeecmascript::deleteLater()
3394 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
3395 QObject *o = component.create();
3397 QCOMPARE(o->property("test").toBool(), true);
3401 void tst_qdeclarativeecmascript::in()
3403 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
3404 QObject *o = component.create();
3406 QCOMPARE(o->property("test1").toBool(), true);
3407 QCOMPARE(o->property("test2").toBool(), true);
3411 void tst_qdeclarativeecmascript::sharedAttachedObject()
3413 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
3414 QObject *o = component.create();
3416 QCOMPARE(o->property("test1").toBool(), true);
3417 QCOMPARE(o->property("test2").toBool(), true);
3422 void tst_qdeclarativeecmascript::objectName()
3424 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
3425 QObject *o = component.create();
3428 QCOMPARE(o->property("test1").toString(), QString("hello"));
3429 QCOMPARE(o->property("test2").toString(), QString("ell"));
3431 o->setObjectName("world");
3433 QCOMPARE(o->property("test1").toString(), QString("world"));
3434 QCOMPARE(o->property("test2").toString(), QString("orl"));
3439 void tst_qdeclarativeecmascript::writeRemovesBinding()
3441 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
3442 QObject *o = component.create();
3445 QCOMPARE(o->property("test").toBool(), true);
3450 // Test bindings assigned to alias properties actually assign to the alias' target
3451 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
3453 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
3454 QObject *o = component.create();
3457 QCOMPARE(o->property("test").toBool(), true);
3462 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
3463 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
3466 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
3467 QObject *o = component.create();
3470 QCOMPARE(o->property("test").toBool(), true);
3476 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
3477 QObject *o = component.create();
3480 QCOMPARE(o->property("test").toBool(), true);
3486 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
3487 QObject *o = component.create();
3490 QCOMPARE(o->property("test").toBool(), true);
3496 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
3497 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
3500 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
3501 QObject *o = component.create();
3504 QCOMPARE(o->property("test").toBool(), true);
3510 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
3511 QObject *o = component.create();
3514 QCOMPARE(o->property("test").toBool(), true);
3520 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
3521 QObject *o = component.create();
3524 QCOMPARE(o->property("test").toBool(), true);
3530 // Allow an alais to a composite element
3532 void tst_qdeclarativeecmascript::aliasToCompositeElement()
3534 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
3536 QObject *object = component.create();
3537 QVERIFY(object != 0);
3542 void tst_qdeclarativeecmascript::revisionErrors()
3545 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
3546 QString url = component.url().toString();
3548 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
3549 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
3550 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
3552 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3553 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3554 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3555 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3556 QVERIFY(object != 0);
3560 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
3561 QString url = component.url().toString();
3563 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
3564 // method2, prop2 from MyRevisionedClass not available
3565 // method4, prop4 from MyRevisionedSubclass not available
3566 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
3567 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
3568 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
3569 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
3570 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
3572 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3573 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3574 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3575 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
3576 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
3577 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3578 QVERIFY(object != 0);
3582 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
3583 QString url = component.url().toString();
3585 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
3586 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
3587 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
3588 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
3589 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
3590 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
3591 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
3592 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
3593 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3594 QVERIFY(object != 0);
3599 void tst_qdeclarativeecmascript::revision()
3602 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
3603 QString url = component.url().toString();
3605 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3606 QVERIFY(object != 0);
3610 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
3611 QString url = component.url().toString();
3613 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3614 QVERIFY(object != 0);
3618 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
3619 QString url = component.url().toString();
3621 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
3622 QVERIFY(object != 0);
3625 // Test that non-root classes can resolve revisioned methods
3627 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
3629 QObject *object = component.create();
3630 QVERIFY(object != 0);
3631 QCOMPARE(object->property("test").toReal(), 11.);
3636 void tst_qdeclarativeecmascript::realToInt()
3638 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
3639 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
3640 QVERIFY(object != 0);
3642 QMetaObject::invokeMethod(object, "test1");
3643 QCOMPARE(object->value(), int(4));
3644 QMetaObject::invokeMethod(object, "test2");
3645 QCOMPARE(object->value(), int(8));
3648 QTEST_MAIN(tst_qdeclarativeecmascript)
3650 #include "tst_qdeclarativeecmascript.moc"