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 ****************************************************************************/
41 #include <QtTest/QtTest>
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/qv8gccallback_p.h>
53 #include <private/qdeclarativevmemetaobject_p.h>
54 #include <private/qv4compiler_p.h>
55 #include "testtypes.h"
56 #include "testhttpserver.h"
57 #include "../shared/util.h"
60 This test covers evaluation of ECMAScript expressions and bindings from within
61 QML. This does not include static QML language issues.
63 Static QML language issues are covered in qmllanguage
65 inline QUrl TEST_FILE(const QString &filename)
67 return QUrl::fromLocalFile(TESTDATA(filename));
70 inline QUrl TEST_FILE(const char *filename)
72 return TEST_FILE(QLatin1String(filename));
75 class tst_qdeclarativeecmascript : public QObject
79 tst_qdeclarativeecmascript() {}
83 void assignBasicTypes();
84 void idShortcutInvalidates();
85 void boolPropertiesEvaluateAsBool();
87 void signalAssignment();
89 void basicExpressions();
90 void basicExpressions_data();
91 void arrayExpressions();
92 void contextPropertiesTriggerReeval();
93 void objectPropertiesTriggerReeval();
94 void deferredProperties();
95 void deferredPropertiesErrors();
96 void extensionObjects();
97 void overrideExtensionProperties();
98 void attachedProperties();
100 void valueTypeFunctions();
101 void constantsOverrideBindings();
102 void outerBindingOverridesInnerBinding();
103 void aliasPropertyAndBinding();
104 void aliasPropertyReset();
105 void nonExistentAttachedObject();
108 void signalParameterTypes();
109 void objectsCompareAsEqual();
110 void dynamicCreation_data();
111 void dynamicCreation();
112 void dynamicDestruction();
113 void objectToString();
114 void objectHasOwnProperty();
115 void selfDeletingBinding();
116 void extendedObjectPropertyLookup();
118 void functionErrors();
119 void propertyAssignmentErrors();
120 void signalTriggeredBindings();
121 void listProperties();
122 void exceptionClearsOnReeval();
123 void exceptionSlotProducesWarning();
124 void exceptionBindingProducesWarning();
125 void transientErrors();
126 void shutdownErrors();
127 void compositePropertyType();
129 void undefinedResetsProperty();
130 void listToVariant();
131 void listAssignment();
132 void multiEngineObject();
133 void deletedObject();
134 void attachedPropertyScope();
135 void scriptConnect();
136 void scriptDisconnect();
138 void cppOwnershipReturnValue();
139 void ownershipCustomReturnValue();
140 void qlistqobjectMethods();
141 void strictlyEquals();
143 void numberAssignment();
144 void propertySplicing();
145 void signalWithUnknownTypes();
146 void signalWithJSValueInVariant_data();
147 void signalWithJSValueInVariant();
148 void signalWithJSValueInVariant_twoEngines_data();
149 void signalWithJSValueInVariant_twoEngines();
150 void moduleApi_data();
152 void importScripts_data();
153 void importScripts();
154 void scarceResources();
155 void propertyChangeSlots();
156 void propertyVar_data();
158 void propertyVarCpp();
159 void propertyVarOwnership();
160 void propertyVarImplicitOwnership();
161 void propertyVarReparent();
162 void propertyVarReparentNullContext();
163 void propertyVarCircular();
164 void propertyVarCircular2();
165 void propertyVarInheritance();
166 void propertyVarInheritance2();
167 void elementAssign();
168 void objectPassThroughSignals();
169 void objectConversion();
170 void booleanConversion();
171 void handleReferenceManagement();
173 void readonlyDeclaration();
174 void sequenceConversionRead();
175 void sequenceConversionWrite();
176 void sequenceConversionArray();
177 void sequenceConversionThreads();
178 void sequenceConversionBindings();
179 void sequenceConversionCopy();
183 void dynamicCreationCrash();
184 void dynamicCreationOwnership();
186 void nullObjectBinding();
187 void deletedEngine();
188 void libraryScriptAssert();
189 void variantsAssignedUndefined();
191 void qtcreatorbug_1289();
192 void noSpuriousWarningsAtShutdown();
193 void canAssignNullToQObject();
194 void functionAssignment_fromBinding();
195 void functionAssignment_fromJS();
196 void functionAssignment_fromJS_data();
197 void functionAssignmentfromJS_invalid();
203 void nonscriptable();
207 void sharedAttachedObject();
209 void writeRemovesBinding();
210 void aliasBindingsAssignCorrectly();
211 void aliasBindingsOverrideTarget();
212 void aliasWritesOverrideBindings();
213 void aliasToCompositeElement();
215 void dynamicString();
217 void signalHandlers();
218 void doubleEvaluate();
220 void nonNotifyable();
221 void deleteWhileBindingRunning();
222 void callQtInvokables();
223 void invokableObjectArg();
224 void invokableObjectRet();
227 void revisionErrors();
230 void automaticSemicolon();
231 void unaryExpression();
234 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
235 QDeclarativeEngine engine;
238 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
240 void tst_qdeclarativeecmascript::assignBasicTypes()
243 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
244 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
245 QVERIFY(object != 0);
246 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
247 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
248 QCOMPARE(object->stringProperty(), QString("Hello World!"));
249 QCOMPARE(object->uintProperty(), uint(10));
250 QCOMPARE(object->intProperty(), -19);
251 QCOMPARE((float)object->realProperty(), float(23.2));
252 QCOMPARE((float)object->doubleProperty(), float(-19.75));
253 QCOMPARE((float)object->floatProperty(), float(8.5));
254 QCOMPARE(object->colorProperty(), QColor("red"));
255 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
256 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
257 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
258 QCOMPARE(object->pointProperty(), QPoint(99,13));
259 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
260 QCOMPARE(object->sizeProperty(), QSize(99, 13));
261 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
262 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
263 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
264 QCOMPARE(object->boolProperty(), true);
265 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
266 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
267 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
271 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
272 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
273 QVERIFY(object != 0);
274 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
275 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
276 QCOMPARE(object->stringProperty(), QString("Hello World!"));
277 QCOMPARE(object->uintProperty(), uint(10));
278 QCOMPARE(object->intProperty(), -19);
279 QCOMPARE((float)object->realProperty(), float(23.2));
280 QCOMPARE((float)object->doubleProperty(), float(-19.75));
281 QCOMPARE((float)object->floatProperty(), float(8.5));
282 QCOMPARE(object->colorProperty(), QColor("red"));
283 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
284 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
285 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
286 QCOMPARE(object->pointProperty(), QPoint(99,13));
287 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
288 QCOMPARE(object->sizeProperty(), QSize(99, 13));
289 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
290 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
291 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
292 QCOMPARE(object->boolProperty(), true);
293 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
294 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
295 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
300 void tst_qdeclarativeecmascript::idShortcutInvalidates()
303 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
304 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
305 QVERIFY(object != 0);
306 QVERIFY(object->objectProperty() != 0);
307 delete object->objectProperty();
308 QVERIFY(object->objectProperty() == 0);
313 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
314 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
315 QVERIFY(object != 0);
316 QVERIFY(object->objectProperty() != 0);
317 delete object->objectProperty();
318 QVERIFY(object->objectProperty() == 0);
323 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
326 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
327 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
328 QVERIFY(object != 0);
329 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
333 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
334 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
335 QVERIFY(object != 0);
336 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
341 void tst_qdeclarativeecmascript::signalAssignment()
344 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
345 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
346 QVERIFY(object != 0);
347 QCOMPARE(object->string(), QString());
348 emit object->basicSignal();
349 QCOMPARE(object->string(), QString("pass"));
354 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
355 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
356 QVERIFY(object != 0);
357 QCOMPARE(object->string(), QString());
358 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
359 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
364 void tst_qdeclarativeecmascript::methods()
367 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
368 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
369 QVERIFY(object != 0);
370 QCOMPARE(object->methodCalled(), false);
371 QCOMPARE(object->methodIntCalled(), false);
372 emit object->basicSignal();
373 QCOMPARE(object->methodCalled(), true);
374 QCOMPARE(object->methodIntCalled(), false);
379 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
380 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
381 QVERIFY(object != 0);
382 QCOMPARE(object->methodCalled(), false);
383 QCOMPARE(object->methodIntCalled(), false);
384 emit object->basicSignal();
385 QCOMPARE(object->methodCalled(), false);
386 QCOMPARE(object->methodIntCalled(), true);
391 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
392 QObject *object = component.create();
393 QVERIFY(object != 0);
394 QCOMPARE(object->property("test").toInt(), 19);
399 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
400 QObject *object = component.create();
401 QVERIFY(object != 0);
402 QCOMPARE(object->property("test").toInt(), 19);
403 QCOMPARE(object->property("test2").toInt(), 17);
404 QCOMPARE(object->property("test3").toInt(), 16);
409 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
410 QObject *object = component.create();
411 QVERIFY(object != 0);
412 QCOMPARE(object->property("test").toInt(), 9);
417 void tst_qdeclarativeecmascript::bindingLoop()
419 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
420 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
421 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
422 QObject *object = component.create();
423 QVERIFY(object != 0);
427 void tst_qdeclarativeecmascript::basicExpressions_data()
429 QTest::addColumn<QString>("expression");
430 QTest::addColumn<QVariant>("result");
431 QTest::addColumn<bool>("nest");
433 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
434 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
435 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
436 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
437 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
438 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
439 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
440 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
441 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
442 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
443 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
444 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
445 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
446 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
447 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
448 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
449 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
450 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
451 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
454 void tst_qdeclarativeecmascript::basicExpressions()
456 QFETCH(QString, expression);
457 QFETCH(QVariant, result);
463 MyDefaultObject1 default1;
464 MyDefaultObject3 default3;
465 object1.setStringProperty("Object1");
466 object2.setStringProperty("Object2");
467 object3.setStringProperty("Object3");
469 QDeclarativeContext context(engine.rootContext());
470 QDeclarativeContext nestedContext(&context);
472 context.setContextObject(&default1);
473 context.setContextProperty("a", QVariant(1944));
474 context.setContextProperty("b", QVariant("Milk"));
475 context.setContextProperty("object", &object1);
476 context.setContextProperty("objectOverride", &object2);
477 nestedContext.setContextObject(&default3);
478 nestedContext.setContextProperty("b", QVariant("Cow"));
479 nestedContext.setContextProperty("objectOverride", &object3);
480 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
482 MyExpression expr(nest?&nestedContext:&context, expression);
483 QCOMPARE(expr.evaluate(), result);
486 void tst_qdeclarativeecmascript::arrayExpressions()
492 QDeclarativeContext context(engine.rootContext());
493 context.setContextProperty("a", &obj1);
494 context.setContextProperty("b", &obj2);
495 context.setContextProperty("c", &obj3);
497 MyExpression expr(&context, "[a, b, c, 10]");
498 QVariant result = expr.evaluate();
499 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
500 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
501 QCOMPARE(list.count(), 4);
502 QCOMPARE(list.at(0), &obj1);
503 QCOMPARE(list.at(1), &obj2);
504 QCOMPARE(list.at(2), &obj3);
505 QCOMPARE(list.at(3), (QObject *)0);
508 // Tests that modifying a context property will reevaluate expressions
509 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
511 QDeclarativeContext context(engine.rootContext());
514 MyQmlObject *object3 = new MyQmlObject;
516 object1.setStringProperty("Hello");
517 object2.setStringProperty("World");
519 context.setContextProperty("testProp", QVariant(1));
520 context.setContextProperty("testObj", &object1);
521 context.setContextProperty("testObj2", object3);
524 MyExpression expr(&context, "testProp + 1");
525 QCOMPARE(expr.changed, false);
526 QCOMPARE(expr.evaluate(), QVariant(2));
528 context.setContextProperty("testProp", QVariant(2));
529 QCOMPARE(expr.changed, true);
530 QCOMPARE(expr.evaluate(), QVariant(3));
534 MyExpression expr(&context, "testProp + testProp + testProp");
535 QCOMPARE(expr.changed, false);
536 QCOMPARE(expr.evaluate(), QVariant(6));
538 context.setContextProperty("testProp", QVariant(4));
539 QCOMPARE(expr.changed, true);
540 QCOMPARE(expr.evaluate(), QVariant(12));
544 MyExpression expr(&context, "testObj.stringProperty");
545 QCOMPARE(expr.changed, false);
546 QCOMPARE(expr.evaluate(), QVariant("Hello"));
548 context.setContextProperty("testObj", &object2);
549 QCOMPARE(expr.changed, true);
550 QCOMPARE(expr.evaluate(), QVariant("World"));
554 MyExpression expr(&context, "testObj.stringProperty /**/");
555 QCOMPARE(expr.changed, false);
556 QCOMPARE(expr.evaluate(), QVariant("World"));
558 context.setContextProperty("testObj", &object1);
559 QCOMPARE(expr.changed, true);
560 QCOMPARE(expr.evaluate(), QVariant("Hello"));
564 MyExpression expr(&context, "testObj2");
565 QCOMPARE(expr.changed, false);
566 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
572 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
574 QDeclarativeContext context(engine.rootContext());
578 context.setContextProperty("testObj", &object1);
580 object1.setStringProperty(QLatin1String("Hello"));
581 object2.setStringProperty(QLatin1String("Dog"));
582 object3.setStringProperty(QLatin1String("Cat"));
585 MyExpression expr(&context, "testObj.stringProperty");
586 QCOMPARE(expr.changed, false);
587 QCOMPARE(expr.evaluate(), QVariant("Hello"));
589 object1.setStringProperty(QLatin1String("World"));
590 QCOMPARE(expr.changed, true);
591 QCOMPARE(expr.evaluate(), QVariant("World"));
595 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
596 QCOMPARE(expr.changed, false);
597 QCOMPARE(expr.evaluate(), QVariant());
599 object1.setObjectProperty(&object2);
600 QCOMPARE(expr.changed, true);
601 expr.changed = false;
602 QCOMPARE(expr.evaluate(), QVariant("Dog"));
604 object1.setObjectProperty(&object3);
605 QCOMPARE(expr.changed, true);
606 expr.changed = false;
607 QCOMPARE(expr.evaluate(), QVariant("Cat"));
609 object1.setObjectProperty(0);
610 QCOMPARE(expr.changed, true);
611 expr.changed = false;
612 QCOMPARE(expr.evaluate(), QVariant());
614 object1.setObjectProperty(&object3);
615 QCOMPARE(expr.changed, true);
616 expr.changed = false;
617 QCOMPARE(expr.evaluate(), QVariant("Cat"));
619 object3.setStringProperty("Donkey");
620 QCOMPARE(expr.changed, true);
621 expr.changed = false;
622 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
626 void tst_qdeclarativeecmascript::deferredProperties()
628 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
629 MyDeferredObject *object =
630 qobject_cast<MyDeferredObject *>(component.create());
631 QVERIFY(object != 0);
632 QCOMPARE(object->value(), 0);
633 QVERIFY(object->objectProperty() == 0);
634 QVERIFY(object->objectProperty2() != 0);
635 qmlExecuteDeferred(object);
636 QCOMPARE(object->value(), 10);
637 QVERIFY(object->objectProperty() != 0);
638 MyQmlObject *qmlObject =
639 qobject_cast<MyQmlObject *>(object->objectProperty());
640 QVERIFY(qmlObject != 0);
641 QCOMPARE(qmlObject->value(), 10);
642 object->setValue(19);
643 QCOMPARE(qmlObject->value(), 19);
648 // Check errors on deferred properties are correctly emitted
649 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
651 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
652 MyDeferredObject *object =
653 qobject_cast<MyDeferredObject *>(component.create());
654 QVERIFY(object != 0);
655 QCOMPARE(object->value(), 0);
656 QVERIFY(object->objectProperty() == 0);
657 QVERIFY(object->objectProperty2() == 0);
659 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
660 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
662 qmlExecuteDeferred(object);
667 void tst_qdeclarativeecmascript::extensionObjects()
669 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
670 MyExtendedObject *object =
671 qobject_cast<MyExtendedObject *>(component.create());
672 QVERIFY(object != 0);
673 QCOMPARE(object->baseProperty(), 13);
674 QCOMPARE(object->coreProperty(), 9);
675 object->setProperty("extendedProperty", QVariant(11));
676 object->setProperty("baseExtendedProperty", QVariant(92));
677 QCOMPARE(object->coreProperty(), 11);
678 QCOMPARE(object->baseProperty(), 92);
680 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
682 QCOMPARE(nested->baseProperty(), 13);
683 QCOMPARE(nested->coreProperty(), 9);
684 nested->setProperty("extendedProperty", QVariant(11));
685 nested->setProperty("baseExtendedProperty", QVariant(92));
686 QCOMPARE(nested->coreProperty(), 11);
687 QCOMPARE(nested->baseProperty(), 92);
692 void tst_qdeclarativeecmascript::overrideExtensionProperties()
694 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
695 OverrideDefaultPropertyObject *object =
696 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
697 QVERIFY(object != 0);
698 QVERIFY(object->secondProperty() != 0);
699 QVERIFY(object->firstProperty() == 0);
704 void tst_qdeclarativeecmascript::attachedProperties()
707 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
708 QObject *object = component.create();
709 QVERIFY(object != 0);
710 QCOMPARE(object->property("a").toInt(), 19);
711 QCOMPARE(object->property("b").toInt(), 19);
712 QCOMPARE(object->property("c").toInt(), 19);
713 QCOMPARE(object->property("d").toInt(), 19);
718 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
719 QObject *object = component.create();
720 QVERIFY(object != 0);
721 QCOMPARE(object->property("a").toInt(), 26);
722 QCOMPARE(object->property("b").toInt(), 26);
723 QCOMPARE(object->property("c").toInt(), 26);
724 QCOMPARE(object->property("d").toInt(), 26);
730 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
731 QObject *object = component.create();
732 QVERIFY(object != 0);
734 QMetaObject::invokeMethod(object, "writeValue2");
736 MyQmlAttachedObject *attached =
737 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
738 QVERIFY(attached != 0);
740 QCOMPARE(attached->value2(), 9);
745 void tst_qdeclarativeecmascript::enums()
749 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
750 QObject *object = component.create();
751 QVERIFY(object != 0);
753 QCOMPARE(object->property("a").toInt(), 0);
754 QCOMPARE(object->property("b").toInt(), 1);
755 QCOMPARE(object->property("c").toInt(), 2);
756 QCOMPARE(object->property("d").toInt(), 3);
757 QCOMPARE(object->property("e").toInt(), 0);
758 QCOMPARE(object->property("f").toInt(), 1);
759 QCOMPARE(object->property("g").toInt(), 2);
760 QCOMPARE(object->property("h").toInt(), 3);
761 QCOMPARE(object->property("i").toInt(), 19);
762 QCOMPARE(object->property("j").toInt(), 19);
766 // Non-existent enums
768 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
770 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
771 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
772 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
773 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
775 QObject *object = component.create();
776 QVERIFY(object != 0);
777 QCOMPARE(object->property("a").toInt(), 0);
778 QCOMPARE(object->property("b").toInt(), 0);
784 void tst_qdeclarativeecmascript::valueTypeFunctions()
786 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
787 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
789 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
790 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
796 Tests that writing a constant to a property with a binding on it disables the
799 void tst_qdeclarativeecmascript::constantsOverrideBindings()
803 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
804 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
805 QVERIFY(object != 0);
807 QCOMPARE(object->property("c2").toInt(), 0);
808 object->setProperty("c1", QVariant(9));
809 QCOMPARE(object->property("c2").toInt(), 9);
811 emit object->basicSignal();
813 QCOMPARE(object->property("c2").toInt(), 13);
814 object->setProperty("c1", QVariant(8));
815 QCOMPARE(object->property("c2").toInt(), 13);
820 // During construction
822 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
823 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
824 QVERIFY(object != 0);
826 QCOMPARE(object->property("c1").toInt(), 0);
827 QCOMPARE(object->property("c2").toInt(), 10);
828 object->setProperty("c1", QVariant(9));
829 QCOMPARE(object->property("c1").toInt(), 9);
830 QCOMPARE(object->property("c2").toInt(), 10);
838 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
839 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
840 QVERIFY(object != 0);
842 QCOMPARE(object->property("c2").toInt(), 0);
843 object->setProperty("c1", QVariant(9));
844 QCOMPARE(object->property("c2").toInt(), 9);
846 object->setProperty("c2", QVariant(13));
847 QCOMPARE(object->property("c2").toInt(), 13);
848 object->setProperty("c1", QVariant(7));
849 QCOMPARE(object->property("c1").toInt(), 7);
850 QCOMPARE(object->property("c2").toInt(), 13);
858 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
859 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
860 QVERIFY(object != 0);
862 QCOMPARE(object->property("c1").toInt(), 0);
863 QCOMPARE(object->property("c3").toInt(), 10);
864 object->setProperty("c1", QVariant(9));
865 QCOMPARE(object->property("c1").toInt(), 9);
866 QCOMPARE(object->property("c3").toInt(), 10);
873 Tests that assigning a binding to a property that already has a binding causes
874 the original binding to be disabled.
876 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
878 QDeclarativeComponent component(&engine,
879 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
880 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
881 QVERIFY(object != 0);
883 QCOMPARE(object->property("c1").toInt(), 0);
884 QCOMPARE(object->property("c2").toInt(), 0);
885 QCOMPARE(object->property("c3").toInt(), 0);
887 object->setProperty("c1", QVariant(9));
888 QCOMPARE(object->property("c1").toInt(), 9);
889 QCOMPARE(object->property("c2").toInt(), 0);
890 QCOMPARE(object->property("c3").toInt(), 0);
892 object->setProperty("c3", QVariant(8));
893 QCOMPARE(object->property("c1").toInt(), 9);
894 QCOMPARE(object->property("c2").toInt(), 8);
895 QCOMPARE(object->property("c3").toInt(), 8);
901 Access a non-existent attached object.
903 Tests for a regression where this used to crash.
905 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
907 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
909 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
910 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
912 QObject *object = component.create();
913 QVERIFY(object != 0);
918 void tst_qdeclarativeecmascript::scope()
921 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
922 QObject *object = component.create();
923 QVERIFY(object != 0);
925 QCOMPARE(object->property("test1").toInt(), 1);
926 QCOMPARE(object->property("test2").toInt(), 2);
927 QCOMPARE(object->property("test3").toString(), QString("1Test"));
928 QCOMPARE(object->property("test4").toString(), QString("2Test"));
929 QCOMPARE(object->property("test5").toInt(), 1);
930 QCOMPARE(object->property("test6").toInt(), 1);
931 QCOMPARE(object->property("test7").toInt(), 2);
932 QCOMPARE(object->property("test8").toInt(), 2);
933 QCOMPARE(object->property("test9").toInt(), 1);
934 QCOMPARE(object->property("test10").toInt(), 3);
940 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
941 QObject *object = component.create();
942 QVERIFY(object != 0);
944 QCOMPARE(object->property("test1").toInt(), 19);
945 QCOMPARE(object->property("test2").toInt(), 19);
946 QCOMPARE(object->property("test3").toInt(), 14);
947 QCOMPARE(object->property("test4").toInt(), 14);
948 QCOMPARE(object->property("test5").toInt(), 24);
949 QCOMPARE(object->property("test6").toInt(), 24);
955 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
956 QObject *object = component.create();
957 QVERIFY(object != 0);
959 QCOMPARE(object->property("test1").toBool(), true);
960 QCOMPARE(object->property("test2").toBool(), true);
961 QCOMPARE(object->property("test3").toBool(), true);
966 // Signal argument scope
968 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
969 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
970 QVERIFY(object != 0);
972 QCOMPARE(object->property("test").toInt(), 0);
973 QCOMPARE(object->property("test2").toString(), QString());
975 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
977 QCOMPARE(object->property("test").toInt(), 13);
978 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
984 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
985 QObject *object = component.create();
986 QVERIFY(object != 0);
988 QCOMPARE(object->property("test1").toBool(), true);
989 QCOMPARE(object->property("test2").toBool(), true);
995 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
996 QObject *object = component.create();
997 QVERIFY(object != 0);
999 QCOMPARE(object->property("test").toBool(), true);
1005 // In 4.7, non-library javascript files that had no imports shared the imports of their
1006 // importing context
1007 void tst_qdeclarativeecmascript::importScope()
1009 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
1010 QObject *o = component.create();
1013 QCOMPARE(o->property("test").toInt(), 240);
1019 Tests that "any" type passes through a synthesized signal parameter. This
1020 is essentially a test of QDeclarativeMetaType::copy()
1022 void tst_qdeclarativeecmascript::signalParameterTypes()
1024 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
1025 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1026 QVERIFY(object != 0);
1028 emit object->basicSignal();
1030 QCOMPARE(object->property("intProperty").toInt(), 10);
1031 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1032 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1033 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1034 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1035 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1041 Test that two JS objects for the same QObject compare as equal.
1043 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1045 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1046 QObject *object = component.create();
1047 QVERIFY(object != 0);
1049 QCOMPARE(object->property("test1").toBool(), true);
1050 QCOMPARE(object->property("test2").toBool(), true);
1051 QCOMPARE(object->property("test3").toBool(), true);
1052 QCOMPARE(object->property("test4").toBool(), true);
1053 QCOMPARE(object->property("test5").toBool(), true);
1059 Confirm bindings and alias properties can coexist.
1061 Tests for a regression where the binding would not reevaluate.
1063 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1065 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1066 QObject *object = component.create();
1067 QVERIFY(object != 0);
1069 QCOMPARE(object->property("c2").toInt(), 3);
1070 QCOMPARE(object->property("c3").toInt(), 3);
1072 object->setProperty("c2", QVariant(19));
1074 QCOMPARE(object->property("c2").toInt(), 19);
1075 QCOMPARE(object->property("c3").toInt(), 19);
1081 Ensure that we can write undefined value to an alias property,
1082 and that the aliased property is reset correctly if possible.
1084 void tst_qdeclarativeecmascript::aliasPropertyReset()
1086 QObject *object = 0;
1088 // test that a manual write (of undefined) to a resettable aliased property succeeds
1089 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1090 object = c1.create();
1091 QVERIFY(object != 0);
1092 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1093 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1094 QMetaObject::invokeMethod(object, "resetAliased");
1095 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1096 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1099 // test that a manual write (of undefined) to a resettable alias property succeeds
1100 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1101 object = c2.create();
1102 QVERIFY(object != 0);
1103 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1104 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1105 QMetaObject::invokeMethod(object, "resetAlias");
1106 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1107 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1110 // test that an alias to a bound property works correctly
1111 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1112 object = c3.create();
1113 QVERIFY(object != 0);
1114 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1115 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1116 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1117 QMetaObject::invokeMethod(object, "resetAlias");
1118 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1119 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1120 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1123 // test that a manual write (of undefined) to a resettable alias property
1124 // whose aliased property's object has been deleted, does not crash.
1125 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1126 object = c4.create();
1127 QVERIFY(object != 0);
1128 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1129 QObject *loader = object->findChild<QObject*>("loader");
1130 QVERIFY(loader != 0);
1132 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1133 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1134 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1135 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1136 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1139 // test that binding an alias property to an undefined value works correctly
1140 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1141 object = c5.create();
1142 QVERIFY(object != 0);
1143 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1146 // test that a manual write (of undefined) to a non-resettable property fails properly
1147 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1148 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1149 QDeclarativeComponent e1(&engine, url);
1150 object = e1.create();
1151 QVERIFY(object != 0);
1152 QCOMPARE(object->property("intAlias").value<int>(), 12);
1153 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1154 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1155 QMetaObject::invokeMethod(object, "resetAlias");
1156 QCOMPARE(object->property("intAlias").value<int>(), 12);
1157 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1161 void tst_qdeclarativeecmascript::dynamicCreation_data()
1163 QTest::addColumn<QString>("method");
1164 QTest::addColumn<QString>("createdName");
1166 QTest::newRow("One") << "createOne" << "objectOne";
1167 QTest::newRow("Two") << "createTwo" << "objectTwo";
1168 QTest::newRow("Three") << "createThree" << "objectThree";
1172 Test using createQmlObject to dynamically generate an item
1173 Also using createComponent is tested.
1175 void tst_qdeclarativeecmascript::dynamicCreation()
1177 QFETCH(QString, method);
1178 QFETCH(QString, createdName);
1180 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1181 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1182 QVERIFY(object != 0);
1184 QMetaObject::invokeMethod(object, method.toUtf8());
1185 QObject *created = object->objectProperty();
1187 QCOMPARE(created->objectName(), createdName);
1193 Tests the destroy function
1195 void tst_qdeclarativeecmascript::dynamicDestruction()
1198 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1199 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1200 QVERIFY(object != 0);
1201 QDeclarativeGuard<QObject> createdQmlObject = 0;
1203 QMetaObject::invokeMethod(object, "create");
1204 createdQmlObject = object->objectProperty();
1205 QVERIFY(createdQmlObject);
1206 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1208 QMetaObject::invokeMethod(object, "killOther");
1209 QVERIFY(createdQmlObject);
1210 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1211 QVERIFY(createdQmlObject);
1212 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1213 if (createdQmlObject) {
1215 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1218 QVERIFY(!createdQmlObject);
1220 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1221 QMetaObject::invokeMethod(object, "killMe");
1224 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1229 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1230 QObject *o = component.create();
1233 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1235 QMetaObject::invokeMethod(o, "create");
1237 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1239 QMetaObject::invokeMethod(o, "destroy");
1241 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1243 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1250 tests that id.toString() works
1252 void tst_qdeclarativeecmascript::objectToString()
1254 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1255 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1256 QVERIFY(object != 0);
1257 QMetaObject::invokeMethod(object, "testToString");
1258 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1259 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1265 tests that id.hasOwnProperty() works
1267 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1269 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1270 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1271 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1272 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1274 QDeclarativeComponent component(&engine, url);
1275 QObject *object = component.create();
1276 QVERIFY(object != 0);
1278 // test QObjects in QML
1279 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1280 QVERIFY(object->property("result").value<bool>() == true);
1281 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1282 QVERIFY(object->property("result").value<bool>() == false);
1284 // now test other types in QML
1285 QObject *child = object->findChild<QObject*>("typeObj");
1286 QVERIFY(child != 0);
1287 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1288 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1289 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1290 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1291 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1292 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1293 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1294 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1295 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1296 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1297 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1298 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1300 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1301 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1302 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1303 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1304 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1305 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1306 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1307 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1308 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1314 Tests bindings that indirectly cause their own deletion work.
1316 This test is best run under valgrind to ensure no invalid memory access occur.
1318 void tst_qdeclarativeecmascript::selfDeletingBinding()
1321 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1322 QObject *object = component.create();
1323 QVERIFY(object != 0);
1324 object->setProperty("triggerDelete", true);
1329 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1330 QObject *object = component.create();
1331 QVERIFY(object != 0);
1332 object->setProperty("triggerDelete", true);
1338 Test that extended object properties can be accessed.
1340 This test a regression where this used to crash. The issue was specificially
1341 for extended objects that did not include a synthesized meta object (so non-root
1342 and no synthesiszed properties).
1344 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1346 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1347 QObject *object = component.create();
1348 QVERIFY(object != 0);
1353 Test file/lineNumbers for binding/Script errors.
1355 void tst_qdeclarativeecmascript::scriptErrors()
1357 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1358 QString url = component.url().toString();
1360 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1361 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1362 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1363 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1364 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1365 QString warning6 = url + ":7: Unable to assign [undefined] to int";
1366 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1367 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1369 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1370 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1371 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1372 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1373 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1374 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1375 QVERIFY(object != 0);
1377 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1378 emit object->basicSignal();
1380 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1381 emit object->anotherBasicSignal();
1383 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1384 emit object->thirdBasicSignal();
1390 Test file/lineNumbers for inline functions.
1392 void tst_qdeclarativeecmascript::functionErrors()
1394 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1395 QString url = component.url().toString();
1397 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1399 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1401 QObject *object = component.create();
1402 QVERIFY(object != 0);
1405 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1406 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1407 url = componentTwo.url().toString();
1408 object = componentTwo.create();
1409 QVERIFY(object != 0);
1411 QString srpname = object->property("srp_name").toString();
1413 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1414 QLatin1String(" is not a function");
1415 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1416 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1421 Test various errors that can occur when assigning a property from script
1423 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1425 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1427 QString url = component.url().toString();
1429 QObject *object = component.create();
1430 QVERIFY(object != 0);
1432 QCOMPARE(object->property("test1").toBool(), true);
1433 QCOMPARE(object->property("test2").toBool(), true);
1439 Test bindings still work when the reeval is triggered from within
1442 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1444 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1445 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1446 QVERIFY(object != 0);
1448 QCOMPARE(object->property("base").toReal(), 50.);
1449 QCOMPARE(object->property("test1").toReal(), 50.);
1450 QCOMPARE(object->property("test2").toReal(), 50.);
1452 object->basicSignal();
1454 QCOMPARE(object->property("base").toReal(), 200.);
1455 QCOMPARE(object->property("test1").toReal(), 200.);
1456 QCOMPARE(object->property("test2").toReal(), 200.);
1458 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1460 QCOMPARE(object->property("base").toReal(), 400.);
1461 QCOMPARE(object->property("test1").toReal(), 400.);
1462 QCOMPARE(object->property("test2").toReal(), 400.);
1468 Test that list properties can be iterated from ECMAScript
1470 void tst_qdeclarativeecmascript::listProperties()
1472 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1473 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1474 QVERIFY(object != 0);
1476 QCOMPARE(object->property("test1").toInt(), 21);
1477 QCOMPARE(object->property("test2").toInt(), 2);
1478 QCOMPARE(object->property("test3").toBool(), true);
1479 QCOMPARE(object->property("test4").toBool(), true);
1484 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1486 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1487 QString url = component.url().toString();
1489 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1491 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1492 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1493 QVERIFY(object != 0);
1495 QCOMPARE(object->property("test").toBool(), false);
1497 MyQmlObject object2;
1498 MyQmlObject object3;
1499 object2.setObjectProperty(&object3);
1500 object->setObjectProperty(&object2);
1502 QCOMPARE(object->property("test").toBool(), true);
1507 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1509 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1510 QString url = component.url().toString();
1512 QString warning = component.url().toString() + ":6: Error: JS exception";
1514 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1515 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1516 QVERIFY(object != 0);
1520 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1522 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1523 QString url = component.url().toString();
1525 QString warning = component.url().toString() + ":5: Error: JS exception";
1527 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1528 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1529 QVERIFY(object != 0);
1533 static int transientErrorsMsgCount = 0;
1534 static void transientErrorsMsgHandler(QtMsgType, const char *)
1536 ++transientErrorsMsgCount;
1539 // Check that transient binding errors are not displayed
1540 void tst_qdeclarativeecmascript::transientErrors()
1543 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1545 transientErrorsMsgCount = 0;
1546 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1548 QObject *object = component.create();
1549 QVERIFY(object != 0);
1551 qInstallMsgHandler(old);
1553 QCOMPARE(transientErrorsMsgCount, 0);
1558 // One binding erroring multiple times, but then resolving
1560 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1562 transientErrorsMsgCount = 0;
1563 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1565 QObject *object = component.create();
1566 QVERIFY(object != 0);
1568 qInstallMsgHandler(old);
1570 QCOMPARE(transientErrorsMsgCount, 0);
1576 // Check that errors during shutdown are minimized
1577 void tst_qdeclarativeecmascript::shutdownErrors()
1579 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1580 QObject *object = component.create();
1581 QVERIFY(object != 0);
1583 transientErrorsMsgCount = 0;
1584 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1588 qInstallMsgHandler(old);
1589 QCOMPARE(transientErrorsMsgCount, 0);
1592 void tst_qdeclarativeecmascript::compositePropertyType()
1594 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1595 QString messageFormat = QString(QLatin1String("hello world (%1:%2)")).arg(TEST_FILE("compositePropertyType.qml").toString()).arg(7);
1596 QTest::ignoreMessage(QtDebugMsg, qPrintable(messageFormat));
1597 QObject *object = qobject_cast<QObject *>(component.create());
1602 void tst_qdeclarativeecmascript::jsObject()
1604 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1605 QObject *object = component.create();
1606 QVERIFY(object != 0);
1608 QCOMPARE(object->property("test").toInt(), 92);
1613 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1616 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1617 QObject *object = component.create();
1618 QVERIFY(object != 0);
1620 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1622 object->setProperty("setUndefined", true);
1624 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1626 object->setProperty("setUndefined", false);
1628 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1633 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1634 QObject *object = component.create();
1635 QVERIFY(object != 0);
1637 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1639 QMetaObject::invokeMethod(object, "doReset");
1641 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1647 // Aliases to variant properties should work
1648 void tst_qdeclarativeecmascript::qtbug_22464()
1650 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22464.qml"));
1651 QObject *object = component.create();
1652 QVERIFY(object != 0);
1654 QCOMPARE(object->property("test").toBool(), true);
1660 void tst_qdeclarativeecmascript::bug1()
1662 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1663 QObject *object = component.create();
1664 QVERIFY(object != 0);
1666 QCOMPARE(object->property("test").toInt(), 14);
1668 object->setProperty("a", 11);
1670 QCOMPARE(object->property("test").toInt(), 3);
1672 object->setProperty("b", true);
1674 QCOMPARE(object->property("test").toInt(), 9);
1679 void tst_qdeclarativeecmascript::bug2()
1681 QDeclarativeComponent component(&engine);
1682 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1684 QObject *object = component.create();
1685 QVERIFY(object != 0);
1690 // Don't crash in createObject when the component has errors.
1691 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1693 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1694 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1695 QVERIFY(object != 0);
1697 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1698 QMetaObject::invokeMethod(object, "dontCrash");
1699 QObject *created = object->objectProperty();
1700 QVERIFY(created == 0);
1705 // ownership transferred to JS, ensure that GC runs the dtor
1706 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1709 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1711 // allow the engine to go out of scope too.
1713 QDeclarativeEngine dcoEngine;
1714 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1715 QObject *object = component.create();
1716 QVERIFY(object != 0);
1717 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1718 QVERIFY(mdcdo != 0);
1719 mdcdo->setDtorCount(&dtorCount);
1721 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1722 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1724 // we do this once manually, but it should be done automatically
1725 // when the engine goes out of scope (since it should gc in dtor)
1726 QMetaObject::invokeMethod(object, "performGc");
1729 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1735 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1736 QCOMPARE(dtorCount, expectedDtorCount);
1740 void tst_qdeclarativeecmascript::regExpBug()
1742 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1743 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1744 QVERIFY(object != 0);
1745 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1749 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1751 QString functionSource = QLatin1String("(function(object) { return ") +
1752 QLatin1String(source) + QLatin1String(" })");
1754 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1757 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1758 if (function.IsEmpty())
1760 v8::Handle<v8::Value> args[] = { o };
1761 function->Call(engine->global(), 1, args);
1762 return tc.HasCaught();
1765 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1766 const char *source, v8::Handle<v8::Value> result)
1768 QString functionSource = QLatin1String("(function(object) { return ") +
1769 QLatin1String(source) + QLatin1String(" })");
1771 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1774 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1775 if (function.IsEmpty())
1777 v8::Handle<v8::Value> args[] = { o };
1779 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1784 return value->StrictEquals(result);
1787 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1790 QString functionSource = QLatin1String("(function(object) { return ") +
1791 QLatin1String(source) + QLatin1String(" })");
1793 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1795 return v8::Handle<v8::Value>();
1796 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1797 if (function.IsEmpty())
1798 return v8::Handle<v8::Value>();
1799 v8::Handle<v8::Value> args[] = { o };
1801 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1804 return v8::Handle<v8::Value>();
1808 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1809 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1810 #define EVALUATE(source) evaluate(engine, object, source)
1812 void tst_qdeclarativeecmascript::callQtInvokables()
1814 MyInvokableObject o;
1816 QDeclarativeEngine qmlengine;
1817 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1819 QV8Engine *engine = ep->v8engine();
1821 v8::HandleScope handle_scope;
1822 v8::Context::Scope scope(engine->context());
1824 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1826 // Non-existent methods
1828 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1829 QCOMPARE(o.error(), false);
1830 QCOMPARE(o.invoked(), -1);
1831 QCOMPARE(o.actuals().count(), 0);
1834 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1835 QCOMPARE(o.error(), false);
1836 QCOMPARE(o.invoked(), -1);
1837 QCOMPARE(o.actuals().count(), 0);
1839 // Insufficient arguments
1841 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1842 QCOMPARE(o.error(), false);
1843 QCOMPARE(o.invoked(), -1);
1844 QCOMPARE(o.actuals().count(), 0);
1847 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1848 QCOMPARE(o.error(), false);
1849 QCOMPARE(o.invoked(), -1);
1850 QCOMPARE(o.actuals().count(), 0);
1852 // Excessive arguments
1854 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1855 QCOMPARE(o.error(), false);
1856 QCOMPARE(o.invoked(), 8);
1857 QCOMPARE(o.actuals().count(), 1);
1858 QCOMPARE(o.actuals().at(0), QVariant(10));
1861 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1862 QCOMPARE(o.error(), false);
1863 QCOMPARE(o.invoked(), 9);
1864 QCOMPARE(o.actuals().count(), 2);
1865 QCOMPARE(o.actuals().at(0), QVariant(10));
1866 QCOMPARE(o.actuals().at(1), QVariant(11));
1868 // Test return types
1870 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1871 QCOMPARE(o.error(), false);
1872 QCOMPARE(o.invoked(), 0);
1873 QCOMPARE(o.actuals().count(), 0);
1876 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1877 QCOMPARE(o.error(), false);
1878 QCOMPARE(o.invoked(), 1);
1879 QCOMPARE(o.actuals().count(), 0);
1882 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1883 QCOMPARE(o.error(), false);
1884 QCOMPARE(o.invoked(), 2);
1885 QCOMPARE(o.actuals().count(), 0);
1889 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1890 QVERIFY(!ret.IsEmpty());
1891 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1892 QCOMPARE(o.error(), false);
1893 QCOMPARE(o.invoked(), 3);
1894 QCOMPARE(o.actuals().count(), 0);
1899 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1900 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1901 QCOMPARE(o.error(), false);
1902 QCOMPARE(o.invoked(), 4);
1903 QCOMPARE(o.actuals().count(), 0);
1907 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1908 QCOMPARE(o.error(), false);
1909 QCOMPARE(o.invoked(), 5);
1910 QCOMPARE(o.actuals().count(), 0);
1914 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1915 QVERIFY(ret->IsString());
1916 QCOMPARE(engine->toString(ret), QString("Hello world"));
1917 QCOMPARE(o.error(), false);
1918 QCOMPARE(o.invoked(), 6);
1919 QCOMPARE(o.actuals().count(), 0);
1923 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1924 QCOMPARE(o.error(), false);
1925 QCOMPARE(o.invoked(), 7);
1926 QCOMPARE(o.actuals().count(), 0);
1930 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1931 QCOMPARE(o.error(), false);
1932 QCOMPARE(o.invoked(), 8);
1933 QCOMPARE(o.actuals().count(), 1);
1934 QCOMPARE(o.actuals().at(0), QVariant(94));
1937 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1938 QCOMPARE(o.error(), false);
1939 QCOMPARE(o.invoked(), 8);
1940 QCOMPARE(o.actuals().count(), 1);
1941 QCOMPARE(o.actuals().at(0), QVariant(94));
1944 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1945 QCOMPARE(o.error(), false);
1946 QCOMPARE(o.invoked(), 8);
1947 QCOMPARE(o.actuals().count(), 1);
1948 QCOMPARE(o.actuals().at(0), QVariant(0));
1951 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1952 QCOMPARE(o.error(), false);
1953 QCOMPARE(o.invoked(), 8);
1954 QCOMPARE(o.actuals().count(), 1);
1955 QCOMPARE(o.actuals().at(0), QVariant(0));
1958 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1959 QCOMPARE(o.error(), false);
1960 QCOMPARE(o.invoked(), 8);
1961 QCOMPARE(o.actuals().count(), 1);
1962 QCOMPARE(o.actuals().at(0), QVariant(0));
1965 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1966 QCOMPARE(o.error(), false);
1967 QCOMPARE(o.invoked(), 8);
1968 QCOMPARE(o.actuals().count(), 1);
1969 QCOMPARE(o.actuals().at(0), QVariant(0));
1972 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1973 QCOMPARE(o.error(), false);
1974 QCOMPARE(o.invoked(), 9);
1975 QCOMPARE(o.actuals().count(), 2);
1976 QCOMPARE(o.actuals().at(0), QVariant(122));
1977 QCOMPARE(o.actuals().at(1), QVariant(9));
1980 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1981 QCOMPARE(o.error(), false);
1982 QCOMPARE(o.invoked(), 10);
1983 QCOMPARE(o.actuals().count(), 1);
1984 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1987 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
1988 QCOMPARE(o.error(), false);
1989 QCOMPARE(o.invoked(), 10);
1990 QCOMPARE(o.actuals().count(), 1);
1991 QCOMPARE(o.actuals().at(0), QVariant(94.3));
1994 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
1995 QCOMPARE(o.error(), false);
1996 QCOMPARE(o.invoked(), 10);
1997 QCOMPARE(o.actuals().count(), 1);
1998 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2001 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
2002 QCOMPARE(o.error(), false);
2003 QCOMPARE(o.invoked(), 10);
2004 QCOMPARE(o.actuals().count(), 1);
2005 QCOMPARE(o.actuals().at(0), QVariant(0));
2008 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2009 QCOMPARE(o.error(), false);
2010 QCOMPARE(o.invoked(), 10);
2011 QCOMPARE(o.actuals().count(), 1);
2012 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2015 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2016 QCOMPARE(o.error(), false);
2017 QCOMPARE(o.invoked(), 10);
2018 QCOMPARE(o.actuals().count(), 1);
2019 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2022 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2023 QCOMPARE(o.error(), false);
2024 QCOMPARE(o.invoked(), 11);
2025 QCOMPARE(o.actuals().count(), 1);
2026 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2029 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2030 QCOMPARE(o.error(), false);
2031 QCOMPARE(o.invoked(), 11);
2032 QCOMPARE(o.actuals().count(), 1);
2033 QCOMPARE(o.actuals().at(0), QVariant("19"));
2037 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2038 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2039 QCOMPARE(o.error(), false);
2040 QCOMPARE(o.invoked(), 11);
2041 QCOMPARE(o.actuals().count(), 1);
2042 QCOMPARE(o.actuals().at(0), QVariant(expected));
2046 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2047 QCOMPARE(o.error(), false);
2048 QCOMPARE(o.invoked(), 11);
2049 QCOMPARE(o.actuals().count(), 1);
2050 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2053 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2054 QCOMPARE(o.error(), false);
2055 QCOMPARE(o.invoked(), 11);
2056 QCOMPARE(o.actuals().count(), 1);
2057 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2060 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2061 QCOMPARE(o.error(), false);
2062 QCOMPARE(o.invoked(), 12);
2063 QCOMPARE(o.actuals().count(), 1);
2064 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2067 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2068 QCOMPARE(o.error(), false);
2069 QCOMPARE(o.invoked(), 12);
2070 QCOMPARE(o.actuals().count(), 1);
2071 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2074 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2075 QCOMPARE(o.error(), false);
2076 QCOMPARE(o.invoked(), 12);
2077 QCOMPARE(o.actuals().count(), 1);
2078 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2081 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2082 QCOMPARE(o.error(), false);
2083 QCOMPARE(o.invoked(), 12);
2084 QCOMPARE(o.actuals().count(), 1);
2085 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2088 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2089 QCOMPARE(o.error(), false);
2090 QCOMPARE(o.invoked(), 12);
2091 QCOMPARE(o.actuals().count(), 1);
2092 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2095 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2096 QCOMPARE(o.error(), false);
2097 QCOMPARE(o.invoked(), 12);
2098 QCOMPARE(o.actuals().count(), 1);
2099 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2102 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2103 QCOMPARE(o.error(), false);
2104 QCOMPARE(o.invoked(), 13);
2105 QCOMPARE(o.actuals().count(), 1);
2106 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2109 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2110 QCOMPARE(o.error(), false);
2111 QCOMPARE(o.invoked(), 13);
2112 QCOMPARE(o.actuals().count(), 1);
2113 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2116 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2117 QCOMPARE(o.error(), false);
2118 QCOMPARE(o.invoked(), 13);
2119 QCOMPARE(o.actuals().count(), 1);
2120 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2123 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2124 QCOMPARE(o.error(), false);
2125 QCOMPARE(o.invoked(), 13);
2126 QCOMPARE(o.actuals().count(), 1);
2127 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2130 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2131 QCOMPARE(o.error(), false);
2132 QCOMPARE(o.invoked(), 13);
2133 QCOMPARE(o.actuals().count(), 1);
2134 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2137 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2138 QCOMPARE(o.error(), false);
2139 QCOMPARE(o.invoked(), 14);
2140 QCOMPARE(o.actuals().count(), 1);
2141 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2144 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2145 QCOMPARE(o.error(), false);
2146 QCOMPARE(o.invoked(), 14);
2147 QCOMPARE(o.actuals().count(), 1);
2148 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2151 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2152 QCOMPARE(o.error(), false);
2153 QCOMPARE(o.invoked(), 14);
2154 QCOMPARE(o.actuals().count(), 1);
2155 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2158 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2159 QCOMPARE(o.error(), false);
2160 QCOMPARE(o.invoked(), 14);
2161 QCOMPARE(o.actuals().count(), 1);
2162 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2165 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2166 QCOMPARE(o.error(), false);
2167 QCOMPARE(o.invoked(), 15);
2168 QCOMPARE(o.actuals().count(), 2);
2169 QCOMPARE(o.actuals().at(0), QVariant(4));
2170 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2173 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2174 QCOMPARE(o.error(), false);
2175 QCOMPARE(o.invoked(), 15);
2176 QCOMPARE(o.actuals().count(), 2);
2177 QCOMPARE(o.actuals().at(0), QVariant(8));
2178 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2181 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2182 QCOMPARE(o.error(), false);
2183 QCOMPARE(o.invoked(), 15);
2184 QCOMPARE(o.actuals().count(), 2);
2185 QCOMPARE(o.actuals().at(0), QVariant(3));
2186 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2189 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2190 QCOMPARE(o.error(), false);
2191 QCOMPARE(o.invoked(), 15);
2192 QCOMPARE(o.actuals().count(), 2);
2193 QCOMPARE(o.actuals().at(0), QVariant(44));
2194 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2197 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2198 QCOMPARE(o.error(), false);
2199 QCOMPARE(o.invoked(), -1);
2200 QCOMPARE(o.actuals().count(), 0);
2203 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2204 QCOMPARE(o.error(), false);
2205 QCOMPARE(o.invoked(), 16);
2206 QCOMPARE(o.actuals().count(), 1);
2207 QCOMPARE(o.actuals().at(0), QVariant(10));
2210 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2211 QCOMPARE(o.error(), false);
2212 QCOMPARE(o.invoked(), 17);
2213 QCOMPARE(o.actuals().count(), 2);
2214 QCOMPARE(o.actuals().at(0), QVariant(10));
2215 QCOMPARE(o.actuals().at(1), QVariant(11));
2218 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2219 QCOMPARE(o.error(), false);
2220 QCOMPARE(o.invoked(), 18);
2221 QCOMPARE(o.actuals().count(), 1);
2222 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2225 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2226 QCOMPARE(o.error(), false);
2227 QCOMPARE(o.invoked(), 19);
2228 QCOMPARE(o.actuals().count(), 1);
2229 QCOMPARE(o.actuals().at(0), QVariant(9));
2232 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2233 QCOMPARE(o.error(), false);
2234 QCOMPARE(o.invoked(), 20);
2235 QCOMPARE(o.actuals().count(), 2);
2236 QCOMPARE(o.actuals().at(0), QVariant(10));
2237 QCOMPARE(o.actuals().at(1), QVariant(19));
2240 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2241 QCOMPARE(o.error(), false);
2242 QCOMPARE(o.invoked(), 20);
2243 QCOMPARE(o.actuals().count(), 2);
2244 QCOMPARE(o.actuals().at(0), QVariant(10));
2245 QCOMPARE(o.actuals().at(1), QVariant(13));
2248 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2249 QCOMPARE(o.error(), false);
2250 QCOMPARE(o.invoked(), -3);
2251 QCOMPARE(o.actuals().count(), 1);
2252 QCOMPARE(o.actuals().at(0), QVariant(9));
2255 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2256 QCOMPARE(o.error(), false);
2257 QCOMPARE(o.invoked(), 21);
2258 QCOMPARE(o.actuals().count(), 2);
2259 QCOMPARE(o.actuals().at(0), QVariant(9));
2260 QCOMPARE(o.actuals().at(1), QVariant());
2263 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2264 QCOMPARE(o.error(), false);
2265 QCOMPARE(o.invoked(), 21);
2266 QCOMPARE(o.actuals().count(), 2);
2267 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2268 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2271 // QTBUG-13047 (check that you can pass registered object types as args)
2272 void tst_qdeclarativeecmascript::invokableObjectArg()
2274 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2276 QObject *o = component.create();
2278 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2280 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2285 // QTBUG-13047 (check that you can return registered object types from methods)
2286 void tst_qdeclarativeecmascript::invokableObjectRet()
2288 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2290 QObject *o = component.create();
2292 QCOMPARE(o->property("test").toBool(), true);
2297 void tst_qdeclarativeecmascript::listToVariant()
2299 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2301 MyQmlContainer container;
2303 QDeclarativeContext context(engine.rootContext());
2304 context.setContextObject(&container);
2306 QObject *object = component.create(&context);
2307 QVERIFY(object != 0);
2309 QVariant v = object->property("test");
2310 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2311 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2317 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2318 void tst_qdeclarativeecmascript::listAssignment()
2320 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2321 QObject *obj = component.create();
2322 QCOMPARE(obj->property("list1length").toInt(), 2);
2323 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2324 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2325 QCOMPARE(list1.count(&list1), list2.count(&list2));
2326 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2327 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2332 void tst_qdeclarativeecmascript::multiEngineObject()
2335 obj.setStringProperty("Howdy planet");
2337 QDeclarativeEngine e1;
2338 e1.rootContext()->setContextProperty("thing", &obj);
2339 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2341 QDeclarativeEngine e2;
2342 e2.rootContext()->setContextProperty("thing", &obj);
2343 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2345 QObject *o1 = c1.create();
2346 QObject *o2 = c2.create();
2348 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2349 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2355 // Test that references to QObjects are cleanup when the object is destroyed
2356 void tst_qdeclarativeecmascript::deletedObject()
2358 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2360 QObject *object = component.create();
2362 QCOMPARE(object->property("test1").toBool(), true);
2363 QCOMPARE(object->property("test2").toBool(), true);
2364 QCOMPARE(object->property("test3").toBool(), true);
2365 QCOMPARE(object->property("test4").toBool(), true);
2370 void tst_qdeclarativeecmascript::attachedPropertyScope()
2372 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2374 QObject *object = component.create();
2375 QVERIFY(object != 0);
2377 MyQmlAttachedObject *attached =
2378 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2379 QVERIFY(attached != 0);
2381 QCOMPARE(object->property("value2").toInt(), 0);
2383 attached->emitMySignal();
2385 QCOMPARE(object->property("value2").toInt(), 9);
2390 void tst_qdeclarativeecmascript::scriptConnect()
2393 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2395 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2396 QVERIFY(object != 0);
2398 QCOMPARE(object->property("test").toBool(), false);
2399 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2400 QCOMPARE(object->property("test").toBool(), true);
2406 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2408 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2409 QVERIFY(object != 0);
2411 QCOMPARE(object->property("test").toBool(), false);
2412 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2413 QCOMPARE(object->property("test").toBool(), true);
2419 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2421 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2422 QVERIFY(object != 0);
2424 QCOMPARE(object->property("test").toBool(), false);
2425 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2426 QCOMPARE(object->property("test").toBool(), true);
2432 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2434 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2435 QVERIFY(object != 0);
2437 QCOMPARE(object->methodCalled(), false);
2438 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2439 QCOMPARE(object->methodCalled(), true);
2445 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2447 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2448 QVERIFY(object != 0);
2450 QCOMPARE(object->methodCalled(), false);
2451 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2452 QCOMPARE(object->methodCalled(), true);
2458 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2460 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2461 QVERIFY(object != 0);
2463 QCOMPARE(object->property("test").toInt(), 0);
2464 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2465 QCOMPARE(object->property("test").toInt(), 2);
2471 void tst_qdeclarativeecmascript::scriptDisconnect()
2474 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2476 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2477 QVERIFY(object != 0);
2479 QCOMPARE(object->property("test").toInt(), 0);
2480 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2481 QCOMPARE(object->property("test").toInt(), 1);
2482 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2483 QCOMPARE(object->property("test").toInt(), 2);
2484 emit object->basicSignal();
2485 QCOMPARE(object->property("test").toInt(), 2);
2486 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2487 QCOMPARE(object->property("test").toInt(), 2);
2493 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2495 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2496 QVERIFY(object != 0);
2498 QCOMPARE(object->property("test").toInt(), 0);
2499 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2500 QCOMPARE(object->property("test").toInt(), 1);
2501 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2502 QCOMPARE(object->property("test").toInt(), 2);
2503 emit object->basicSignal();
2504 QCOMPARE(object->property("test").toInt(), 2);
2505 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2506 QCOMPARE(object->property("test").toInt(), 2);
2512 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2514 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2515 QVERIFY(object != 0);
2517 QCOMPARE(object->property("test").toInt(), 0);
2518 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2519 QCOMPARE(object->property("test").toInt(), 1);
2520 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2521 QCOMPARE(object->property("test").toInt(), 2);
2522 emit object->basicSignal();
2523 QCOMPARE(object->property("test").toInt(), 2);
2524 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2525 QCOMPARE(object->property("test").toInt(), 3);
2530 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2532 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2533 QVERIFY(object != 0);
2535 QCOMPARE(object->property("test").toInt(), 0);
2536 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2537 QCOMPARE(object->property("test").toInt(), 1);
2538 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2539 QCOMPARE(object->property("test").toInt(), 2);
2540 emit object->basicSignal();
2541 QCOMPARE(object->property("test").toInt(), 2);
2542 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2543 QCOMPARE(object->property("test").toInt(), 3);
2549 class OwnershipObject : public QObject
2553 OwnershipObject() { object = new QObject; }
2555 QPointer<QObject> object;
2558 QObject *getObject() { return object; }
2561 void tst_qdeclarativeecmascript::ownership()
2563 OwnershipObject own;
2564 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2565 context->setContextObject(&own);
2568 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2570 QVERIFY(own.object != 0);
2572 QObject *object = component.create(context);
2574 engine.collectGarbage();
2576 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2578 QVERIFY(own.object == 0);
2583 own.object = new QObject(&own);
2586 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2588 QVERIFY(own.object != 0);
2590 QObject *object = component.create(context);
2592 engine.collectGarbage();
2594 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2596 QVERIFY(own.object != 0);
2604 class CppOwnershipReturnValue : public QObject
2608 CppOwnershipReturnValue() : value(0) {}
2609 ~CppOwnershipReturnValue() { delete value; }
2611 Q_INVOKABLE QObject *create() {
2612 value = new QObject;
2613 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2617 Q_INVOKABLE MyQmlObject *createQmlObject() {
2618 MyQmlObject *rv = new MyQmlObject;
2623 QPointer<QObject> value;
2627 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2628 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2630 CppOwnershipReturnValue source;
2633 QDeclarativeEngine engine;
2634 engine.rootContext()->setContextProperty("source", &source);
2636 QVERIFY(source.value == 0);
2638 QDeclarativeComponent component(&engine);
2639 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2641 QObject *object = component.create();
2643 QVERIFY(object != 0);
2644 QVERIFY(source.value != 0);
2649 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2651 QVERIFY(source.value != 0);
2655 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2657 CppOwnershipReturnValue source;
2660 QDeclarativeEngine engine;
2661 engine.rootContext()->setContextProperty("source", &source);
2663 QVERIFY(source.value == 0);
2665 QDeclarativeComponent component(&engine);
2666 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2668 QObject *object = component.create();
2670 QVERIFY(object != 0);
2671 QVERIFY(source.value != 0);
2676 engine.collectGarbage();
2677 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2679 QVERIFY(source.value == 0);
2682 class QListQObjectMethodsObject : public QObject
2686 QListQObjectMethodsObject() {
2687 m_objects.append(new MyQmlObject());
2688 m_objects.append(new MyQmlObject());
2691 ~QListQObjectMethodsObject() {
2692 qDeleteAll(m_objects);
2696 QList<QObject *> getObjects() { return m_objects; }
2699 QList<QObject *> m_objects;
2702 // Tests that returning a QList<QObject*> from a method works
2703 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2705 QListQObjectMethodsObject obj;
2706 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2707 context->setContextObject(&obj);
2709 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2711 QObject *object = component.create(context);
2713 QCOMPARE(object->property("test").toInt(), 2);
2714 QCOMPARE(object->property("test2").toBool(), true);
2721 void tst_qdeclarativeecmascript::strictlyEquals()
2723 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2725 QObject *object = component.create();
2726 QVERIFY(object != 0);
2728 QCOMPARE(object->property("test1").toBool(), true);
2729 QCOMPARE(object->property("test2").toBool(), true);
2730 QCOMPARE(object->property("test3").toBool(), true);
2731 QCOMPARE(object->property("test4").toBool(), true);
2732 QCOMPARE(object->property("test5").toBool(), true);
2733 QCOMPARE(object->property("test6").toBool(), true);
2734 QCOMPARE(object->property("test7").toBool(), true);
2735 QCOMPARE(object->property("test8").toBool(), true);
2740 void tst_qdeclarativeecmascript::compiled()
2742 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2744 QObject *object = component.create();
2745 QVERIFY(object != 0);
2747 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2748 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2749 QCOMPARE(object->property("test3").toBool(), true);
2750 QCOMPARE(object->property("test4").toBool(), false);
2751 QCOMPARE(object->property("test5").toBool(), false);
2752 QCOMPARE(object->property("test6").toBool(), true);
2754 QCOMPARE(object->property("test7").toInt(), 185);
2755 QCOMPARE(object->property("test8").toInt(), 167);
2756 QCOMPARE(object->property("test9").toBool(), true);
2757 QCOMPARE(object->property("test10").toBool(), false);
2758 QCOMPARE(object->property("test11").toBool(), false);
2759 QCOMPARE(object->property("test12").toBool(), true);
2761 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2762 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2763 QCOMPARE(object->property("test15").toBool(), false);
2764 QCOMPARE(object->property("test16").toBool(), true);
2766 QCOMPARE(object->property("test17").toInt(), 5);
2767 QCOMPARE(object->property("test18").toReal(), qreal(176));
2768 QCOMPARE(object->property("test19").toInt(), 7);
2769 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2770 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2771 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2772 QCOMPARE(object->property("test23").toBool(), true);
2773 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2774 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2779 // Test that numbers assigned in bindings as strings work consistently
2780 void tst_qdeclarativeecmascript::numberAssignment()
2782 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2784 QObject *object = component.create();
2785 QVERIFY(object != 0);
2787 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2788 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2789 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2790 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2791 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2793 QCOMPARE(object->property("test5"), QVariant((int)7));
2794 QCOMPARE(object->property("test6"), QVariant((int)7));
2795 QCOMPARE(object->property("test7"), QVariant((int)6));
2796 QCOMPARE(object->property("test8"), QVariant((int)6));
2798 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2799 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2800 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2801 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2806 void tst_qdeclarativeecmascript::propertySplicing()
2808 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2810 QObject *object = component.create();
2811 QVERIFY(object != 0);
2813 QCOMPARE(object->property("test").toBool(), true);
2819 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2821 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2823 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2824 QVERIFY(object != 0);
2826 MyQmlObject::MyType type;
2827 type.value = 0x8971123;
2828 emit object->signalWithUnknownType(type);
2830 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2832 QCOMPARE(result.value, type.value);
2838 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2840 QTest::addColumn<QString>("expression");
2841 QTest::addColumn<QString>("compare");
2843 QString compareStrict("(function(a, b) { return a === b; })");
2844 QTest::newRow("true") << "true" << compareStrict;
2845 QTest::newRow("undefined") << "undefined" << compareStrict;
2846 QTest::newRow("null") << "null" << compareStrict;
2847 QTest::newRow("123") << "123" << compareStrict;
2848 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2850 QString comparePropertiesStrict(
2852 " if (typeof b != 'object')"
2854 " var props = Object.getOwnPropertyNames(b);"
2855 " for (var i = 0; i < props.length; ++i) {"
2856 " var p = props[i];"
2857 " return arguments.callee(a[p], b[p]);"
2860 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2861 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2864 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2866 QFETCH(QString, expression);
2867 QFETCH(QString, compare);
2869 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2870 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2871 QVERIFY(object != 0);
2873 QJSValue value = engine.evaluate(expression);
2874 QVERIFY(!engine.hasUncaughtException());
2875 object->setProperty("expression", expression);
2876 object->setProperty("compare", compare);
2877 object->setProperty("pass", false);
2879 emit object->signalWithVariant(QVariant::fromValue(value));
2880 QVERIFY(object->property("pass").toBool());
2883 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2885 signalWithJSValueInVariant_data();
2888 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2890 QFETCH(QString, expression);
2891 QFETCH(QString, compare);
2893 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2894 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2895 QVERIFY(object != 0);
2898 QJSValue value = engine2.evaluate(expression);
2899 QVERIFY(!engine2.hasUncaughtException());
2900 object->setProperty("expression", expression);
2901 object->setProperty("compare", compare);
2902 object->setProperty("pass", false);
2904 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2905 emit object->signalWithVariant(QVariant::fromValue(value));
2906 QVERIFY(!object->property("pass").toBool());
2909 void tst_qdeclarativeecmascript::moduleApi_data()
2911 QTest::addColumn<QUrl>("testfile");
2912 QTest::addColumn<QString>("errorMessage");
2913 QTest::addColumn<QStringList>("warningMessages");
2914 QTest::addColumn<QStringList>("readProperties");
2915 QTest::addColumn<QVariantList>("readExpectedValues");
2916 QTest::addColumn<QStringList>("writeProperties");
2917 QTest::addColumn<QVariantList>("writeValues");
2918 QTest::addColumn<QStringList>("readBackProperties");
2919 QTest::addColumn<QVariantList>("readBackExpectedValues");
2921 QTest::newRow("qobject, register + read + method")
2922 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2925 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2926 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2927 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2933 QTest::newRow("script, register + read")
2934 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2937 << (QStringList() << "scriptTest")
2938 << (QVariantList() << 13)
2944 QTest::newRow("qobject, caching + read")
2945 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2948 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2949 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2955 QTest::newRow("script, caching + read")
2956 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2959 << (QStringList() << "scriptTest")
2960 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2966 QTest::newRow("qobject, writing + readonly constraints")
2967 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2969 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2970 << (QStringList() << "readOnlyProperty" << "writableProperty")
2971 << (QVariantList() << 20 << 50)
2972 << (QStringList() << "firstProperty" << "writableProperty")
2973 << (QVariantList() << 30 << 30)
2974 << (QStringList() << "readOnlyProperty" << "writableProperty")
2975 << (QVariantList() << 20 << 30);
2977 QTest::newRow("script, writing + readonly constraints")
2978 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
2980 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
2981 << (QStringList() << "readBack" << "unchanged")
2982 << (QVariantList() << 13 << 42)
2983 << (QStringList() << "firstProperty" << "secondProperty")
2984 << (QVariantList() << 30 << 30)
2985 << (QStringList() << "readBack" << "unchanged")
2986 << (QVariantList() << 30 << 42);
2988 QTest::newRow("qobject module API enum values in JS")
2989 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
2992 << (QStringList() << "enumValue" << "enumMethod")
2993 << (QVariantList() << 42 << 30)
2999 QTest::newRow("qobject, invalid major version fail")
3000 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
3001 << QString("QDeclarativeComponent: Component is not ready")
3010 QTest::newRow("qobject, invalid minor version fail")
3011 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
3012 << QString("QDeclarativeComponent: Component is not ready")
3022 void tst_qdeclarativeecmascript::moduleApi()
3024 QFETCH(QUrl, testfile);
3025 QFETCH(QString, errorMessage);
3026 QFETCH(QStringList, warningMessages);
3027 QFETCH(QStringList, readProperties);
3028 QFETCH(QVariantList, readExpectedValues);
3029 QFETCH(QStringList, writeProperties);
3030 QFETCH(QVariantList, writeValues);
3031 QFETCH(QStringList, readBackProperties);
3032 QFETCH(QVariantList, readBackExpectedValues);
3034 QDeclarativeComponent component(&engine, testfile);
3036 if (!errorMessage.isEmpty())
3037 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3039 if (warningMessages.size())
3040 foreach (const QString &warning, warningMessages)
3041 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3043 QObject *object = component.create();
3044 if (!errorMessage.isEmpty()) {
3045 QVERIFY(object == 0);
3047 QVERIFY(object != 0);
3048 for (int i = 0; i < readProperties.size(); ++i)
3049 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3050 for (int i = 0; i < writeProperties.size(); ++i)
3051 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3052 for (int i = 0; i < readBackProperties.size(); ++i)
3053 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3058 void tst_qdeclarativeecmascript::importScripts_data()
3060 QTest::addColumn<QUrl>("testfile");
3061 QTest::addColumn<QString>("errorMessage");
3062 QTest::addColumn<QStringList>("warningMessages");
3063 QTest::addColumn<QStringList>("propertyNames");
3064 QTest::addColumn<QVariantList>("propertyValues");
3066 QTest::newRow("basic functionality")
3067 << TEST_FILE("jsimport/testImport.qml")
3070 << (QStringList() << QLatin1String("importedScriptStringValue")
3071 << QLatin1String("importedScriptFunctionValue")
3072 << QLatin1String("importedModuleAttachedPropertyValue")
3073 << QLatin1String("importedModuleEnumValue"))
3074 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3079 QTest::newRow("import scoping")
3080 << TEST_FILE("jsimport/testImportScoping.qml")
3083 << (QStringList() << QLatin1String("componentError"))
3084 << (QVariantList() << QVariant(5));
3086 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3087 << TEST_FILE("jsimportfail/failOne.qml")
3089 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3090 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3091 << (QVariantList() << QVariant(QString()));
3093 QTest::newRow("javascript imports in an import should be private to the import scope")
3094 << TEST_FILE("jsimportfail/failTwo.qml")
3096 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3097 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3098 << (QVariantList() << QVariant(QString()));
3100 QTest::newRow("module imports in an import should be private to the import scope")
3101 << TEST_FILE("jsimportfail/failThree.qml")
3103 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3104 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3105 << (QVariantList() << QVariant(false));
3107 QTest::newRow("typenames in an import should be private to the import scope")
3108 << TEST_FILE("jsimportfail/failFour.qml")
3110 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3111 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3112 << (QVariantList() << QVariant(0));
3114 QTest::newRow("import with imports has it's own activation scope")
3115 << TEST_FILE("jsimportfail/failFive.qml")
3117 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3118 << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3119 << (QStringList() << QLatin1String("componentError"))
3120 << (QVariantList() << QVariant(0));
3122 QTest::newRow("import pragma library script")
3123 << TEST_FILE("jsimport/testImportPragmaLibrary.qml")
3126 << (QStringList() << QLatin1String("testValue"))
3127 << (QVariantList() << QVariant(31));
3129 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3130 << TEST_FILE("jsimportfail/testImportPragmaLibrary.qml")
3133 << (QStringList() << QLatin1String("testValue"))
3134 << (QVariantList() << QVariant(0));
3136 QTest::newRow("import pragma library script which has an import")
3137 << TEST_FILE("jsimport/testImportPragmaLibraryWithImports.qml")
3140 << (QStringList() << QLatin1String("testValue"))
3141 << (QVariantList() << QVariant(55));
3143 QTest::newRow("import pragma library script which has a pragma library import")
3144 << TEST_FILE("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3147 << (QStringList() << QLatin1String("testValue"))
3148 << (QVariantList() << QVariant(18));
3151 void tst_qdeclarativeecmascript::importScripts()
3153 QFETCH(QUrl, testfile);
3154 QFETCH(QString, errorMessage);
3155 QFETCH(QStringList, warningMessages);
3156 QFETCH(QStringList, propertyNames);
3157 QFETCH(QVariantList, propertyValues);
3159 QDeclarativeComponent component(&engine, testfile);
3161 if (!errorMessage.isEmpty())
3162 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3164 if (warningMessages.size())
3165 foreach (const QString &warning, warningMessages)
3166 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3168 QObject *object = component.create();
3169 if (!errorMessage.isEmpty()) {
3170 QVERIFY(object == 0);
3172 QVERIFY(object != 0);
3173 for (int i = 0; i < propertyNames.size(); ++i)
3174 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3179 void tst_qdeclarativeecmascript::scarceResources()
3181 QPixmap origPixmap(100, 100);
3182 origPixmap.fill(Qt::blue);
3184 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3185 ScarceResourceObject *eo = 0;
3186 QObject *object = 0;
3188 // in the following three cases, the instance created from the component
3189 // has a property which is a copy of the scarce resource; hence, the
3190 // resource should NOT be detached prior to deletion of the object instance,
3191 // unless the resource is destroyed explicitly.
3192 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
3193 object = component.create();
3194 QVERIFY(object != 0);
3195 QVERIFY(object->property("scarceResourceCopy").isValid());
3196 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3197 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3198 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3199 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3202 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3203 object = componentTwo.create();
3204 QVERIFY(object != 0);
3205 QVERIFY(object->property("scarceResourceCopy").isValid());
3206 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3207 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3208 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3209 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3212 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3213 object = componentThree.create();
3214 QVERIFY(object != 0);
3215 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3216 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3217 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3218 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3221 // in the following three cases, no other copy should exist in memory,
3222 // and so it should be detached (unless explicitly preserved).
3223 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3224 object = componentFour.create();
3225 QVERIFY(object != 0);
3226 QVERIFY(object->property("scarceResourceTest").isValid());
3227 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3228 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3229 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3230 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3233 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3234 object = componentFive.create();
3235 QVERIFY(object != 0);
3236 QVERIFY(object->property("scarceResourceTest").isValid());
3237 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3238 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3239 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3240 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3243 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3244 object = componentSix.create();
3245 QVERIFY(object != 0);
3246 QVERIFY(object->property("scarceResourceTest").isValid());
3247 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3248 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3249 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3250 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3253 // test that scarce resources are handled correctly for imports
3254 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3255 object = componentSeven.create();
3256 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3257 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3260 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3261 object = componentEight.create();
3262 QVERIFY(object != 0);
3263 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3264 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3267 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3268 object = componentNine.create();
3269 QVERIFY(object != 0);
3270 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3271 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3272 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3273 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3274 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3275 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3278 // test that scarce resources are handled properly in signal invocation
3279 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3280 object = componentTen.create();
3281 QVERIFY(object != 0);
3282 QObject *srsc = object->findChild<QObject*>("srsc");
3284 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3285 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3286 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3287 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3288 QMetaObject::invokeMethod(srsc, "testSignal");
3289 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3290 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3291 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3292 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3293 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3294 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3295 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3296 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3297 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3298 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3301 // test that scarce resources are handled properly from js functions in qml files
3302 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3303 object = componentEleven.create();
3304 QVERIFY(object != 0);
3305 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3306 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3307 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3308 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3309 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3310 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3311 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3312 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3313 QMetaObject::invokeMethod(object, "releaseScarceResource");
3314 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3315 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3316 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3317 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3320 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3321 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3322 object = componentTwelve.create();
3323 QVERIFY(object != 0);
3324 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3325 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3326 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3327 QString srp_name = object->property("srp_name").toString();
3328 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3329 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3330 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3331 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3332 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3333 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3334 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3338 void tst_qdeclarativeecmascript::propertyChangeSlots()
3340 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3341 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3342 QObject *object = component.create();
3343 QVERIFY(object != 0);
3346 // ensure that invalid property names fail properly.
3347 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3348 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3349 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3350 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3351 object = e1.create();
3352 QVERIFY(object == 0);
3355 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3356 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3357 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3358 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3359 object = e2.create();
3360 QVERIFY(object == 0);
3363 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3364 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3365 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3366 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3367 object = e3.create();
3368 QVERIFY(object == 0);
3371 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3372 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3373 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3374 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3375 object = e4.create();
3376 QVERIFY(object == 0);
3380 void tst_qdeclarativeecmascript::propertyVar_data()
3382 QTest::addColumn<QUrl>("qmlFile");
3385 QTest::newRow("non-bindable object subproperty changed") << TEST_FILE("propertyVar.1.qml");
3386 QTest::newRow("non-bindable object changed") << TEST_FILE("propertyVar.2.qml");
3387 QTest::newRow("primitive changed") << TEST_FILE("propertyVar.3.qml");
3388 QTest::newRow("javascript array modification") << TEST_FILE("propertyVar.4.qml");
3389 QTest::newRow("javascript map modification") << TEST_FILE("propertyVar.5.qml");
3390 QTest::newRow("javascript array assignment") << TEST_FILE("propertyVar.6.qml");
3391 QTest::newRow("javascript map assignment") << TEST_FILE("propertyVar.7.qml");
3392 QTest::newRow("literal property assignment") << TEST_FILE("propertyVar.8.qml");
3393 QTest::newRow("qobject property assignment") << TEST_FILE("propertyVar.9.qml");
3396 void tst_qdeclarativeecmascript::propertyVar()
3398 QFETCH(QUrl, qmlFile);
3400 QDeclarativeComponent component(&engine, qmlFile);
3401 QObject *object = component.create();
3402 QVERIFY(object != 0);
3404 QCOMPARE(object->property("test").toBool(), true);
3409 // Tests that we can write QVariant values to var properties from C++
3410 void tst_qdeclarativeecmascript::propertyVarCpp()
3412 QObject *object = 0;
3414 // ensure that writing to and reading from a var property from cpp works as required.
3415 // Literal values stored in var properties can be read and written as QVariants
3416 // of a specific type, whereas object values are read as QVariantMaps.
3417 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarCpp.qml"));
3418 object = component.create();
3419 QVERIFY(object != 0);
3420 // assign int to property var that currently has int assigned
3421 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3422 QCOMPARE(object->property("varBound"), QVariant(15));
3423 QCOMPARE(object->property("intBound"), QVariant(15));
3424 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3425 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3426 // assign string to property var that current has bool assigned
3427 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3428 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3429 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3430 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3431 // now enforce behaviour when accessing JavaScript objects from cpp.
3432 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3436 static void gc(QDeclarativeEngine &engine)
3438 engine.collectGarbage();
3439 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3442 void tst_qdeclarativeecmascript::propertyVarOwnership()
3444 // Referenced JS objects are not collected
3446 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.qml"));
3447 QObject *object = component.create();
3448 QVERIFY(object != 0);
3449 QCOMPARE(object->property("test").toBool(), false);
3450 QMetaObject::invokeMethod(object, "runTest");
3451 QCOMPARE(object->property("test").toBool(), true);
3454 // Referenced JS objects are not collected
3456 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.2.qml"));
3457 QObject *object = component.create();
3458 QVERIFY(object != 0);
3459 QCOMPARE(object->property("test").toBool(), false);
3460 QMetaObject::invokeMethod(object, "runTest");
3461 QCOMPARE(object->property("test").toBool(), true);
3464 // Qt objects are not collected until they've been dereferenced
3466 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.3.qml"));
3467 QObject *object = component.create();
3468 QVERIFY(object != 0);
3470 QCOMPARE(object->property("test2").toBool(), false);
3471 QCOMPARE(object->property("test2").toBool(), false);
3473 QMetaObject::invokeMethod(object, "runTest");
3474 QCOMPARE(object->property("test1").toBool(), true);
3476 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3477 QVERIFY(!referencedObject.isNull());
3479 QVERIFY(!referencedObject.isNull());
3481 QMetaObject::invokeMethod(object, "runTest2");
3482 QCOMPARE(object->property("test2").toBool(), true);
3484 QVERIFY(referencedObject.isNull());
3488 // Self reference does not prevent Qt object collection
3490 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.4.qml"));
3491 QObject *object = component.create();
3492 QVERIFY(object != 0);
3494 QCOMPARE(object->property("test").toBool(), true);
3496 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3497 QVERIFY(!referencedObject.isNull());
3499 QVERIFY(!referencedObject.isNull());
3501 QMetaObject::invokeMethod(object, "runTest");
3503 QVERIFY(referencedObject.isNull());
3509 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3511 // The childObject has a reference to a different QObject. We want to ensure
3512 // that the different item will not be cleaned up until required. IE, the childObject
3513 // has implicit ownership of the constructed QObject.
3514 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarImplicitOwnership.qml"));
3515 QObject *object = component.create();
3516 QVERIFY(object != 0);
3517 QMetaObject::invokeMethod(object, "assignCircular");
3518 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3519 QObject *rootObject = object->property("vp").value<QObject*>();
3520 QVERIFY(rootObject != 0);
3521 QObject *childObject = rootObject->findChild<QObject*>("text");
3522 QVERIFY(childObject != 0);
3523 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3524 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3525 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3526 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3527 QVERIFY(!qobjectGuard.isNull());
3528 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3529 QVERIFY(!qobjectGuard.isNull());
3530 QMetaObject::invokeMethod(object, "deassignCircular");
3531 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3532 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3536 void tst_qdeclarativeecmascript::propertyVarReparent()
3538 // ensure that nothing breaks if we re-parent objects
3539 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3540 QObject *object = component.create();
3541 QVERIFY(object != 0);
3542 QMetaObject::invokeMethod(object, "assignVarProp");
3543 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3544 QObject *rect = object->property("vp").value<QObject*>();
3545 QObject *text = rect->findChild<QObject*>("textOne");
3546 QObject *text2 = rect->findChild<QObject*>("textTwo");
3547 QWeakPointer<QObject> rectGuard(rect);
3548 QWeakPointer<QObject> textGuard(text);
3549 QWeakPointer<QObject> text2Guard(text2);
3550 QVERIFY(!rectGuard.isNull());
3551 QVERIFY(!textGuard.isNull());
3552 QVERIFY(!text2Guard.isNull());
3553 QCOMPARE(text->property("textCanary").toInt(), 11);
3554 QCOMPARE(text2->property("textCanary").toInt(), 12);
3555 // now construct an image which we will reparent.
3556 QMetaObject::invokeMethod(text2, "constructQObject");
3557 QObject *image = text2->property("vp").value<QObject*>();
3558 QWeakPointer<QObject> imageGuard(image);
3559 QVERIFY(!imageGuard.isNull());
3560 QCOMPARE(image->property("imageCanary").toInt(), 13);
3561 // now reparent the "Image" object (currently, it has JS ownership)
3562 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3563 QMetaObject::invokeMethod(text2, "deassignVp");
3564 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3565 QCOMPARE(text->property("textCanary").toInt(), 11);
3566 QCOMPARE(text2->property("textCanary").toInt(), 22);
3567 QVERIFY(!imageGuard.isNull()); // should still be alive.
3568 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3569 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3570 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3571 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3575 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3577 // sometimes reparenting can cause problems
3578 // (eg, if the ctxt is collected, varproperties are no longer available)
3579 // this test ensures that no crash occurs in that situation.
3580 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3581 QObject *object = component.create();
3582 QVERIFY(object != 0);
3583 QMetaObject::invokeMethod(object, "assignVarProp");
3584 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3585 QObject *rect = object->property("vp").value<QObject*>();
3586 QObject *text = rect->findChild<QObject*>("textOne");
3587 QObject *text2 = rect->findChild<QObject*>("textTwo");
3588 QWeakPointer<QObject> rectGuard(rect);
3589 QWeakPointer<QObject> textGuard(text);
3590 QWeakPointer<QObject> text2Guard(text2);
3591 QVERIFY(!rectGuard.isNull());
3592 QVERIFY(!textGuard.isNull());
3593 QVERIFY(!text2Guard.isNull());
3594 QCOMPARE(text->property("textCanary").toInt(), 11);
3595 QCOMPARE(text2->property("textCanary").toInt(), 12);
3596 // now construct an image which we will reparent.
3597 QMetaObject::invokeMethod(text2, "constructQObject");
3598 QObject *image = text2->property("vp").value<QObject*>();
3599 QWeakPointer<QObject> imageGuard(image);
3600 QVERIFY(!imageGuard.isNull());
3601 QCOMPARE(image->property("imageCanary").toInt(), 13);
3602 // now reparent the "Image" object (currently, it has JS ownership)
3603 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3604 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3605 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3606 QVERIFY(!imageGuard.isNull()); // should still be alive.
3607 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3609 QVERIFY(imageGuard.isNull()); // should now be dead.
3612 void tst_qdeclarativeecmascript::propertyVarCircular()
3614 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3615 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.qml"));
3616 QObject *object = component.create();
3617 QVERIFY(object != 0);
3618 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3619 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3620 QCOMPARE(object->property("canaryInt"), QVariant(5));
3621 QVariant canaryResourceVariant = object->property("canaryResource");
3622 QVERIFY(canaryResourceVariant.isValid());
3623 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3624 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3625 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3626 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3627 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3628 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3629 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3630 QCOMPARE(object->property("canaryInt"), QVariant(2));
3631 QCOMPARE(object->property("canaryResource"), QVariant(1));
3632 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3636 void tst_qdeclarativeecmascript::propertyVarCircular2()
3638 // track deletion of JS-owned parent item with Cpp-owned child
3639 // where the child has a var property referencing its parent.
3640 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3641 QObject *object = component.create();
3642 QVERIFY(object != 0);
3643 QMetaObject::invokeMethod(object, "assignCircular");
3644 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3645 QObject *rootObject = object->property("vp").value<QObject*>();
3646 QVERIFY(rootObject != 0);
3647 QObject *childObject = rootObject->findChild<QObject*>("text");
3648 QVERIFY(childObject != 0);
3649 QWeakPointer<QObject> rootObjectTracker(rootObject);
3650 QVERIFY(!rootObjectTracker.isNull());
3651 QWeakPointer<QObject> childObjectTracker(childObject);
3652 QVERIFY(!childObjectTracker.isNull());
3654 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3655 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3656 QMetaObject::invokeMethod(object, "deassignCircular");
3657 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3658 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3659 QVERIFY(childObjectTracker.isNull()); // should have been collected
3663 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3665 *(int*)(parameter) += 1;
3666 qPersistentDispose(object);
3669 void tst_qdeclarativeecmascript::propertyVarInheritance()
3671 int propertyVarWeakRefCallbackCount = 0;
3673 // enforce behaviour regarding element inheritance - ensure handle disposal.
3674 // The particular component under test here has a chain of references.
3675 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.inherit.qml"));
3676 QObject *object = component.create();
3677 QVERIFY(object != 0);
3678 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3679 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3680 // we want to be able to track when the varProperties array of the last metaobject is disposed
3681 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3682 QObject *ico5 = object->property("varProperty").value<QObject*>()->property("inheritanceVarProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3683 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3684 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
3685 v8::Persistent<v8::Value> icoCanaryHandle;
3686 v8::Persistent<v8::Value> ccoCanaryHandle;
3689 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
3690 // public function which can return us a handle to something in the varProperties array.
3691 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(41));
3692 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(41));
3693 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
3694 // as the varproperties array of each vmemo still references the resource.
3695 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3696 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3698 QVERIFY(propertyVarWeakRefCallbackCount == 0);
3700 // now we deassign the var prop, which should trigger collection of item subtrees.
3701 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3702 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3703 // ensure that there are only weak handles to the underlying varProperties array remaining.
3705 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
3707 // since there are no parent vmemo's to keep implicit references alive, and the only handles
3708 // to what remains are weak, all varProperties arrays must have been collected.
3711 void tst_qdeclarativeecmascript::propertyVarInheritance2()
3713 int propertyVarWeakRefCallbackCount = 0;
3715 // The particular component under test here does NOT have a chain of references; the
3716 // only link between rootObject and childObject is that rootObject is the parent of childObject.
3717 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3718 QObject *object = component.create();
3719 QVERIFY(object != 0);
3720 QMetaObject::invokeMethod(object, "assignCircular");
3721 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3722 QObject *rootObject = object->property("vp").value<QObject*>();
3723 QVERIFY(rootObject != 0);
3724 QObject *childObject = rootObject->findChild<QObject*>("text");
3725 QVERIFY(childObject != 0);
3726 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3727 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3728 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
3731 propertyVarWeakRefCallbackCount = 0; // reset callback count.
3732 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(58));
3733 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3735 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
3736 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3738 QMetaObject::invokeMethod(object, "deassignCircular");
3739 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3740 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
3744 // Ensure that QObject type conversion works on binding assignment
3745 void tst_qdeclarativeecmascript::elementAssign()
3747 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3749 QObject *object = component.create();
3750 QVERIFY(object != 0);
3752 QCOMPARE(object->property("test").toBool(), true);
3758 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3760 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3762 QObject *object = component.create();
3763 QVERIFY(object != 0);
3765 QCOMPARE(object->property("test").toBool(), true);
3771 void tst_qdeclarativeecmascript::objectConversion()
3773 QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
3775 QObject *object = component.create();
3776 QVERIFY(object != 0);
3778 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
3779 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
3786 void tst_qdeclarativeecmascript::booleanConversion()
3788 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3790 QObject *object = component.create();
3791 QVERIFY(object != 0);
3793 QCOMPARE(object->property("test_true1").toBool(), true);
3794 QCOMPARE(object->property("test_true2").toBool(), true);
3795 QCOMPARE(object->property("test_true3").toBool(), true);
3796 QCOMPARE(object->property("test_true4").toBool(), true);
3797 QCOMPARE(object->property("test_true5").toBool(), true);
3799 QCOMPARE(object->property("test_false1").toBool(), false);
3800 QCOMPARE(object->property("test_false2").toBool(), false);
3801 QCOMPARE(object->property("test_false3").toBool(), false);
3806 void tst_qdeclarativeecmascript::handleReferenceManagement()
3811 // Linear QObject reference
3812 QDeclarativeEngine hrmEngine;
3813 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3814 QObject *object = component.create();
3815 QVERIFY(object != 0);
3816 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3817 cro->setDtorCount(&dtorCount);
3818 QMetaObject::invokeMethod(object, "createReference");
3820 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3822 hrmEngine.collectGarbage();
3823 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3824 QCOMPARE(dtorCount, 3);
3829 // Circular QObject reference
3830 QDeclarativeEngine hrmEngine;
3831 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3832 QObject *object = component.create();
3833 QVERIFY(object != 0);
3834 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3835 cro->setDtorCount(&dtorCount);
3836 QMetaObject::invokeMethod(object, "circularReference");
3838 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3840 hrmEngine.collectGarbage();
3841 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3842 QCOMPARE(dtorCount, 3);
3847 // Linear handle reference
3848 QDeclarativeEngine hrmEngine;
3849 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3850 QObject *object = component.create();
3851 QVERIFY(object != 0);
3852 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3854 crh->setDtorCount(&dtorCount);
3855 QMetaObject::invokeMethod(object, "createReference");
3856 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3857 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3858 QVERIFY(first != 0);
3859 QVERIFY(second != 0);
3860 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3861 // now we have to reparent second and make second owned by JS.
3862 second->setParent(0);
3863 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3865 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3867 hrmEngine.collectGarbage();
3868 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3869 QCOMPARE(dtorCount, 3);
3874 // Circular handle reference
3875 QDeclarativeEngine hrmEngine;
3876 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3877 QObject *object = component.create();
3878 QVERIFY(object != 0);
3879 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3881 crh->setDtorCount(&dtorCount);
3882 QMetaObject::invokeMethod(object, "circularReference");
3883 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3884 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3885 QVERIFY(first != 0);
3886 QVERIFY(second != 0);
3887 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3888 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3889 // now we have to reparent and change ownership.
3890 first->setParent(0);
3891 second->setParent(0);
3892 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3893 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3895 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3897 hrmEngine.collectGarbage();
3898 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3899 QCOMPARE(dtorCount, 3);
3904 // multiple engine interaction - linear reference
3905 QDeclarativeEngine hrmEngine1;
3906 QDeclarativeEngine hrmEngine2;
3907 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3908 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3909 QObject *object1 = component1.create();
3910 QObject *object2 = component2.create();
3911 QVERIFY(object1 != 0);
3912 QVERIFY(object2 != 0);
3913 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3914 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3917 crh1->setDtorCount(&dtorCount);
3918 crh2->setDtorCount(&dtorCount);
3919 QMetaObject::invokeMethod(object1, "createReference");
3920 QMetaObject::invokeMethod(object2, "createReference");
3921 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3922 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3923 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3924 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3925 QVERIFY(first1 != 0);
3926 QVERIFY(second1 != 0);
3927 QVERIFY(first2 != 0);
3928 QVERIFY(second2 != 0);
3929 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3930 // now we have to reparent second2 and make second2 owned by JS.
3931 second2->setParent(0);
3932 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3934 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3935 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3938 hrmEngine1.collectGarbage();
3939 hrmEngine2.collectGarbage();
3940 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3941 QCOMPARE(dtorCount, 6);
3946 // multiple engine interaction - circular reference
3947 QDeclarativeEngine hrmEngine1;
3948 QDeclarativeEngine hrmEngine2;
3949 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3950 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3951 QObject *object1 = component1.create();
3952 QObject *object2 = component2.create();
3953 QVERIFY(object1 != 0);
3954 QVERIFY(object2 != 0);
3955 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3956 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3959 crh1->setDtorCount(&dtorCount);
3960 crh2->setDtorCount(&dtorCount);
3961 QMetaObject::invokeMethod(object1, "createReference");
3962 QMetaObject::invokeMethod(object2, "createReference");
3963 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3964 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3965 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3966 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3967 QVERIFY(first1 != 0);
3968 QVERIFY(second1 != 0);
3969 QVERIFY(first2 != 0);
3970 QVERIFY(second2 != 0);
3971 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3972 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3973 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3974 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3975 // now we have to reparent and change ownership to JS.
3976 first1->setParent(0);
3977 second1->setParent(0);
3978 first2->setParent(0);
3979 second2->setParent(0);
3980 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
3981 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3982 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3983 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3985 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3986 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
3989 hrmEngine1.collectGarbage();
3990 hrmEngine2.collectGarbage();
3991 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3992 QCOMPARE(dtorCount, 6);
3997 // multiple engine interaction - linear reference with engine deletion
3998 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
3999 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4000 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4001 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4002 QObject *object1 = component1.create();
4003 QObject *object2 = component2.create();
4004 QVERIFY(object1 != 0);
4005 QVERIFY(object2 != 0);
4006 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4007 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4010 crh1->setDtorCount(&dtorCount);
4011 crh2->setDtorCount(&dtorCount);
4012 QMetaObject::invokeMethod(object1, "createReference");
4013 QMetaObject::invokeMethod(object2, "createReference");
4014 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4015 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4016 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4017 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4018 QVERIFY(first1 != 0);
4019 QVERIFY(second1 != 0);
4020 QVERIFY(first2 != 0);
4021 QVERIFY(second2 != 0);
4022 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4023 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4024 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4025 // now we have to reparent and change ownership to JS.
4026 first1->setParent(crh1);
4027 second1->setParent(0);
4028 first2->setParent(0);
4029 second2->setParent(0);
4030 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4031 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4032 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4034 QCOMPARE(dtorCount, 0);
4037 QCOMPARE(dtorCount, 0);
4040 hrmEngine1->collectGarbage();
4041 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4042 QCOMPARE(dtorCount, 6);
4047 void tst_qdeclarativeecmascript::stringArg()
4049 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
4050 QObject *object = component.create();
4051 QVERIFY(object != 0);
4052 QMetaObject::invokeMethod(object, "success");
4053 QVERIFY(object->property("returnValue").toBool());
4055 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4056 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4057 QMetaObject::invokeMethod(object, "failure");
4058 QVERIFY(object->property("returnValue").toBool());
4063 void tst_qdeclarativeecmascript::readonlyDeclaration()
4065 QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml"));
4067 QObject *object = component.create();
4068 QVERIFY(object != 0);
4070 QCOMPARE(object->property("test").toBool(), true);
4075 Q_DECLARE_METATYPE(QList<int>)
4076 Q_DECLARE_METATYPE(QList<qreal>)
4077 Q_DECLARE_METATYPE(QList<bool>)
4078 Q_DECLARE_METATYPE(QList<QString>)
4079 Q_DECLARE_METATYPE(QList<QUrl>)
4080 void tst_qdeclarativeecmascript::sequenceConversionRead()
4083 QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml");
4084 QDeclarativeComponent component(&engine, qmlFile);
4085 QObject *object = component.create();
4086 QVERIFY(object != 0);
4087 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4090 QMetaObject::invokeMethod(object, "readSequences");
4091 QList<int> intList; intList << 1 << 2 << 3 << 4;
4092 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4093 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4094 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4095 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4096 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4097 QList<bool> boolList; boolList << true << false << true << false;
4098 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4099 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4100 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4101 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4102 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4103 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4104 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4105 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4106 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4107 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4108 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4110 QMetaObject::invokeMethod(object, "readSequenceElements");
4111 QCOMPARE(object->property("intVal").toInt(), 2);
4112 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4113 QCOMPARE(object->property("boolVal").toBool(), false);
4114 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4115 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4116 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4118 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4119 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4121 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4122 QDeclarativeProperty seqProp(seq, "intListProperty");
4123 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4124 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4125 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4127 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4128 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4134 QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml");
4135 QDeclarativeComponent component(&engine, qmlFile);
4136 QObject *object = component.create();
4137 QVERIFY(object != 0);
4138 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4141 // we haven't registered QList<QPoint> as a sequence type.
4142 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4143 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4144 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4145 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4147 QMetaObject::invokeMethod(object, "performTest");
4149 // QList<QPoint> has not been registered as a sequence type.
4150 QCOMPARE(object->property("pointListLength").toInt(), 0);
4151 QVERIFY(!object->property("pointList").isValid());
4152 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4153 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4154 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4160 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4163 QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml");
4164 QDeclarativeComponent component(&engine, qmlFile);
4165 QObject *object = component.create();
4166 QVERIFY(object != 0);
4167 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4170 QMetaObject::invokeMethod(object, "writeSequences");
4171 QCOMPARE(object->property("success").toBool(), true);
4173 QMetaObject::invokeMethod(object, "writeSequenceElements");
4174 QCOMPARE(object->property("success").toBool(), true);
4176 QMetaObject::invokeMethod(object, "writeOtherElements");
4177 QCOMPARE(object->property("success").toBool(), true);
4179 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4180 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4186 QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml");
4187 QDeclarativeComponent component(&engine, qmlFile);
4188 QObject *object = component.create();
4189 QVERIFY(object != 0);
4190 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4193 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4194 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4195 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4197 QMetaObject::invokeMethod(object, "performTest");
4199 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4200 QCOMPARE(seq->pointListProperty(), pointList);
4206 void tst_qdeclarativeecmascript::sequenceConversionArray()
4208 // ensure that in JS the returned sequences act just like normal JS Arrays.
4209 QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml");
4210 QDeclarativeComponent component(&engine, qmlFile);
4211 QObject *object = component.create();
4212 QVERIFY(object != 0);
4213 //QMetaObject::invokeMethod(object, "indexedAccess");
4214 //QVERIFY(object->property("success").toBool());
4215 //QMetaObject::invokeMethod(object, "arrayOperations");
4216 //QVERIFY(object->property("success").toBool());
4217 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4218 QVERIFY(object->property("success").toBool());
4219 //QMetaObject::invokeMethod(object, "testReferenceDeletion");
4220 //QCOMPARE(object->property("referenceDeletion").toBool(), true);
4224 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4226 // ensure that sequence conversion operations work correctly in a worker thread
4227 // and that serialisation between the main and worker thread succeeds.
4228 QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml");
4229 QDeclarativeComponent component(&engine, qmlFile);
4230 QObject *object = component.create();
4231 QVERIFY(object != 0);
4233 QMetaObject::invokeMethod(object, "testIntSequence");
4234 QTRY_VERIFY(object->property("finished").toBool());
4235 QVERIFY(object->property("success").toBool());
4237 QMetaObject::invokeMethod(object, "testQrealSequence");
4238 QTRY_VERIFY(object->property("finished").toBool());
4239 QVERIFY(object->property("success").toBool());
4241 QMetaObject::invokeMethod(object, "testBoolSequence");
4242 QTRY_VERIFY(object->property("finished").toBool());
4243 QVERIFY(object->property("success").toBool());
4245 QMetaObject::invokeMethod(object, "testStringSequence");
4246 QTRY_VERIFY(object->property("finished").toBool());
4247 QVERIFY(object->property("success").toBool());
4249 QMetaObject::invokeMethod(object, "testQStringSequence");
4250 QTRY_VERIFY(object->property("finished").toBool());
4251 QVERIFY(object->property("success").toBool());
4253 QMetaObject::invokeMethod(object, "testUrlSequence");
4254 QTRY_VERIFY(object->property("finished").toBool());
4255 QVERIFY(object->property("success").toBool());
4257 QMetaObject::invokeMethod(object, "testVariantSequence");
4258 QTRY_VERIFY(object->property("finished").toBool());
4259 QVERIFY(object->property("success").toBool());
4264 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4267 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml");
4268 QDeclarativeComponent component(&engine, qmlFile);
4269 QObject *object = component.create();
4270 QVERIFY(object != 0);
4271 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4272 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4273 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4274 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4275 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4280 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml");
4281 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4282 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4283 QDeclarativeComponent component(&engine, qmlFile);
4284 QObject *object = component.create();
4285 QVERIFY(object != 0);
4290 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4292 QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml");
4293 QDeclarativeComponent component(&engine, qmlFile);
4294 QObject *object = component.create();
4295 QVERIFY(object != 0);
4296 QMetaObject::invokeMethod(object, "testCopySequences");
4297 QCOMPARE(object->property("success").toBool(), true);
4298 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4299 QCOMPARE(object->property("success").toBool(), true);
4300 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4301 QCOMPARE(object->property("success").toBool(), true);
4305 // Test that assigning a null object works
4306 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4307 void tst_qdeclarativeecmascript::nullObjectBinding()
4309 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
4311 QObject *object = component.create();
4312 QVERIFY(object != 0);
4314 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4319 // Test that bindings don't evaluate once the engine has been destroyed
4320 void tst_qdeclarativeecmascript::deletedEngine()
4322 QDeclarativeEngine *engine = new QDeclarativeEngine;
4323 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
4325 QObject *object = component.create();
4326 QVERIFY(object != 0);
4328 QCOMPARE(object->property("a").toInt(), 39);
4329 object->setProperty("b", QVariant(9));
4330 QCOMPARE(object->property("a").toInt(), 117);
4334 QCOMPARE(object->property("a").toInt(), 117);
4335 object->setProperty("b", QVariant(10));
4336 QCOMPARE(object->property("a").toInt(), 117);
4341 // Test the crashing part of QTBUG-9705
4342 void tst_qdeclarativeecmascript::libraryScriptAssert()
4344 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
4346 QObject *object = component.create();
4347 QVERIFY(object != 0);
4352 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4354 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
4356 QObject *object = component.create();
4357 QVERIFY(object != 0);
4359 QCOMPARE(object->property("test1").toInt(), 10);
4360 QCOMPARE(object->property("test2").toInt(), 11);
4362 object->setProperty("runTest", true);
4364 QCOMPARE(object->property("test1"), QVariant());
4365 QCOMPARE(object->property("test2"), QVariant());
4371 void tst_qdeclarativeecmascript::qtbug_9792()
4373 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
4375 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4377 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4378 QVERIFY(object != 0);
4380 QString message = QString(QLatin1String("Hello world! (%1:%2)")).arg(TEST_FILE("qtbug_9792.qml").toString()).arg(4);
4381 QTest::ignoreMessage(QtDebugMsg, qPrintable(message));
4382 object->basicSignal();
4386 transientErrorsMsgCount = 0;
4387 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4389 object->basicSignal();
4391 qInstallMsgHandler(old);
4393 QCOMPARE(transientErrorsMsgCount, 0);
4398 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4399 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4401 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
4403 QObject *o = component.create();
4406 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4407 QVERIFY(nested != 0);
4409 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4412 nested = qvariant_cast<QObject *>(o->property("object"));
4413 QVERIFY(nested == 0);
4415 // If the bug is present, the next line will crash
4419 // Test that we shut down without stupid warnings
4420 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4423 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
4425 QObject *o = component.create();
4427 transientErrorsMsgCount = 0;
4428 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4432 qInstallMsgHandler(old);
4434 QCOMPARE(transientErrorsMsgCount, 0);
4439 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
4441 QObject *o = component.create();
4443 transientErrorsMsgCount = 0;
4444 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4448 qInstallMsgHandler(old);
4450 QCOMPARE(transientErrorsMsgCount, 0);
4454 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4457 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
4459 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4462 QVERIFY(o->objectProperty() != 0);
4464 o->setProperty("runTest", true);
4466 QVERIFY(o->objectProperty() == 0);
4472 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
4474 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4477 QVERIFY(o->objectProperty() == 0);
4483 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4485 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
4487 QString url = component.url().toString();
4488 QString warning = url + ":4: Unable to assign a function to a property.";
4489 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4491 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4494 QVERIFY(!o->property("a").isValid());
4499 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4501 QFETCH(QString, triggerProperty);
4503 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4504 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4506 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4508 QVERIFY(!o->property("a").isValid());
4510 o->setProperty("aNumber", QVariant(5));
4511 o->setProperty(triggerProperty.toUtf8().constData(), true);
4512 QCOMPARE(o->property("a"), QVariant(50));
4514 o->setProperty("aNumber", QVariant(10));
4515 QCOMPARE(o->property("a"), QVariant(100));
4520 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4522 QTest::addColumn<QString>("triggerProperty");
4524 QTest::newRow("assign to property") << "assignToProperty";
4525 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4527 QTest::newRow("assign to value type") << "assignToValueType";
4529 QTest::newRow("use 'this'") << "assignWithThis";
4530 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4533 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4535 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4536 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4538 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4540 QVERIFY(!o->property("a").isValid());
4542 o->setProperty("assignFuncWithoutReturn", true);
4543 QVERIFY(!o->property("a").isValid());
4545 QString url = component.url().toString();
4546 QString warning = url + ":67: Unable to assign QString to int";
4547 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4548 o->setProperty("assignWrongType", true);
4550 warning = url + ":71: Unable to assign QString to int";
4551 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4552 o->setProperty("assignWrongTypeToValueType", true);
4557 void tst_qdeclarativeecmascript::eval()
4559 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
4561 QObject *o = component.create();
4564 QCOMPARE(o->property("test1").toBool(), true);
4565 QCOMPARE(o->property("test2").toBool(), true);
4566 QCOMPARE(o->property("test3").toBool(), true);
4567 QCOMPARE(o->property("test4").toBool(), true);
4568 QCOMPARE(o->property("test5").toBool(), true);
4573 void tst_qdeclarativeecmascript::function()
4575 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
4577 QObject *o = component.create();
4580 QCOMPARE(o->property("test1").toBool(), true);
4581 QCOMPARE(o->property("test2").toBool(), true);
4582 QCOMPARE(o->property("test3").toBool(), true);
4587 // Test the "Qt.include" method
4588 void tst_qdeclarativeecmascript::include()
4590 // Non-library relative include
4592 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
4593 QObject *o = component.create();
4596 QCOMPARE(o->property("test0").toInt(), 99);
4597 QCOMPARE(o->property("test1").toBool(), true);
4598 QCOMPARE(o->property("test2").toBool(), true);
4599 QCOMPARE(o->property("test2_1").toBool(), true);
4600 QCOMPARE(o->property("test3").toBool(), true);
4601 QCOMPARE(o->property("test3_1").toBool(), true);
4606 // Library relative include
4608 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
4609 QObject *o = component.create();
4612 QCOMPARE(o->property("test0").toInt(), 99);
4613 QCOMPARE(o->property("test1").toBool(), true);
4614 QCOMPARE(o->property("test2").toBool(), true);
4615 QCOMPARE(o->property("test2_1").toBool(), true);
4616 QCOMPARE(o->property("test3").toBool(), true);
4617 QCOMPARE(o->property("test3_1").toBool(), true);
4624 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
4625 QObject *o = component.create();
4628 QCOMPARE(o->property("test1").toBool(), true);
4629 QCOMPARE(o->property("test2").toBool(), true);
4630 QCOMPARE(o->property("test3").toBool(), true);
4631 QCOMPARE(o->property("test4").toBool(), true);
4632 QCOMPARE(o->property("test5").toBool(), true);
4633 QCOMPARE(o->property("test6").toBool(), true);
4638 // Including file with ".pragma library"
4640 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
4641 QObject *o = component.create();
4643 QCOMPARE(o->property("test1").toInt(), 100);
4650 TestHTTPServer server(8111);
4651 QVERIFY(server.isValid());
4652 server.serveDirectory(TESTDATA(""));
4654 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
4655 QObject *o = component.create();
4658 QTRY_VERIFY(o->property("done").toBool() == true);
4659 QTRY_VERIFY(o->property("done2").toBool() == true);
4661 QCOMPARE(o->property("test1").toBool(), true);
4662 QCOMPARE(o->property("test2").toBool(), true);
4663 QCOMPARE(o->property("test3").toBool(), true);
4664 QCOMPARE(o->property("test4").toBool(), true);
4665 QCOMPARE(o->property("test5").toBool(), true);
4667 QCOMPARE(o->property("test6").toBool(), true);
4668 QCOMPARE(o->property("test7").toBool(), true);
4669 QCOMPARE(o->property("test8").toBool(), true);
4670 QCOMPARE(o->property("test9").toBool(), true);
4671 QCOMPARE(o->property("test10").toBool(), true);
4678 TestHTTPServer server(8111);
4679 QVERIFY(server.isValid());
4680 server.serveDirectory(TESTDATA(""));
4682 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
4683 QObject *o = component.create();
4686 QTRY_VERIFY(o->property("done").toBool() == true);
4688 QCOMPARE(o->property("test1").toBool(), true);
4689 QCOMPARE(o->property("test2").toBool(), true);
4690 QCOMPARE(o->property("test3").toBool(), true);
4696 void tst_qdeclarativeecmascript::signalHandlers()
4698 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
4699 QObject *o = component.create();
4702 QVERIFY(o->property("count").toInt() == 0);
4703 QMetaObject::invokeMethod(o, "testSignalCall");
4704 QCOMPARE(o->property("count").toInt(), 1);
4706 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
4707 QCOMPARE(o->property("count").toInt(), 1);
4708 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
4710 QVERIFY(o->property("funcCount").toInt() == 0);
4711 QMetaObject::invokeMethod(o, "testSignalConnection");
4712 QCOMPARE(o->property("funcCount").toInt(), 1);
4714 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
4715 QCOMPARE(o->property("funcCount").toInt(), 2);
4717 QMetaObject::invokeMethod(o, "testSignalDefined");
4718 QCOMPARE(o->property("definedResult").toBool(), true);
4720 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
4721 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
4726 void tst_qdeclarativeecmascript::qtbug_10696()
4728 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
4729 QObject *o = component.create();
4734 void tst_qdeclarativeecmascript::qtbug_11606()
4736 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
4737 QObject *o = component.create();
4739 QCOMPARE(o->property("test").toBool(), true);
4743 void tst_qdeclarativeecmascript::qtbug_11600()
4745 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
4746 QObject *o = component.create();
4748 QCOMPARE(o->property("test").toBool(), true);
4752 // Reading and writing non-scriptable properties should fail
4753 void tst_qdeclarativeecmascript::nonscriptable()
4755 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
4756 QObject *o = component.create();
4758 QCOMPARE(o->property("readOk").toBool(), true);
4759 QCOMPARE(o->property("writeOk").toBool(), true);
4763 // deleteLater() should not be callable from QML
4764 void tst_qdeclarativeecmascript::deleteLater()
4766 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
4767 QObject *o = component.create();
4769 QCOMPARE(o->property("test").toBool(), true);
4773 void tst_qdeclarativeecmascript::in()
4775 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
4776 QObject *o = component.create();
4778 QCOMPARE(o->property("test1").toBool(), true);
4779 QCOMPARE(o->property("test2").toBool(), true);
4783 void tst_qdeclarativeecmascript::typeOf()
4785 QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml"));
4786 QObject *o = component.create();
4788 QEXPECT_FAIL("", "QTBUG-21864", Abort);
4789 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
4790 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
4791 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
4792 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
4793 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
4794 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
4795 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
4796 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
4797 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
4802 void tst_qdeclarativeecmascript::sharedAttachedObject()
4804 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
4805 QObject *o = component.create();
4807 QCOMPARE(o->property("test1").toBool(), true);
4808 QCOMPARE(o->property("test2").toBool(), true);
4813 void tst_qdeclarativeecmascript::objectName()
4815 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
4816 QObject *o = component.create();
4819 QCOMPARE(o->property("test1").toString(), QString("hello"));
4820 QCOMPARE(o->property("test2").toString(), QString("ell"));
4822 o->setObjectName("world");
4824 QCOMPARE(o->property("test1").toString(), QString("world"));
4825 QCOMPARE(o->property("test2").toString(), QString("orl"));
4830 void tst_qdeclarativeecmascript::writeRemovesBinding()
4832 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
4833 QObject *o = component.create();
4836 QCOMPARE(o->property("test").toBool(), true);
4841 // Test bindings assigned to alias properties actually assign to the alias' target
4842 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
4844 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4845 QObject *o = component.create();
4848 QCOMPARE(o->property("test").toBool(), true);
4853 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4854 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4857 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4858 QObject *o = component.create();
4861 QCOMPARE(o->property("test").toBool(), true);
4867 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4868 QObject *o = component.create();
4871 QCOMPARE(o->property("test").toBool(), true);
4877 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4878 QObject *o = component.create();
4881 QCOMPARE(o->property("test").toBool(), true);
4887 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4888 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4891 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4892 QObject *o = component.create();
4895 QCOMPARE(o->property("test").toBool(), true);
4901 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
4902 QObject *o = component.create();
4905 QCOMPARE(o->property("test").toBool(), true);
4911 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
4912 QObject *o = component.create();
4915 QCOMPARE(o->property("test").toBool(), true);
4921 // Allow an alais to a composite element
4923 void tst_qdeclarativeecmascript::aliasToCompositeElement()
4925 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
4927 QObject *object = component.create();
4928 QVERIFY(object != 0);
4933 void tst_qdeclarativeecmascript::qtbug_20344()
4935 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_20344.qml"));
4937 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
4938 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
4940 QObject *object = component.create();
4941 QVERIFY(object != 0);
4946 void tst_qdeclarativeecmascript::revisionErrors()
4949 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
4950 QString url = component.url().toString();
4952 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4953 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
4954 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
4956 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4957 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4958 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4959 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4960 QVERIFY(object != 0);
4964 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
4965 QString url = component.url().toString();
4967 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
4968 // method2, prop2 from MyRevisionedClass not available
4969 // method4, prop4 from MyRevisionedSubclass not available
4970 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4971 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
4972 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
4973 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
4974 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
4976 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4977 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4978 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4979 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
4980 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
4981 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4982 QVERIFY(object != 0);
4986 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
4987 QString url = component.url().toString();
4989 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
4990 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
4991 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
4992 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
4993 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
4994 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4995 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4996 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4997 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4998 QVERIFY(object != 0);
5003 void tst_qdeclarativeecmascript::revision()
5006 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
5007 QString url = component.url().toString();
5009 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5010 QVERIFY(object != 0);
5014 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
5015 QString url = component.url().toString();
5017 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5018 QVERIFY(object != 0);
5022 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
5023 QString url = component.url().toString();
5025 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5026 QVERIFY(object != 0);
5029 // Test that non-root classes can resolve revisioned methods
5031 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
5033 QObject *object = component.create();
5034 QVERIFY(object != 0);
5035 QCOMPARE(object->property("test").toReal(), 11.);
5040 void tst_qdeclarativeecmascript::realToInt()
5042 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
5043 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5044 QVERIFY(object != 0);
5046 QMetaObject::invokeMethod(object, "test1");
5047 QCOMPARE(object->value(), int(4));
5048 QMetaObject::invokeMethod(object, "test2");
5049 QCOMPARE(object->value(), int(8));
5051 void tst_qdeclarativeecmascript::dynamicString()
5053 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
5054 QObject *object = component.create();
5055 QVERIFY(object != 0);
5056 QCOMPARE(object->property("stringProperty").toString(),
5057 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5060 void tst_qdeclarativeecmascript::automaticSemicolon()
5062 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
5063 QObject *object = component.create();
5064 QVERIFY(object != 0);
5067 void tst_qdeclarativeecmascript::unaryExpression()
5069 QDeclarativeComponent component(&engine, TEST_FILE("unaryExpression.qml"));
5070 QObject *object = component.create();
5071 QVERIFY(object != 0);
5074 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5075 void tst_qdeclarativeecmascript::doubleEvaluate()
5077 QDeclarativeComponent component(&engine, TEST_FILE("doubleEvaluate.qml"));
5078 QObject *object = component.create();
5079 QVERIFY(object != 0);
5080 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5082 QCOMPARE(wc->count(), 1);
5084 wc->setProperty("x", 9);
5086 QCOMPARE(wc->count(), 2);
5091 static QStringList messages;
5092 static void captureMsgHandler(QtMsgType, const char *msg)
5094 messages.append(QLatin1String(msg));
5097 void tst_qdeclarativeecmascript::nonNotifyable()
5099 QV4Compiler::enableV4(false);
5100 QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml"));
5101 QV4Compiler::enableV4(true);
5103 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5105 QObject *object = component.create();
5106 qInstallMsgHandler(old);
5108 QVERIFY(object != 0);
5110 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5111 component.url().toString() +
5112 QLatin1String(":5 depends on non-NOTIFYable properties:");
5113 QString expected2 = QLatin1String(" ") +
5114 QLatin1String(object->metaObject()->className()) +
5115 QLatin1String("::value");
5117 QCOMPARE(messages.length(), 2);
5118 QCOMPARE(messages.at(0), expected1);
5119 QCOMPARE(messages.at(1), expected2);
5124 void tst_qdeclarativeecmascript::forInLoop()
5126 QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
5127 QObject *object = component.create();
5128 QVERIFY(object != 0);
5130 QMetaObject::invokeMethod(object, "listProperty");
5132 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5133 QCOMPARE(r.size(), 3);
5134 QCOMPARE(r[0],QLatin1String("0=obj1"));
5135 QCOMPARE(r[1],QLatin1String("1=obj2"));
5136 QCOMPARE(r[2],QLatin1String("2=obj3"));
5138 //TODO: should test for in loop for other objects (such as QObjects) as well.
5143 // An object the binding depends on is deleted while the binding is still running
5144 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5146 QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml"));
5147 QObject *object = component.create();
5148 QVERIFY(object != 0);
5152 void tst_qdeclarativeecmascript::qtbug_22679()
5155 object.setStringProperty(QLatin1String("Please work correctly"));
5156 engine.rootContext()->setContextProperty("contextProp", &object);
5158 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22679.qml"));
5159 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5160 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5162 QObject *o = component.create();
5164 QCOMPARE(warningsSpy.count(), 0);
5168 QTEST_MAIN(tst_qdeclarativeecmascript)
5170 #include "tst_qdeclarativeecmascript.moc"