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();
184 void dynamicCreationCrash();
185 void dynamicCreationOwnership();
187 void nullObjectBinding();
188 void deletedEngine();
189 void libraryScriptAssert();
190 void variantsAssignedUndefined();
192 void qtcreatorbug_1289();
193 void noSpuriousWarningsAtShutdown();
194 void canAssignNullToQObject();
195 void functionAssignment_fromBinding();
196 void functionAssignment_fromJS();
197 void functionAssignment_fromJS_data();
198 void functionAssignmentfromJS_invalid();
204 void nonscriptable();
208 void sharedAttachedObject();
210 void writeRemovesBinding();
211 void aliasBindingsAssignCorrectly();
212 void aliasBindingsOverrideTarget();
213 void aliasWritesOverrideBindings();
214 void aliasToCompositeElement();
216 void dynamicString();
218 void signalHandlers();
219 void doubleEvaluate();
221 void nonNotifyable();
222 void deleteWhileBindingRunning();
223 void callQtInvokables();
224 void invokableObjectArg();
225 void invokableObjectRet();
228 void qtbug_22843_data();
230 void revisionErrors();
233 void automaticSemicolon();
234 void unaryExpression();
237 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
238 QDeclarativeEngine engine;
241 void tst_qdeclarativeecmascript::initTestCase() { registerTypes(); }
243 void tst_qdeclarativeecmascript::assignBasicTypes()
246 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.qml"));
247 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
248 QVERIFY(object != 0);
249 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
250 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
251 QCOMPARE(object->stringProperty(), QString("Hello World!"));
252 QCOMPARE(object->uintProperty(), uint(10));
253 QCOMPARE(object->intProperty(), -19);
254 QCOMPARE((float)object->realProperty(), float(23.2));
255 QCOMPARE((float)object->doubleProperty(), float(-19.75));
256 QCOMPARE((float)object->floatProperty(), float(8.5));
257 QCOMPARE(object->colorProperty(), QColor("red"));
258 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
259 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
260 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
261 QCOMPARE(object->pointProperty(), QPoint(99,13));
262 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
263 QCOMPARE(object->sizeProperty(), QSize(99, 13));
264 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
265 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
266 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
267 QCOMPARE(object->boolProperty(), true);
268 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
269 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
270 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
274 QDeclarativeComponent component(&engine, TEST_FILE("assignBasicTypes.2.qml"));
275 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
276 QVERIFY(object != 0);
277 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
278 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
279 QCOMPARE(object->stringProperty(), QString("Hello World!"));
280 QCOMPARE(object->uintProperty(), uint(10));
281 QCOMPARE(object->intProperty(), -19);
282 QCOMPARE((float)object->realProperty(), float(23.2));
283 QCOMPARE((float)object->doubleProperty(), float(-19.75));
284 QCOMPARE((float)object->floatProperty(), float(8.5));
285 QCOMPARE(object->colorProperty(), QColor("red"));
286 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
287 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
288 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
289 QCOMPARE(object->pointProperty(), QPoint(99,13));
290 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
291 QCOMPARE(object->sizeProperty(), QSize(99, 13));
292 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
293 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
294 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
295 QCOMPARE(object->boolProperty(), true);
296 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
297 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
298 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
303 void tst_qdeclarativeecmascript::idShortcutInvalidates()
306 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.qml"));
307 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
308 QVERIFY(object != 0);
309 QVERIFY(object->objectProperty() != 0);
310 delete object->objectProperty();
311 QVERIFY(object->objectProperty() == 0);
316 QDeclarativeComponent component(&engine, TEST_FILE("idShortcutInvalidates.1.qml"));
317 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
318 QVERIFY(object != 0);
319 QVERIFY(object->objectProperty() != 0);
320 delete object->objectProperty();
321 QVERIFY(object->objectProperty() == 0);
326 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
329 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.1.qml"));
330 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
331 QVERIFY(object != 0);
332 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
336 QDeclarativeComponent component(&engine, TEST_FILE("boolPropertiesEvaluateAsBool.2.qml"));
337 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
338 QVERIFY(object != 0);
339 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
344 void tst_qdeclarativeecmascript::signalAssignment()
347 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.1.qml"));
348 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
349 QVERIFY(object != 0);
350 QCOMPARE(object->string(), QString());
351 emit object->basicSignal();
352 QCOMPARE(object->string(), QString("pass"));
357 QDeclarativeComponent component(&engine, TEST_FILE("signalAssignment.2.qml"));
358 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
359 QVERIFY(object != 0);
360 QCOMPARE(object->string(), QString());
361 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
362 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
367 void tst_qdeclarativeecmascript::methods()
370 QDeclarativeComponent component(&engine, TEST_FILE("methods.1.qml"));
371 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
372 QVERIFY(object != 0);
373 QCOMPARE(object->methodCalled(), false);
374 QCOMPARE(object->methodIntCalled(), false);
375 emit object->basicSignal();
376 QCOMPARE(object->methodCalled(), true);
377 QCOMPARE(object->methodIntCalled(), false);
382 QDeclarativeComponent component(&engine, TEST_FILE("methods.2.qml"));
383 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
384 QVERIFY(object != 0);
385 QCOMPARE(object->methodCalled(), false);
386 QCOMPARE(object->methodIntCalled(), false);
387 emit object->basicSignal();
388 QCOMPARE(object->methodCalled(), false);
389 QCOMPARE(object->methodIntCalled(), true);
394 QDeclarativeComponent component(&engine, TEST_FILE("methods.3.qml"));
395 QObject *object = component.create();
396 QVERIFY(object != 0);
397 QCOMPARE(object->property("test").toInt(), 19);
402 QDeclarativeComponent component(&engine, TEST_FILE("methods.4.qml"));
403 QObject *object = component.create();
404 QVERIFY(object != 0);
405 QCOMPARE(object->property("test").toInt(), 19);
406 QCOMPARE(object->property("test2").toInt(), 17);
407 QCOMPARE(object->property("test3").toInt(), 16);
412 QDeclarativeComponent component(&engine, TEST_FILE("methods.5.qml"));
413 QObject *object = component.create();
414 QVERIFY(object != 0);
415 QCOMPARE(object->property("test").toInt(), 9);
420 void tst_qdeclarativeecmascript::bindingLoop()
422 QDeclarativeComponent component(&engine, TEST_FILE("bindingLoop.qml"));
423 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
424 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
425 QObject *object = component.create();
426 QVERIFY(object != 0);
430 void tst_qdeclarativeecmascript::basicExpressions_data()
432 QTest::addColumn<QString>("expression");
433 QTest::addColumn<QVariant>("result");
434 QTest::addColumn<bool>("nest");
436 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
437 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
438 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
439 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
440 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
441 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
442 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
443 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
444 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
445 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
446 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
447 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
448 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
449 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
450 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
451 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
452 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
453 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
454 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
457 void tst_qdeclarativeecmascript::basicExpressions()
459 QFETCH(QString, expression);
460 QFETCH(QVariant, result);
466 MyDefaultObject1 default1;
467 MyDefaultObject3 default3;
468 object1.setStringProperty("Object1");
469 object2.setStringProperty("Object2");
470 object3.setStringProperty("Object3");
472 QDeclarativeContext context(engine.rootContext());
473 QDeclarativeContext nestedContext(&context);
475 context.setContextObject(&default1);
476 context.setContextProperty("a", QVariant(1944));
477 context.setContextProperty("b", QVariant("Milk"));
478 context.setContextProperty("object", &object1);
479 context.setContextProperty("objectOverride", &object2);
480 nestedContext.setContextObject(&default3);
481 nestedContext.setContextProperty("b", QVariant("Cow"));
482 nestedContext.setContextProperty("objectOverride", &object3);
483 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
485 MyExpression expr(nest?&nestedContext:&context, expression);
486 QCOMPARE(expr.evaluate(), result);
489 void tst_qdeclarativeecmascript::arrayExpressions()
495 QDeclarativeContext context(engine.rootContext());
496 context.setContextProperty("a", &obj1);
497 context.setContextProperty("b", &obj2);
498 context.setContextProperty("c", &obj3);
500 MyExpression expr(&context, "[a, b, c, 10]");
501 QVariant result = expr.evaluate();
502 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
503 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
504 QCOMPARE(list.count(), 4);
505 QCOMPARE(list.at(0), &obj1);
506 QCOMPARE(list.at(1), &obj2);
507 QCOMPARE(list.at(2), &obj3);
508 QCOMPARE(list.at(3), (QObject *)0);
511 // Tests that modifying a context property will reevaluate expressions
512 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
514 QDeclarativeContext context(engine.rootContext());
517 MyQmlObject *object3 = new MyQmlObject;
519 object1.setStringProperty("Hello");
520 object2.setStringProperty("World");
522 context.setContextProperty("testProp", QVariant(1));
523 context.setContextProperty("testObj", &object1);
524 context.setContextProperty("testObj2", object3);
527 MyExpression expr(&context, "testProp + 1");
528 QCOMPARE(expr.changed, false);
529 QCOMPARE(expr.evaluate(), QVariant(2));
531 context.setContextProperty("testProp", QVariant(2));
532 QCOMPARE(expr.changed, true);
533 QCOMPARE(expr.evaluate(), QVariant(3));
537 MyExpression expr(&context, "testProp + testProp + testProp");
538 QCOMPARE(expr.changed, false);
539 QCOMPARE(expr.evaluate(), QVariant(6));
541 context.setContextProperty("testProp", QVariant(4));
542 QCOMPARE(expr.changed, true);
543 QCOMPARE(expr.evaluate(), QVariant(12));
547 MyExpression expr(&context, "testObj.stringProperty");
548 QCOMPARE(expr.changed, false);
549 QCOMPARE(expr.evaluate(), QVariant("Hello"));
551 context.setContextProperty("testObj", &object2);
552 QCOMPARE(expr.changed, true);
553 QCOMPARE(expr.evaluate(), QVariant("World"));
557 MyExpression expr(&context, "testObj.stringProperty /**/");
558 QCOMPARE(expr.changed, false);
559 QCOMPARE(expr.evaluate(), QVariant("World"));
561 context.setContextProperty("testObj", &object1);
562 QCOMPARE(expr.changed, true);
563 QCOMPARE(expr.evaluate(), QVariant("Hello"));
567 MyExpression expr(&context, "testObj2");
568 QCOMPARE(expr.changed, false);
569 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
575 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
577 QDeclarativeContext context(engine.rootContext());
581 context.setContextProperty("testObj", &object1);
583 object1.setStringProperty(QLatin1String("Hello"));
584 object2.setStringProperty(QLatin1String("Dog"));
585 object3.setStringProperty(QLatin1String("Cat"));
588 MyExpression expr(&context, "testObj.stringProperty");
589 QCOMPARE(expr.changed, false);
590 QCOMPARE(expr.evaluate(), QVariant("Hello"));
592 object1.setStringProperty(QLatin1String("World"));
593 QCOMPARE(expr.changed, true);
594 QCOMPARE(expr.evaluate(), QVariant("World"));
598 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
599 QCOMPARE(expr.changed, false);
600 QCOMPARE(expr.evaluate(), QVariant());
602 object1.setObjectProperty(&object2);
603 QCOMPARE(expr.changed, true);
604 expr.changed = false;
605 QCOMPARE(expr.evaluate(), QVariant("Dog"));
607 object1.setObjectProperty(&object3);
608 QCOMPARE(expr.changed, true);
609 expr.changed = false;
610 QCOMPARE(expr.evaluate(), QVariant("Cat"));
612 object1.setObjectProperty(0);
613 QCOMPARE(expr.changed, true);
614 expr.changed = false;
615 QCOMPARE(expr.evaluate(), QVariant());
617 object1.setObjectProperty(&object3);
618 QCOMPARE(expr.changed, true);
619 expr.changed = false;
620 QCOMPARE(expr.evaluate(), QVariant("Cat"));
622 object3.setStringProperty("Donkey");
623 QCOMPARE(expr.changed, true);
624 expr.changed = false;
625 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
629 void tst_qdeclarativeecmascript::deferredProperties()
631 QDeclarativeComponent component(&engine, TEST_FILE("deferredProperties.qml"));
632 MyDeferredObject *object =
633 qobject_cast<MyDeferredObject *>(component.create());
634 QVERIFY(object != 0);
635 QCOMPARE(object->value(), 0);
636 QVERIFY(object->objectProperty() == 0);
637 QVERIFY(object->objectProperty2() != 0);
638 qmlExecuteDeferred(object);
639 QCOMPARE(object->value(), 10);
640 QVERIFY(object->objectProperty() != 0);
641 MyQmlObject *qmlObject =
642 qobject_cast<MyQmlObject *>(object->objectProperty());
643 QVERIFY(qmlObject != 0);
644 QCOMPARE(qmlObject->value(), 10);
645 object->setValue(19);
646 QCOMPARE(qmlObject->value(), 19);
651 // Check errors on deferred properties are correctly emitted
652 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
654 QDeclarativeComponent component(&engine, TEST_FILE("deferredPropertiesErrors.qml"));
655 MyDeferredObject *object =
656 qobject_cast<MyDeferredObject *>(component.create());
657 QVERIFY(object != 0);
658 QCOMPARE(object->value(), 0);
659 QVERIFY(object->objectProperty() == 0);
660 QVERIFY(object->objectProperty2() == 0);
662 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
663 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
665 qmlExecuteDeferred(object);
670 void tst_qdeclarativeecmascript::extensionObjects()
672 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjects.qml"));
673 MyExtendedObject *object =
674 qobject_cast<MyExtendedObject *>(component.create());
675 QVERIFY(object != 0);
676 QCOMPARE(object->baseProperty(), 13);
677 QCOMPARE(object->coreProperty(), 9);
678 object->setProperty("extendedProperty", QVariant(11));
679 object->setProperty("baseExtendedProperty", QVariant(92));
680 QCOMPARE(object->coreProperty(), 11);
681 QCOMPARE(object->baseProperty(), 92);
683 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
685 QCOMPARE(nested->baseProperty(), 13);
686 QCOMPARE(nested->coreProperty(), 9);
687 nested->setProperty("extendedProperty", QVariant(11));
688 nested->setProperty("baseExtendedProperty", QVariant(92));
689 QCOMPARE(nested->coreProperty(), 11);
690 QCOMPARE(nested->baseProperty(), 92);
695 void tst_qdeclarativeecmascript::overrideExtensionProperties()
697 QDeclarativeComponent component(&engine, TEST_FILE("extensionObjectsPropertyOverride.qml"));
698 OverrideDefaultPropertyObject *object =
699 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
700 QVERIFY(object != 0);
701 QVERIFY(object->secondProperty() != 0);
702 QVERIFY(object->firstProperty() == 0);
707 void tst_qdeclarativeecmascript::attachedProperties()
710 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.qml"));
711 QObject *object = component.create();
712 QVERIFY(object != 0);
713 QCOMPARE(object->property("a").toInt(), 19);
714 QCOMPARE(object->property("b").toInt(), 19);
715 QCOMPARE(object->property("c").toInt(), 19);
716 QCOMPARE(object->property("d").toInt(), 19);
721 QDeclarativeComponent component(&engine, TEST_FILE("attachedProperty.2.qml"));
722 QObject *object = component.create();
723 QVERIFY(object != 0);
724 QCOMPARE(object->property("a").toInt(), 26);
725 QCOMPARE(object->property("b").toInt(), 26);
726 QCOMPARE(object->property("c").toInt(), 26);
727 QCOMPARE(object->property("d").toInt(), 26);
733 QDeclarativeComponent component(&engine, TEST_FILE("writeAttachedProperty.qml"));
734 QObject *object = component.create();
735 QVERIFY(object != 0);
737 QMetaObject::invokeMethod(object, "writeValue2");
739 MyQmlAttachedObject *attached =
740 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
741 QVERIFY(attached != 0);
743 QCOMPARE(attached->value2(), 9);
748 void tst_qdeclarativeecmascript::enums()
752 QDeclarativeComponent component(&engine, TEST_FILE("enums.1.qml"));
753 QObject *object = component.create();
754 QVERIFY(object != 0);
756 QCOMPARE(object->property("a").toInt(), 0);
757 QCOMPARE(object->property("b").toInt(), 1);
758 QCOMPARE(object->property("c").toInt(), 2);
759 QCOMPARE(object->property("d").toInt(), 3);
760 QCOMPARE(object->property("e").toInt(), 0);
761 QCOMPARE(object->property("f").toInt(), 1);
762 QCOMPARE(object->property("g").toInt(), 2);
763 QCOMPARE(object->property("h").toInt(), 3);
764 QCOMPARE(object->property("i").toInt(), 19);
765 QCOMPARE(object->property("j").toInt(), 19);
769 // Non-existent enums
771 QDeclarativeComponent component(&engine, TEST_FILE("enums.2.qml"));
773 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
774 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
775 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
776 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
778 QObject *object = component.create();
779 QVERIFY(object != 0);
780 QCOMPARE(object->property("a").toInt(), 0);
781 QCOMPARE(object->property("b").toInt(), 0);
787 void tst_qdeclarativeecmascript::valueTypeFunctions()
789 QDeclarativeComponent component(&engine, TEST_FILE("valueTypeFunctions.qml"));
790 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
792 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
793 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
799 Tests that writing a constant to a property with a binding on it disables the
802 void tst_qdeclarativeecmascript::constantsOverrideBindings()
806 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.1.qml"));
807 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
808 QVERIFY(object != 0);
810 QCOMPARE(object->property("c2").toInt(), 0);
811 object->setProperty("c1", QVariant(9));
812 QCOMPARE(object->property("c2").toInt(), 9);
814 emit object->basicSignal();
816 QCOMPARE(object->property("c2").toInt(), 13);
817 object->setProperty("c1", QVariant(8));
818 QCOMPARE(object->property("c2").toInt(), 13);
823 // During construction
825 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.2.qml"));
826 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
827 QVERIFY(object != 0);
829 QCOMPARE(object->property("c1").toInt(), 0);
830 QCOMPARE(object->property("c2").toInt(), 10);
831 object->setProperty("c1", QVariant(9));
832 QCOMPARE(object->property("c1").toInt(), 9);
833 QCOMPARE(object->property("c2").toInt(), 10);
841 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.3.qml"));
842 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
843 QVERIFY(object != 0);
845 QCOMPARE(object->property("c2").toInt(), 0);
846 object->setProperty("c1", QVariant(9));
847 QCOMPARE(object->property("c2").toInt(), 9);
849 object->setProperty("c2", QVariant(13));
850 QCOMPARE(object->property("c2").toInt(), 13);
851 object->setProperty("c1", QVariant(7));
852 QCOMPARE(object->property("c1").toInt(), 7);
853 QCOMPARE(object->property("c2").toInt(), 13);
861 QDeclarativeComponent component(&engine, TEST_FILE("constantsOverrideBindings.4.qml"));
862 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
863 QVERIFY(object != 0);
865 QCOMPARE(object->property("c1").toInt(), 0);
866 QCOMPARE(object->property("c3").toInt(), 10);
867 object->setProperty("c1", QVariant(9));
868 QCOMPARE(object->property("c1").toInt(), 9);
869 QCOMPARE(object->property("c3").toInt(), 10);
876 Tests that assigning a binding to a property that already has a binding causes
877 the original binding to be disabled.
879 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
881 QDeclarativeComponent component(&engine,
882 TEST_FILE("outerBindingOverridesInnerBinding.qml"));
883 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
884 QVERIFY(object != 0);
886 QCOMPARE(object->property("c1").toInt(), 0);
887 QCOMPARE(object->property("c2").toInt(), 0);
888 QCOMPARE(object->property("c3").toInt(), 0);
890 object->setProperty("c1", QVariant(9));
891 QCOMPARE(object->property("c1").toInt(), 9);
892 QCOMPARE(object->property("c2").toInt(), 0);
893 QCOMPARE(object->property("c3").toInt(), 0);
895 object->setProperty("c3", QVariant(8));
896 QCOMPARE(object->property("c1").toInt(), 9);
897 QCOMPARE(object->property("c2").toInt(), 8);
898 QCOMPARE(object->property("c3").toInt(), 8);
904 Access a non-existent attached object.
906 Tests for a regression where this used to crash.
908 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
910 QDeclarativeComponent component(&engine, TEST_FILE("nonExistentAttachedObject.qml"));
912 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
913 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
915 QObject *object = component.create();
916 QVERIFY(object != 0);
921 void tst_qdeclarativeecmascript::scope()
924 QDeclarativeComponent component(&engine, TEST_FILE("scope.qml"));
925 QObject *object = component.create();
926 QVERIFY(object != 0);
928 QCOMPARE(object->property("test1").toInt(), 1);
929 QCOMPARE(object->property("test2").toInt(), 2);
930 QCOMPARE(object->property("test3").toString(), QString("1Test"));
931 QCOMPARE(object->property("test4").toString(), QString("2Test"));
932 QCOMPARE(object->property("test5").toInt(), 1);
933 QCOMPARE(object->property("test6").toInt(), 1);
934 QCOMPARE(object->property("test7").toInt(), 2);
935 QCOMPARE(object->property("test8").toInt(), 2);
936 QCOMPARE(object->property("test9").toInt(), 1);
937 QCOMPARE(object->property("test10").toInt(), 3);
943 QDeclarativeComponent component(&engine, TEST_FILE("scope.2.qml"));
944 QObject *object = component.create();
945 QVERIFY(object != 0);
947 QCOMPARE(object->property("test1").toInt(), 19);
948 QCOMPARE(object->property("test2").toInt(), 19);
949 QCOMPARE(object->property("test3").toInt(), 14);
950 QCOMPARE(object->property("test4").toInt(), 14);
951 QCOMPARE(object->property("test5").toInt(), 24);
952 QCOMPARE(object->property("test6").toInt(), 24);
958 QDeclarativeComponent component(&engine, TEST_FILE("scope.3.qml"));
959 QObject *object = component.create();
960 QVERIFY(object != 0);
962 QCOMPARE(object->property("test1").toBool(), true);
963 QCOMPARE(object->property("test2").toBool(), true);
964 QCOMPARE(object->property("test3").toBool(), true);
969 // Signal argument scope
971 QDeclarativeComponent component(&engine, TEST_FILE("scope.4.qml"));
972 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
973 QVERIFY(object != 0);
975 QCOMPARE(object->property("test").toInt(), 0);
976 QCOMPARE(object->property("test2").toString(), QString());
978 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
980 QCOMPARE(object->property("test").toInt(), 13);
981 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
987 QDeclarativeComponent component(&engine, TEST_FILE("scope.5.qml"));
988 QObject *object = component.create();
989 QVERIFY(object != 0);
991 QCOMPARE(object->property("test1").toBool(), true);
992 QCOMPARE(object->property("test2").toBool(), true);
998 QDeclarativeComponent component(&engine, TEST_FILE("scope.6.qml"));
999 QObject *object = component.create();
1000 QVERIFY(object != 0);
1002 QCOMPARE(object->property("test").toBool(), true);
1008 // In 4.7, non-library javascript files that had no imports shared the imports of their
1009 // importing context
1010 void tst_qdeclarativeecmascript::importScope()
1012 QDeclarativeComponent component(&engine, TEST_FILE("importScope.qml"));
1013 QObject *o = component.create();
1016 QCOMPARE(o->property("test").toInt(), 240);
1022 Tests that "any" type passes through a synthesized signal parameter. This
1023 is essentially a test of QDeclarativeMetaType::copy()
1025 void tst_qdeclarativeecmascript::signalParameterTypes()
1027 QDeclarativeComponent component(&engine, TEST_FILE("signalParameterTypes.qml"));
1028 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1029 QVERIFY(object != 0);
1031 emit object->basicSignal();
1033 QCOMPARE(object->property("intProperty").toInt(), 10);
1034 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1035 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1036 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1037 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1038 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1044 Test that two JS objects for the same QObject compare as equal.
1046 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1048 QDeclarativeComponent component(&engine, TEST_FILE("objectsCompareAsEqual.qml"));
1049 QObject *object = component.create();
1050 QVERIFY(object != 0);
1052 QCOMPARE(object->property("test1").toBool(), true);
1053 QCOMPARE(object->property("test2").toBool(), true);
1054 QCOMPARE(object->property("test3").toBool(), true);
1055 QCOMPARE(object->property("test4").toBool(), true);
1056 QCOMPARE(object->property("test5").toBool(), true);
1062 Confirm bindings and alias properties can coexist.
1064 Tests for a regression where the binding would not reevaluate.
1066 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1068 QDeclarativeComponent component(&engine, TEST_FILE("aliasPropertyAndBinding.qml"));
1069 QObject *object = component.create();
1070 QVERIFY(object != 0);
1072 QCOMPARE(object->property("c2").toInt(), 3);
1073 QCOMPARE(object->property("c3").toInt(), 3);
1075 object->setProperty("c2", QVariant(19));
1077 QCOMPARE(object->property("c2").toInt(), 19);
1078 QCOMPARE(object->property("c3").toInt(), 19);
1084 Ensure that we can write undefined value to an alias property,
1085 and that the aliased property is reset correctly if possible.
1087 void tst_qdeclarativeecmascript::aliasPropertyReset()
1089 QObject *object = 0;
1091 // test that a manual write (of undefined) to a resettable aliased property succeeds
1092 QDeclarativeComponent c1(&engine, TEST_FILE("aliasreset/aliasPropertyReset.1.qml"));
1093 object = c1.create();
1094 QVERIFY(object != 0);
1095 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1096 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1097 QMetaObject::invokeMethod(object, "resetAliased");
1098 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1099 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1102 // test that a manual write (of undefined) to a resettable alias property succeeds
1103 QDeclarativeComponent c2(&engine, TEST_FILE("aliasreset/aliasPropertyReset.2.qml"));
1104 object = c2.create();
1105 QVERIFY(object != 0);
1106 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1107 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1108 QMetaObject::invokeMethod(object, "resetAlias");
1109 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1110 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1113 // test that an alias to a bound property works correctly
1114 QDeclarativeComponent c3(&engine, TEST_FILE("aliasreset/aliasPropertyReset.3.qml"));
1115 object = c3.create();
1116 QVERIFY(object != 0);
1117 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1118 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1119 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1120 QMetaObject::invokeMethod(object, "resetAlias");
1121 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1122 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1123 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1126 // test that a manual write (of undefined) to a resettable alias property
1127 // whose aliased property's object has been deleted, does not crash.
1128 QDeclarativeComponent c4(&engine, TEST_FILE("aliasreset/aliasPropertyReset.4.qml"));
1129 object = c4.create();
1130 QVERIFY(object != 0);
1131 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1132 QObject *loader = object->findChild<QObject*>("loader");
1133 QVERIFY(loader != 0);
1135 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1136 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1137 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1138 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1139 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1142 // test that binding an alias property to an undefined value works correctly
1143 QDeclarativeComponent c5(&engine, TEST_FILE("aliasreset/aliasPropertyReset.5.qml"));
1144 object = c5.create();
1145 QVERIFY(object != 0);
1146 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1149 // test that a manual write (of undefined) to a non-resettable property fails properly
1150 QUrl url = TEST_FILE("aliasreset/aliasPropertyReset.error.1.qml");
1151 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1152 QDeclarativeComponent e1(&engine, url);
1153 object = e1.create();
1154 QVERIFY(object != 0);
1155 QCOMPARE(object->property("intAlias").value<int>(), 12);
1156 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1157 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1158 QMetaObject::invokeMethod(object, "resetAlias");
1159 QCOMPARE(object->property("intAlias").value<int>(), 12);
1160 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1164 void tst_qdeclarativeecmascript::dynamicCreation_data()
1166 QTest::addColumn<QString>("method");
1167 QTest::addColumn<QString>("createdName");
1169 QTest::newRow("One") << "createOne" << "objectOne";
1170 QTest::newRow("Two") << "createTwo" << "objectTwo";
1171 QTest::newRow("Three") << "createThree" << "objectThree";
1175 Test using createQmlObject to dynamically generate an item
1176 Also using createComponent is tested.
1178 void tst_qdeclarativeecmascript::dynamicCreation()
1180 QFETCH(QString, method);
1181 QFETCH(QString, createdName);
1183 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1184 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1185 QVERIFY(object != 0);
1187 QMetaObject::invokeMethod(object, method.toUtf8());
1188 QObject *created = object->objectProperty();
1190 QCOMPARE(created->objectName(), createdName);
1196 Tests the destroy function
1198 void tst_qdeclarativeecmascript::dynamicDestruction()
1201 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.qml"));
1202 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1203 QVERIFY(object != 0);
1204 QDeclarativeGuard<QObject> createdQmlObject = 0;
1206 QMetaObject::invokeMethod(object, "create");
1207 createdQmlObject = object->objectProperty();
1208 QVERIFY(createdQmlObject);
1209 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1211 QMetaObject::invokeMethod(object, "killOther");
1212 QVERIFY(createdQmlObject);
1213 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1214 QVERIFY(createdQmlObject);
1215 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1216 if (createdQmlObject) {
1218 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1221 QVERIFY(!createdQmlObject);
1223 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1224 QMetaObject::invokeMethod(object, "killMe");
1227 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1232 QDeclarativeComponent component(&engine, TEST_FILE("dynamicDeletion.2.qml"));
1233 QObject *o = component.create();
1236 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1238 QMetaObject::invokeMethod(o, "create");
1240 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1242 QMetaObject::invokeMethod(o, "destroy");
1244 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1246 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1253 tests that id.toString() works
1255 void tst_qdeclarativeecmascript::objectToString()
1257 QDeclarativeComponent component(&engine, TEST_FILE("declarativeToString.qml"));
1258 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1259 QVERIFY(object != 0);
1260 QMetaObject::invokeMethod(object, "testToString");
1261 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1262 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1268 tests that id.hasOwnProperty() works
1270 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1272 QUrl url = TEST_FILE("declarativeHasOwnProperty.qml");
1273 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1274 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1275 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1277 QDeclarativeComponent component(&engine, url);
1278 QObject *object = component.create();
1279 QVERIFY(object != 0);
1281 // test QObjects in QML
1282 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1283 QVERIFY(object->property("result").value<bool>() == true);
1284 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1285 QVERIFY(object->property("result").value<bool>() == false);
1287 // now test other types in QML
1288 QObject *child = object->findChild<QObject*>("typeObj");
1289 QVERIFY(child != 0);
1290 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1291 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1292 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1293 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1294 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1295 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1296 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1297 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1298 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1299 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1300 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1301 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1303 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1304 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1305 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1306 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1307 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1308 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1309 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1310 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1311 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1317 Tests bindings that indirectly cause their own deletion work.
1319 This test is best run under valgrind to ensure no invalid memory access occur.
1321 void tst_qdeclarativeecmascript::selfDeletingBinding()
1324 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.qml"));
1325 QObject *object = component.create();
1326 QVERIFY(object != 0);
1327 object->setProperty("triggerDelete", true);
1332 QDeclarativeComponent component(&engine, TEST_FILE("selfDeletingBinding.2.qml"));
1333 QObject *object = component.create();
1334 QVERIFY(object != 0);
1335 object->setProperty("triggerDelete", true);
1341 Test that extended object properties can be accessed.
1343 This test a regression where this used to crash. The issue was specificially
1344 for extended objects that did not include a synthesized meta object (so non-root
1345 and no synthesiszed properties).
1347 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1349 QDeclarativeComponent component(&engine, TEST_FILE("extendedObjectPropertyLookup.qml"));
1350 QObject *object = component.create();
1351 QVERIFY(object != 0);
1356 Test file/lineNumbers for binding/Script errors.
1358 void tst_qdeclarativeecmascript::scriptErrors()
1360 QDeclarativeComponent component(&engine, TEST_FILE("scriptErrors.qml"));
1361 QString url = component.url().toString();
1363 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1364 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1365 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1366 QString warning4 = url + ":10: ReferenceError: Can't find variable: a";
1367 QString warning5 = url + ":8: ReferenceError: Can't find variable: a";
1368 QString warning6 = url + ":7: Unable to assign [undefined] to int";
1369 QString warning7 = url + ":12: Error: Cannot assign to read-only property \"trueProperty\"";
1370 QString warning8 = url + ":13: Error: Cannot assign to non-existent property \"fakeProperty\"";
1372 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1373 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1374 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1375 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1376 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1377 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1378 QVERIFY(object != 0);
1380 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1381 emit object->basicSignal();
1383 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1384 emit object->anotherBasicSignal();
1386 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1387 emit object->thirdBasicSignal();
1393 Test file/lineNumbers for inline functions.
1395 void tst_qdeclarativeecmascript::functionErrors()
1397 QDeclarativeComponent component(&engine, TEST_FILE("functionErrors.qml"));
1398 QString url = component.url().toString();
1400 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1402 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1404 QObject *object = component.create();
1405 QVERIFY(object != 0);
1408 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1409 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
1410 url = componentTwo.url().toString();
1411 object = componentTwo.create();
1412 QVERIFY(object != 0);
1414 QString srpname = object->property("srp_name").toString();
1416 warning = url + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srpname +
1417 QLatin1String(" is not a function");
1418 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1419 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1424 Test various errors that can occur when assigning a property from script
1426 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1428 QDeclarativeComponent component(&engine, TEST_FILE("propertyAssignmentErrors.qml"));
1430 QString url = component.url().toString();
1432 QObject *object = component.create();
1433 QVERIFY(object != 0);
1435 QCOMPARE(object->property("test1").toBool(), true);
1436 QCOMPARE(object->property("test2").toBool(), true);
1442 Test bindings still work when the reeval is triggered from within
1445 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1447 QDeclarativeComponent component(&engine, TEST_FILE("signalTriggeredBindings.qml"));
1448 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1449 QVERIFY(object != 0);
1451 QCOMPARE(object->property("base").toReal(), 50.);
1452 QCOMPARE(object->property("test1").toReal(), 50.);
1453 QCOMPARE(object->property("test2").toReal(), 50.);
1455 object->basicSignal();
1457 QCOMPARE(object->property("base").toReal(), 200.);
1458 QCOMPARE(object->property("test1").toReal(), 200.);
1459 QCOMPARE(object->property("test2").toReal(), 200.);
1461 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1463 QCOMPARE(object->property("base").toReal(), 400.);
1464 QCOMPARE(object->property("test1").toReal(), 400.);
1465 QCOMPARE(object->property("test2").toReal(), 400.);
1471 Test that list properties can be iterated from ECMAScript
1473 void tst_qdeclarativeecmascript::listProperties()
1475 QDeclarativeComponent component(&engine, TEST_FILE("listProperties.qml"));
1476 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1477 QVERIFY(object != 0);
1479 QCOMPARE(object->property("test1").toInt(), 21);
1480 QCOMPARE(object->property("test2").toInt(), 2);
1481 QCOMPARE(object->property("test3").toBool(), true);
1482 QCOMPARE(object->property("test4").toBool(), true);
1487 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1489 QDeclarativeComponent component(&engine, TEST_FILE("exceptionClearsOnReeval.qml"));
1490 QString url = component.url().toString();
1492 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1494 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1495 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1496 QVERIFY(object != 0);
1498 QCOMPARE(object->property("test").toBool(), false);
1500 MyQmlObject object2;
1501 MyQmlObject object3;
1502 object2.setObjectProperty(&object3);
1503 object->setObjectProperty(&object2);
1505 QCOMPARE(object->property("test").toBool(), true);
1510 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1512 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning.qml"));
1513 QString url = component.url().toString();
1515 QString warning = component.url().toString() + ":6: Error: JS exception";
1517 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1518 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1519 QVERIFY(object != 0);
1523 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1525 QDeclarativeComponent component(&engine, TEST_FILE("exceptionProducesWarning2.qml"));
1526 QString url = component.url().toString();
1528 QString warning = component.url().toString() + ":5: Error: JS exception";
1530 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1531 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1532 QVERIFY(object != 0);
1536 static int transientErrorsMsgCount = 0;
1537 static void transientErrorsMsgHandler(QtMsgType, const char *)
1539 ++transientErrorsMsgCount;
1542 // Check that transient binding errors are not displayed
1543 void tst_qdeclarativeecmascript::transientErrors()
1546 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.qml"));
1548 transientErrorsMsgCount = 0;
1549 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1551 QObject *object = component.create();
1552 QVERIFY(object != 0);
1554 qInstallMsgHandler(old);
1556 QCOMPARE(transientErrorsMsgCount, 0);
1561 // One binding erroring multiple times, but then resolving
1563 QDeclarativeComponent component(&engine, TEST_FILE("transientErrors.2.qml"));
1565 transientErrorsMsgCount = 0;
1566 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1568 QObject *object = component.create();
1569 QVERIFY(object != 0);
1571 qInstallMsgHandler(old);
1573 QCOMPARE(transientErrorsMsgCount, 0);
1579 // Check that errors during shutdown are minimized
1580 void tst_qdeclarativeecmascript::shutdownErrors()
1582 QDeclarativeComponent component(&engine, TEST_FILE("shutdownErrors.qml"));
1583 QObject *object = component.create();
1584 QVERIFY(object != 0);
1586 transientErrorsMsgCount = 0;
1587 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1591 qInstallMsgHandler(old);
1592 QCOMPARE(transientErrorsMsgCount, 0);
1595 void tst_qdeclarativeecmascript::compositePropertyType()
1597 QDeclarativeComponent component(&engine, TEST_FILE("compositePropertyType.qml"));
1599 QTest::ignoreMessage(QtDebugMsg, "hello world");
1600 QObject *object = qobject_cast<QObject *>(component.create());
1605 void tst_qdeclarativeecmascript::jsObject()
1607 QDeclarativeComponent component(&engine, TEST_FILE("jsObject.qml"));
1608 QObject *object = component.create();
1609 QVERIFY(object != 0);
1611 QCOMPARE(object->property("test").toInt(), 92);
1616 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1619 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.qml"));
1620 QObject *object = component.create();
1621 QVERIFY(object != 0);
1623 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1625 object->setProperty("setUndefined", true);
1627 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1629 object->setProperty("setUndefined", false);
1631 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1636 QDeclarativeComponent component(&engine, TEST_FILE("undefinedResetsProperty.2.qml"));
1637 QObject *object = component.create();
1638 QVERIFY(object != 0);
1640 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1642 QMetaObject::invokeMethod(object, "doReset");
1644 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1650 // Aliases to variant properties should work
1651 void tst_qdeclarativeecmascript::qtbug_22464()
1653 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22464.qml"));
1654 QObject *object = component.create();
1655 QVERIFY(object != 0);
1657 QCOMPARE(object->property("test").toBool(), true);
1662 void tst_qdeclarativeecmascript::qtbug_21580()
1664 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_21580.qml"));
1666 QObject *object = component.create();
1667 QVERIFY(object != 0);
1669 QCOMPARE(object->property("test").toBool(), true);
1675 void tst_qdeclarativeecmascript::bug1()
1677 QDeclarativeComponent component(&engine, TEST_FILE("bug.1.qml"));
1678 QObject *object = component.create();
1679 QVERIFY(object != 0);
1681 QCOMPARE(object->property("test").toInt(), 14);
1683 object->setProperty("a", 11);
1685 QCOMPARE(object->property("test").toInt(), 3);
1687 object->setProperty("b", true);
1689 QCOMPARE(object->property("test").toInt(), 9);
1694 void tst_qdeclarativeecmascript::bug2()
1696 QDeclarativeComponent component(&engine);
1697 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1699 QObject *object = component.create();
1700 QVERIFY(object != 0);
1705 // Don't crash in createObject when the component has errors.
1706 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1708 QDeclarativeComponent component(&engine, TEST_FILE("dynamicCreation.qml"));
1709 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1710 QVERIFY(object != 0);
1712 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1713 QMetaObject::invokeMethod(object, "dontCrash");
1714 QObject *created = object->objectProperty();
1715 QVERIFY(created == 0);
1720 // ownership transferred to JS, ensure that GC runs the dtor
1721 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1724 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1726 // allow the engine to go out of scope too.
1728 QDeclarativeEngine dcoEngine;
1729 QDeclarativeComponent component(&dcoEngine, TEST_FILE("dynamicCreationOwnership.qml"));
1730 QObject *object = component.create();
1731 QVERIFY(object != 0);
1732 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1733 QVERIFY(mdcdo != 0);
1734 mdcdo->setDtorCount(&dtorCount);
1736 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1737 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1739 // we do this once manually, but it should be done automatically
1740 // when the engine goes out of scope (since it should gc in dtor)
1741 QMetaObject::invokeMethod(object, "performGc");
1744 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1750 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1751 QCOMPARE(dtorCount, expectedDtorCount);
1755 void tst_qdeclarativeecmascript::regExpBug()
1757 QDeclarativeComponent component(&engine, TEST_FILE("regExp.qml"));
1758 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1759 QVERIFY(object != 0);
1760 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1764 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1766 QString functionSource = QLatin1String("(function(object) { return ") +
1767 QLatin1String(source) + QLatin1String(" })");
1769 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1772 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1773 if (function.IsEmpty())
1775 v8::Handle<v8::Value> args[] = { o };
1776 function->Call(engine->global(), 1, args);
1777 return tc.HasCaught();
1780 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1781 const char *source, v8::Handle<v8::Value> result)
1783 QString functionSource = QLatin1String("(function(object) { return ") +
1784 QLatin1String(source) + QLatin1String(" })");
1786 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1789 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1790 if (function.IsEmpty())
1792 v8::Handle<v8::Value> args[] = { o };
1794 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1799 return value->StrictEquals(result);
1802 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1805 QString functionSource = QLatin1String("(function(object) { return ") +
1806 QLatin1String(source) + QLatin1String(" })");
1808 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1810 return v8::Handle<v8::Value>();
1811 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1812 if (function.IsEmpty())
1813 return v8::Handle<v8::Value>();
1814 v8::Handle<v8::Value> args[] = { o };
1816 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1819 return v8::Handle<v8::Value>();
1823 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1824 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1825 #define EVALUATE(source) evaluate(engine, object, source)
1827 void tst_qdeclarativeecmascript::callQtInvokables()
1829 MyInvokableObject o;
1831 QDeclarativeEngine qmlengine;
1832 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1834 QV8Engine *engine = ep->v8engine();
1836 v8::HandleScope handle_scope;
1837 v8::Context::Scope scope(engine->context());
1839 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1841 // Non-existent methods
1843 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1844 QCOMPARE(o.error(), false);
1845 QCOMPARE(o.invoked(), -1);
1846 QCOMPARE(o.actuals().count(), 0);
1849 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1850 QCOMPARE(o.error(), false);
1851 QCOMPARE(o.invoked(), -1);
1852 QCOMPARE(o.actuals().count(), 0);
1854 // Insufficient arguments
1856 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1857 QCOMPARE(o.error(), false);
1858 QCOMPARE(o.invoked(), -1);
1859 QCOMPARE(o.actuals().count(), 0);
1862 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1863 QCOMPARE(o.error(), false);
1864 QCOMPARE(o.invoked(), -1);
1865 QCOMPARE(o.actuals().count(), 0);
1867 // Excessive arguments
1869 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1870 QCOMPARE(o.error(), false);
1871 QCOMPARE(o.invoked(), 8);
1872 QCOMPARE(o.actuals().count(), 1);
1873 QCOMPARE(o.actuals().at(0), QVariant(10));
1876 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1877 QCOMPARE(o.error(), false);
1878 QCOMPARE(o.invoked(), 9);
1879 QCOMPARE(o.actuals().count(), 2);
1880 QCOMPARE(o.actuals().at(0), QVariant(10));
1881 QCOMPARE(o.actuals().at(1), QVariant(11));
1883 // Test return types
1885 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1886 QCOMPARE(o.error(), false);
1887 QCOMPARE(o.invoked(), 0);
1888 QCOMPARE(o.actuals().count(), 0);
1891 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1892 QCOMPARE(o.error(), false);
1893 QCOMPARE(o.invoked(), 1);
1894 QCOMPARE(o.actuals().count(), 0);
1897 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1898 QCOMPARE(o.error(), false);
1899 QCOMPARE(o.invoked(), 2);
1900 QCOMPARE(o.actuals().count(), 0);
1904 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1905 QVERIFY(!ret.IsEmpty());
1906 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1907 QCOMPARE(o.error(), false);
1908 QCOMPARE(o.invoked(), 3);
1909 QCOMPARE(o.actuals().count(), 0);
1914 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1915 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1916 QCOMPARE(o.error(), false);
1917 QCOMPARE(o.invoked(), 4);
1918 QCOMPARE(o.actuals().count(), 0);
1922 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1923 QCOMPARE(o.error(), false);
1924 QCOMPARE(o.invoked(), 5);
1925 QCOMPARE(o.actuals().count(), 0);
1929 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1930 QVERIFY(ret->IsString());
1931 QCOMPARE(engine->toString(ret), QString("Hello world"));
1932 QCOMPARE(o.error(), false);
1933 QCOMPARE(o.invoked(), 6);
1934 QCOMPARE(o.actuals().count(), 0);
1938 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1939 QCOMPARE(o.error(), false);
1940 QCOMPARE(o.invoked(), 7);
1941 QCOMPARE(o.actuals().count(), 0);
1945 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1946 QCOMPARE(o.error(), false);
1947 QCOMPARE(o.invoked(), 8);
1948 QCOMPARE(o.actuals().count(), 1);
1949 QCOMPARE(o.actuals().at(0), QVariant(94));
1952 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1953 QCOMPARE(o.error(), false);
1954 QCOMPARE(o.invoked(), 8);
1955 QCOMPARE(o.actuals().count(), 1);
1956 QCOMPARE(o.actuals().at(0), QVariant(94));
1959 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1960 QCOMPARE(o.error(), false);
1961 QCOMPARE(o.invoked(), 8);
1962 QCOMPARE(o.actuals().count(), 1);
1963 QCOMPARE(o.actuals().at(0), QVariant(0));
1966 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1967 QCOMPARE(o.error(), false);
1968 QCOMPARE(o.invoked(), 8);
1969 QCOMPARE(o.actuals().count(), 1);
1970 QCOMPARE(o.actuals().at(0), QVariant(0));
1973 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1974 QCOMPARE(o.error(), false);
1975 QCOMPARE(o.invoked(), 8);
1976 QCOMPARE(o.actuals().count(), 1);
1977 QCOMPARE(o.actuals().at(0), QVariant(0));
1980 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
1981 QCOMPARE(o.error(), false);
1982 QCOMPARE(o.invoked(), 8);
1983 QCOMPARE(o.actuals().count(), 1);
1984 QCOMPARE(o.actuals().at(0), QVariant(0));
1987 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
1988 QCOMPARE(o.error(), false);
1989 QCOMPARE(o.invoked(), 9);
1990 QCOMPARE(o.actuals().count(), 2);
1991 QCOMPARE(o.actuals().at(0), QVariant(122));
1992 QCOMPARE(o.actuals().at(1), QVariant(9));
1995 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
1996 QCOMPARE(o.error(), false);
1997 QCOMPARE(o.invoked(), 10);
1998 QCOMPARE(o.actuals().count(), 1);
1999 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2002 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
2003 QCOMPARE(o.error(), false);
2004 QCOMPARE(o.invoked(), 10);
2005 QCOMPARE(o.actuals().count(), 1);
2006 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2009 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
2010 QCOMPARE(o.error(), false);
2011 QCOMPARE(o.invoked(), 10);
2012 QCOMPARE(o.actuals().count(), 1);
2013 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2016 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
2017 QCOMPARE(o.error(), false);
2018 QCOMPARE(o.invoked(), 10);
2019 QCOMPARE(o.actuals().count(), 1);
2020 QCOMPARE(o.actuals().at(0), QVariant(0));
2023 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2024 QCOMPARE(o.error(), false);
2025 QCOMPARE(o.invoked(), 10);
2026 QCOMPARE(o.actuals().count(), 1);
2027 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2030 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2031 QCOMPARE(o.error(), false);
2032 QCOMPARE(o.invoked(), 10);
2033 QCOMPARE(o.actuals().count(), 1);
2034 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2037 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2038 QCOMPARE(o.error(), false);
2039 QCOMPARE(o.invoked(), 11);
2040 QCOMPARE(o.actuals().count(), 1);
2041 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2044 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2045 QCOMPARE(o.error(), false);
2046 QCOMPARE(o.invoked(), 11);
2047 QCOMPARE(o.actuals().count(), 1);
2048 QCOMPARE(o.actuals().at(0), QVariant("19"));
2052 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2053 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", 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(expected));
2061 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2062 QCOMPARE(o.error(), false);
2063 QCOMPARE(o.invoked(), 11);
2064 QCOMPARE(o.actuals().count(), 1);
2065 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2068 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2069 QCOMPARE(o.error(), false);
2070 QCOMPARE(o.invoked(), 11);
2071 QCOMPARE(o.actuals().count(), 1);
2072 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2075 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2076 QCOMPARE(o.error(), false);
2077 QCOMPARE(o.invoked(), 12);
2078 QCOMPARE(o.actuals().count(), 1);
2079 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2082 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2083 QCOMPARE(o.error(), false);
2084 QCOMPARE(o.invoked(), 12);
2085 QCOMPARE(o.actuals().count(), 1);
2086 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2089 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2090 QCOMPARE(o.error(), false);
2091 QCOMPARE(o.invoked(), 12);
2092 QCOMPARE(o.actuals().count(), 1);
2093 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2096 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2097 QCOMPARE(o.error(), false);
2098 QCOMPARE(o.invoked(), 12);
2099 QCOMPARE(o.actuals().count(), 1);
2100 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2103 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2104 QCOMPARE(o.error(), false);
2105 QCOMPARE(o.invoked(), 12);
2106 QCOMPARE(o.actuals().count(), 1);
2107 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2110 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2111 QCOMPARE(o.error(), false);
2112 QCOMPARE(o.invoked(), 12);
2113 QCOMPARE(o.actuals().count(), 1);
2114 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2117 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2118 QCOMPARE(o.error(), false);
2119 QCOMPARE(o.invoked(), 13);
2120 QCOMPARE(o.actuals().count(), 1);
2121 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2124 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2125 QCOMPARE(o.error(), false);
2126 QCOMPARE(o.invoked(), 13);
2127 QCOMPARE(o.actuals().count(), 1);
2128 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2131 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2132 QCOMPARE(o.error(), false);
2133 QCOMPARE(o.invoked(), 13);
2134 QCOMPARE(o.actuals().count(), 1);
2135 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2138 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2139 QCOMPARE(o.error(), false);
2140 QCOMPARE(o.invoked(), 13);
2141 QCOMPARE(o.actuals().count(), 1);
2142 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2145 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2146 QCOMPARE(o.error(), false);
2147 QCOMPARE(o.invoked(), 13);
2148 QCOMPARE(o.actuals().count(), 1);
2149 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2152 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2153 QCOMPARE(o.error(), false);
2154 QCOMPARE(o.invoked(), 14);
2155 QCOMPARE(o.actuals().count(), 1);
2156 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2159 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2160 QCOMPARE(o.error(), false);
2161 QCOMPARE(o.invoked(), 14);
2162 QCOMPARE(o.actuals().count(), 1);
2163 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2166 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2167 QCOMPARE(o.error(), false);
2168 QCOMPARE(o.invoked(), 14);
2169 QCOMPARE(o.actuals().count(), 1);
2170 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2173 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2174 QCOMPARE(o.error(), false);
2175 QCOMPARE(o.invoked(), 14);
2176 QCOMPARE(o.actuals().count(), 1);
2177 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2180 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2181 QCOMPARE(o.error(), false);
2182 QCOMPARE(o.invoked(), 15);
2183 QCOMPARE(o.actuals().count(), 2);
2184 QCOMPARE(o.actuals().at(0), QVariant(4));
2185 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2188 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2189 QCOMPARE(o.error(), false);
2190 QCOMPARE(o.invoked(), 15);
2191 QCOMPARE(o.actuals().count(), 2);
2192 QCOMPARE(o.actuals().at(0), QVariant(8));
2193 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2196 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2197 QCOMPARE(o.error(), false);
2198 QCOMPARE(o.invoked(), 15);
2199 QCOMPARE(o.actuals().count(), 2);
2200 QCOMPARE(o.actuals().at(0), QVariant(3));
2201 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2204 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2205 QCOMPARE(o.error(), false);
2206 QCOMPARE(o.invoked(), 15);
2207 QCOMPARE(o.actuals().count(), 2);
2208 QCOMPARE(o.actuals().at(0), QVariant(44));
2209 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2212 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2213 QCOMPARE(o.error(), false);
2214 QCOMPARE(o.invoked(), -1);
2215 QCOMPARE(o.actuals().count(), 0);
2218 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2219 QCOMPARE(o.error(), false);
2220 QCOMPARE(o.invoked(), 16);
2221 QCOMPARE(o.actuals().count(), 1);
2222 QCOMPARE(o.actuals().at(0), QVariant(10));
2225 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2226 QCOMPARE(o.error(), false);
2227 QCOMPARE(o.invoked(), 17);
2228 QCOMPARE(o.actuals().count(), 2);
2229 QCOMPARE(o.actuals().at(0), QVariant(10));
2230 QCOMPARE(o.actuals().at(1), QVariant(11));
2233 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2234 QCOMPARE(o.error(), false);
2235 QCOMPARE(o.invoked(), 18);
2236 QCOMPARE(o.actuals().count(), 1);
2237 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2240 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2241 QCOMPARE(o.error(), false);
2242 QCOMPARE(o.invoked(), 19);
2243 QCOMPARE(o.actuals().count(), 1);
2244 QCOMPARE(o.actuals().at(0), QVariant(9));
2247 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2248 QCOMPARE(o.error(), false);
2249 QCOMPARE(o.invoked(), 20);
2250 QCOMPARE(o.actuals().count(), 2);
2251 QCOMPARE(o.actuals().at(0), QVariant(10));
2252 QCOMPARE(o.actuals().at(1), QVariant(19));
2255 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2256 QCOMPARE(o.error(), false);
2257 QCOMPARE(o.invoked(), 20);
2258 QCOMPARE(o.actuals().count(), 2);
2259 QCOMPARE(o.actuals().at(0), QVariant(10));
2260 QCOMPARE(o.actuals().at(1), QVariant(13));
2263 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2264 QCOMPARE(o.error(), false);
2265 QCOMPARE(o.invoked(), -3);
2266 QCOMPARE(o.actuals().count(), 1);
2267 QCOMPARE(o.actuals().at(0), QVariant(9));
2270 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2271 QCOMPARE(o.error(), false);
2272 QCOMPARE(o.invoked(), 21);
2273 QCOMPARE(o.actuals().count(), 2);
2274 QCOMPARE(o.actuals().at(0), QVariant(9));
2275 QCOMPARE(o.actuals().at(1), QVariant());
2278 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2279 QCOMPARE(o.error(), false);
2280 QCOMPARE(o.invoked(), 21);
2281 QCOMPARE(o.actuals().count(), 2);
2282 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2283 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2286 // QTBUG-13047 (check that you can pass registered object types as args)
2287 void tst_qdeclarativeecmascript::invokableObjectArg()
2289 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectArg.qml"));
2291 QObject *o = component.create();
2293 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2295 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2300 // QTBUG-13047 (check that you can return registered object types from methods)
2301 void tst_qdeclarativeecmascript::invokableObjectRet()
2303 QDeclarativeComponent component(&engine, TEST_FILE("invokableObjectRet.qml"));
2305 QObject *o = component.create();
2307 QCOMPARE(o->property("test").toBool(), true);
2312 void tst_qdeclarativeecmascript::listToVariant()
2314 QDeclarativeComponent component(&engine, TEST_FILE("listToVariant.qml"));
2316 MyQmlContainer container;
2318 QDeclarativeContext context(engine.rootContext());
2319 context.setContextObject(&container);
2321 QObject *object = component.create(&context);
2322 QVERIFY(object != 0);
2324 QVariant v = object->property("test");
2325 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2326 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2332 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2333 void tst_qdeclarativeecmascript::listAssignment()
2335 QDeclarativeComponent component(&engine, TEST_FILE("listAssignment.qml"));
2336 QObject *obj = component.create();
2337 QCOMPARE(obj->property("list1length").toInt(), 2);
2338 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2339 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2340 QCOMPARE(list1.count(&list1), list2.count(&list2));
2341 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2342 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2347 void tst_qdeclarativeecmascript::multiEngineObject()
2350 obj.setStringProperty("Howdy planet");
2352 QDeclarativeEngine e1;
2353 e1.rootContext()->setContextProperty("thing", &obj);
2354 QDeclarativeComponent c1(&e1, TEST_FILE("multiEngineObject.qml"));
2356 QDeclarativeEngine e2;
2357 e2.rootContext()->setContextProperty("thing", &obj);
2358 QDeclarativeComponent c2(&e2, TEST_FILE("multiEngineObject.qml"));
2360 QObject *o1 = c1.create();
2361 QObject *o2 = c2.create();
2363 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2364 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2370 // Test that references to QObjects are cleanup when the object is destroyed
2371 void tst_qdeclarativeecmascript::deletedObject()
2373 QDeclarativeComponent component(&engine, TEST_FILE("deletedObject.qml"));
2375 QObject *object = component.create();
2377 QCOMPARE(object->property("test1").toBool(), true);
2378 QCOMPARE(object->property("test2").toBool(), true);
2379 QCOMPARE(object->property("test3").toBool(), true);
2380 QCOMPARE(object->property("test4").toBool(), true);
2385 void tst_qdeclarativeecmascript::attachedPropertyScope()
2387 QDeclarativeComponent component(&engine, TEST_FILE("attachedPropertyScope.qml"));
2389 QObject *object = component.create();
2390 QVERIFY(object != 0);
2392 MyQmlAttachedObject *attached =
2393 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2394 QVERIFY(attached != 0);
2396 QCOMPARE(object->property("value2").toInt(), 0);
2398 attached->emitMySignal();
2400 QCOMPARE(object->property("value2").toInt(), 9);
2405 void tst_qdeclarativeecmascript::scriptConnect()
2408 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.1.qml"));
2410 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2411 QVERIFY(object != 0);
2413 QCOMPARE(object->property("test").toBool(), false);
2414 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2415 QCOMPARE(object->property("test").toBool(), true);
2421 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.2.qml"));
2423 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2424 QVERIFY(object != 0);
2426 QCOMPARE(object->property("test").toBool(), false);
2427 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2428 QCOMPARE(object->property("test").toBool(), true);
2434 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.3.qml"));
2436 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2437 QVERIFY(object != 0);
2439 QCOMPARE(object->property("test").toBool(), false);
2440 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2441 QCOMPARE(object->property("test").toBool(), true);
2447 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.4.qml"));
2449 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2450 QVERIFY(object != 0);
2452 QCOMPARE(object->methodCalled(), false);
2453 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2454 QCOMPARE(object->methodCalled(), true);
2460 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.5.qml"));
2462 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2463 QVERIFY(object != 0);
2465 QCOMPARE(object->methodCalled(), false);
2466 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2467 QCOMPARE(object->methodCalled(), true);
2473 QDeclarativeComponent component(&engine, TEST_FILE("scriptConnect.6.qml"));
2475 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2476 QVERIFY(object != 0);
2478 QCOMPARE(object->property("test").toInt(), 0);
2479 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2480 QCOMPARE(object->property("test").toInt(), 2);
2486 void tst_qdeclarativeecmascript::scriptDisconnect()
2489 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.1.qml"));
2491 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2492 QVERIFY(object != 0);
2494 QCOMPARE(object->property("test").toInt(), 0);
2495 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2496 QCOMPARE(object->property("test").toInt(), 1);
2497 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2498 QCOMPARE(object->property("test").toInt(), 2);
2499 emit object->basicSignal();
2500 QCOMPARE(object->property("test").toInt(), 2);
2501 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2502 QCOMPARE(object->property("test").toInt(), 2);
2508 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.2.qml"));
2510 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2511 QVERIFY(object != 0);
2513 QCOMPARE(object->property("test").toInt(), 0);
2514 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2515 QCOMPARE(object->property("test").toInt(), 1);
2516 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2517 QCOMPARE(object->property("test").toInt(), 2);
2518 emit object->basicSignal();
2519 QCOMPARE(object->property("test").toInt(), 2);
2520 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2521 QCOMPARE(object->property("test").toInt(), 2);
2527 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.3.qml"));
2529 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2530 QVERIFY(object != 0);
2532 QCOMPARE(object->property("test").toInt(), 0);
2533 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2534 QCOMPARE(object->property("test").toInt(), 1);
2535 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2536 QCOMPARE(object->property("test").toInt(), 2);
2537 emit object->basicSignal();
2538 QCOMPARE(object->property("test").toInt(), 2);
2539 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2540 QCOMPARE(object->property("test").toInt(), 3);
2545 QDeclarativeComponent component(&engine, TEST_FILE("scriptDisconnect.4.qml"));
2547 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2548 QVERIFY(object != 0);
2550 QCOMPARE(object->property("test").toInt(), 0);
2551 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2552 QCOMPARE(object->property("test").toInt(), 1);
2553 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2554 QCOMPARE(object->property("test").toInt(), 2);
2555 emit object->basicSignal();
2556 QCOMPARE(object->property("test").toInt(), 2);
2557 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2558 QCOMPARE(object->property("test").toInt(), 3);
2564 class OwnershipObject : public QObject
2568 OwnershipObject() { object = new QObject; }
2570 QPointer<QObject> object;
2573 QObject *getObject() { return object; }
2576 void tst_qdeclarativeecmascript::ownership()
2578 OwnershipObject own;
2579 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2580 context->setContextObject(&own);
2583 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2585 QVERIFY(own.object != 0);
2587 QObject *object = component.create(context);
2589 engine.collectGarbage();
2591 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2593 QVERIFY(own.object == 0);
2598 own.object = new QObject(&own);
2601 QDeclarativeComponent component(&engine, TEST_FILE("ownership.qml"));
2603 QVERIFY(own.object != 0);
2605 QObject *object = component.create(context);
2607 engine.collectGarbage();
2609 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2611 QVERIFY(own.object != 0);
2619 class CppOwnershipReturnValue : public QObject
2623 CppOwnershipReturnValue() : value(0) {}
2624 ~CppOwnershipReturnValue() { delete value; }
2626 Q_INVOKABLE QObject *create() {
2627 value = new QObject;
2628 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2632 Q_INVOKABLE MyQmlObject *createQmlObject() {
2633 MyQmlObject *rv = new MyQmlObject;
2638 QPointer<QObject> value;
2642 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2643 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2645 CppOwnershipReturnValue source;
2648 QDeclarativeEngine engine;
2649 engine.rootContext()->setContextProperty("source", &source);
2651 QVERIFY(source.value == 0);
2653 QDeclarativeComponent component(&engine);
2654 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2656 QObject *object = component.create();
2658 QVERIFY(object != 0);
2659 QVERIFY(source.value != 0);
2664 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2666 QVERIFY(source.value != 0);
2670 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2672 CppOwnershipReturnValue source;
2675 QDeclarativeEngine engine;
2676 engine.rootContext()->setContextProperty("source", &source);
2678 QVERIFY(source.value == 0);
2680 QDeclarativeComponent component(&engine);
2681 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2683 QObject *object = component.create();
2685 QVERIFY(object != 0);
2686 QVERIFY(source.value != 0);
2691 engine.collectGarbage();
2692 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2694 QVERIFY(source.value == 0);
2697 class QListQObjectMethodsObject : public QObject
2701 QListQObjectMethodsObject() {
2702 m_objects.append(new MyQmlObject());
2703 m_objects.append(new MyQmlObject());
2706 ~QListQObjectMethodsObject() {
2707 qDeleteAll(m_objects);
2711 QList<QObject *> getObjects() { return m_objects; }
2714 QList<QObject *> m_objects;
2717 // Tests that returning a QList<QObject*> from a method works
2718 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2720 QListQObjectMethodsObject obj;
2721 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2722 context->setContextObject(&obj);
2724 QDeclarativeComponent component(&engine, TEST_FILE("qlistqobjectMethods.qml"));
2726 QObject *object = component.create(context);
2728 QCOMPARE(object->property("test").toInt(), 2);
2729 QCOMPARE(object->property("test2").toBool(), true);
2736 void tst_qdeclarativeecmascript::strictlyEquals()
2738 QDeclarativeComponent component(&engine, TEST_FILE("strictlyEquals.qml"));
2740 QObject *object = component.create();
2741 QVERIFY(object != 0);
2743 QCOMPARE(object->property("test1").toBool(), true);
2744 QCOMPARE(object->property("test2").toBool(), true);
2745 QCOMPARE(object->property("test3").toBool(), true);
2746 QCOMPARE(object->property("test4").toBool(), true);
2747 QCOMPARE(object->property("test5").toBool(), true);
2748 QCOMPARE(object->property("test6").toBool(), true);
2749 QCOMPARE(object->property("test7").toBool(), true);
2750 QCOMPARE(object->property("test8").toBool(), true);
2755 void tst_qdeclarativeecmascript::compiled()
2757 QDeclarativeComponent component(&engine, TEST_FILE("compiled.qml"));
2759 QObject *object = component.create();
2760 QVERIFY(object != 0);
2762 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2763 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2764 QCOMPARE(object->property("test3").toBool(), true);
2765 QCOMPARE(object->property("test4").toBool(), false);
2766 QCOMPARE(object->property("test5").toBool(), false);
2767 QCOMPARE(object->property("test6").toBool(), true);
2769 QCOMPARE(object->property("test7").toInt(), 185);
2770 QCOMPARE(object->property("test8").toInt(), 167);
2771 QCOMPARE(object->property("test9").toBool(), true);
2772 QCOMPARE(object->property("test10").toBool(), false);
2773 QCOMPARE(object->property("test11").toBool(), false);
2774 QCOMPARE(object->property("test12").toBool(), true);
2776 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2777 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2778 QCOMPARE(object->property("test15").toBool(), false);
2779 QCOMPARE(object->property("test16").toBool(), true);
2781 QCOMPARE(object->property("test17").toInt(), 5);
2782 QCOMPARE(object->property("test18").toReal(), qreal(176));
2783 QCOMPARE(object->property("test19").toInt(), 7);
2784 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2785 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2786 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2787 QCOMPARE(object->property("test23").toBool(), true);
2788 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2789 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2794 // Test that numbers assigned in bindings as strings work consistently
2795 void tst_qdeclarativeecmascript::numberAssignment()
2797 QDeclarativeComponent component(&engine, TEST_FILE("numberAssignment.qml"));
2799 QObject *object = component.create();
2800 QVERIFY(object != 0);
2802 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2803 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2804 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2805 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2806 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2808 QCOMPARE(object->property("test5"), QVariant((int)7));
2809 QCOMPARE(object->property("test6"), QVariant((int)7));
2810 QCOMPARE(object->property("test7"), QVariant((int)6));
2811 QCOMPARE(object->property("test8"), QVariant((int)6));
2813 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2814 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2815 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2816 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2821 void tst_qdeclarativeecmascript::propertySplicing()
2823 QDeclarativeComponent component(&engine, TEST_FILE("propertySplicing.qml"));
2825 QObject *object = component.create();
2826 QVERIFY(object != 0);
2828 QCOMPARE(object->property("test").toBool(), true);
2834 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2836 QDeclarativeComponent component(&engine, TEST_FILE("signalWithUnknownTypes.qml"));
2838 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2839 QVERIFY(object != 0);
2841 MyQmlObject::MyType type;
2842 type.value = 0x8971123;
2843 emit object->signalWithUnknownType(type);
2845 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2847 QCOMPARE(result.value, type.value);
2853 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2855 QTest::addColumn<QString>("expression");
2856 QTest::addColumn<QString>("compare");
2858 QString compareStrict("(function(a, b) { return a === b; })");
2859 QTest::newRow("true") << "true" << compareStrict;
2860 QTest::newRow("undefined") << "undefined" << compareStrict;
2861 QTest::newRow("null") << "null" << compareStrict;
2862 QTest::newRow("123") << "123" << compareStrict;
2863 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2865 QString comparePropertiesStrict(
2867 " if (typeof b != 'object')"
2869 " var props = Object.getOwnPropertyNames(b);"
2870 " for (var i = 0; i < props.length; ++i) {"
2871 " var p = props[i];"
2872 " return arguments.callee(a[p], b[p]);"
2875 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2876 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2879 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2881 QFETCH(QString, expression);
2882 QFETCH(QString, compare);
2884 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2885 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2886 QVERIFY(object != 0);
2888 QJSValue value = engine.evaluate(expression);
2889 QVERIFY(!engine.hasUncaughtException());
2890 object->setProperty("expression", expression);
2891 object->setProperty("compare", compare);
2892 object->setProperty("pass", false);
2894 emit object->signalWithVariant(QVariant::fromValue(value));
2895 QVERIFY(object->property("pass").toBool());
2898 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2900 signalWithJSValueInVariant_data();
2903 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2905 QFETCH(QString, expression);
2906 QFETCH(QString, compare);
2908 QDeclarativeComponent component(&engine, TEST_FILE("signalWithJSValueInVariant.qml"));
2909 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2910 QVERIFY(object != 0);
2913 QJSValue value = engine2.evaluate(expression);
2914 QVERIFY(!engine2.hasUncaughtException());
2915 object->setProperty("expression", expression);
2916 object->setProperty("compare", compare);
2917 object->setProperty("pass", false);
2919 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2920 emit object->signalWithVariant(QVariant::fromValue(value));
2921 QVERIFY(!object->property("pass").toBool());
2924 void tst_qdeclarativeecmascript::moduleApi_data()
2926 QTest::addColumn<QUrl>("testfile");
2927 QTest::addColumn<QString>("errorMessage");
2928 QTest::addColumn<QStringList>("warningMessages");
2929 QTest::addColumn<QStringList>("readProperties");
2930 QTest::addColumn<QVariantList>("readExpectedValues");
2931 QTest::addColumn<QStringList>("writeProperties");
2932 QTest::addColumn<QVariantList>("writeValues");
2933 QTest::addColumn<QStringList>("readBackProperties");
2934 QTest::addColumn<QVariantList>("readBackExpectedValues");
2936 QTest::newRow("qobject, register + read + method")
2937 << TEST_FILE("moduleapi/qobjectModuleApi.qml")
2940 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2941 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2942 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2948 QTest::newRow("script, register + read")
2949 << TEST_FILE("moduleapi/scriptModuleApi.qml")
2952 << (QStringList() << "scriptTest")
2953 << (QVariantList() << 13)
2959 QTest::newRow("qobject, caching + read")
2960 << TEST_FILE("moduleapi/qobjectModuleApiCaching.qml")
2963 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
2964 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
2970 QTest::newRow("script, caching + read")
2971 << TEST_FILE("moduleapi/scriptModuleApiCaching.qml")
2974 << (QStringList() << "scriptTest")
2975 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
2981 QTest::newRow("qobject, writing + readonly constraints")
2982 << TEST_FILE("moduleapi/qobjectModuleApiWriting.qml")
2984 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
2985 << (QStringList() << "readOnlyProperty" << "writableProperty")
2986 << (QVariantList() << 20 << 50)
2987 << (QStringList() << "firstProperty" << "writableProperty")
2988 << (QVariantList() << 30 << 30)
2989 << (QStringList() << "readOnlyProperty" << "writableProperty")
2990 << (QVariantList() << 20 << 30);
2992 QTest::newRow("script, writing + readonly constraints")
2993 << TEST_FILE("moduleapi/scriptModuleApiWriting.qml")
2995 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
2996 << (QStringList() << "readBack" << "unchanged")
2997 << (QVariantList() << 13 << 42)
2998 << (QStringList() << "firstProperty" << "secondProperty")
2999 << (QVariantList() << 30 << 30)
3000 << (QStringList() << "readBack" << "unchanged")
3001 << (QVariantList() << 30 << 42);
3003 QTest::newRow("qobject module API enum values in JS")
3004 << TEST_FILE("moduleapi/qobjectModuleApiEnums.qml")
3007 << (QStringList() << "enumValue" << "enumMethod")
3008 << (QVariantList() << 42 << 30)
3014 QTest::newRow("qobject, invalid major version fail")
3015 << TEST_FILE("moduleapi/moduleApiMajorVersionFail.qml")
3016 << QString("QDeclarativeComponent: Component is not ready")
3025 QTest::newRow("qobject, invalid minor version fail")
3026 << TEST_FILE("moduleapi/moduleApiMinorVersionFail.qml")
3027 << QString("QDeclarativeComponent: Component is not ready")
3037 void tst_qdeclarativeecmascript::moduleApi()
3039 QFETCH(QUrl, testfile);
3040 QFETCH(QString, errorMessage);
3041 QFETCH(QStringList, warningMessages);
3042 QFETCH(QStringList, readProperties);
3043 QFETCH(QVariantList, readExpectedValues);
3044 QFETCH(QStringList, writeProperties);
3045 QFETCH(QVariantList, writeValues);
3046 QFETCH(QStringList, readBackProperties);
3047 QFETCH(QVariantList, readBackExpectedValues);
3049 QDeclarativeComponent component(&engine, testfile);
3051 if (!errorMessage.isEmpty())
3052 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3054 if (warningMessages.size())
3055 foreach (const QString &warning, warningMessages)
3056 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3058 QObject *object = component.create();
3059 if (!errorMessage.isEmpty()) {
3060 QVERIFY(object == 0);
3062 QVERIFY(object != 0);
3063 for (int i = 0; i < readProperties.size(); ++i)
3064 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3065 for (int i = 0; i < writeProperties.size(); ++i)
3066 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3067 for (int i = 0; i < readBackProperties.size(); ++i)
3068 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3073 void tst_qdeclarativeecmascript::importScripts_data()
3075 QTest::addColumn<QUrl>("testfile");
3076 QTest::addColumn<QString>("errorMessage");
3077 QTest::addColumn<QStringList>("warningMessages");
3078 QTest::addColumn<QStringList>("propertyNames");
3079 QTest::addColumn<QVariantList>("propertyValues");
3081 QTest::newRow("basic functionality")
3082 << TEST_FILE("jsimport/testImport.qml")
3085 << (QStringList() << QLatin1String("importedScriptStringValue")
3086 << QLatin1String("importedScriptFunctionValue")
3087 << QLatin1String("importedModuleAttachedPropertyValue")
3088 << QLatin1String("importedModuleEnumValue"))
3089 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3094 QTest::newRow("import scoping")
3095 << TEST_FILE("jsimport/testImportScoping.qml")
3098 << (QStringList() << QLatin1String("componentError"))
3099 << (QVariantList() << QVariant(5));
3101 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3102 << TEST_FILE("jsimportfail/failOne.qml")
3104 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3105 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3106 << (QVariantList() << QVariant(QString()));
3108 QTest::newRow("javascript imports in an import should be private to the import scope")
3109 << TEST_FILE("jsimportfail/failTwo.qml")
3111 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3112 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3113 << (QVariantList() << QVariant(QString()));
3115 QTest::newRow("module imports in an import should be private to the import scope")
3116 << TEST_FILE("jsimportfail/failThree.qml")
3118 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3119 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3120 << (QVariantList() << QVariant(false));
3122 QTest::newRow("typenames in an import should be private to the import scope")
3123 << TEST_FILE("jsimportfail/failFour.qml")
3125 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3126 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3127 << (QVariantList() << QVariant(0));
3129 QTest::newRow("import with imports has it's own activation scope")
3130 << TEST_FILE("jsimportfail/failFive.qml")
3132 << (QStringList() << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3133 << QString(QLatin1String("file://") + TEST_FILE("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3134 << (QStringList() << QLatin1String("componentError"))
3135 << (QVariantList() << QVariant(0));
3137 QTest::newRow("import pragma library script")
3138 << TEST_FILE("jsimport/testImportPragmaLibrary.qml")
3141 << (QStringList() << QLatin1String("testValue"))
3142 << (QVariantList() << QVariant(31));
3144 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3145 << TEST_FILE("jsimportfail/testImportPragmaLibrary.qml")
3148 << (QStringList() << QLatin1String("testValue"))
3149 << (QVariantList() << QVariant(0));
3151 QTest::newRow("import pragma library script which has an import")
3152 << TEST_FILE("jsimport/testImportPragmaLibraryWithImports.qml")
3155 << (QStringList() << QLatin1String("testValue"))
3156 << (QVariantList() << QVariant(55));
3158 QTest::newRow("import pragma library script which has a pragma library import")
3159 << TEST_FILE("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3162 << (QStringList() << QLatin1String("testValue"))
3163 << (QVariantList() << QVariant(18));
3166 void tst_qdeclarativeecmascript::importScripts()
3168 QFETCH(QUrl, testfile);
3169 QFETCH(QString, errorMessage);
3170 QFETCH(QStringList, warningMessages);
3171 QFETCH(QStringList, propertyNames);
3172 QFETCH(QVariantList, propertyValues);
3174 QDeclarativeComponent component(&engine, testfile);
3176 if (!errorMessage.isEmpty())
3177 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3179 if (warningMessages.size())
3180 foreach (const QString &warning, warningMessages)
3181 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3183 QObject *object = component.create();
3184 if (!errorMessage.isEmpty()) {
3185 QVERIFY(object == 0);
3187 QVERIFY(object != 0);
3188 for (int i = 0; i < propertyNames.size(); ++i)
3189 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3194 void tst_qdeclarativeecmascript::scarceResources()
3196 QPixmap origPixmap(100, 100);
3197 origPixmap.fill(Qt::blue);
3199 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3200 ScarceResourceObject *eo = 0;
3201 QObject *object = 0;
3203 // in the following three cases, the instance created from the component
3204 // has a property which is a copy of the scarce resource; hence, the
3205 // resource should NOT be detached prior to deletion of the object instance,
3206 // unless the resource is destroyed explicitly.
3207 QDeclarativeComponent component(&engine, TEST_FILE("scarceresources/scarceResourceCopy.qml"));
3208 object = component.create();
3209 QVERIFY(object != 0);
3210 QVERIFY(object->property("scarceResourceCopy").isValid());
3211 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3212 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3213 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3214 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3217 QDeclarativeComponent componentTwo(&engine, TEST_FILE("scarceresources/scarceResourceCopyFromJs.qml"));
3218 object = componentTwo.create();
3219 QVERIFY(object != 0);
3220 QVERIFY(object->property("scarceResourceCopy").isValid());
3221 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3222 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3223 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3224 QVERIFY(!eo->scarceResourceIsDetached()); // there are two copies of it in existence: the property of object, and the property of eo.
3227 QDeclarativeComponent componentThree(&engine, TEST_FILE("scarceresources/scarceResourceDestroyedCopy.qml"));
3228 object = componentThree.create();
3229 QVERIFY(object != 0);
3230 QVERIFY(!(object->property("scarceResourceCopy").isValid())); // was manually released prior to being returned.
3231 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3232 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3233 QVERIFY(eo->scarceResourceIsDetached()); // should have explicitly been released during the evaluation of the binding.
3236 // in the following three cases, no other copy should exist in memory,
3237 // and so it should be detached (unless explicitly preserved).
3238 QDeclarativeComponent componentFour(&engine, TEST_FILE("scarceresources/scarceResourceTest.qml"));
3239 object = componentFour.create();
3240 QVERIFY(object != 0);
3241 QVERIFY(object->property("scarceResourceTest").isValid());
3242 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3243 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3244 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3245 QVERIFY(eo->scarceResourceIsDetached()); // the resource should have been released after the binding was evaluated.
3248 QDeclarativeComponent componentFive(&engine, TEST_FILE("scarceresources/scarceResourceTestPreserve.qml"));
3249 object = componentFive.create();
3250 QVERIFY(object != 0);
3251 QVERIFY(object->property("scarceResourceTest").isValid());
3252 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3253 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3254 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3255 QVERIFY(!eo->scarceResourceIsDetached()); // this won't be detached since we explicitly preserved it.
3258 QDeclarativeComponent componentSix(&engine, TEST_FILE("scarceresources/scarceResourceTestMultiple.qml"));
3259 object = componentSix.create();
3260 QVERIFY(object != 0);
3261 QVERIFY(object->property("scarceResourceTest").isValid());
3262 QCOMPARE(object->property("scarceResourceTest").toInt(), 100);
3263 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3264 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3265 QVERIFY(eo->scarceResourceIsDetached()); // all resources were released manually or automatically released.
3268 // test that scarce resources are handled correctly for imports
3269 QDeclarativeComponent componentSeven(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportNoBinding.qml"));
3270 object = componentSeven.create();
3271 QVERIFY(object != 0); // the import should have caused the addition of a resource to the ScarceResources list
3272 QVERIFY(ep->scarceResources.isEmpty()); // but they should have been released by this point.
3275 QDeclarativeComponent componentEight(&engine, TEST_FILE("scarceresources/scarceResourceCopyImportFail.qml"));
3276 object = componentEight.create();
3277 QVERIFY(object != 0);
3278 QVERIFY(!object->property("scarceResourceCopy").isValid()); // wasn't preserved, so shouldn't be valid.
3279 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3282 QDeclarativeComponent componentNine(&engine, TEST_FILE("scarceresources/scarceResourceCopyImport.qml"));
3283 object = componentNine.create();
3284 QVERIFY(object != 0);
3285 QVERIFY(object->property("scarceResourceCopy").isValid()); // preserved, so should be valid.
3286 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3287 QVERIFY(object->property("scarceResourceAssignedCopyOne").isValid()); // assigned before destroy(), so should be valid.
3288 QCOMPARE(object->property("scarceResourceAssignedCopyOne").value<QPixmap>(), origPixmap);
3289 QVERIFY(!object->property("scarceResourceAssignedCopyTwo").isValid()); // assigned after destroy(), so should be invalid.
3290 QVERIFY(ep->scarceResources.isEmpty()); // this will still be zero, because "preserve()" REMOVES it from this list.
3293 // test that scarce resources are handled properly in signal invocation
3294 QDeclarativeComponent componentTen(&engine, TEST_FILE("scarceresources/scarceResourceSignal.qml"));
3295 object = componentTen.create();
3296 QVERIFY(object != 0);
3297 QObject *srsc = object->findChild<QObject*>("srsc");
3299 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3300 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3301 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3302 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3303 QMetaObject::invokeMethod(srsc, "testSignal");
3304 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3305 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3306 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3307 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3308 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3309 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3310 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3311 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3312 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3313 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3316 // test that scarce resources are handled properly from js functions in qml files
3317 QDeclarativeComponent componentEleven(&engine, TEST_FILE("scarceresources/scarceResourceFunction.qml"));
3318 object = componentEleven.create();
3319 QVERIFY(object != 0);
3320 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3321 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3322 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3323 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3324 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3325 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3326 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3327 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3328 QMetaObject::invokeMethod(object, "releaseScarceResource");
3329 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3330 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3331 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3332 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3335 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3336 QDeclarativeComponent componentTwelve(&engine, TEST_FILE("scarceresources/scarceResourceFunctionFail.qml"));
3337 object = componentTwelve.create();
3338 QVERIFY(object != 0);
3339 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3340 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3341 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3342 QString srp_name = object->property("srp_name").toString();
3343 QString expectedWarning = componentTwelve.url().toString() + QLatin1String(":17: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3344 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3345 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3346 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3347 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3348 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3349 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3353 void tst_qdeclarativeecmascript::propertyChangeSlots()
3355 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3356 QDeclarativeComponent component(&engine, TEST_FILE("changeslots/propertyChangeSlots.qml"));
3357 QObject *object = component.create();
3358 QVERIFY(object != 0);
3361 // ensure that invalid property names fail properly.
3362 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3363 QDeclarativeComponent e1(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.1.qml"));
3364 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3365 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3366 object = e1.create();
3367 QVERIFY(object == 0);
3370 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3371 QDeclarativeComponent e2(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.2.qml"));
3372 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3373 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3374 object = e2.create();
3375 QVERIFY(object == 0);
3378 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3379 QDeclarativeComponent e3(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.3.qml"));
3380 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3381 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3382 object = e3.create();
3383 QVERIFY(object == 0);
3386 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3387 QDeclarativeComponent e4(&engine, TEST_FILE("changeslots/propertyChangeSlotErrors.4.qml"));
3388 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3389 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3390 object = e4.create();
3391 QVERIFY(object == 0);
3395 void tst_qdeclarativeecmascript::propertyVar_data()
3397 QTest::addColumn<QUrl>("qmlFile");
3400 QTest::newRow("non-bindable object subproperty changed") << TEST_FILE("propertyVar.1.qml");
3401 QTest::newRow("non-bindable object changed") << TEST_FILE("propertyVar.2.qml");
3402 QTest::newRow("primitive changed") << TEST_FILE("propertyVar.3.qml");
3403 QTest::newRow("javascript array modification") << TEST_FILE("propertyVar.4.qml");
3404 QTest::newRow("javascript map modification") << TEST_FILE("propertyVar.5.qml");
3405 QTest::newRow("javascript array assignment") << TEST_FILE("propertyVar.6.qml");
3406 QTest::newRow("javascript map assignment") << TEST_FILE("propertyVar.7.qml");
3407 QTest::newRow("literal property assignment") << TEST_FILE("propertyVar.8.qml");
3408 QTest::newRow("qobject property assignment") << TEST_FILE("propertyVar.9.qml");
3411 void tst_qdeclarativeecmascript::propertyVar()
3413 QFETCH(QUrl, qmlFile);
3415 QDeclarativeComponent component(&engine, qmlFile);
3416 QObject *object = component.create();
3417 QVERIFY(object != 0);
3419 QCOMPARE(object->property("test").toBool(), true);
3424 // Tests that we can write QVariant values to var properties from C++
3425 void tst_qdeclarativeecmascript::propertyVarCpp()
3427 QObject *object = 0;
3429 // ensure that writing to and reading from a var property from cpp works as required.
3430 // Literal values stored in var properties can be read and written as QVariants
3431 // of a specific type, whereas object values are read as QVariantMaps.
3432 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarCpp.qml"));
3433 object = component.create();
3434 QVERIFY(object != 0);
3435 // assign int to property var that currently has int assigned
3436 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3437 QCOMPARE(object->property("varBound"), QVariant(15));
3438 QCOMPARE(object->property("intBound"), QVariant(15));
3439 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3440 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3441 // assign string to property var that current has bool assigned
3442 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3443 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3444 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3445 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3446 // now enforce behaviour when accessing JavaScript objects from cpp.
3447 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3451 static void gc(QDeclarativeEngine &engine)
3453 engine.collectGarbage();
3454 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3457 void tst_qdeclarativeecmascript::propertyVarOwnership()
3459 // Referenced JS objects are not collected
3461 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.qml"));
3462 QObject *object = component.create();
3463 QVERIFY(object != 0);
3464 QCOMPARE(object->property("test").toBool(), false);
3465 QMetaObject::invokeMethod(object, "runTest");
3466 QCOMPARE(object->property("test").toBool(), true);
3469 // Referenced JS objects are not collected
3471 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.2.qml"));
3472 QObject *object = component.create();
3473 QVERIFY(object != 0);
3474 QCOMPARE(object->property("test").toBool(), false);
3475 QMetaObject::invokeMethod(object, "runTest");
3476 QCOMPARE(object->property("test").toBool(), true);
3479 // Qt objects are not collected until they've been dereferenced
3481 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.3.qml"));
3482 QObject *object = component.create();
3483 QVERIFY(object != 0);
3485 QCOMPARE(object->property("test2").toBool(), false);
3486 QCOMPARE(object->property("test2").toBool(), false);
3488 QMetaObject::invokeMethod(object, "runTest");
3489 QCOMPARE(object->property("test1").toBool(), true);
3491 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3492 QVERIFY(!referencedObject.isNull());
3494 QVERIFY(!referencedObject.isNull());
3496 QMetaObject::invokeMethod(object, "runTest2");
3497 QCOMPARE(object->property("test2").toBool(), true);
3499 QVERIFY(referencedObject.isNull());
3503 // Self reference does not prevent Qt object collection
3505 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarOwnership.4.qml"));
3506 QObject *object = component.create();
3507 QVERIFY(object != 0);
3509 QCOMPARE(object->property("test").toBool(), true);
3511 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3512 QVERIFY(!referencedObject.isNull());
3514 QVERIFY(!referencedObject.isNull());
3516 QMetaObject::invokeMethod(object, "runTest");
3518 QVERIFY(referencedObject.isNull());
3524 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3526 // The childObject has a reference to a different QObject. We want to ensure
3527 // that the different item will not be cleaned up until required. IE, the childObject
3528 // has implicit ownership of the constructed QObject.
3529 QDeclarativeComponent component(&engine, TEST_FILE("propertyVarImplicitOwnership.qml"));
3530 QObject *object = component.create();
3531 QVERIFY(object != 0);
3532 QMetaObject::invokeMethod(object, "assignCircular");
3533 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3534 QObject *rootObject = object->property("vp").value<QObject*>();
3535 QVERIFY(rootObject != 0);
3536 QObject *childObject = rootObject->findChild<QObject*>("text");
3537 QVERIFY(childObject != 0);
3538 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3539 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3540 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3541 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3542 QVERIFY(!qobjectGuard.isNull());
3543 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3544 QVERIFY(!qobjectGuard.isNull());
3545 QMetaObject::invokeMethod(object, "deassignCircular");
3546 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3547 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3551 void tst_qdeclarativeecmascript::propertyVarReparent()
3553 // ensure that nothing breaks if we re-parent objects
3554 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3555 QObject *object = component.create();
3556 QVERIFY(object != 0);
3557 QMetaObject::invokeMethod(object, "assignVarProp");
3558 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3559 QObject *rect = object->property("vp").value<QObject*>();
3560 QObject *text = rect->findChild<QObject*>("textOne");
3561 QObject *text2 = rect->findChild<QObject*>("textTwo");
3562 QWeakPointer<QObject> rectGuard(rect);
3563 QWeakPointer<QObject> textGuard(text);
3564 QWeakPointer<QObject> text2Guard(text2);
3565 QVERIFY(!rectGuard.isNull());
3566 QVERIFY(!textGuard.isNull());
3567 QVERIFY(!text2Guard.isNull());
3568 QCOMPARE(text->property("textCanary").toInt(), 11);
3569 QCOMPARE(text2->property("textCanary").toInt(), 12);
3570 // now construct an image which we will reparent.
3571 QMetaObject::invokeMethod(text2, "constructQObject");
3572 QObject *image = text2->property("vp").value<QObject*>();
3573 QWeakPointer<QObject> imageGuard(image);
3574 QVERIFY(!imageGuard.isNull());
3575 QCOMPARE(image->property("imageCanary").toInt(), 13);
3576 // now reparent the "Image" object (currently, it has JS ownership)
3577 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3578 QMetaObject::invokeMethod(text2, "deassignVp");
3579 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3580 QCOMPARE(text->property("textCanary").toInt(), 11);
3581 QCOMPARE(text2->property("textCanary").toInt(), 22);
3582 QVERIFY(!imageGuard.isNull()); // should still be alive.
3583 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3584 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3585 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3586 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3590 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3592 // sometimes reparenting can cause problems
3593 // (eg, if the ctxt is collected, varproperties are no longer available)
3594 // this test ensures that no crash occurs in that situation.
3595 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.reparent.qml"));
3596 QObject *object = component.create();
3597 QVERIFY(object != 0);
3598 QMetaObject::invokeMethod(object, "assignVarProp");
3599 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3600 QObject *rect = object->property("vp").value<QObject*>();
3601 QObject *text = rect->findChild<QObject*>("textOne");
3602 QObject *text2 = rect->findChild<QObject*>("textTwo");
3603 QWeakPointer<QObject> rectGuard(rect);
3604 QWeakPointer<QObject> textGuard(text);
3605 QWeakPointer<QObject> text2Guard(text2);
3606 QVERIFY(!rectGuard.isNull());
3607 QVERIFY(!textGuard.isNull());
3608 QVERIFY(!text2Guard.isNull());
3609 QCOMPARE(text->property("textCanary").toInt(), 11);
3610 QCOMPARE(text2->property("textCanary").toInt(), 12);
3611 // now construct an image which we will reparent.
3612 QMetaObject::invokeMethod(text2, "constructQObject");
3613 QObject *image = text2->property("vp").value<QObject*>();
3614 QWeakPointer<QObject> imageGuard(image);
3615 QVERIFY(!imageGuard.isNull());
3616 QCOMPARE(image->property("imageCanary").toInt(), 13);
3617 // now reparent the "Image" object (currently, it has JS ownership)
3618 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3619 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3620 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3621 QVERIFY(!imageGuard.isNull()); // should still be alive.
3622 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3624 QVERIFY(imageGuard.isNull()); // should now be dead.
3627 void tst_qdeclarativeecmascript::propertyVarCircular()
3629 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3630 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.qml"));
3631 QObject *object = component.create();
3632 QVERIFY(object != 0);
3633 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3634 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3635 QCOMPARE(object->property("canaryInt"), QVariant(5));
3636 QVariant canaryResourceVariant = object->property("canaryResource");
3637 QVERIFY(canaryResourceVariant.isValid());
3638 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3639 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3640 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3641 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3642 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3643 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3644 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3645 QCOMPARE(object->property("canaryInt"), QVariant(2));
3646 QCOMPARE(object->property("canaryResource"), QVariant(1));
3647 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3651 void tst_qdeclarativeecmascript::propertyVarCircular2()
3653 // track deletion of JS-owned parent item with Cpp-owned child
3654 // where the child has a var property referencing its parent.
3655 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3656 QObject *object = component.create();
3657 QVERIFY(object != 0);
3658 QMetaObject::invokeMethod(object, "assignCircular");
3659 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3660 QObject *rootObject = object->property("vp").value<QObject*>();
3661 QVERIFY(rootObject != 0);
3662 QObject *childObject = rootObject->findChild<QObject*>("text");
3663 QVERIFY(childObject != 0);
3664 QWeakPointer<QObject> rootObjectTracker(rootObject);
3665 QVERIFY(!rootObjectTracker.isNull());
3666 QWeakPointer<QObject> childObjectTracker(childObject);
3667 QVERIFY(!childObjectTracker.isNull());
3669 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3670 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3671 QMetaObject::invokeMethod(object, "deassignCircular");
3672 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3673 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3674 QVERIFY(childObjectTracker.isNull()); // should have been collected
3678 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3680 *(int*)(parameter) += 1;
3681 qPersistentDispose(object);
3684 void tst_qdeclarativeecmascript::propertyVarInheritance()
3686 int propertyVarWeakRefCallbackCount = 0;
3688 // enforce behaviour regarding element inheritance - ensure handle disposal.
3689 // The particular component under test here has a chain of references.
3690 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.inherit.qml"));
3691 QObject *object = component.create();
3692 QVERIFY(object != 0);
3693 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3694 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3695 // we want to be able to track when the varProperties array of the last metaobject is disposed
3696 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3697 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*>();
3698 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3699 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
3700 v8::Persistent<v8::Value> icoCanaryHandle;
3701 v8::Persistent<v8::Value> ccoCanaryHandle;
3704 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
3705 // public function which can return us a handle to something in the varProperties array.
3706 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(41));
3707 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(41));
3708 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
3709 // as the varproperties array of each vmemo still references the resource.
3710 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3711 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3713 QVERIFY(propertyVarWeakRefCallbackCount == 0);
3715 // now we deassign the var prop, which should trigger collection of item subtrees.
3716 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3717 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3718 // ensure that there are only weak handles to the underlying varProperties array remaining.
3720 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
3722 // since there are no parent vmemo's to keep implicit references alive, and the only handles
3723 // to what remains are weak, all varProperties arrays must have been collected.
3726 void tst_qdeclarativeecmascript::propertyVarInheritance2()
3728 int propertyVarWeakRefCallbackCount = 0;
3730 // The particular component under test here does NOT have a chain of references; the
3731 // only link between rootObject and childObject is that rootObject is the parent of childObject.
3732 QDeclarativeComponent component(&engine, TEST_FILE("propertyVar.circular.2.qml"));
3733 QObject *object = component.create();
3734 QVERIFY(object != 0);
3735 QMetaObject::invokeMethod(object, "assignCircular");
3736 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3737 QObject *rootObject = object->property("vp").value<QObject*>();
3738 QVERIFY(rootObject != 0);
3739 QObject *childObject = rootObject->findChild<QObject*>("text");
3740 QVERIFY(childObject != 0);
3741 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3742 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3743 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
3746 propertyVarWeakRefCallbackCount = 0; // reset callback count.
3747 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(58));
3748 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
3750 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
3751 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3753 QMetaObject::invokeMethod(object, "deassignCircular");
3754 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3755 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
3759 // Ensure that QObject type conversion works on binding assignment
3760 void tst_qdeclarativeecmascript::elementAssign()
3762 QDeclarativeComponent component(&engine, TEST_FILE("elementAssign.qml"));
3764 QObject *object = component.create();
3765 QVERIFY(object != 0);
3767 QCOMPARE(object->property("test").toBool(), true);
3773 void tst_qdeclarativeecmascript::objectPassThroughSignals()
3775 QDeclarativeComponent component(&engine, TEST_FILE("objectsPassThroughSignals.qml"));
3777 QObject *object = component.create();
3778 QVERIFY(object != 0);
3780 QCOMPARE(object->property("test").toBool(), true);
3786 void tst_qdeclarativeecmascript::objectConversion()
3788 QDeclarativeComponent component(&engine, TEST_FILE("objectConversion.qml"));
3790 QObject *object = component.create();
3791 QVERIFY(object != 0);
3793 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
3794 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
3801 void tst_qdeclarativeecmascript::booleanConversion()
3803 QDeclarativeComponent component(&engine, TEST_FILE("booleanConversion.qml"));
3805 QObject *object = component.create();
3806 QVERIFY(object != 0);
3808 QCOMPARE(object->property("test_true1").toBool(), true);
3809 QCOMPARE(object->property("test_true2").toBool(), true);
3810 QCOMPARE(object->property("test_true3").toBool(), true);
3811 QCOMPARE(object->property("test_true4").toBool(), true);
3812 QCOMPARE(object->property("test_true5").toBool(), true);
3814 QCOMPARE(object->property("test_false1").toBool(), false);
3815 QCOMPARE(object->property("test_false2").toBool(), false);
3816 QCOMPARE(object->property("test_false3").toBool(), false);
3821 void tst_qdeclarativeecmascript::handleReferenceManagement()
3826 // Linear QObject reference
3827 QDeclarativeEngine hrmEngine;
3828 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.1.qml"));
3829 QObject *object = component.create();
3830 QVERIFY(object != 0);
3831 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3832 cro->setDtorCount(&dtorCount);
3833 QMetaObject::invokeMethod(object, "createReference");
3835 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
3837 hrmEngine.collectGarbage();
3838 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3839 QCOMPARE(dtorCount, 3);
3844 // Circular QObject reference
3845 QDeclarativeEngine hrmEngine;
3846 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.object.2.qml"));
3847 QObject *object = component.create();
3848 QVERIFY(object != 0);
3849 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
3850 cro->setDtorCount(&dtorCount);
3851 QMetaObject::invokeMethod(object, "circularReference");
3853 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
3855 hrmEngine.collectGarbage();
3856 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3857 QCOMPARE(dtorCount, 3);
3862 // Linear handle reference
3863 QDeclarativeEngine hrmEngine;
3864 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3865 QObject *object = component.create();
3866 QVERIFY(object != 0);
3867 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3869 crh->setDtorCount(&dtorCount);
3870 QMetaObject::invokeMethod(object, "createReference");
3871 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3872 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3873 QVERIFY(first != 0);
3874 QVERIFY(second != 0);
3875 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
3876 // now we have to reparent second and make second owned by JS.
3877 second->setParent(0);
3878 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3880 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
3882 hrmEngine.collectGarbage();
3883 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3884 QCOMPARE(dtorCount, 3);
3889 // Circular handle reference
3890 QDeclarativeEngine hrmEngine;
3891 QDeclarativeComponent component(&hrmEngine, TEST_FILE("handleReferenceManagement.handle.2.qml"));
3892 QObject *object = component.create();
3893 QVERIFY(object != 0);
3894 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
3896 crh->setDtorCount(&dtorCount);
3897 QMetaObject::invokeMethod(object, "circularReference");
3898 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
3899 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
3900 QVERIFY(first != 0);
3901 QVERIFY(second != 0);
3902 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
3903 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
3904 // now we have to reparent and change ownership.
3905 first->setParent(0);
3906 second->setParent(0);
3907 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
3908 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
3910 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
3912 hrmEngine.collectGarbage();
3913 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3914 QCOMPARE(dtorCount, 3);
3919 // multiple engine interaction - linear reference
3920 QDeclarativeEngine hrmEngine1;
3921 QDeclarativeEngine hrmEngine2;
3922 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3923 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3924 QObject *object1 = component1.create();
3925 QObject *object2 = component2.create();
3926 QVERIFY(object1 != 0);
3927 QVERIFY(object2 != 0);
3928 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3929 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3932 crh1->setDtorCount(&dtorCount);
3933 crh2->setDtorCount(&dtorCount);
3934 QMetaObject::invokeMethod(object1, "createReference");
3935 QMetaObject::invokeMethod(object2, "createReference");
3936 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3937 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3938 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3939 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3940 QVERIFY(first1 != 0);
3941 QVERIFY(second1 != 0);
3942 QVERIFY(first2 != 0);
3943 QVERIFY(second2 != 0);
3944 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
3945 // now we have to reparent second2 and make second2 owned by JS.
3946 second2->setParent(0);
3947 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
3949 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3950 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
3953 hrmEngine1.collectGarbage();
3954 hrmEngine2.collectGarbage();
3955 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3956 QCOMPARE(dtorCount, 6);
3961 // multiple engine interaction - circular reference
3962 QDeclarativeEngine hrmEngine1;
3963 QDeclarativeEngine hrmEngine2;
3964 QDeclarativeComponent component1(&hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3965 QDeclarativeComponent component2(&hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
3966 QObject *object1 = component1.create();
3967 QObject *object2 = component2.create();
3968 QVERIFY(object1 != 0);
3969 QVERIFY(object2 != 0);
3970 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
3971 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
3974 crh1->setDtorCount(&dtorCount);
3975 crh2->setDtorCount(&dtorCount);
3976 QMetaObject::invokeMethod(object1, "createReference");
3977 QMetaObject::invokeMethod(object2, "createReference");
3978 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
3979 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
3980 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
3981 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
3982 QVERIFY(first1 != 0);
3983 QVERIFY(second1 != 0);
3984 QVERIFY(first2 != 0);
3985 QVERIFY(second2 != 0);
3986 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
3987 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
3988 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
3989 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
3990 // now we have to reparent and change ownership to JS.
3991 first1->setParent(0);
3992 second1->setParent(0);
3993 first2->setParent(0);
3994 second2->setParent(0);
3995 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
3996 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
3997 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
3998 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4000 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4001 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
4004 hrmEngine1.collectGarbage();
4005 hrmEngine2.collectGarbage();
4006 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4007 QCOMPARE(dtorCount, 6);
4012 // multiple engine interaction - linear reference with engine deletion
4013 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
4014 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4015 QDeclarativeComponent component1(hrmEngine1, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4016 QDeclarativeComponent component2(hrmEngine2, TEST_FILE("handleReferenceManagement.handle.1.qml"));
4017 QObject *object1 = component1.create();
4018 QObject *object2 = component2.create();
4019 QVERIFY(object1 != 0);
4020 QVERIFY(object2 != 0);
4021 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4022 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4025 crh1->setDtorCount(&dtorCount);
4026 crh2->setDtorCount(&dtorCount);
4027 QMetaObject::invokeMethod(object1, "createReference");
4028 QMetaObject::invokeMethod(object2, "createReference");
4029 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4030 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4031 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4032 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4033 QVERIFY(first1 != 0);
4034 QVERIFY(second1 != 0);
4035 QVERIFY(first2 != 0);
4036 QVERIFY(second2 != 0);
4037 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4038 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4039 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4040 // now we have to reparent and change ownership to JS.
4041 first1->setParent(crh1);
4042 second1->setParent(0);
4043 first2->setParent(0);
4044 second2->setParent(0);
4045 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4046 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4047 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4049 QCOMPARE(dtorCount, 0);
4052 QCOMPARE(dtorCount, 0);
4055 hrmEngine1->collectGarbage();
4056 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4057 QCOMPARE(dtorCount, 6);
4062 void tst_qdeclarativeecmascript::stringArg()
4064 QDeclarativeComponent component(&engine, TEST_FILE("stringArg.qml"));
4065 QObject *object = component.create();
4066 QVERIFY(object != 0);
4067 QMetaObject::invokeMethod(object, "success");
4068 QVERIFY(object->property("returnValue").toBool());
4070 QString w1 = TEST_FILE("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4071 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4072 QMetaObject::invokeMethod(object, "failure");
4073 QVERIFY(object->property("returnValue").toBool());
4078 void tst_qdeclarativeecmascript::readonlyDeclaration()
4080 QDeclarativeComponent component(&engine, TEST_FILE("readonlyDeclaration.qml"));
4082 QObject *object = component.create();
4083 QVERIFY(object != 0);
4085 QCOMPARE(object->property("test").toBool(), true);
4090 Q_DECLARE_METATYPE(QList<int>)
4091 Q_DECLARE_METATYPE(QList<qreal>)
4092 Q_DECLARE_METATYPE(QList<bool>)
4093 Q_DECLARE_METATYPE(QList<QString>)
4094 Q_DECLARE_METATYPE(QList<QUrl>)
4095 void tst_qdeclarativeecmascript::sequenceConversionRead()
4098 QUrl qmlFile = TEST_FILE("sequenceConversion.read.qml");
4099 QDeclarativeComponent component(&engine, qmlFile);
4100 QObject *object = component.create();
4101 QVERIFY(object != 0);
4102 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4105 QMetaObject::invokeMethod(object, "readSequences");
4106 QList<int> intList; intList << 1 << 2 << 3 << 4;
4107 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4108 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4109 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4110 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4111 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4112 QList<bool> boolList; boolList << true << false << true << false;
4113 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4114 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4115 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4116 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4117 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4118 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4119 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4120 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4121 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4122 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4123 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4125 QMetaObject::invokeMethod(object, "readSequenceElements");
4126 QCOMPARE(object->property("intVal").toInt(), 2);
4127 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4128 QCOMPARE(object->property("boolVal").toBool(), false);
4129 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4130 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4131 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4133 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4134 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4136 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4137 QDeclarativeProperty seqProp(seq, "intListProperty");
4138 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4139 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4140 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4142 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4143 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4149 QUrl qmlFile = TEST_FILE("sequenceConversion.read.error.qml");
4150 QDeclarativeComponent component(&engine, qmlFile);
4151 QObject *object = component.create();
4152 QVERIFY(object != 0);
4153 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4156 // we haven't registered QList<QPoint> as a sequence type.
4157 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4158 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4159 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4160 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4162 QMetaObject::invokeMethod(object, "performTest");
4164 // QList<QPoint> has not been registered as a sequence type.
4165 QCOMPARE(object->property("pointListLength").toInt(), 0);
4166 QVERIFY(!object->property("pointList").isValid());
4167 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4168 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4169 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4175 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4178 QUrl qmlFile = TEST_FILE("sequenceConversion.write.qml");
4179 QDeclarativeComponent component(&engine, qmlFile);
4180 QObject *object = component.create();
4181 QVERIFY(object != 0);
4182 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4185 QMetaObject::invokeMethod(object, "writeSequences");
4186 QCOMPARE(object->property("success").toBool(), true);
4188 QMetaObject::invokeMethod(object, "writeSequenceElements");
4189 QCOMPARE(object->property("success").toBool(), true);
4191 QMetaObject::invokeMethod(object, "writeOtherElements");
4192 QCOMPARE(object->property("success").toBool(), true);
4194 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4195 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4201 QUrl qmlFile = TEST_FILE("sequenceConversion.write.error.qml");
4202 QDeclarativeComponent component(&engine, qmlFile);
4203 QObject *object = component.create();
4204 QVERIFY(object != 0);
4205 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4208 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4209 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4210 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4212 QMetaObject::invokeMethod(object, "performTest");
4214 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4215 QCOMPARE(seq->pointListProperty(), pointList);
4221 void tst_qdeclarativeecmascript::sequenceConversionArray()
4223 // ensure that in JS the returned sequences act just like normal JS Arrays.
4224 QUrl qmlFile = TEST_FILE("sequenceConversion.array.qml");
4225 QDeclarativeComponent component(&engine, qmlFile);
4226 QObject *object = component.create();
4227 QVERIFY(object != 0);
4228 QMetaObject::invokeMethod(object, "indexedAccess");
4229 QVERIFY(object->property("success").toBool());
4230 QMetaObject::invokeMethod(object, "arrayOperations");
4231 QVERIFY(object->property("success").toBool());
4232 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4233 QVERIFY(object->property("success").toBool());
4234 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4235 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4239 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4241 // ensure that sequence conversion operations work correctly in a worker thread
4242 // and that serialisation between the main and worker thread succeeds.
4243 QUrl qmlFile = TEST_FILE("sequenceConversion.threads.qml");
4244 QDeclarativeComponent component(&engine, qmlFile);
4245 QObject *object = component.create();
4246 QVERIFY(object != 0);
4248 QMetaObject::invokeMethod(object, "testIntSequence");
4249 QTRY_VERIFY(object->property("finished").toBool());
4250 QVERIFY(object->property("success").toBool());
4252 QMetaObject::invokeMethod(object, "testQrealSequence");
4253 QTRY_VERIFY(object->property("finished").toBool());
4254 QVERIFY(object->property("success").toBool());
4256 QMetaObject::invokeMethod(object, "testBoolSequence");
4257 QTRY_VERIFY(object->property("finished").toBool());
4258 QVERIFY(object->property("success").toBool());
4260 QMetaObject::invokeMethod(object, "testStringSequence");
4261 QTRY_VERIFY(object->property("finished").toBool());
4262 QVERIFY(object->property("success").toBool());
4264 QMetaObject::invokeMethod(object, "testQStringSequence");
4265 QTRY_VERIFY(object->property("finished").toBool());
4266 QVERIFY(object->property("success").toBool());
4268 QMetaObject::invokeMethod(object, "testUrlSequence");
4269 QTRY_VERIFY(object->property("finished").toBool());
4270 QVERIFY(object->property("success").toBool());
4272 QMetaObject::invokeMethod(object, "testVariantSequence");
4273 QTRY_VERIFY(object->property("finished").toBool());
4274 QVERIFY(object->property("success").toBool());
4279 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4282 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.qml");
4283 QDeclarativeComponent component(&engine, qmlFile);
4284 QObject *object = component.create();
4285 QVERIFY(object != 0);
4286 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4287 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4288 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4289 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4290 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4295 QUrl qmlFile = TEST_FILE("sequenceConversion.bindings.error.qml");
4296 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4297 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4298 QDeclarativeComponent component(&engine, qmlFile);
4299 QObject *object = component.create();
4300 QVERIFY(object != 0);
4305 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4307 QUrl qmlFile = TEST_FILE("sequenceConversion.copy.qml");
4308 QDeclarativeComponent component(&engine, qmlFile);
4309 QObject *object = component.create();
4310 QVERIFY(object != 0);
4311 QMetaObject::invokeMethod(object, "testCopySequences");
4312 QCOMPARE(object->property("success").toBool(), true);
4313 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4314 QCOMPARE(object->property("success").toBool(), true);
4315 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4316 QCOMPARE(object->property("success").toBool(), true);
4320 // Test that assigning a null object works
4321 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4322 void tst_qdeclarativeecmascript::nullObjectBinding()
4324 QDeclarativeComponent component(&engine, TEST_FILE("nullObjectBinding.qml"));
4326 QObject *object = component.create();
4327 QVERIFY(object != 0);
4329 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4334 // Test that bindings don't evaluate once the engine has been destroyed
4335 void tst_qdeclarativeecmascript::deletedEngine()
4337 QDeclarativeEngine *engine = new QDeclarativeEngine;
4338 QDeclarativeComponent component(engine, TEST_FILE("deletedEngine.qml"));
4340 QObject *object = component.create();
4341 QVERIFY(object != 0);
4343 QCOMPARE(object->property("a").toInt(), 39);
4344 object->setProperty("b", QVariant(9));
4345 QCOMPARE(object->property("a").toInt(), 117);
4349 QCOMPARE(object->property("a").toInt(), 117);
4350 object->setProperty("b", QVariant(10));
4351 QCOMPARE(object->property("a").toInt(), 117);
4356 // Test the crashing part of QTBUG-9705
4357 void tst_qdeclarativeecmascript::libraryScriptAssert()
4359 QDeclarativeComponent component(&engine, TEST_FILE("libraryScriptAssert.qml"));
4361 QObject *object = component.create();
4362 QVERIFY(object != 0);
4367 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4369 QDeclarativeComponent component(&engine, TEST_FILE("variantsAssignedUndefined.qml"));
4371 QObject *object = component.create();
4372 QVERIFY(object != 0);
4374 QCOMPARE(object->property("test1").toInt(), 10);
4375 QCOMPARE(object->property("test2").toInt(), 11);
4377 object->setProperty("runTest", true);
4379 QCOMPARE(object->property("test1"), QVariant());
4380 QCOMPARE(object->property("test2"), QVariant());
4386 void tst_qdeclarativeecmascript::qtbug_9792()
4388 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_9792.qml"));
4390 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4392 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4393 QVERIFY(object != 0);
4395 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4396 object->basicSignal();
4400 transientErrorsMsgCount = 0;
4401 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4403 object->basicSignal();
4405 qInstallMsgHandler(old);
4407 QCOMPARE(transientErrorsMsgCount, 0);
4412 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4413 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4415 QDeclarativeComponent component(&engine, TEST_FILE("qtcreatorbug_1289.qml"));
4417 QObject *o = component.create();
4420 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4421 QVERIFY(nested != 0);
4423 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4426 nested = qvariant_cast<QObject *>(o->property("object"));
4427 QVERIFY(nested == 0);
4429 // If the bug is present, the next line will crash
4433 // Test that we shut down without stupid warnings
4434 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4437 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.qml"));
4439 QObject *o = component.create();
4441 transientErrorsMsgCount = 0;
4442 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4446 qInstallMsgHandler(old);
4448 QCOMPARE(transientErrorsMsgCount, 0);
4453 QDeclarativeComponent component(&engine, TEST_FILE("noSpuriousWarningsAtShutdown.2.qml"));
4455 QObject *o = component.create();
4457 transientErrorsMsgCount = 0;
4458 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4462 qInstallMsgHandler(old);
4464 QCOMPARE(transientErrorsMsgCount, 0);
4468 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4471 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.1.qml"));
4473 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4476 QVERIFY(o->objectProperty() != 0);
4478 o->setProperty("runTest", true);
4480 QVERIFY(o->objectProperty() == 0);
4486 QDeclarativeComponent component(&engine, TEST_FILE("canAssignNullToQObject.2.qml"));
4488 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4491 QVERIFY(o->objectProperty() == 0);
4497 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4499 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.1.qml"));
4501 QString url = component.url().toString();
4502 QString warning = url + ":4: Unable to assign a function to a property.";
4503 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4505 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4508 QVERIFY(!o->property("a").isValid());
4513 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4515 QFETCH(QString, triggerProperty);
4517 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4518 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4520 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4522 QVERIFY(!o->property("a").isValid());
4524 o->setProperty("aNumber", QVariant(5));
4525 o->setProperty(triggerProperty.toUtf8().constData(), true);
4526 QCOMPARE(o->property("a"), QVariant(50));
4528 o->setProperty("aNumber", QVariant(10));
4529 QCOMPARE(o->property("a"), QVariant(100));
4534 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4536 QTest::addColumn<QString>("triggerProperty");
4538 QTest::newRow("assign to property") << "assignToProperty";
4539 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4541 QTest::newRow("assign to value type") << "assignToValueType";
4543 QTest::newRow("use 'this'") << "assignWithThis";
4544 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4547 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4549 QDeclarativeComponent component(&engine, TEST_FILE("functionAssignment.2.qml"));
4550 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4552 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4554 QVERIFY(!o->property("a").isValid());
4556 o->setProperty("assignFuncWithoutReturn", true);
4557 QVERIFY(!o->property("a").isValid());
4559 QString url = component.url().toString();
4560 QString warning = url + ":67: Unable to assign QString to int";
4561 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4562 o->setProperty("assignWrongType", true);
4564 warning = url + ":71: Unable to assign QString to int";
4565 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4566 o->setProperty("assignWrongTypeToValueType", true);
4571 void tst_qdeclarativeecmascript::eval()
4573 QDeclarativeComponent component(&engine, TEST_FILE("eval.qml"));
4575 QObject *o = component.create();
4578 QCOMPARE(o->property("test1").toBool(), true);
4579 QCOMPARE(o->property("test2").toBool(), true);
4580 QCOMPARE(o->property("test3").toBool(), true);
4581 QCOMPARE(o->property("test4").toBool(), true);
4582 QCOMPARE(o->property("test5").toBool(), true);
4587 void tst_qdeclarativeecmascript::function()
4589 QDeclarativeComponent component(&engine, TEST_FILE("function.qml"));
4591 QObject *o = component.create();
4594 QCOMPARE(o->property("test1").toBool(), true);
4595 QCOMPARE(o->property("test2").toBool(), true);
4596 QCOMPARE(o->property("test3").toBool(), true);
4601 // Test the "Qt.include" method
4602 void tst_qdeclarativeecmascript::include()
4604 // Non-library relative include
4606 QDeclarativeComponent component(&engine, TEST_FILE("include.qml"));
4607 QObject *o = component.create();
4610 QCOMPARE(o->property("test0").toInt(), 99);
4611 QCOMPARE(o->property("test1").toBool(), true);
4612 QCOMPARE(o->property("test2").toBool(), true);
4613 QCOMPARE(o->property("test2_1").toBool(), true);
4614 QCOMPARE(o->property("test3").toBool(), true);
4615 QCOMPARE(o->property("test3_1").toBool(), true);
4620 // Library relative include
4622 QDeclarativeComponent component(&engine, TEST_FILE("include_shared.qml"));
4623 QObject *o = component.create();
4626 QCOMPARE(o->property("test0").toInt(), 99);
4627 QCOMPARE(o->property("test1").toBool(), true);
4628 QCOMPARE(o->property("test2").toBool(), true);
4629 QCOMPARE(o->property("test2_1").toBool(), true);
4630 QCOMPARE(o->property("test3").toBool(), true);
4631 QCOMPARE(o->property("test3_1").toBool(), true);
4638 QDeclarativeComponent component(&engine, TEST_FILE("include_callback.qml"));
4639 QObject *o = component.create();
4642 QCOMPARE(o->property("test1").toBool(), true);
4643 QCOMPARE(o->property("test2").toBool(), true);
4644 QCOMPARE(o->property("test3").toBool(), true);
4645 QCOMPARE(o->property("test4").toBool(), true);
4646 QCOMPARE(o->property("test5").toBool(), true);
4647 QCOMPARE(o->property("test6").toBool(), true);
4652 // Including file with ".pragma library"
4654 QDeclarativeComponent component(&engine, TEST_FILE("include_pragma.qml"));
4655 QObject *o = component.create();
4657 QCOMPARE(o->property("test1").toInt(), 100);
4664 TestHTTPServer server(8111);
4665 QVERIFY(server.isValid());
4666 server.serveDirectory(TESTDATA(""));
4668 QDeclarativeComponent component(&engine, TEST_FILE("include_remote.qml"));
4669 QObject *o = component.create();
4672 QTRY_VERIFY(o->property("done").toBool() == true);
4673 QTRY_VERIFY(o->property("done2").toBool() == true);
4675 QCOMPARE(o->property("test1").toBool(), true);
4676 QCOMPARE(o->property("test2").toBool(), true);
4677 QCOMPARE(o->property("test3").toBool(), true);
4678 QCOMPARE(o->property("test4").toBool(), true);
4679 QCOMPARE(o->property("test5").toBool(), true);
4681 QCOMPARE(o->property("test6").toBool(), true);
4682 QCOMPARE(o->property("test7").toBool(), true);
4683 QCOMPARE(o->property("test8").toBool(), true);
4684 QCOMPARE(o->property("test9").toBool(), true);
4685 QCOMPARE(o->property("test10").toBool(), true);
4692 TestHTTPServer server(8111);
4693 QVERIFY(server.isValid());
4694 server.serveDirectory(TESTDATA(""));
4696 QDeclarativeComponent component(&engine, TEST_FILE("include_remote_missing.qml"));
4697 QObject *o = component.create();
4700 QTRY_VERIFY(o->property("done").toBool() == true);
4702 QCOMPARE(o->property("test1").toBool(), true);
4703 QCOMPARE(o->property("test2").toBool(), true);
4704 QCOMPARE(o->property("test3").toBool(), true);
4710 void tst_qdeclarativeecmascript::signalHandlers()
4712 QDeclarativeComponent component(&engine, TEST_FILE("signalHandlers.qml"));
4713 QObject *o = component.create();
4716 QVERIFY(o->property("count").toInt() == 0);
4717 QMetaObject::invokeMethod(o, "testSignalCall");
4718 QCOMPARE(o->property("count").toInt(), 1);
4720 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
4721 QCOMPARE(o->property("count").toInt(), 1);
4722 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
4724 QVERIFY(o->property("funcCount").toInt() == 0);
4725 QMetaObject::invokeMethod(o, "testSignalConnection");
4726 QCOMPARE(o->property("funcCount").toInt(), 1);
4728 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
4729 QCOMPARE(o->property("funcCount").toInt(), 2);
4731 QMetaObject::invokeMethod(o, "testSignalDefined");
4732 QCOMPARE(o->property("definedResult").toBool(), true);
4734 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
4735 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
4740 void tst_qdeclarativeecmascript::qtbug_10696()
4742 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_10696.qml"));
4743 QObject *o = component.create();
4748 void tst_qdeclarativeecmascript::qtbug_11606()
4750 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11606.qml"));
4751 QObject *o = component.create();
4753 QCOMPARE(o->property("test").toBool(), true);
4757 void tst_qdeclarativeecmascript::qtbug_11600()
4759 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_11600.qml"));
4760 QObject *o = component.create();
4762 QCOMPARE(o->property("test").toBool(), true);
4766 // Reading and writing non-scriptable properties should fail
4767 void tst_qdeclarativeecmascript::nonscriptable()
4769 QDeclarativeComponent component(&engine, TEST_FILE("nonscriptable.qml"));
4770 QObject *o = component.create();
4772 QCOMPARE(o->property("readOk").toBool(), true);
4773 QCOMPARE(o->property("writeOk").toBool(), true);
4777 // deleteLater() should not be callable from QML
4778 void tst_qdeclarativeecmascript::deleteLater()
4780 QDeclarativeComponent component(&engine, TEST_FILE("deleteLater.qml"));
4781 QObject *o = component.create();
4783 QCOMPARE(o->property("test").toBool(), true);
4787 void tst_qdeclarativeecmascript::in()
4789 QDeclarativeComponent component(&engine, TEST_FILE("in.qml"));
4790 QObject *o = component.create();
4792 QCOMPARE(o->property("test1").toBool(), true);
4793 QCOMPARE(o->property("test2").toBool(), true);
4797 void tst_qdeclarativeecmascript::typeOf()
4799 QDeclarativeComponent component(&engine, TEST_FILE("typeOf.qml"));
4800 QObject *o = component.create();
4802 QEXPECT_FAIL("", "QTBUG-21864", Abort);
4803 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
4804 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
4805 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
4806 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
4807 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
4808 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
4809 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
4810 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
4811 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
4816 void tst_qdeclarativeecmascript::sharedAttachedObject()
4818 QDeclarativeComponent component(&engine, TEST_FILE("sharedAttachedObject.qml"));
4819 QObject *o = component.create();
4821 QCOMPARE(o->property("test1").toBool(), true);
4822 QCOMPARE(o->property("test2").toBool(), true);
4827 void tst_qdeclarativeecmascript::objectName()
4829 QDeclarativeComponent component(&engine, TEST_FILE("objectName.qml"));
4830 QObject *o = component.create();
4833 QCOMPARE(o->property("test1").toString(), QString("hello"));
4834 QCOMPARE(o->property("test2").toString(), QString("ell"));
4836 o->setObjectName("world");
4838 QCOMPARE(o->property("test1").toString(), QString("world"));
4839 QCOMPARE(o->property("test2").toString(), QString("orl"));
4844 void tst_qdeclarativeecmascript::writeRemovesBinding()
4846 QDeclarativeComponent component(&engine, TEST_FILE("writeRemovesBinding.qml"));
4847 QObject *o = component.create();
4850 QCOMPARE(o->property("test").toBool(), true);
4855 // Test bindings assigned to alias properties actually assign to the alias' target
4856 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
4858 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsAssignCorrectly.qml"));
4859 QObject *o = component.create();
4862 QCOMPARE(o->property("test").toBool(), true);
4867 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
4868 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
4871 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.qml"));
4872 QObject *o = component.create();
4875 QCOMPARE(o->property("test").toBool(), true);
4881 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.2.qml"));
4882 QObject *o = component.create();
4885 QCOMPARE(o->property("test").toBool(), true);
4891 QDeclarativeComponent component(&engine, TEST_FILE("aliasBindingsOverrideTarget.3.qml"));
4892 QObject *o = component.create();
4895 QCOMPARE(o->property("test").toBool(), true);
4901 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
4902 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
4905 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.qml"));
4906 QObject *o = component.create();
4909 QCOMPARE(o->property("test").toBool(), true);
4915 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.2.qml"));
4916 QObject *o = component.create();
4919 QCOMPARE(o->property("test").toBool(), true);
4925 QDeclarativeComponent component(&engine, TEST_FILE("aliasWritesOverrideBindings.3.qml"));
4926 QObject *o = component.create();
4929 QCOMPARE(o->property("test").toBool(), true);
4935 // Allow an alais to a composite element
4937 void tst_qdeclarativeecmascript::aliasToCompositeElement()
4939 QDeclarativeComponent component(&engine, TEST_FILE("aliasToCompositeElement.qml"));
4941 QObject *object = component.create();
4942 QVERIFY(object != 0);
4947 void tst_qdeclarativeecmascript::qtbug_20344()
4949 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_20344.qml"));
4951 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
4952 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
4954 QObject *object = component.create();
4955 QVERIFY(object != 0);
4960 void tst_qdeclarativeecmascript::revisionErrors()
4963 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors.qml"));
4964 QString url = component.url().toString();
4966 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4967 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
4968 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
4970 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4971 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4972 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4973 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4974 QVERIFY(object != 0);
4978 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors2.qml"));
4979 QString url = component.url().toString();
4981 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
4982 // method2, prop2 from MyRevisionedClass not available
4983 // method4, prop4 from MyRevisionedSubclass not available
4984 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
4985 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
4986 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
4987 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
4988 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
4990 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
4991 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
4992 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
4993 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
4994 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
4995 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
4996 QVERIFY(object != 0);
5000 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevisionErrors3.qml"));
5001 QString url = component.url().toString();
5003 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
5004 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
5005 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
5006 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
5007 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
5008 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5009 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5010 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5011 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5012 QVERIFY(object != 0);
5017 void tst_qdeclarativeecmascript::revision()
5020 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision.qml"));
5021 QString url = component.url().toString();
5023 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5024 QVERIFY(object != 0);
5028 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision2.qml"));
5029 QString url = component.url().toString();
5031 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5032 QVERIFY(object != 0);
5036 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision3.qml"));
5037 QString url = component.url().toString();
5039 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5040 QVERIFY(object != 0);
5043 // Test that non-root classes can resolve revisioned methods
5045 QDeclarativeComponent component(&engine, TEST_FILE("metaobjectRevision4.qml"));
5047 QObject *object = component.create();
5048 QVERIFY(object != 0);
5049 QCOMPARE(object->property("test").toReal(), 11.);
5054 void tst_qdeclarativeecmascript::realToInt()
5056 QDeclarativeComponent component(&engine, TEST_FILE("realToInt.qml"));
5057 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5058 QVERIFY(object != 0);
5060 QMetaObject::invokeMethod(object, "test1");
5061 QCOMPARE(object->value(), int(4));
5062 QMetaObject::invokeMethod(object, "test2");
5063 QCOMPARE(object->value(), int(8));
5065 void tst_qdeclarativeecmascript::dynamicString()
5067 QDeclarativeComponent component(&engine, TEST_FILE("dynamicString.qml"));
5068 QObject *object = component.create();
5069 QVERIFY(object != 0);
5070 QCOMPARE(object->property("stringProperty").toString(),
5071 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5074 void tst_qdeclarativeecmascript::automaticSemicolon()
5076 QDeclarativeComponent component(&engine, TEST_FILE("automaticSemicolon.qml"));
5077 QObject *object = component.create();
5078 QVERIFY(object != 0);
5081 void tst_qdeclarativeecmascript::unaryExpression()
5083 QDeclarativeComponent component(&engine, TEST_FILE("unaryExpression.qml"));
5084 QObject *object = component.create();
5085 QVERIFY(object != 0);
5088 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5089 void tst_qdeclarativeecmascript::doubleEvaluate()
5091 QDeclarativeComponent component(&engine, TEST_FILE("doubleEvaluate.qml"));
5092 QObject *object = component.create();
5093 QVERIFY(object != 0);
5094 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5096 QCOMPARE(wc->count(), 1);
5098 wc->setProperty("x", 9);
5100 QCOMPARE(wc->count(), 2);
5105 static QStringList messages;
5106 static void captureMsgHandler(QtMsgType, const char *msg)
5108 messages.append(QLatin1String(msg));
5111 void tst_qdeclarativeecmascript::nonNotifyable()
5113 QV4Compiler::enableV4(false);
5114 QDeclarativeComponent component(&engine, TEST_FILE("nonNotifyable.qml"));
5115 QV4Compiler::enableV4(true);
5117 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5119 QObject *object = component.create();
5120 qInstallMsgHandler(old);
5122 QVERIFY(object != 0);
5124 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5125 component.url().toString() +
5126 QLatin1String(":5 depends on non-NOTIFYable properties:");
5127 QString expected2 = QLatin1String(" ") +
5128 QLatin1String(object->metaObject()->className()) +
5129 QLatin1String("::value");
5131 QCOMPARE(messages.length(), 2);
5132 QCOMPARE(messages.at(0), expected1);
5133 QCOMPARE(messages.at(1), expected2);
5138 void tst_qdeclarativeecmascript::forInLoop()
5140 QDeclarativeComponent component(&engine, TEST_FILE("forInLoop.qml"));
5141 QObject *object = component.create();
5142 QVERIFY(object != 0);
5144 QMetaObject::invokeMethod(object, "listProperty");
5146 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5147 QCOMPARE(r.size(), 3);
5148 QCOMPARE(r[0],QLatin1String("0=obj1"));
5149 QCOMPARE(r[1],QLatin1String("1=obj2"));
5150 QCOMPARE(r[2],QLatin1String("2=obj3"));
5152 //TODO: should test for in loop for other objects (such as QObjects) as well.
5157 // An object the binding depends on is deleted while the binding is still running
5158 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5160 QDeclarativeComponent component(&engine, TEST_FILE("deleteWhileBindingRunning.qml"));
5161 QObject *object = component.create();
5162 QVERIFY(object != 0);
5166 void tst_qdeclarativeecmascript::qtbug_22679()
5169 object.setStringProperty(QLatin1String("Please work correctly"));
5170 engine.rootContext()->setContextProperty("contextProp", &object);
5172 QDeclarativeComponent component(&engine, TEST_FILE("qtbug_22679.qml"));
5173 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5174 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5176 QObject *o = component.create();
5178 QCOMPARE(warningsSpy.count(), 0);
5182 void tst_qdeclarativeecmascript::qtbug_22843_data()
5184 QTest::addColumn<bool>("library");
5186 QTest::newRow("without .pragma library") << false;
5187 QTest::newRow("with .pragma library") << true;
5190 void tst_qdeclarativeecmascript::qtbug_22843()
5192 QFETCH(bool, library);
5194 QString fileName("qtbug_22843");
5196 fileName += QLatin1String(".library");
5197 fileName += QLatin1String(".qml");
5199 QDeclarativeComponent component(&engine, TEST_FILE(fileName));
5200 QString url = component.url().toString();
5201 QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
5202 QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
5204 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5205 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5206 for (int x = 0; x < 3; ++x) {
5207 warningsSpy.clear();
5208 // For libraries, only the first import attempt should produce a
5209 // SyntaxError warning; subsequent component creation should not
5210 // attempt to reload the script.
5211 bool expectSyntaxError = !library || (x == 0);
5212 if (expectSyntaxError)
5213 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5214 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5215 QObject *object = component.create();
5216 QVERIFY(object != 0);
5217 QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
5222 QTEST_MAIN(tst_qdeclarativeecmascript)
5224 #include "tst_qdeclarativeecmascript.moc"