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/qdeclarativevmemetaobject_p.h>
53 #include <private/qv4compiler_p.h>
54 #include "testtypes.h"
55 #include "testhttpserver.h"
56 #include "../../shared/util.h"
59 This test covers evaluation of ECMAScript expressions and bindings from within
60 QML. This does not include static QML language issues.
62 Static QML language issues are covered in qmllanguage
65 class tst_qdeclarativeecmascript : public QDeclarativeDataTest
69 tst_qdeclarativeecmascript() {}
73 void assignBasicTypes();
74 void idShortcutInvalidates();
75 void boolPropertiesEvaluateAsBool();
77 void signalAssignment();
79 void basicExpressions();
80 void basicExpressions_data();
81 void arrayExpressions();
82 void contextPropertiesTriggerReeval();
83 void objectPropertiesTriggerReeval();
84 void deferredProperties();
85 void deferredPropertiesErrors();
86 void extensionObjects();
87 void overrideExtensionProperties();
88 void attachedProperties();
90 void valueTypeFunctions();
91 void constantsOverrideBindings();
92 void outerBindingOverridesInnerBinding();
93 void aliasPropertyAndBinding();
94 void aliasPropertyReset();
95 void nonExistentAttachedObject();
98 void signalParameterTypes();
99 void objectsCompareAsEqual();
100 void dynamicCreation_data();
101 void dynamicCreation();
102 void dynamicDestruction();
103 void objectToString();
104 void objectHasOwnProperty();
105 void selfDeletingBinding();
106 void extendedObjectPropertyLookup();
107 void extendedObjectPropertyLookup2();
109 void functionErrors();
110 void propertyAssignmentErrors();
111 void signalTriggeredBindings();
112 void listProperties();
113 void exceptionClearsOnReeval();
114 void exceptionSlotProducesWarning();
115 void exceptionBindingProducesWarning();
116 void transientErrors();
117 void shutdownErrors();
118 void compositePropertyType();
120 void undefinedResetsProperty();
121 void listToVariant();
122 void listAssignment();
123 void multiEngineObject();
124 void deletedObject();
125 void attachedPropertyScope();
126 void scriptConnect();
127 void scriptDisconnect();
129 void cppOwnershipReturnValue();
130 void ownershipCustomReturnValue();
131 void qlistqobjectMethods();
132 void strictlyEquals();
134 void numberAssignment();
135 void propertySplicing();
136 void signalWithUnknownTypes();
137 void signalWithJSValueInVariant_data();
138 void signalWithJSValueInVariant();
139 void signalWithJSValueInVariant_twoEngines_data();
140 void signalWithJSValueInVariant_twoEngines();
141 void signalWithQJSValue_data();
142 void signalWithQJSValue();
143 void moduleApi_data();
145 void importScripts_data();
146 void importScripts();
147 void scarceResources();
148 void scarceResources_data();
149 void scarceResources_other();
150 void propertyChangeSlots();
151 void propertyVar_data();
153 void propertyVarCpp();
154 void propertyVarOwnership();
155 void propertyVarImplicitOwnership();
156 void propertyVarReparent();
157 void propertyVarReparentNullContext();
158 void propertyVarCircular();
159 void propertyVarCircular2();
160 void propertyVarInheritance();
161 void propertyVarInheritance2();
162 void elementAssign();
163 void objectPassThroughSignals();
164 void objectConversion();
165 void booleanConversion();
166 void handleReferenceManagement();
168 void readonlyDeclaration();
169 void sequenceConversionRead();
170 void sequenceConversionWrite();
171 void sequenceConversionArray();
172 void sequenceConversionThreads();
173 void sequenceConversionBindings();
174 void sequenceConversionCopy();
175 void assignSequenceTypes();
181 void dynamicCreationCrash();
182 void dynamicCreationOwnership();
184 void nullObjectBinding();
185 void deletedEngine();
186 void libraryScriptAssert();
187 void variantsAssignedUndefined();
189 void qtcreatorbug_1289();
190 void noSpuriousWarningsAtShutdown();
191 void canAssignNullToQObject();
192 void functionAssignment_fromBinding();
193 void functionAssignment_fromJS();
194 void functionAssignment_fromJS_data();
195 void functionAssignmentfromJS_invalid();
202 void nonscriptable();
206 void sharedAttachedObject();
208 void writeRemovesBinding();
209 void aliasBindingsAssignCorrectly();
210 void aliasBindingsOverrideTarget();
211 void aliasWritesOverrideBindings();
212 void aliasToCompositeElement();
215 void dynamicString();
217 void signalHandlers();
218 void doubleEvaluate();
220 void nonNotifyable();
221 void deleteWhileBindingRunning();
222 void callQtInvokables();
223 void invokableObjectArg();
224 void invokableObjectRet();
227 void qtbug_22843_data();
229 void revisionErrors();
232 void automaticSemicolon();
233 void unaryExpression();
234 void switchStatement();
235 void withStatement();
239 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
240 QDeclarativeEngine engine;
243 void tst_qdeclarativeecmascript::initTestCase()
245 QDeclarativeDataTest::initTestCase();
249 void tst_qdeclarativeecmascript::assignBasicTypes()
252 QDeclarativeComponent component(&engine, testFileUrl("assignBasicTypes.qml"));
253 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
254 QVERIFY(object != 0);
255 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
256 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
257 QCOMPARE(object->stringProperty(), QString("Hello World!"));
258 QCOMPARE(object->uintProperty(), uint(10));
259 QCOMPARE(object->intProperty(), -19);
260 QCOMPARE((float)object->realProperty(), float(23.2));
261 QCOMPARE((float)object->doubleProperty(), float(-19.75));
262 QCOMPARE((float)object->floatProperty(), float(8.5));
263 QCOMPARE(object->colorProperty(), QColor("red"));
264 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
265 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
266 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
267 QCOMPARE(object->pointProperty(), QPoint(99,13));
268 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
269 QCOMPARE(object->sizeProperty(), QSize(99, 13));
270 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
271 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
272 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
273 QCOMPARE(object->boolProperty(), true);
274 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
275 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
276 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
280 QDeclarativeComponent component(&engine, testFileUrl("assignBasicTypes.2.qml"));
281 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
282 QVERIFY(object != 0);
283 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
284 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
285 QCOMPARE(object->stringProperty(), QString("Hello World!"));
286 QCOMPARE(object->uintProperty(), uint(10));
287 QCOMPARE(object->intProperty(), -19);
288 QCOMPARE((float)object->realProperty(), float(23.2));
289 QCOMPARE((float)object->doubleProperty(), float(-19.75));
290 QCOMPARE((float)object->floatProperty(), float(8.5));
291 QCOMPARE(object->colorProperty(), QColor("red"));
292 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
293 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
294 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
295 QCOMPARE(object->pointProperty(), QPoint(99,13));
296 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
297 QCOMPARE(object->sizeProperty(), QSize(99, 13));
298 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
299 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
300 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
301 QCOMPARE(object->boolProperty(), true);
302 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
303 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
304 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
309 void tst_qdeclarativeecmascript::idShortcutInvalidates()
312 QDeclarativeComponent component(&engine, testFileUrl("idShortcutInvalidates.qml"));
313 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
314 QVERIFY(object != 0);
315 QVERIFY(object->objectProperty() != 0);
316 delete object->objectProperty();
317 QVERIFY(object->objectProperty() == 0);
322 QDeclarativeComponent component(&engine, testFileUrl("idShortcutInvalidates.1.qml"));
323 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
324 QVERIFY(object != 0);
325 QVERIFY(object->objectProperty() != 0);
326 delete object->objectProperty();
327 QVERIFY(object->objectProperty() == 0);
332 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
335 QDeclarativeComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.1.qml"));
336 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
337 QVERIFY(object != 0);
338 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
342 QDeclarativeComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.2.qml"));
343 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
344 QVERIFY(object != 0);
345 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
350 void tst_qdeclarativeecmascript::signalAssignment()
353 QDeclarativeComponent component(&engine, testFileUrl("signalAssignment.1.qml"));
354 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
355 QVERIFY(object != 0);
356 QCOMPARE(object->string(), QString());
357 emit object->basicSignal();
358 QCOMPARE(object->string(), QString("pass"));
363 QDeclarativeComponent component(&engine, testFileUrl("signalAssignment.2.qml"));
364 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
365 QVERIFY(object != 0);
366 QCOMPARE(object->string(), QString());
367 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
368 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
373 void tst_qdeclarativeecmascript::methods()
376 QDeclarativeComponent component(&engine, testFileUrl("methods.1.qml"));
377 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
378 QVERIFY(object != 0);
379 QCOMPARE(object->methodCalled(), false);
380 QCOMPARE(object->methodIntCalled(), false);
381 emit object->basicSignal();
382 QCOMPARE(object->methodCalled(), true);
383 QCOMPARE(object->methodIntCalled(), false);
388 QDeclarativeComponent component(&engine, testFileUrl("methods.2.qml"));
389 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
390 QVERIFY(object != 0);
391 QCOMPARE(object->methodCalled(), false);
392 QCOMPARE(object->methodIntCalled(), false);
393 emit object->basicSignal();
394 QCOMPARE(object->methodCalled(), false);
395 QCOMPARE(object->methodIntCalled(), true);
400 QDeclarativeComponent component(&engine, testFileUrl("methods.3.qml"));
401 QObject *object = component.create();
402 QVERIFY(object != 0);
403 QCOMPARE(object->property("test").toInt(), 19);
408 QDeclarativeComponent component(&engine, testFileUrl("methods.4.qml"));
409 QObject *object = component.create();
410 QVERIFY(object != 0);
411 QCOMPARE(object->property("test").toInt(), 19);
412 QCOMPARE(object->property("test2").toInt(), 17);
413 QCOMPARE(object->property("test3").toInt(), 16);
418 QDeclarativeComponent component(&engine, testFileUrl("methods.5.qml"));
419 QObject *object = component.create();
420 QVERIFY(object != 0);
421 QCOMPARE(object->property("test").toInt(), 9);
426 void tst_qdeclarativeecmascript::bindingLoop()
428 QDeclarativeComponent component(&engine, testFileUrl("bindingLoop.qml"));
429 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
430 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
431 QObject *object = component.create();
432 QVERIFY(object != 0);
436 void tst_qdeclarativeecmascript::basicExpressions_data()
438 QTest::addColumn<QString>("expression");
439 QTest::addColumn<QVariant>("result");
440 QTest::addColumn<bool>("nest");
442 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
443 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
444 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
445 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
446 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
447 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
448 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
449 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
450 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
451 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
452 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
453 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
454 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
455 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
456 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
457 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
458 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
459 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
460 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
463 void tst_qdeclarativeecmascript::basicExpressions()
465 QFETCH(QString, expression);
466 QFETCH(QVariant, result);
472 MyDefaultObject1 default1;
473 MyDefaultObject3 default3;
474 object1.setStringProperty("Object1");
475 object2.setStringProperty("Object2");
476 object3.setStringProperty("Object3");
478 QDeclarativeContext context(engine.rootContext());
479 QDeclarativeContext nestedContext(&context);
481 context.setContextObject(&default1);
482 context.setContextProperty("a", QVariant(1944));
483 context.setContextProperty("b", QVariant("Milk"));
484 context.setContextProperty("object", &object1);
485 context.setContextProperty("objectOverride", &object2);
486 nestedContext.setContextObject(&default3);
487 nestedContext.setContextProperty("b", QVariant("Cow"));
488 nestedContext.setContextProperty("objectOverride", &object3);
489 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
491 MyExpression expr(nest?&nestedContext:&context, expression);
492 QCOMPARE(expr.evaluate(), result);
495 void tst_qdeclarativeecmascript::arrayExpressions()
501 QDeclarativeContext context(engine.rootContext());
502 context.setContextProperty("a", &obj1);
503 context.setContextProperty("b", &obj2);
504 context.setContextProperty("c", &obj3);
506 MyExpression expr(&context, "[a, b, c, 10]");
507 QVariant result = expr.evaluate();
508 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
509 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
510 QCOMPARE(list.count(), 4);
511 QCOMPARE(list.at(0), &obj1);
512 QCOMPARE(list.at(1), &obj2);
513 QCOMPARE(list.at(2), &obj3);
514 QCOMPARE(list.at(3), (QObject *)0);
517 // Tests that modifying a context property will reevaluate expressions
518 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
520 QDeclarativeContext context(engine.rootContext());
523 MyQmlObject *object3 = new MyQmlObject;
525 object1.setStringProperty("Hello");
526 object2.setStringProperty("World");
528 context.setContextProperty("testProp", QVariant(1));
529 context.setContextProperty("testObj", &object1);
530 context.setContextProperty("testObj2", object3);
533 MyExpression expr(&context, "testProp + 1");
534 QCOMPARE(expr.changed, false);
535 QCOMPARE(expr.evaluate(), QVariant(2));
537 context.setContextProperty("testProp", QVariant(2));
538 QCOMPARE(expr.changed, true);
539 QCOMPARE(expr.evaluate(), QVariant(3));
543 MyExpression expr(&context, "testProp + testProp + testProp");
544 QCOMPARE(expr.changed, false);
545 QCOMPARE(expr.evaluate(), QVariant(6));
547 context.setContextProperty("testProp", QVariant(4));
548 QCOMPARE(expr.changed, true);
549 QCOMPARE(expr.evaluate(), QVariant(12));
553 MyExpression expr(&context, "testObj.stringProperty");
554 QCOMPARE(expr.changed, false);
555 QCOMPARE(expr.evaluate(), QVariant("Hello"));
557 context.setContextProperty("testObj", &object2);
558 QCOMPARE(expr.changed, true);
559 QCOMPARE(expr.evaluate(), QVariant("World"));
563 MyExpression expr(&context, "testObj.stringProperty /**/");
564 QCOMPARE(expr.changed, false);
565 QCOMPARE(expr.evaluate(), QVariant("World"));
567 context.setContextProperty("testObj", &object1);
568 QCOMPARE(expr.changed, true);
569 QCOMPARE(expr.evaluate(), QVariant("Hello"));
573 MyExpression expr(&context, "testObj2");
574 QCOMPARE(expr.changed, false);
575 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
581 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
583 QDeclarativeContext context(engine.rootContext());
587 context.setContextProperty("testObj", &object1);
589 object1.setStringProperty(QLatin1String("Hello"));
590 object2.setStringProperty(QLatin1String("Dog"));
591 object3.setStringProperty(QLatin1String("Cat"));
594 MyExpression expr(&context, "testObj.stringProperty");
595 QCOMPARE(expr.changed, false);
596 QCOMPARE(expr.evaluate(), QVariant("Hello"));
598 object1.setStringProperty(QLatin1String("World"));
599 QCOMPARE(expr.changed, true);
600 QCOMPARE(expr.evaluate(), QVariant("World"));
604 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
605 QCOMPARE(expr.changed, false);
606 QCOMPARE(expr.evaluate(), QVariant());
608 object1.setObjectProperty(&object2);
609 QCOMPARE(expr.changed, true);
610 expr.changed = false;
611 QCOMPARE(expr.evaluate(), QVariant("Dog"));
613 object1.setObjectProperty(&object3);
614 QCOMPARE(expr.changed, true);
615 expr.changed = false;
616 QCOMPARE(expr.evaluate(), QVariant("Cat"));
618 object1.setObjectProperty(0);
619 QCOMPARE(expr.changed, true);
620 expr.changed = false;
621 QCOMPARE(expr.evaluate(), QVariant());
623 object1.setObjectProperty(&object3);
624 QCOMPARE(expr.changed, true);
625 expr.changed = false;
626 QCOMPARE(expr.evaluate(), QVariant("Cat"));
628 object3.setStringProperty("Donkey");
629 QCOMPARE(expr.changed, true);
630 expr.changed = false;
631 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
635 void tst_qdeclarativeecmascript::deferredProperties()
637 QDeclarativeComponent component(&engine, testFileUrl("deferredProperties.qml"));
638 MyDeferredObject *object =
639 qobject_cast<MyDeferredObject *>(component.create());
640 QVERIFY(object != 0);
641 QCOMPARE(object->value(), 0);
642 QVERIFY(object->objectProperty() == 0);
643 QVERIFY(object->objectProperty2() != 0);
644 qmlExecuteDeferred(object);
645 QCOMPARE(object->value(), 10);
646 QVERIFY(object->objectProperty() != 0);
647 MyQmlObject *qmlObject =
648 qobject_cast<MyQmlObject *>(object->objectProperty());
649 QVERIFY(qmlObject != 0);
650 QCOMPARE(qmlObject->value(), 10);
651 object->setValue(19);
652 QCOMPARE(qmlObject->value(), 19);
657 // Check errors on deferred properties are correctly emitted
658 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
660 QDeclarativeComponent component(&engine, testFileUrl("deferredPropertiesErrors.qml"));
661 MyDeferredObject *object =
662 qobject_cast<MyDeferredObject *>(component.create());
663 QVERIFY(object != 0);
664 QCOMPARE(object->value(), 0);
665 QVERIFY(object->objectProperty() == 0);
666 QVERIFY(object->objectProperty2() == 0);
668 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
669 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
671 qmlExecuteDeferred(object);
676 void tst_qdeclarativeecmascript::extensionObjects()
678 QDeclarativeComponent component(&engine, testFileUrl("extensionObjects.qml"));
679 MyExtendedObject *object =
680 qobject_cast<MyExtendedObject *>(component.create());
681 QVERIFY(object != 0);
682 QCOMPARE(object->baseProperty(), 13);
683 QCOMPARE(object->coreProperty(), 9);
684 object->setProperty("extendedProperty", QVariant(11));
685 object->setProperty("baseExtendedProperty", QVariant(92));
686 QCOMPARE(object->coreProperty(), 11);
687 QCOMPARE(object->baseProperty(), 92);
689 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
691 QCOMPARE(nested->baseProperty(), 13);
692 QCOMPARE(nested->coreProperty(), 9);
693 nested->setProperty("extendedProperty", QVariant(11));
694 nested->setProperty("baseExtendedProperty", QVariant(92));
695 QCOMPARE(nested->coreProperty(), 11);
696 QCOMPARE(nested->baseProperty(), 92);
701 void tst_qdeclarativeecmascript::overrideExtensionProperties()
703 QDeclarativeComponent component(&engine, testFileUrl("extensionObjectsPropertyOverride.qml"));
704 OverrideDefaultPropertyObject *object =
705 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
706 QVERIFY(object != 0);
707 QVERIFY(object->secondProperty() != 0);
708 QVERIFY(object->firstProperty() == 0);
713 void tst_qdeclarativeecmascript::attachedProperties()
716 QDeclarativeComponent component(&engine, testFileUrl("attachedProperty.qml"));
717 QObject *object = component.create();
718 QVERIFY(object != 0);
719 QCOMPARE(object->property("a").toInt(), 19);
720 QCOMPARE(object->property("b").toInt(), 19);
721 QCOMPARE(object->property("c").toInt(), 19);
722 QCOMPARE(object->property("d").toInt(), 19);
727 QDeclarativeComponent component(&engine, testFileUrl("attachedProperty.2.qml"));
728 QObject *object = component.create();
729 QVERIFY(object != 0);
730 QCOMPARE(object->property("a").toInt(), 26);
731 QCOMPARE(object->property("b").toInt(), 26);
732 QCOMPARE(object->property("c").toInt(), 26);
733 QCOMPARE(object->property("d").toInt(), 26);
739 QDeclarativeComponent component(&engine, testFileUrl("writeAttachedProperty.qml"));
740 QObject *object = component.create();
741 QVERIFY(object != 0);
743 QMetaObject::invokeMethod(object, "writeValue2");
745 MyQmlAttachedObject *attached =
746 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
747 QVERIFY(attached != 0);
749 QCOMPARE(attached->value2(), 9);
754 void tst_qdeclarativeecmascript::enums()
758 QDeclarativeComponent component(&engine, testFileUrl("enums.1.qml"));
759 QObject *object = component.create();
760 QVERIFY(object != 0);
762 QCOMPARE(object->property("a").toInt(), 0);
763 QCOMPARE(object->property("b").toInt(), 1);
764 QCOMPARE(object->property("c").toInt(), 2);
765 QCOMPARE(object->property("d").toInt(), 3);
766 QCOMPARE(object->property("e").toInt(), 0);
767 QCOMPARE(object->property("f").toInt(), 1);
768 QCOMPARE(object->property("g").toInt(), 2);
769 QCOMPARE(object->property("h").toInt(), 3);
770 QCOMPARE(object->property("i").toInt(), 19);
771 QCOMPARE(object->property("j").toInt(), 19);
775 // Non-existent enums
777 QDeclarativeComponent component(&engine, testFileUrl("enums.2.qml"));
779 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
780 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
781 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
782 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
784 QObject *object = component.create();
785 QVERIFY(object != 0);
786 QCOMPARE(object->property("a").toInt(), 0);
787 QCOMPARE(object->property("b").toInt(), 0);
793 void tst_qdeclarativeecmascript::valueTypeFunctions()
795 QDeclarativeComponent component(&engine, testFileUrl("valueTypeFunctions.qml"));
796 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
798 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
799 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
805 Tests that writing a constant to a property with a binding on it disables the
808 void tst_qdeclarativeecmascript::constantsOverrideBindings()
812 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.1.qml"));
813 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
814 QVERIFY(object != 0);
816 QCOMPARE(object->property("c2").toInt(), 0);
817 object->setProperty("c1", QVariant(9));
818 QCOMPARE(object->property("c2").toInt(), 9);
820 emit object->basicSignal();
822 QCOMPARE(object->property("c2").toInt(), 13);
823 object->setProperty("c1", QVariant(8));
824 QCOMPARE(object->property("c2").toInt(), 13);
829 // During construction
831 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.2.qml"));
832 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
833 QVERIFY(object != 0);
835 QCOMPARE(object->property("c1").toInt(), 0);
836 QCOMPARE(object->property("c2").toInt(), 10);
837 object->setProperty("c1", QVariant(9));
838 QCOMPARE(object->property("c1").toInt(), 9);
839 QCOMPARE(object->property("c2").toInt(), 10);
847 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.3.qml"));
848 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
849 QVERIFY(object != 0);
851 QCOMPARE(object->property("c2").toInt(), 0);
852 object->setProperty("c1", QVariant(9));
853 QCOMPARE(object->property("c2").toInt(), 9);
855 object->setProperty("c2", QVariant(13));
856 QCOMPARE(object->property("c2").toInt(), 13);
857 object->setProperty("c1", QVariant(7));
858 QCOMPARE(object->property("c1").toInt(), 7);
859 QCOMPARE(object->property("c2").toInt(), 13);
867 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.4.qml"));
868 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
869 QVERIFY(object != 0);
871 QCOMPARE(object->property("c1").toInt(), 0);
872 QCOMPARE(object->property("c3").toInt(), 10);
873 object->setProperty("c1", QVariant(9));
874 QCOMPARE(object->property("c1").toInt(), 9);
875 QCOMPARE(object->property("c3").toInt(), 10);
882 Tests that assigning a binding to a property that already has a binding causes
883 the original binding to be disabled.
885 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
887 QDeclarativeComponent component(&engine,
888 testFileUrl("outerBindingOverridesInnerBinding.qml"));
889 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
890 QVERIFY(object != 0);
892 QCOMPARE(object->property("c1").toInt(), 0);
893 QCOMPARE(object->property("c2").toInt(), 0);
894 QCOMPARE(object->property("c3").toInt(), 0);
896 object->setProperty("c1", QVariant(9));
897 QCOMPARE(object->property("c1").toInt(), 9);
898 QCOMPARE(object->property("c2").toInt(), 0);
899 QCOMPARE(object->property("c3").toInt(), 0);
901 object->setProperty("c3", QVariant(8));
902 QCOMPARE(object->property("c1").toInt(), 9);
903 QCOMPARE(object->property("c2").toInt(), 8);
904 QCOMPARE(object->property("c3").toInt(), 8);
910 Access a non-existent attached object.
912 Tests for a regression where this used to crash.
914 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
916 QDeclarativeComponent component(&engine, testFileUrl("nonExistentAttachedObject.qml"));
918 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
919 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
921 QObject *object = component.create();
922 QVERIFY(object != 0);
927 void tst_qdeclarativeecmascript::scope()
930 QDeclarativeComponent component(&engine, testFileUrl("scope.qml"));
931 QObject *object = component.create();
932 QVERIFY(object != 0);
934 QCOMPARE(object->property("test1").toInt(), 1);
935 QCOMPARE(object->property("test2").toInt(), 2);
936 QCOMPARE(object->property("test3").toString(), QString("1Test"));
937 QCOMPARE(object->property("test4").toString(), QString("2Test"));
938 QCOMPARE(object->property("test5").toInt(), 1);
939 QCOMPARE(object->property("test6").toInt(), 1);
940 QCOMPARE(object->property("test7").toInt(), 2);
941 QCOMPARE(object->property("test8").toInt(), 2);
942 QCOMPARE(object->property("test9").toInt(), 1);
943 QCOMPARE(object->property("test10").toInt(), 3);
949 QDeclarativeComponent component(&engine, testFileUrl("scope.2.qml"));
950 QObject *object = component.create();
951 QVERIFY(object != 0);
953 QCOMPARE(object->property("test1").toInt(), 19);
954 QCOMPARE(object->property("test2").toInt(), 19);
955 QCOMPARE(object->property("test3").toInt(), 14);
956 QCOMPARE(object->property("test4").toInt(), 14);
957 QCOMPARE(object->property("test5").toInt(), 24);
958 QCOMPARE(object->property("test6").toInt(), 24);
964 QDeclarativeComponent component(&engine, testFileUrl("scope.3.qml"));
965 QObject *object = component.create();
966 QVERIFY(object != 0);
968 QCOMPARE(object->property("test1").toBool(), true);
969 QCOMPARE(object->property("test2").toBool(), true);
970 QCOMPARE(object->property("test3").toBool(), true);
975 // Signal argument scope
977 QDeclarativeComponent component(&engine, testFileUrl("scope.4.qml"));
978 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
979 QVERIFY(object != 0);
981 QCOMPARE(object->property("test").toInt(), 0);
982 QCOMPARE(object->property("test2").toString(), QString());
984 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
986 QCOMPARE(object->property("test").toInt(), 13);
987 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
993 QDeclarativeComponent component(&engine, testFileUrl("scope.5.qml"));
994 QObject *object = component.create();
995 QVERIFY(object != 0);
997 QCOMPARE(object->property("test1").toBool(), true);
998 QCOMPARE(object->property("test2").toBool(), true);
1004 QDeclarativeComponent component(&engine, testFileUrl("scope.6.qml"));
1005 QObject *object = component.create();
1006 QVERIFY(object != 0);
1008 QCOMPARE(object->property("test").toBool(), true);
1014 // In 4.7, non-library javascript files that had no imports shared the imports of their
1015 // importing context
1016 void tst_qdeclarativeecmascript::importScope()
1018 QDeclarativeComponent component(&engine, testFileUrl("importScope.qml"));
1019 QObject *o = component.create();
1022 QCOMPARE(o->property("test").toInt(), 240);
1028 Tests that "any" type passes through a synthesized signal parameter. This
1029 is essentially a test of QDeclarativeMetaType::copy()
1031 void tst_qdeclarativeecmascript::signalParameterTypes()
1033 QDeclarativeComponent component(&engine, testFileUrl("signalParameterTypes.qml"));
1034 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1035 QVERIFY(object != 0);
1037 emit object->basicSignal();
1039 QCOMPARE(object->property("intProperty").toInt(), 10);
1040 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1041 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1042 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1043 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1044 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1050 Test that two JS objects for the same QObject compare as equal.
1052 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1054 QDeclarativeComponent component(&engine, testFileUrl("objectsCompareAsEqual.qml"));
1055 QObject *object = component.create();
1056 QVERIFY(object != 0);
1058 QCOMPARE(object->property("test1").toBool(), true);
1059 QCOMPARE(object->property("test2").toBool(), true);
1060 QCOMPARE(object->property("test3").toBool(), true);
1061 QCOMPARE(object->property("test4").toBool(), true);
1062 QCOMPARE(object->property("test5").toBool(), true);
1068 Confirm bindings and alias properties can coexist.
1070 Tests for a regression where the binding would not reevaluate.
1072 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1074 QDeclarativeComponent component(&engine, testFileUrl("aliasPropertyAndBinding.qml"));
1075 QObject *object = component.create();
1076 QVERIFY(object != 0);
1078 QCOMPARE(object->property("c2").toInt(), 3);
1079 QCOMPARE(object->property("c3").toInt(), 3);
1081 object->setProperty("c2", QVariant(19));
1083 QCOMPARE(object->property("c2").toInt(), 19);
1084 QCOMPARE(object->property("c3").toInt(), 19);
1090 Ensure that we can write undefined value to an alias property,
1091 and that the aliased property is reset correctly if possible.
1093 void tst_qdeclarativeecmascript::aliasPropertyReset()
1095 QObject *object = 0;
1097 // test that a manual write (of undefined) to a resettable aliased property succeeds
1098 QDeclarativeComponent c1(&engine, testFileUrl("aliasreset/aliasPropertyReset.1.qml"));
1099 object = c1.create();
1100 QVERIFY(object != 0);
1101 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1102 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1103 QMetaObject::invokeMethod(object, "resetAliased");
1104 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1105 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1108 // test that a manual write (of undefined) to a resettable alias property succeeds
1109 QDeclarativeComponent c2(&engine, testFileUrl("aliasreset/aliasPropertyReset.2.qml"));
1110 object = c2.create();
1111 QVERIFY(object != 0);
1112 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1113 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1114 QMetaObject::invokeMethod(object, "resetAlias");
1115 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1116 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1119 // test that an alias to a bound property works correctly
1120 QDeclarativeComponent c3(&engine, testFileUrl("aliasreset/aliasPropertyReset.3.qml"));
1121 object = c3.create();
1122 QVERIFY(object != 0);
1123 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1124 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1125 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1126 QMetaObject::invokeMethod(object, "resetAlias");
1127 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1128 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1129 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1132 // test that a manual write (of undefined) to a resettable alias property
1133 // whose aliased property's object has been deleted, does not crash.
1134 QDeclarativeComponent c4(&engine, testFileUrl("aliasreset/aliasPropertyReset.4.qml"));
1135 object = c4.create();
1136 QVERIFY(object != 0);
1137 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1138 QObject *loader = object->findChild<QObject*>("loader");
1139 QVERIFY(loader != 0);
1141 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1142 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1143 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1144 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1145 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1148 // test that binding an alias property to an undefined value works correctly
1149 QDeclarativeComponent c5(&engine, testFileUrl("aliasreset/aliasPropertyReset.5.qml"));
1150 object = c5.create();
1151 QVERIFY(object != 0);
1152 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1155 // test that a manual write (of undefined) to a non-resettable property fails properly
1156 QUrl url = testFileUrl("aliasreset/aliasPropertyReset.error.1.qml");
1157 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1158 QDeclarativeComponent e1(&engine, url);
1159 object = e1.create();
1160 QVERIFY(object != 0);
1161 QCOMPARE(object->property("intAlias").value<int>(), 12);
1162 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1163 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1164 QMetaObject::invokeMethod(object, "resetAlias");
1165 QCOMPARE(object->property("intAlias").value<int>(), 12);
1166 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1170 void tst_qdeclarativeecmascript::dynamicCreation_data()
1172 QTest::addColumn<QString>("method");
1173 QTest::addColumn<QString>("createdName");
1175 QTest::newRow("One") << "createOne" << "objectOne";
1176 QTest::newRow("Two") << "createTwo" << "objectTwo";
1177 QTest::newRow("Three") << "createThree" << "objectThree";
1181 Test using createQmlObject to dynamically generate an item
1182 Also using createComponent is tested.
1184 void tst_qdeclarativeecmascript::dynamicCreation()
1186 QFETCH(QString, method);
1187 QFETCH(QString, createdName);
1189 QDeclarativeComponent component(&engine, testFileUrl("dynamicCreation.qml"));
1190 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1191 QVERIFY(object != 0);
1193 QMetaObject::invokeMethod(object, method.toUtf8());
1194 QObject *created = object->objectProperty();
1196 QCOMPARE(created->objectName(), createdName);
1202 Tests the destroy function
1204 void tst_qdeclarativeecmascript::dynamicDestruction()
1207 QDeclarativeComponent component(&engine, testFileUrl("dynamicDeletion.qml"));
1208 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1209 QVERIFY(object != 0);
1210 QDeclarativeGuard<QObject> createdQmlObject = 0;
1212 QMetaObject::invokeMethod(object, "create");
1213 createdQmlObject = object->objectProperty();
1214 QVERIFY(createdQmlObject);
1215 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1217 QMetaObject::invokeMethod(object, "killOther");
1218 QVERIFY(createdQmlObject);
1219 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1220 QVERIFY(createdQmlObject);
1221 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1222 if (createdQmlObject) {
1224 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1227 QVERIFY(!createdQmlObject);
1229 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1230 QMetaObject::invokeMethod(object, "killMe");
1233 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1238 QDeclarativeComponent component(&engine, testFileUrl("dynamicDeletion.2.qml"));
1239 QObject *o = component.create();
1242 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1244 QMetaObject::invokeMethod(o, "create");
1246 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1248 QMetaObject::invokeMethod(o, "destroy");
1250 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1252 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1259 tests that id.toString() works
1261 void tst_qdeclarativeecmascript::objectToString()
1263 QDeclarativeComponent component(&engine, testFileUrl("declarativeToString.qml"));
1264 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1265 QVERIFY(object != 0);
1266 QMetaObject::invokeMethod(object, "testToString");
1267 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1268 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1274 tests that id.hasOwnProperty() works
1276 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1278 QUrl url = testFileUrl("declarativeHasOwnProperty.qml");
1279 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1280 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1281 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1283 QDeclarativeComponent component(&engine, url);
1284 QObject *object = component.create();
1285 QVERIFY(object != 0);
1287 // test QObjects in QML
1288 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1289 QVERIFY(object->property("result").value<bool>() == true);
1290 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1291 QVERIFY(object->property("result").value<bool>() == false);
1293 // now test other types in QML
1294 QObject *child = object->findChild<QObject*>("typeObj");
1295 QVERIFY(child != 0);
1296 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1297 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1298 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1299 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1300 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1301 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1302 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1303 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1304 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1305 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1306 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1307 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1309 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1310 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1311 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1312 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1313 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1314 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1315 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1316 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1317 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1323 Tests bindings that indirectly cause their own deletion work.
1325 This test is best run under valgrind to ensure no invalid memory access occur.
1327 void tst_qdeclarativeecmascript::selfDeletingBinding()
1330 QDeclarativeComponent component(&engine, testFileUrl("selfDeletingBinding.qml"));
1331 QObject *object = component.create();
1332 QVERIFY(object != 0);
1333 object->setProperty("triggerDelete", true);
1338 QDeclarativeComponent component(&engine, testFileUrl("selfDeletingBinding.2.qml"));
1339 QObject *object = component.create();
1340 QVERIFY(object != 0);
1341 object->setProperty("triggerDelete", true);
1347 Test that extended object properties can be accessed.
1349 This test a regression where this used to crash. The issue was specificially
1350 for extended objects that did not include a synthesized meta object (so non-root
1351 and no synthesiszed properties).
1353 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1355 QDeclarativeComponent component(&engine, testFileUrl("extendedObjectPropertyLookup.qml"));
1356 QObject *object = component.create();
1357 QVERIFY(object != 0);
1362 Test that extended object properties can be accessed correctly.
1364 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup2()
1366 QDeclarativeComponent component(&engine, testFileUrl("extendedObjectPropertyLookup2.qml"));
1367 QObject *object = component.create();
1368 QVERIFY(object != 0);
1370 QVariant returnValue;
1371 QVERIFY(QMetaObject::invokeMethod(object, "getValue", Q_RETURN_ARG(QVariant, returnValue)));
1372 QCOMPARE(returnValue.toInt(), 42);
1377 Test file/lineNumbers for binding/Script errors.
1379 void tst_qdeclarativeecmascript::scriptErrors()
1381 QDeclarativeComponent component(&engine, testFileUrl("scriptErrors.qml"));
1382 QString url = component.url().toString();
1384 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1385 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1386 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1387 QString warning4 = url + ":13: ReferenceError: Can't find variable: a";
1388 QString warning5 = url + ":11: ReferenceError: Can't find variable: a";
1389 QString warning6 = url + ":10: Unable to assign [undefined] to int";
1390 QString warning7 = url + ":15: Error: Cannot assign to read-only property \"trueProperty\"";
1391 QString warning8 = url + ":16: Error: Cannot assign to non-existent property \"fakeProperty\"";
1393 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1394 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1395 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1396 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1397 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1398 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1399 QVERIFY(object != 0);
1401 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1402 emit object->basicSignal();
1404 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1405 emit object->anotherBasicSignal();
1407 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1408 emit object->thirdBasicSignal();
1414 Test file/lineNumbers for inline functions.
1416 void tst_qdeclarativeecmascript::functionErrors()
1418 QDeclarativeComponent component(&engine, testFileUrl("functionErrors.qml"));
1419 QString url = component.url().toString();
1421 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1423 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1425 QObject *object = component.create();
1426 QVERIFY(object != 0);
1429 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1430 QDeclarativeComponent componentTwo(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
1431 url = componentTwo.url().toString();
1432 object = componentTwo.create();
1433 QVERIFY(object != 0);
1435 QString srpname = object->property("srp_name").toString();
1437 warning = url + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srpname
1438 + QLatin1String(" is not a function");
1439 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1440 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1445 Test various errors that can occur when assigning a property from script
1447 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1449 QDeclarativeComponent component(&engine, testFileUrl("propertyAssignmentErrors.qml"));
1451 QString url = component.url().toString();
1453 QObject *object = component.create();
1454 QVERIFY(object != 0);
1456 QCOMPARE(object->property("test1").toBool(), true);
1457 QCOMPARE(object->property("test2").toBool(), true);
1463 Test bindings still work when the reeval is triggered from within
1466 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1468 QDeclarativeComponent component(&engine, testFileUrl("signalTriggeredBindings.qml"));
1469 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1470 QVERIFY(object != 0);
1472 QCOMPARE(object->property("base").toReal(), 50.);
1473 QCOMPARE(object->property("test1").toReal(), 50.);
1474 QCOMPARE(object->property("test2").toReal(), 50.);
1476 object->basicSignal();
1478 QCOMPARE(object->property("base").toReal(), 200.);
1479 QCOMPARE(object->property("test1").toReal(), 200.);
1480 QCOMPARE(object->property("test2").toReal(), 200.);
1482 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1484 QCOMPARE(object->property("base").toReal(), 400.);
1485 QCOMPARE(object->property("test1").toReal(), 400.);
1486 QCOMPARE(object->property("test2").toReal(), 400.);
1492 Test that list properties can be iterated from ECMAScript
1494 void tst_qdeclarativeecmascript::listProperties()
1496 QDeclarativeComponent component(&engine, testFileUrl("listProperties.qml"));
1497 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1498 QVERIFY(object != 0);
1500 QCOMPARE(object->property("test1").toInt(), 21);
1501 QCOMPARE(object->property("test2").toInt(), 2);
1502 QCOMPARE(object->property("test3").toBool(), true);
1503 QCOMPARE(object->property("test4").toBool(), true);
1508 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1510 QDeclarativeComponent component(&engine, testFileUrl("exceptionClearsOnReeval.qml"));
1511 QString url = component.url().toString();
1513 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1515 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1516 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1517 QVERIFY(object != 0);
1519 QCOMPARE(object->property("test").toBool(), false);
1521 MyQmlObject object2;
1522 MyQmlObject object3;
1523 object2.setObjectProperty(&object3);
1524 object->setObjectProperty(&object2);
1526 QCOMPARE(object->property("test").toBool(), true);
1531 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1533 QDeclarativeComponent component(&engine, testFileUrl("exceptionProducesWarning.qml"));
1534 QString url = component.url().toString();
1536 QString warning = component.url().toString() + ":6: Error: JS exception";
1538 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1539 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1540 QVERIFY(object != 0);
1544 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1546 QDeclarativeComponent component(&engine, testFileUrl("exceptionProducesWarning2.qml"));
1547 QString url = component.url().toString();
1549 QString warning = component.url().toString() + ":5: Error: JS exception";
1551 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1552 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1553 QVERIFY(object != 0);
1557 static int transientErrorsMsgCount = 0;
1558 static void transientErrorsMsgHandler(QtMsgType, const char *)
1560 ++transientErrorsMsgCount;
1563 // Check that transient binding errors are not displayed
1564 void tst_qdeclarativeecmascript::transientErrors()
1567 QDeclarativeComponent component(&engine, testFileUrl("transientErrors.qml"));
1569 transientErrorsMsgCount = 0;
1570 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1572 QObject *object = component.create();
1573 QVERIFY(object != 0);
1575 qInstallMsgHandler(old);
1577 QCOMPARE(transientErrorsMsgCount, 0);
1582 // One binding erroring multiple times, but then resolving
1584 QDeclarativeComponent component(&engine, testFileUrl("transientErrors.2.qml"));
1586 transientErrorsMsgCount = 0;
1587 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1589 QObject *object = component.create();
1590 QVERIFY(object != 0);
1592 qInstallMsgHandler(old);
1594 QCOMPARE(transientErrorsMsgCount, 0);
1600 // Check that errors during shutdown are minimized
1601 void tst_qdeclarativeecmascript::shutdownErrors()
1603 QDeclarativeComponent component(&engine, testFileUrl("shutdownErrors.qml"));
1604 QObject *object = component.create();
1605 QVERIFY(object != 0);
1607 transientErrorsMsgCount = 0;
1608 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1612 qInstallMsgHandler(old);
1613 QCOMPARE(transientErrorsMsgCount, 0);
1616 void tst_qdeclarativeecmascript::compositePropertyType()
1618 QDeclarativeComponent component(&engine, testFileUrl("compositePropertyType.qml"));
1620 QTest::ignoreMessage(QtDebugMsg, "hello world");
1621 QObject *object = qobject_cast<QObject *>(component.create());
1626 void tst_qdeclarativeecmascript::jsObject()
1628 QDeclarativeComponent component(&engine, testFileUrl("jsObject.qml"));
1629 QObject *object = component.create();
1630 QVERIFY(object != 0);
1632 QCOMPARE(object->property("test").toInt(), 92);
1637 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1640 QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.qml"));
1641 QObject *object = component.create();
1642 QVERIFY(object != 0);
1644 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1646 object->setProperty("setUndefined", true);
1648 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1650 object->setProperty("setUndefined", false);
1652 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1657 QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.2.qml"));
1658 QObject *object = component.create();
1659 QVERIFY(object != 0);
1661 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1663 QMetaObject::invokeMethod(object, "doReset");
1665 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1671 // Aliases to variant properties should work
1672 void tst_qdeclarativeecmascript::qtbug_22464()
1674 QDeclarativeComponent component(&engine, testFileUrl("qtbug_22464.qml"));
1675 QObject *object = component.create();
1676 QVERIFY(object != 0);
1678 QCOMPARE(object->property("test").toBool(), true);
1683 void tst_qdeclarativeecmascript::qtbug_21580()
1685 QDeclarativeComponent component(&engine, testFileUrl("qtbug_21580.qml"));
1687 QObject *object = component.create();
1688 QVERIFY(object != 0);
1690 QCOMPARE(object->property("test").toBool(), true);
1696 void tst_qdeclarativeecmascript::bug1()
1698 QDeclarativeComponent component(&engine, testFileUrl("bug.1.qml"));
1699 QObject *object = component.create();
1700 QVERIFY(object != 0);
1702 QCOMPARE(object->property("test").toInt(), 14);
1704 object->setProperty("a", 11);
1706 QCOMPARE(object->property("test").toInt(), 3);
1708 object->setProperty("b", true);
1710 QCOMPARE(object->property("test").toInt(), 9);
1715 void tst_qdeclarativeecmascript::bug2()
1717 QDeclarativeComponent component(&engine);
1718 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1720 QObject *object = component.create();
1721 QVERIFY(object != 0);
1726 // Don't crash in createObject when the component has errors.
1727 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1729 QDeclarativeComponent component(&engine, testFileUrl("dynamicCreation.qml"));
1730 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1731 QVERIFY(object != 0);
1733 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1734 QMetaObject::invokeMethod(object, "dontCrash");
1735 QObject *created = object->objectProperty();
1736 QVERIFY(created == 0);
1741 // ownership transferred to JS, ensure that GC runs the dtor
1742 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1745 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1747 // allow the engine to go out of scope too.
1749 QDeclarativeEngine dcoEngine;
1750 QDeclarativeComponent component(&dcoEngine, testFileUrl("dynamicCreationOwnership.qml"));
1751 QObject *object = component.create();
1752 QVERIFY(object != 0);
1753 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1754 QVERIFY(mdcdo != 0);
1755 mdcdo->setDtorCount(&dtorCount);
1757 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1758 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1760 // we do this once manually, but it should be done automatically
1761 // when the engine goes out of scope (since it should gc in dtor)
1762 QMetaObject::invokeMethod(object, "performGc");
1765 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1771 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1772 QCOMPARE(dtorCount, expectedDtorCount);
1776 void tst_qdeclarativeecmascript::regExpBug()
1778 QDeclarativeComponent component(&engine, testFileUrl("regExp.qml"));
1779 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1780 QVERIFY(object != 0);
1781 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1785 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1787 QString functionSource = QLatin1String("(function(object) { return ") +
1788 QLatin1String(source) + QLatin1String(" })");
1790 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1793 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1794 if (function.IsEmpty())
1796 v8::Handle<v8::Value> args[] = { o };
1797 function->Call(engine->global(), 1, args);
1798 return tc.HasCaught();
1801 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1802 const char *source, v8::Handle<v8::Value> result)
1804 QString functionSource = QLatin1String("(function(object) { return ") +
1805 QLatin1String(source) + QLatin1String(" })");
1807 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1810 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1811 if (function.IsEmpty())
1813 v8::Handle<v8::Value> args[] = { o };
1815 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1820 return value->StrictEquals(result);
1823 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1826 QString functionSource = QLatin1String("(function(object) { return ") +
1827 QLatin1String(source) + QLatin1String(" })");
1829 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1831 return v8::Handle<v8::Value>();
1832 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1833 if (function.IsEmpty())
1834 return v8::Handle<v8::Value>();
1835 v8::Handle<v8::Value> args[] = { o };
1837 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1840 return v8::Handle<v8::Value>();
1844 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1845 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1846 #define EVALUATE(source) evaluate(engine, object, source)
1848 void tst_qdeclarativeecmascript::callQtInvokables()
1850 MyInvokableObject o;
1852 QDeclarativeEngine qmlengine;
1853 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1855 QV8Engine *engine = ep->v8engine();
1857 v8::HandleScope handle_scope;
1858 v8::Context::Scope scope(engine->context());
1860 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1862 // Non-existent methods
1864 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1865 QCOMPARE(o.error(), false);
1866 QCOMPARE(o.invoked(), -1);
1867 QCOMPARE(o.actuals().count(), 0);
1870 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1871 QCOMPARE(o.error(), false);
1872 QCOMPARE(o.invoked(), -1);
1873 QCOMPARE(o.actuals().count(), 0);
1875 // Insufficient arguments
1877 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1878 QCOMPARE(o.error(), false);
1879 QCOMPARE(o.invoked(), -1);
1880 QCOMPARE(o.actuals().count(), 0);
1883 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1884 QCOMPARE(o.error(), false);
1885 QCOMPARE(o.invoked(), -1);
1886 QCOMPARE(o.actuals().count(), 0);
1888 // Excessive arguments
1890 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1891 QCOMPARE(o.error(), false);
1892 QCOMPARE(o.invoked(), 8);
1893 QCOMPARE(o.actuals().count(), 1);
1894 QCOMPARE(o.actuals().at(0), QVariant(10));
1897 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1898 QCOMPARE(o.error(), false);
1899 QCOMPARE(o.invoked(), 9);
1900 QCOMPARE(o.actuals().count(), 2);
1901 QCOMPARE(o.actuals().at(0), QVariant(10));
1902 QCOMPARE(o.actuals().at(1), QVariant(11));
1904 // Test return types
1906 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1907 QCOMPARE(o.error(), false);
1908 QCOMPARE(o.invoked(), 0);
1909 QCOMPARE(o.actuals().count(), 0);
1912 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1913 QCOMPARE(o.error(), false);
1914 QCOMPARE(o.invoked(), 1);
1915 QCOMPARE(o.actuals().count(), 0);
1918 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1919 QCOMPARE(o.error(), false);
1920 QCOMPARE(o.invoked(), 2);
1921 QCOMPARE(o.actuals().count(), 0);
1925 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1926 QVERIFY(!ret.IsEmpty());
1927 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1928 QCOMPARE(o.error(), false);
1929 QCOMPARE(o.invoked(), 3);
1930 QCOMPARE(o.actuals().count(), 0);
1935 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1936 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1937 QCOMPARE(o.error(), false);
1938 QCOMPARE(o.invoked(), 4);
1939 QCOMPARE(o.actuals().count(), 0);
1943 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1944 QCOMPARE(o.error(), false);
1945 QCOMPARE(o.invoked(), 5);
1946 QCOMPARE(o.actuals().count(), 0);
1950 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1951 QVERIFY(ret->IsString());
1952 QCOMPARE(engine->toString(ret), QString("Hello world"));
1953 QCOMPARE(o.error(), false);
1954 QCOMPARE(o.invoked(), 6);
1955 QCOMPARE(o.actuals().count(), 0);
1959 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1960 QCOMPARE(o.error(), false);
1961 QCOMPARE(o.invoked(), 7);
1962 QCOMPARE(o.actuals().count(), 0);
1966 QVERIFY(EVALUATE_VALUE("object.method_int(94)", 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(94));
1973 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", 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(94));
1980 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", 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_int(null)", v8::Undefined()));
1988 QCOMPARE(o.error(), false);
1989 QCOMPARE(o.invoked(), 8);
1990 QCOMPARE(o.actuals().count(), 1);
1991 QCOMPARE(o.actuals().at(0), QVariant(0));
1994 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1995 QCOMPARE(o.error(), false);
1996 QCOMPARE(o.invoked(), 8);
1997 QCOMPARE(o.actuals().count(), 1);
1998 QCOMPARE(o.actuals().at(0), QVariant(0));
2001 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
2002 QCOMPARE(o.error(), false);
2003 QCOMPARE(o.invoked(), 8);
2004 QCOMPARE(o.actuals().count(), 1);
2005 QCOMPARE(o.actuals().at(0), QVariant(0));
2008 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
2009 QCOMPARE(o.error(), false);
2010 QCOMPARE(o.invoked(), 9);
2011 QCOMPARE(o.actuals().count(), 2);
2012 QCOMPARE(o.actuals().at(0), QVariant(122));
2013 QCOMPARE(o.actuals().at(1), QVariant(9));
2016 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", 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(94.3));
2023 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
2024 QCOMPARE(o.error(), false);
2025 QCOMPARE(o.invoked(), 10);
2026 QCOMPARE(o.actuals().count(), 1);
2027 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2030 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", 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_real(null)", v8::Undefined()));
2038 QCOMPARE(o.error(), false);
2039 QCOMPARE(o.invoked(), 10);
2040 QCOMPARE(o.actuals().count(), 1);
2041 QCOMPARE(o.actuals().at(0), QVariant(0));
2044 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2045 QCOMPARE(o.error(), false);
2046 QCOMPARE(o.invoked(), 10);
2047 QCOMPARE(o.actuals().count(), 1);
2048 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2051 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2052 QCOMPARE(o.error(), false);
2053 QCOMPARE(o.invoked(), 10);
2054 QCOMPARE(o.actuals().count(), 1);
2055 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2058 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2059 QCOMPARE(o.error(), false);
2060 QCOMPARE(o.invoked(), 11);
2061 QCOMPARE(o.actuals().count(), 1);
2062 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2065 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2066 QCOMPARE(o.error(), false);
2067 QCOMPARE(o.invoked(), 11);
2068 QCOMPARE(o.actuals().count(), 1);
2069 QCOMPARE(o.actuals().at(0), QVariant("19"));
2073 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2074 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2075 QCOMPARE(o.error(), false);
2076 QCOMPARE(o.invoked(), 11);
2077 QCOMPARE(o.actuals().count(), 1);
2078 QCOMPARE(o.actuals().at(0), QVariant(expected));
2082 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2083 QCOMPARE(o.error(), false);
2084 QCOMPARE(o.invoked(), 11);
2085 QCOMPARE(o.actuals().count(), 1);
2086 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2089 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2090 QCOMPARE(o.error(), false);
2091 QCOMPARE(o.invoked(), 11);
2092 QCOMPARE(o.actuals().count(), 1);
2093 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2096 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", 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(null)", 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()));
2110 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", 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()));
2117 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2118 QCOMPARE(o.error(), false);
2119 QCOMPARE(o.invoked(), 12);
2120 QCOMPARE(o.actuals().count(), 1);
2121 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2124 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2125 QCOMPARE(o.error(), false);
2126 QCOMPARE(o.invoked(), 12);
2127 QCOMPARE(o.actuals().count(), 1);
2128 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2131 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2132 QCOMPARE(o.error(), false);
2133 QCOMPARE(o.invoked(), 12);
2134 QCOMPARE(o.actuals().count(), 1);
2135 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2138 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", 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(\"Hello world\")", 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 *)0));
2152 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2153 QCOMPARE(o.error(), false);
2154 QCOMPARE(o.invoked(), 13);
2155 QCOMPARE(o.actuals().count(), 1);
2156 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2159 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2160 QCOMPARE(o.error(), false);
2161 QCOMPARE(o.invoked(), 13);
2162 QCOMPARE(o.actuals().count(), 1);
2163 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2166 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2167 QCOMPARE(o.error(), false);
2168 QCOMPARE(o.invoked(), 13);
2169 QCOMPARE(o.actuals().count(), 1);
2170 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2173 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", 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)).isNull());
2180 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2181 QCOMPARE(o.error(), false);
2182 QCOMPARE(o.invoked(), 14);
2183 QCOMPARE(o.actuals().count(), 1);
2184 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2187 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2188 QCOMPARE(o.error(), false);
2189 QCOMPARE(o.invoked(), 14);
2190 QCOMPARE(o.actuals().count(), 1);
2191 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2194 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2195 QCOMPARE(o.error(), false);
2196 QCOMPARE(o.invoked(), 14);
2197 QCOMPARE(o.actuals().count(), 1);
2198 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2201 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2202 QCOMPARE(o.error(), false);
2203 QCOMPARE(o.invoked(), 15);
2204 QCOMPARE(o.actuals().count(), 2);
2205 QCOMPARE(o.actuals().at(0), QVariant(4));
2206 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2209 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2210 QCOMPARE(o.error(), false);
2211 QCOMPARE(o.invoked(), 15);
2212 QCOMPARE(o.actuals().count(), 2);
2213 QCOMPARE(o.actuals().at(0), QVariant(8));
2214 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2217 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2218 QCOMPARE(o.error(), false);
2219 QCOMPARE(o.invoked(), 15);
2220 QCOMPARE(o.actuals().count(), 2);
2221 QCOMPARE(o.actuals().at(0), QVariant(3));
2222 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2225 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2226 QCOMPARE(o.error(), false);
2227 QCOMPARE(o.invoked(), 15);
2228 QCOMPARE(o.actuals().count(), 2);
2229 QCOMPARE(o.actuals().at(0), QVariant(44));
2230 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2233 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2234 QCOMPARE(o.error(), false);
2235 QCOMPARE(o.invoked(), -1);
2236 QCOMPARE(o.actuals().count(), 0);
2239 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2240 QCOMPARE(o.error(), false);
2241 QCOMPARE(o.invoked(), 16);
2242 QCOMPARE(o.actuals().count(), 1);
2243 QCOMPARE(o.actuals().at(0), QVariant(10));
2246 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2247 QCOMPARE(o.error(), false);
2248 QCOMPARE(o.invoked(), 17);
2249 QCOMPARE(o.actuals().count(), 2);
2250 QCOMPARE(o.actuals().at(0), QVariant(10));
2251 QCOMPARE(o.actuals().at(1), QVariant(11));
2254 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2255 QCOMPARE(o.error(), false);
2256 QCOMPARE(o.invoked(), 18);
2257 QCOMPARE(o.actuals().count(), 1);
2258 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2261 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2262 QCOMPARE(o.error(), false);
2263 QCOMPARE(o.invoked(), 19);
2264 QCOMPARE(o.actuals().count(), 1);
2265 QCOMPARE(o.actuals().at(0), QVariant(9));
2268 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2269 QCOMPARE(o.error(), false);
2270 QCOMPARE(o.invoked(), 20);
2271 QCOMPARE(o.actuals().count(), 2);
2272 QCOMPARE(o.actuals().at(0), QVariant(10));
2273 QCOMPARE(o.actuals().at(1), QVariant(19));
2276 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2277 QCOMPARE(o.error(), false);
2278 QCOMPARE(o.invoked(), 20);
2279 QCOMPARE(o.actuals().count(), 2);
2280 QCOMPARE(o.actuals().at(0), QVariant(10));
2281 QCOMPARE(o.actuals().at(1), QVariant(13));
2284 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2285 QCOMPARE(o.error(), false);
2286 QCOMPARE(o.invoked(), -3);
2287 QCOMPARE(o.actuals().count(), 1);
2288 QCOMPARE(o.actuals().at(0), QVariant(9));
2291 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2292 QCOMPARE(o.error(), false);
2293 QCOMPARE(o.invoked(), 21);
2294 QCOMPARE(o.actuals().count(), 2);
2295 QCOMPARE(o.actuals().at(0), QVariant(9));
2296 QCOMPARE(o.actuals().at(1), QVariant());
2299 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2300 QCOMPARE(o.error(), false);
2301 QCOMPARE(o.invoked(), 21);
2302 QCOMPARE(o.actuals().count(), 2);
2303 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2304 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2307 // QTBUG-13047 (check that you can pass registered object types as args)
2308 void tst_qdeclarativeecmascript::invokableObjectArg()
2310 QDeclarativeComponent component(&engine, testFileUrl("invokableObjectArg.qml"));
2312 QObject *o = component.create();
2314 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2316 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2321 // QTBUG-13047 (check that you can return registered object types from methods)
2322 void tst_qdeclarativeecmascript::invokableObjectRet()
2324 QDeclarativeComponent component(&engine, testFileUrl("invokableObjectRet.qml"));
2326 QObject *o = component.create();
2328 QCOMPARE(o->property("test").toBool(), true);
2333 void tst_qdeclarativeecmascript::listToVariant()
2335 QDeclarativeComponent component(&engine, testFileUrl("listToVariant.qml"));
2337 MyQmlContainer container;
2339 QDeclarativeContext context(engine.rootContext());
2340 context.setContextObject(&container);
2342 QObject *object = component.create(&context);
2343 QVERIFY(object != 0);
2345 QVariant v = object->property("test");
2346 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2347 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2353 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2354 void tst_qdeclarativeecmascript::listAssignment()
2356 QDeclarativeComponent component(&engine, testFileUrl("listAssignment.qml"));
2357 QObject *obj = component.create();
2358 QCOMPARE(obj->property("list1length").toInt(), 2);
2359 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2360 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2361 QCOMPARE(list1.count(&list1), list2.count(&list2));
2362 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2363 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2368 void tst_qdeclarativeecmascript::multiEngineObject()
2371 obj.setStringProperty("Howdy planet");
2373 QDeclarativeEngine e1;
2374 e1.rootContext()->setContextProperty("thing", &obj);
2375 QDeclarativeComponent c1(&e1, testFileUrl("multiEngineObject.qml"));
2377 QDeclarativeEngine e2;
2378 e2.rootContext()->setContextProperty("thing", &obj);
2379 QDeclarativeComponent c2(&e2, testFileUrl("multiEngineObject.qml"));
2381 QObject *o1 = c1.create();
2382 QObject *o2 = c2.create();
2384 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2385 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2391 // Test that references to QObjects are cleanup when the object is destroyed
2392 void tst_qdeclarativeecmascript::deletedObject()
2394 QDeclarativeComponent component(&engine, testFileUrl("deletedObject.qml"));
2396 QObject *object = component.create();
2398 QCOMPARE(object->property("test1").toBool(), true);
2399 QCOMPARE(object->property("test2").toBool(), true);
2400 QCOMPARE(object->property("test3").toBool(), true);
2401 QCOMPARE(object->property("test4").toBool(), true);
2406 void tst_qdeclarativeecmascript::attachedPropertyScope()
2408 QDeclarativeComponent component(&engine, testFileUrl("attachedPropertyScope.qml"));
2410 QObject *object = component.create();
2411 QVERIFY(object != 0);
2413 MyQmlAttachedObject *attached =
2414 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2415 QVERIFY(attached != 0);
2417 QCOMPARE(object->property("value2").toInt(), 0);
2419 attached->emitMySignal();
2421 QCOMPARE(object->property("value2").toInt(), 9);
2426 void tst_qdeclarativeecmascript::scriptConnect()
2429 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.1.qml"));
2431 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2432 QVERIFY(object != 0);
2434 QCOMPARE(object->property("test").toBool(), false);
2435 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2436 QCOMPARE(object->property("test").toBool(), true);
2442 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.2.qml"));
2444 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2445 QVERIFY(object != 0);
2447 QCOMPARE(object->property("test").toBool(), false);
2448 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2449 QCOMPARE(object->property("test").toBool(), true);
2455 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.3.qml"));
2457 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2458 QVERIFY(object != 0);
2460 QCOMPARE(object->property("test").toBool(), false);
2461 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2462 QCOMPARE(object->property("test").toBool(), true);
2468 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.4.qml"));
2470 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2471 QVERIFY(object != 0);
2473 QCOMPARE(object->methodCalled(), false);
2474 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2475 QCOMPARE(object->methodCalled(), true);
2481 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.5.qml"));
2483 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2484 QVERIFY(object != 0);
2486 QCOMPARE(object->methodCalled(), false);
2487 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2488 QCOMPARE(object->methodCalled(), true);
2494 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.6.qml"));
2496 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2497 QVERIFY(object != 0);
2499 QCOMPARE(object->property("test").toInt(), 0);
2500 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2501 QCOMPARE(object->property("test").toInt(), 2);
2507 void tst_qdeclarativeecmascript::scriptDisconnect()
2510 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.1.qml"));
2512 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2513 QVERIFY(object != 0);
2515 QCOMPARE(object->property("test").toInt(), 0);
2516 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2517 QCOMPARE(object->property("test").toInt(), 1);
2518 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2519 QCOMPARE(object->property("test").toInt(), 2);
2520 emit object->basicSignal();
2521 QCOMPARE(object->property("test").toInt(), 2);
2522 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2523 QCOMPARE(object->property("test").toInt(), 2);
2529 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.2.qml"));
2531 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2532 QVERIFY(object != 0);
2534 QCOMPARE(object->property("test").toInt(), 0);
2535 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2536 QCOMPARE(object->property("test").toInt(), 1);
2537 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2538 QCOMPARE(object->property("test").toInt(), 2);
2539 emit object->basicSignal();
2540 QCOMPARE(object->property("test").toInt(), 2);
2541 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2542 QCOMPARE(object->property("test").toInt(), 2);
2548 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.3.qml"));
2550 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2551 QVERIFY(object != 0);
2553 QCOMPARE(object->property("test").toInt(), 0);
2554 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2555 QCOMPARE(object->property("test").toInt(), 1);
2556 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2557 QCOMPARE(object->property("test").toInt(), 2);
2558 emit object->basicSignal();
2559 QCOMPARE(object->property("test").toInt(), 2);
2560 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2561 QCOMPARE(object->property("test").toInt(), 3);
2566 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.4.qml"));
2568 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2569 QVERIFY(object != 0);
2571 QCOMPARE(object->property("test").toInt(), 0);
2572 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2573 QCOMPARE(object->property("test").toInt(), 1);
2574 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2575 QCOMPARE(object->property("test").toInt(), 2);
2576 emit object->basicSignal();
2577 QCOMPARE(object->property("test").toInt(), 2);
2578 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2579 QCOMPARE(object->property("test").toInt(), 3);
2585 class OwnershipObject : public QObject
2589 OwnershipObject() { object = new QObject; }
2591 QPointer<QObject> object;
2594 QObject *getObject() { return object; }
2597 void tst_qdeclarativeecmascript::ownership()
2599 OwnershipObject own;
2600 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2601 context->setContextObject(&own);
2604 QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
2606 QVERIFY(own.object != 0);
2608 QObject *object = component.create(context);
2610 engine.collectGarbage();
2612 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2614 QVERIFY(own.object == 0);
2619 own.object = new QObject(&own);
2622 QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
2624 QVERIFY(own.object != 0);
2626 QObject *object = component.create(context);
2628 engine.collectGarbage();
2630 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2632 QVERIFY(own.object != 0);
2640 class CppOwnershipReturnValue : public QObject
2644 CppOwnershipReturnValue() : value(0) {}
2645 ~CppOwnershipReturnValue() { delete value; }
2647 Q_INVOKABLE QObject *create() {
2648 value = new QObject;
2649 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2653 Q_INVOKABLE MyQmlObject *createQmlObject() {
2654 MyQmlObject *rv = new MyQmlObject;
2659 QPointer<QObject> value;
2663 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2664 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2666 CppOwnershipReturnValue source;
2669 QDeclarativeEngine engine;
2670 engine.rootContext()->setContextProperty("source", &source);
2672 QVERIFY(source.value == 0);
2674 QDeclarativeComponent component(&engine);
2675 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2677 QObject *object = component.create();
2679 QVERIFY(object != 0);
2680 QVERIFY(source.value != 0);
2685 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2687 QVERIFY(source.value != 0);
2691 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2693 CppOwnershipReturnValue source;
2696 QDeclarativeEngine engine;
2697 engine.rootContext()->setContextProperty("source", &source);
2699 QVERIFY(source.value == 0);
2701 QDeclarativeComponent component(&engine);
2702 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2704 QObject *object = component.create();
2706 QVERIFY(object != 0);
2707 QVERIFY(source.value != 0);
2712 engine.collectGarbage();
2713 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2715 QVERIFY(source.value == 0);
2718 class QListQObjectMethodsObject : public QObject
2722 QListQObjectMethodsObject() {
2723 m_objects.append(new MyQmlObject());
2724 m_objects.append(new MyQmlObject());
2727 ~QListQObjectMethodsObject() {
2728 qDeleteAll(m_objects);
2732 QList<QObject *> getObjects() { return m_objects; }
2735 QList<QObject *> m_objects;
2738 // Tests that returning a QList<QObject*> from a method works
2739 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2741 QListQObjectMethodsObject obj;
2742 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2743 context->setContextObject(&obj);
2745 QDeclarativeComponent component(&engine, testFileUrl("qlistqobjectMethods.qml"));
2747 QObject *object = component.create(context);
2749 QCOMPARE(object->property("test").toInt(), 2);
2750 QCOMPARE(object->property("test2").toBool(), true);
2757 void tst_qdeclarativeecmascript::strictlyEquals()
2759 QDeclarativeComponent component(&engine, testFileUrl("strictlyEquals.qml"));
2761 QObject *object = component.create();
2762 QVERIFY(object != 0);
2764 QCOMPARE(object->property("test1").toBool(), true);
2765 QCOMPARE(object->property("test2").toBool(), true);
2766 QCOMPARE(object->property("test3").toBool(), true);
2767 QCOMPARE(object->property("test4").toBool(), true);
2768 QCOMPARE(object->property("test5").toBool(), true);
2769 QCOMPARE(object->property("test6").toBool(), true);
2770 QCOMPARE(object->property("test7").toBool(), true);
2771 QCOMPARE(object->property("test8").toBool(), true);
2776 void tst_qdeclarativeecmascript::compiled()
2778 QDeclarativeComponent component(&engine, testFileUrl("compiled.qml"));
2780 QObject *object = component.create();
2781 QVERIFY(object != 0);
2783 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2784 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2785 QCOMPARE(object->property("test3").toBool(), true);
2786 QCOMPARE(object->property("test4").toBool(), false);
2787 QCOMPARE(object->property("test5").toBool(), false);
2788 QCOMPARE(object->property("test6").toBool(), true);
2790 QCOMPARE(object->property("test7").toInt(), 185);
2791 QCOMPARE(object->property("test8").toInt(), 167);
2792 QCOMPARE(object->property("test9").toBool(), true);
2793 QCOMPARE(object->property("test10").toBool(), false);
2794 QCOMPARE(object->property("test11").toBool(), false);
2795 QCOMPARE(object->property("test12").toBool(), true);
2797 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2798 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2799 QCOMPARE(object->property("test15").toBool(), false);
2800 QCOMPARE(object->property("test16").toBool(), true);
2802 QCOMPARE(object->property("test17").toInt(), 5);
2803 QCOMPARE(object->property("test18").toReal(), qreal(176));
2804 QCOMPARE(object->property("test19").toInt(), 7);
2805 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2806 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2807 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2808 QCOMPARE(object->property("test23").toBool(), true);
2809 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2810 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2815 // Test that numbers assigned in bindings as strings work consistently
2816 void tst_qdeclarativeecmascript::numberAssignment()
2818 QDeclarativeComponent component(&engine, testFileUrl("numberAssignment.qml"));
2820 QObject *object = component.create();
2821 QVERIFY(object != 0);
2823 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2824 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2825 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2826 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2827 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2829 QCOMPARE(object->property("test5"), QVariant((int)7));
2830 QCOMPARE(object->property("test6"), QVariant((int)7));
2831 QCOMPARE(object->property("test7"), QVariant((int)6));
2832 QCOMPARE(object->property("test8"), QVariant((int)6));
2834 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2835 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2836 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2837 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2842 void tst_qdeclarativeecmascript::propertySplicing()
2844 QDeclarativeComponent component(&engine, testFileUrl("propertySplicing.qml"));
2846 QObject *object = component.create();
2847 QVERIFY(object != 0);
2849 QCOMPARE(object->property("test").toBool(), true);
2855 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2857 QDeclarativeComponent component(&engine, testFileUrl("signalWithUnknownTypes.qml"));
2859 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2860 QVERIFY(object != 0);
2862 MyQmlObject::MyType type;
2863 type.value = 0x8971123;
2864 emit object->signalWithUnknownType(type);
2866 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2868 QCOMPARE(result.value, type.value);
2874 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2876 QTest::addColumn<QString>("expression");
2877 QTest::addColumn<QString>("compare");
2879 QString compareStrict("(function(a, b) { return a === b; })");
2880 QTest::newRow("true") << "true" << compareStrict;
2881 QTest::newRow("undefined") << "undefined" << compareStrict;
2882 QTest::newRow("null") << "null" << compareStrict;
2883 QTest::newRow("123") << "123" << compareStrict;
2884 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2886 QString comparePropertiesStrict(
2888 " if (typeof b != 'object')"
2890 " var props = Object.getOwnPropertyNames(b);"
2891 " for (var i = 0; i < props.length; ++i) {"
2892 " var p = props[i];"
2893 " return arguments.callee(a[p], b[p]);"
2896 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2897 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2900 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2902 QFETCH(QString, expression);
2903 QFETCH(QString, compare);
2905 QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
2906 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2907 QVERIFY(object != 0);
2909 QJSValue value = engine.evaluate(expression);
2910 QVERIFY(!engine.hasUncaughtException());
2911 object->setProperty("expression", expression);
2912 object->setProperty("compare", compare);
2913 object->setProperty("pass", false);
2915 emit object->signalWithVariant(QVariant::fromValue(value));
2916 QVERIFY(object->property("pass").toBool());
2919 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2921 signalWithJSValueInVariant_data();
2924 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2926 QFETCH(QString, expression);
2927 QFETCH(QString, compare);
2929 QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
2930 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2931 QVERIFY(object != 0);
2934 QJSValue value = engine2.evaluate(expression);
2935 QVERIFY(!engine2.hasUncaughtException());
2936 object->setProperty("expression", expression);
2937 object->setProperty("compare", compare);
2938 object->setProperty("pass", false);
2940 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2941 emit object->signalWithVariant(QVariant::fromValue(value));
2942 QVERIFY(!object->property("pass").toBool());
2945 void tst_qdeclarativeecmascript::signalWithQJSValue_data()
2947 signalWithJSValueInVariant_data();
2950 void tst_qdeclarativeecmascript::signalWithQJSValue()
2952 QFETCH(QString, expression);
2953 QFETCH(QString, compare);
2955 QDeclarativeComponent component(&engine, testFileUrl("signalWithQJSValue.qml"));
2956 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2957 QVERIFY(object != 0);
2959 QJSValue value = engine.evaluate(expression);
2960 QVERIFY(!engine.hasUncaughtException());
2961 object->setProperty("expression", expression);
2962 object->setProperty("compare", compare);
2963 object->setProperty("pass", false);
2965 emit object->signalWithQJSValue(value);
2967 QVERIFY(object->property("pass").toBool());
2968 QVERIFY(object->qjsvalue().strictlyEquals(value));
2971 void tst_qdeclarativeecmascript::moduleApi_data()
2973 QTest::addColumn<QUrl>("testfile");
2974 QTest::addColumn<QString>("errorMessage");
2975 QTest::addColumn<QStringList>("warningMessages");
2976 QTest::addColumn<QStringList>("readProperties");
2977 QTest::addColumn<QVariantList>("readExpectedValues");
2978 QTest::addColumn<QStringList>("writeProperties");
2979 QTest::addColumn<QVariantList>("writeValues");
2980 QTest::addColumn<QStringList>("readBackProperties");
2981 QTest::addColumn<QVariantList>("readBackExpectedValues");
2983 QTest::newRow("qobject, register + read + method")
2984 << testFileUrl("moduleapi/qobjectModuleApi.qml")
2987 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2988 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2989 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2995 QTest::newRow("script, register + read")
2996 << testFileUrl("moduleapi/scriptModuleApi.qml")
2999 << (QStringList() << "scriptTest")
3000 << (QVariantList() << 13)
3006 QTest::newRow("qobject, caching + read")
3007 << testFileUrl("moduleapi/qobjectModuleApiCaching.qml")
3010 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
3011 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
3017 QTest::newRow("script, caching + read")
3018 << testFileUrl("moduleapi/scriptModuleApiCaching.qml")
3021 << (QStringList() << "scriptTest")
3022 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
3028 QTest::newRow("qobject, writing + readonly constraints")
3029 << testFileUrl("moduleapi/qobjectModuleApiWriting.qml")
3031 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
3032 << (QStringList() << "readOnlyProperty" << "writableProperty")
3033 << (QVariantList() << 20 << 50)
3034 << (QStringList() << "firstProperty" << "writableProperty")
3035 << (QVariantList() << 30 << 30)
3036 << (QStringList() << "readOnlyProperty" << "writableProperty")
3037 << (QVariantList() << 20 << 30);
3039 QTest::newRow("script, writing + readonly constraints")
3040 << testFileUrl("moduleapi/scriptModuleApiWriting.qml")
3042 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
3043 << (QStringList() << "readBack" << "unchanged")
3044 << (QVariantList() << 13 << 42)
3045 << (QStringList() << "firstProperty" << "secondProperty")
3046 << (QVariantList() << 30 << 30)
3047 << (QStringList() << "readBack" << "unchanged")
3048 << (QVariantList() << 30 << 42);
3050 QTest::newRow("qobject module API enum values in JS")
3051 << testFileUrl("moduleapi/qobjectModuleApiEnums.qml")
3054 << (QStringList() << "enumValue" << "enumMethod")
3055 << (QVariantList() << 42 << 30)
3061 QTest::newRow("qobject, invalid major version fail")
3062 << testFileUrl("moduleapi/moduleApiMajorVersionFail.qml")
3063 << QString("QDeclarativeComponent: Component is not ready")
3072 QTest::newRow("qobject, invalid minor version fail")
3073 << testFileUrl("moduleapi/moduleApiMinorVersionFail.qml")
3074 << QString("QDeclarativeComponent: Component is not ready")
3084 void tst_qdeclarativeecmascript::moduleApi()
3086 QFETCH(QUrl, testfile);
3087 QFETCH(QString, errorMessage);
3088 QFETCH(QStringList, warningMessages);
3089 QFETCH(QStringList, readProperties);
3090 QFETCH(QVariantList, readExpectedValues);
3091 QFETCH(QStringList, writeProperties);
3092 QFETCH(QVariantList, writeValues);
3093 QFETCH(QStringList, readBackProperties);
3094 QFETCH(QVariantList, readBackExpectedValues);
3096 QDeclarativeComponent component(&engine, testfile);
3098 if (!errorMessage.isEmpty())
3099 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3101 if (warningMessages.size())
3102 foreach (const QString &warning, warningMessages)
3103 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3105 QObject *object = component.create();
3106 if (!errorMessage.isEmpty()) {
3107 QVERIFY(object == 0);
3109 QVERIFY(object != 0);
3110 for (int i = 0; i < readProperties.size(); ++i)
3111 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3112 for (int i = 0; i < writeProperties.size(); ++i)
3113 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3114 for (int i = 0; i < readBackProperties.size(); ++i)
3115 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3120 void tst_qdeclarativeecmascript::importScripts_data()
3122 QTest::addColumn<QUrl>("testfile");
3123 QTest::addColumn<QString>("errorMessage");
3124 QTest::addColumn<QStringList>("warningMessages");
3125 QTest::addColumn<QStringList>("propertyNames");
3126 QTest::addColumn<QVariantList>("propertyValues");
3128 QTest::newRow("basic functionality")
3129 << testFileUrl("jsimport/testImport.qml")
3132 << (QStringList() << QLatin1String("importedScriptStringValue")
3133 << QLatin1String("importedScriptFunctionValue")
3134 << QLatin1String("importedModuleAttachedPropertyValue")
3135 << QLatin1String("importedModuleEnumValue"))
3136 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3141 QTest::newRow("import scoping")
3142 << testFileUrl("jsimport/testImportScoping.qml")
3145 << (QStringList() << QLatin1String("componentError"))
3146 << (QVariantList() << QVariant(5));
3148 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3149 << testFileUrl("jsimportfail/failOne.qml")
3151 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3152 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3153 << (QVariantList() << QVariant(QString()));
3155 QTest::newRow("javascript imports in an import should be private to the import scope")
3156 << testFileUrl("jsimportfail/failTwo.qml")
3158 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3159 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3160 << (QVariantList() << QVariant(QString()));
3162 QTest::newRow("module imports in an import should be private to the import scope")
3163 << testFileUrl("jsimportfail/failThree.qml")
3165 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3166 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3167 << (QVariantList() << QVariant(false));
3169 QTest::newRow("typenames in an import should be private to the import scope")
3170 << testFileUrl("jsimportfail/failFour.qml")
3172 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3173 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3174 << (QVariantList() << QVariant(0));
3176 QTest::newRow("import with imports has it's own activation scope")
3177 << testFileUrl("jsimportfail/failFive.qml")
3179 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3180 << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3181 << (QStringList() << QLatin1String("componentError"))
3182 << (QVariantList() << QVariant(0));
3184 QTest::newRow("import pragma library script")
3185 << testFileUrl("jsimport/testImportPragmaLibrary.qml")
3188 << (QStringList() << QLatin1String("testValue"))
3189 << (QVariantList() << QVariant(31));
3191 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3192 << testFileUrl("jsimportfail/testImportPragmaLibrary.qml")
3195 << (QStringList() << QLatin1String("testValue"))
3196 << (QVariantList() << QVariant(0));
3198 QTest::newRow("import pragma library script which has an import")
3199 << testFileUrl("jsimport/testImportPragmaLibraryWithImports.qml")
3202 << (QStringList() << QLatin1String("testValue"))
3203 << (QVariantList() << QVariant(55));
3205 QTest::newRow("import pragma library script which has a pragma library import")
3206 << testFileUrl("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3209 << (QStringList() << QLatin1String("testValue"))
3210 << (QVariantList() << QVariant(18));
3213 void tst_qdeclarativeecmascript::importScripts()
3215 QFETCH(QUrl, testfile);
3216 QFETCH(QString, errorMessage);
3217 QFETCH(QStringList, warningMessages);
3218 QFETCH(QStringList, propertyNames);
3219 QFETCH(QVariantList, propertyValues);
3221 QDeclarativeComponent component(&engine, testfile);
3223 if (!errorMessage.isEmpty())
3224 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3226 if (warningMessages.size())
3227 foreach (const QString &warning, warningMessages)
3228 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3230 QObject *object = component.create();
3231 if (!errorMessage.isEmpty()) {
3232 QVERIFY(object == 0);
3234 QVERIFY(object != 0);
3235 for (int i = 0; i < propertyNames.size(); ++i)
3236 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3241 void tst_qdeclarativeecmascript::scarceResources_other()
3243 /* These tests require knowledge of state, since we test values after
3244 performing signal or function invocation. */
3246 QPixmap origPixmap(100, 100);
3247 origPixmap.fill(Qt::blue);
3248 QString srp_name, expectedWarning;
3249 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3250 ScarceResourceObject *eo = 0;
3252 QObject *object = 0;
3254 /* property var semantics */
3256 // test that scarce resources are handled properly in signal invocation
3257 QDeclarativeComponent varComponentTen(&engine, testFileUrl("scarceResourceSignal.var.qml"));
3258 object = varComponentTen.create();
3259 srsc = object->findChild<QObject*>("srsc");
3261 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3262 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3263 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3264 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3265 QMetaObject::invokeMethod(srsc, "testSignal");
3266 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3267 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3268 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3269 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3270 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3271 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3272 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3273 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3274 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3275 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3278 // test that scarce resources are handled properly from js functions in qml files
3279 QDeclarativeComponent varComponentEleven(&engine, testFileUrl("scarceResourceFunction.var.qml"));
3280 object = varComponentEleven.create();
3281 QVERIFY(object != 0);
3282 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3283 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3284 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3285 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3286 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3287 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3288 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3289 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3290 QMetaObject::invokeMethod(object, "releaseScarceResource");
3291 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3292 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3293 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3294 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3297 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3298 QDeclarativeComponent varComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
3299 object = varComponentTwelve.create();
3300 QVERIFY(object != 0);
3301 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3302 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3303 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3304 srp_name = object->property("srp_name").toString();
3305 expectedWarning = varComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3306 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3307 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3308 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3309 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3310 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3311 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3314 // test that if an Item which has JS ownership but has a scarce resource property is garbage collected,
3315 // that the scarce resource is removed from the engine's list of scarce resources to clean up.
3316 QDeclarativeComponent varComponentThirteen(&engine, testFileUrl("scarceResourceObjectGc.var.qml"));
3317 object = varComponentThirteen.create();
3318 QVERIFY(object != 0);
3319 QVERIFY(!object->property("varProperty").isValid()); // not assigned yet
3320 QMetaObject::invokeMethod(object, "assignVarProperty");
3321 QVERIFY(ep->scarceResources.isEmpty()); // the scarce resource is a VME property.
3322 QMetaObject::invokeMethod(object, "deassignVarProperty");
3323 QVERIFY(ep->scarceResources.isEmpty()); // should still be empty; the resource should have been released on gc.
3326 /* property variant semantics */
3328 // test that scarce resources are handled properly in signal invocation
3329 QDeclarativeComponent variantComponentTen(&engine, testFileUrl("scarceResourceSignal.variant.qml"));
3330 object = variantComponentTen.create();
3331 QVERIFY(object != 0);
3332 srsc = object->findChild<QObject*>("srsc");
3334 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3335 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3336 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3337 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3338 QMetaObject::invokeMethod(srsc, "testSignal");
3339 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3340 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3341 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3342 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3343 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3344 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3345 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3346 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3347 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3348 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3351 // test that scarce resources are handled properly from js functions in qml files
3352 QDeclarativeComponent variantComponentEleven(&engine, testFileUrl("scarceResourceFunction.variant.qml"));
3353 object = variantComponentEleven.create();
3354 QVERIFY(object != 0);
3355 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3356 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3357 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3358 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3359 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3360 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3361 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3362 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3363 QMetaObject::invokeMethod(object, "releaseScarceResource");
3364 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3365 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3366 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3367 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3370 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3371 QDeclarativeComponent variantComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.variant.qml"));
3372 object = variantComponentTwelve.create();
3373 QVERIFY(object != 0);
3374 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3375 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3376 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3377 srp_name = object->property("srp_name").toString();
3378 expectedWarning = variantComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3379 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3380 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3381 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3382 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3383 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3384 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3388 void tst_qdeclarativeecmascript::scarceResources_data()
3390 QTest::addColumn<QUrl>("qmlFile");
3391 QTest::addColumn<bool>("readDetachStatus");
3392 QTest::addColumn<bool>("expectedDetachStatus");
3393 QTest::addColumn<QStringList>("propertyNames");
3394 QTest::addColumn<QVariantList>("expectedValidity");
3395 QTest::addColumn<QVariantList>("expectedValues");
3396 QTest::addColumn<QStringList>("expectedErrors");
3398 QPixmap origPixmap(100, 100);
3399 origPixmap.fill(Qt::blue);
3401 /* property var semantics */
3403 // in the following three cases, the instance created from the component
3404 // has a property which is a copy of the scarce resource; hence, the
3405 // resource should NOT be detached prior to deletion of the object instance,
3406 // unless the resource is destroyed explicitly.
3407 QTest::newRow("var: import scarce resource copy directly")
3408 << testFileUrl("scarceResourceCopy.var.qml")
3410 << false // won't be detached, because assigned to property and not explicitly released
3411 << (QStringList() << QLatin1String("scarceResourceCopy"))
3412 << (QList<QVariant>() << true)
3413 << (QList<QVariant>() << origPixmap)
3416 QTest::newRow("var: import scarce resource copy from JS")
3417 << testFileUrl("scarceResourceCopyFromJs.var.qml")
3419 << false // won't be detached, because assigned to property and not explicitly released
3420 << (QStringList() << QLatin1String("scarceResourceCopy"))
3421 << (QList<QVariant>() << true)
3422 << (QList<QVariant>() << origPixmap)
3425 QTest::newRow("var: import released scarce resource copy from JS")
3426 << testFileUrl("scarceResourceDestroyedCopy.var.qml")
3428 << true // explicitly released, so it will be detached
3429 << (QStringList() << QLatin1String("scarceResourceCopy"))
3430 << (QList<QVariant>() << false)
3431 << (QList<QVariant>() << QVariant())
3434 // in the following three cases, no other copy should exist in memory,
3435 // and so it should be detached (unless explicitly preserved).
3436 QTest::newRow("var: import auto-release SR from JS in binding side-effect")
3437 << testFileUrl("scarceResourceTest.var.qml")
3439 << true // auto released, so it will be detached
3440 << (QStringList() << QLatin1String("scarceResourceTest"))
3441 << (QList<QVariant>() << true)
3442 << (QList<QVariant>() << QVariant(100))
3444 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3445 << testFileUrl("scarceResourceTestPreserve.var.qml")
3447 << false // won't be detached because we explicitly preserve it
3448 << (QStringList() << QLatin1String("scarceResourceTest"))
3449 << (QList<QVariant>() << true)
3450 << (QList<QVariant>() << QVariant(100))
3452 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3453 << testFileUrl("scarceResourceTestMultiple.var.qml")
3455 << true // will be detached because all resources were released manually or automatically.
3456 << (QStringList() << QLatin1String("scarceResourceTest"))
3457 << (QList<QVariant>() << true)
3458 << (QList<QVariant>() << QVariant(100))
3461 // In the following three cases, test that scarce resources are handled
3462 // correctly for imports.
3463 QTest::newRow("var: import with no binding")
3464 << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
3465 << false // cannot check detach status.
3468 << QList<QVariant>()
3469 << QList<QVariant>()
3471 QTest::newRow("var: import with binding without explicit preserve")
3472 << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
3475 << (QStringList() << QLatin1String("scarceResourceCopy"))
3476 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3477 << (QList<QVariant>() << QVariant())
3479 QTest::newRow("var: import with explicit release after binding evaluation")
3480 << testFileUrl("scarceResourceCopyImport.var.qml")
3483 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3484 << (QList<QVariant>() << false << false << false << true) // since property var = JS object reference, by releasing the provider's resource, all handles are invalidated.
3485 << (QList<QVariant>() << QVariant() << QVariant() << QVariant() << QVariant(true))
3487 QTest::newRow("var: import with different js objects")
3488 << testFileUrl("scarceResourceCopyImportDifferent.var.qml")
3491 << (QStringList() << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3492 << (QList<QVariant>() << false << true << true) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3493 << (QList<QVariant>() << QVariant() << QVariant(origPixmap) << QVariant(false))
3495 QTest::newRow("var: import with different js objects and explicit release")
3496 << testFileUrl("scarceResourceMultipleDifferentNoBinding.var.qml")
3499 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3500 << (QList<QVariant>() << true << false) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3501 << (QList<QVariant>() << QVariant(origPixmap) << QVariant())
3503 QTest::newRow("var: import with same js objects and explicit release")
3504 << testFileUrl("scarceResourceMultipleSameNoBinding.var.qml")
3507 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3508 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3509 << (QList<QVariant>() << QVariant() << QVariant())
3511 QTest::newRow("var: binding with same js objects and explicit release")
3512 << testFileUrl("scarceResourceMultipleSameWithBinding.var.qml")
3515 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3516 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3517 << (QList<QVariant>() << QVariant() << QVariant())
3521 /* property variant semantics */
3523 // in the following three cases, the instance created from the component
3524 // has a property which is a copy of the scarce resource; hence, the
3525 // resource should NOT be detached prior to deletion of the object instance,
3526 // unless the resource is destroyed explicitly.
3527 QTest::newRow("variant: import scarce resource copy directly")
3528 << testFileUrl("scarceResourceCopy.variant.qml")
3530 << false // won't be detached, because assigned to property and not explicitly released
3531 << (QStringList() << QLatin1String("scarceResourceCopy"))
3532 << (QList<QVariant>() << true)
3533 << (QList<QVariant>() << origPixmap)
3536 QTest::newRow("variant: import scarce resource copy from JS")
3537 << testFileUrl("scarceResourceCopyFromJs.variant.qml")
3539 << false // won't be detached, because assigned to property and not explicitly released
3540 << (QStringList() << QLatin1String("scarceResourceCopy"))
3541 << (QList<QVariant>() << true)
3542 << (QList<QVariant>() << origPixmap)
3545 QTest::newRow("variant: import released scarce resource copy from JS")
3546 << testFileUrl("scarceResourceDestroyedCopy.variant.qml")
3548 << true // explicitly released, so it will be detached
3549 << (QStringList() << QLatin1String("scarceResourceCopy"))
3550 << (QList<QVariant>() << false)
3551 << (QList<QVariant>() << QVariant())
3554 // in the following three cases, no other copy should exist in memory,
3555 // and so it should be detached (unless explicitly preserved).
3556 QTest::newRow("variant: import auto-release SR from JS in binding side-effect")
3557 << testFileUrl("scarceResourceTest.variant.qml")
3559 << true // auto released, so it will be detached
3560 << (QStringList() << QLatin1String("scarceResourceTest"))
3561 << (QList<QVariant>() << true)
3562 << (QList<QVariant>() << QVariant(100))
3564 QTest::newRow("variant: import explicit-preserve SR from JS in binding side-effect")
3565 << testFileUrl("scarceResourceTestPreserve.variant.qml")
3567 << false // won't be detached because we explicitly preserve it
3568 << (QStringList() << QLatin1String("scarceResourceTest"))
3569 << (QList<QVariant>() << true)
3570 << (QList<QVariant>() << QVariant(100))
3572 QTest::newRow("variant: import multiple scarce resources")
3573 << testFileUrl("scarceResourceTestMultiple.variant.qml")
3575 << true // will be detached because all resources were released manually or automatically.
3576 << (QStringList() << QLatin1String("scarceResourceTest"))
3577 << (QList<QVariant>() << true)
3578 << (QList<QVariant>() << QVariant(100))
3581 // In the following three cases, test that scarce resources are handled
3582 // correctly for imports.
3583 QTest::newRow("variant: import with no binding")
3584 << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
3585 << false // cannot check detach status.
3588 << QList<QVariant>()
3589 << QList<QVariant>()
3591 QTest::newRow("variant: import with binding without explicit preserve")
3592 << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
3595 << (QStringList() << QLatin1String("scarceResourceCopy"))
3596 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3597 << (QList<QVariant>() << QVariant())
3599 QTest::newRow("variant: import with explicit release after binding evaluation")
3600 << testFileUrl("scarceResourceCopyImport.variant.qml")
3603 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo"))
3604 << (QList<QVariant>() << true << true << false) // since property variant = variant copy, releasing the provider's resource does not invalidate previously assigned copies.
3605 << (QList<QVariant>() << origPixmap << origPixmap << QVariant())
3609 void tst_qdeclarativeecmascript::scarceResources()
3611 QFETCH(QUrl, qmlFile);
3612 QFETCH(bool, readDetachStatus);
3613 QFETCH(bool, expectedDetachStatus);
3614 QFETCH(QStringList, propertyNames);
3615 QFETCH(QVariantList, expectedValidity);
3616 QFETCH(QVariantList, expectedValues);
3617 QFETCH(QStringList, expectedErrors);
3619 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3620 ScarceResourceObject *eo = 0;
3621 QObject *object = 0;
3623 QDeclarativeComponent c(&engine, qmlFile);
3624 object = c.create();
3625 QVERIFY(object != 0);
3626 for (int i = 0; i < propertyNames.size(); ++i) {
3627 QString prop = propertyNames.at(i);
3628 bool validity = expectedValidity.at(i).toBool();
3629 QVariant value = expectedValues.at(i);
3631 QCOMPARE(object->property(prop.toLatin1().constData()).isValid(), validity);
3632 if (value.type() == QVariant::Int) {
3633 QCOMPARE(object->property(prop.toLatin1().constData()).toInt(), value.toInt());
3634 } else if (value.type() == QVariant::Pixmap) {
3635 QCOMPARE(object->property(prop.toLatin1().constData()).value<QPixmap>(), value.value<QPixmap>());
3639 if (readDetachStatus) {
3640 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3641 QCOMPARE(eo->scarceResourceIsDetached(), expectedDetachStatus);
3644 QVERIFY(ep->scarceResources.isEmpty());
3648 void tst_qdeclarativeecmascript::propertyChangeSlots()
3650 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3651 QDeclarativeComponent component(&engine, testFileUrl("changeslots/propertyChangeSlots.qml"));
3652 QObject *object = component.create();
3653 QVERIFY(object != 0);
3656 // ensure that invalid property names fail properly.
3657 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3658 QDeclarativeComponent e1(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.1.qml"));
3659 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3660 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3661 object = e1.create();
3662 QVERIFY(object == 0);
3665 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3666 QDeclarativeComponent e2(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.2.qml"));
3667 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3668 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3669 object = e2.create();
3670 QVERIFY(object == 0);
3673 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3674 QDeclarativeComponent e3(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.3.qml"));
3675 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3676 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3677 object = e3.create();
3678 QVERIFY(object == 0);
3681 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3682 QDeclarativeComponent e4(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.4.qml"));
3683 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3684 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3685 object = e4.create();
3686 QVERIFY(object == 0);
3690 void tst_qdeclarativeecmascript::propertyVar_data()
3692 QTest::addColumn<QUrl>("qmlFile");
3695 QTest::newRow("non-bindable object subproperty changed") << testFileUrl("propertyVar.1.qml");
3696 QTest::newRow("non-bindable object changed") << testFileUrl("propertyVar.2.qml");
3697 QTest::newRow("primitive changed") << testFileUrl("propertyVar.3.qml");
3698 QTest::newRow("javascript array modification") << testFileUrl("propertyVar.4.qml");
3699 QTest::newRow("javascript map modification") << testFileUrl("propertyVar.5.qml");
3700 QTest::newRow("javascript array assignment") << testFileUrl("propertyVar.6.qml");
3701 QTest::newRow("javascript map assignment") << testFileUrl("propertyVar.7.qml");
3702 QTest::newRow("literal property assignment") << testFileUrl("propertyVar.8.qml");
3703 QTest::newRow("qobject property assignment") << testFileUrl("propertyVar.9.qml");
3704 QTest::newRow("base class var property assignment") << testFileUrl("propertyVar.10.qml");
3707 void tst_qdeclarativeecmascript::propertyVar()
3709 QFETCH(QUrl, qmlFile);
3711 QDeclarativeComponent component(&engine, qmlFile);
3712 QObject *object = component.create();
3713 QVERIFY(object != 0);
3715 QCOMPARE(object->property("test").toBool(), true);
3720 // Tests that we can write QVariant values to var properties from C++
3721 void tst_qdeclarativeecmascript::propertyVarCpp()
3723 QObject *object = 0;
3725 // ensure that writing to and reading from a var property from cpp works as required.
3726 // Literal values stored in var properties can be read and written as QVariants
3727 // of a specific type, whereas object values are read as QVariantMaps.
3728 QDeclarativeComponent component(&engine, testFileUrl("propertyVarCpp.qml"));
3729 object = component.create();
3730 QVERIFY(object != 0);
3731 // assign int to property var that currently has int assigned
3732 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3733 QCOMPARE(object->property("varBound"), QVariant(15));
3734 QCOMPARE(object->property("intBound"), QVariant(15));
3735 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3736 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3737 // assign string to property var that current has bool assigned
3738 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3739 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3740 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3741 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3742 // now enforce behaviour when accessing JavaScript objects from cpp.
3743 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3747 static void gc(QDeclarativeEngine &engine)
3749 engine.collectGarbage();
3750 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3753 void tst_qdeclarativeecmascript::propertyVarOwnership()
3755 // Referenced JS objects are not collected
3757 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.qml"));
3758 QObject *object = component.create();
3759 QVERIFY(object != 0);
3760 QCOMPARE(object->property("test").toBool(), false);
3761 QMetaObject::invokeMethod(object, "runTest");
3762 QCOMPARE(object->property("test").toBool(), true);
3765 // Referenced JS objects are not collected
3767 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.2.qml"));
3768 QObject *object = component.create();
3769 QVERIFY(object != 0);
3770 QCOMPARE(object->property("test").toBool(), false);
3771 QMetaObject::invokeMethod(object, "runTest");
3772 QCOMPARE(object->property("test").toBool(), true);
3775 // Qt objects are not collected until they've been dereferenced
3777 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.3.qml"));
3778 QObject *object = component.create();
3779 QVERIFY(object != 0);
3781 QCOMPARE(object->property("test2").toBool(), false);
3782 QCOMPARE(object->property("test2").toBool(), false);
3784 QMetaObject::invokeMethod(object, "runTest");
3785 QCOMPARE(object->property("test1").toBool(), true);
3787 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3788 QVERIFY(!referencedObject.isNull());
3790 QVERIFY(!referencedObject.isNull());
3792 QMetaObject::invokeMethod(object, "runTest2");
3793 QCOMPARE(object->property("test2").toBool(), true);
3795 QVERIFY(referencedObject.isNull());
3799 // Self reference does not prevent Qt object collection
3801 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.4.qml"));
3802 QObject *object = component.create();
3803 QVERIFY(object != 0);
3805 QCOMPARE(object->property("test").toBool(), true);
3807 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3808 QVERIFY(!referencedObject.isNull());
3810 QVERIFY(!referencedObject.isNull());
3812 QMetaObject::invokeMethod(object, "runTest");
3814 QVERIFY(referencedObject.isNull());
3820 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3822 // The childObject has a reference to a different QObject. We want to ensure
3823 // that the different item will not be cleaned up until required. IE, the childObject
3824 // has implicit ownership of the constructed QObject.
3825 QDeclarativeComponent component(&engine, testFileUrl("propertyVarImplicitOwnership.qml"));
3826 QObject *object = component.create();
3827 QVERIFY(object != 0);
3828 QMetaObject::invokeMethod(object, "assignCircular");
3829 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3830 QObject *rootObject = object->property("vp").value<QObject*>();
3831 QVERIFY(rootObject != 0);
3832 QObject *childObject = rootObject->findChild<QObject*>("text");
3833 QVERIFY(childObject != 0);
3834 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3835 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3836 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3837 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3838 QVERIFY(!qobjectGuard.isNull());
3839 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3840 QVERIFY(!qobjectGuard.isNull());
3841 QMetaObject::invokeMethod(object, "deassignCircular");
3842 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3843 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3847 void tst_qdeclarativeecmascript::propertyVarReparent()
3849 // ensure that nothing breaks if we re-parent objects
3850 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
3851 QObject *object = component.create();
3852 QVERIFY(object != 0);
3853 QMetaObject::invokeMethod(object, "assignVarProp");
3854 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3855 QObject *rect = object->property("vp").value<QObject*>();
3856 QObject *text = rect->findChild<QObject*>("textOne");
3857 QObject *text2 = rect->findChild<QObject*>("textTwo");
3858 QWeakPointer<QObject> rectGuard(rect);
3859 QWeakPointer<QObject> textGuard(text);
3860 QWeakPointer<QObject> text2Guard(text2);
3861 QVERIFY(!rectGuard.isNull());
3862 QVERIFY(!textGuard.isNull());
3863 QVERIFY(!text2Guard.isNull());
3864 QCOMPARE(text->property("textCanary").toInt(), 11);
3865 QCOMPARE(text2->property("textCanary").toInt(), 12);
3866 // now construct an image which we will reparent.
3867 QMetaObject::invokeMethod(text2, "constructQObject");
3868 QObject *image = text2->property("vp").value<QObject*>();
3869 QWeakPointer<QObject> imageGuard(image);
3870 QVERIFY(!imageGuard.isNull());
3871 QCOMPARE(image->property("imageCanary").toInt(), 13);
3872 // now reparent the "Image" object (currently, it has JS ownership)
3873 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3874 QMetaObject::invokeMethod(text2, "deassignVp");
3875 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3876 QCOMPARE(text->property("textCanary").toInt(), 11);
3877 QCOMPARE(text2->property("textCanary").toInt(), 22);
3878 QVERIFY(!imageGuard.isNull()); // should still be alive.
3879 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3880 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3881 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3882 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3886 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3888 // sometimes reparenting can cause problems
3889 // (eg, if the ctxt is collected, varproperties are no longer available)
3890 // this test ensures that no crash occurs in that situation.
3891 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
3892 QObject *object = component.create();
3893 QVERIFY(object != 0);
3894 QMetaObject::invokeMethod(object, "assignVarProp");
3895 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3896 QObject *rect = object->property("vp").value<QObject*>();
3897 QObject *text = rect->findChild<QObject*>("textOne");
3898 QObject *text2 = rect->findChild<QObject*>("textTwo");
3899 QWeakPointer<QObject> rectGuard(rect);
3900 QWeakPointer<QObject> textGuard(text);
3901 QWeakPointer<QObject> text2Guard(text2);
3902 QVERIFY(!rectGuard.isNull());
3903 QVERIFY(!textGuard.isNull());
3904 QVERIFY(!text2Guard.isNull());
3905 QCOMPARE(text->property("textCanary").toInt(), 11);
3906 QCOMPARE(text2->property("textCanary").toInt(), 12);
3907 // now construct an image which we will reparent.
3908 QMetaObject::invokeMethod(text2, "constructQObject");
3909 QObject *image = text2->property("vp").value<QObject*>();
3910 QWeakPointer<QObject> imageGuard(image);
3911 QVERIFY(!imageGuard.isNull());
3912 QCOMPARE(image->property("imageCanary").toInt(), 13);
3913 // now reparent the "Image" object (currently, it has JS ownership)
3914 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3915 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3916 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3917 QVERIFY(!imageGuard.isNull()); // should still be alive.
3918 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3920 QVERIFY(imageGuard.isNull()); // should now be dead.
3923 void tst_qdeclarativeecmascript::propertyVarCircular()
3925 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3926 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.qml"));
3927 QObject *object = component.create();
3928 QVERIFY(object != 0);
3929 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3930 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3931 QCOMPARE(object->property("canaryInt"), QVariant(5));
3932 QVariant canaryResourceVariant = object->property("canaryResource");
3933 QVERIFY(canaryResourceVariant.isValid());
3934 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3935 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3936 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3937 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3938 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3939 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3940 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3941 QCOMPARE(object->property("canaryInt"), QVariant(2));
3942 QCOMPARE(object->property("canaryResource"), QVariant(1));
3943 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3947 void tst_qdeclarativeecmascript::propertyVarCircular2()
3949 // track deletion of JS-owned parent item with Cpp-owned child
3950 // where the child has a var property referencing its parent.
3951 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
3952 QObject *object = component.create();
3953 QVERIFY(object != 0);
3954 QMetaObject::invokeMethod(object, "assignCircular");
3955 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3956 QObject *rootObject = object->property("vp").value<QObject*>();
3957 QVERIFY(rootObject != 0);
3958 QObject *childObject = rootObject->findChild<QObject*>("text");
3959 QVERIFY(childObject != 0);
3960 QWeakPointer<QObject> rootObjectTracker(rootObject);
3961 QVERIFY(!rootObjectTracker.isNull());
3962 QWeakPointer<QObject> childObjectTracker(childObject);
3963 QVERIFY(!childObjectTracker.isNull());
3965 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3966 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3967 QMetaObject::invokeMethod(object, "deassignCircular");
3968 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3969 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3970 QVERIFY(childObjectTracker.isNull()); // should have been collected
3974 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3976 *(int*)(parameter) += 1;
3977 qPersistentDispose(object);
3980 void tst_qdeclarativeecmascript::propertyVarInheritance()
3982 int propertyVarWeakRefCallbackCount = 0;
3984 // enforce behaviour regarding element inheritance - ensure handle disposal.
3985 // The particular component under test here has a chain of references.
3986 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.inherit.qml"));
3987 QObject *object = component.create();
3988 QVERIFY(object != 0);
3989 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3990 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3991 // we want to be able to track when the varProperties array of the last metaobject is disposed
3992 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3993 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*>();
3994 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3995 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
3996 v8::Persistent<v8::Value> icoCanaryHandle;
3997 v8::Persistent<v8::Value> ccoCanaryHandle;
4000 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
4001 // public function which can return us a handle to something in the varProperties array.
4002 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(ico5->metaObject()->indexOfProperty("circ")));
4003 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(cco5->metaObject()->indexOfProperty("circ")));
4004 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
4005 // as the varproperties array of each vmemo still references the resource.
4006 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4007 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4009 QVERIFY(propertyVarWeakRefCallbackCount == 0);
4011 // now we deassign the var prop, which should trigger collection of item subtrees.
4012 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
4013 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
4014 // ensure that there are only weak handles to the underlying varProperties array remaining.
4016 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
4018 // since there are no parent vmemo's to keep implicit references alive, and the only handles
4019 // to what remains are weak, all varProperties arrays must have been collected.
4022 void tst_qdeclarativeecmascript::propertyVarInheritance2()
4024 int propertyVarWeakRefCallbackCount = 0;
4026 // The particular component under test here does NOT have a chain of references; the
4027 // only link between rootObject and childObject is that rootObject is the parent of childObject.
4028 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
4029 QObject *object = component.create();
4030 QVERIFY(object != 0);
4031 QMetaObject::invokeMethod(object, "assignCircular");
4032 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
4033 QObject *rootObject = object->property("vp").value<QObject*>();
4034 QVERIFY(rootObject != 0);
4035 QObject *childObject = rootObject->findChild<QObject*>("text");
4036 QVERIFY(childObject != 0);
4037 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
4038 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4039 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
4042 propertyVarWeakRefCallbackCount = 0; // reset callback count.
4043 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(childObject->metaObject()->indexOfProperty("vp")));
4044 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4046 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
4047 QCOMPARE(childObject->property("vp").value<QObject*>(), rootObject);
4048 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4050 QMetaObject::invokeMethod(object, "deassignCircular");
4051 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
4052 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
4056 // Ensure that QObject type conversion works on binding assignment
4057 void tst_qdeclarativeecmascript::elementAssign()
4059 QDeclarativeComponent component(&engine, testFileUrl("elementAssign.qml"));
4061 QObject *object = component.create();
4062 QVERIFY(object != 0);
4064 QCOMPARE(object->property("test").toBool(), true);
4070 void tst_qdeclarativeecmascript::objectPassThroughSignals()
4072 QDeclarativeComponent component(&engine, testFileUrl("objectsPassThroughSignals.qml"));
4074 QObject *object = component.create();
4075 QVERIFY(object != 0);
4077 QCOMPARE(object->property("test").toBool(), true);
4083 void tst_qdeclarativeecmascript::objectConversion()
4085 QDeclarativeComponent component(&engine, testFileUrl("objectConversion.qml"));
4087 QObject *object = component.create();
4088 QVERIFY(object != 0);
4090 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
4091 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
4098 void tst_qdeclarativeecmascript::booleanConversion()
4100 QDeclarativeComponent component(&engine, testFileUrl("booleanConversion.qml"));
4102 QObject *object = component.create();
4103 QVERIFY(object != 0);
4105 QCOMPARE(object->property("test_true1").toBool(), true);
4106 QCOMPARE(object->property("test_true2").toBool(), true);
4107 QCOMPARE(object->property("test_true3").toBool(), true);
4108 QCOMPARE(object->property("test_true4").toBool(), true);
4109 QCOMPARE(object->property("test_true5").toBool(), true);
4111 QCOMPARE(object->property("test_false1").toBool(), false);
4112 QCOMPARE(object->property("test_false2").toBool(), false);
4113 QCOMPARE(object->property("test_false3").toBool(), false);
4118 void tst_qdeclarativeecmascript::handleReferenceManagement()
4123 // Linear QObject reference
4124 QDeclarativeEngine hrmEngine;
4125 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.1.qml"));
4126 QObject *object = component.create();
4127 QVERIFY(object != 0);
4128 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4129 cro->setEngine(&hrmEngine);
4130 cro->setDtorCount(&dtorCount);
4131 QMetaObject::invokeMethod(object, "createReference");
4133 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
4135 hrmEngine.collectGarbage();
4136 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4137 QCOMPARE(dtorCount, 3);
4142 // Circular QObject reference
4143 QDeclarativeEngine hrmEngine;
4144 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.2.qml"));
4145 QObject *object = component.create();
4146 QVERIFY(object != 0);
4147 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4148 cro->setEngine(&hrmEngine);
4149 cro->setDtorCount(&dtorCount);
4150 QMetaObject::invokeMethod(object, "circularReference");
4152 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
4154 hrmEngine.collectGarbage();
4155 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4156 QCOMPARE(dtorCount, 3);
4161 // Linear handle reference
4162 QDeclarativeEngine hrmEngine;
4163 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.1.qml"));
4164 QObject *object = component.create();
4165 QVERIFY(object != 0);
4166 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4168 crh->setEngine(&hrmEngine);
4169 crh->setDtorCount(&dtorCount);
4170 QMetaObject::invokeMethod(object, "createReference");
4171 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4172 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4173 QVERIFY(first != 0);
4174 QVERIFY(second != 0);
4175 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
4176 // now we have to reparent second and make second owned by JS.
4177 second->setParent(0);
4178 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4180 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
4182 hrmEngine.collectGarbage();
4183 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4184 QCOMPARE(dtorCount, 3);
4189 // Circular handle reference
4190 QDeclarativeEngine hrmEngine;
4191 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.2.qml"));
4192 QObject *object = component.create();
4193 QVERIFY(object != 0);
4194 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4196 crh->setEngine(&hrmEngine);
4197 crh->setDtorCount(&dtorCount);
4198 QMetaObject::invokeMethod(object, "circularReference");
4199 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4200 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4201 QVERIFY(first != 0);
4202 QVERIFY(second != 0);
4203 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
4204 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
4205 // now we have to reparent and change ownership.
4206 first->setParent(0);
4207 second->setParent(0);
4208 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
4209 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4211 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
4213 hrmEngine.collectGarbage();
4214 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4215 QCOMPARE(dtorCount, 3);
4220 // multiple engine interaction - linear reference
4221 QDeclarativeEngine hrmEngine1;
4222 QDeclarativeEngine hrmEngine2;
4223 QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4224 QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4225 QObject *object1 = component1.create();
4226 QObject *object2 = component2.create();
4227 QVERIFY(object1 != 0);
4228 QVERIFY(object2 != 0);
4229 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4230 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4233 crh1->setEngine(&hrmEngine1);
4234 crh2->setEngine(&hrmEngine2);
4235 crh1->setDtorCount(&dtorCount);
4236 crh2->setDtorCount(&dtorCount);
4237 QMetaObject::invokeMethod(object1, "createReference");
4238 QMetaObject::invokeMethod(object2, "createReference");
4239 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4240 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4241 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4242 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4243 QVERIFY(first1 != 0);
4244 QVERIFY(second1 != 0);
4245 QVERIFY(first2 != 0);
4246 QVERIFY(second2 != 0);
4247 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
4248 // now we have to reparent second2 and make second2 owned by JS.
4249 second2->setParent(0);
4250 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4252 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4253 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
4256 hrmEngine1.collectGarbage();
4257 hrmEngine2.collectGarbage();
4258 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4259 QCOMPARE(dtorCount, 6);
4264 // multiple engine interaction - circular reference
4265 QDeclarativeEngine hrmEngine1;
4266 QDeclarativeEngine hrmEngine2;
4267 QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4268 QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4269 QObject *object1 = component1.create();
4270 QObject *object2 = component2.create();
4271 QVERIFY(object1 != 0);
4272 QVERIFY(object2 != 0);
4273 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4274 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4277 crh1->setEngine(&hrmEngine1);
4278 crh2->setEngine(&hrmEngine2);
4279 crh1->setDtorCount(&dtorCount);
4280 crh2->setDtorCount(&dtorCount);
4281 QMetaObject::invokeMethod(object1, "createReference");
4282 QMetaObject::invokeMethod(object2, "createReference");
4283 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4284 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4285 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4286 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4287 QVERIFY(first1 != 0);
4288 QVERIFY(second1 != 0);
4289 QVERIFY(first2 != 0);
4290 QVERIFY(second2 != 0);
4291 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4292 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4293 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4294 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
4295 // now we have to reparent and change ownership to JS.
4296 first1->setParent(0);
4297 second1->setParent(0);
4298 first2->setParent(0);
4299 second2->setParent(0);
4300 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
4301 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4302 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4303 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4305 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4306 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
4309 hrmEngine1.collectGarbage();
4310 hrmEngine2.collectGarbage();
4311 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4312 QCOMPARE(dtorCount, 6);
4317 // multiple engine interaction - linear reference with engine deletion
4318 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
4319 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4320 QDeclarativeComponent component1(hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4321 QDeclarativeComponent component2(hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4322 QObject *object1 = component1.create();
4323 QObject *object2 = component2.create();
4324 QVERIFY(object1 != 0);
4325 QVERIFY(object2 != 0);
4326 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4327 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4330 crh1->setEngine(hrmEngine1);
4331 crh2->setEngine(hrmEngine2);
4332 crh1->setDtorCount(&dtorCount);
4333 crh2->setDtorCount(&dtorCount);
4334 QMetaObject::invokeMethod(object1, "createReference");
4335 QMetaObject::invokeMethod(object2, "createReference");
4336 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4337 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4338 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4339 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4340 QVERIFY(first1 != 0);
4341 QVERIFY(second1 != 0);
4342 QVERIFY(first2 != 0);
4343 QVERIFY(second2 != 0);
4344 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4345 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4346 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4347 // now we have to reparent and change ownership to JS.
4348 first1->setParent(crh1);
4349 second1->setParent(0);
4350 first2->setParent(0);
4351 second2->setParent(0);
4352 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4353 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4354 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4356 QCOMPARE(dtorCount, 0);
4359 QCOMPARE(dtorCount, 0);
4362 hrmEngine1->collectGarbage();
4363 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4364 QCOMPARE(dtorCount, 6);
4369 void tst_qdeclarativeecmascript::stringArg()
4371 QDeclarativeComponent component(&engine, testFileUrl("stringArg.qml"));
4372 QObject *object = component.create();
4373 QVERIFY(object != 0);
4374 QMetaObject::invokeMethod(object, "success");
4375 QVERIFY(object->property("returnValue").toBool());
4377 QString w1 = testFileUrl("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4378 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4379 QMetaObject::invokeMethod(object, "failure");
4380 QVERIFY(object->property("returnValue").toBool());
4385 void tst_qdeclarativeecmascript::readonlyDeclaration()
4387 QDeclarativeComponent component(&engine, testFileUrl("readonlyDeclaration.qml"));
4389 QObject *object = component.create();
4390 QVERIFY(object != 0);
4392 QCOMPARE(object->property("test").toBool(), true);
4397 Q_DECLARE_METATYPE(QList<int>)
4398 Q_DECLARE_METATYPE(QList<qreal>)
4399 Q_DECLARE_METATYPE(QList<bool>)
4400 Q_DECLARE_METATYPE(QList<QString>)
4401 Q_DECLARE_METATYPE(QList<QUrl>)
4402 void tst_qdeclarativeecmascript::sequenceConversionRead()
4405 QUrl qmlFile = testFileUrl("sequenceConversion.read.qml");
4406 QDeclarativeComponent component(&engine, qmlFile);
4407 QObject *object = component.create();
4408 QVERIFY(object != 0);
4409 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4412 QMetaObject::invokeMethod(object, "readSequences");
4413 QList<int> intList; intList << 1 << 2 << 3 << 4;
4414 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4415 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4416 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4417 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4418 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4419 QList<bool> boolList; boolList << true << false << true << false;
4420 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4421 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4422 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4423 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4424 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4425 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4426 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4427 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4428 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4429 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4430 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4432 QMetaObject::invokeMethod(object, "readSequenceElements");
4433 QCOMPARE(object->property("intVal").toInt(), 2);
4434 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4435 QCOMPARE(object->property("boolVal").toBool(), false);
4436 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4437 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4438 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4440 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4441 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4443 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4444 QDeclarativeProperty seqProp(seq, "intListProperty");
4445 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4446 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4447 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4449 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4450 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4456 QUrl qmlFile = testFileUrl("sequenceConversion.read.error.qml");
4457 QDeclarativeComponent component(&engine, qmlFile);
4458 QObject *object = component.create();
4459 QVERIFY(object != 0);
4460 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4463 // we haven't registered QList<QPoint> as a sequence type.
4464 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4465 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4466 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4467 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4469 QMetaObject::invokeMethod(object, "performTest");
4471 // QList<QPoint> has not been registered as a sequence type.
4472 QCOMPARE(object->property("pointListLength").toInt(), 0);
4473 QVERIFY(!object->property("pointList").isValid());
4474 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4475 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4476 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4482 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4485 QUrl qmlFile = testFileUrl("sequenceConversion.write.qml");
4486 QDeclarativeComponent component(&engine, qmlFile);
4487 QObject *object = component.create();
4488 QVERIFY(object != 0);
4489 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4492 QMetaObject::invokeMethod(object, "writeSequences");
4493 QCOMPARE(object->property("success").toBool(), true);
4495 QMetaObject::invokeMethod(object, "writeSequenceElements");
4496 QCOMPARE(object->property("success").toBool(), true);
4498 QMetaObject::invokeMethod(object, "writeOtherElements");
4499 QCOMPARE(object->property("success").toBool(), true);
4501 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4502 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4508 QUrl qmlFile = testFileUrl("sequenceConversion.write.error.qml");
4509 QDeclarativeComponent component(&engine, qmlFile);
4510 QObject *object = component.create();
4511 QVERIFY(object != 0);
4512 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4515 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4516 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4517 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4519 QMetaObject::invokeMethod(object, "performTest");
4521 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4522 QCOMPARE(seq->pointListProperty(), pointList);
4528 void tst_qdeclarativeecmascript::sequenceConversionArray()
4530 // ensure that in JS the returned sequences act just like normal JS Arrays.
4531 QUrl qmlFile = testFileUrl("sequenceConversion.array.qml");
4532 QDeclarativeComponent component(&engine, qmlFile);
4533 QObject *object = component.create();
4534 QVERIFY(object != 0);
4535 QMetaObject::invokeMethod(object, "indexedAccess");
4536 QVERIFY(object->property("success").toBool());
4537 QMetaObject::invokeMethod(object, "arrayOperations");
4538 QVERIFY(object->property("success").toBool());
4539 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4540 QVERIFY(object->property("success").toBool());
4541 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4542 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4546 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4548 // ensure that sequence conversion operations work correctly in a worker thread
4549 // and that serialisation between the main and worker thread succeeds.
4550 QUrl qmlFile = testFileUrl("sequenceConversion.threads.qml");
4551 QDeclarativeComponent component(&engine, qmlFile);
4552 QObject *object = component.create();
4553 QVERIFY(object != 0);
4555 QMetaObject::invokeMethod(object, "testIntSequence");
4556 QTRY_VERIFY(object->property("finished").toBool());
4557 QVERIFY(object->property("success").toBool());
4559 QMetaObject::invokeMethod(object, "testQrealSequence");
4560 QTRY_VERIFY(object->property("finished").toBool());
4561 QVERIFY(object->property("success").toBool());
4563 QMetaObject::invokeMethod(object, "testBoolSequence");
4564 QTRY_VERIFY(object->property("finished").toBool());
4565 QVERIFY(object->property("success").toBool());
4567 QMetaObject::invokeMethod(object, "testStringSequence");
4568 QTRY_VERIFY(object->property("finished").toBool());
4569 QVERIFY(object->property("success").toBool());
4571 QMetaObject::invokeMethod(object, "testQStringSequence");
4572 QTRY_VERIFY(object->property("finished").toBool());
4573 QVERIFY(object->property("success").toBool());
4575 QMetaObject::invokeMethod(object, "testUrlSequence");
4576 QTRY_VERIFY(object->property("finished").toBool());
4577 QVERIFY(object->property("success").toBool());
4579 QMetaObject::invokeMethod(object, "testVariantSequence");
4580 QTRY_VERIFY(object->property("finished").toBool());
4581 QVERIFY(object->property("success").toBool());
4586 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4589 QUrl qmlFile = testFileUrl("sequenceConversion.bindings.qml");
4590 QDeclarativeComponent component(&engine, qmlFile);
4591 QObject *object = component.create();
4592 QVERIFY(object != 0);
4593 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4594 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4595 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4596 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4597 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4602 QUrl qmlFile = testFileUrl("sequenceConversion.bindings.error.qml");
4603 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4604 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4605 QDeclarativeComponent component(&engine, qmlFile);
4606 QObject *object = component.create();
4607 QVERIFY(object != 0);
4612 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4614 QUrl qmlFile = testFileUrl("sequenceConversion.copy.qml");
4615 QDeclarativeComponent component(&engine, qmlFile);
4616 QObject *object = component.create();
4617 QVERIFY(object != 0);
4618 QMetaObject::invokeMethod(object, "testCopySequences");
4619 QCOMPARE(object->property("success").toBool(), true);
4620 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4621 QCOMPARE(object->property("success").toBool(), true);
4622 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4623 QCOMPARE(object->property("success").toBool(), true);
4627 void tst_qdeclarativeecmascript::assignSequenceTypes()
4629 // test binding array to sequence type property
4631 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.1.qml"));
4632 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4633 QVERIFY(object != 0);
4634 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4635 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4636 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4637 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4638 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4639 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4643 // test binding literal to sequence type property
4645 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.2.qml"));
4646 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4647 QVERIFY(object != 0);
4648 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4649 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4650 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4651 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4652 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4653 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4657 // test binding single value to sequence type property
4659 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.3.qml"));
4660 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4661 QVERIFY(object != 0);
4662 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4663 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4664 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4665 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4669 // test assigning array to sequence type property in js function
4671 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.4.qml"));
4672 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4673 QVERIFY(object != 0);
4674 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4675 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4676 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4677 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4678 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4679 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4683 // test assigning literal to sequence type property in js function
4685 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.5.qml"));
4686 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4687 QVERIFY(object != 0);
4688 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4689 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4690 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4691 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4692 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4693 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4697 // test assigning single value to sequence type property in js function
4699 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.6.qml"));
4700 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4701 QVERIFY(object != 0);
4702 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4703 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4704 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4705 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4709 // test QList<QUrl> literal assignment and binding assignment causes url resolution when required
4711 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.7.qml"));
4712 QObject *object = component.create();
4713 QVERIFY(object != 0);
4714 MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
4715 MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
4716 MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
4717 MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
4718 MySequenceConversionObject *msco5 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco5"));
4719 QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0 && msco5 != 0);
4720 QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4721 QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4722 QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4723 QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4724 QCOMPARE(msco5->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4729 // Test that assigning a null object works
4730 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4731 void tst_qdeclarativeecmascript::nullObjectBinding()
4733 QDeclarativeComponent component(&engine, testFileUrl("nullObjectBinding.qml"));
4735 QObject *object = component.create();
4736 QVERIFY(object != 0);
4738 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4743 // Test that bindings don't evaluate once the engine has been destroyed
4744 void tst_qdeclarativeecmascript::deletedEngine()
4746 QDeclarativeEngine *engine = new QDeclarativeEngine;
4747 QDeclarativeComponent component(engine, testFileUrl("deletedEngine.qml"));
4749 QObject *object = component.create();
4750 QVERIFY(object != 0);
4752 QCOMPARE(object->property("a").toInt(), 39);
4753 object->setProperty("b", QVariant(9));
4754 QCOMPARE(object->property("a").toInt(), 117);
4758 QCOMPARE(object->property("a").toInt(), 117);
4759 object->setProperty("b", QVariant(10));
4760 QCOMPARE(object->property("a").toInt(), 117);
4765 // Test the crashing part of QTBUG-9705
4766 void tst_qdeclarativeecmascript::libraryScriptAssert()
4768 QDeclarativeComponent component(&engine, testFileUrl("libraryScriptAssert.qml"));
4770 QObject *object = component.create();
4771 QVERIFY(object != 0);
4776 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4778 QDeclarativeComponent component(&engine, testFileUrl("variantsAssignedUndefined.qml"));
4780 QObject *object = component.create();
4781 QVERIFY(object != 0);
4783 QCOMPARE(object->property("test1").toInt(), 10);
4784 QCOMPARE(object->property("test2").toInt(), 11);
4786 object->setProperty("runTest", true);
4788 QCOMPARE(object->property("test1"), QVariant());
4789 QCOMPARE(object->property("test2"), QVariant());
4795 void tst_qdeclarativeecmascript::qtbug_9792()
4797 QDeclarativeComponent component(&engine, testFileUrl("qtbug_9792.qml"));
4799 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4801 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4802 QVERIFY(object != 0);
4804 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4805 object->basicSignal();
4809 transientErrorsMsgCount = 0;
4810 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4812 object->basicSignal();
4814 qInstallMsgHandler(old);
4816 QCOMPARE(transientErrorsMsgCount, 0);
4821 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4822 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4824 QDeclarativeComponent component(&engine, testFileUrl("qtcreatorbug_1289.qml"));
4826 QObject *o = component.create();
4829 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4830 QVERIFY(nested != 0);
4832 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4835 nested = qvariant_cast<QObject *>(o->property("object"));
4836 QVERIFY(nested == 0);
4838 // If the bug is present, the next line will crash
4842 // Test that we shut down without stupid warnings
4843 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4846 QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.qml"));
4848 QObject *o = component.create();
4850 transientErrorsMsgCount = 0;
4851 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4855 qInstallMsgHandler(old);
4857 QCOMPARE(transientErrorsMsgCount, 0);
4862 QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.2.qml"));
4864 QObject *o = component.create();
4866 transientErrorsMsgCount = 0;
4867 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4871 qInstallMsgHandler(old);
4873 QCOMPARE(transientErrorsMsgCount, 0);
4877 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4880 QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.1.qml"));
4882 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4885 QVERIFY(o->objectProperty() != 0);
4887 o->setProperty("runTest", true);
4889 QVERIFY(o->objectProperty() == 0);
4895 QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.2.qml"));
4897 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4900 QVERIFY(o->objectProperty() == 0);
4906 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4908 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.1.qml"));
4910 QString url = component.url().toString();
4911 QString warning = url + ":4: Unable to assign a function to a property.";
4912 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4914 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4917 QVERIFY(!o->property("a").isValid());
4922 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4924 QFETCH(QString, triggerProperty);
4926 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
4927 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4929 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4931 QVERIFY(!o->property("a").isValid());
4933 o->setProperty("aNumber", QVariant(5));
4934 o->setProperty(triggerProperty.toUtf8().constData(), true);
4935 QCOMPARE(o->property("a"), QVariant(50));
4937 o->setProperty("aNumber", QVariant(10));
4938 QCOMPARE(o->property("a"), QVariant(100));
4943 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4945 QTest::addColumn<QString>("triggerProperty");
4947 QTest::newRow("assign to property") << "assignToProperty";
4948 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4950 QTest::newRow("assign to value type") << "assignToValueType";
4952 QTest::newRow("use 'this'") << "assignWithThis";
4953 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4956 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4958 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
4959 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4961 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4963 QVERIFY(!o->property("a").isValid());
4965 o->setProperty("assignFuncWithoutReturn", true);
4966 QVERIFY(!o->property("a").isValid());
4968 QString url = component.url().toString();
4969 QString warning = url + ":67: Unable to assign QString to int";
4970 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4971 o->setProperty("assignWrongType", true);
4973 warning = url + ":71: Unable to assign QString to int";
4974 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4975 o->setProperty("assignWrongTypeToValueType", true);
4980 void tst_qdeclarativeecmascript::eval()
4982 QDeclarativeComponent component(&engine, testFileUrl("eval.qml"));
4984 QObject *o = component.create();
4987 QCOMPARE(o->property("test1").toBool(), true);
4988 QCOMPARE(o->property("test2").toBool(), true);
4989 QCOMPARE(o->property("test3").toBool(), true);
4990 QCOMPARE(o->property("test4").toBool(), true);
4991 QCOMPARE(o->property("test5").toBool(), true);
4996 void tst_qdeclarativeecmascript::function()
4998 QDeclarativeComponent component(&engine, testFileUrl("function.qml"));
5000 QObject *o = component.create();
5003 QCOMPARE(o->property("test1").toBool(), true);
5004 QCOMPARE(o->property("test2").toBool(), true);
5005 QCOMPARE(o->property("test3").toBool(), true);
5010 // Test the "Qt.include" method
5011 void tst_qdeclarativeecmascript::include()
5013 // Non-library relative include
5015 QDeclarativeComponent component(&engine, testFileUrl("include.qml"));
5016 QObject *o = component.create();
5019 QCOMPARE(o->property("test0").toInt(), 99);
5020 QCOMPARE(o->property("test1").toBool(), true);
5021 QCOMPARE(o->property("test2").toBool(), true);
5022 QCOMPARE(o->property("test2_1").toBool(), true);
5023 QCOMPARE(o->property("test3").toBool(), true);
5024 QCOMPARE(o->property("test3_1").toBool(), true);
5029 // Library relative include
5031 QDeclarativeComponent component(&engine, testFileUrl("include_shared.qml"));
5032 QObject *o = component.create();
5035 QCOMPARE(o->property("test0").toInt(), 99);
5036 QCOMPARE(o->property("test1").toBool(), true);
5037 QCOMPARE(o->property("test2").toBool(), true);
5038 QCOMPARE(o->property("test2_1").toBool(), true);
5039 QCOMPARE(o->property("test3").toBool(), true);
5040 QCOMPARE(o->property("test3_1").toBool(), true);
5047 QDeclarativeComponent component(&engine, testFileUrl("include_callback.qml"));
5048 QObject *o = component.create();
5051 QCOMPARE(o->property("test1").toBool(), true);
5052 QCOMPARE(o->property("test2").toBool(), true);
5053 QCOMPARE(o->property("test3").toBool(), true);
5054 QCOMPARE(o->property("test4").toBool(), true);
5055 QCOMPARE(o->property("test5").toBool(), true);
5056 QCOMPARE(o->property("test6").toBool(), true);
5061 // Including file with ".pragma library"
5063 QDeclarativeComponent component(&engine, testFileUrl("include_pragma.qml"));
5064 QObject *o = component.create();
5066 QCOMPARE(o->property("test1").toInt(), 100);
5073 TestHTTPServer server(8111);
5074 QVERIFY(server.isValid());
5075 server.serveDirectory(dataDirectory());
5077 QDeclarativeComponent component(&engine, testFileUrl("include_remote.qml"));
5078 QObject *o = component.create();
5081 QTRY_VERIFY(o->property("done").toBool() == true);
5082 QTRY_VERIFY(o->property("done2").toBool() == true);
5084 QCOMPARE(o->property("test1").toBool(), true);
5085 QCOMPARE(o->property("test2").toBool(), true);
5086 QCOMPARE(o->property("test3").toBool(), true);
5087 QCOMPARE(o->property("test4").toBool(), true);
5088 QCOMPARE(o->property("test5").toBool(), true);
5090 QCOMPARE(o->property("test6").toBool(), true);
5091 QCOMPARE(o->property("test7").toBool(), true);
5092 QCOMPARE(o->property("test8").toBool(), true);
5093 QCOMPARE(o->property("test9").toBool(), true);
5094 QCOMPARE(o->property("test10").toBool(), true);
5101 TestHTTPServer server(8111);
5102 QVERIFY(server.isValid());
5103 server.serveDirectory(dataDirectory());
5105 QDeclarativeComponent component(&engine, testFileUrl("include_remote_missing.qml"));
5106 QObject *o = component.create();
5109 QTRY_VERIFY(o->property("done").toBool() == true);
5111 QCOMPARE(o->property("test1").toBool(), true);
5112 QCOMPARE(o->property("test2").toBool(), true);
5113 QCOMPARE(o->property("test3").toBool(), true);
5119 void tst_qdeclarativeecmascript::signalHandlers()
5121 QDeclarativeComponent component(&engine, testFileUrl("signalHandlers.qml"));
5122 QObject *o = component.create();
5125 QVERIFY(o->property("count").toInt() == 0);
5126 QMetaObject::invokeMethod(o, "testSignalCall");
5127 QCOMPARE(o->property("count").toInt(), 1);
5129 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
5130 QCOMPARE(o->property("count").toInt(), 1);
5131 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
5133 QVERIFY(o->property("funcCount").toInt() == 0);
5134 QMetaObject::invokeMethod(o, "testSignalConnection");
5135 QCOMPARE(o->property("funcCount").toInt(), 1);
5137 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
5138 QCOMPARE(o->property("funcCount").toInt(), 2);
5140 QMetaObject::invokeMethod(o, "testSignalDefined");
5141 QCOMPARE(o->property("definedResult").toBool(), true);
5143 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
5144 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
5149 void tst_qdeclarativeecmascript::qtbug_10696()
5151 QDeclarativeComponent component(&engine, testFileUrl("qtbug_10696.qml"));
5152 QObject *o = component.create();
5157 void tst_qdeclarativeecmascript::qtbug_11606()
5159 QDeclarativeComponent component(&engine, testFileUrl("qtbug_11606.qml"));
5160 QObject *o = component.create();
5162 QCOMPARE(o->property("test").toBool(), true);
5166 void tst_qdeclarativeecmascript::qtbug_11600()
5168 QDeclarativeComponent component(&engine, testFileUrl("qtbug_11600.qml"));
5169 QObject *o = component.create();
5171 QCOMPARE(o->property("test").toBool(), true);
5175 void tst_qdeclarativeecmascript::qtbug_21864()
5177 QDeclarativeComponent component(&engine, testFileUrl("qtbug_21864.qml"));
5178 QObject *o = component.create();
5180 QCOMPARE(o->property("test").toBool(), true);
5184 // Reading and writing non-scriptable properties should fail
5185 void tst_qdeclarativeecmascript::nonscriptable()
5187 QDeclarativeComponent component(&engine, testFileUrl("nonscriptable.qml"));
5188 QObject *o = component.create();
5190 QCOMPARE(o->property("readOk").toBool(), true);
5191 QCOMPARE(o->property("writeOk").toBool(), true);
5195 // deleteLater() should not be callable from QML
5196 void tst_qdeclarativeecmascript::deleteLater()
5198 QDeclarativeComponent component(&engine, testFileUrl("deleteLater.qml"));
5199 QObject *o = component.create();
5201 QCOMPARE(o->property("test").toBool(), true);
5205 void tst_qdeclarativeecmascript::in()
5207 QDeclarativeComponent component(&engine, testFileUrl("in.qml"));
5208 QObject *o = component.create();
5210 QCOMPARE(o->property("test1").toBool(), true);
5211 QCOMPARE(o->property("test2").toBool(), true);
5215 void tst_qdeclarativeecmascript::typeOf()
5217 QDeclarativeComponent component(&engine, testFileUrl("typeOf.qml"));
5219 // These warnings should not happen once QTBUG-21864 is fixed
5220 QString warning1 = component.url().toString() + QLatin1String(":16: Error: Cannot assign [undefined] to QString");
5221 QString warning2 = component.url().resolved(QUrl("typeOf.js")).toString() + QLatin1String(":1: ReferenceError: Can't find variable: a");
5223 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5224 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5226 QObject *o = component.create();
5229 QEXPECT_FAIL("", "QTBUG-21864", Abort);
5230 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
5231 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
5232 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
5233 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
5234 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
5235 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
5236 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
5237 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
5238 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
5243 void tst_qdeclarativeecmascript::sharedAttachedObject()
5245 QDeclarativeComponent component(&engine, testFileUrl("sharedAttachedObject.qml"));
5246 QObject *o = component.create();
5248 QCOMPARE(o->property("test1").toBool(), true);
5249 QCOMPARE(o->property("test2").toBool(), true);
5254 void tst_qdeclarativeecmascript::objectName()
5256 QDeclarativeComponent component(&engine, testFileUrl("objectName.qml"));
5257 QObject *o = component.create();
5260 QCOMPARE(o->property("test1").toString(), QString("hello"));
5261 QCOMPARE(o->property("test2").toString(), QString("ell"));
5263 o->setObjectName("world");
5265 QCOMPARE(o->property("test1").toString(), QString("world"));
5266 QCOMPARE(o->property("test2").toString(), QString("orl"));
5271 void tst_qdeclarativeecmascript::writeRemovesBinding()
5273 QDeclarativeComponent component(&engine, testFileUrl("writeRemovesBinding.qml"));
5274 QObject *o = component.create();
5277 QCOMPARE(o->property("test").toBool(), true);
5282 // Test bindings assigned to alias properties actually assign to the alias' target
5283 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
5285 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsAssignCorrectly.qml"));
5286 QObject *o = component.create();
5289 QCOMPARE(o->property("test").toBool(), true);
5294 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
5295 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
5298 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.qml"));
5299 QObject *o = component.create();
5302 QCOMPARE(o->property("test").toBool(), true);
5308 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.2.qml"));
5309 QObject *o = component.create();
5312 QCOMPARE(o->property("test").toBool(), true);
5318 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.3.qml"));
5319 QObject *o = component.create();
5322 QCOMPARE(o->property("test").toBool(), true);
5328 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
5329 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
5332 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.qml"));
5333 QObject *o = component.create();
5336 QCOMPARE(o->property("test").toBool(), true);
5342 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.2.qml"));
5343 QObject *o = component.create();
5346 QCOMPARE(o->property("test").toBool(), true);
5352 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.3.qml"));
5353 QObject *o = component.create();
5356 QCOMPARE(o->property("test").toBool(), true);
5362 // Allow an alais to a composite element
5364 void tst_qdeclarativeecmascript::aliasToCompositeElement()
5366 QDeclarativeComponent component(&engine, testFileUrl("aliasToCompositeElement.qml"));
5368 QObject *object = component.create();
5369 QVERIFY(object != 0);
5374 void tst_qdeclarativeecmascript::qtbug_20344()
5376 QDeclarativeComponent component(&engine, testFileUrl("qtbug_20344.qml"));
5378 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
5379 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5381 QObject *object = component.create();
5382 QVERIFY(object != 0);
5387 void tst_qdeclarativeecmascript::revisionErrors()
5390 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors.qml"));
5391 QString url = component.url().toString();
5393 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5394 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
5395 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
5397 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5398 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5399 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5400 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5401 QVERIFY(object != 0);
5405 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors2.qml"));
5406 QString url = component.url().toString();
5408 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
5409 // method2, prop2 from MyRevisionedClass not available
5410 // method4, prop4 from MyRevisionedSubclass not available
5411 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5412 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
5413 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
5414 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
5415 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
5417 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5418 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5419 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5420 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
5421 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
5422 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5423 QVERIFY(object != 0);
5427 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors3.qml"));
5428 QString url = component.url().toString();
5430 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
5431 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
5432 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
5433 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
5434 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
5435 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5436 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5437 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5438 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5439 QVERIFY(object != 0);
5444 void tst_qdeclarativeecmascript::revision()
5447 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision.qml"));
5448 QString url = component.url().toString();
5450 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5451 QVERIFY(object != 0);
5455 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision2.qml"));
5456 QString url = component.url().toString();
5458 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5459 QVERIFY(object != 0);
5463 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision3.qml"));
5464 QString url = component.url().toString();
5466 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5467 QVERIFY(object != 0);
5470 // Test that non-root classes can resolve revisioned methods
5472 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision4.qml"));
5474 QObject *object = component.create();
5475 QVERIFY(object != 0);
5476 QCOMPARE(object->property("test").toReal(), 11.);
5481 void tst_qdeclarativeecmascript::realToInt()
5483 QDeclarativeComponent component(&engine, testFileUrl("realToInt.qml"));
5484 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5485 QVERIFY(object != 0);
5487 QMetaObject::invokeMethod(object, "test1");
5488 QCOMPARE(object->value(), int(4));
5489 QMetaObject::invokeMethod(object, "test2");
5490 QCOMPARE(object->value(), int(8));
5493 void tst_qdeclarativeecmascript::urlProperty()
5496 QDeclarativeComponent component(&engine, testFileUrl("urlProperty.1.qml"));
5497 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5498 QVERIFY(object != 0);
5499 object->setStringProperty("http://qt-project.org");
5500 QCOMPARE(object->urlProperty(), QUrl("http://qt-project.org/index.html"));
5501 QCOMPARE(object->intProperty(), 123);
5502 QCOMPARE(object->value(), 1);
5503 QCOMPARE(object->property("result").toBool(), true);
5507 void tst_qdeclarativeecmascript::dynamicString()
5509 QDeclarativeComponent component(&engine, testFileUrl("dynamicString.qml"));
5510 QObject *object = component.create();
5511 QVERIFY(object != 0);
5512 QCOMPARE(object->property("stringProperty").toString(),
5513 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5516 void tst_qdeclarativeecmascript::automaticSemicolon()
5518 QDeclarativeComponent component(&engine, testFileUrl("automaticSemicolon.qml"));
5519 QObject *object = component.create();
5520 QVERIFY(object != 0);
5523 void tst_qdeclarativeecmascript::unaryExpression()
5525 QDeclarativeComponent component(&engine, testFileUrl("unaryExpression.qml"));
5526 QObject *object = component.create();
5527 QVERIFY(object != 0);
5530 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5531 void tst_qdeclarativeecmascript::doubleEvaluate()
5533 QDeclarativeComponent component(&engine, testFileUrl("doubleEvaluate.qml"));
5534 QObject *object = component.create();
5535 QVERIFY(object != 0);
5536 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5538 QCOMPARE(wc->count(), 1);
5540 wc->setProperty("x", 9);
5542 QCOMPARE(wc->count(), 2);
5547 static QStringList messages;
5548 static void captureMsgHandler(QtMsgType, const char *msg)
5550 messages.append(QLatin1String(msg));
5553 void tst_qdeclarativeecmascript::nonNotifyable()
5555 QV4Compiler::enableV4(false);
5556 QDeclarativeComponent component(&engine, testFileUrl("nonNotifyable.qml"));
5557 QV4Compiler::enableV4(true);
5559 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5561 QObject *object = component.create();
5562 qInstallMsgHandler(old);
5564 QVERIFY(object != 0);
5566 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5567 component.url().toString() +
5568 QLatin1String(":5 depends on non-NOTIFYable properties:");
5569 QString expected2 = QLatin1String(" ") +
5570 QLatin1String(object->metaObject()->className()) +
5571 QLatin1String("::value");
5573 QCOMPARE(messages.length(), 2);
5574 QCOMPARE(messages.at(0), expected1);
5575 QCOMPARE(messages.at(1), expected2);
5580 void tst_qdeclarativeecmascript::forInLoop()
5582 QDeclarativeComponent component(&engine, testFileUrl("forInLoop.qml"));
5583 QObject *object = component.create();
5584 QVERIFY(object != 0);
5586 QMetaObject::invokeMethod(object, "listProperty");
5588 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5589 QCOMPARE(r.size(), 3);
5590 QCOMPARE(r[0],QLatin1String("0=obj1"));
5591 QCOMPARE(r[1],QLatin1String("1=obj2"));
5592 QCOMPARE(r[2],QLatin1String("2=obj3"));
5594 //TODO: should test for in loop for other objects (such as QObjects) as well.
5599 // An object the binding depends on is deleted while the binding is still running
5600 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5602 QDeclarativeComponent component(&engine, testFileUrl("deleteWhileBindingRunning.qml"));
5603 QObject *object = component.create();
5604 QVERIFY(object != 0);
5608 void tst_qdeclarativeecmascript::qtbug_22679()
5611 object.setStringProperty(QLatin1String("Please work correctly"));
5612 engine.rootContext()->setContextProperty("contextProp", &object);
5614 QDeclarativeComponent component(&engine, testFileUrl("qtbug_22679.qml"));
5615 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5616 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5618 QObject *o = component.create();
5620 QCOMPARE(warningsSpy.count(), 0);
5624 void tst_qdeclarativeecmascript::qtbug_22843_data()
5626 QTest::addColumn<bool>("library");
5628 QTest::newRow("without .pragma library") << false;
5629 QTest::newRow("with .pragma library") << true;
5632 void tst_qdeclarativeecmascript::qtbug_22843()
5634 QFETCH(bool, library);
5636 QString fileName("qtbug_22843");
5638 fileName += QLatin1String(".library");
5639 fileName += QLatin1String(".qml");
5641 QDeclarativeComponent component(&engine, testFileUrl(fileName));
5642 QString url = component.url().toString();
5643 QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
5644 QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
5646 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5647 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5648 for (int x = 0; x < 3; ++x) {
5649 warningsSpy.clear();
5650 // For libraries, only the first import attempt should produce a
5651 // SyntaxError warning; subsequent component creation should not
5652 // attempt to reload the script.
5653 bool expectSyntaxError = !library || (x == 0);
5654 if (expectSyntaxError)
5655 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5656 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5657 QObject *object = component.create();
5658 QVERIFY(object != 0);
5659 QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
5665 void tst_qdeclarativeecmascript::switchStatement()
5668 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.1.qml"));
5669 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5670 QVERIFY(object != 0);
5672 // `object->value()' is the number of executed statements
5674 object->setStringProperty("A");
5675 QCOMPARE(object->value(), 5);
5677 object->setStringProperty("S");
5678 QCOMPARE(object->value(), 3);
5680 object->setStringProperty("D");
5681 QCOMPARE(object->value(), 3);
5683 object->setStringProperty("F");
5684 QCOMPARE(object->value(), 4);
5686 object->setStringProperty("something else");
5687 QCOMPARE(object->value(), 1);
5691 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.2.qml"));
5692 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5693 QVERIFY(object != 0);
5695 // `object->value()' is the number of executed statements
5697 object->setStringProperty("A");
5698 QCOMPARE(object->value(), 5);
5700 object->setStringProperty("S");
5701 QCOMPARE(object->value(), 3);
5703 object->setStringProperty("D");
5704 QCOMPARE(object->value(), 3);
5706 object->setStringProperty("F");
5707 QCOMPARE(object->value(), 3);
5709 object->setStringProperty("something else");
5710 QCOMPARE(object->value(), 4);
5714 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.3.qml"));
5715 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5716 QVERIFY(object != 0);
5718 // `object->value()' is the number of executed statements
5720 object->setStringProperty("A");
5721 QCOMPARE(object->value(), 5);
5723 object->setStringProperty("S");
5724 QCOMPARE(object->value(), 3);
5726 object->setStringProperty("D");
5727 QCOMPARE(object->value(), 3);
5729 object->setStringProperty("F");
5730 QCOMPARE(object->value(), 3);
5732 object->setStringProperty("something else");
5733 QCOMPARE(object->value(), 6);
5737 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.4.qml"));
5739 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
5740 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5742 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5743 QVERIFY(object != 0);
5745 // `object->value()' is the number of executed statements
5747 object->setStringProperty("A");
5748 QCOMPARE(object->value(), 5);
5750 object->setStringProperty("S");
5751 QCOMPARE(object->value(), 3);
5753 object->setStringProperty("D");
5754 QCOMPARE(object->value(), 3);
5756 object->setStringProperty("F");
5757 QCOMPARE(object->value(), 3);
5759 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5761 object->setStringProperty("something else");
5765 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.5.qml"));
5766 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5767 QVERIFY(object != 0);
5769 // `object->value()' is the number of executed statements
5771 object->setStringProperty("A");
5772 QCOMPARE(object->value(), 1);
5774 object->setStringProperty("S");
5775 QCOMPARE(object->value(), 1);
5777 object->setStringProperty("D");
5778 QCOMPARE(object->value(), 1);
5780 object->setStringProperty("F");
5781 QCOMPARE(object->value(), 1);
5783 object->setStringProperty("something else");
5784 QCOMPARE(object->value(), 1);
5788 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.6.qml"));
5789 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5790 QVERIFY(object != 0);
5792 // `object->value()' is the number of executed statements
5794 object->setStringProperty("A");
5795 QCOMPARE(object->value(), 123);
5797 object->setStringProperty("S");
5798 QCOMPARE(object->value(), 123);
5800 object->setStringProperty("D");
5801 QCOMPARE(object->value(), 321);
5803 object->setStringProperty("F");
5804 QCOMPARE(object->value(), 321);
5806 object->setStringProperty("something else");
5807 QCOMPARE(object->value(), 0);
5811 void tst_qdeclarativeecmascript::withStatement()
5814 QDeclarativeComponent component(&engine, testFileUrl("withStatement.1.qml"));
5815 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5816 QVERIFY(object != 0);
5818 QCOMPARE(object->value(), 123);
5822 void tst_qdeclarativeecmascript::tryStatement()
5825 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.1.qml"));
5826 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5827 QVERIFY(object != 0);
5829 QCOMPARE(object->value(), 123);
5833 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.2.qml"));
5834 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5835 QVERIFY(object != 0);
5837 QCOMPARE(object->value(), 321);
5841 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.3.qml"));
5842 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5843 QVERIFY(object != 0);
5845 QCOMPARE(object->value(), 1);
5849 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.4.qml"));
5850 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5851 QVERIFY(object != 0);
5853 QCOMPARE(object->value(), 1);
5857 QTEST_MAIN(tst_qdeclarativeecmascript)
5859 #include "tst_qdeclarativeecmascript.moc"