1 /****************************************************************************
3 ** Copyright (C) 2012 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 qobjectConnectionListExceptionHandling();
203 void nonscriptable();
207 void sharedAttachedObject();
209 void writeRemovesBinding();
210 void aliasBindingsAssignCorrectly();
211 void aliasBindingsOverrideTarget();
212 void aliasWritesOverrideBindings();
213 void aliasToCompositeElement();
216 void dynamicString();
218 void signalHandlers();
219 void doubleEvaluate();
221 void nonNotifyable();
222 void deleteWhileBindingRunning();
223 void callQtInvokables();
224 void invokableObjectArg();
225 void invokableObjectRet();
228 void qtbug_22843_data();
230 void revisionErrors();
233 void automaticSemicolon();
234 void unaryExpression();
235 void switchStatement();
236 void withStatement();
240 static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
241 QDeclarativeEngine engine;
244 void tst_qdeclarativeecmascript::initTestCase()
246 QDeclarativeDataTest::initTestCase();
250 void tst_qdeclarativeecmascript::assignBasicTypes()
253 QDeclarativeComponent component(&engine, testFileUrl("assignBasicTypes.qml"));
254 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
255 QVERIFY(object != 0);
256 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
257 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
258 QCOMPARE(object->stringProperty(), QString("Hello World!"));
259 QCOMPARE(object->uintProperty(), uint(10));
260 QCOMPARE(object->intProperty(), -19);
261 QCOMPARE((float)object->realProperty(), float(23.2));
262 QCOMPARE((float)object->doubleProperty(), float(-19.75));
263 QCOMPARE((float)object->floatProperty(), float(8.5));
264 QCOMPARE(object->colorProperty(), QColor("red"));
265 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
266 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
267 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
268 QCOMPARE(object->pointProperty(), QPoint(99,13));
269 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
270 QCOMPARE(object->sizeProperty(), QSize(99, 13));
271 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
272 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
273 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
274 QCOMPARE(object->boolProperty(), true);
275 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
276 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
277 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
281 QDeclarativeComponent component(&engine, testFileUrl("assignBasicTypes.2.qml"));
282 MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
283 QVERIFY(object != 0);
284 QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
285 QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
286 QCOMPARE(object->stringProperty(), QString("Hello World!"));
287 QCOMPARE(object->uintProperty(), uint(10));
288 QCOMPARE(object->intProperty(), -19);
289 QCOMPARE((float)object->realProperty(), float(23.2));
290 QCOMPARE((float)object->doubleProperty(), float(-19.75));
291 QCOMPARE((float)object->floatProperty(), float(8.5));
292 QCOMPARE(object->colorProperty(), QColor("red"));
293 QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
294 QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
295 QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
296 QCOMPARE(object->pointProperty(), QPoint(99,13));
297 QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
298 QCOMPARE(object->sizeProperty(), QSize(99, 13));
299 QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
300 QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
301 QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
302 QCOMPARE(object->boolProperty(), true);
303 QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
304 QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
305 QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
310 void tst_qdeclarativeecmascript::idShortcutInvalidates()
313 QDeclarativeComponent component(&engine, testFileUrl("idShortcutInvalidates.qml"));
314 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
315 QVERIFY(object != 0);
316 QVERIFY(object->objectProperty() != 0);
317 delete object->objectProperty();
318 QVERIFY(object->objectProperty() == 0);
323 QDeclarativeComponent component(&engine, testFileUrl("idShortcutInvalidates.1.qml"));
324 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
325 QVERIFY(object != 0);
326 QVERIFY(object->objectProperty() != 0);
327 delete object->objectProperty();
328 QVERIFY(object->objectProperty() == 0);
333 void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
336 QDeclarativeComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.1.qml"));
337 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
338 QVERIFY(object != 0);
339 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
343 QDeclarativeComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.2.qml"));
344 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
345 QVERIFY(object != 0);
346 QCOMPARE(object->stringProperty(), QLatin1String("pass"));
351 void tst_qdeclarativeecmascript::signalAssignment()
354 QDeclarativeComponent component(&engine, testFileUrl("signalAssignment.1.qml"));
355 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
356 QVERIFY(object != 0);
357 QCOMPARE(object->string(), QString());
358 emit object->basicSignal();
359 QCOMPARE(object->string(), QString("pass"));
364 QDeclarativeComponent component(&engine, testFileUrl("signalAssignment.2.qml"));
365 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
366 QVERIFY(object != 0);
367 QCOMPARE(object->string(), QString());
368 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
369 QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
374 void tst_qdeclarativeecmascript::methods()
377 QDeclarativeComponent component(&engine, testFileUrl("methods.1.qml"));
378 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
379 QVERIFY(object != 0);
380 QCOMPARE(object->methodCalled(), false);
381 QCOMPARE(object->methodIntCalled(), false);
382 emit object->basicSignal();
383 QCOMPARE(object->methodCalled(), true);
384 QCOMPARE(object->methodIntCalled(), false);
389 QDeclarativeComponent component(&engine, testFileUrl("methods.2.qml"));
390 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
391 QVERIFY(object != 0);
392 QCOMPARE(object->methodCalled(), false);
393 QCOMPARE(object->methodIntCalled(), false);
394 emit object->basicSignal();
395 QCOMPARE(object->methodCalled(), false);
396 QCOMPARE(object->methodIntCalled(), true);
401 QDeclarativeComponent component(&engine, testFileUrl("methods.3.qml"));
402 QObject *object = component.create();
403 QVERIFY(object != 0);
404 QCOMPARE(object->property("test").toInt(), 19);
409 QDeclarativeComponent component(&engine, testFileUrl("methods.4.qml"));
410 QObject *object = component.create();
411 QVERIFY(object != 0);
412 QCOMPARE(object->property("test").toInt(), 19);
413 QCOMPARE(object->property("test2").toInt(), 17);
414 QCOMPARE(object->property("test3").toInt(), 16);
419 QDeclarativeComponent component(&engine, testFileUrl("methods.5.qml"));
420 QObject *object = component.create();
421 QVERIFY(object != 0);
422 QCOMPARE(object->property("test").toInt(), 9);
427 void tst_qdeclarativeecmascript::bindingLoop()
429 QDeclarativeComponent component(&engine, testFileUrl("bindingLoop.qml"));
430 QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
431 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
432 QObject *object = component.create();
433 QVERIFY(object != 0);
437 void tst_qdeclarativeecmascript::basicExpressions_data()
439 QTest::addColumn<QString>("expression");
440 QTest::addColumn<QVariant>("result");
441 QTest::addColumn<bool>("nest");
443 QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
444 QTest::newRow("Context property") << "a" << QVariant(1944) << false;
445 QTest::newRow("Context property") << "a" << QVariant(1944) << true;
446 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
447 QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
448 QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
449 QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
450 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
451 QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
452 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
453 QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
454 QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
455 QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
456 QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
457 QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
458 QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
459 QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
460 QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
461 QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
464 void tst_qdeclarativeecmascript::basicExpressions()
466 QFETCH(QString, expression);
467 QFETCH(QVariant, result);
473 MyDefaultObject1 default1;
474 MyDefaultObject3 default3;
475 object1.setStringProperty("Object1");
476 object2.setStringProperty("Object2");
477 object3.setStringProperty("Object3");
479 QDeclarativeContext context(engine.rootContext());
480 QDeclarativeContext nestedContext(&context);
482 context.setContextObject(&default1);
483 context.setContextProperty("a", QVariant(1944));
484 context.setContextProperty("b", QVariant("Milk"));
485 context.setContextProperty("object", &object1);
486 context.setContextProperty("objectOverride", &object2);
487 nestedContext.setContextObject(&default3);
488 nestedContext.setContextProperty("b", QVariant("Cow"));
489 nestedContext.setContextProperty("objectOverride", &object3);
490 nestedContext.setContextProperty("millipedeLegs", QVariant(100));
492 MyExpression expr(nest?&nestedContext:&context, expression);
493 QCOMPARE(expr.evaluate(), result);
496 void tst_qdeclarativeecmascript::arrayExpressions()
502 QDeclarativeContext context(engine.rootContext());
503 context.setContextProperty("a", &obj1);
504 context.setContextProperty("b", &obj2);
505 context.setContextProperty("c", &obj3);
507 MyExpression expr(&context, "[a, b, c, 10]");
508 QVariant result = expr.evaluate();
509 QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
510 QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
511 QCOMPARE(list.count(), 4);
512 QCOMPARE(list.at(0), &obj1);
513 QCOMPARE(list.at(1), &obj2);
514 QCOMPARE(list.at(2), &obj3);
515 QCOMPARE(list.at(3), (QObject *)0);
518 // Tests that modifying a context property will reevaluate expressions
519 void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
521 QDeclarativeContext context(engine.rootContext());
524 MyQmlObject *object3 = new MyQmlObject;
526 object1.setStringProperty("Hello");
527 object2.setStringProperty("World");
529 context.setContextProperty("testProp", QVariant(1));
530 context.setContextProperty("testObj", &object1);
531 context.setContextProperty("testObj2", object3);
534 MyExpression expr(&context, "testProp + 1");
535 QCOMPARE(expr.changed, false);
536 QCOMPARE(expr.evaluate(), QVariant(2));
538 context.setContextProperty("testProp", QVariant(2));
539 QCOMPARE(expr.changed, true);
540 QCOMPARE(expr.evaluate(), QVariant(3));
544 MyExpression expr(&context, "testProp + testProp + testProp");
545 QCOMPARE(expr.changed, false);
546 QCOMPARE(expr.evaluate(), QVariant(6));
548 context.setContextProperty("testProp", QVariant(4));
549 QCOMPARE(expr.changed, true);
550 QCOMPARE(expr.evaluate(), QVariant(12));
554 MyExpression expr(&context, "testObj.stringProperty");
555 QCOMPARE(expr.changed, false);
556 QCOMPARE(expr.evaluate(), QVariant("Hello"));
558 context.setContextProperty("testObj", &object2);
559 QCOMPARE(expr.changed, true);
560 QCOMPARE(expr.evaluate(), QVariant("World"));
564 MyExpression expr(&context, "testObj.stringProperty /**/");
565 QCOMPARE(expr.changed, false);
566 QCOMPARE(expr.evaluate(), QVariant("World"));
568 context.setContextProperty("testObj", &object1);
569 QCOMPARE(expr.changed, true);
570 QCOMPARE(expr.evaluate(), QVariant("Hello"));
574 MyExpression expr(&context, "testObj2");
575 QCOMPARE(expr.changed, false);
576 QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
582 void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
584 QDeclarativeContext context(engine.rootContext());
588 context.setContextProperty("testObj", &object1);
590 object1.setStringProperty(QLatin1String("Hello"));
591 object2.setStringProperty(QLatin1String("Dog"));
592 object3.setStringProperty(QLatin1String("Cat"));
595 MyExpression expr(&context, "testObj.stringProperty");
596 QCOMPARE(expr.changed, false);
597 QCOMPARE(expr.evaluate(), QVariant("Hello"));
599 object1.setStringProperty(QLatin1String("World"));
600 QCOMPARE(expr.changed, true);
601 QCOMPARE(expr.evaluate(), QVariant("World"));
605 MyExpression expr(&context, "testObj.objectProperty.stringProperty");
606 QCOMPARE(expr.changed, false);
607 QCOMPARE(expr.evaluate(), QVariant());
609 object1.setObjectProperty(&object2);
610 QCOMPARE(expr.changed, true);
611 expr.changed = false;
612 QCOMPARE(expr.evaluate(), QVariant("Dog"));
614 object1.setObjectProperty(&object3);
615 QCOMPARE(expr.changed, true);
616 expr.changed = false;
617 QCOMPARE(expr.evaluate(), QVariant("Cat"));
619 object1.setObjectProperty(0);
620 QCOMPARE(expr.changed, true);
621 expr.changed = false;
622 QCOMPARE(expr.evaluate(), QVariant());
624 object1.setObjectProperty(&object3);
625 QCOMPARE(expr.changed, true);
626 expr.changed = false;
627 QCOMPARE(expr.evaluate(), QVariant("Cat"));
629 object3.setStringProperty("Donkey");
630 QCOMPARE(expr.changed, true);
631 expr.changed = false;
632 QCOMPARE(expr.evaluate(), QVariant("Donkey"));
636 void tst_qdeclarativeecmascript::deferredProperties()
638 QDeclarativeComponent component(&engine, testFileUrl("deferredProperties.qml"));
639 MyDeferredObject *object =
640 qobject_cast<MyDeferredObject *>(component.create());
641 QVERIFY(object != 0);
642 QCOMPARE(object->value(), 0);
643 QVERIFY(object->objectProperty() == 0);
644 QVERIFY(object->objectProperty2() != 0);
645 qmlExecuteDeferred(object);
646 QCOMPARE(object->value(), 10);
647 QVERIFY(object->objectProperty() != 0);
648 MyQmlObject *qmlObject =
649 qobject_cast<MyQmlObject *>(object->objectProperty());
650 QVERIFY(qmlObject != 0);
651 QCOMPARE(qmlObject->value(), 10);
652 object->setValue(19);
653 QCOMPARE(qmlObject->value(), 19);
658 // Check errors on deferred properties are correctly emitted
659 void tst_qdeclarativeecmascript::deferredPropertiesErrors()
661 QDeclarativeComponent component(&engine, testFileUrl("deferredPropertiesErrors.qml"));
662 MyDeferredObject *object =
663 qobject_cast<MyDeferredObject *>(component.create());
664 QVERIFY(object != 0);
665 QCOMPARE(object->value(), 0);
666 QVERIFY(object->objectProperty() == 0);
667 QVERIFY(object->objectProperty2() == 0);
669 QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
670 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
672 qmlExecuteDeferred(object);
677 void tst_qdeclarativeecmascript::extensionObjects()
679 QDeclarativeComponent component(&engine, testFileUrl("extensionObjects.qml"));
680 MyExtendedObject *object =
681 qobject_cast<MyExtendedObject *>(component.create());
682 QVERIFY(object != 0);
683 QCOMPARE(object->baseProperty(), 13);
684 QCOMPARE(object->coreProperty(), 9);
685 object->setProperty("extendedProperty", QVariant(11));
686 object->setProperty("baseExtendedProperty", QVariant(92));
687 QCOMPARE(object->coreProperty(), 11);
688 QCOMPARE(object->baseProperty(), 92);
690 MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
692 QCOMPARE(nested->baseProperty(), 13);
693 QCOMPARE(nested->coreProperty(), 9);
694 nested->setProperty("extendedProperty", QVariant(11));
695 nested->setProperty("baseExtendedProperty", QVariant(92));
696 QCOMPARE(nested->coreProperty(), 11);
697 QCOMPARE(nested->baseProperty(), 92);
702 void tst_qdeclarativeecmascript::overrideExtensionProperties()
704 QDeclarativeComponent component(&engine, testFileUrl("extensionObjectsPropertyOverride.qml"));
705 OverrideDefaultPropertyObject *object =
706 qobject_cast<OverrideDefaultPropertyObject *>(component.create());
707 QVERIFY(object != 0);
708 QVERIFY(object->secondProperty() != 0);
709 QVERIFY(object->firstProperty() == 0);
714 void tst_qdeclarativeecmascript::attachedProperties()
717 QDeclarativeComponent component(&engine, testFileUrl("attachedProperty.qml"));
718 QObject *object = component.create();
719 QVERIFY(object != 0);
720 QCOMPARE(object->property("a").toInt(), 19);
721 QCOMPARE(object->property("b").toInt(), 19);
722 QCOMPARE(object->property("c").toInt(), 19);
723 QCOMPARE(object->property("d").toInt(), 19);
728 QDeclarativeComponent component(&engine, testFileUrl("attachedProperty.2.qml"));
729 QObject *object = component.create();
730 QVERIFY(object != 0);
731 QCOMPARE(object->property("a").toInt(), 26);
732 QCOMPARE(object->property("b").toInt(), 26);
733 QCOMPARE(object->property("c").toInt(), 26);
734 QCOMPARE(object->property("d").toInt(), 26);
740 QDeclarativeComponent component(&engine, testFileUrl("writeAttachedProperty.qml"));
741 QObject *object = component.create();
742 QVERIFY(object != 0);
744 QMetaObject::invokeMethod(object, "writeValue2");
746 MyQmlAttachedObject *attached =
747 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
748 QVERIFY(attached != 0);
750 QCOMPARE(attached->value2(), 9);
755 void tst_qdeclarativeecmascript::enums()
759 QDeclarativeComponent component(&engine, testFileUrl("enums.1.qml"));
760 QObject *object = component.create();
761 QVERIFY(object != 0);
763 QCOMPARE(object->property("a").toInt(), 0);
764 QCOMPARE(object->property("b").toInt(), 1);
765 QCOMPARE(object->property("c").toInt(), 2);
766 QCOMPARE(object->property("d").toInt(), 3);
767 QCOMPARE(object->property("e").toInt(), 0);
768 QCOMPARE(object->property("f").toInt(), 1);
769 QCOMPARE(object->property("g").toInt(), 2);
770 QCOMPARE(object->property("h").toInt(), 3);
771 QCOMPARE(object->property("i").toInt(), 19);
772 QCOMPARE(object->property("j").toInt(), 19);
776 // Non-existent enums
778 QDeclarativeComponent component(&engine, testFileUrl("enums.2.qml"));
780 QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
781 QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
782 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
783 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
785 QObject *object = component.create();
786 QVERIFY(object != 0);
787 QCOMPARE(object->property("a").toInt(), 0);
788 QCOMPARE(object->property("b").toInt(), 0);
794 void tst_qdeclarativeecmascript::valueTypeFunctions()
796 QDeclarativeComponent component(&engine, testFileUrl("valueTypeFunctions.qml"));
797 MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
799 QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
800 QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
806 Tests that writing a constant to a property with a binding on it disables the
809 void tst_qdeclarativeecmascript::constantsOverrideBindings()
813 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.1.qml"));
814 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
815 QVERIFY(object != 0);
817 QCOMPARE(object->property("c2").toInt(), 0);
818 object->setProperty("c1", QVariant(9));
819 QCOMPARE(object->property("c2").toInt(), 9);
821 emit object->basicSignal();
823 QCOMPARE(object->property("c2").toInt(), 13);
824 object->setProperty("c1", QVariant(8));
825 QCOMPARE(object->property("c2").toInt(), 13);
830 // During construction
832 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.2.qml"));
833 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
834 QVERIFY(object != 0);
836 QCOMPARE(object->property("c1").toInt(), 0);
837 QCOMPARE(object->property("c2").toInt(), 10);
838 object->setProperty("c1", QVariant(9));
839 QCOMPARE(object->property("c1").toInt(), 9);
840 QCOMPARE(object->property("c2").toInt(), 10);
848 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.3.qml"));
849 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
850 QVERIFY(object != 0);
852 QCOMPARE(object->property("c2").toInt(), 0);
853 object->setProperty("c1", QVariant(9));
854 QCOMPARE(object->property("c2").toInt(), 9);
856 object->setProperty("c2", QVariant(13));
857 QCOMPARE(object->property("c2").toInt(), 13);
858 object->setProperty("c1", QVariant(7));
859 QCOMPARE(object->property("c1").toInt(), 7);
860 QCOMPARE(object->property("c2").toInt(), 13);
868 QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.4.qml"));
869 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
870 QVERIFY(object != 0);
872 QCOMPARE(object->property("c1").toInt(), 0);
873 QCOMPARE(object->property("c3").toInt(), 10);
874 object->setProperty("c1", QVariant(9));
875 QCOMPARE(object->property("c1").toInt(), 9);
876 QCOMPARE(object->property("c3").toInt(), 10);
883 Tests that assigning a binding to a property that already has a binding causes
884 the original binding to be disabled.
886 void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
888 QDeclarativeComponent component(&engine,
889 testFileUrl("outerBindingOverridesInnerBinding.qml"));
890 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
891 QVERIFY(object != 0);
893 QCOMPARE(object->property("c1").toInt(), 0);
894 QCOMPARE(object->property("c2").toInt(), 0);
895 QCOMPARE(object->property("c3").toInt(), 0);
897 object->setProperty("c1", QVariant(9));
898 QCOMPARE(object->property("c1").toInt(), 9);
899 QCOMPARE(object->property("c2").toInt(), 0);
900 QCOMPARE(object->property("c3").toInt(), 0);
902 object->setProperty("c3", QVariant(8));
903 QCOMPARE(object->property("c1").toInt(), 9);
904 QCOMPARE(object->property("c2").toInt(), 8);
905 QCOMPARE(object->property("c3").toInt(), 8);
911 Access a non-existent attached object.
913 Tests for a regression where this used to crash.
915 void tst_qdeclarativeecmascript::nonExistentAttachedObject()
917 QDeclarativeComponent component(&engine, testFileUrl("nonExistentAttachedObject.qml"));
919 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
920 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
922 QObject *object = component.create();
923 QVERIFY(object != 0);
928 void tst_qdeclarativeecmascript::scope()
931 QDeclarativeComponent component(&engine, testFileUrl("scope.qml"));
932 QObject *object = component.create();
933 QVERIFY(object != 0);
935 QCOMPARE(object->property("test1").toInt(), 1);
936 QCOMPARE(object->property("test2").toInt(), 2);
937 QCOMPARE(object->property("test3").toString(), QString("1Test"));
938 QCOMPARE(object->property("test4").toString(), QString("2Test"));
939 QCOMPARE(object->property("test5").toInt(), 1);
940 QCOMPARE(object->property("test6").toInt(), 1);
941 QCOMPARE(object->property("test7").toInt(), 2);
942 QCOMPARE(object->property("test8").toInt(), 2);
943 QCOMPARE(object->property("test9").toInt(), 1);
944 QCOMPARE(object->property("test10").toInt(), 3);
950 QDeclarativeComponent component(&engine, testFileUrl("scope.2.qml"));
951 QObject *object = component.create();
952 QVERIFY(object != 0);
954 QCOMPARE(object->property("test1").toInt(), 19);
955 QCOMPARE(object->property("test2").toInt(), 19);
956 QCOMPARE(object->property("test3").toInt(), 14);
957 QCOMPARE(object->property("test4").toInt(), 14);
958 QCOMPARE(object->property("test5").toInt(), 24);
959 QCOMPARE(object->property("test6").toInt(), 24);
965 QDeclarativeComponent component(&engine, testFileUrl("scope.3.qml"));
966 QObject *object = component.create();
967 QVERIFY(object != 0);
969 QCOMPARE(object->property("test1").toBool(), true);
970 QCOMPARE(object->property("test2").toBool(), true);
971 QCOMPARE(object->property("test3").toBool(), true);
976 // Signal argument scope
978 QDeclarativeComponent component(&engine, testFileUrl("scope.4.qml"));
979 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
980 QVERIFY(object != 0);
982 QCOMPARE(object->property("test").toInt(), 0);
983 QCOMPARE(object->property("test2").toString(), QString());
985 emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
987 QCOMPARE(object->property("test").toInt(), 13);
988 QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
994 QDeclarativeComponent component(&engine, testFileUrl("scope.5.qml"));
995 QObject *object = component.create();
996 QVERIFY(object != 0);
998 QCOMPARE(object->property("test1").toBool(), true);
999 QCOMPARE(object->property("test2").toBool(), true);
1005 QDeclarativeComponent component(&engine, testFileUrl("scope.6.qml"));
1006 QObject *object = component.create();
1007 QVERIFY(object != 0);
1009 QCOMPARE(object->property("test").toBool(), true);
1015 // In 4.7, non-library javascript files that had no imports shared the imports of their
1016 // importing context
1017 void tst_qdeclarativeecmascript::importScope()
1019 QDeclarativeComponent component(&engine, testFileUrl("importScope.qml"));
1020 QObject *o = component.create();
1023 QCOMPARE(o->property("test").toInt(), 240);
1029 Tests that "any" type passes through a synthesized signal parameter. This
1030 is essentially a test of QDeclarativeMetaType::copy()
1032 void tst_qdeclarativeecmascript::signalParameterTypes()
1034 QDeclarativeComponent component(&engine, testFileUrl("signalParameterTypes.qml"));
1035 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1036 QVERIFY(object != 0);
1038 emit object->basicSignal();
1040 QCOMPARE(object->property("intProperty").toInt(), 10);
1041 QCOMPARE(object->property("realProperty").toReal(), 19.2);
1042 QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
1043 QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
1044 QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
1045 QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
1051 Test that two JS objects for the same QObject compare as equal.
1053 void tst_qdeclarativeecmascript::objectsCompareAsEqual()
1055 QDeclarativeComponent component(&engine, testFileUrl("objectsCompareAsEqual.qml"));
1056 QObject *object = component.create();
1057 QVERIFY(object != 0);
1059 QCOMPARE(object->property("test1").toBool(), true);
1060 QCOMPARE(object->property("test2").toBool(), true);
1061 QCOMPARE(object->property("test3").toBool(), true);
1062 QCOMPARE(object->property("test4").toBool(), true);
1063 QCOMPARE(object->property("test5").toBool(), true);
1069 Confirm bindings and alias properties can coexist.
1071 Tests for a regression where the binding would not reevaluate.
1073 void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
1075 QDeclarativeComponent component(&engine, testFileUrl("aliasPropertyAndBinding.qml"));
1076 QObject *object = component.create();
1077 QVERIFY(object != 0);
1079 QCOMPARE(object->property("c2").toInt(), 3);
1080 QCOMPARE(object->property("c3").toInt(), 3);
1082 object->setProperty("c2", QVariant(19));
1084 QCOMPARE(object->property("c2").toInt(), 19);
1085 QCOMPARE(object->property("c3").toInt(), 19);
1091 Ensure that we can write undefined value to an alias property,
1092 and that the aliased property is reset correctly if possible.
1094 void tst_qdeclarativeecmascript::aliasPropertyReset()
1096 QObject *object = 0;
1098 // test that a manual write (of undefined) to a resettable aliased property succeeds
1099 QDeclarativeComponent c1(&engine, testFileUrl("aliasreset/aliasPropertyReset.1.qml"));
1100 object = c1.create();
1101 QVERIFY(object != 0);
1102 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1103 QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
1104 QMetaObject::invokeMethod(object, "resetAliased");
1105 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1106 QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
1109 // test that a manual write (of undefined) to a resettable alias property succeeds
1110 QDeclarativeComponent c2(&engine, testFileUrl("aliasreset/aliasPropertyReset.2.qml"));
1111 object = c2.create();
1112 QVERIFY(object != 0);
1113 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1114 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
1115 QMetaObject::invokeMethod(object, "resetAlias");
1116 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1117 QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
1120 // test that an alias to a bound property works correctly
1121 QDeclarativeComponent c3(&engine, testFileUrl("aliasreset/aliasPropertyReset.3.qml"));
1122 object = c3.create();
1123 QVERIFY(object != 0);
1124 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1125 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
1126 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1127 QMetaObject::invokeMethod(object, "resetAlias");
1128 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1129 QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
1130 QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
1133 // test that a manual write (of undefined) to a resettable alias property
1134 // whose aliased property's object has been deleted, does not crash.
1135 QDeclarativeComponent c4(&engine, testFileUrl("aliasreset/aliasPropertyReset.4.qml"));
1136 object = c4.create();
1137 QVERIFY(object != 0);
1138 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
1139 QObject *loader = object->findChild<QObject*>("loader");
1140 QVERIFY(loader != 0);
1142 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
1143 QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
1144 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1145 QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
1146 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
1149 // test that binding an alias property to an undefined value works correctly
1150 QDeclarativeComponent c5(&engine, testFileUrl("aliasreset/aliasPropertyReset.5.qml"));
1151 object = c5.create();
1152 QVERIFY(object != 0);
1153 QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
1156 // test that a manual write (of undefined) to a non-resettable property fails properly
1157 QUrl url = testFileUrl("aliasreset/aliasPropertyReset.error.1.qml");
1158 QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
1159 QDeclarativeComponent e1(&engine, url);
1160 object = e1.create();
1161 QVERIFY(object != 0);
1162 QCOMPARE(object->property("intAlias").value<int>(), 12);
1163 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1164 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1165 QMetaObject::invokeMethod(object, "resetAlias");
1166 QCOMPARE(object->property("intAlias").value<int>(), 12);
1167 QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
1171 void tst_qdeclarativeecmascript::dynamicCreation_data()
1173 QTest::addColumn<QString>("method");
1174 QTest::addColumn<QString>("createdName");
1176 QTest::newRow("One") << "createOne" << "objectOne";
1177 QTest::newRow("Two") << "createTwo" << "objectTwo";
1178 QTest::newRow("Three") << "createThree" << "objectThree";
1182 Test using createQmlObject to dynamically generate an item
1183 Also using createComponent is tested.
1185 void tst_qdeclarativeecmascript::dynamicCreation()
1187 QFETCH(QString, method);
1188 QFETCH(QString, createdName);
1190 QDeclarativeComponent component(&engine, testFileUrl("dynamicCreation.qml"));
1191 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1192 QVERIFY(object != 0);
1194 QMetaObject::invokeMethod(object, method.toUtf8());
1195 QObject *created = object->objectProperty();
1197 QCOMPARE(created->objectName(), createdName);
1203 Tests the destroy function
1205 void tst_qdeclarativeecmascript::dynamicDestruction()
1208 QDeclarativeComponent component(&engine, testFileUrl("dynamicDeletion.qml"));
1209 QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
1210 QVERIFY(object != 0);
1211 QDeclarativeGuard<QObject> createdQmlObject = 0;
1213 QMetaObject::invokeMethod(object, "create");
1214 createdQmlObject = object->objectProperty();
1215 QVERIFY(createdQmlObject);
1216 QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
1218 QMetaObject::invokeMethod(object, "killOther");
1219 QVERIFY(createdQmlObject);
1220 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1221 QVERIFY(createdQmlObject);
1222 for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
1223 if (createdQmlObject) {
1225 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1228 QVERIFY(!createdQmlObject);
1230 QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
1231 QMetaObject::invokeMethod(object, "killMe");
1234 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1239 QDeclarativeComponent component(&engine, testFileUrl("dynamicDeletion.2.qml"));
1240 QObject *o = component.create();
1243 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1245 QMetaObject::invokeMethod(o, "create");
1247 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
1249 QMetaObject::invokeMethod(o, "destroy");
1251 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
1253 QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
1260 tests that id.toString() works
1262 void tst_qdeclarativeecmascript::objectToString()
1264 QDeclarativeComponent component(&engine, testFileUrl("declarativeToString.qml"));
1265 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1266 QVERIFY(object != 0);
1267 QMetaObject::invokeMethod(object, "testToString");
1268 QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
1269 QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
1275 tests that id.hasOwnProperty() works
1277 void tst_qdeclarativeecmascript::objectHasOwnProperty()
1279 QUrl url = testFileUrl("declarativeHasOwnProperty.qml");
1280 QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1281 QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1282 QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
1284 QDeclarativeComponent component(&engine, url);
1285 QObject *object = component.create();
1286 QVERIFY(object != 0);
1288 // test QObjects in QML
1289 QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
1290 QVERIFY(object->property("result").value<bool>() == true);
1291 QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
1292 QVERIFY(object->property("result").value<bool>() == false);
1294 // now test other types in QML
1295 QObject *child = object->findChild<QObject*>("typeObj");
1296 QVERIFY(child != 0);
1297 QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
1298 QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
1299 QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
1300 QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
1301 QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
1302 QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
1303 QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
1304 QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
1305 QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
1306 QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
1307 QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
1308 QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
1310 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1311 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
1312 QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
1313 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1314 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
1315 QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
1316 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1317 QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
1318 QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
1324 Tests bindings that indirectly cause their own deletion work.
1326 This test is best run under valgrind to ensure no invalid memory access occur.
1328 void tst_qdeclarativeecmascript::selfDeletingBinding()
1331 QDeclarativeComponent component(&engine, testFileUrl("selfDeletingBinding.qml"));
1332 QObject *object = component.create();
1333 QVERIFY(object != 0);
1334 object->setProperty("triggerDelete", true);
1339 QDeclarativeComponent component(&engine, testFileUrl("selfDeletingBinding.2.qml"));
1340 QObject *object = component.create();
1341 QVERIFY(object != 0);
1342 object->setProperty("triggerDelete", true);
1348 Test that extended object properties can be accessed.
1350 This test a regression where this used to crash. The issue was specificially
1351 for extended objects that did not include a synthesized meta object (so non-root
1352 and no synthesiszed properties).
1354 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
1356 QDeclarativeComponent component(&engine, testFileUrl("extendedObjectPropertyLookup.qml"));
1357 QObject *object = component.create();
1358 QVERIFY(object != 0);
1363 Test that extended object properties can be accessed correctly.
1365 void tst_qdeclarativeecmascript::extendedObjectPropertyLookup2()
1367 QDeclarativeComponent component(&engine, testFileUrl("extendedObjectPropertyLookup2.qml"));
1368 QObject *object = component.create();
1369 QVERIFY(object != 0);
1371 QVariant returnValue;
1372 QVERIFY(QMetaObject::invokeMethod(object, "getValue", Q_RETURN_ARG(QVariant, returnValue)));
1373 QCOMPARE(returnValue.toInt(), 42);
1378 Test file/lineNumbers for binding/Script errors.
1380 void tst_qdeclarativeecmascript::scriptErrors()
1382 QDeclarativeComponent component(&engine, testFileUrl("scriptErrors.qml"));
1383 QString url = component.url().toString();
1385 QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
1386 QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
1387 QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
1388 QString warning4 = url + ":13: ReferenceError: Can't find variable: a";
1389 QString warning5 = url + ":11: ReferenceError: Can't find variable: a";
1390 QString warning6 = url + ":10: Unable to assign [undefined] to int";
1391 QString warning7 = url + ":15: Error: Cannot assign to read-only property \"trueProperty\"";
1392 QString warning8 = url + ":16: Error: Cannot assign to non-existent property \"fakeProperty\"";
1394 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
1395 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
1396 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
1397 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
1398 QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
1399 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
1400 QVERIFY(object != 0);
1402 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
1403 emit object->basicSignal();
1405 QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
1406 emit object->anotherBasicSignal();
1408 QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
1409 emit object->thirdBasicSignal();
1415 Test file/lineNumbers for inline functions.
1417 void tst_qdeclarativeecmascript::functionErrors()
1419 QDeclarativeComponent component(&engine, testFileUrl("functionErrors.qml"));
1420 QString url = component.url().toString();
1422 QString warning = url + ":5: Error: Invalid write to global property \"a\"";
1424 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1426 QObject *object = component.create();
1427 QVERIFY(object != 0);
1430 // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
1431 QDeclarativeComponent componentTwo(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
1432 url = componentTwo.url().toString();
1433 object = componentTwo.create();
1434 QVERIFY(object != 0);
1436 QString srpname = object->property("srp_name").toString();
1438 warning = url + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srpname
1439 + QLatin1String(" is not a function");
1440 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
1441 QMetaObject::invokeMethod(object, "retrieveScarceResource");
1446 Test various errors that can occur when assigning a property from script
1448 void tst_qdeclarativeecmascript::propertyAssignmentErrors()
1450 QDeclarativeComponent component(&engine, testFileUrl("propertyAssignmentErrors.qml"));
1452 QString url = component.url().toString();
1454 QObject *object = component.create();
1455 QVERIFY(object != 0);
1457 QCOMPARE(object->property("test1").toBool(), true);
1458 QCOMPARE(object->property("test2").toBool(), true);
1464 Test bindings still work when the reeval is triggered from within
1467 void tst_qdeclarativeecmascript::signalTriggeredBindings()
1469 QDeclarativeComponent component(&engine, testFileUrl("signalTriggeredBindings.qml"));
1470 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1471 QVERIFY(object != 0);
1473 QCOMPARE(object->property("base").toReal(), 50.);
1474 QCOMPARE(object->property("test1").toReal(), 50.);
1475 QCOMPARE(object->property("test2").toReal(), 50.);
1477 object->basicSignal();
1479 QCOMPARE(object->property("base").toReal(), 200.);
1480 QCOMPARE(object->property("test1").toReal(), 200.);
1481 QCOMPARE(object->property("test2").toReal(), 200.);
1483 object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
1485 QCOMPARE(object->property("base").toReal(), 400.);
1486 QCOMPARE(object->property("test1").toReal(), 400.);
1487 QCOMPARE(object->property("test2").toReal(), 400.);
1493 Test that list properties can be iterated from ECMAScript
1495 void tst_qdeclarativeecmascript::listProperties()
1497 QDeclarativeComponent component(&engine, testFileUrl("listProperties.qml"));
1498 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1499 QVERIFY(object != 0);
1501 QCOMPARE(object->property("test1").toInt(), 21);
1502 QCOMPARE(object->property("test2").toInt(), 2);
1503 QCOMPARE(object->property("test3").toBool(), true);
1504 QCOMPARE(object->property("test4").toBool(), true);
1509 void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
1511 QDeclarativeComponent component(&engine, testFileUrl("exceptionClearsOnReeval.qml"));
1512 QString url = component.url().toString();
1514 QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
1516 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1517 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1518 QVERIFY(object != 0);
1520 QCOMPARE(object->property("test").toBool(), false);
1522 MyQmlObject object2;
1523 MyQmlObject object3;
1524 object2.setObjectProperty(&object3);
1525 object->setObjectProperty(&object2);
1527 QCOMPARE(object->property("test").toBool(), true);
1532 void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
1534 QDeclarativeComponent component(&engine, testFileUrl("exceptionProducesWarning.qml"));
1535 QString url = component.url().toString();
1537 QString warning = component.url().toString() + ":6: Error: JS exception";
1539 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1540 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1541 QVERIFY(object != 0);
1545 void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
1547 QDeclarativeComponent component(&engine, testFileUrl("exceptionProducesWarning2.qml"));
1548 QString url = component.url().toString();
1550 QString warning = component.url().toString() + ":5: Error: JS exception";
1552 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
1553 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1554 QVERIFY(object != 0);
1558 static int transientErrorsMsgCount = 0;
1559 static void transientErrorsMsgHandler(QtMsgType, const char *)
1561 ++transientErrorsMsgCount;
1564 // Check that transient binding errors are not displayed
1565 void tst_qdeclarativeecmascript::transientErrors()
1568 QDeclarativeComponent component(&engine, testFileUrl("transientErrors.qml"));
1570 transientErrorsMsgCount = 0;
1571 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1573 QObject *object = component.create();
1574 QVERIFY(object != 0);
1576 qInstallMsgHandler(old);
1578 QCOMPARE(transientErrorsMsgCount, 0);
1583 // One binding erroring multiple times, but then resolving
1585 QDeclarativeComponent component(&engine, testFileUrl("transientErrors.2.qml"));
1587 transientErrorsMsgCount = 0;
1588 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1590 QObject *object = component.create();
1591 QVERIFY(object != 0);
1593 qInstallMsgHandler(old);
1595 QCOMPARE(transientErrorsMsgCount, 0);
1601 // Check that errors during shutdown are minimized
1602 void tst_qdeclarativeecmascript::shutdownErrors()
1604 QDeclarativeComponent component(&engine, testFileUrl("shutdownErrors.qml"));
1605 QObject *object = component.create();
1606 QVERIFY(object != 0);
1608 transientErrorsMsgCount = 0;
1609 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
1613 qInstallMsgHandler(old);
1614 QCOMPARE(transientErrorsMsgCount, 0);
1617 void tst_qdeclarativeecmascript::compositePropertyType()
1619 QDeclarativeComponent component(&engine, testFileUrl("compositePropertyType.qml"));
1621 QTest::ignoreMessage(QtDebugMsg, "hello world");
1622 QObject *object = qobject_cast<QObject *>(component.create());
1627 void tst_qdeclarativeecmascript::jsObject()
1629 QDeclarativeComponent component(&engine, testFileUrl("jsObject.qml"));
1630 QObject *object = component.create();
1631 QVERIFY(object != 0);
1633 QCOMPARE(object->property("test").toInt(), 92);
1638 void tst_qdeclarativeecmascript::undefinedResetsProperty()
1641 QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.qml"));
1642 QObject *object = component.create();
1643 QVERIFY(object != 0);
1645 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1647 object->setProperty("setUndefined", true);
1649 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1651 object->setProperty("setUndefined", false);
1653 QCOMPARE(object->property("resettableProperty").toInt(), 92);
1658 QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.2.qml"));
1659 QObject *object = component.create();
1660 QVERIFY(object != 0);
1662 QCOMPARE(object->property("resettableProperty").toInt(), 19);
1664 QMetaObject::invokeMethod(object, "doReset");
1666 QCOMPARE(object->property("resettableProperty").toInt(), 13);
1672 // Aliases to variant properties should work
1673 void tst_qdeclarativeecmascript::qtbug_22464()
1675 QDeclarativeComponent component(&engine, testFileUrl("qtbug_22464.qml"));
1676 QObject *object = component.create();
1677 QVERIFY(object != 0);
1679 QCOMPARE(object->property("test").toBool(), true);
1684 void tst_qdeclarativeecmascript::qtbug_21580()
1686 QDeclarativeComponent component(&engine, testFileUrl("qtbug_21580.qml"));
1688 QObject *object = component.create();
1689 QVERIFY(object != 0);
1691 QCOMPARE(object->property("test").toBool(), true);
1697 void tst_qdeclarativeecmascript::bug1()
1699 QDeclarativeComponent component(&engine, testFileUrl("bug.1.qml"));
1700 QObject *object = component.create();
1701 QVERIFY(object != 0);
1703 QCOMPARE(object->property("test").toInt(), 14);
1705 object->setProperty("a", 11);
1707 QCOMPARE(object->property("test").toInt(), 3);
1709 object->setProperty("b", true);
1711 QCOMPARE(object->property("test").toInt(), 9);
1716 void tst_qdeclarativeecmascript::bug2()
1718 QDeclarativeComponent component(&engine);
1719 component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
1721 QObject *object = component.create();
1722 QVERIFY(object != 0);
1727 // Don't crash in createObject when the component has errors.
1728 void tst_qdeclarativeecmascript::dynamicCreationCrash()
1730 QDeclarativeComponent component(&engine, testFileUrl("dynamicCreation.qml"));
1731 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1732 QVERIFY(object != 0);
1734 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
1735 QMetaObject::invokeMethod(object, "dontCrash");
1736 QObject *created = object->objectProperty();
1737 QVERIFY(created == 0);
1742 // ownership transferred to JS, ensure that GC runs the dtor
1743 void tst_qdeclarativeecmascript::dynamicCreationOwnership()
1746 int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
1748 // allow the engine to go out of scope too.
1750 QDeclarativeEngine dcoEngine;
1751 QDeclarativeComponent component(&dcoEngine, testFileUrl("dynamicCreationOwnership.qml"));
1752 QObject *object = component.create();
1753 QVERIFY(object != 0);
1754 MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
1755 QVERIFY(mdcdo != 0);
1756 mdcdo->setDtorCount(&dtorCount);
1758 for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
1759 QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
1761 // we do this once manually, but it should be done automatically
1762 // when the engine goes out of scope (since it should gc in dtor)
1763 QMetaObject::invokeMethod(object, "performGc");
1766 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1772 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
1773 QCOMPARE(dtorCount, expectedDtorCount);
1777 void tst_qdeclarativeecmascript::regExpBug()
1779 QDeclarativeComponent component(&engine, testFileUrl("regExp.qml"));
1780 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
1781 QVERIFY(object != 0);
1782 QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
1786 static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
1788 QString functionSource = QLatin1String("(function(object) { return ") +
1789 QLatin1String(source) + QLatin1String(" })");
1791 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1794 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1795 if (function.IsEmpty())
1797 v8::Handle<v8::Value> args[] = { o };
1798 function->Call(engine->global(), 1, args);
1799 return tc.HasCaught();
1802 static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
1803 const char *source, v8::Handle<v8::Value> result)
1805 QString functionSource = QLatin1String("(function(object) { return ") +
1806 QLatin1String(source) + QLatin1String(" })");
1808 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1811 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1812 if (function.IsEmpty())
1814 v8::Handle<v8::Value> args[] = { o };
1816 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1821 return value->StrictEquals(result);
1824 static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
1827 QString functionSource = QLatin1String("(function(object) { return ") +
1828 QLatin1String(source) + QLatin1String(" })");
1830 v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
1832 return v8::Handle<v8::Value>();
1833 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
1834 if (function.IsEmpty())
1835 return v8::Handle<v8::Value>();
1836 v8::Handle<v8::Value> args[] = { o };
1838 v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
1841 return v8::Handle<v8::Value>();
1845 #define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
1846 #define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
1847 #define EVALUATE(source) evaluate(engine, object, source)
1849 void tst_qdeclarativeecmascript::callQtInvokables()
1851 MyInvokableObject o;
1853 QDeclarativeEngine qmlengine;
1854 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
1856 QV8Engine *engine = ep->v8engine();
1858 v8::HandleScope handle_scope;
1859 v8::Context::Scope scope(engine->context());
1861 v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
1863 // Non-existent methods
1865 QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
1866 QCOMPARE(o.error(), false);
1867 QCOMPARE(o.invoked(), -1);
1868 QCOMPARE(o.actuals().count(), 0);
1871 QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
1872 QCOMPARE(o.error(), false);
1873 QCOMPARE(o.invoked(), -1);
1874 QCOMPARE(o.actuals().count(), 0);
1876 // Insufficient arguments
1878 QVERIFY(EVALUATE_ERROR("object.method_int()"));
1879 QCOMPARE(o.error(), false);
1880 QCOMPARE(o.invoked(), -1);
1881 QCOMPARE(o.actuals().count(), 0);
1884 QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
1885 QCOMPARE(o.error(), false);
1886 QCOMPARE(o.invoked(), -1);
1887 QCOMPARE(o.actuals().count(), 0);
1889 // Excessive arguments
1891 QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
1892 QCOMPARE(o.error(), false);
1893 QCOMPARE(o.invoked(), 8);
1894 QCOMPARE(o.actuals().count(), 1);
1895 QCOMPARE(o.actuals().at(0), QVariant(10));
1898 QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
1899 QCOMPARE(o.error(), false);
1900 QCOMPARE(o.invoked(), 9);
1901 QCOMPARE(o.actuals().count(), 2);
1902 QCOMPARE(o.actuals().at(0), QVariant(10));
1903 QCOMPARE(o.actuals().at(1), QVariant(11));
1905 // Test return types
1907 QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
1908 QCOMPARE(o.error(), false);
1909 QCOMPARE(o.invoked(), 0);
1910 QCOMPARE(o.actuals().count(), 0);
1913 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
1914 QCOMPARE(o.error(), false);
1915 QCOMPARE(o.invoked(), 1);
1916 QCOMPARE(o.actuals().count(), 0);
1919 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
1920 QCOMPARE(o.error(), false);
1921 QCOMPARE(o.invoked(), 2);
1922 QCOMPARE(o.actuals().count(), 0);
1926 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
1927 QVERIFY(!ret.IsEmpty());
1928 QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
1929 QCOMPARE(o.error(), false);
1930 QCOMPARE(o.invoked(), 3);
1931 QCOMPARE(o.actuals().count(), 0);
1936 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
1937 QCOMPARE(engine->toQObject(ret), (QObject *)&o);
1938 QCOMPARE(o.error(), false);
1939 QCOMPARE(o.invoked(), 4);
1940 QCOMPARE(o.actuals().count(), 0);
1944 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
1945 QCOMPARE(o.error(), false);
1946 QCOMPARE(o.invoked(), 5);
1947 QCOMPARE(o.actuals().count(), 0);
1951 v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
1952 QVERIFY(ret->IsString());
1953 QCOMPARE(engine->toString(ret), QString("Hello world"));
1954 QCOMPARE(o.error(), false);
1955 QCOMPARE(o.invoked(), 6);
1956 QCOMPARE(o.actuals().count(), 0);
1960 QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
1961 QCOMPARE(o.error(), false);
1962 QCOMPARE(o.invoked(), 7);
1963 QCOMPARE(o.actuals().count(), 0);
1967 QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
1968 QCOMPARE(o.error(), false);
1969 QCOMPARE(o.invoked(), 8);
1970 QCOMPARE(o.actuals().count(), 1);
1971 QCOMPARE(o.actuals().at(0), QVariant(94));
1974 QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
1975 QCOMPARE(o.error(), false);
1976 QCOMPARE(o.invoked(), 8);
1977 QCOMPARE(o.actuals().count(), 1);
1978 QCOMPARE(o.actuals().at(0), QVariant(94));
1981 QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
1982 QCOMPARE(o.error(), false);
1983 QCOMPARE(o.invoked(), 8);
1984 QCOMPARE(o.actuals().count(), 1);
1985 QCOMPARE(o.actuals().at(0), QVariant(0));
1988 QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
1989 QCOMPARE(o.error(), false);
1990 QCOMPARE(o.invoked(), 8);
1991 QCOMPARE(o.actuals().count(), 1);
1992 QCOMPARE(o.actuals().at(0), QVariant(0));
1995 QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
1996 QCOMPARE(o.error(), false);
1997 QCOMPARE(o.invoked(), 8);
1998 QCOMPARE(o.actuals().count(), 1);
1999 QCOMPARE(o.actuals().at(0), QVariant(0));
2002 QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
2003 QCOMPARE(o.error(), false);
2004 QCOMPARE(o.invoked(), 8);
2005 QCOMPARE(o.actuals().count(), 1);
2006 QCOMPARE(o.actuals().at(0), QVariant(0));
2009 QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
2010 QCOMPARE(o.error(), false);
2011 QCOMPARE(o.invoked(), 9);
2012 QCOMPARE(o.actuals().count(), 2);
2013 QCOMPARE(o.actuals().at(0), QVariant(122));
2014 QCOMPARE(o.actuals().at(1), QVariant(9));
2017 QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
2018 QCOMPARE(o.error(), false);
2019 QCOMPARE(o.invoked(), 10);
2020 QCOMPARE(o.actuals().count(), 1);
2021 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2024 QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
2025 QCOMPARE(o.error(), false);
2026 QCOMPARE(o.invoked(), 10);
2027 QCOMPARE(o.actuals().count(), 1);
2028 QCOMPARE(o.actuals().at(0), QVariant(94.3));
2031 QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
2032 QCOMPARE(o.error(), false);
2033 QCOMPARE(o.invoked(), 10);
2034 QCOMPARE(o.actuals().count(), 1);
2035 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2038 QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
2039 QCOMPARE(o.error(), false);
2040 QCOMPARE(o.invoked(), 10);
2041 QCOMPARE(o.actuals().count(), 1);
2042 QCOMPARE(o.actuals().at(0), QVariant(0));
2045 QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
2046 QCOMPARE(o.error(), false);
2047 QCOMPARE(o.invoked(), 10);
2048 QCOMPARE(o.actuals().count(), 1);
2049 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2052 QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
2053 QCOMPARE(o.error(), false);
2054 QCOMPARE(o.invoked(), 10);
2055 QCOMPARE(o.actuals().count(), 1);
2056 QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
2059 QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
2060 QCOMPARE(o.error(), false);
2061 QCOMPARE(o.invoked(), 11);
2062 QCOMPARE(o.actuals().count(), 1);
2063 QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
2066 QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
2067 QCOMPARE(o.error(), false);
2068 QCOMPARE(o.invoked(), 11);
2069 QCOMPARE(o.actuals().count(), 1);
2070 QCOMPARE(o.actuals().at(0), QVariant("19"));
2074 QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
2075 QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
2076 QCOMPARE(o.error(), false);
2077 QCOMPARE(o.invoked(), 11);
2078 QCOMPARE(o.actuals().count(), 1);
2079 QCOMPARE(o.actuals().at(0), QVariant(expected));
2083 QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
2084 QCOMPARE(o.error(), false);
2085 QCOMPARE(o.invoked(), 11);
2086 QCOMPARE(o.actuals().count(), 1);
2087 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2090 QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
2091 QCOMPARE(o.error(), false);
2092 QCOMPARE(o.invoked(), 11);
2093 QCOMPARE(o.actuals().count(), 1);
2094 QCOMPARE(o.actuals().at(0), QVariant(QString()));
2097 QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
2098 QCOMPARE(o.error(), false);
2099 QCOMPARE(o.invoked(), 12);
2100 QCOMPARE(o.actuals().count(), 1);
2101 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2104 QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
2105 QCOMPARE(o.error(), false);
2106 QCOMPARE(o.invoked(), 12);
2107 QCOMPARE(o.actuals().count(), 1);
2108 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2111 QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
2112 QCOMPARE(o.error(), false);
2113 QCOMPARE(o.invoked(), 12);
2114 QCOMPARE(o.actuals().count(), 1);
2115 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2118 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
2119 QCOMPARE(o.error(), false);
2120 QCOMPARE(o.invoked(), 12);
2121 QCOMPARE(o.actuals().count(), 1);
2122 QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
2125 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
2126 QCOMPARE(o.error(), false);
2127 QCOMPARE(o.invoked(), 12);
2128 QCOMPARE(o.actuals().count(), 1);
2129 QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
2132 QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
2133 QCOMPARE(o.error(), false);
2134 QCOMPARE(o.invoked(), 12);
2135 QCOMPARE(o.actuals().count(), 1);
2136 QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
2139 QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
2140 QCOMPARE(o.error(), false);
2141 QCOMPARE(o.invoked(), 13);
2142 QCOMPARE(o.actuals().count(), 1);
2143 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2146 QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
2147 QCOMPARE(o.error(), false);
2148 QCOMPARE(o.invoked(), 13);
2149 QCOMPARE(o.actuals().count(), 1);
2150 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2153 QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
2154 QCOMPARE(o.error(), false);
2155 QCOMPARE(o.invoked(), 13);
2156 QCOMPARE(o.actuals().count(), 1);
2157 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2160 QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
2161 QCOMPARE(o.error(), false);
2162 QCOMPARE(o.invoked(), 13);
2163 QCOMPARE(o.actuals().count(), 1);
2164 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
2167 QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
2168 QCOMPARE(o.error(), false);
2169 QCOMPARE(o.invoked(), 13);
2170 QCOMPARE(o.actuals().count(), 1);
2171 QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
2174 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
2175 QCOMPARE(o.error(), false);
2176 QCOMPARE(o.invoked(), 14);
2177 QCOMPARE(o.actuals().count(), 1);
2178 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
2181 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
2182 QCOMPARE(o.error(), false);
2183 QCOMPARE(o.invoked(), 14);
2184 QCOMPARE(o.actuals().count(), 1);
2185 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
2188 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
2189 QCOMPARE(o.error(), false);
2190 QCOMPARE(o.invoked(), 14);
2191 QCOMPARE(o.actuals().count(), 1);
2192 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
2195 QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
2196 QCOMPARE(o.error(), false);
2197 QCOMPARE(o.invoked(), 14);
2198 QCOMPARE(o.actuals().count(), 1);
2199 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
2202 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
2203 QCOMPARE(o.error(), false);
2204 QCOMPARE(o.invoked(), 15);
2205 QCOMPARE(o.actuals().count(), 2);
2206 QCOMPARE(o.actuals().at(0), QVariant(4));
2207 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
2210 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
2211 QCOMPARE(o.error(), false);
2212 QCOMPARE(o.invoked(), 15);
2213 QCOMPARE(o.actuals().count(), 2);
2214 QCOMPARE(o.actuals().at(0), QVariant(8));
2215 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
2218 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
2219 QCOMPARE(o.error(), false);
2220 QCOMPARE(o.invoked(), 15);
2221 QCOMPARE(o.actuals().count(), 2);
2222 QCOMPARE(o.actuals().at(0), QVariant(3));
2223 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
2226 QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
2227 QCOMPARE(o.error(), false);
2228 QCOMPARE(o.invoked(), 15);
2229 QCOMPARE(o.actuals().count(), 2);
2230 QCOMPARE(o.actuals().at(0), QVariant(44));
2231 QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
2234 QVERIFY(EVALUATE_ERROR("object.method_overload()"));
2235 QCOMPARE(o.error(), false);
2236 QCOMPARE(o.invoked(), -1);
2237 QCOMPARE(o.actuals().count(), 0);
2240 QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
2241 QCOMPARE(o.error(), false);
2242 QCOMPARE(o.invoked(), 16);
2243 QCOMPARE(o.actuals().count(), 1);
2244 QCOMPARE(o.actuals().at(0), QVariant(10));
2247 QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
2248 QCOMPARE(o.error(), false);
2249 QCOMPARE(o.invoked(), 17);
2250 QCOMPARE(o.actuals().count(), 2);
2251 QCOMPARE(o.actuals().at(0), QVariant(10));
2252 QCOMPARE(o.actuals().at(1), QVariant(11));
2255 QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
2256 QCOMPARE(o.error(), false);
2257 QCOMPARE(o.invoked(), 18);
2258 QCOMPARE(o.actuals().count(), 1);
2259 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2262 QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
2263 QCOMPARE(o.error(), false);
2264 QCOMPARE(o.invoked(), 19);
2265 QCOMPARE(o.actuals().count(), 1);
2266 QCOMPARE(o.actuals().at(0), QVariant(9));
2269 QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
2270 QCOMPARE(o.error(), false);
2271 QCOMPARE(o.invoked(), 20);
2272 QCOMPARE(o.actuals().count(), 2);
2273 QCOMPARE(o.actuals().at(0), QVariant(10));
2274 QCOMPARE(o.actuals().at(1), QVariant(19));
2277 QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
2278 QCOMPARE(o.error(), false);
2279 QCOMPARE(o.invoked(), 20);
2280 QCOMPARE(o.actuals().count(), 2);
2281 QCOMPARE(o.actuals().at(0), QVariant(10));
2282 QCOMPARE(o.actuals().at(1), QVariant(13));
2285 QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
2286 QCOMPARE(o.error(), false);
2287 QCOMPARE(o.invoked(), -3);
2288 QCOMPARE(o.actuals().count(), 1);
2289 QCOMPARE(o.actuals().at(0), QVariant(9));
2292 QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
2293 QCOMPARE(o.error(), false);
2294 QCOMPARE(o.invoked(), 21);
2295 QCOMPARE(o.actuals().count(), 2);
2296 QCOMPARE(o.actuals().at(0), QVariant(9));
2297 QCOMPARE(o.actuals().at(1), QVariant());
2300 QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
2301 QCOMPARE(o.error(), false);
2302 QCOMPARE(o.invoked(), 21);
2303 QCOMPARE(o.actuals().count(), 2);
2304 QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
2305 QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
2308 // QTBUG-13047 (check that you can pass registered object types as args)
2309 void tst_qdeclarativeecmascript::invokableObjectArg()
2311 QDeclarativeComponent component(&engine, testFileUrl("invokableObjectArg.qml"));
2313 QObject *o = component.create();
2315 MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
2317 QCOMPARE(qmlobject->myinvokableObject, qmlobject);
2322 // QTBUG-13047 (check that you can return registered object types from methods)
2323 void tst_qdeclarativeecmascript::invokableObjectRet()
2325 QDeclarativeComponent component(&engine, testFileUrl("invokableObjectRet.qml"));
2327 QObject *o = component.create();
2329 QCOMPARE(o->property("test").toBool(), true);
2334 void tst_qdeclarativeecmascript::listToVariant()
2336 QDeclarativeComponent component(&engine, testFileUrl("listToVariant.qml"));
2338 MyQmlContainer container;
2340 QDeclarativeContext context(engine.rootContext());
2341 context.setContextObject(&container);
2343 QObject *object = component.create(&context);
2344 QVERIFY(object != 0);
2346 QVariant v = object->property("test");
2347 QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
2348 QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
2354 Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
2355 void tst_qdeclarativeecmascript::listAssignment()
2357 QDeclarativeComponent component(&engine, testFileUrl("listAssignment.qml"));
2358 QObject *obj = component.create();
2359 QCOMPARE(obj->property("list1length").toInt(), 2);
2360 QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
2361 QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
2362 QCOMPARE(list1.count(&list1), list2.count(&list2));
2363 QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
2364 QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
2369 void tst_qdeclarativeecmascript::multiEngineObject()
2372 obj.setStringProperty("Howdy planet");
2374 QDeclarativeEngine e1;
2375 e1.rootContext()->setContextProperty("thing", &obj);
2376 QDeclarativeComponent c1(&e1, testFileUrl("multiEngineObject.qml"));
2378 QDeclarativeEngine e2;
2379 e2.rootContext()->setContextProperty("thing", &obj);
2380 QDeclarativeComponent c2(&e2, testFileUrl("multiEngineObject.qml"));
2382 QObject *o1 = c1.create();
2383 QObject *o2 = c2.create();
2385 QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
2386 QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
2392 // Test that references to QObjects are cleanup when the object is destroyed
2393 void tst_qdeclarativeecmascript::deletedObject()
2395 QDeclarativeComponent component(&engine, testFileUrl("deletedObject.qml"));
2397 QObject *object = component.create();
2399 QCOMPARE(object->property("test1").toBool(), true);
2400 QCOMPARE(object->property("test2").toBool(), true);
2401 QCOMPARE(object->property("test3").toBool(), true);
2402 QCOMPARE(object->property("test4").toBool(), true);
2407 void tst_qdeclarativeecmascript::attachedPropertyScope()
2409 QDeclarativeComponent component(&engine, testFileUrl("attachedPropertyScope.qml"));
2411 QObject *object = component.create();
2412 QVERIFY(object != 0);
2414 MyQmlAttachedObject *attached =
2415 qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
2416 QVERIFY(attached != 0);
2418 QCOMPARE(object->property("value2").toInt(), 0);
2420 attached->emitMySignal();
2422 QCOMPARE(object->property("value2").toInt(), 9);
2427 void tst_qdeclarativeecmascript::scriptConnect()
2430 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.1.qml"));
2432 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2433 QVERIFY(object != 0);
2435 QCOMPARE(object->property("test").toBool(), false);
2436 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2437 QCOMPARE(object->property("test").toBool(), true);
2443 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.2.qml"));
2445 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2446 QVERIFY(object != 0);
2448 QCOMPARE(object->property("test").toBool(), false);
2449 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2450 QCOMPARE(object->property("test").toBool(), true);
2456 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.3.qml"));
2458 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2459 QVERIFY(object != 0);
2461 QCOMPARE(object->property("test").toBool(), false);
2462 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2463 QCOMPARE(object->property("test").toBool(), true);
2469 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.4.qml"));
2471 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2472 QVERIFY(object != 0);
2474 QCOMPARE(object->methodCalled(), false);
2475 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2476 QCOMPARE(object->methodCalled(), true);
2482 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.5.qml"));
2484 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2485 QVERIFY(object != 0);
2487 QCOMPARE(object->methodCalled(), false);
2488 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2489 QCOMPARE(object->methodCalled(), true);
2495 QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.6.qml"));
2497 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2498 QVERIFY(object != 0);
2500 QCOMPARE(object->property("test").toInt(), 0);
2501 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2502 QCOMPARE(object->property("test").toInt(), 2);
2508 void tst_qdeclarativeecmascript::scriptDisconnect()
2511 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.1.qml"));
2513 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2514 QVERIFY(object != 0);
2516 QCOMPARE(object->property("test").toInt(), 0);
2517 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2518 QCOMPARE(object->property("test").toInt(), 1);
2519 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2520 QCOMPARE(object->property("test").toInt(), 2);
2521 emit object->basicSignal();
2522 QCOMPARE(object->property("test").toInt(), 2);
2523 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2524 QCOMPARE(object->property("test").toInt(), 2);
2530 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.2.qml"));
2532 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2533 QVERIFY(object != 0);
2535 QCOMPARE(object->property("test").toInt(), 0);
2536 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2537 QCOMPARE(object->property("test").toInt(), 1);
2538 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2539 QCOMPARE(object->property("test").toInt(), 2);
2540 emit object->basicSignal();
2541 QCOMPARE(object->property("test").toInt(), 2);
2542 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2543 QCOMPARE(object->property("test").toInt(), 2);
2549 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.3.qml"));
2551 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2552 QVERIFY(object != 0);
2554 QCOMPARE(object->property("test").toInt(), 0);
2555 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2556 QCOMPARE(object->property("test").toInt(), 1);
2557 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2558 QCOMPARE(object->property("test").toInt(), 2);
2559 emit object->basicSignal();
2560 QCOMPARE(object->property("test").toInt(), 2);
2561 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2562 QCOMPARE(object->property("test").toInt(), 3);
2567 QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.4.qml"));
2569 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2570 QVERIFY(object != 0);
2572 QCOMPARE(object->property("test").toInt(), 0);
2573 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2574 QCOMPARE(object->property("test").toInt(), 1);
2575 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2576 QCOMPARE(object->property("test").toInt(), 2);
2577 emit object->basicSignal();
2578 QCOMPARE(object->property("test").toInt(), 2);
2579 emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
2580 QCOMPARE(object->property("test").toInt(), 3);
2586 class OwnershipObject : public QObject
2590 OwnershipObject() { object = new QObject; }
2592 QPointer<QObject> object;
2595 QObject *getObject() { return object; }
2598 void tst_qdeclarativeecmascript::ownership()
2600 OwnershipObject own;
2601 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2602 context->setContextObject(&own);
2605 QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
2607 QVERIFY(own.object != 0);
2609 QObject *object = component.create(context);
2611 engine.collectGarbage();
2613 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2615 QVERIFY(own.object == 0);
2620 own.object = new QObject(&own);
2623 QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
2625 QVERIFY(own.object != 0);
2627 QObject *object = component.create(context);
2629 engine.collectGarbage();
2631 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
2633 QVERIFY(own.object != 0);
2641 class CppOwnershipReturnValue : public QObject
2645 CppOwnershipReturnValue() : value(0) {}
2646 ~CppOwnershipReturnValue() { delete value; }
2648 Q_INVOKABLE QObject *create() {
2649 value = new QObject;
2650 QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
2654 Q_INVOKABLE MyQmlObject *createQmlObject() {
2655 MyQmlObject *rv = new MyQmlObject;
2660 QPointer<QObject> value;
2664 // Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
2665 void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
2667 CppOwnershipReturnValue source;
2670 QDeclarativeEngine engine;
2671 engine.rootContext()->setContextProperty("source", &source);
2673 QVERIFY(source.value == 0);
2675 QDeclarativeComponent component(&engine);
2676 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
2678 QObject *object = component.create();
2680 QVERIFY(object != 0);
2681 QVERIFY(source.value != 0);
2686 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2688 QVERIFY(source.value != 0);
2692 void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
2694 CppOwnershipReturnValue source;
2697 QDeclarativeEngine engine;
2698 engine.rootContext()->setContextProperty("source", &source);
2700 QVERIFY(source.value == 0);
2702 QDeclarativeComponent component(&engine);
2703 component.setData("import QtQuick 1.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
2705 QObject *object = component.create();
2707 QVERIFY(object != 0);
2708 QVERIFY(source.value != 0);
2713 engine.collectGarbage();
2714 QCoreApplication::instance()->processEvents(QEventLoop::DeferredDeletion);
2716 QVERIFY(source.value == 0);
2719 class QListQObjectMethodsObject : public QObject
2723 QListQObjectMethodsObject() {
2724 m_objects.append(new MyQmlObject());
2725 m_objects.append(new MyQmlObject());
2728 ~QListQObjectMethodsObject() {
2729 qDeleteAll(m_objects);
2733 QList<QObject *> getObjects() { return m_objects; }
2736 QList<QObject *> m_objects;
2739 // Tests that returning a QList<QObject*> from a method works
2740 void tst_qdeclarativeecmascript::qlistqobjectMethods()
2742 QListQObjectMethodsObject obj;
2743 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
2744 context->setContextObject(&obj);
2746 QDeclarativeComponent component(&engine, testFileUrl("qlistqobjectMethods.qml"));
2748 QObject *object = component.create(context);
2750 QCOMPARE(object->property("test").toInt(), 2);
2751 QCOMPARE(object->property("test2").toBool(), true);
2758 void tst_qdeclarativeecmascript::strictlyEquals()
2760 QDeclarativeComponent component(&engine, testFileUrl("strictlyEquals.qml"));
2762 QObject *object = component.create();
2763 QVERIFY(object != 0);
2765 QCOMPARE(object->property("test1").toBool(), true);
2766 QCOMPARE(object->property("test2").toBool(), true);
2767 QCOMPARE(object->property("test3").toBool(), true);
2768 QCOMPARE(object->property("test4").toBool(), true);
2769 QCOMPARE(object->property("test5").toBool(), true);
2770 QCOMPARE(object->property("test6").toBool(), true);
2771 QCOMPARE(object->property("test7").toBool(), true);
2772 QCOMPARE(object->property("test8").toBool(), true);
2777 void tst_qdeclarativeecmascript::compiled()
2779 QDeclarativeComponent component(&engine, testFileUrl("compiled.qml"));
2781 QObject *object = component.create();
2782 QVERIFY(object != 0);
2784 QCOMPARE(object->property("test1").toReal(), qreal(15.7));
2785 QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
2786 QCOMPARE(object->property("test3").toBool(), true);
2787 QCOMPARE(object->property("test4").toBool(), false);
2788 QCOMPARE(object->property("test5").toBool(), false);
2789 QCOMPARE(object->property("test6").toBool(), true);
2791 QCOMPARE(object->property("test7").toInt(), 185);
2792 QCOMPARE(object->property("test8").toInt(), 167);
2793 QCOMPARE(object->property("test9").toBool(), true);
2794 QCOMPARE(object->property("test10").toBool(), false);
2795 QCOMPARE(object->property("test11").toBool(), false);
2796 QCOMPARE(object->property("test12").toBool(), true);
2798 QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
2799 QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
2800 QCOMPARE(object->property("test15").toBool(), false);
2801 QCOMPARE(object->property("test16").toBool(), true);
2803 QCOMPARE(object->property("test17").toInt(), 5);
2804 QCOMPARE(object->property("test18").toReal(), qreal(176));
2805 QCOMPARE(object->property("test19").toInt(), 7);
2806 QCOMPARE(object->property("test20").toReal(), qreal(6.7));
2807 QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
2808 QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
2809 QCOMPARE(object->property("test23").toBool(), true);
2810 QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
2811 QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
2816 // Test that numbers assigned in bindings as strings work consistently
2817 void tst_qdeclarativeecmascript::numberAssignment()
2819 QDeclarativeComponent component(&engine, testFileUrl("numberAssignment.qml"));
2821 QObject *object = component.create();
2822 QVERIFY(object != 0);
2824 QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
2825 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2826 QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
2827 QCOMPARE(object->property("test3"), QVariant((qreal)6));
2828 QCOMPARE(object->property("test4"), QVariant((qreal)6));
2830 QCOMPARE(object->property("test5"), QVariant((int)7));
2831 QCOMPARE(object->property("test6"), QVariant((int)7));
2832 QCOMPARE(object->property("test7"), QVariant((int)6));
2833 QCOMPARE(object->property("test8"), QVariant((int)6));
2835 QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
2836 QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
2837 QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
2838 QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
2843 void tst_qdeclarativeecmascript::propertySplicing()
2845 QDeclarativeComponent component(&engine, testFileUrl("propertySplicing.qml"));
2847 QObject *object = component.create();
2848 QVERIFY(object != 0);
2850 QCOMPARE(object->property("test").toBool(), true);
2856 void tst_qdeclarativeecmascript::signalWithUnknownTypes()
2858 QDeclarativeComponent component(&engine, testFileUrl("signalWithUnknownTypes.qml"));
2860 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
2861 QVERIFY(object != 0);
2863 MyQmlObject::MyType type;
2864 type.value = 0x8971123;
2865 emit object->signalWithUnknownType(type);
2867 MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
2869 QCOMPARE(result.value, type.value);
2875 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
2877 QTest::addColumn<QString>("expression");
2878 QTest::addColumn<QString>("compare");
2880 QString compareStrict("(function(a, b) { return a === b; })");
2881 QTest::newRow("true") << "true" << compareStrict;
2882 QTest::newRow("undefined") << "undefined" << compareStrict;
2883 QTest::newRow("null") << "null" << compareStrict;
2884 QTest::newRow("123") << "123" << compareStrict;
2885 QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
2887 QString comparePropertiesStrict(
2889 " if (typeof b != 'object')"
2891 " var props = Object.getOwnPropertyNames(b);"
2892 " for (var i = 0; i < props.length; ++i) {"
2893 " var p = props[i];"
2894 " return arguments.callee(a[p], b[p]);"
2897 QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
2898 QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
2901 void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
2903 QFETCH(QString, expression);
2904 QFETCH(QString, compare);
2906 QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
2907 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2908 QVERIFY(object != 0);
2910 QJSValue value = engine.evaluate(expression);
2911 QVERIFY(!engine.hasUncaughtException());
2912 object->setProperty("expression", expression);
2913 object->setProperty("compare", compare);
2914 object->setProperty("pass", false);
2916 emit object->signalWithVariant(QVariant::fromValue(value));
2917 QVERIFY(object->property("pass").toBool());
2920 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
2922 signalWithJSValueInVariant_data();
2925 void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
2927 QFETCH(QString, expression);
2928 QFETCH(QString, compare);
2930 QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
2931 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2932 QVERIFY(object != 0);
2935 QJSValue value = engine2.evaluate(expression);
2936 QVERIFY(!engine2.hasUncaughtException());
2937 object->setProperty("expression", expression);
2938 object->setProperty("compare", compare);
2939 object->setProperty("pass", false);
2941 QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
2942 emit object->signalWithVariant(QVariant::fromValue(value));
2943 QVERIFY(!object->property("pass").toBool());
2946 void tst_qdeclarativeecmascript::signalWithQJSValue_data()
2948 signalWithJSValueInVariant_data();
2951 void tst_qdeclarativeecmascript::signalWithQJSValue()
2953 QFETCH(QString, expression);
2954 QFETCH(QString, compare);
2956 QDeclarativeComponent component(&engine, testFileUrl("signalWithQJSValue.qml"));
2957 QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
2958 QVERIFY(object != 0);
2960 QJSValue value = engine.evaluate(expression);
2961 QVERIFY(!engine.hasUncaughtException());
2962 object->setProperty("expression", expression);
2963 object->setProperty("compare", compare);
2964 object->setProperty("pass", false);
2966 emit object->signalWithQJSValue(value);
2968 QVERIFY(object->property("pass").toBool());
2969 QVERIFY(object->qjsvalue().strictlyEquals(value));
2972 void tst_qdeclarativeecmascript::moduleApi_data()
2974 QTest::addColumn<QUrl>("testfile");
2975 QTest::addColumn<QString>("errorMessage");
2976 QTest::addColumn<QStringList>("warningMessages");
2977 QTest::addColumn<QStringList>("readProperties");
2978 QTest::addColumn<QVariantList>("readExpectedValues");
2979 QTest::addColumn<QStringList>("writeProperties");
2980 QTest::addColumn<QVariantList>("writeValues");
2981 QTest::addColumn<QStringList>("readBackProperties");
2982 QTest::addColumn<QVariantList>("readBackExpectedValues");
2984 QTest::newRow("qobject, register + read + method")
2985 << testFileUrl("moduleapi/qobjectModuleApi.qml")
2988 << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
2989 << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
2990 << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
2996 QTest::newRow("script, register + read")
2997 << testFileUrl("moduleapi/scriptModuleApi.qml")
3000 << (QStringList() << "scriptTest")
3001 << (QVariantList() << 13)
3007 QTest::newRow("qobject, caching + read")
3008 << testFileUrl("moduleapi/qobjectModuleApiCaching.qml")
3011 << (QStringList() << "existingUriTest" << "qobjectParentedTest")
3012 << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
3018 QTest::newRow("script, caching + read")
3019 << testFileUrl("moduleapi/scriptModuleApiCaching.qml")
3022 << (QStringList() << "scriptTest")
3023 << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
3029 QTest::newRow("qobject, writing + readonly constraints")
3030 << testFileUrl("moduleapi/qobjectModuleApiWriting.qml")
3032 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
3033 << (QStringList() << "readOnlyProperty" << "writableProperty")
3034 << (QVariantList() << 20 << 50)
3035 << (QStringList() << "firstProperty" << "writableProperty")
3036 << (QVariantList() << 30 << 30)
3037 << (QStringList() << "readOnlyProperty" << "writableProperty")
3038 << (QVariantList() << 20 << 30);
3040 QTest::newRow("script, writing + readonly constraints")
3041 << testFileUrl("moduleapi/scriptModuleApiWriting.qml")
3043 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
3044 << (QStringList() << "readBack" << "unchanged")
3045 << (QVariantList() << 13 << 42)
3046 << (QStringList() << "firstProperty" << "secondProperty")
3047 << (QVariantList() << 30 << 30)
3048 << (QStringList() << "readBack" << "unchanged")
3049 << (QVariantList() << 30 << 42);
3051 QTest::newRow("qobject module API enum values in JS")
3052 << testFileUrl("moduleapi/qobjectModuleApiEnums.qml")
3055 << (QStringList() << "enumValue" << "enumMethod")
3056 << (QVariantList() << 42 << 30)
3062 QTest::newRow("qobject, invalid major version fail")
3063 << testFileUrl("moduleapi/moduleApiMajorVersionFail.qml")
3064 << QString("QDeclarativeComponent: Component is not ready")
3073 QTest::newRow("qobject, invalid minor version fail")
3074 << testFileUrl("moduleapi/moduleApiMinorVersionFail.qml")
3075 << QString("QDeclarativeComponent: Component is not ready")
3085 void tst_qdeclarativeecmascript::moduleApi()
3087 QFETCH(QUrl, testfile);
3088 QFETCH(QString, errorMessage);
3089 QFETCH(QStringList, warningMessages);
3090 QFETCH(QStringList, readProperties);
3091 QFETCH(QVariantList, readExpectedValues);
3092 QFETCH(QStringList, writeProperties);
3093 QFETCH(QVariantList, writeValues);
3094 QFETCH(QStringList, readBackProperties);
3095 QFETCH(QVariantList, readBackExpectedValues);
3097 QDeclarativeComponent component(&engine, testfile);
3099 if (!errorMessage.isEmpty())
3100 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3102 if (warningMessages.size())
3103 foreach (const QString &warning, warningMessages)
3104 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3106 QObject *object = component.create();
3107 if (!errorMessage.isEmpty()) {
3108 QVERIFY(object == 0);
3110 QVERIFY(object != 0);
3111 for (int i = 0; i < readProperties.size(); ++i)
3112 QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
3113 for (int i = 0; i < writeProperties.size(); ++i)
3114 QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
3115 for (int i = 0; i < readBackProperties.size(); ++i)
3116 QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
3121 void tst_qdeclarativeecmascript::importScripts_data()
3123 QTest::addColumn<QUrl>("testfile");
3124 QTest::addColumn<QString>("errorMessage");
3125 QTest::addColumn<QStringList>("warningMessages");
3126 QTest::addColumn<QStringList>("propertyNames");
3127 QTest::addColumn<QVariantList>("propertyValues");
3129 QTest::newRow("basic functionality")
3130 << testFileUrl("jsimport/testImport.qml")
3133 << (QStringList() << QLatin1String("importedScriptStringValue")
3134 << QLatin1String("importedScriptFunctionValue")
3135 << QLatin1String("importedModuleAttachedPropertyValue")
3136 << QLatin1String("importedModuleEnumValue"))
3137 << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
3142 QTest::newRow("import scoping")
3143 << testFileUrl("jsimport/testImportScoping.qml")
3146 << (QStringList() << QLatin1String("componentError"))
3147 << (QVariantList() << QVariant(5));
3149 QTest::newRow("parent scope shouldn't be inherited by import with imports")
3150 << testFileUrl("jsimportfail/failOne.qml")
3152 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
3153 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3154 << (QVariantList() << QVariant(QString()));
3156 QTest::newRow("javascript imports in an import should be private to the import scope")
3157 << testFileUrl("jsimportfail/failTwo.qml")
3159 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
3160 << (QStringList() << QLatin1String("importScriptFunctionValue"))
3161 << (QVariantList() << QVariant(QString()));
3163 QTest::newRow("module imports in an import should be private to the import scope")
3164 << testFileUrl("jsimportfail/failThree.qml")
3166 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
3167 << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
3168 << (QVariantList() << QVariant(false));
3170 QTest::newRow("typenames in an import should be private to the import scope")
3171 << testFileUrl("jsimportfail/failFour.qml")
3173 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
3174 << (QStringList() << QLatin1String("importedModuleEnumValue"))
3175 << (QVariantList() << QVariant(0));
3177 QTest::newRow("import with imports has it's own activation scope")
3178 << testFileUrl("jsimportfail/failFive.qml")
3180 << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component"))
3181 << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
3182 << (QStringList() << QLatin1String("componentError"))
3183 << (QVariantList() << QVariant(0));
3185 QTest::newRow("import pragma library script")
3186 << testFileUrl("jsimport/testImportPragmaLibrary.qml")
3189 << (QStringList() << QLatin1String("testValue"))
3190 << (QVariantList() << QVariant(31));
3192 QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
3193 << testFileUrl("jsimportfail/testImportPragmaLibrary.qml")
3196 << (QStringList() << QLatin1String("testValue"))
3197 << (QVariantList() << QVariant(0));
3199 QTest::newRow("import pragma library script which has an import")
3200 << testFileUrl("jsimport/testImportPragmaLibraryWithImports.qml")
3203 << (QStringList() << QLatin1String("testValue"))
3204 << (QVariantList() << QVariant(55));
3206 QTest::newRow("import pragma library script which has a pragma library import")
3207 << testFileUrl("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
3210 << (QStringList() << QLatin1String("testValue"))
3211 << (QVariantList() << QVariant(18));
3214 void tst_qdeclarativeecmascript::importScripts()
3216 QFETCH(QUrl, testfile);
3217 QFETCH(QString, errorMessage);
3218 QFETCH(QStringList, warningMessages);
3219 QFETCH(QStringList, propertyNames);
3220 QFETCH(QVariantList, propertyValues);
3222 QDeclarativeComponent component(&engine, testfile);
3224 if (!errorMessage.isEmpty())
3225 QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
3227 if (warningMessages.size())
3228 foreach (const QString &warning, warningMessages)
3229 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
3231 QObject *object = component.create();
3232 if (!errorMessage.isEmpty()) {
3233 QVERIFY(object == 0);
3235 QVERIFY(object != 0);
3236 for (int i = 0; i < propertyNames.size(); ++i)
3237 QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
3242 void tst_qdeclarativeecmascript::scarceResources_other()
3244 /* These tests require knowledge of state, since we test values after
3245 performing signal or function invocation. */
3247 QPixmap origPixmap(100, 100);
3248 origPixmap.fill(Qt::blue);
3249 QString srp_name, expectedWarning;
3250 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3251 ScarceResourceObject *eo = 0;
3253 QObject *object = 0;
3255 /* property var semantics */
3257 // test that scarce resources are handled properly in signal invocation
3258 QDeclarativeComponent varComponentTen(&engine, testFileUrl("scarceResourceSignal.var.qml"));
3259 object = varComponentTen.create();
3260 srsc = object->findChild<QObject*>("srsc");
3262 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3263 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3264 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3265 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3266 QMetaObject::invokeMethod(srsc, "testSignal");
3267 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3268 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3269 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3270 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3271 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3272 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3273 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3274 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3275 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3276 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3279 // test that scarce resources are handled properly from js functions in qml files
3280 QDeclarativeComponent varComponentEleven(&engine, testFileUrl("scarceResourceFunction.var.qml"));
3281 object = varComponentEleven.create();
3282 QVERIFY(object != 0);
3283 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3284 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3285 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3286 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3287 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3288 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3289 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3290 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3291 QMetaObject::invokeMethod(object, "releaseScarceResource");
3292 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3293 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3294 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3295 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3298 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3299 QDeclarativeComponent varComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
3300 object = varComponentTwelve.create();
3301 QVERIFY(object != 0);
3302 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3303 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3304 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3305 srp_name = object->property("srp_name").toString();
3306 expectedWarning = varComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3307 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3308 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3309 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3310 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3311 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3312 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3315 // test that if an Item which has JS ownership but has a scarce resource property is garbage collected,
3316 // that the scarce resource is removed from the engine's list of scarce resources to clean up.
3317 QDeclarativeComponent varComponentThirteen(&engine, testFileUrl("scarceResourceObjectGc.var.qml"));
3318 object = varComponentThirteen.create();
3319 QVERIFY(object != 0);
3320 QVERIFY(!object->property("varProperty").isValid()); // not assigned yet
3321 QMetaObject::invokeMethod(object, "assignVarProperty");
3322 QVERIFY(ep->scarceResources.isEmpty()); // the scarce resource is a VME property.
3323 QMetaObject::invokeMethod(object, "deassignVarProperty");
3324 QVERIFY(ep->scarceResources.isEmpty()); // should still be empty; the resource should have been released on gc.
3327 /* property variant semantics */
3329 // test that scarce resources are handled properly in signal invocation
3330 QDeclarativeComponent variantComponentTen(&engine, testFileUrl("scarceResourceSignal.variant.qml"));
3331 object = variantComponentTen.create();
3332 QVERIFY(object != 0);
3333 srsc = object->findChild<QObject*>("srsc");
3335 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
3336 QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
3337 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3338 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3339 QMetaObject::invokeMethod(srsc, "testSignal");
3340 QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
3341 QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
3342 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3343 QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
3344 QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
3345 QVERIFY(srsc->property("scarceResourceCopy").isValid());
3346 QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3347 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3348 QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
3349 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3352 // test that scarce resources are handled properly from js functions in qml files
3353 QDeclarativeComponent variantComponentEleven(&engine, testFileUrl("scarceResourceFunction.variant.qml"));
3354 object = variantComponentEleven.create();
3355 QVERIFY(object != 0);
3356 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3357 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3358 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3359 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3360 QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
3361 QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
3362 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3363 QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
3364 QMetaObject::invokeMethod(object, "releaseScarceResource");
3365 QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
3366 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3367 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3368 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3371 // test that if an exception occurs while invoking js function from cpp, that the resources are released.
3372 QDeclarativeComponent variantComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.variant.qml"));
3373 object = variantComponentTwelve.create();
3374 QVERIFY(object != 0);
3375 QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
3376 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3377 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3378 srp_name = object->property("srp_name").toString();
3379 expectedWarning = variantComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
3380 QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
3381 QMetaObject::invokeMethod(object, "retrieveScarceResource");
3382 QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
3383 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3384 QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
3385 QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
3389 void tst_qdeclarativeecmascript::scarceResources_data()
3391 QTest::addColumn<QUrl>("qmlFile");
3392 QTest::addColumn<bool>("readDetachStatus");
3393 QTest::addColumn<bool>("expectedDetachStatus");
3394 QTest::addColumn<QStringList>("propertyNames");
3395 QTest::addColumn<QVariantList>("expectedValidity");
3396 QTest::addColumn<QVariantList>("expectedValues");
3397 QTest::addColumn<QStringList>("expectedErrors");
3399 QPixmap origPixmap(100, 100);
3400 origPixmap.fill(Qt::blue);
3402 /* property var semantics */
3404 // in the following three cases, the instance created from the component
3405 // has a property which is a copy of the scarce resource; hence, the
3406 // resource should NOT be detached prior to deletion of the object instance,
3407 // unless the resource is destroyed explicitly.
3408 QTest::newRow("var: import scarce resource copy directly")
3409 << testFileUrl("scarceResourceCopy.var.qml")
3411 << false // won't be detached, because assigned to property and not explicitly released
3412 << (QStringList() << QLatin1String("scarceResourceCopy"))
3413 << (QList<QVariant>() << true)
3414 << (QList<QVariant>() << origPixmap)
3417 QTest::newRow("var: import scarce resource copy from JS")
3418 << testFileUrl("scarceResourceCopyFromJs.var.qml")
3420 << false // won't be detached, because assigned to property and not explicitly released
3421 << (QStringList() << QLatin1String("scarceResourceCopy"))
3422 << (QList<QVariant>() << true)
3423 << (QList<QVariant>() << origPixmap)
3426 QTest::newRow("var: import released scarce resource copy from JS")
3427 << testFileUrl("scarceResourceDestroyedCopy.var.qml")
3429 << true // explicitly released, so it will be detached
3430 << (QStringList() << QLatin1String("scarceResourceCopy"))
3431 << (QList<QVariant>() << false)
3432 << (QList<QVariant>() << QVariant())
3435 // in the following three cases, no other copy should exist in memory,
3436 // and so it should be detached (unless explicitly preserved).
3437 QTest::newRow("var: import auto-release SR from JS in binding side-effect")
3438 << testFileUrl("scarceResourceTest.var.qml")
3440 << true // auto released, so it will be detached
3441 << (QStringList() << QLatin1String("scarceResourceTest"))
3442 << (QList<QVariant>() << true)
3443 << (QList<QVariant>() << QVariant(100))
3445 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3446 << testFileUrl("scarceResourceTestPreserve.var.qml")
3448 << false // won't be detached because we explicitly preserve it
3449 << (QStringList() << QLatin1String("scarceResourceTest"))
3450 << (QList<QVariant>() << true)
3451 << (QList<QVariant>() << QVariant(100))
3453 QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
3454 << testFileUrl("scarceResourceTestMultiple.var.qml")
3456 << true // will be detached because all resources were released manually or automatically.
3457 << (QStringList() << QLatin1String("scarceResourceTest"))
3458 << (QList<QVariant>() << true)
3459 << (QList<QVariant>() << QVariant(100))
3462 // In the following three cases, test that scarce resources are handled
3463 // correctly for imports.
3464 QTest::newRow("var: import with no binding")
3465 << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
3466 << false // cannot check detach status.
3469 << QList<QVariant>()
3470 << QList<QVariant>()
3472 QTest::newRow("var: import with binding without explicit preserve")
3473 << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
3476 << (QStringList() << QLatin1String("scarceResourceCopy"))
3477 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3478 << (QList<QVariant>() << QVariant())
3480 QTest::newRow("var: import with explicit release after binding evaluation")
3481 << testFileUrl("scarceResourceCopyImport.var.qml")
3484 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3485 << (QList<QVariant>() << false << false << false << true) // since property var = JS object reference, by releasing the provider's resource, all handles are invalidated.
3486 << (QList<QVariant>() << QVariant() << QVariant() << QVariant() << QVariant(true))
3488 QTest::newRow("var: import with different js objects")
3489 << testFileUrl("scarceResourceCopyImportDifferent.var.qml")
3492 << (QStringList() << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
3493 << (QList<QVariant>() << false << true << true) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3494 << (QList<QVariant>() << QVariant() << QVariant(origPixmap) << QVariant(false))
3496 QTest::newRow("var: import with different js objects and explicit release")
3497 << testFileUrl("scarceResourceMultipleDifferentNoBinding.var.qml")
3500 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3501 << (QList<QVariant>() << true << false) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
3502 << (QList<QVariant>() << QVariant(origPixmap) << QVariant())
3504 QTest::newRow("var: import with same js objects and explicit release")
3505 << testFileUrl("scarceResourceMultipleSameNoBinding.var.qml")
3508 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3509 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3510 << (QList<QVariant>() << QVariant() << QVariant())
3512 QTest::newRow("var: binding with same js objects and explicit release")
3513 << testFileUrl("scarceResourceMultipleSameWithBinding.var.qml")
3516 << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
3517 << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
3518 << (QList<QVariant>() << QVariant() << QVariant())
3522 /* property variant semantics */
3524 // in the following three cases, the instance created from the component
3525 // has a property which is a copy of the scarce resource; hence, the
3526 // resource should NOT be detached prior to deletion of the object instance,
3527 // unless the resource is destroyed explicitly.
3528 QTest::newRow("variant: import scarce resource copy directly")
3529 << testFileUrl("scarceResourceCopy.variant.qml")
3531 << false // won't be detached, because assigned to property and not explicitly released
3532 << (QStringList() << QLatin1String("scarceResourceCopy"))
3533 << (QList<QVariant>() << true)
3534 << (QList<QVariant>() << origPixmap)
3537 QTest::newRow("variant: import scarce resource copy from JS")
3538 << testFileUrl("scarceResourceCopyFromJs.variant.qml")
3540 << false // won't be detached, because assigned to property and not explicitly released
3541 << (QStringList() << QLatin1String("scarceResourceCopy"))
3542 << (QList<QVariant>() << true)
3543 << (QList<QVariant>() << origPixmap)
3546 QTest::newRow("variant: import released scarce resource copy from JS")
3547 << testFileUrl("scarceResourceDestroyedCopy.variant.qml")
3549 << true // explicitly released, so it will be detached
3550 << (QStringList() << QLatin1String("scarceResourceCopy"))
3551 << (QList<QVariant>() << false)
3552 << (QList<QVariant>() << QVariant())
3555 // in the following three cases, no other copy should exist in memory,
3556 // and so it should be detached (unless explicitly preserved).
3557 QTest::newRow("variant: import auto-release SR from JS in binding side-effect")
3558 << testFileUrl("scarceResourceTest.variant.qml")
3560 << true // auto released, so it will be detached
3561 << (QStringList() << QLatin1String("scarceResourceTest"))
3562 << (QList<QVariant>() << true)
3563 << (QList<QVariant>() << QVariant(100))
3565 QTest::newRow("variant: import explicit-preserve SR from JS in binding side-effect")
3566 << testFileUrl("scarceResourceTestPreserve.variant.qml")
3568 << false // won't be detached because we explicitly preserve it
3569 << (QStringList() << QLatin1String("scarceResourceTest"))
3570 << (QList<QVariant>() << true)
3571 << (QList<QVariant>() << QVariant(100))
3573 QTest::newRow("variant: import multiple scarce resources")
3574 << testFileUrl("scarceResourceTestMultiple.variant.qml")
3576 << true // will be detached because all resources were released manually or automatically.
3577 << (QStringList() << QLatin1String("scarceResourceTest"))
3578 << (QList<QVariant>() << true)
3579 << (QList<QVariant>() << QVariant(100))
3582 // In the following three cases, test that scarce resources are handled
3583 // correctly for imports.
3584 QTest::newRow("variant: import with no binding")
3585 << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
3586 << false // cannot check detach status.
3589 << QList<QVariant>()
3590 << QList<QVariant>()
3592 QTest::newRow("variant: import with binding without explicit preserve")
3593 << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
3596 << (QStringList() << QLatin1String("scarceResourceCopy"))
3597 << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
3598 << (QList<QVariant>() << QVariant())
3600 QTest::newRow("variant: import with explicit release after binding evaluation")
3601 << testFileUrl("scarceResourceCopyImport.variant.qml")
3604 << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo"))
3605 << (QList<QVariant>() << true << true << false) // since property variant = variant copy, releasing the provider's resource does not invalidate previously assigned copies.
3606 << (QList<QVariant>() << origPixmap << origPixmap << QVariant())
3610 void tst_qdeclarativeecmascript::scarceResources()
3612 QFETCH(QUrl, qmlFile);
3613 QFETCH(bool, readDetachStatus);
3614 QFETCH(bool, expectedDetachStatus);
3615 QFETCH(QStringList, propertyNames);
3616 QFETCH(QVariantList, expectedValidity);
3617 QFETCH(QVariantList, expectedValues);
3618 QFETCH(QStringList, expectedErrors);
3620 QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
3621 ScarceResourceObject *eo = 0;
3622 QObject *object = 0;
3624 QDeclarativeComponent c(&engine, qmlFile);
3625 object = c.create();
3626 QVERIFY(object != 0);
3627 for (int i = 0; i < propertyNames.size(); ++i) {
3628 QString prop = propertyNames.at(i);
3629 bool validity = expectedValidity.at(i).toBool();
3630 QVariant value = expectedValues.at(i);
3632 QCOMPARE(object->property(prop.toLatin1().constData()).isValid(), validity);
3633 if (value.type() == QVariant::Int) {
3634 QCOMPARE(object->property(prop.toLatin1().constData()).toInt(), value.toInt());
3635 } else if (value.type() == QVariant::Pixmap) {
3636 QCOMPARE(object->property(prop.toLatin1().constData()).value<QPixmap>(), value.value<QPixmap>());
3640 if (readDetachStatus) {
3641 eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
3642 QCOMPARE(eo->scarceResourceIsDetached(), expectedDetachStatus);
3645 QVERIFY(ep->scarceResources.isEmpty());
3649 void tst_qdeclarativeecmascript::propertyChangeSlots()
3651 // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
3652 QDeclarativeComponent component(&engine, testFileUrl("changeslots/propertyChangeSlots.qml"));
3653 QObject *object = component.create();
3654 QVERIFY(object != 0);
3657 // ensure that invalid property names fail properly.
3658 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3659 QDeclarativeComponent e1(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.1.qml"));
3660 QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
3661 QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
3662 object = e1.create();
3663 QVERIFY(object == 0);
3666 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3667 QDeclarativeComponent e2(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.2.qml"));
3668 expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
3669 QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
3670 object = e2.create();
3671 QVERIFY(object == 0);
3674 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3675 QDeclarativeComponent e3(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.3.qml"));
3676 expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
3677 QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
3678 object = e3.create();
3679 QVERIFY(object == 0);
3682 QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
3683 QDeclarativeComponent e4(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.4.qml"));
3684 expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
3685 QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
3686 object = e4.create();
3687 QVERIFY(object == 0);
3691 void tst_qdeclarativeecmascript::propertyVar_data()
3693 QTest::addColumn<QUrl>("qmlFile");
3696 QTest::newRow("non-bindable object subproperty changed") << testFileUrl("propertyVar.1.qml");
3697 QTest::newRow("non-bindable object changed") << testFileUrl("propertyVar.2.qml");
3698 QTest::newRow("primitive changed") << testFileUrl("propertyVar.3.qml");
3699 QTest::newRow("javascript array modification") << testFileUrl("propertyVar.4.qml");
3700 QTest::newRow("javascript map modification") << testFileUrl("propertyVar.5.qml");
3701 QTest::newRow("javascript array assignment") << testFileUrl("propertyVar.6.qml");
3702 QTest::newRow("javascript map assignment") << testFileUrl("propertyVar.7.qml");
3703 QTest::newRow("literal property assignment") << testFileUrl("propertyVar.8.qml");
3704 QTest::newRow("qobject property assignment") << testFileUrl("propertyVar.9.qml");
3705 QTest::newRow("base class var property assignment") << testFileUrl("propertyVar.10.qml");
3708 void tst_qdeclarativeecmascript::propertyVar()
3710 QFETCH(QUrl, qmlFile);
3712 QDeclarativeComponent component(&engine, qmlFile);
3713 QObject *object = component.create();
3714 QVERIFY(object != 0);
3716 QCOMPARE(object->property("test").toBool(), true);
3721 // Tests that we can write QVariant values to var properties from C++
3722 void tst_qdeclarativeecmascript::propertyVarCpp()
3724 QObject *object = 0;
3726 // ensure that writing to and reading from a var property from cpp works as required.
3727 // Literal values stored in var properties can be read and written as QVariants
3728 // of a specific type, whereas object values are read as QVariantMaps.
3729 QDeclarativeComponent component(&engine, testFileUrl("propertyVarCpp.qml"));
3730 object = component.create();
3731 QVERIFY(object != 0);
3732 // assign int to property var that currently has int assigned
3733 QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
3734 QCOMPARE(object->property("varBound"), QVariant(15));
3735 QCOMPARE(object->property("intBound"), QVariant(15));
3736 QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
3737 QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
3738 // assign string to property var that current has bool assigned
3739 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
3740 QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
3741 QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
3742 QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
3743 // now enforce behaviour when accessing JavaScript objects from cpp.
3744 QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
3748 static void gc(QDeclarativeEngine &engine)
3750 engine.collectGarbage();
3751 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
3754 void tst_qdeclarativeecmascript::propertyVarOwnership()
3756 // Referenced JS objects are not collected
3758 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.qml"));
3759 QObject *object = component.create();
3760 QVERIFY(object != 0);
3761 QCOMPARE(object->property("test").toBool(), false);
3762 QMetaObject::invokeMethod(object, "runTest");
3763 QCOMPARE(object->property("test").toBool(), true);
3766 // Referenced JS objects are not collected
3768 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.2.qml"));
3769 QObject *object = component.create();
3770 QVERIFY(object != 0);
3771 QCOMPARE(object->property("test").toBool(), false);
3772 QMetaObject::invokeMethod(object, "runTest");
3773 QCOMPARE(object->property("test").toBool(), true);
3776 // Qt objects are not collected until they've been dereferenced
3778 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.3.qml"));
3779 QObject *object = component.create();
3780 QVERIFY(object != 0);
3782 QCOMPARE(object->property("test2").toBool(), false);
3783 QCOMPARE(object->property("test2").toBool(), false);
3785 QMetaObject::invokeMethod(object, "runTest");
3786 QCOMPARE(object->property("test1").toBool(), true);
3788 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3789 QVERIFY(!referencedObject.isNull());
3791 QVERIFY(!referencedObject.isNull());
3793 QMetaObject::invokeMethod(object, "runTest2");
3794 QCOMPARE(object->property("test2").toBool(), true);
3796 QVERIFY(referencedObject.isNull());
3800 // Self reference does not prevent Qt object collection
3802 QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.4.qml"));
3803 QObject *object = component.create();
3804 QVERIFY(object != 0);
3806 QCOMPARE(object->property("test").toBool(), true);
3808 QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
3809 QVERIFY(!referencedObject.isNull());
3811 QVERIFY(!referencedObject.isNull());
3813 QMetaObject::invokeMethod(object, "runTest");
3815 QVERIFY(referencedObject.isNull());
3821 void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
3823 // The childObject has a reference to a different QObject. We want to ensure
3824 // that the different item will not be cleaned up until required. IE, the childObject
3825 // has implicit ownership of the constructed QObject.
3826 QDeclarativeComponent component(&engine, testFileUrl("propertyVarImplicitOwnership.qml"));
3827 QObject *object = component.create();
3828 QVERIFY(object != 0);
3829 QMetaObject::invokeMethod(object, "assignCircular");
3830 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3831 QObject *rootObject = object->property("vp").value<QObject*>();
3832 QVERIFY(rootObject != 0);
3833 QObject *childObject = rootObject->findChild<QObject*>("text");
3834 QVERIFY(childObject != 0);
3835 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3836 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3837 QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
3838 QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
3839 QVERIFY(!qobjectGuard.isNull());
3840 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3841 QVERIFY(!qobjectGuard.isNull());
3842 QMetaObject::invokeMethod(object, "deassignCircular");
3843 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3844 QVERIFY(qobjectGuard.isNull()); // should have been collected now.
3848 void tst_qdeclarativeecmascript::propertyVarReparent()
3850 // ensure that nothing breaks if we re-parent objects
3851 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
3852 QObject *object = component.create();
3853 QVERIFY(object != 0);
3854 QMetaObject::invokeMethod(object, "assignVarProp");
3855 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3856 QObject *rect = object->property("vp").value<QObject*>();
3857 QObject *text = rect->findChild<QObject*>("textOne");
3858 QObject *text2 = rect->findChild<QObject*>("textTwo");
3859 QWeakPointer<QObject> rectGuard(rect);
3860 QWeakPointer<QObject> textGuard(text);
3861 QWeakPointer<QObject> text2Guard(text2);
3862 QVERIFY(!rectGuard.isNull());
3863 QVERIFY(!textGuard.isNull());
3864 QVERIFY(!text2Guard.isNull());
3865 QCOMPARE(text->property("textCanary").toInt(), 11);
3866 QCOMPARE(text2->property("textCanary").toInt(), 12);
3867 // now construct an image which we will reparent.
3868 QMetaObject::invokeMethod(text2, "constructQObject");
3869 QObject *image = text2->property("vp").value<QObject*>();
3870 QWeakPointer<QObject> imageGuard(image);
3871 QVERIFY(!imageGuard.isNull());
3872 QCOMPARE(image->property("imageCanary").toInt(), 13);
3873 // now reparent the "Image" object (currently, it has JS ownership)
3874 image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
3875 QMetaObject::invokeMethod(text2, "deassignVp");
3876 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3877 QCOMPARE(text->property("textCanary").toInt(), 11);
3878 QCOMPARE(text2->property("textCanary").toInt(), 22);
3879 QVERIFY(!imageGuard.isNull()); // should still be alive.
3880 QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
3881 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3882 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3883 QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
3887 void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
3889 // sometimes reparenting can cause problems
3890 // (eg, if the ctxt is collected, varproperties are no longer available)
3891 // this test ensures that no crash occurs in that situation.
3892 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
3893 QObject *object = component.create();
3894 QVERIFY(object != 0);
3895 QMetaObject::invokeMethod(object, "assignVarProp");
3896 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3897 QObject *rect = object->property("vp").value<QObject*>();
3898 QObject *text = rect->findChild<QObject*>("textOne");
3899 QObject *text2 = rect->findChild<QObject*>("textTwo");
3900 QWeakPointer<QObject> rectGuard(rect);
3901 QWeakPointer<QObject> textGuard(text);
3902 QWeakPointer<QObject> text2Guard(text2);
3903 QVERIFY(!rectGuard.isNull());
3904 QVERIFY(!textGuard.isNull());
3905 QVERIFY(!text2Guard.isNull());
3906 QCOMPARE(text->property("textCanary").toInt(), 11);
3907 QCOMPARE(text2->property("textCanary").toInt(), 12);
3908 // now construct an image which we will reparent.
3909 QMetaObject::invokeMethod(text2, "constructQObject");
3910 QObject *image = text2->property("vp").value<QObject*>();
3911 QWeakPointer<QObject> imageGuard(image);
3912 QVERIFY(!imageGuard.isNull());
3913 QCOMPARE(image->property("imageCanary").toInt(), 13);
3914 // now reparent the "Image" object (currently, it has JS ownership)
3915 image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
3916 QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
3917 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3918 QVERIFY(!imageGuard.isNull()); // should still be alive.
3919 QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
3921 QVERIFY(imageGuard.isNull()); // should now be dead.
3924 void tst_qdeclarativeecmascript::propertyVarCircular()
3926 // enforce behaviour regarding circular references - ensure qdvmemo deletion.
3927 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.qml"));
3928 QObject *object = component.create();
3929 QVERIFY(object != 0);
3930 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3931 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3932 QCOMPARE(object->property("canaryInt"), QVariant(5));
3933 QVariant canaryResourceVariant = object->property("canaryResource");
3934 QVERIFY(canaryResourceVariant.isValid());
3935 QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
3936 canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
3937 QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
3938 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3939 QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
3940 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
3941 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3942 QCOMPARE(object->property("canaryInt"), QVariant(2));
3943 QCOMPARE(object->property("canaryResource"), QVariant(1));
3944 QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
3948 void tst_qdeclarativeecmascript::propertyVarCircular2()
3950 // track deletion of JS-owned parent item with Cpp-owned child
3951 // where the child has a var property referencing its parent.
3952 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
3953 QObject *object = component.create();
3954 QVERIFY(object != 0);
3955 QMetaObject::invokeMethod(object, "assignCircular");
3956 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3957 QObject *rootObject = object->property("vp").value<QObject*>();
3958 QVERIFY(rootObject != 0);
3959 QObject *childObject = rootObject->findChild<QObject*>("text");
3960 QVERIFY(childObject != 0);
3961 QWeakPointer<QObject> rootObjectTracker(rootObject);
3962 QVERIFY(!rootObjectTracker.isNull());
3963 QWeakPointer<QObject> childObjectTracker(childObject);
3964 QVERIFY(!childObjectTracker.isNull());
3966 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
3967 QCOMPARE(childObject->property("textCanary").toInt(), 10);
3968 QMetaObject::invokeMethod(object, "deassignCircular");
3969 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3970 QVERIFY(rootObjectTracker.isNull()); // should have been collected
3971 QVERIFY(childObjectTracker.isNull()); // should have been collected
3975 void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
3977 *(int*)(parameter) += 1;
3978 qPersistentDispose(object);
3981 void tst_qdeclarativeecmascript::propertyVarInheritance()
3983 int propertyVarWeakRefCallbackCount = 0;
3985 // enforce behaviour regarding element inheritance - ensure handle disposal.
3986 // The particular component under test here has a chain of references.
3987 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.inherit.qml"));
3988 QObject *object = component.create();
3989 QVERIFY(object != 0);
3990 QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
3991 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
3992 // we want to be able to track when the varProperties array of the last metaobject is disposed
3993 QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
3994 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*>();
3995 QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
3996 QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
3997 v8::Persistent<v8::Value> icoCanaryHandle;
3998 v8::Persistent<v8::Value> ccoCanaryHandle;
4001 // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
4002 // public function which can return us a handle to something in the varProperties array.
4003 icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(ico5->metaObject()->indexOfProperty("circ")));
4004 ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(cco5->metaObject()->indexOfProperty("circ")));
4005 // we make them weak and invoke the gc, but we should not hit the weak-callback yet
4006 // as the varproperties array of each vmemo still references the resource.
4007 icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4008 ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4010 QVERIFY(propertyVarWeakRefCallbackCount == 0);
4012 // now we deassign the var prop, which should trigger collection of item subtrees.
4013 QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
4014 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
4015 // ensure that there are only weak handles to the underlying varProperties array remaining.
4017 QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
4019 // since there are no parent vmemo's to keep implicit references alive, and the only handles
4020 // to what remains are weak, all varProperties arrays must have been collected.
4023 void tst_qdeclarativeecmascript::propertyVarInheritance2()
4025 int propertyVarWeakRefCallbackCount = 0;
4027 // The particular component under test here does NOT have a chain of references; the
4028 // only link between rootObject and childObject is that rootObject is the parent of childObject.
4029 QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
4030 QObject *object = component.create();
4031 QVERIFY(object != 0);
4032 QMetaObject::invokeMethod(object, "assignCircular");
4033 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
4034 QObject *rootObject = object->property("vp").value<QObject*>();
4035 QVERIFY(rootObject != 0);
4036 QObject *childObject = rootObject->findChild<QObject*>("text");
4037 QVERIFY(childObject != 0);
4038 QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
4039 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4040 v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
4043 propertyVarWeakRefCallbackCount = 0; // reset callback count.
4044 childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(childObject->metaObject()->indexOfProperty("vp")));
4045 childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
4047 QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
4048 QCOMPARE(childObject->property("vp").value<QObject*>(), rootObject);
4049 QCOMPARE(childObject->property("textCanary").toInt(), 10);
4051 QMetaObject::invokeMethod(object, "deassignCircular");
4052 QCoreApplication::processEvents(QEventLoop::DeferredDeletion); // process deleteLater() events from QV8QObjectWrapper.
4053 QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
4057 // Ensure that QObject type conversion works on binding assignment
4058 void tst_qdeclarativeecmascript::elementAssign()
4060 QDeclarativeComponent component(&engine, testFileUrl("elementAssign.qml"));
4062 QObject *object = component.create();
4063 QVERIFY(object != 0);
4065 QCOMPARE(object->property("test").toBool(), true);
4071 void tst_qdeclarativeecmascript::objectPassThroughSignals()
4073 QDeclarativeComponent component(&engine, testFileUrl("objectsPassThroughSignals.qml"));
4075 QObject *object = component.create();
4076 QVERIFY(object != 0);
4078 QCOMPARE(object->property("test").toBool(), true);
4084 void tst_qdeclarativeecmascript::objectConversion()
4086 QDeclarativeComponent component(&engine, testFileUrl("objectConversion.qml"));
4088 QObject *object = component.create();
4089 QVERIFY(object != 0);
4091 QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
4092 QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
4099 void tst_qdeclarativeecmascript::booleanConversion()
4101 QDeclarativeComponent component(&engine, testFileUrl("booleanConversion.qml"));
4103 QObject *object = component.create();
4104 QVERIFY(object != 0);
4106 QCOMPARE(object->property("test_true1").toBool(), true);
4107 QCOMPARE(object->property("test_true2").toBool(), true);
4108 QCOMPARE(object->property("test_true3").toBool(), true);
4109 QCOMPARE(object->property("test_true4").toBool(), true);
4110 QCOMPARE(object->property("test_true5").toBool(), true);
4112 QCOMPARE(object->property("test_false1").toBool(), false);
4113 QCOMPARE(object->property("test_false2").toBool(), false);
4114 QCOMPARE(object->property("test_false3").toBool(), false);
4119 void tst_qdeclarativeecmascript::handleReferenceManagement()
4124 // Linear QObject reference
4125 QDeclarativeEngine hrmEngine;
4126 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.1.qml"));
4127 QObject *object = component.create();
4128 QVERIFY(object != 0);
4129 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4130 cro->setEngine(&hrmEngine);
4131 cro->setDtorCount(&dtorCount);
4132 QMetaObject::invokeMethod(object, "createReference");
4134 QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
4136 hrmEngine.collectGarbage();
4137 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4138 QCOMPARE(dtorCount, 3);
4143 // Circular QObject reference
4144 QDeclarativeEngine hrmEngine;
4145 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.2.qml"));
4146 QObject *object = component.create();
4147 QVERIFY(object != 0);
4148 CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
4149 cro->setEngine(&hrmEngine);
4150 cro->setDtorCount(&dtorCount);
4151 QMetaObject::invokeMethod(object, "circularReference");
4153 QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
4155 hrmEngine.collectGarbage();
4156 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4157 QCOMPARE(dtorCount, 3);
4162 // Linear handle reference
4163 QDeclarativeEngine hrmEngine;
4164 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.1.qml"));
4165 QObject *object = component.create();
4166 QVERIFY(object != 0);
4167 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4169 crh->setEngine(&hrmEngine);
4170 crh->setDtorCount(&dtorCount);
4171 QMetaObject::invokeMethod(object, "createReference");
4172 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4173 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4174 QVERIFY(first != 0);
4175 QVERIFY(second != 0);
4176 first->addReference(QDeclarativeData::get(second)->v8object); // create reference
4177 // now we have to reparent second and make second owned by JS.
4178 second->setParent(0);
4179 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4181 QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
4183 hrmEngine.collectGarbage();
4184 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4185 QCOMPARE(dtorCount, 3);
4190 // Circular handle reference
4191 QDeclarativeEngine hrmEngine;
4192 QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.2.qml"));
4193 QObject *object = component.create();
4194 QVERIFY(object != 0);
4195 CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
4197 crh->setEngine(&hrmEngine);
4198 crh->setDtorCount(&dtorCount);
4199 QMetaObject::invokeMethod(object, "circularReference");
4200 CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
4201 CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
4202 QVERIFY(first != 0);
4203 QVERIFY(second != 0);
4204 first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
4205 second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
4206 // now we have to reparent and change ownership.
4207 first->setParent(0);
4208 second->setParent(0);
4209 QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
4210 QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
4212 QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
4214 hrmEngine.collectGarbage();
4215 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4216 QCOMPARE(dtorCount, 3);
4221 // multiple engine interaction - linear reference
4222 QDeclarativeEngine hrmEngine1;
4223 QDeclarativeEngine hrmEngine2;
4224 QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4225 QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4226 QObject *object1 = component1.create();
4227 QObject *object2 = component2.create();
4228 QVERIFY(object1 != 0);
4229 QVERIFY(object2 != 0);
4230 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4231 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4234 crh1->setEngine(&hrmEngine1);
4235 crh2->setEngine(&hrmEngine2);
4236 crh1->setDtorCount(&dtorCount);
4237 crh2->setDtorCount(&dtorCount);
4238 QMetaObject::invokeMethod(object1, "createReference");
4239 QMetaObject::invokeMethod(object2, "createReference");
4240 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4241 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4242 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4243 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4244 QVERIFY(first1 != 0);
4245 QVERIFY(second1 != 0);
4246 QVERIFY(first2 != 0);
4247 QVERIFY(second2 != 0);
4248 first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
4249 // now we have to reparent second2 and make second2 owned by JS.
4250 second2->setParent(0);
4251 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4253 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4254 QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
4257 hrmEngine1.collectGarbage();
4258 hrmEngine2.collectGarbage();
4259 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4260 QCOMPARE(dtorCount, 6);
4265 // multiple engine interaction - circular reference
4266 QDeclarativeEngine hrmEngine1;
4267 QDeclarativeEngine hrmEngine2;
4268 QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4269 QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4270 QObject *object1 = component1.create();
4271 QObject *object2 = component2.create();
4272 QVERIFY(object1 != 0);
4273 QVERIFY(object2 != 0);
4274 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4275 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4278 crh1->setEngine(&hrmEngine1);
4279 crh2->setEngine(&hrmEngine2);
4280 crh1->setDtorCount(&dtorCount);
4281 crh2->setDtorCount(&dtorCount);
4282 QMetaObject::invokeMethod(object1, "createReference");
4283 QMetaObject::invokeMethod(object2, "createReference");
4284 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4285 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4286 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4287 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4288 QVERIFY(first1 != 0);
4289 QVERIFY(second1 != 0);
4290 QVERIFY(first2 != 0);
4291 QVERIFY(second2 != 0);
4292 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4293 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4294 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4295 first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
4296 // now we have to reparent and change ownership to JS.
4297 first1->setParent(0);
4298 second1->setParent(0);
4299 first2->setParent(0);
4300 second2->setParent(0);
4301 QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
4302 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4303 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4304 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4306 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4307 QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
4310 hrmEngine1.collectGarbage();
4311 hrmEngine2.collectGarbage();
4312 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4313 QCOMPARE(dtorCount, 6);
4318 // multiple engine interaction - linear reference with engine deletion
4319 QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
4320 QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
4321 QDeclarativeComponent component1(hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
4322 QDeclarativeComponent component2(hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
4323 QObject *object1 = component1.create();
4324 QObject *object2 = component2.create();
4325 QVERIFY(object1 != 0);
4326 QVERIFY(object2 != 0);
4327 CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
4328 CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
4331 crh1->setEngine(hrmEngine1);
4332 crh2->setEngine(hrmEngine2);
4333 crh1->setDtorCount(&dtorCount);
4334 crh2->setDtorCount(&dtorCount);
4335 QMetaObject::invokeMethod(object1, "createReference");
4336 QMetaObject::invokeMethod(object2, "createReference");
4337 CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
4338 CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
4339 CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
4340 CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
4341 QVERIFY(first1 != 0);
4342 QVERIFY(second1 != 0);
4343 QVERIFY(first2 != 0);
4344 QVERIFY(second2 != 0);
4345 first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
4346 second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
4347 second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
4348 // now we have to reparent and change ownership to JS.
4349 first1->setParent(crh1);
4350 second1->setParent(0);
4351 first2->setParent(0);
4352 second2->setParent(0);
4353 QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
4354 QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
4355 QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
4357 QCOMPARE(dtorCount, 0);
4360 QCOMPARE(dtorCount, 0);
4363 hrmEngine1->collectGarbage();
4364 QCoreApplication::processEvents(QEventLoop::DeferredDeletion);
4365 QCOMPARE(dtorCount, 6);
4370 void tst_qdeclarativeecmascript::stringArg()
4372 QDeclarativeComponent component(&engine, testFileUrl("stringArg.qml"));
4373 QObject *object = component.create();
4374 QVERIFY(object != 0);
4375 QMetaObject::invokeMethod(object, "success");
4376 QVERIFY(object->property("returnValue").toBool());
4378 QString w1 = testFileUrl("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
4379 QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
4380 QMetaObject::invokeMethod(object, "failure");
4381 QVERIFY(object->property("returnValue").toBool());
4386 void tst_qdeclarativeecmascript::readonlyDeclaration()
4388 QDeclarativeComponent component(&engine, testFileUrl("readonlyDeclaration.qml"));
4390 QObject *object = component.create();
4391 QVERIFY(object != 0);
4393 QCOMPARE(object->property("test").toBool(), true);
4398 Q_DECLARE_METATYPE(QList<int>)
4399 Q_DECLARE_METATYPE(QList<qreal>)
4400 Q_DECLARE_METATYPE(QList<bool>)
4401 Q_DECLARE_METATYPE(QList<QString>)
4402 Q_DECLARE_METATYPE(QList<QUrl>)
4403 void tst_qdeclarativeecmascript::sequenceConversionRead()
4406 QUrl qmlFile = testFileUrl("sequenceConversion.read.qml");
4407 QDeclarativeComponent component(&engine, qmlFile);
4408 QObject *object = component.create();
4409 QVERIFY(object != 0);
4410 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4413 QMetaObject::invokeMethod(object, "readSequences");
4414 QList<int> intList; intList << 1 << 2 << 3 << 4;
4415 QCOMPARE(object->property("intListLength").toInt(), intList.length());
4416 QCOMPARE(object->property("intList").value<QList<int> >(), intList);
4417 QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
4418 QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
4419 QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
4420 QList<bool> boolList; boolList << true << false << true << false;
4421 QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
4422 QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
4423 QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4424 QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
4425 QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
4426 QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
4427 QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
4428 QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
4429 QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
4430 QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
4431 QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
4433 QMetaObject::invokeMethod(object, "readSequenceElements");
4434 QCOMPARE(object->property("intVal").toInt(), 2);
4435 QCOMPARE(object->property("qrealVal").toReal(), 2.2);
4436 QCOMPARE(object->property("boolVal").toBool(), false);
4437 QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
4438 QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
4439 QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
4441 QMetaObject::invokeMethod(object, "enumerateSequenceElements");
4442 QCOMPARE(object->property("enumerationMatches").toBool(), true);
4444 intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
4445 QDeclarativeProperty seqProp(seq, "intListProperty");
4446 QCOMPARE(seqProp.read().value<QList<int> >(), intList);
4447 QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
4448 QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
4450 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4451 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4457 QUrl qmlFile = testFileUrl("sequenceConversion.read.error.qml");
4458 QDeclarativeComponent component(&engine, qmlFile);
4459 QObject *object = component.create();
4460 QVERIFY(object != 0);
4461 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4464 // we haven't registered QList<QPoint> as a sequence type.
4465 QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4466 QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
4467 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4468 QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
4470 QMetaObject::invokeMethod(object, "performTest");
4472 // QList<QPoint> has not been registered as a sequence type.
4473 QCOMPARE(object->property("pointListLength").toInt(), 0);
4474 QVERIFY(!object->property("pointList").isValid());
4475 QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
4476 QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
4477 QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
4483 void tst_qdeclarativeecmascript::sequenceConversionWrite()
4486 QUrl qmlFile = testFileUrl("sequenceConversion.write.qml");
4487 QDeclarativeComponent component(&engine, qmlFile);
4488 QObject *object = component.create();
4489 QVERIFY(object != 0);
4490 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4493 QMetaObject::invokeMethod(object, "writeSequences");
4494 QCOMPARE(object->property("success").toBool(), true);
4496 QMetaObject::invokeMethod(object, "writeSequenceElements");
4497 QCOMPARE(object->property("success").toBool(), true);
4499 QMetaObject::invokeMethod(object, "writeOtherElements");
4500 QCOMPARE(object->property("success").toBool(), true);
4502 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4503 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4509 QUrl qmlFile = testFileUrl("sequenceConversion.write.error.qml");
4510 QDeclarativeComponent component(&engine, qmlFile);
4511 QObject *object = component.create();
4512 QVERIFY(object != 0);
4513 MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
4516 // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
4517 QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
4518 QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
4520 QMetaObject::invokeMethod(object, "performTest");
4522 QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
4523 QCOMPARE(seq->pointListProperty(), pointList);
4529 void tst_qdeclarativeecmascript::sequenceConversionArray()
4531 // ensure that in JS the returned sequences act just like normal JS Arrays.
4532 QUrl qmlFile = testFileUrl("sequenceConversion.array.qml");
4533 QDeclarativeComponent component(&engine, qmlFile);
4534 QObject *object = component.create();
4535 QVERIFY(object != 0);
4536 QMetaObject::invokeMethod(object, "indexedAccess");
4537 QVERIFY(object->property("success").toBool());
4538 QMetaObject::invokeMethod(object, "arrayOperations");
4539 QVERIFY(object->property("success").toBool());
4540 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4541 QVERIFY(object->property("success").toBool());
4542 QMetaObject::invokeMethod(object, "testReferenceDeletion");
4543 QCOMPARE(object->property("referenceDeletion").toBool(), true);
4547 void tst_qdeclarativeecmascript::sequenceConversionThreads()
4549 // ensure that sequence conversion operations work correctly in a worker thread
4550 // and that serialisation between the main and worker thread succeeds.
4551 QUrl qmlFile = testFileUrl("sequenceConversion.threads.qml");
4552 QDeclarativeComponent component(&engine, qmlFile);
4553 QObject *object = component.create();
4554 QVERIFY(object != 0);
4556 QMetaObject::invokeMethod(object, "testIntSequence");
4557 QTRY_VERIFY(object->property("finished").toBool());
4558 QVERIFY(object->property("success").toBool());
4560 QMetaObject::invokeMethod(object, "testQrealSequence");
4561 QTRY_VERIFY(object->property("finished").toBool());
4562 QVERIFY(object->property("success").toBool());
4564 QMetaObject::invokeMethod(object, "testBoolSequence");
4565 QTRY_VERIFY(object->property("finished").toBool());
4566 QVERIFY(object->property("success").toBool());
4568 QMetaObject::invokeMethod(object, "testStringSequence");
4569 QTRY_VERIFY(object->property("finished").toBool());
4570 QVERIFY(object->property("success").toBool());
4572 QMetaObject::invokeMethod(object, "testQStringSequence");
4573 QTRY_VERIFY(object->property("finished").toBool());
4574 QVERIFY(object->property("success").toBool());
4576 QMetaObject::invokeMethod(object, "testUrlSequence");
4577 QTRY_VERIFY(object->property("finished").toBool());
4578 QVERIFY(object->property("success").toBool());
4580 QMetaObject::invokeMethod(object, "testVariantSequence");
4581 QTRY_VERIFY(object->property("finished").toBool());
4582 QVERIFY(object->property("success").toBool());
4587 void tst_qdeclarativeecmascript::sequenceConversionBindings()
4590 QUrl qmlFile = testFileUrl("sequenceConversion.bindings.qml");
4591 QDeclarativeComponent component(&engine, qmlFile);
4592 QObject *object = component.create();
4593 QVERIFY(object != 0);
4594 QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
4595 QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
4596 QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
4597 QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
4598 QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
4603 QUrl qmlFile = testFileUrl("sequenceConversion.bindings.error.qml");
4604 QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
4605 QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
4606 QDeclarativeComponent component(&engine, qmlFile);
4607 QObject *object = component.create();
4608 QVERIFY(object != 0);
4613 void tst_qdeclarativeecmascript::sequenceConversionCopy()
4615 QUrl qmlFile = testFileUrl("sequenceConversion.copy.qml");
4616 QDeclarativeComponent component(&engine, qmlFile);
4617 QObject *object = component.create();
4618 QVERIFY(object != 0);
4619 QMetaObject::invokeMethod(object, "testCopySequences");
4620 QCOMPARE(object->property("success").toBool(), true);
4621 QMetaObject::invokeMethod(object, "readSequenceCopyElements");
4622 QCOMPARE(object->property("success").toBool(), true);
4623 QMetaObject::invokeMethod(object, "testEqualitySemantics");
4624 QCOMPARE(object->property("success").toBool(), true);
4628 void tst_qdeclarativeecmascript::assignSequenceTypes()
4630 // test binding array to sequence type property
4632 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.1.qml"));
4633 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4634 QVERIFY(object != 0);
4635 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4636 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4637 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4638 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4639 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4640 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4644 // test binding literal to sequence type property
4646 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.2.qml"));
4647 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4648 QVERIFY(object != 0);
4649 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4650 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4651 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4652 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4653 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4654 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4658 // test binding single value to sequence type property
4660 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.3.qml"));
4661 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4662 QVERIFY(object != 0);
4663 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4664 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4665 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4666 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4670 // test assigning array to sequence type property in js function
4672 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.4.qml"));
4673 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4674 QVERIFY(object != 0);
4675 QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
4676 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
4677 QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
4678 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
4679 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
4680 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
4684 // test assigning literal to sequence type property in js function
4686 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.5.qml"));
4687 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4688 QVERIFY(object != 0);
4689 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4690 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4691 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4692 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
4693 QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
4694 QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
4698 // test assigning single value to sequence type property in js function
4700 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.6.qml"));
4701 MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
4702 QVERIFY(object != 0);
4703 QCOMPARE(object->intListProperty(), (QList<int>() << 1));
4704 QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
4705 QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
4706 QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4710 // test QList<QUrl> literal assignment and binding assignment causes url resolution when required
4712 QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.7.qml"));
4713 QObject *object = component.create();
4714 QVERIFY(object != 0);
4715 MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
4716 MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
4717 MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
4718 MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
4719 MySequenceConversionObject *msco5 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco5"));
4720 QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0 && msco5 != 0);
4721 QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4722 QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
4723 QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4724 QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4725 QCOMPARE(msco5->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
4730 // Test that assigning a null object works
4731 // Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
4732 void tst_qdeclarativeecmascript::nullObjectBinding()
4734 QDeclarativeComponent component(&engine, testFileUrl("nullObjectBinding.qml"));
4736 QObject *object = component.create();
4737 QVERIFY(object != 0);
4739 QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
4744 // Test that bindings don't evaluate once the engine has been destroyed
4745 void tst_qdeclarativeecmascript::deletedEngine()
4747 QDeclarativeEngine *engine = new QDeclarativeEngine;
4748 QDeclarativeComponent component(engine, testFileUrl("deletedEngine.qml"));
4750 QObject *object = component.create();
4751 QVERIFY(object != 0);
4753 QCOMPARE(object->property("a").toInt(), 39);
4754 object->setProperty("b", QVariant(9));
4755 QCOMPARE(object->property("a").toInt(), 117);
4759 QCOMPARE(object->property("a").toInt(), 117);
4760 object->setProperty("b", QVariant(10));
4761 QCOMPARE(object->property("a").toInt(), 117);
4766 // Test the crashing part of QTBUG-9705
4767 void tst_qdeclarativeecmascript::libraryScriptAssert()
4769 QDeclarativeComponent component(&engine, testFileUrl("libraryScriptAssert.qml"));
4771 QObject *object = component.create();
4772 QVERIFY(object != 0);
4777 void tst_qdeclarativeecmascript::variantsAssignedUndefined()
4779 QDeclarativeComponent component(&engine, testFileUrl("variantsAssignedUndefined.qml"));
4781 QObject *object = component.create();
4782 QVERIFY(object != 0);
4784 QCOMPARE(object->property("test1").toInt(), 10);
4785 QCOMPARE(object->property("test2").toInt(), 11);
4787 object->setProperty("runTest", true);
4789 QCOMPARE(object->property("test1"), QVariant());
4790 QCOMPARE(object->property("test2"), QVariant());
4796 void tst_qdeclarativeecmascript::qtbug_9792()
4798 QDeclarativeComponent component(&engine, testFileUrl("qtbug_9792.qml"));
4800 QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
4802 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
4803 QVERIFY(object != 0);
4805 QTest::ignoreMessage(QtDebugMsg, "Hello world!");
4806 object->basicSignal();
4810 transientErrorsMsgCount = 0;
4811 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4813 object->basicSignal();
4815 qInstallMsgHandler(old);
4817 QCOMPARE(transientErrorsMsgCount, 0);
4822 // Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
4823 void tst_qdeclarativeecmascript::qtcreatorbug_1289()
4825 QDeclarativeComponent component(&engine, testFileUrl("qtcreatorbug_1289.qml"));
4827 QObject *o = component.create();
4830 QObject *nested = qvariant_cast<QObject *>(o->property("object"));
4831 QVERIFY(nested != 0);
4833 QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
4836 nested = qvariant_cast<QObject *>(o->property("object"));
4837 QVERIFY(nested == 0);
4839 // If the bug is present, the next line will crash
4843 // Test that we shut down without stupid warnings
4844 void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
4847 QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.qml"));
4849 QObject *o = component.create();
4851 transientErrorsMsgCount = 0;
4852 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4856 qInstallMsgHandler(old);
4858 QCOMPARE(transientErrorsMsgCount, 0);
4863 QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.2.qml"));
4865 QObject *o = component.create();
4867 transientErrorsMsgCount = 0;
4868 QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
4872 qInstallMsgHandler(old);
4874 QCOMPARE(transientErrorsMsgCount, 0);
4878 void tst_qdeclarativeecmascript::canAssignNullToQObject()
4881 QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.1.qml"));
4883 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4886 QVERIFY(o->objectProperty() != 0);
4888 o->setProperty("runTest", true);
4890 QVERIFY(o->objectProperty() == 0);
4896 QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.2.qml"));
4898 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4901 QVERIFY(o->objectProperty() == 0);
4907 void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
4909 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.1.qml"));
4911 QString url = component.url().toString();
4912 QString warning = url + ":4: Unable to assign a function to a property.";
4913 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4915 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4918 QVERIFY(!o->property("a").isValid());
4923 void tst_qdeclarativeecmascript::functionAssignment_fromJS()
4925 QFETCH(QString, triggerProperty);
4927 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
4928 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4930 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4932 QVERIFY(!o->property("a").isValid());
4934 o->setProperty("aNumber", QVariant(5));
4935 o->setProperty(triggerProperty.toUtf8().constData(), true);
4936 QCOMPARE(o->property("a"), QVariant(50));
4938 o->setProperty("aNumber", QVariant(10));
4939 QCOMPARE(o->property("a"), QVariant(100));
4944 void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
4946 QTest::addColumn<QString>("triggerProperty");
4948 QTest::newRow("assign to property") << "assignToProperty";
4949 QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
4951 QTest::newRow("assign to value type") << "assignToValueType";
4953 QTest::newRow("use 'this'") << "assignWithThis";
4954 QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
4957 void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
4959 QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
4960 QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
4962 MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
4964 QVERIFY(!o->property("a").isValid());
4966 o->setProperty("assignFuncWithoutReturn", true);
4967 QVERIFY(!o->property("a").isValid());
4969 QString url = component.url().toString();
4970 QString warning = url + ":67: Unable to assign QString to int";
4971 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4972 o->setProperty("assignWrongType", true);
4974 warning = url + ":71: Unable to assign QString to int";
4975 QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
4976 o->setProperty("assignWrongTypeToValueType", true);
4981 void tst_qdeclarativeecmascript::eval()
4983 QDeclarativeComponent component(&engine, testFileUrl("eval.qml"));
4985 QObject *o = component.create();
4988 QCOMPARE(o->property("test1").toBool(), true);
4989 QCOMPARE(o->property("test2").toBool(), true);
4990 QCOMPARE(o->property("test3").toBool(), true);
4991 QCOMPARE(o->property("test4").toBool(), true);
4992 QCOMPARE(o->property("test5").toBool(), true);
4997 void tst_qdeclarativeecmascript::function()
4999 QDeclarativeComponent component(&engine, testFileUrl("function.qml"));
5001 QObject *o = component.create();
5004 QCOMPARE(o->property("test1").toBool(), true);
5005 QCOMPARE(o->property("test2").toBool(), true);
5006 QCOMPARE(o->property("test3").toBool(), true);
5011 // Test the "Qt.include" method
5012 void tst_qdeclarativeecmascript::include()
5014 // Non-library relative include
5016 QDeclarativeComponent component(&engine, testFileUrl("include.qml"));
5017 QObject *o = component.create();
5020 QCOMPARE(o->property("test0").toInt(), 99);
5021 QCOMPARE(o->property("test1").toBool(), true);
5022 QCOMPARE(o->property("test2").toBool(), true);
5023 QCOMPARE(o->property("test2_1").toBool(), true);
5024 QCOMPARE(o->property("test3").toBool(), true);
5025 QCOMPARE(o->property("test3_1").toBool(), true);
5030 // Library relative include
5032 QDeclarativeComponent component(&engine, testFileUrl("include_shared.qml"));
5033 QObject *o = component.create();
5036 QCOMPARE(o->property("test0").toInt(), 99);
5037 QCOMPARE(o->property("test1").toBool(), true);
5038 QCOMPARE(o->property("test2").toBool(), true);
5039 QCOMPARE(o->property("test2_1").toBool(), true);
5040 QCOMPARE(o->property("test3").toBool(), true);
5041 QCOMPARE(o->property("test3_1").toBool(), true);
5048 QDeclarativeComponent component(&engine, testFileUrl("include_callback.qml"));
5049 QObject *o = component.create();
5052 QCOMPARE(o->property("test1").toBool(), true);
5053 QCOMPARE(o->property("test2").toBool(), true);
5054 QCOMPARE(o->property("test3").toBool(), true);
5055 QCOMPARE(o->property("test4").toBool(), true);
5056 QCOMPARE(o->property("test5").toBool(), true);
5057 QCOMPARE(o->property("test6").toBool(), true);
5062 // Including file with ".pragma library"
5064 QDeclarativeComponent component(&engine, testFileUrl("include_pragma.qml"));
5065 QObject *o = component.create();
5067 QCOMPARE(o->property("test1").toInt(), 100);
5074 TestHTTPServer server(8111);
5075 QVERIFY(server.isValid());
5076 server.serveDirectory(dataDirectory());
5078 QDeclarativeComponent component(&engine, testFileUrl("include_remote.qml"));
5079 QObject *o = component.create();
5082 QTRY_VERIFY(o->property("done").toBool() == true);
5083 QTRY_VERIFY(o->property("done2").toBool() == true);
5085 QCOMPARE(o->property("test1").toBool(), true);
5086 QCOMPARE(o->property("test2").toBool(), true);
5087 QCOMPARE(o->property("test3").toBool(), true);
5088 QCOMPARE(o->property("test4").toBool(), true);
5089 QCOMPARE(o->property("test5").toBool(), true);
5091 QCOMPARE(o->property("test6").toBool(), true);
5092 QCOMPARE(o->property("test7").toBool(), true);
5093 QCOMPARE(o->property("test8").toBool(), true);
5094 QCOMPARE(o->property("test9").toBool(), true);
5095 QCOMPARE(o->property("test10").toBool(), true);
5102 TestHTTPServer server(8111);
5103 QVERIFY(server.isValid());
5104 server.serveDirectory(dataDirectory());
5106 QDeclarativeComponent component(&engine, testFileUrl("include_remote_missing.qml"));
5107 QObject *o = component.create();
5110 QTRY_VERIFY(o->property("done").toBool() == true);
5112 QCOMPARE(o->property("test1").toBool(), true);
5113 QCOMPARE(o->property("test2").toBool(), true);
5114 QCOMPARE(o->property("test3").toBool(), true);
5120 void tst_qdeclarativeecmascript::signalHandlers()
5122 QDeclarativeComponent component(&engine, testFileUrl("signalHandlers.qml"));
5123 QObject *o = component.create();
5126 QVERIFY(o->property("count").toInt() == 0);
5127 QMetaObject::invokeMethod(o, "testSignalCall");
5128 QCOMPARE(o->property("count").toInt(), 1);
5130 QMetaObject::invokeMethod(o, "testSignalHandlerCall");
5131 QCOMPARE(o->property("count").toInt(), 1);
5132 QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
5134 QVERIFY(o->property("funcCount").toInt() == 0);
5135 QMetaObject::invokeMethod(o, "testSignalConnection");
5136 QCOMPARE(o->property("funcCount").toInt(), 1);
5138 QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
5139 QCOMPARE(o->property("funcCount").toInt(), 2);
5141 QMetaObject::invokeMethod(o, "testSignalDefined");
5142 QCOMPARE(o->property("definedResult").toBool(), true);
5144 QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
5145 QCOMPARE(o->property("definedHandlerResult").toBool(), true);
5150 void tst_qdeclarativeecmascript::qtbug_10696()
5152 QDeclarativeComponent component(&engine, testFileUrl("qtbug_10696.qml"));
5153 QObject *o = component.create();
5158 void tst_qdeclarativeecmascript::qtbug_11606()
5160 QDeclarativeComponent component(&engine, testFileUrl("qtbug_11606.qml"));
5161 QObject *o = component.create();
5163 QCOMPARE(o->property("test").toBool(), true);
5167 void tst_qdeclarativeecmascript::qtbug_11600()
5169 QDeclarativeComponent component(&engine, testFileUrl("qtbug_11600.qml"));
5170 QObject *o = component.create();
5172 QCOMPARE(o->property("test").toBool(), true);
5176 void tst_qdeclarativeecmascript::qtbug_21864()
5178 QDeclarativeComponent component(&engine, testFileUrl("qtbug_21864.qml"));
5179 QObject *o = component.create();
5181 QCOMPARE(o->property("test").toBool(), true);
5185 void tst_qdeclarativeecmascript::qobjectConnectionListExceptionHandling()
5188 QDeclarativeComponent component(&engine, testFileUrl("qobjectConnectionListExceptionHandling.qml"));
5189 QString warning = component.url().toString() + QLatin1String(":13: TypeError: Cannot read property 'undefined' of undefined");
5190 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5191 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5192 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5193 QObject *o = component.create();
5195 QCOMPARE(o->property("test").toBool(), true);
5199 // Reading and writing non-scriptable properties should fail
5200 void tst_qdeclarativeecmascript::nonscriptable()
5202 QDeclarativeComponent component(&engine, testFileUrl("nonscriptable.qml"));
5203 QObject *o = component.create();
5205 QCOMPARE(o->property("readOk").toBool(), true);
5206 QCOMPARE(o->property("writeOk").toBool(), true);
5210 // deleteLater() should not be callable from QML
5211 void tst_qdeclarativeecmascript::deleteLater()
5213 QDeclarativeComponent component(&engine, testFileUrl("deleteLater.qml"));
5214 QObject *o = component.create();
5216 QCOMPARE(o->property("test").toBool(), true);
5220 void tst_qdeclarativeecmascript::in()
5222 QDeclarativeComponent component(&engine, testFileUrl("in.qml"));
5223 QObject *o = component.create();
5225 QCOMPARE(o->property("test1").toBool(), true);
5226 QCOMPARE(o->property("test2").toBool(), true);
5230 void tst_qdeclarativeecmascript::typeOf()
5232 QDeclarativeComponent component(&engine, testFileUrl("typeOf.qml"));
5234 // These warnings should not happen once QTBUG-21864 is fixed
5235 QString warning1 = component.url().toString() + QLatin1String(":16: Error: Cannot assign [undefined] to QString");
5236 QString warning2 = component.url().resolved(QUrl("typeOf.js")).toString() + QLatin1String(":1: ReferenceError: Can't find variable: a");
5238 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5239 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5241 QObject *o = component.create();
5244 QEXPECT_FAIL("", "QTBUG-21864", Abort);
5245 QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
5246 QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
5247 QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
5248 QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
5249 QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
5250 QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
5251 QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
5252 QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
5253 QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
5258 void tst_qdeclarativeecmascript::sharedAttachedObject()
5260 QDeclarativeComponent component(&engine, testFileUrl("sharedAttachedObject.qml"));
5261 QObject *o = component.create();
5263 QCOMPARE(o->property("test1").toBool(), true);
5264 QCOMPARE(o->property("test2").toBool(), true);
5269 void tst_qdeclarativeecmascript::objectName()
5271 QDeclarativeComponent component(&engine, testFileUrl("objectName.qml"));
5272 QObject *o = component.create();
5275 QCOMPARE(o->property("test1").toString(), QString("hello"));
5276 QCOMPARE(o->property("test2").toString(), QString("ell"));
5278 o->setObjectName("world");
5280 QCOMPARE(o->property("test1").toString(), QString("world"));
5281 QCOMPARE(o->property("test2").toString(), QString("orl"));
5286 void tst_qdeclarativeecmascript::writeRemovesBinding()
5288 QDeclarativeComponent component(&engine, testFileUrl("writeRemovesBinding.qml"));
5289 QObject *o = component.create();
5292 QCOMPARE(o->property("test").toBool(), true);
5297 // Test bindings assigned to alias properties actually assign to the alias' target
5298 void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
5300 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsAssignCorrectly.qml"));
5301 QObject *o = component.create();
5304 QCOMPARE(o->property("test").toBool(), true);
5309 // Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
5310 void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
5313 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.qml"));
5314 QObject *o = component.create();
5317 QCOMPARE(o->property("test").toBool(), true);
5323 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.2.qml"));
5324 QObject *o = component.create();
5327 QCOMPARE(o->property("test").toBool(), true);
5333 QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.3.qml"));
5334 QObject *o = component.create();
5337 QCOMPARE(o->property("test").toBool(), true);
5343 // Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
5344 void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
5347 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.qml"));
5348 QObject *o = component.create();
5351 QCOMPARE(o->property("test").toBool(), true);
5357 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.2.qml"));
5358 QObject *o = component.create();
5361 QCOMPARE(o->property("test").toBool(), true);
5367 QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.3.qml"));
5368 QObject *o = component.create();
5371 QCOMPARE(o->property("test").toBool(), true);
5377 // Allow an alais to a composite element
5379 void tst_qdeclarativeecmascript::aliasToCompositeElement()
5381 QDeclarativeComponent component(&engine, testFileUrl("aliasToCompositeElement.qml"));
5383 QObject *object = component.create();
5384 QVERIFY(object != 0);
5389 void tst_qdeclarativeecmascript::qtbug_20344()
5391 QDeclarativeComponent component(&engine, testFileUrl("qtbug_20344.qml"));
5393 QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
5394 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5396 QObject *object = component.create();
5397 QVERIFY(object != 0);
5402 void tst_qdeclarativeecmascript::revisionErrors()
5405 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors.qml"));
5406 QString url = component.url().toString();
5408 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5409 QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
5410 QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
5412 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5413 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5414 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5415 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5416 QVERIFY(object != 0);
5420 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors2.qml"));
5421 QString url = component.url().toString();
5423 // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
5424 // method2, prop2 from MyRevisionedClass not available
5425 // method4, prop4 from MyRevisionedSubclass not available
5426 QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
5427 QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
5428 QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
5429 QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
5430 QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
5432 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5433 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5434 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5435 QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
5436 QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
5437 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5438 QVERIFY(object != 0);
5442 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors3.qml"));
5443 QString url = component.url().toString();
5445 // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
5446 // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
5447 QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
5448 QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
5449 QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
5450 QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
5451 QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
5452 QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
5453 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5454 QVERIFY(object != 0);
5459 void tst_qdeclarativeecmascript::revision()
5462 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision.qml"));
5463 QString url = component.url().toString();
5465 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5466 QVERIFY(object != 0);
5470 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision2.qml"));
5471 QString url = component.url().toString();
5473 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5474 QVERIFY(object != 0);
5478 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision3.qml"));
5479 QString url = component.url().toString();
5481 MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
5482 QVERIFY(object != 0);
5485 // Test that non-root classes can resolve revisioned methods
5487 QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision4.qml"));
5489 QObject *object = component.create();
5490 QVERIFY(object != 0);
5491 QCOMPARE(object->property("test").toReal(), 11.);
5496 void tst_qdeclarativeecmascript::realToInt()
5498 QDeclarativeComponent component(&engine, testFileUrl("realToInt.qml"));
5499 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5500 QVERIFY(object != 0);
5502 QMetaObject::invokeMethod(object, "test1");
5503 QCOMPARE(object->value(), int(4));
5504 QMetaObject::invokeMethod(object, "test2");
5505 QCOMPARE(object->value(), int(8));
5508 void tst_qdeclarativeecmascript::urlProperty()
5511 QDeclarativeComponent component(&engine, testFileUrl("urlProperty.1.qml"));
5512 MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
5513 QVERIFY(object != 0);
5514 object->setStringProperty("http://qt-project.org");
5515 QCOMPARE(object->urlProperty(), QUrl("http://qt-project.org/index.html"));
5516 QCOMPARE(object->intProperty(), 123);
5517 QCOMPARE(object->value(), 1);
5518 QCOMPARE(object->property("result").toBool(), true);
5522 void tst_qdeclarativeecmascript::dynamicString()
5524 QDeclarativeComponent component(&engine, testFileUrl("dynamicString.qml"));
5525 QObject *object = component.create();
5526 QVERIFY(object != 0);
5527 QCOMPARE(object->property("stringProperty").toString(),
5528 QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
5531 void tst_qdeclarativeecmascript::automaticSemicolon()
5533 QDeclarativeComponent component(&engine, testFileUrl("automaticSemicolon.qml"));
5534 QObject *object = component.create();
5535 QVERIFY(object != 0);
5538 void tst_qdeclarativeecmascript::unaryExpression()
5540 QDeclarativeComponent component(&engine, testFileUrl("unaryExpression.qml"));
5541 QObject *object = component.create();
5542 QVERIFY(object != 0);
5545 // Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
5546 void tst_qdeclarativeecmascript::doubleEvaluate()
5548 QDeclarativeComponent component(&engine, testFileUrl("doubleEvaluate.qml"));
5549 QObject *object = component.create();
5550 QVERIFY(object != 0);
5551 WriteCounter *wc = qobject_cast<WriteCounter *>(object);
5553 QCOMPARE(wc->count(), 1);
5555 wc->setProperty("x", 9);
5557 QCOMPARE(wc->count(), 2);
5562 static QStringList messages;
5563 static void captureMsgHandler(QtMsgType, const char *msg)
5565 messages.append(QLatin1String(msg));
5568 void tst_qdeclarativeecmascript::nonNotifyable()
5570 QV4Compiler::enableV4(false);
5571 QDeclarativeComponent component(&engine, testFileUrl("nonNotifyable.qml"));
5572 QV4Compiler::enableV4(true);
5574 QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
5576 QObject *object = component.create();
5577 qInstallMsgHandler(old);
5579 QVERIFY(object != 0);
5581 QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
5582 component.url().toString() +
5583 QLatin1String(":5 depends on non-NOTIFYable properties:");
5584 QString expected2 = QLatin1String(" ") +
5585 QLatin1String(object->metaObject()->className()) +
5586 QLatin1String("::value");
5588 QCOMPARE(messages.length(), 2);
5589 QCOMPARE(messages.at(0), expected1);
5590 QCOMPARE(messages.at(1), expected2);
5595 void tst_qdeclarativeecmascript::forInLoop()
5597 QDeclarativeComponent component(&engine, testFileUrl("forInLoop.qml"));
5598 QObject *object = component.create();
5599 QVERIFY(object != 0);
5601 QMetaObject::invokeMethod(object, "listProperty");
5603 QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
5604 QCOMPARE(r.size(), 3);
5605 QCOMPARE(r[0],QLatin1String("0=obj1"));
5606 QCOMPARE(r[1],QLatin1String("1=obj2"));
5607 QCOMPARE(r[2],QLatin1String("2=obj3"));
5609 //TODO: should test for in loop for other objects (such as QObjects) as well.
5614 // An object the binding depends on is deleted while the binding is still running
5615 void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
5617 QDeclarativeComponent component(&engine, testFileUrl("deleteWhileBindingRunning.qml"));
5618 QObject *object = component.create();
5619 QVERIFY(object != 0);
5623 void tst_qdeclarativeecmascript::qtbug_22679()
5626 object.setStringProperty(QLatin1String("Please work correctly"));
5627 engine.rootContext()->setContextProperty("contextProp", &object);
5629 QDeclarativeComponent component(&engine, testFileUrl("qtbug_22679.qml"));
5630 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5631 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5633 QObject *o = component.create();
5635 QCOMPARE(warningsSpy.count(), 0);
5639 void tst_qdeclarativeecmascript::qtbug_22843_data()
5641 QTest::addColumn<bool>("library");
5643 QTest::newRow("without .pragma library") << false;
5644 QTest::newRow("with .pragma library") << true;
5647 void tst_qdeclarativeecmascript::qtbug_22843()
5649 QFETCH(bool, library);
5651 QString fileName("qtbug_22843");
5653 fileName += QLatin1String(".library");
5654 fileName += QLatin1String(".qml");
5656 QDeclarativeComponent component(&engine, testFileUrl(fileName));
5657 QString url = component.url().toString();
5658 QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
5659 QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
5661 qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
5662 QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
5663 for (int x = 0; x < 3; ++x) {
5664 warningsSpy.clear();
5665 // For libraries, only the first import attempt should produce a
5666 // SyntaxError warning; subsequent component creation should not
5667 // attempt to reload the script.
5668 bool expectSyntaxError = !library || (x == 0);
5669 if (expectSyntaxError)
5670 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
5671 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
5672 QObject *object = component.create();
5673 QVERIFY(object != 0);
5674 QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
5680 void tst_qdeclarativeecmascript::switchStatement()
5683 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.1.qml"));
5684 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5685 QVERIFY(object != 0);
5687 // `object->value()' is the number of executed statements
5689 object->setStringProperty("A");
5690 QCOMPARE(object->value(), 5);
5692 object->setStringProperty("S");
5693 QCOMPARE(object->value(), 3);
5695 object->setStringProperty("D");
5696 QCOMPARE(object->value(), 3);
5698 object->setStringProperty("F");
5699 QCOMPARE(object->value(), 4);
5701 object->setStringProperty("something else");
5702 QCOMPARE(object->value(), 1);
5706 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.2.qml"));
5707 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5708 QVERIFY(object != 0);
5710 // `object->value()' is the number of executed statements
5712 object->setStringProperty("A");
5713 QCOMPARE(object->value(), 5);
5715 object->setStringProperty("S");
5716 QCOMPARE(object->value(), 3);
5718 object->setStringProperty("D");
5719 QCOMPARE(object->value(), 3);
5721 object->setStringProperty("F");
5722 QCOMPARE(object->value(), 3);
5724 object->setStringProperty("something else");
5725 QCOMPARE(object->value(), 4);
5729 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.3.qml"));
5730 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5731 QVERIFY(object != 0);
5733 // `object->value()' is the number of executed statements
5735 object->setStringProperty("A");
5736 QCOMPARE(object->value(), 5);
5738 object->setStringProperty("S");
5739 QCOMPARE(object->value(), 3);
5741 object->setStringProperty("D");
5742 QCOMPARE(object->value(), 3);
5744 object->setStringProperty("F");
5745 QCOMPARE(object->value(), 3);
5747 object->setStringProperty("something else");
5748 QCOMPARE(object->value(), 6);
5752 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.4.qml"));
5754 QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
5755 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5757 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5758 QVERIFY(object != 0);
5760 // `object->value()' is the number of executed statements
5762 object->setStringProperty("A");
5763 QCOMPARE(object->value(), 5);
5765 object->setStringProperty("S");
5766 QCOMPARE(object->value(), 3);
5768 object->setStringProperty("D");
5769 QCOMPARE(object->value(), 3);
5771 object->setStringProperty("F");
5772 QCOMPARE(object->value(), 3);
5774 QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
5776 object->setStringProperty("something else");
5780 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.5.qml"));
5781 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5782 QVERIFY(object != 0);
5784 // `object->value()' is the number of executed statements
5786 object->setStringProperty("A");
5787 QCOMPARE(object->value(), 1);
5789 object->setStringProperty("S");
5790 QCOMPARE(object->value(), 1);
5792 object->setStringProperty("D");
5793 QCOMPARE(object->value(), 1);
5795 object->setStringProperty("F");
5796 QCOMPARE(object->value(), 1);
5798 object->setStringProperty("something else");
5799 QCOMPARE(object->value(), 1);
5803 QDeclarativeComponent component(&engine, testFileUrl("switchStatement.6.qml"));
5804 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5805 QVERIFY(object != 0);
5807 // `object->value()' is the number of executed statements
5809 object->setStringProperty("A");
5810 QCOMPARE(object->value(), 123);
5812 object->setStringProperty("S");
5813 QCOMPARE(object->value(), 123);
5815 object->setStringProperty("D");
5816 QCOMPARE(object->value(), 321);
5818 object->setStringProperty("F");
5819 QCOMPARE(object->value(), 321);
5821 object->setStringProperty("something else");
5822 QCOMPARE(object->value(), 0);
5826 void tst_qdeclarativeecmascript::withStatement()
5829 QDeclarativeComponent component(&engine, testFileUrl("withStatement.1.qml"));
5830 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5831 QVERIFY(object != 0);
5833 QCOMPARE(object->value(), 123);
5837 void tst_qdeclarativeecmascript::tryStatement()
5840 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.1.qml"));
5841 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5842 QVERIFY(object != 0);
5844 QCOMPARE(object->value(), 123);
5848 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.2.qml"));
5849 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5850 QVERIFY(object != 0);
5852 QCOMPARE(object->value(), 321);
5856 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.3.qml"));
5857 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5858 QVERIFY(object != 0);
5860 QCOMPARE(object->value(), 1);
5864 QDeclarativeComponent component(&engine, testFileUrl("tryStatement.4.qml"));
5865 MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
5866 QVERIFY(object != 0);
5868 QCOMPARE(object->value(), 1);
5872 QTEST_MAIN(tst_qdeclarativeecmascript)
5874 #include "tst_qdeclarativeecmascript.moc"