aboutsummaryrefslogtreecommitdiffstats
path: root/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp')
-rw-r--r--tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp6097
1 files changed, 0 insertions, 6097 deletions
diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
deleted file mode 100644
index 6905252107..0000000000
--- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp
+++ /dev/null
@@ -1,6097 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/
-**
-** This file is part of the test suite of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this
-** file. Please review the following information to ensure the GNU Lesser
-** General Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-#include <QtTest/QtTest>
-#include <QtDeclarative/qdeclarativecomponent.h>
-#include <QtDeclarative/qdeclarativeengine.h>
-#include <QtDeclarative/qdeclarativeexpression.h>
-#include <QtDeclarative/qdeclarativecontext.h>
-#include <QtCore/qfileinfo.h>
-#include <QtCore/qdebug.h>
-#include <QtDeclarative/private/qdeclarativeguard_p.h>
-#include <QtCore/qdir.h>
-#include <QtCore/qnumeric.h>
-#include <private/qdeclarativeengine_p.h>
-#include <private/qdeclarativevmemetaobject_p.h>
-#include <private/qv4compiler_p.h>
-#include "testtypes.h"
-#include "testhttpserver.h"
-#include "../../shared/util.h"
-
-/*
-This test covers evaluation of ECMAScript expressions and bindings from within
-QML. This does not include static QML language issues.
-
-Static QML language issues are covered in qmllanguage
-*/
-
-class tst_qdeclarativeecmascript : public QDeclarativeDataTest
-{
- Q_OBJECT
-public:
- tst_qdeclarativeecmascript() {}
-
-private slots:
- void initTestCase();
- void assignBasicTypes();
- void idShortcutInvalidates();
- void boolPropertiesEvaluateAsBool();
- void methods();
- void signalAssignment();
- void bindingLoop();
- void basicExpressions();
- void basicExpressions_data();
- void arrayExpressions();
- void contextPropertiesTriggerReeval();
- void objectPropertiesTriggerReeval();
- void deferredProperties();
- void deferredPropertiesErrors();
- void extensionObjects();
- void overrideExtensionProperties();
- void attachedProperties();
- void enums();
- void valueTypeFunctions();
- void constantsOverrideBindings();
- void outerBindingOverridesInnerBinding();
- void aliasPropertyAndBinding();
- void aliasPropertyReset();
- void nonExistentAttachedObject();
- void scope();
- void importScope();
- void signalParameterTypes();
- void objectsCompareAsEqual();
- void dynamicCreation_data();
- void dynamicCreation();
- void dynamicDestruction();
- void objectToString();
- void objectHasOwnProperty();
- void selfDeletingBinding();
- void extendedObjectPropertyLookup();
- void extendedObjectPropertyLookup2();
- void scriptErrors();
- void functionErrors();
- void propertyAssignmentErrors();
- void signalTriggeredBindings();
- void listProperties();
- void exceptionClearsOnReeval();
- void exceptionSlotProducesWarning();
- void exceptionBindingProducesWarning();
- void compileInvalidBinding();
- void transientErrors();
- void shutdownErrors();
- void compositePropertyType();
- void jsObject();
- void undefinedResetsProperty();
- void listToVariant();
- void listAssignment();
- void multiEngineObject();
- void deletedObject();
- void attachedPropertyScope();
- void scriptConnect();
- void scriptDisconnect();
- void ownership();
- void cppOwnershipReturnValue();
- void ownershipCustomReturnValue();
- void qlistqobjectMethods();
- void strictlyEquals();
- void compiled();
- void numberAssignment();
- void propertySplicing();
- void signalWithUnknownTypes();
- void signalWithJSValueInVariant_data();
- void signalWithJSValueInVariant();
- void signalWithJSValueInVariant_twoEngines_data();
- void signalWithJSValueInVariant_twoEngines();
- void signalWithQJSValue_data();
- void signalWithQJSValue();
- void moduleApi_data();
- void moduleApi();
- void importScripts_data();
- void importScripts();
- void scarceResources();
- void scarceResources_data();
- void scarceResources_other();
- void propertyChangeSlots();
- void propertyVar_data();
- void propertyVar();
- void propertyVarCpp();
- void propertyVarOwnership();
- void propertyVarImplicitOwnership();
- void propertyVarReparent();
- void propertyVarReparentNullContext();
- void propertyVarCircular();
- void propertyVarCircular2();
- void propertyVarInheritance();
- void propertyVarInheritance2();
- void elementAssign();
- void objectPassThroughSignals();
- void objectConversion();
- void booleanConversion();
- void handleReferenceManagement();
- void stringArg();
- void readonlyDeclaration();
- void sequenceConversionRead();
- void sequenceConversionWrite();
- void sequenceConversionArray();
- void sequenceConversionIndexes();
- void sequenceConversionThreads();
- void sequenceConversionBindings();
- void sequenceConversionCopy();
- void assignSequenceTypes();
- void qtbug_22464();
- void qtbug_21580();
-
- void bug1();
- void bug2();
- void dynamicCreationCrash();
- void dynamicCreationOwnership();
- void regExpBug();
- void nullObjectBinding();
- void deletedEngine();
- void libraryScriptAssert();
- void variantsAssignedUndefined();
- void qtbug_9792();
- void qtcreatorbug_1289();
- void noSpuriousWarningsAtShutdown();
- void canAssignNullToQObject();
- void functionAssignment_fromBinding();
- void functionAssignment_fromJS();
- void functionAssignment_fromJS_data();
- void functionAssignmentfromJS_invalid();
- void eval();
- void function();
- void functionException();
- void qtbug_10696();
- void qtbug_11606();
- void qtbug_11600();
- void qtbug_21864();
- void qobjectConnectionListExceptionHandling();
- void nonscriptable();
- void deleteLater();
- void in();
- void typeOf();
- void sharedAttachedObject();
- void objectName();
- void writeRemovesBinding();
- void aliasBindingsAssignCorrectly();
- void aliasBindingsOverrideTarget();
- void aliasWritesOverrideBindings();
- void aliasToCompositeElement();
- void realToInt();
- void urlProperty();
- void urlPropertyWithEncoding();
- void urlListPropertyWithEncoding();
- void dynamicString();
- void include();
- void signalHandlers();
- void doubleEvaluate();
- void forInLoop();
- void nonNotifyable();
- void deleteWhileBindingRunning();
- void callQtInvokables();
- void invokableObjectArg();
- void invokableObjectRet();
- void qtbug_20344();
- void qtbug_22679();
- void qtbug_22843_data();
- void qtbug_22843();
- void rewriteMultiLineStrings();
- void revisionErrors();
- void revision();
- void invokableWithQObjectDerived();
-
- void automaticSemicolon();
- void unaryExpression();
- void switchStatement();
- void withStatement();
- void tryStatement();
-
-private:
- static void propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter);
- QDeclarativeEngine engine;
-};
-
-void tst_qdeclarativeecmascript::initTestCase()
-{
- QDeclarativeDataTest::initTestCase();
- registerTypes();
-}
-
-void tst_qdeclarativeecmascript::assignBasicTypes()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("assignBasicTypes.qml"));
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
- QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
- QCOMPARE(object->stringProperty(), QString("Hello World!"));
- QCOMPARE(object->uintProperty(), uint(10));
- QCOMPARE(object->intProperty(), -19);
- QCOMPARE((float)object->realProperty(), float(23.2));
- QCOMPARE((float)object->doubleProperty(), float(-19.75));
- QCOMPARE((float)object->floatProperty(), float(8.5));
- QCOMPARE(object->colorProperty(), QColor("red"));
- QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
- QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
- QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
- QCOMPARE(object->pointProperty(), QPoint(99,13));
- QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
- QCOMPARE(object->sizeProperty(), QSize(99, 13));
- QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
- QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
- QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
- QCOMPARE(object->boolProperty(), true);
- QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
- QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
- QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
- delete object;
- }
- {
- QDeclarativeComponent component(&engine, testFileUrl("assignBasicTypes.2.qml"));
- MyTypeObject *object = qobject_cast<MyTypeObject *>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->flagProperty(), MyTypeObject::FlagVal1 | MyTypeObject::FlagVal3);
- QCOMPARE(object->enumProperty(), MyTypeObject::EnumVal2);
- QCOMPARE(object->stringProperty(), QString("Hello World!"));
- QCOMPARE(object->uintProperty(), uint(10));
- QCOMPARE(object->intProperty(), -19);
- QCOMPARE((float)object->realProperty(), float(23.2));
- QCOMPARE((float)object->doubleProperty(), float(-19.75));
- QCOMPARE((float)object->floatProperty(), float(8.5));
- QCOMPARE(object->colorProperty(), QColor("red"));
- QCOMPARE(object->dateProperty(), QDate(1982, 11, 25));
- QCOMPARE(object->timeProperty(), QTime(11, 11, 32));
- QCOMPARE(object->dateTimeProperty(), QDateTime(QDate(2009, 5, 12), QTime(13, 22, 1)));
- QCOMPARE(object->pointProperty(), QPoint(99,13));
- QCOMPARE(object->pointFProperty(), QPointF(-10.1, 12.3));
- QCOMPARE(object->sizeProperty(), QSize(99, 13));
- QCOMPARE(object->sizeFProperty(), QSizeF(0.1, 0.2));
- QCOMPARE(object->rectProperty(), QRect(9, 7, 100, 200));
- QCOMPARE(object->rectFProperty(), QRectF(1000.1, -10.9, 400, 90.99));
- QCOMPARE(object->boolProperty(), true);
- QCOMPARE(object->variantProperty(), QVariant("Hello World!"));
- QCOMPARE(object->vectorProperty(), QVector3D(10, 1, 2.2));
- QCOMPARE(object->urlProperty(), component.url().resolved(QUrl("main.qml")));
- delete object;
- }
-}
-
-void tst_qdeclarativeecmascript::idShortcutInvalidates()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("idShortcutInvalidates.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
- QVERIFY(object->objectProperty() != 0);
- delete object->objectProperty();
- QVERIFY(object->objectProperty() == 0);
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("idShortcutInvalidates.1.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
- QVERIFY(object->objectProperty() != 0);
- delete object->objectProperty();
- QVERIFY(object->objectProperty() == 0);
- delete object;
- }
-}
-
-void tst_qdeclarativeecmascript::boolPropertiesEvaluateAsBool()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.1.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->stringProperty(), QLatin1String("pass"));
- delete object;
- }
- {
- QDeclarativeComponent component(&engine, testFileUrl("boolPropertiesEvaluateAsBool.2.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->stringProperty(), QLatin1String("pass"));
- delete object;
- }
-}
-
-void tst_qdeclarativeecmascript::signalAssignment()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("signalAssignment.1.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->string(), QString());
- emit object->basicSignal();
- QCOMPARE(object->string(), QString("pass"));
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("signalAssignment.2.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->string(), QString());
- emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
- QCOMPARE(object->string(), QString("pass 19 Hello world! 10.25 3 2"));
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("signalAssignment.3.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->string(), QString());
- emit object->unnamedArgumentSignal(19, 10.25, "Hello world!");
- QEXPECT_FAIL("", "QTBUG-24481", Continue);
- QCOMPARE(object->string(), QString("pass 19 Hello world!"));
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("signalAssignment.4.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->string(), QString());
- emit object->signalWithGlobalName(19);
- QCOMPARE(object->string(), QString("pass 5"));
- delete object;
- }
-}
-
-void tst_qdeclarativeecmascript::methods()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("methods.1.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->methodCalled(), false);
- QCOMPARE(object->methodIntCalled(), false);
- emit object->basicSignal();
- QCOMPARE(object->methodCalled(), true);
- QCOMPARE(object->methodIntCalled(), false);
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("methods.2.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->methodCalled(), false);
- QCOMPARE(object->methodIntCalled(), false);
- emit object->basicSignal();
- QCOMPARE(object->methodCalled(), false);
- QCOMPARE(object->methodIntCalled(), true);
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("methods.3.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- QCOMPARE(object->property("test").toInt(), 19);
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("methods.4.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- QCOMPARE(object->property("test").toInt(), 19);
- QCOMPARE(object->property("test2").toInt(), 17);
- QCOMPARE(object->property("test3").toInt(), 16);
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("methods.5.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- QCOMPARE(object->property("test").toInt(), 9);
- delete object;
- }
-}
-
-void tst_qdeclarativeecmascript::bindingLoop()
-{
- QDeclarativeComponent component(&engine, testFileUrl("bindingLoop.qml"));
- QString warning = component.url().toString() + ":5:9: QML MyQmlObject: Binding loop detected for property \"stringProperty\"";
- QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
- QObject *object = component.create();
- QVERIFY(object != 0);
- delete object;
-}
-
-void tst_qdeclarativeecmascript::basicExpressions_data()
-{
- QTest::addColumn<QString>("expression");
- QTest::addColumn<QVariant>("result");
- QTest::addColumn<bool>("nest");
-
- QTest::newRow("Syntax error (self test)") << "{console.log({'a':1'}.a)}" << QVariant() << false;
- QTest::newRow("Context property") << "a" << QVariant(1944) << false;
- QTest::newRow("Context property") << "a" << QVariant(1944) << true;
- QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << false;
- QTest::newRow("Context property expression") << "a * 2" << QVariant(3888) << true;
- QTest::newRow("Overridden context property") << "b" << QVariant("Milk") << false;
- QTest::newRow("Overridden context property") << "b" << QVariant("Cow") << true;
- QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << false;
- QTest::newRow("Object property") << "object.stringProperty" << QVariant("Object1") << true;
- QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object2") << false;
- QTest::newRow("Overridden object property") << "objectOverride.stringProperty" << QVariant("Object3") << true;
- QTest::newRow("Default object property") << "horseLegs" << QVariant(4) << false;
- QTest::newRow("Default object property") << "antLegs" << QVariant(6) << false;
- QTest::newRow("Default object property") << "emuLegs" << QVariant(2) << false;
- QTest::newRow("Nested default object property") << "horseLegs" << QVariant(4) << true;
- QTest::newRow("Nested default object property") << "antLegs" << QVariant(7) << true;
- QTest::newRow("Nested default object property") << "emuLegs" << QVariant(2) << true;
- QTest::newRow("Nested default object property") << "humanLegs" << QVariant(2) << true;
- QTest::newRow("Context property override default object property") << "millipedeLegs" << QVariant(100) << true;
-}
-
-void tst_qdeclarativeecmascript::basicExpressions()
-{
- QFETCH(QString, expression);
- QFETCH(QVariant, result);
- QFETCH(bool, nest);
-
- MyQmlObject object1;
- MyQmlObject object2;
- MyQmlObject object3;
- MyDefaultObject1 default1;
- MyDefaultObject3 default3;
- object1.setStringProperty("Object1");
- object2.setStringProperty("Object2");
- object3.setStringProperty("Object3");
-
- QDeclarativeContext context(engine.rootContext());
- QDeclarativeContext nestedContext(&context);
-
- context.setContextObject(&default1);
- context.setContextProperty("a", QVariant(1944));
- context.setContextProperty("b", QVariant("Milk"));
- context.setContextProperty("object", &object1);
- context.setContextProperty("objectOverride", &object2);
- nestedContext.setContextObject(&default3);
- nestedContext.setContextProperty("b", QVariant("Cow"));
- nestedContext.setContextProperty("objectOverride", &object3);
- nestedContext.setContextProperty("millipedeLegs", QVariant(100));
-
- MyExpression expr(nest?&nestedContext:&context, expression);
- QCOMPARE(expr.evaluate(), result);
-}
-
-void tst_qdeclarativeecmascript::arrayExpressions()
-{
- QObject obj1;
- QObject obj2;
- QObject obj3;
-
- QDeclarativeContext context(engine.rootContext());
- context.setContextProperty("a", &obj1);
- context.setContextProperty("b", &obj2);
- context.setContextProperty("c", &obj3);
-
- MyExpression expr(&context, "[a, b, c, 10]");
- QVariant result = expr.evaluate();
- QCOMPARE(result.userType(), qMetaTypeId<QList<QObject *> >());
- QList<QObject *> list = qvariant_cast<QList<QObject *> >(result);
- QCOMPARE(list.count(), 4);
- QCOMPARE(list.at(0), &obj1);
- QCOMPARE(list.at(1), &obj2);
- QCOMPARE(list.at(2), &obj3);
- QCOMPARE(list.at(3), (QObject *)0);
-}
-
-// Tests that modifying a context property will reevaluate expressions
-void tst_qdeclarativeecmascript::contextPropertiesTriggerReeval()
-{
- QDeclarativeContext context(engine.rootContext());
- MyQmlObject object1;
- MyQmlObject object2;
- MyQmlObject *object3 = new MyQmlObject;
-
- object1.setStringProperty("Hello");
- object2.setStringProperty("World");
-
- context.setContextProperty("testProp", QVariant(1));
- context.setContextProperty("testObj", &object1);
- context.setContextProperty("testObj2", object3);
-
- {
- MyExpression expr(&context, "testProp + 1");
- QCOMPARE(expr.changed, false);
- QCOMPARE(expr.evaluate(), QVariant(2));
-
- context.setContextProperty("testProp", QVariant(2));
- QCOMPARE(expr.changed, true);
- QCOMPARE(expr.evaluate(), QVariant(3));
- }
-
- {
- MyExpression expr(&context, "testProp + testProp + testProp");
- QCOMPARE(expr.changed, false);
- QCOMPARE(expr.evaluate(), QVariant(6));
-
- context.setContextProperty("testProp", QVariant(4));
- QCOMPARE(expr.changed, true);
- QCOMPARE(expr.evaluate(), QVariant(12));
- }
-
- {
- MyExpression expr(&context, "testObj.stringProperty");
- QCOMPARE(expr.changed, false);
- QCOMPARE(expr.evaluate(), QVariant("Hello"));
-
- context.setContextProperty("testObj", &object2);
- QCOMPARE(expr.changed, true);
- QCOMPARE(expr.evaluate(), QVariant("World"));
- }
-
- {
- MyExpression expr(&context, "testObj.stringProperty /**/");
- QCOMPARE(expr.changed, false);
- QCOMPARE(expr.evaluate(), QVariant("World"));
-
- context.setContextProperty("testObj", &object1);
- QCOMPARE(expr.changed, true);
- QCOMPARE(expr.evaluate(), QVariant("Hello"));
- }
-
- {
- MyExpression expr(&context, "testObj2");
- QCOMPARE(expr.changed, false);
- QCOMPARE(expr.evaluate(), QVariant::fromValue((QObject *)object3));
- }
-
- delete object3;
-}
-
-void tst_qdeclarativeecmascript::objectPropertiesTriggerReeval()
-{
- QDeclarativeContext context(engine.rootContext());
- MyQmlObject object1;
- MyQmlObject object2;
- MyQmlObject object3;
- context.setContextProperty("testObj", &object1);
-
- object1.setStringProperty(QLatin1String("Hello"));
- object2.setStringProperty(QLatin1String("Dog"));
- object3.setStringProperty(QLatin1String("Cat"));
-
- {
- MyExpression expr(&context, "testObj.stringProperty");
- QCOMPARE(expr.changed, false);
- QCOMPARE(expr.evaluate(), QVariant("Hello"));
-
- object1.setStringProperty(QLatin1String("World"));
- QCOMPARE(expr.changed, true);
- QCOMPARE(expr.evaluate(), QVariant("World"));
- }
-
- {
- MyExpression expr(&context, "testObj.objectProperty.stringProperty");
- QCOMPARE(expr.changed, false);
- QCOMPARE(expr.evaluate(), QVariant());
-
- object1.setObjectProperty(&object2);
- QCOMPARE(expr.changed, true);
- expr.changed = false;
- QCOMPARE(expr.evaluate(), QVariant("Dog"));
-
- object1.setObjectProperty(&object3);
- QCOMPARE(expr.changed, true);
- expr.changed = false;
- QCOMPARE(expr.evaluate(), QVariant("Cat"));
-
- object1.setObjectProperty(0);
- QCOMPARE(expr.changed, true);
- expr.changed = false;
- QCOMPARE(expr.evaluate(), QVariant());
-
- object1.setObjectProperty(&object3);
- QCOMPARE(expr.changed, true);
- expr.changed = false;
- QCOMPARE(expr.evaluate(), QVariant("Cat"));
-
- object3.setStringProperty("Donkey");
- QCOMPARE(expr.changed, true);
- expr.changed = false;
- QCOMPARE(expr.evaluate(), QVariant("Donkey"));
- }
-}
-
-void tst_qdeclarativeecmascript::deferredProperties()
-{
- QDeclarativeComponent component(&engine, testFileUrl("deferredProperties.qml"));
- MyDeferredObject *object =
- qobject_cast<MyDeferredObject *>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->value(), 0);
- QVERIFY(object->objectProperty() == 0);
- QVERIFY(object->objectProperty2() != 0);
- qmlExecuteDeferred(object);
- QCOMPARE(object->value(), 10);
- QVERIFY(object->objectProperty() != 0);
- MyQmlObject *qmlObject =
- qobject_cast<MyQmlObject *>(object->objectProperty());
- QVERIFY(qmlObject != 0);
- QCOMPARE(qmlObject->value(), 10);
- object->setValue(19);
- QCOMPARE(qmlObject->value(), 19);
-
- delete object;
-}
-
-// Check errors on deferred properties are correctly emitted
-void tst_qdeclarativeecmascript::deferredPropertiesErrors()
-{
- QDeclarativeComponent component(&engine, testFileUrl("deferredPropertiesErrors.qml"));
- MyDeferredObject *object =
- qobject_cast<MyDeferredObject *>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->value(), 0);
- QVERIFY(object->objectProperty() == 0);
- QVERIFY(object->objectProperty2() == 0);
-
- QString warning = component.url().toString() + ":6: Unable to assign [undefined] to QObject*";
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
-
- qmlExecuteDeferred(object);
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::extensionObjects()
-{
- QDeclarativeComponent component(&engine, testFileUrl("extensionObjects.qml"));
- MyExtendedObject *object =
- qobject_cast<MyExtendedObject *>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->baseProperty(), 13);
- QCOMPARE(object->coreProperty(), 9);
- object->setProperty("extendedProperty", QVariant(11));
- object->setProperty("baseExtendedProperty", QVariant(92));
- QCOMPARE(object->coreProperty(), 11);
- QCOMPARE(object->baseProperty(), 92);
-
- MyExtendedObject *nested = qobject_cast<MyExtendedObject*>(qvariant_cast<QObject *>(object->property("nested")));
- QVERIFY(nested);
- QCOMPARE(nested->baseProperty(), 13);
- QCOMPARE(nested->coreProperty(), 9);
- nested->setProperty("extendedProperty", QVariant(11));
- nested->setProperty("baseExtendedProperty", QVariant(92));
- QCOMPARE(nested->coreProperty(), 11);
- QCOMPARE(nested->baseProperty(), 92);
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::overrideExtensionProperties()
-{
- QDeclarativeComponent component(&engine, testFileUrl("extensionObjectsPropertyOverride.qml"));
- OverrideDefaultPropertyObject *object =
- qobject_cast<OverrideDefaultPropertyObject *>(component.create());
- QVERIFY(object != 0);
- QVERIFY(object->secondProperty() != 0);
- QVERIFY(object->firstProperty() == 0);
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::attachedProperties()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("attachedProperty.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- QCOMPARE(object->property("a").toInt(), 19);
- QCOMPARE(object->property("b").toInt(), 19);
- QCOMPARE(object->property("c").toInt(), 19);
- QCOMPARE(object->property("d").toInt(), 19);
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("attachedProperty.2.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- QCOMPARE(object->property("a").toInt(), 26);
- QCOMPARE(object->property("b").toInt(), 26);
- QCOMPARE(object->property("c").toInt(), 26);
- QCOMPARE(object->property("d").toInt(), 26);
-
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("writeAttachedProperty.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QMetaObject::invokeMethod(object, "writeValue2");
-
- MyQmlAttachedObject *attached =
- qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
- QVERIFY(attached != 0);
-
- QCOMPARE(attached->value2(), 9);
- delete object;
- }
-}
-
-void tst_qdeclarativeecmascript::enums()
-{
- // Existent enums
- {
- QDeclarativeComponent component(&engine, testFileUrl("enums.1.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("a").toInt(), 0);
- QCOMPARE(object->property("b").toInt(), 1);
- QCOMPARE(object->property("c").toInt(), 2);
- QCOMPARE(object->property("d").toInt(), 3);
- QCOMPARE(object->property("e").toInt(), 0);
- QCOMPARE(object->property("f").toInt(), 1);
- QCOMPARE(object->property("g").toInt(), 2);
- QCOMPARE(object->property("h").toInt(), 3);
- QCOMPARE(object->property("i").toInt(), 19);
- QCOMPARE(object->property("j").toInt(), 19);
-
- delete object;
- }
- // Non-existent enums
- {
- QDeclarativeComponent component(&engine, testFileUrl("enums.2.qml"));
-
- QString warning1 = component.url().toString() + ":5: Unable to assign [undefined] to int";
- QString warning2 = component.url().toString() + ":6: Unable to assign [undefined] to int";
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
- QCOMPARE(object->property("a").toInt(), 0);
- QCOMPARE(object->property("b").toInt(), 0);
-
- delete object;
- }
-}
-
-void tst_qdeclarativeecmascript::valueTypeFunctions()
-{
- QDeclarativeComponent component(&engine, testFileUrl("valueTypeFunctions.qml"));
- MyTypeObject *obj = qobject_cast<MyTypeObject*>(component.create());
- QVERIFY(obj != 0);
- QCOMPARE(obj->rectProperty(), QRect(0,0,100,100));
- QCOMPARE(obj->rectFProperty(), QRectF(0,0.5,100,99.5));
-
- delete obj;
-}
-
-/*
-Tests that writing a constant to a property with a binding on it disables the
-binding.
-*/
-void tst_qdeclarativeecmascript::constantsOverrideBindings()
-{
- // From ECMAScript
- {
- QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.1.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("c2").toInt(), 0);
- object->setProperty("c1", QVariant(9));
- QCOMPARE(object->property("c2").toInt(), 9);
-
- emit object->basicSignal();
-
- QCOMPARE(object->property("c2").toInt(), 13);
- object->setProperty("c1", QVariant(8));
- QCOMPARE(object->property("c2").toInt(), 13);
-
- delete object;
- }
-
- // During construction
- {
- QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.2.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("c1").toInt(), 0);
- QCOMPARE(object->property("c2").toInt(), 10);
- object->setProperty("c1", QVariant(9));
- QCOMPARE(object->property("c1").toInt(), 9);
- QCOMPARE(object->property("c2").toInt(), 10);
-
- delete object;
- }
-
-#if 0
- // From C++
- {
- QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.3.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("c2").toInt(), 0);
- object->setProperty("c1", QVariant(9));
- QCOMPARE(object->property("c2").toInt(), 9);
-
- object->setProperty("c2", QVariant(13));
- QCOMPARE(object->property("c2").toInt(), 13);
- object->setProperty("c1", QVariant(7));
- QCOMPARE(object->property("c1").toInt(), 7);
- QCOMPARE(object->property("c2").toInt(), 13);
-
- delete object;
- }
-#endif
-
- // Using an alias
- {
- QDeclarativeComponent component(&engine, testFileUrl("constantsOverrideBindings.4.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("c1").toInt(), 0);
- QCOMPARE(object->property("c3").toInt(), 10);
- object->setProperty("c1", QVariant(9));
- QCOMPARE(object->property("c1").toInt(), 9);
- QCOMPARE(object->property("c3").toInt(), 10);
-
- delete object;
- }
-}
-
-/*
-Tests that assigning a binding to a property that already has a binding causes
-the original binding to be disabled.
-*/
-void tst_qdeclarativeecmascript::outerBindingOverridesInnerBinding()
-{
- QDeclarativeComponent component(&engine,
- testFileUrl("outerBindingOverridesInnerBinding.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("c1").toInt(), 0);
- QCOMPARE(object->property("c2").toInt(), 0);
- QCOMPARE(object->property("c3").toInt(), 0);
-
- object->setProperty("c1", QVariant(9));
- QCOMPARE(object->property("c1").toInt(), 9);
- QCOMPARE(object->property("c2").toInt(), 0);
- QCOMPARE(object->property("c3").toInt(), 0);
-
- object->setProperty("c3", QVariant(8));
- QCOMPARE(object->property("c1").toInt(), 9);
- QCOMPARE(object->property("c2").toInt(), 8);
- QCOMPARE(object->property("c3").toInt(), 8);
-
- delete object;
-}
-
-/*
-Access a non-existent attached object.
-
-Tests for a regression where this used to crash.
-*/
-void tst_qdeclarativeecmascript::nonExistentAttachedObject()
-{
- QDeclarativeComponent component(&engine, testFileUrl("nonExistentAttachedObject.qml"));
-
- QString warning = component.url().toString() + ":4: Unable to assign [undefined] to QString";
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::scope()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("scope.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test1").toInt(), 1);
- QCOMPARE(object->property("test2").toInt(), 2);
- QCOMPARE(object->property("test3").toString(), QString("1Test"));
- QCOMPARE(object->property("test4").toString(), QString("2Test"));
- QCOMPARE(object->property("test5").toInt(), 1);
- QCOMPARE(object->property("test6").toInt(), 1);
- QCOMPARE(object->property("test7").toInt(), 2);
- QCOMPARE(object->property("test8").toInt(), 2);
- QCOMPARE(object->property("test9").toInt(), 1);
- QCOMPARE(object->property("test10").toInt(), 3);
-
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("scope.2.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test1").toInt(), 19);
- QCOMPARE(object->property("test2").toInt(), 19);
- QCOMPARE(object->property("test3").toInt(), 14);
- QCOMPARE(object->property("test4").toInt(), 14);
- QCOMPARE(object->property("test5").toInt(), 24);
- QCOMPARE(object->property("test6").toInt(), 24);
-
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("scope.3.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test1").toBool(), true);
- QCOMPARE(object->property("test2").toBool(), true);
- QCOMPARE(object->property("test3").toBool(), true);
-
- delete object;
- }
-
- // Signal argument scope
- {
- QDeclarativeComponent component(&engine, testFileUrl("scope.4.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toInt(), 0);
- QCOMPARE(object->property("test2").toString(), QString());
-
- emit object->argumentSignal(13, "Argument Scope", 9, MyQmlObject::EnumValue4, Qt::RightButton);
-
- QCOMPARE(object->property("test").toInt(), 13);
- QCOMPARE(object->property("test2").toString(), QString("Argument Scope"));
-
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("scope.5.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test1").toBool(), true);
- QCOMPARE(object->property("test2").toBool(), true);
-
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("scope.6.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
- }
-}
-
-// In 4.7, non-library javascript files that had no imports shared the imports of their
-// importing context
-void tst_qdeclarativeecmascript::importScope()
-{
- QDeclarativeComponent component(&engine, testFileUrl("importScope.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QCOMPARE(o->property("test").toInt(), 240);
-
- delete o;
-}
-
-/*
-Tests that "any" type passes through a synthesized signal parameter. This
-is essentially a test of QDeclarativeMetaType::copy()
-*/
-void tst_qdeclarativeecmascript::signalParameterTypes()
-{
- QDeclarativeComponent component(&engine, testFileUrl("signalParameterTypes.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- emit object->basicSignal();
-
- QCOMPARE(object->property("intProperty").toInt(), 10);
- QCOMPARE(object->property("realProperty").toReal(), 19.2);
- QVERIFY(object->property("colorProperty").value<QColor>() == QColor(255, 255, 0, 255));
- QVERIFY(object->property("variantProperty") == QVariant::fromValue(QColor(255, 0, 255, 255)));
- QVERIFY(object->property("enumProperty") == MyQmlObject::EnumValue3);
- QVERIFY(object->property("qtEnumProperty") == Qt::LeftButton);
-
- delete object;
-}
-
-/*
-Test that two JS objects for the same QObject compare as equal.
-*/
-void tst_qdeclarativeecmascript::objectsCompareAsEqual()
-{
- QDeclarativeComponent component(&engine, testFileUrl("objectsCompareAsEqual.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test1").toBool(), true);
- QCOMPARE(object->property("test2").toBool(), true);
- QCOMPARE(object->property("test3").toBool(), true);
- QCOMPARE(object->property("test4").toBool(), true);
- QCOMPARE(object->property("test5").toBool(), true);
-
- delete object;
-}
-
-/*
-Confirm bindings and alias properties can coexist.
-
-Tests for a regression where the binding would not reevaluate.
-*/
-void tst_qdeclarativeecmascript::aliasPropertyAndBinding()
-{
- QDeclarativeComponent component(&engine, testFileUrl("aliasPropertyAndBinding.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("c2").toInt(), 3);
- QCOMPARE(object->property("c3").toInt(), 3);
-
- object->setProperty("c2", QVariant(19));
-
- QCOMPARE(object->property("c2").toInt(), 19);
- QCOMPARE(object->property("c3").toInt(), 19);
-
- delete object;
-}
-
-/*
-Ensure that we can write undefined value to an alias property,
-and that the aliased property is reset correctly if possible.
-*/
-void tst_qdeclarativeecmascript::aliasPropertyReset()
-{
- QObject *object = 0;
-
- // test that a manual write (of undefined) to a resettable aliased property succeeds
- QDeclarativeComponent c1(&engine, testFileUrl("aliasreset/aliasPropertyReset.1.qml"));
- object = c1.create();
- QVERIFY(object != 0);
- QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
- QCOMPARE(object->property("aliasIsUndefined"), QVariant(false));
- QMetaObject::invokeMethod(object, "resetAliased");
- QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
- QCOMPARE(object->property("aliasIsUndefined"), QVariant(true));
- delete object;
-
- // test that a manual write (of undefined) to a resettable alias property succeeds
- QDeclarativeComponent c2(&engine, testFileUrl("aliasreset/aliasPropertyReset.2.qml"));
- object = c2.create();
- QVERIFY(object != 0);
- QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
- QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(false));
- QMetaObject::invokeMethod(object, "resetAlias");
- QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
- QCOMPARE(object->property("loaderSourceComponentIsUndefined"), QVariant(true));
- delete object;
-
- // test that an alias to a bound property works correctly
- QDeclarativeComponent c3(&engine, testFileUrl("aliasreset/aliasPropertyReset.3.qml"));
- object = c3.create();
- QVERIFY(object != 0);
- QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
- QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(false));
- QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
- QMetaObject::invokeMethod(object, "resetAlias");
- QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
- QCOMPARE(object->property("loaderOneSourceComponentIsUndefined"), QVariant(true));
- QCOMPARE(object->property("loaderTwoSourceComponentIsUndefined"), QVariant(false));
- delete object;
-
- // test that a manual write (of undefined) to a resettable alias property
- // whose aliased property's object has been deleted, does not crash.
- QDeclarativeComponent c4(&engine, testFileUrl("aliasreset/aliasPropertyReset.4.qml"));
- object = c4.create();
- QVERIFY(object != 0);
- QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() != 0);
- QObject *loader = object->findChild<QObject*>("loader");
- QVERIFY(loader != 0);
- delete loader;
- QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // deletion should have caused value unset.
- QMetaObject::invokeMethod(object, "resetAlias"); // shouldn't crash.
- QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
- QMetaObject::invokeMethod(object, "setAlias"); // shouldn't crash, and shouldn't change value (since it's no longer referencing anything).
- QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0);
- delete object;
-
- // test that binding an alias property to an undefined value works correctly
- QDeclarativeComponent c5(&engine, testFileUrl("aliasreset/aliasPropertyReset.5.qml"));
- object = c5.create();
- QVERIFY(object != 0);
- QVERIFY(object->property("sourceComponentAlias").value<QDeclarativeComponent*>() == 0); // bound to undefined value.
- delete object;
-
- // test that a manual write (of undefined) to a non-resettable property fails properly
- QUrl url = testFileUrl("aliasreset/aliasPropertyReset.error.1.qml");
- QString warning1 = url.toString() + QLatin1String(":15: Error: Cannot assign [undefined] to int");
- QDeclarativeComponent e1(&engine, url);
- object = e1.create();
- QVERIFY(object != 0);
- QCOMPARE(object->property("intAlias").value<int>(), 12);
- QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
- QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
- QMetaObject::invokeMethod(object, "resetAlias");
- QCOMPARE(object->property("intAlias").value<int>(), 12);
- QCOMPARE(object->property("aliasedIntIsUndefined"), QVariant(false));
- delete object;
-}
-
-void tst_qdeclarativeecmascript::dynamicCreation_data()
-{
- QTest::addColumn<QString>("method");
- QTest::addColumn<QString>("createdName");
-
- QTest::newRow("One") << "createOne" << "objectOne";
- QTest::newRow("Two") << "createTwo" << "objectTwo";
- QTest::newRow("Three") << "createThree" << "objectThree";
-}
-
-/*
-Test using createQmlObject to dynamically generate an item
-Also using createComponent is tested.
-*/
-void tst_qdeclarativeecmascript::dynamicCreation()
-{
- QFETCH(QString, method);
- QFETCH(QString, createdName);
-
- QDeclarativeComponent component(&engine, testFileUrl("dynamicCreation.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
-
- QMetaObject::invokeMethod(object, method.toUtf8());
- QObject *created = object->objectProperty();
- QVERIFY(created);
- QCOMPARE(created->objectName(), createdName);
-
- delete object;
-}
-
-/*
- Tests the destroy function
-*/
-void tst_qdeclarativeecmascript::dynamicDestruction()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("dynamicDeletion.qml"));
- QDeclarativeGuard<MyQmlObject> object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
- QDeclarativeGuard<QObject> createdQmlObject = 0;
-
- QMetaObject::invokeMethod(object, "create");
- createdQmlObject = object->objectProperty();
- QVERIFY(createdQmlObject);
- QCOMPARE(createdQmlObject->objectName(), QString("emptyObject"));
-
- QMetaObject::invokeMethod(object, "killOther");
- QVERIFY(createdQmlObject);
-
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
- QVERIFY(createdQmlObject);
- for (int ii = 0; createdQmlObject && ii < 50; ++ii) { // After 5 seconds we should give up
- if (createdQmlObject) {
- QTest::qWait(100);
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
- }
- }
- QVERIFY(!createdQmlObject);
-
- QDeclarativeEngine::setObjectOwnership(object, QDeclarativeEngine::JavaScriptOwnership);
- QMetaObject::invokeMethod(object, "killMe");
- QVERIFY(object);
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
- QVERIFY(!object);
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("dynamicDeletion.2.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
-
- QMetaObject::invokeMethod(o, "create");
-
- QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) != 0);
-
- QMetaObject::invokeMethod(o, "destroy");
-
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
-
- QVERIFY(qvariant_cast<QObject*>(o->property("objectProperty")) == 0);
-
- delete o;
- }
-}
-
-/*
- tests that id.toString() works
-*/
-void tst_qdeclarativeecmascript::objectToString()
-{
- QDeclarativeComponent component(&engine, testFileUrl("declarativeToString.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
- QMetaObject::invokeMethod(object, "testToString");
- QVERIFY(object->stringProperty().startsWith("MyQmlObject_QML_"));
- QVERIFY(object->stringProperty().endsWith(", \"objName\")"));
-
- delete object;
-}
-
-/*
- tests that id.hasOwnProperty() works
-*/
-void tst_qdeclarativeecmascript::objectHasOwnProperty()
-{
- QUrl url = testFileUrl("declarativeHasOwnProperty.qml");
- QString warning1 = url.toString() + ":59: TypeError: Cannot call method 'hasOwnProperty' of undefined";
- QString warning2 = url.toString() + ":64: TypeError: Cannot call method 'hasOwnProperty' of undefined";
- QString warning3 = url.toString() + ":69: TypeError: Cannot call method 'hasOwnProperty' of undefined";
-
- QDeclarativeComponent component(&engine, url);
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- // test QObjects in QML
- QMetaObject::invokeMethod(object, "testHasOwnPropertySuccess");
- QVERIFY(object->property("result").value<bool>() == true);
- QMetaObject::invokeMethod(object, "testHasOwnPropertyFailure");
- QVERIFY(object->property("result").value<bool>() == false);
-
- // now test other types in QML
- QObject *child = object->findChild<QObject*>("typeObj");
- QVERIFY(child != 0);
- QMetaObject::invokeMethod(child, "testHasOwnPropertySuccess");
- QCOMPARE(child->property("valueTypeHasOwnProperty").toBool(), true);
- QCOMPARE(child->property("valueTypeHasOwnProperty2").toBool(), true);
- QCOMPARE(child->property("variantTypeHasOwnProperty").toBool(), true);
- QCOMPARE(child->property("stringTypeHasOwnProperty").toBool(), true);
- QCOMPARE(child->property("listTypeHasOwnProperty").toBool(), true);
- QCOMPARE(child->property("emptyListTypeHasOwnProperty").toBool(), true);
- QCOMPARE(child->property("enumTypeHasOwnProperty").toBool(), true);
- QCOMPARE(child->property("typenameHasOwnProperty").toBool(), true);
- QCOMPARE(child->property("typenameHasOwnProperty2").toBool(), true);
- QCOMPARE(child->property("moduleApiTypeHasOwnProperty").toBool(), true);
- QCOMPARE(child->property("moduleApiPropertyTypeHasOwnProperty").toBool(), true);
-
- QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
- QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureOne");
- QCOMPARE(child->property("enumNonValueHasOwnProperty").toBool(), false);
- QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
- QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureTwo");
- QCOMPARE(child->property("moduleApiNonPropertyHasOwnProperty").toBool(), false);
- QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
- QMetaObject::invokeMethod(child, "testHasOwnPropertyFailureThree");
- QCOMPARE(child->property("listAtInvalidHasOwnProperty").toBool(), false);
-
- delete object;
-}
-
-/*
-Tests bindings that indirectly cause their own deletion work.
-
-This test is best run under valgrind to ensure no invalid memory access occur.
-*/
-void tst_qdeclarativeecmascript::selfDeletingBinding()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("selfDeletingBinding.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- object->setProperty("triggerDelete", true);
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("selfDeletingBinding.2.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- object->setProperty("triggerDelete", true);
- delete object;
- }
-}
-
-/*
-Test that extended object properties can be accessed.
-
-This test a regression where this used to crash. The issue was specificially
-for extended objects that did not include a synthesized meta object (so non-root
-and no synthesiszed properties).
-*/
-void tst_qdeclarativeecmascript::extendedObjectPropertyLookup()
-{
- QDeclarativeComponent component(&engine, testFileUrl("extendedObjectPropertyLookup.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- delete object;
-}
-
-/*
-Test that extended object properties can be accessed correctly.
-*/
-void tst_qdeclarativeecmascript::extendedObjectPropertyLookup2()
-{
- QDeclarativeComponent component(&engine, testFileUrl("extendedObjectPropertyLookup2.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QVariant returnValue;
- QVERIFY(QMetaObject::invokeMethod(object, "getValue", Q_RETURN_ARG(QVariant, returnValue)));
- QCOMPARE(returnValue.toInt(), 42);
-
- delete object;
-}
-/*
-Test file/lineNumbers for binding/Script errors.
-*/
-void tst_qdeclarativeecmascript::scriptErrors()
-{
- QDeclarativeComponent component(&engine, testFileUrl("scriptErrors.qml"));
- QString url = component.url().toString();
-
- QString warning1 = url.left(url.length() - 3) + "js:2: Error: Invalid write to global property \"a\"";
- QString warning2 = url + ":5: ReferenceError: Can't find variable: a";
- QString warning3 = url.left(url.length() - 3) + "js:4: Error: Invalid write to global property \"a\"";
- QString warning4 = url + ":13: ReferenceError: Can't find variable: a";
- QString warning5 = url + ":11: ReferenceError: Can't find variable: a";
- QString warning6 = url + ":10: Unable to assign [undefined] to int";
- QString warning7 = url + ":15: Error: Cannot assign to read-only property \"trueProperty\"";
- QString warning8 = url + ":16: Error: Cannot assign to non-existent property \"fakeProperty\"";
-
- QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
- QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
- QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
- QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
- QTest::ignoreMessage(QtWarningMsg, warning6.toLatin1().constData());
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
- emit object->basicSignal();
-
- QTest::ignoreMessage(QtWarningMsg, warning7.toLatin1().constData());
- emit object->anotherBasicSignal();
-
- QTest::ignoreMessage(QtWarningMsg, warning8.toLatin1().constData());
- emit object->thirdBasicSignal();
-
- delete object;
-}
-
-/*
-Test file/lineNumbers for inline functions.
-*/
-void tst_qdeclarativeecmascript::functionErrors()
-{
- QDeclarativeComponent component(&engine, testFileUrl("functionErrors.qml"));
- QString url = component.url().toString();
-
- QString warning = url + ":5: Error: Invalid write to global property \"a\"";
-
- QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
-
- QObject *object = component.create();
- QVERIFY(object != 0);
- delete object;
-
- // test that if an exception occurs while invoking js function from cpp, it is reported as expected.
- QDeclarativeComponent componentTwo(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
- url = componentTwo.url().toString();
- object = componentTwo.create();
- QVERIFY(object != 0);
-
- QString srpname = object->property("srp_name").toString();
-
- warning = url + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srpname
- + QLatin1String(" is not a function");
- QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData()); // we expect a meaningful warning to be printed.
- QMetaObject::invokeMethod(object, "retrieveScarceResource");
- delete object;
-}
-
-/*
-Test various errors that can occur when assigning a property from script
-*/
-void tst_qdeclarativeecmascript::propertyAssignmentErrors()
-{
- QDeclarativeComponent component(&engine, testFileUrl("propertyAssignmentErrors.qml"));
-
- QString url = component.url().toString();
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test1").toBool(), true);
- QCOMPARE(object->property("test2").toBool(), true);
-
- delete object;
-}
-
-/*
-Test bindings still work when the reeval is triggered from within
-a signal script.
-*/
-void tst_qdeclarativeecmascript::signalTriggeredBindings()
-{
- QDeclarativeComponent component(&engine, testFileUrl("signalTriggeredBindings.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("base").toReal(), 50.);
- QCOMPARE(object->property("test1").toReal(), 50.);
- QCOMPARE(object->property("test2").toReal(), 50.);
-
- object->basicSignal();
-
- QCOMPARE(object->property("base").toReal(), 200.);
- QCOMPARE(object->property("test1").toReal(), 200.);
- QCOMPARE(object->property("test2").toReal(), 200.);
-
- object->argumentSignal(10, QString(), 10, MyQmlObject::EnumValue4, Qt::RightButton);
-
- QCOMPARE(object->property("base").toReal(), 400.);
- QCOMPARE(object->property("test1").toReal(), 400.);
- QCOMPARE(object->property("test2").toReal(), 400.);
-
- delete object;
-}
-
-/*
-Test that list properties can be iterated from ECMAScript
-*/
-void tst_qdeclarativeecmascript::listProperties()
-{
- QDeclarativeComponent component(&engine, testFileUrl("listProperties.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test1").toInt(), 21);
- QCOMPARE(object->property("test2").toInt(), 2);
- QCOMPARE(object->property("test3").toBool(), true);
- QCOMPARE(object->property("test4").toBool(), true);
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::exceptionClearsOnReeval()
-{
- QDeclarativeComponent component(&engine, testFileUrl("exceptionClearsOnReeval.qml"));
- QString url = component.url().toString();
-
- QString warning = url + ":4: TypeError: Cannot read property 'objectProperty' of null";
-
- QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toBool(), false);
-
- MyQmlObject object2;
- MyQmlObject object3;
- object2.setObjectProperty(&object3);
- object->setObjectProperty(&object2);
-
- QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::exceptionSlotProducesWarning()
-{
- QDeclarativeComponent component(&engine, testFileUrl("exceptionProducesWarning.qml"));
- QString url = component.url().toString();
-
- QString warning = component.url().toString() + ":6: Error: JS exception";
-
- QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
- delete object;
-}
-
-void tst_qdeclarativeecmascript::exceptionBindingProducesWarning()
-{
- QDeclarativeComponent component(&engine, testFileUrl("exceptionProducesWarning2.qml"));
- QString url = component.url().toString();
-
- QString warning = component.url().toString() + ":5: Error: JS exception";
-
- QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
- delete object;
-}
-
-void tst_qdeclarativeecmascript::compileInvalidBinding()
-{
- // QTBUG-23387: ensure that invalid bindings don't cause a crash.
- QDeclarativeComponent component(&engine, testFileUrl("v8bindingException.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- delete object;
-}
-
-static int transientErrorsMsgCount = 0;
-static void transientErrorsMsgHandler(QtMsgType, const char *)
-{
- ++transientErrorsMsgCount;
-}
-
-// Check that transient binding errors are not displayed
-void tst_qdeclarativeecmascript::transientErrors()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("transientErrors.qml"));
-
- transientErrorsMsgCount = 0;
- QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- qInstallMsgHandler(old);
-
- QCOMPARE(transientErrorsMsgCount, 0);
-
- delete object;
- }
-
- // One binding erroring multiple times, but then resolving
- {
- QDeclarativeComponent component(&engine, testFileUrl("transientErrors.2.qml"));
-
- transientErrorsMsgCount = 0;
- QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- qInstallMsgHandler(old);
-
- QCOMPARE(transientErrorsMsgCount, 0);
-
- delete object;
- }
-}
-
-// Check that errors during shutdown are minimized
-void tst_qdeclarativeecmascript::shutdownErrors()
-{
- QDeclarativeComponent component(&engine, testFileUrl("shutdownErrors.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- transientErrorsMsgCount = 0;
- QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
-
- delete object;
-
- qInstallMsgHandler(old);
- QCOMPARE(transientErrorsMsgCount, 0);
-}
-
-void tst_qdeclarativeecmascript::compositePropertyType()
-{
- QDeclarativeComponent component(&engine, testFileUrl("compositePropertyType.qml"));
-
- QTest::ignoreMessage(QtDebugMsg, "hello world");
- QObject *object = qobject_cast<QObject *>(component.create());
- delete object;
-}
-
-// QTBUG-5759
-void tst_qdeclarativeecmascript::jsObject()
-{
- QDeclarativeComponent component(&engine, testFileUrl("jsObject.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toInt(), 92);
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::undefinedResetsProperty()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("resettableProperty").toInt(), 92);
-
- object->setProperty("setUndefined", true);
-
- QCOMPARE(object->property("resettableProperty").toInt(), 13);
-
- object->setProperty("setUndefined", false);
-
- QCOMPARE(object->property("resettableProperty").toInt(), 92);
-
- delete object;
- }
- {
- QDeclarativeComponent component(&engine, testFileUrl("undefinedResetsProperty.2.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("resettableProperty").toInt(), 19);
-
- QMetaObject::invokeMethod(object, "doReset");
-
- QCOMPARE(object->property("resettableProperty").toInt(), 13);
-
- delete object;
- }
-}
-
-// Aliases to variant properties should work
-void tst_qdeclarativeecmascript::qtbug_22464()
-{
- QDeclarativeComponent component(&engine, testFileUrl("qtbug_22464.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::qtbug_21580()
-{
- QDeclarativeComponent component(&engine, testFileUrl("qtbug_21580.qml"));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
-}
-
-// QTBUG-6781
-void tst_qdeclarativeecmascript::bug1()
-{
- QDeclarativeComponent component(&engine, testFileUrl("bug.1.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toInt(), 14);
-
- object->setProperty("a", 11);
-
- QCOMPARE(object->property("test").toInt(), 3);
-
- object->setProperty("b", true);
-
- QCOMPARE(object->property("test").toInt(), 9);
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::bug2()
-{
- QDeclarativeComponent component(&engine);
- component.setData("import Qt.test 1.0;\nQPlainTextEdit { width: 100 }", QUrl());
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- delete object;
-}
-
-// Don't crash in createObject when the component has errors.
-void tst_qdeclarativeecmascript::dynamicCreationCrash()
-{
- QDeclarativeComponent component(&engine, testFileUrl("dynamicCreation.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
-
- QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
- QMetaObject::invokeMethod(object, "dontCrash");
- QObject *created = object->objectProperty();
- QVERIFY(created == 0);
-
- delete object;
-}
-
-// ownership transferred to JS, ensure that GC runs the dtor
-void tst_qdeclarativeecmascript::dynamicCreationOwnership()
-{
- int dtorCount = 0;
- int expectedDtorCount = 1; // start at 1 since we expect mdcdo to dtor too.
-
- // allow the engine to go out of scope too.
- {
- QDeclarativeEngine dcoEngine;
- QDeclarativeComponent component(&dcoEngine, testFileUrl("dynamicCreationOwnership.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- MyDynamicCreationDestructionObject *mdcdo = object->findChild<MyDynamicCreationDestructionObject*>("mdcdo");
- QVERIFY(mdcdo != 0);
- mdcdo->setDtorCount(&dtorCount);
-
- for (int i = 1; i < 105; ++i, ++expectedDtorCount) {
- QMetaObject::invokeMethod(object, "dynamicallyCreateJsOwnedObject");
- if (i % 90 == 0) {
- // we do this once manually, but it should be done automatically
- // when the engine goes out of scope (since it should gc in dtor)
- QMetaObject::invokeMethod(object, "performGc");
- }
- if (i % 10 == 0) {
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
- }
- }
-
- delete object;
- }
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
- QCOMPARE(dtorCount, expectedDtorCount);
-}
-
-void tst_qdeclarativeecmascript::regExpBug()
-{
- //QTBUG-9367
- {
- QDeclarativeComponent component(&engine, testFileUrl("regExp.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->regExp().pattern(), QLatin1String("[a-zA-z]"));
- delete object;
- }
-
- //QTBUG-23068
- {
- QString err = QString(QLatin1String("%1:6 Invalid property assignment: regular expression expected; use /pattern/ syntax\n")).arg(testFileUrl("regExp.2.qml").toString());
- QDeclarativeComponent component(&engine, testFileUrl("regExp.2.qml"));
- QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(!object);
- QCOMPARE(component.errorString(), err);
- }
-}
-
-static inline bool evaluate_error(QV8Engine *engine, v8::Handle<v8::Object> o, const char *source)
-{
- QString functionSource = QLatin1String("(function(object) { return ") +
- QLatin1String(source) + QLatin1String(" })");
- v8::TryCatch tc;
- v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
- if (tc.HasCaught())
- return false;
- v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
- if (function.IsEmpty())
- return false;
- v8::Handle<v8::Value> args[] = { o };
- function->Call(engine->global(), 1, args);
- return tc.HasCaught();
-}
-
-static inline bool evaluate_value(QV8Engine *engine, v8::Handle<v8::Object> o,
- const char *source, v8::Handle<v8::Value> result)
-{
- QString functionSource = QLatin1String("(function(object) { return ") +
- QLatin1String(source) + QLatin1String(" })");
- v8::TryCatch tc;
- v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
- if (tc.HasCaught())
- return false;
- v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
- if (function.IsEmpty())
- return false;
- v8::Handle<v8::Value> args[] = { o };
-
- v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
-
- if (tc.HasCaught())
- return false;
-
- return value->StrictEquals(result);
-}
-
-static inline v8::Handle<v8::Value> evaluate(QV8Engine *engine, v8::Handle<v8::Object> o,
- const char *source)
-{
- QString functionSource = QLatin1String("(function(object) { return ") +
- QLatin1String(source) + QLatin1String(" })");
- v8::TryCatch tc;
- v8::Local<v8::Script> program = v8::Script::Compile(engine->toString(functionSource));
- if (tc.HasCaught())
- return v8::Handle<v8::Value>();
- v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(program->Run());
- if (function.IsEmpty())
- return v8::Handle<v8::Value>();
- v8::Handle<v8::Value> args[] = { o };
-
- v8::Handle<v8::Value> value = function->Call(engine->global(), 1, args);
-
- if (tc.HasCaught())
- return v8::Handle<v8::Value>();
- return value;
-}
-
-#define EVALUATE_ERROR(source) evaluate_error(engine, object, source)
-#define EVALUATE_VALUE(source, result) evaluate_value(engine, object, source, result)
-#define EVALUATE(source) evaluate(engine, object, source)
-
-void tst_qdeclarativeecmascript::callQtInvokables()
-{
- MyInvokableObject o;
-
- QDeclarativeEngine qmlengine;
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&qmlengine);
-
- QV8Engine *engine = ep->v8engine();
-
- v8::HandleScope handle_scope;
- v8::Context::Scope scope(engine->context());
-
- v8::Local<v8::Object> object = engine->newQObject(&o)->ToObject();
-
- // Non-existent methods
- o.reset();
- QVERIFY(EVALUATE_ERROR("object.method_nonexistent()"));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), -1);
- QCOMPARE(o.actuals().count(), 0);
-
- o.reset();
- QVERIFY(EVALUATE_ERROR("object.method_nonexistent(10, 11)"));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), -1);
- QCOMPARE(o.actuals().count(), 0);
-
- // Insufficient arguments
- o.reset();
- QVERIFY(EVALUATE_ERROR("object.method_int()"));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), -1);
- QCOMPARE(o.actuals().count(), 0);
-
- o.reset();
- QVERIFY(EVALUATE_ERROR("object.method_intint(10)"));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), -1);
- QCOMPARE(o.actuals().count(), 0);
-
- // Excessive arguments
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_int(10, 11)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 8);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(10));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_intint(10, 11, 12)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 9);
- QCOMPARE(o.actuals().count(), 2);
- QCOMPARE(o.actuals().at(0), QVariant(10));
- QCOMPARE(o.actuals().at(1), QVariant(11));
-
- // Test return types
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_NoArgs()", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 0);
- QCOMPARE(o.actuals().count(), 0);
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_NoArgs_int()", v8::Integer::New(6)));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 1);
- QCOMPARE(o.actuals().count(), 0);
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_NoArgs_real()", v8::Number::New(19.75)));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 2);
- QCOMPARE(o.actuals().count(), 0);
-
- o.reset();
- {
- v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QPointF()");
- QVERIFY(!ret.IsEmpty());
- QCOMPARE(engine->toVariant(ret, -1), QVariant(QPointF(123, 4.5)));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 3);
- QCOMPARE(o.actuals().count(), 0);
- }
-
- o.reset();
- {
- v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QObject()");
- QCOMPARE(engine->toQObject(ret), (QObject *)&o);
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 4);
- QCOMPARE(o.actuals().count(), 0);
- }
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_NoArgs_unknown()", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 5);
- QCOMPARE(o.actuals().count(), 0);
-
- o.reset();
- {
- v8::Handle<v8::Value> ret = EVALUATE("object.method_NoArgs_QScriptValue()");
- QVERIFY(ret->IsString());
- QCOMPARE(engine->toString(ret), QString("Hello world"));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 6);
- QCOMPARE(o.actuals().count(), 0);
- }
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_NoArgs_QVariant()", engine->toString("QML rocks")));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 7);
- QCOMPARE(o.actuals().count(), 0);
-
- // Test arg types
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_int(94)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 8);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(94));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_int(\"94\")", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 8);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(94));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_int(\"not a number\")", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 8);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(0));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_int(null)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 8);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(0));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_int(undefined)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 8);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(0));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_int(object)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 8);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(0));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_intint(122, 9)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 9);
- QCOMPARE(o.actuals().count(), 2);
- QCOMPARE(o.actuals().at(0), QVariant(122));
- QCOMPARE(o.actuals().at(1), QVariant(9));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_real(94.3)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 10);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(94.3));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_real(\"94.3\")", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 10);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(94.3));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_real(\"not a number\")", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 10);
- QCOMPARE(o.actuals().count(), 1);
- QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_real(null)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 10);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(0));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_real(undefined)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 10);
- QCOMPARE(o.actuals().count(), 1);
- QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_real(object)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 10);
- QCOMPARE(o.actuals().count(), 1);
- QVERIFY(qIsNaN(o.actuals().at(0).toDouble()));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QString(\"Hello world\")", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 11);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant("Hello world"));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QString(19)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 11);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant("19"));
-
- o.reset();
- {
- QString expected = "MyInvokableObject(0x" + QString::number((quintptr)&o, 16) + ")";
- QVERIFY(EVALUATE_VALUE("object.method_QString(object)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 11);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(expected));
- }
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QString(null)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 11);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(QString()));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QString(undefined)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 11);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(QString()));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QPointF(0)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 12);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QPointF(null)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 12);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QPointF(undefined)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 12);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QPointF(object)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 12);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(QPointF()));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPointF())", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 12);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(QPointF(99.3, -10.2)));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QPointF(object.method_get_QPoint())", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 12);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(QPointF(9, 12)));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QObject(0)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 13);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QObject(\"Hello world\")", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 13);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QObject(null)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 13);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QObject(undefined)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 13);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)0));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QObject(object)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 13);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), qVariantFromValue((QObject *)&o));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(null)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 14);
- QCOMPARE(o.actuals().count(), 1);
- QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isNull());
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(undefined)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 14);
- QCOMPARE(o.actuals().count(), 1);
- QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isUndefined());
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QScriptValue(19)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 14);
- QCOMPARE(o.actuals().count(), 1);
- QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).strictlyEquals(QJSValue(19)));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QScriptValue([19, 20])", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 14);
- QCOMPARE(o.actuals().count(), 1);
- QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(0)).isArray());
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(4, null)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 15);
- QCOMPARE(o.actuals().count(), 2);
- QCOMPARE(o.actuals().at(0), QVariant(4));
- QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isNull());
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(8, undefined)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 15);
- QCOMPARE(o.actuals().count(), 2);
- QCOMPARE(o.actuals().at(0), QVariant(8));
- QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isUndefined());
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(3, 19)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 15);
- QCOMPARE(o.actuals().count(), 2);
- QCOMPARE(o.actuals().at(0), QVariant(3));
- QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).strictlyEquals(QJSValue(19)));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_intQScriptValue(44, [19, 20])", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 15);
- QCOMPARE(o.actuals().count(), 2);
- QCOMPARE(o.actuals().at(0), QVariant(44));
- QVERIFY(qvariant_cast<QJSValue>(o.actuals().at(1)).isArray());
-
- o.reset();
- QVERIFY(EVALUATE_ERROR("object.method_overload()"));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), -1);
- QCOMPARE(o.actuals().count(), 0);
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_overload(10)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 16);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(10));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_overload(10, 11)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 17);
- QCOMPARE(o.actuals().count(), 2);
- QCOMPARE(o.actuals().at(0), QVariant(10));
- QCOMPARE(o.actuals().at(1), QVariant(11));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_overload(\"Hello\")", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 18);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_with_enum(9)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 19);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(9));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_default(10)", v8::Integer::New(19)));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 20);
- QCOMPARE(o.actuals().count(), 2);
- QCOMPARE(o.actuals().at(0), QVariant(10));
- QCOMPARE(o.actuals().at(1), QVariant(19));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_default(10, 13)", v8::Integer::New(13)));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 20);
- QCOMPARE(o.actuals().count(), 2);
- QCOMPARE(o.actuals().at(0), QVariant(10));
- QCOMPARE(o.actuals().at(1), QVariant(13));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_inherited(9)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), -3);
- QCOMPARE(o.actuals().count(), 1);
- QCOMPARE(o.actuals().at(0), QVariant(9));
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QVariant(9)", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 21);
- QCOMPARE(o.actuals().count(), 2);
- QCOMPARE(o.actuals().at(0), QVariant(9));
- QCOMPARE(o.actuals().at(1), QVariant());
-
- o.reset();
- QVERIFY(EVALUATE_VALUE("object.method_QVariant(\"Hello\", \"World\")", v8::Undefined()));
- QCOMPARE(o.error(), false);
- QCOMPARE(o.invoked(), 21);
- QCOMPARE(o.actuals().count(), 2);
- QCOMPARE(o.actuals().at(0), QVariant(QString("Hello")));
- QCOMPARE(o.actuals().at(1), QVariant(QString("World")));
-}
-
-// QTBUG-13047 (check that you can pass registered object types as args)
-void tst_qdeclarativeecmascript::invokableObjectArg()
-{
- QDeclarativeComponent component(&engine, testFileUrl("invokableObjectArg.qml"));
-
- QObject *o = component.create();
- QVERIFY(o);
- MyQmlObject *qmlobject = qobject_cast<MyQmlObject *>(o);
- QVERIFY(qmlobject);
- QCOMPARE(qmlobject->myinvokableObject, qmlobject);
-
- delete o;
-}
-
-// QTBUG-13047 (check that you can return registered object types from methods)
-void tst_qdeclarativeecmascript::invokableObjectRet()
-{
- QDeclarativeComponent component(&engine, testFileUrl("invokableObjectRet.qml"));
-
- QObject *o = component.create();
- QVERIFY(o);
- QCOMPARE(o->property("test").toBool(), true);
- delete o;
-}
-
-// QTBUG-5675
-void tst_qdeclarativeecmascript::listToVariant()
-{
- QDeclarativeComponent component(&engine, testFileUrl("listToVariant.qml"));
-
- MyQmlContainer container;
-
- QDeclarativeContext context(engine.rootContext());
- context.setContextObject(&container);
-
- QObject *object = component.create(&context);
- QVERIFY(object != 0);
-
- QVariant v = object->property("test");
- QCOMPARE(v.userType(), qMetaTypeId<QDeclarativeListReference>());
- QVERIFY(qvariant_cast<QDeclarativeListReference>(v).object() == &container);
-
- delete object;
-}
-
-// QTBUG-16316
-Q_DECLARE_METATYPE(QDeclarativeListProperty<MyQmlObject>)
-void tst_qdeclarativeecmascript::listAssignment()
-{
- QDeclarativeComponent component(&engine, testFileUrl("listAssignment.qml"));
- QObject *obj = component.create();
- QCOMPARE(obj->property("list1length").toInt(), 2);
- QDeclarativeListProperty<MyQmlObject> list1 = obj->property("list1").value<QDeclarativeListProperty<MyQmlObject> >();
- QDeclarativeListProperty<MyQmlObject> list2 = obj->property("list2").value<QDeclarativeListProperty<MyQmlObject> >();
- QCOMPARE(list1.count(&list1), list2.count(&list2));
- QCOMPARE(list1.at(&list1, 0), list2.at(&list2, 0));
- QCOMPARE(list1.at(&list1, 1), list2.at(&list2, 1));
- delete obj;
-}
-
-// QTBUG-7957
-void tst_qdeclarativeecmascript::multiEngineObject()
-{
- MyQmlObject obj;
- obj.setStringProperty("Howdy planet");
-
- QDeclarativeEngine e1;
- e1.rootContext()->setContextProperty("thing", &obj);
- QDeclarativeComponent c1(&e1, testFileUrl("multiEngineObject.qml"));
-
- QDeclarativeEngine e2;
- e2.rootContext()->setContextProperty("thing", &obj);
- QDeclarativeComponent c2(&e2, testFileUrl("multiEngineObject.qml"));
-
- QObject *o1 = c1.create();
- QObject *o2 = c2.create();
-
- QCOMPARE(o1->property("test").toString(), QString("Howdy planet"));
- QCOMPARE(o2->property("test").toString(), QString("Howdy planet"));
-
- delete o2;
- delete o1;
-}
-
-// Test that references to QObjects are cleanup when the object is destroyed
-void tst_qdeclarativeecmascript::deletedObject()
-{
- QDeclarativeComponent component(&engine, testFileUrl("deletedObject.qml"));
-
- QObject *object = component.create();
-
- QCOMPARE(object->property("test1").toBool(), true);
- QCOMPARE(object->property("test2").toBool(), true);
- QCOMPARE(object->property("test3").toBool(), true);
- QCOMPARE(object->property("test4").toBool(), true);
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::attachedPropertyScope()
-{
- QDeclarativeComponent component(&engine, testFileUrl("attachedPropertyScope.qml"));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- MyQmlAttachedObject *attached =
- qobject_cast<MyQmlAttachedObject *>(qmlAttachedPropertiesObject<MyQmlObject>(object));
- QVERIFY(attached != 0);
-
- QCOMPARE(object->property("value2").toInt(), 0);
-
- attached->emitMySignal();
-
- QCOMPARE(object->property("value2").toInt(), 9);
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::scriptConnect()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.1.qml"));
-
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toBool(), false);
- emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
- QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.2.qml"));
-
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toBool(), false);
- emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
- QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.3.qml"));
-
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toBool(), false);
- emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
- QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.4.qml"));
-
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->methodCalled(), false);
- emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
- QCOMPARE(object->methodCalled(), true);
-
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.5.qml"));
-
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->methodCalled(), false);
- emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
- QCOMPARE(object->methodCalled(), true);
-
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("scriptConnect.6.qml"));
-
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toInt(), 0);
- emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
- QCOMPARE(object->property("test").toInt(), 2);
-
- delete object;
- }
-}
-
-void tst_qdeclarativeecmascript::scriptDisconnect()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.1.qml"));
-
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toInt(), 0);
- emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
- QCOMPARE(object->property("test").toInt(), 1);
- emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
- QCOMPARE(object->property("test").toInt(), 2);
- emit object->basicSignal();
- QCOMPARE(object->property("test").toInt(), 2);
- emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
- QCOMPARE(object->property("test").toInt(), 2);
-
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.2.qml"));
-
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toInt(), 0);
- emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
- QCOMPARE(object->property("test").toInt(), 1);
- emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
- QCOMPARE(object->property("test").toInt(), 2);
- emit object->basicSignal();
- QCOMPARE(object->property("test").toInt(), 2);
- emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
- QCOMPARE(object->property("test").toInt(), 2);
-
- delete object;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.3.qml"));
-
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toInt(), 0);
- emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
- QCOMPARE(object->property("test").toInt(), 1);
- emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
- QCOMPARE(object->property("test").toInt(), 2);
- emit object->basicSignal();
- QCOMPARE(object->property("test").toInt(), 2);
- emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
- QCOMPARE(object->property("test").toInt(), 3);
-
- delete object;
- }
- {
- QDeclarativeComponent component(&engine, testFileUrl("scriptDisconnect.4.qml"));
-
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toInt(), 0);
- emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
- QCOMPARE(object->property("test").toInt(), 1);
- emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
- QCOMPARE(object->property("test").toInt(), 2);
- emit object->basicSignal();
- QCOMPARE(object->property("test").toInt(), 2);
- emit object->argumentSignal(19, "Hello world!", 10.25, MyQmlObject::EnumValue4, Qt::RightButton);
- QCOMPARE(object->property("test").toInt(), 3);
-
- delete object;
- }
-}
-
-class OwnershipObject : public QObject
-{
- Q_OBJECT
-public:
- OwnershipObject() { object = new QObject; }
-
- QPointer<QObject> object;
-
-public slots:
- QObject *getObject() { return object; }
-};
-
-void tst_qdeclarativeecmascript::ownership()
-{
- OwnershipObject own;
- QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
- context->setContextObject(&own);
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
-
- QVERIFY(own.object != 0);
-
- QObject *object = component.create(context);
-
- engine.collectGarbage();
-
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
-
- QVERIFY(own.object == 0);
-
- delete object;
- }
-
- own.object = new QObject(&own);
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("ownership.qml"));
-
- QVERIFY(own.object != 0);
-
- QObject *object = component.create(context);
-
- engine.collectGarbage();
-
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
-
- QVERIFY(own.object != 0);
-
- delete object;
- }
-
- delete context;
-}
-
-class CppOwnershipReturnValue : public QObject
-{
- Q_OBJECT
-public:
- CppOwnershipReturnValue() : value(0) {}
- ~CppOwnershipReturnValue() { delete value; }
-
- Q_INVOKABLE QObject *create() {
- value = new QObject;
- QDeclarativeEngine::setObjectOwnership(value, QDeclarativeEngine::CppOwnership);
- return value;
- }
-
- Q_INVOKABLE MyQmlObject *createQmlObject() {
- MyQmlObject *rv = new MyQmlObject;
- value = rv;
- return rv;
- }
-
- QPointer<QObject> value;
-};
-
-// QTBUG-15695.
-// Test setObjectOwnership(CppOwnership) works even when there is no QDeclarativeData
-void tst_qdeclarativeecmascript::cppOwnershipReturnValue()
-{
- CppOwnershipReturnValue source;
-
- {
- QDeclarativeEngine engine;
- engine.rootContext()->setContextProperty("source", &source);
-
- QVERIFY(source.value == 0);
-
- QDeclarativeComponent component(&engine);
- component.setData("import QtQuick 2.0\nQtObject {\nComponent.onCompleted: { var a = source.create(); }\n}\n", QUrl());
-
- QObject *object = component.create();
-
- QVERIFY(object != 0);
- QVERIFY(source.value != 0);
-
- delete object;
- }
-
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
-
- QVERIFY(source.value != 0);
-}
-
-// QTBUG-15697
-void tst_qdeclarativeecmascript::ownershipCustomReturnValue()
-{
- CppOwnershipReturnValue source;
-
- {
- QDeclarativeEngine engine;
- engine.rootContext()->setContextProperty("source", &source);
-
- QVERIFY(source.value == 0);
-
- QDeclarativeComponent component(&engine);
- component.setData("import QtQuick 2.0\nQtObject {\nComponent.onCompleted: { var a = source.createQmlObject(); }\n}\n", QUrl());
-
- QObject *object = component.create();
-
- QVERIFY(object != 0);
- QVERIFY(source.value != 0);
-
- delete object;
- }
-
- engine.collectGarbage();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
-
- QVERIFY(source.value == 0);
-}
-
-class QListQObjectMethodsObject : public QObject
-{
- Q_OBJECT
-public:
- QListQObjectMethodsObject() {
- m_objects.append(new MyQmlObject());
- m_objects.append(new MyQmlObject());
- }
-
- ~QListQObjectMethodsObject() {
- qDeleteAll(m_objects);
- }
-
-public slots:
- QList<QObject *> getObjects() { return m_objects; }
-
-private:
- QList<QObject *> m_objects;
-};
-
-// Tests that returning a QList<QObject*> from a method works
-void tst_qdeclarativeecmascript::qlistqobjectMethods()
-{
- QListQObjectMethodsObject obj;
- QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
- context->setContextObject(&obj);
-
- QDeclarativeComponent component(&engine, testFileUrl("qlistqobjectMethods.qml"));
-
- QObject *object = component.create(context);
-
- QCOMPARE(object->property("test").toInt(), 2);
- QCOMPARE(object->property("test2").toBool(), true);
-
- delete object;
- delete context;
-}
-
-// QTBUG-9205
-void tst_qdeclarativeecmascript::strictlyEquals()
-{
- QDeclarativeComponent component(&engine, testFileUrl("strictlyEquals.qml"));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test1").toBool(), true);
- QCOMPARE(object->property("test2").toBool(), true);
- QCOMPARE(object->property("test3").toBool(), true);
- QCOMPARE(object->property("test4").toBool(), true);
- QCOMPARE(object->property("test5").toBool(), true);
- QCOMPARE(object->property("test6").toBool(), true);
- QCOMPARE(object->property("test7").toBool(), true);
- QCOMPARE(object->property("test8").toBool(), true);
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::compiled()
-{
- QDeclarativeComponent component(&engine, testFileUrl("compiled.qml"));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test1").toReal(), qreal(15.7));
- QCOMPARE(object->property("test2").toReal(), qreal(-6.7));
- QCOMPARE(object->property("test3").toBool(), true);
- QCOMPARE(object->property("test4").toBool(), false);
- QCOMPARE(object->property("test5").toBool(), false);
- QCOMPARE(object->property("test6").toBool(), true);
-
- QCOMPARE(object->property("test7").toInt(), 185);
- QCOMPARE(object->property("test8").toInt(), 167);
- QCOMPARE(object->property("test9").toBool(), true);
- QCOMPARE(object->property("test10").toBool(), false);
- QCOMPARE(object->property("test11").toBool(), false);
- QCOMPARE(object->property("test12").toBool(), true);
-
- QCOMPARE(object->property("test13").toString(), QLatin1String("HelloWorld"));
- QCOMPARE(object->property("test14").toString(), QLatin1String("Hello World"));
- QCOMPARE(object->property("test15").toBool(), false);
- QCOMPARE(object->property("test16").toBool(), true);
-
- QCOMPARE(object->property("test17").toInt(), 5);
- QCOMPARE(object->property("test18").toReal(), qreal(176));
- QCOMPARE(object->property("test19").toInt(), 7);
- QCOMPARE(object->property("test20").toReal(), qreal(6.7));
- QCOMPARE(object->property("test21").toString(), QLatin1String("6.7"));
- QCOMPARE(object->property("test22").toString(), QLatin1String("!"));
- QCOMPARE(object->property("test23").toBool(), true);
- QCOMPARE(qvariant_cast<QColor>(object->property("test24")), QColor(0x11,0x22,0x33));
- QCOMPARE(qvariant_cast<QColor>(object->property("test25")), QColor(0x11,0x22,0x33,0xAA));
-
- delete object;
-}
-
-// Test that numbers assigned in bindings as strings work consistently
-void tst_qdeclarativeecmascript::numberAssignment()
-{
- QDeclarativeComponent component(&engine, testFileUrl("numberAssignment.qml"));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test1"), QVariant((qreal)6.7));
- QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
- QCOMPARE(object->property("test2"), QVariant((qreal)6.7));
- QCOMPARE(object->property("test3"), QVariant((qreal)6));
- QCOMPARE(object->property("test4"), QVariant((qreal)6));
-
- QCOMPARE(object->property("test5"), QVariant((int)7));
- QCOMPARE(object->property("test6"), QVariant((int)7));
- QCOMPARE(object->property("test7"), QVariant((int)6));
- QCOMPARE(object->property("test8"), QVariant((int)6));
-
- QCOMPARE(object->property("test9"), QVariant((unsigned int)7));
- QCOMPARE(object->property("test10"), QVariant((unsigned int)7));
- QCOMPARE(object->property("test11"), QVariant((unsigned int)6));
- QCOMPARE(object->property("test12"), QVariant((unsigned int)6));
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::propertySplicing()
-{
- QDeclarativeComponent component(&engine, testFileUrl("propertySplicing.qml"));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
-}
-
-// QTBUG-16683
-void tst_qdeclarativeecmascript::signalWithUnknownTypes()
-{
- QDeclarativeComponent component(&engine, testFileUrl("signalWithUnknownTypes.qml"));
-
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- MyQmlObject::MyType type;
- type.value = 0x8971123;
- emit object->signalWithUnknownType(type);
-
- MyQmlObject::MyType result = qvariant_cast<MyQmlObject::MyType>(object->variant());
-
- QCOMPARE(result.value, type.value);
-
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::signalWithJSValueInVariant_data()
-{
- QTest::addColumn<QString>("expression");
- QTest::addColumn<QString>("compare");
-
- QString compareStrict("(function(a, b) { return a === b; })");
- QTest::newRow("true") << "true" << compareStrict;
- QTest::newRow("undefined") << "undefined" << compareStrict;
- QTest::newRow("null") << "null" << compareStrict;
- QTest::newRow("123") << "123" << compareStrict;
- QTest::newRow("'ciao'") << "'ciao'" << compareStrict;
-
- QString comparePropertiesStrict(
- "(function(a, b) {"
- " if (typeof b != 'object')"
- " return a === b;"
- " var props = Object.getOwnPropertyNames(b);"
- " for (var i = 0; i < props.length; ++i) {"
- " var p = props[i];"
- " return arguments.callee(a[p], b[p]);"
- " }"
- "})");
- QTest::newRow("{ foo: 'bar' }") << "({ foo: 'bar' })" << comparePropertiesStrict;
- QTest::newRow("[10,20,30]") << "[10,20,30]" << comparePropertiesStrict;
-}
-
-void tst_qdeclarativeecmascript::signalWithJSValueInVariant()
-{
- QFETCH(QString, expression);
- QFETCH(QString, compare);
-
- QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
- QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
- QVERIFY(object != 0);
-
- QJSValue value = engine.evaluate(expression);
- QVERIFY(!engine.hasUncaughtException());
- object->setProperty("expression", expression);
- object->setProperty("compare", compare);
- object->setProperty("pass", false);
-
- emit object->signalWithVariant(QVariant::fromValue(value));
- QVERIFY(object->property("pass").toBool());
-}
-
-void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines_data()
-{
- signalWithJSValueInVariant_data();
-}
-
-void tst_qdeclarativeecmascript::signalWithJSValueInVariant_twoEngines()
-{
- QFETCH(QString, expression);
- QFETCH(QString, compare);
-
- QDeclarativeComponent component(&engine, testFileUrl("signalWithJSValueInVariant.qml"));
- QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
- QVERIFY(object != 0);
-
- QJSEngine engine2;
- QJSValue value = engine2.evaluate(expression);
- QVERIFY(!engine2.hasUncaughtException());
- object->setProperty("expression", expression);
- object->setProperty("compare", compare);
- object->setProperty("pass", false);
-
- QTest::ignoreMessage(QtWarningMsg, "JSValue can't be rassigned to an another engine.");
- emit object->signalWithVariant(QVariant::fromValue(value));
- QVERIFY(!object->property("pass").toBool());
-}
-
-void tst_qdeclarativeecmascript::signalWithQJSValue_data()
-{
- signalWithJSValueInVariant_data();
-}
-
-void tst_qdeclarativeecmascript::signalWithQJSValue()
-{
- QFETCH(QString, expression);
- QFETCH(QString, compare);
-
- QDeclarativeComponent component(&engine, testFileUrl("signalWithQJSValue.qml"));
- QScopedPointer<MyQmlObject> object(qobject_cast<MyQmlObject *>(component.create()));
- QVERIFY(object != 0);
-
- QJSValue value = engine.evaluate(expression);
- QVERIFY(!engine.hasUncaughtException());
- object->setProperty("expression", expression);
- object->setProperty("compare", compare);
- object->setProperty("pass", false);
-
- emit object->signalWithQJSValue(value);
-
- QVERIFY(object->property("pass").toBool());
- QVERIFY(object->qjsvalue().strictlyEquals(value));
-}
-
-void tst_qdeclarativeecmascript::moduleApi_data()
-{
- QTest::addColumn<QUrl>("testfile");
- QTest::addColumn<QString>("errorMessage");
- QTest::addColumn<QStringList>("warningMessages");
- QTest::addColumn<QStringList>("readProperties");
- QTest::addColumn<QVariantList>("readExpectedValues");
- QTest::addColumn<QStringList>("writeProperties");
- QTest::addColumn<QVariantList>("writeValues");
- QTest::addColumn<QStringList>("readBackProperties");
- QTest::addColumn<QVariantList>("readBackExpectedValues");
-
- QTest::newRow("qobject, register + read + method")
- << testFileUrl("moduleapi/qobjectModuleApi.qml")
- << QString()
- << QStringList()
- << (QStringList() << "existingUriTest" << "qobjectTest" << "qobjectMethodTest"
- << "qobjectMinorVersionTest" << "qobjectMajorVersionTest" << "qobjectParentedTest")
- << (QVariantList() << 20 << 20 << 1 << 20 << 20 << 26)
- << QStringList()
- << QVariantList()
- << QStringList()
- << QVariantList();
-
- QTest::newRow("script, register + read")
- << testFileUrl("moduleapi/scriptModuleApi.qml")
- << QString()
- << QStringList()
- << (QStringList() << "scriptTest")
- << (QVariantList() << 13)
- << QStringList()
- << QVariantList()
- << QStringList()
- << QVariantList();
-
- QTest::newRow("qobject, caching + read")
- << testFileUrl("moduleapi/qobjectModuleApiCaching.qml")
- << QString()
- << QStringList()
- << (QStringList() << "existingUriTest" << "qobjectParentedTest")
- << (QVariantList() << 20 << 26) // 26, shouldn't have incremented to 27.
- << QStringList()
- << QVariantList()
- << QStringList()
- << QVariantList();
-
- QTest::newRow("script, caching + read")
- << testFileUrl("moduleapi/scriptModuleApiCaching.qml")
- << QString()
- << QStringList()
- << (QStringList() << "scriptTest")
- << (QVariantList() << 13) // 13, shouldn't have incremented to 14.
- << QStringList()
- << QVariantList()
- << QStringList()
- << QVariantList();
-
- QTest::newRow("qobject, writing + readonly constraints")
- << testFileUrl("moduleapi/qobjectModuleApiWriting.qml")
- << QString()
- << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/qobjectModuleApiWriting.qml").toLocalFile() + QLatin1String(":14: Error: Cannot assign to read-only property \"qobjectTestProperty\"")))
- << (QStringList() << "readOnlyProperty" << "writableProperty")
- << (QVariantList() << 20 << 50)
- << (QStringList() << "firstProperty" << "writableProperty")
- << (QVariantList() << 30 << 30)
- << (QStringList() << "readOnlyProperty" << "writableProperty")
- << (QVariantList() << 20 << 30);
-
- QTest::newRow("script, writing + readonly constraints")
- << testFileUrl("moduleapi/scriptModuleApiWriting.qml")
- << QString()
- << (QStringList() << QString(QLatin1String("file://") + testFileUrl("moduleapi/scriptModuleApiWriting.qml").toLocalFile() + QLatin1String(":21: Error: Cannot assign to read-only property \"scriptTestProperty\"")))
- << (QStringList() << "readBack" << "unchanged")
- << (QVariantList() << 13 << 42)
- << (QStringList() << "firstProperty" << "secondProperty")
- << (QVariantList() << 30 << 30)
- << (QStringList() << "readBack" << "unchanged")
- << (QVariantList() << 30 << 42);
-
- QTest::newRow("qobject module API enum values in JS")
- << testFileUrl("moduleapi/qobjectModuleApiEnums.qml")
- << QString()
- << QStringList()
- << (QStringList() << "enumValue" << "enumMethod")
- << (QVariantList() << 42 << 30)
- << QStringList()
- << QVariantList()
- << QStringList()
- << QVariantList();
-
- QTest::newRow("qobject, invalid major version fail")
- << testFileUrl("moduleapi/moduleApiMajorVersionFail.qml")
- << QString("QDeclarativeComponent: Component is not ready")
- << QStringList()
- << QStringList()
- << QVariantList()
- << QStringList()
- << QVariantList()
- << QStringList()
- << QVariantList();
-
- QTest::newRow("qobject, invalid minor version fail")
- << testFileUrl("moduleapi/moduleApiMinorVersionFail.qml")
- << QString("QDeclarativeComponent: Component is not ready")
- << QStringList()
- << QStringList()
- << QVariantList()
- << QStringList()
- << QVariantList()
- << QStringList()
- << QVariantList();
-}
-
-void tst_qdeclarativeecmascript::moduleApi()
-{
- QFETCH(QUrl, testfile);
- QFETCH(QString, errorMessage);
- QFETCH(QStringList, warningMessages);
- QFETCH(QStringList, readProperties);
- QFETCH(QVariantList, readExpectedValues);
- QFETCH(QStringList, writeProperties);
- QFETCH(QVariantList, writeValues);
- QFETCH(QStringList, readBackProperties);
- QFETCH(QVariantList, readBackExpectedValues);
-
- QDeclarativeComponent component(&engine, testfile);
-
- if (!errorMessage.isEmpty())
- QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
-
- if (warningMessages.size())
- foreach (const QString &warning, warningMessages)
- QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
-
- QObject *object = component.create();
- if (!errorMessage.isEmpty()) {
- QVERIFY(object == 0);
- } else {
- QVERIFY(object != 0);
- for (int i = 0; i < readProperties.size(); ++i)
- QCOMPARE(object->property(readProperties.at(i).toAscii().constData()), readExpectedValues.at(i));
- for (int i = 0; i < writeProperties.size(); ++i)
- QVERIFY(object->setProperty(writeProperties.at(i).toAscii().constData(), writeValues.at(i)));
- for (int i = 0; i < readBackProperties.size(); ++i)
- QCOMPARE(object->property(readBackProperties.at(i).toAscii().constData()), readBackExpectedValues.at(i));
- delete object;
- }
-}
-
-void tst_qdeclarativeecmascript::importScripts_data()
-{
- QTest::addColumn<QUrl>("testfile");
- QTest::addColumn<QString>("errorMessage");
- QTest::addColumn<QStringList>("warningMessages");
- QTest::addColumn<QStringList>("propertyNames");
- QTest::addColumn<QVariantList>("propertyValues");
-
- QTest::newRow("basic functionality")
- << testFileUrl("jsimport/testImport.qml")
- << QString()
- << QStringList()
- << (QStringList() << QLatin1String("importedScriptStringValue")
- << QLatin1String("importedScriptFunctionValue")
- << QLatin1String("importedModuleAttachedPropertyValue")
- << QLatin1String("importedModuleEnumValue"))
- << (QVariantList() << QVariant(QLatin1String("Hello, World!"))
- << QVariant(20)
- << QVariant(19)
- << QVariant(2));
-
- QTest::newRow("import scoping")
- << testFileUrl("jsimport/testImportScoping.qml")
- << QString()
- << QStringList()
- << (QStringList() << QLatin1String("componentError"))
- << (QVariantList() << QVariant(5));
-
- QTest::newRow("parent scope shouldn't be inherited by import with imports")
- << testFileUrl("jsimportfail/failOne.qml")
- << QString()
- << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failOne.qml").toLocalFile() + QLatin1String(":6: TypeError: Cannot call method 'greetingString' of undefined")))
- << (QStringList() << QLatin1String("importScriptFunctionValue"))
- << (QVariantList() << QVariant(QString()));
-
- QTest::newRow("javascript imports in an import should be private to the import scope")
- << testFileUrl("jsimportfail/failTwo.qml")
- << QString()
- << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failTwo.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: ImportOneJs")))
- << (QStringList() << QLatin1String("importScriptFunctionValue"))
- << (QVariantList() << QVariant(QString()));
-
- QTest::newRow("module imports in an import should be private to the import scope")
- << testFileUrl("jsimportfail/failThree.qml")
- << QString()
- << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failThree.qml").toLocalFile() + QLatin1String(":7: TypeError: Cannot read property 'JsQtTest' of undefined")))
- << (QStringList() << QLatin1String("importedModuleAttachedPropertyValue"))
- << (QVariantList() << QVariant(false));
-
- QTest::newRow("typenames in an import should be private to the import scope")
- << testFileUrl("jsimportfail/failFour.qml")
- << QString()
- << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/failFour.qml").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: JsQtTest")))
- << (QStringList() << QLatin1String("importedModuleEnumValue"))
- << (QVariantList() << QVariant(0));
-
- QTest::newRow("import with imports has it's own activation scope")
- << testFileUrl("jsimportfail/failFive.qml")
- << QString()
- << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importWithImports.js").toLocalFile() + QLatin1String(":8: ReferenceError: Can't find variable: Component")))
- << (QStringList() << QLatin1String("componentError"))
- << (QVariantList() << QVariant(0));
-
- QTest::newRow("import pragma library script")
- << testFileUrl("jsimport/testImportPragmaLibrary.qml")
- << QString()
- << QStringList()
- << (QStringList() << QLatin1String("testValue"))
- << (QVariantList() << QVariant(31));
-
- QTest::newRow("pragma library imports shouldn't inherit parent imports or scope")
- << testFileUrl("jsimportfail/testImportPragmaLibrary.qml")
- << QString()
- << (QStringList() << QString(QLatin1String("file://") + testFileUrl("jsimportfail/importPragmaLibrary.js").toLocalFile() + QLatin1String(":6: ReferenceError: Can't find variable: Component")))
- << (QStringList() << QLatin1String("testValue"))
- << (QVariantList() << QVariant(0));
-
- QTest::newRow("import pragma library script which has an import")
- << testFileUrl("jsimport/testImportPragmaLibraryWithImports.qml")
- << QString()
- << QStringList()
- << (QStringList() << QLatin1String("testValue"))
- << (QVariantList() << QVariant(55));
-
- QTest::newRow("import pragma library script which has a pragma library import")
- << testFileUrl("jsimport/testImportPragmaLibraryWithPragmaLibraryImports.qml")
- << QString()
- << QStringList()
- << (QStringList() << QLatin1String("testValue"))
- << (QVariantList() << QVariant(18));
-
- QTest::newRow("import module api into js import")
- << testFileUrl("jsimport/testImportModuleApi.qml")
- << QString()
- << QStringList()
- << (QStringList() << QLatin1String("testValue"))
- << (QVariantList() << QVariant(20));
-}
-
-void tst_qdeclarativeecmascript::importScripts()
-{
- QFETCH(QUrl, testfile);
- QFETCH(QString, errorMessage);
- QFETCH(QStringList, warningMessages);
- QFETCH(QStringList, propertyNames);
- QFETCH(QVariantList, propertyValues);
-
- QDeclarativeComponent component(&engine, testfile);
-
- if (!errorMessage.isEmpty())
- QTest::ignoreMessage(QtWarningMsg, errorMessage.toAscii().constData());
-
- if (warningMessages.size())
- foreach (const QString &warning, warningMessages)
- QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
-
- QObject *object = component.create();
- if (!errorMessage.isEmpty()) {
- QVERIFY(object == 0);
- } else {
- QVERIFY(object != 0);
- for (int i = 0; i < propertyNames.size(); ++i)
- QCOMPARE(object->property(propertyNames.at(i).toAscii().constData()), propertyValues.at(i));
- delete object;
- }
-}
-
-void tst_qdeclarativeecmascript::scarceResources_other()
-{
- /* These tests require knowledge of state, since we test values after
- performing signal or function invocation. */
-
- QPixmap origPixmap(100, 100);
- origPixmap.fill(Qt::blue);
- QString srp_name, expectedWarning;
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
- ScarceResourceObject *eo = 0;
- QObject *srsc = 0;
- QObject *object = 0;
-
- /* property var semantics */
-
- // test that scarce resources are handled properly in signal invocation
- QDeclarativeComponent varComponentTen(&engine, testFileUrl("scarceResourceSignal.var.qml"));
- object = varComponentTen.create();
- srsc = object->findChild<QObject*>("srsc");
- QVERIFY(srsc);
- QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
- QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
- eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
- QMetaObject::invokeMethod(srsc, "testSignal");
- QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
- QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
- eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
- QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
- QVERIFY(srsc->property("scarceResourceCopy").isValid());
- QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
- eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
- QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
- delete object;
-
- // test that scarce resources are handled properly from js functions in qml files
- QDeclarativeComponent varComponentEleven(&engine, testFileUrl("scarceResourceFunction.var.qml"));
- object = varComponentEleven.create();
- QVERIFY(object != 0);
- QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
- eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
- QMetaObject::invokeMethod(object, "retrieveScarceResource");
- QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
- QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
- eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
- QMetaObject::invokeMethod(object, "releaseScarceResource");
- QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
- eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
- QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
- delete object;
-
- // test that if an exception occurs while invoking js function from cpp, that the resources are released.
- QDeclarativeComponent varComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.var.qml"));
- object = varComponentTwelve.create();
- QVERIFY(object != 0);
- QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
- eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
- srp_name = object->property("srp_name").toString();
- expectedWarning = varComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
- QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
- QMetaObject::invokeMethod(object, "retrieveScarceResource");
- QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
- eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
- QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
- delete object;
-
- // test that if an Item which has JS ownership but has a scarce resource property is garbage collected,
- // that the scarce resource is removed from the engine's list of scarce resources to clean up.
- QDeclarativeComponent varComponentThirteen(&engine, testFileUrl("scarceResourceObjectGc.var.qml"));
- object = varComponentThirteen.create();
- QVERIFY(object != 0);
- QVERIFY(!object->property("varProperty").isValid()); // not assigned yet
- QMetaObject::invokeMethod(object, "assignVarProperty");
- QVERIFY(ep->scarceResources.isEmpty()); // the scarce resource is a VME property.
- QMetaObject::invokeMethod(object, "deassignVarProperty");
- QVERIFY(ep->scarceResources.isEmpty()); // should still be empty; the resource should have been released on gc.
- delete object;
-
- /* property variant semantics */
-
- // test that scarce resources are handled properly in signal invocation
- QDeclarativeComponent variantComponentTen(&engine, testFileUrl("scarceResourceSignal.variant.qml"));
- object = variantComponentTen.create();
- QVERIFY(object != 0);
- srsc = object->findChild<QObject*>("srsc");
- QVERIFY(srsc);
- QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // hasn't been instantiated yet.
- QCOMPARE(srsc->property("width"), QVariant(5)); // default value is 5.
- eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
- QMetaObject::invokeMethod(srsc, "testSignal");
- QVERIFY(!srsc->property("scarceResourceCopy").isValid()); // still hasn't been instantiated
- QCOMPARE(srsc->property("width"), QVariant(10)); // but width was assigned to 10.
- eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(eo->scarceResourceIsDetached()); // should still be no other copies of it at this stage.
- QMetaObject::invokeMethod(srsc, "testSignal2"); // assigns scarceResourceCopy to the scarce pixmap.
- QVERIFY(srsc->property("scarceResourceCopy").isValid());
- QCOMPARE(srsc->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
- eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(!(eo->scarceResourceIsDetached())); // should be another copy of the resource now.
- QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
- delete object;
-
- // test that scarce resources are handled properly from js functions in qml files
- QDeclarativeComponent variantComponentEleven(&engine, testFileUrl("scarceResourceFunction.variant.qml"));
- object = variantComponentEleven.create();
- QVERIFY(object != 0);
- QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
- eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
- QMetaObject::invokeMethod(object, "retrieveScarceResource");
- QVERIFY(object->property("scarceResourceCopy").isValid()); // assigned, so should be valid.
- QCOMPARE(object->property("scarceResourceCopy").value<QPixmap>(), origPixmap);
- eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(!eo->scarceResourceIsDetached()); // should be a copy of the resource at this stage.
- QMetaObject::invokeMethod(object, "releaseScarceResource");
- QVERIFY(!object->property("scarceResourceCopy").isValid()); // just released, so should not be valid
- eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
- QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
- delete object;
-
- // test that if an exception occurs while invoking js function from cpp, that the resources are released.
- QDeclarativeComponent variantComponentTwelve(&engine, testFileUrl("scarceResourceFunctionFail.variant.qml"));
- object = variantComponentTwelve.create();
- QVERIFY(object != 0);
- QVERIFY(!object->property("scarceResourceCopy").isValid()); // not yet assigned, so should not be valid
- eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
- srp_name = object->property("srp_name").toString();
- expectedWarning = variantComponentTwelve.url().toString() + QLatin1String(":16: TypeError: Property 'scarceResource' of object ") + srp_name + QLatin1String(" is not a function");
- QTest::ignoreMessage(QtWarningMsg, qPrintable(expectedWarning)); // we expect a meaningful warning to be printed.
- QMetaObject::invokeMethod(object, "retrieveScarceResource");
- QVERIFY(!object->property("scarceResourceCopy").isValid()); // due to exception, assignment will NOT have occurred.
- eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QVERIFY(eo->scarceResourceIsDetached()); // should be no other copies of it at this stage.
- QVERIFY(ep->scarceResources.isEmpty()); // should have been released by this point.
- delete object;
-}
-
-void tst_qdeclarativeecmascript::scarceResources_data()
-{
- QTest::addColumn<QUrl>("qmlFile");
- QTest::addColumn<bool>("readDetachStatus");
- QTest::addColumn<bool>("expectedDetachStatus");
- QTest::addColumn<QStringList>("propertyNames");
- QTest::addColumn<QVariantList>("expectedValidity");
- QTest::addColumn<QVariantList>("expectedValues");
- QTest::addColumn<QStringList>("expectedErrors");
-
- QPixmap origPixmap(100, 100);
- origPixmap.fill(Qt::blue);
-
- /* property var semantics */
-
- // in the following three cases, the instance created from the component
- // has a property which is a copy of the scarce resource; hence, the
- // resource should NOT be detached prior to deletion of the object instance,
- // unless the resource is destroyed explicitly.
- QTest::newRow("var: import scarce resource copy directly")
- << testFileUrl("scarceResourceCopy.var.qml")
- << true
- << false // won't be detached, because assigned to property and not explicitly released
- << (QStringList() << QLatin1String("scarceResourceCopy"))
- << (QList<QVariant>() << true)
- << (QList<QVariant>() << origPixmap)
- << QStringList();
-
- QTest::newRow("var: import scarce resource copy from JS")
- << testFileUrl("scarceResourceCopyFromJs.var.qml")
- << true
- << false // won't be detached, because assigned to property and not explicitly released
- << (QStringList() << QLatin1String("scarceResourceCopy"))
- << (QList<QVariant>() << true)
- << (QList<QVariant>() << origPixmap)
- << QStringList();
-
- QTest::newRow("var: import released scarce resource copy from JS")
- << testFileUrl("scarceResourceDestroyedCopy.var.qml")
- << true
- << true // explicitly released, so it will be detached
- << (QStringList() << QLatin1String("scarceResourceCopy"))
- << (QList<QVariant>() << false)
- << (QList<QVariant>() << QVariant())
- << QStringList();
-
- // in the following three cases, no other copy should exist in memory,
- // and so it should be detached (unless explicitly preserved).
- QTest::newRow("var: import auto-release SR from JS in binding side-effect")
- << testFileUrl("scarceResourceTest.var.qml")
- << true
- << true // auto released, so it will be detached
- << (QStringList() << QLatin1String("scarceResourceTest"))
- << (QList<QVariant>() << true)
- << (QList<QVariant>() << QVariant(100))
- << QStringList();
- QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
- << testFileUrl("scarceResourceTestPreserve.var.qml")
- << true
- << false // won't be detached because we explicitly preserve it
- << (QStringList() << QLatin1String("scarceResourceTest"))
- << (QList<QVariant>() << true)
- << (QList<QVariant>() << QVariant(100))
- << QStringList();
- QTest::newRow("var: import explicit-preserve SR from JS in binding side-effect")
- << testFileUrl("scarceResourceTestMultiple.var.qml")
- << true
- << true // will be detached because all resources were released manually or automatically.
- << (QStringList() << QLatin1String("scarceResourceTest"))
- << (QList<QVariant>() << true)
- << (QList<QVariant>() << QVariant(100))
- << QStringList();
-
- // In the following three cases, test that scarce resources are handled
- // correctly for imports.
- QTest::newRow("var: import with no binding")
- << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
- << false // cannot check detach status.
- << false
- << QStringList()
- << QList<QVariant>()
- << QList<QVariant>()
- << QStringList();
- QTest::newRow("var: import with binding without explicit preserve")
- << testFileUrl("scarceResourceCopyImportNoBinding.var.qml")
- << false
- << false
- << (QStringList() << QLatin1String("scarceResourceCopy"))
- << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
- << (QList<QVariant>() << QVariant())
- << QStringList();
- QTest::newRow("var: import with explicit release after binding evaluation")
- << testFileUrl("scarceResourceCopyImport.var.qml")
- << false
- << false
- << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
- << (QList<QVariant>() << false << false << false << true) // since property var = JS object reference, by releasing the provider's resource, all handles are invalidated.
- << (QList<QVariant>() << QVariant() << QVariant() << QVariant() << QVariant(true))
- << QStringList();
- QTest::newRow("var: import with different js objects")
- << testFileUrl("scarceResourceCopyImportDifferent.var.qml")
- << false
- << false
- << (QStringList() << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo") << QLatin1String("arePropertiesEqual"))
- << (QList<QVariant>() << false << true << true) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
- << (QList<QVariant>() << QVariant() << QVariant(origPixmap) << QVariant(false))
- << QStringList();
- QTest::newRow("var: import with different js objects and explicit release")
- << testFileUrl("scarceResourceMultipleDifferentNoBinding.var.qml")
- << false
- << false
- << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
- << (QList<QVariant>() << true << false) // invalidating one shouldn't invalidate the other, because they're not references to the same JS object.
- << (QList<QVariant>() << QVariant(origPixmap) << QVariant())
- << QStringList();
- QTest::newRow("var: import with same js objects and explicit release")
- << testFileUrl("scarceResourceMultipleSameNoBinding.var.qml")
- << false
- << false
- << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
- << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
- << (QList<QVariant>() << QVariant() << QVariant())
- << QStringList();
- QTest::newRow("var: binding with same js objects and explicit release")
- << testFileUrl("scarceResourceMultipleSameWithBinding.var.qml")
- << false
- << false
- << (QStringList() << QLatin1String("resourceOne") << QLatin1String("resourceTwo"))
- << (QList<QVariant>() << false << false) // invalidating one should invalidate the other, because they're references to the same JS object.
- << (QList<QVariant>() << QVariant() << QVariant())
- << QStringList();
-
-
- /* property variant semantics */
-
- // in the following three cases, the instance created from the component
- // has a property which is a copy of the scarce resource; hence, the
- // resource should NOT be detached prior to deletion of the object instance,
- // unless the resource is destroyed explicitly.
- QTest::newRow("variant: import scarce resource copy directly")
- << testFileUrl("scarceResourceCopy.variant.qml")
- << true
- << false // won't be detached, because assigned to property and not explicitly released
- << (QStringList() << QLatin1String("scarceResourceCopy"))
- << (QList<QVariant>() << true)
- << (QList<QVariant>() << origPixmap)
- << QStringList();
-
- QTest::newRow("variant: import scarce resource copy from JS")
- << testFileUrl("scarceResourceCopyFromJs.variant.qml")
- << true
- << false // won't be detached, because assigned to property and not explicitly released
- << (QStringList() << QLatin1String("scarceResourceCopy"))
- << (QList<QVariant>() << true)
- << (QList<QVariant>() << origPixmap)
- << QStringList();
-
- QTest::newRow("variant: import released scarce resource copy from JS")
- << testFileUrl("scarceResourceDestroyedCopy.variant.qml")
- << true
- << true // explicitly released, so it will be detached
- << (QStringList() << QLatin1String("scarceResourceCopy"))
- << (QList<QVariant>() << false)
- << (QList<QVariant>() << QVariant())
- << QStringList();
-
- // in the following three cases, no other copy should exist in memory,
- // and so it should be detached (unless explicitly preserved).
- QTest::newRow("variant: import auto-release SR from JS in binding side-effect")
- << testFileUrl("scarceResourceTest.variant.qml")
- << true
- << true // auto released, so it will be detached
- << (QStringList() << QLatin1String("scarceResourceTest"))
- << (QList<QVariant>() << true)
- << (QList<QVariant>() << QVariant(100))
- << QStringList();
- QTest::newRow("variant: import explicit-preserve SR from JS in binding side-effect")
- << testFileUrl("scarceResourceTestPreserve.variant.qml")
- << true
- << false // won't be detached because we explicitly preserve it
- << (QStringList() << QLatin1String("scarceResourceTest"))
- << (QList<QVariant>() << true)
- << (QList<QVariant>() << QVariant(100))
- << QStringList();
- QTest::newRow("variant: import multiple scarce resources")
- << testFileUrl("scarceResourceTestMultiple.variant.qml")
- << true
- << true // will be detached because all resources were released manually or automatically.
- << (QStringList() << QLatin1String("scarceResourceTest"))
- << (QList<QVariant>() << true)
- << (QList<QVariant>() << QVariant(100))
- << QStringList();
-
- // In the following three cases, test that scarce resources are handled
- // correctly for imports.
- QTest::newRow("variant: import with no binding")
- << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
- << false // cannot check detach status.
- << false
- << QStringList()
- << QList<QVariant>()
- << QList<QVariant>()
- << QStringList();
- QTest::newRow("variant: import with binding without explicit preserve")
- << testFileUrl("scarceResourceCopyImportNoBinding.variant.qml")
- << false
- << false
- << (QStringList() << QLatin1String("scarceResourceCopy"))
- << (QList<QVariant>() << false) // will have been released prior to evaluation of binding.
- << (QList<QVariant>() << QVariant())
- << QStringList();
- QTest::newRow("variant: import with explicit release after binding evaluation")
- << testFileUrl("scarceResourceCopyImport.variant.qml")
- << false
- << false
- << (QStringList() << QLatin1String("scarceResourceImportedCopy") << QLatin1String("scarceResourceAssignedCopyOne") << QLatin1String("scarceResourceAssignedCopyTwo"))
- << (QList<QVariant>() << true << true << false) // since property variant = variant copy, releasing the provider's resource does not invalidate previously assigned copies.
- << (QList<QVariant>() << origPixmap << origPixmap << QVariant())
- << QStringList();
-}
-
-void tst_qdeclarativeecmascript::scarceResources()
-{
- QFETCH(QUrl, qmlFile);
- QFETCH(bool, readDetachStatus);
- QFETCH(bool, expectedDetachStatus);
- QFETCH(QStringList, propertyNames);
- QFETCH(QVariantList, expectedValidity);
- QFETCH(QVariantList, expectedValues);
- QFETCH(QStringList, expectedErrors);
-
- QDeclarativeEnginePrivate *ep = QDeclarativeEnginePrivate::get(&engine);
- ScarceResourceObject *eo = 0;
- QObject *object = 0;
-
- QDeclarativeComponent c(&engine, qmlFile);
- object = c.create();
- QVERIFY(object != 0);
- for (int i = 0; i < propertyNames.size(); ++i) {
- QString prop = propertyNames.at(i);
- bool validity = expectedValidity.at(i).toBool();
- QVariant value = expectedValues.at(i);
-
- QCOMPARE(object->property(prop.toLatin1().constData()).isValid(), validity);
- if (value.type() == QVariant::Int) {
- QCOMPARE(object->property(prop.toLatin1().constData()).toInt(), value.toInt());
- } else if (value.type() == QVariant::Pixmap) {
- QCOMPARE(object->property(prop.toLatin1().constData()).value<QPixmap>(), value.value<QPixmap>());
- }
- }
-
- if (readDetachStatus) {
- eo = qobject_cast<ScarceResourceObject*>(QDeclarativeProperty::read(object, "a").value<QObject*>());
- QCOMPARE(eo->scarceResourceIsDetached(), expectedDetachStatus);
- }
-
- QVERIFY(ep->scarceResources.isEmpty());
- delete object;
-}
-
-void tst_qdeclarativeecmascript::propertyChangeSlots()
-{
- // ensure that allowable property names are allowed and onPropertyNameChanged slots are generated correctly.
- QDeclarativeComponent component(&engine, testFileUrl("changeslots/propertyChangeSlots.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- delete object;
-
- // ensure that invalid property names fail properly.
- QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
- QDeclarativeComponent e1(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.1.qml"));
- QString expectedErrorString = e1.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_nameWithUnderscoreChanged\"");
- QCOMPARE(e1.errors().at(0).toString(), expectedErrorString);
- object = e1.create();
- QVERIFY(object == 0);
- delete object;
-
- QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
- QDeclarativeComponent e2(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.2.qml"));
- expectedErrorString = e2.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on____nameWithUnderscoresChanged\"");
- QCOMPARE(e2.errors().at(0).toString(), expectedErrorString);
- object = e2.create();
- QVERIFY(object == 0);
- delete object;
-
- QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
- QDeclarativeComponent e3(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.3.qml"));
- expectedErrorString = e3.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on$NameWithDollarsignChanged\"");
- QCOMPARE(e3.errors().at(0).toString(), expectedErrorString);
- object = e3.create();
- QVERIFY(object == 0);
- delete object;
-
- QTest::ignoreMessage(QtWarningMsg, "QDeclarativeComponent: Component is not ready");
- QDeclarativeComponent e4(&engine, testFileUrl("changeslots/propertyChangeSlotErrors.4.qml"));
- expectedErrorString = e4.url().toString() + QLatin1String(":9:5: Cannot assign to non-existent property \"on_6NameWithUnderscoreNumberChanged\"");
- QCOMPARE(e4.errors().at(0).toString(), expectedErrorString);
- object = e4.create();
- QVERIFY(object == 0);
- delete object;
-}
-
-void tst_qdeclarativeecmascript::propertyVar_data()
-{
- QTest::addColumn<QUrl>("qmlFile");
-
- // valid
- QTest::newRow("non-bindable object subproperty changed") << testFileUrl("propertyVar.1.qml");
- QTest::newRow("non-bindable object changed") << testFileUrl("propertyVar.2.qml");
- QTest::newRow("primitive changed") << testFileUrl("propertyVar.3.qml");
- QTest::newRow("javascript array modification") << testFileUrl("propertyVar.4.qml");
- QTest::newRow("javascript map modification") << testFileUrl("propertyVar.5.qml");
- QTest::newRow("javascript array assignment") << testFileUrl("propertyVar.6.qml");
- QTest::newRow("javascript map assignment") << testFileUrl("propertyVar.7.qml");
- QTest::newRow("literal property assignment") << testFileUrl("propertyVar.8.qml");
- QTest::newRow("qobject property assignment") << testFileUrl("propertyVar.9.qml");
- QTest::newRow("base class var property assignment") << testFileUrl("propertyVar.10.qml");
-}
-
-void tst_qdeclarativeecmascript::propertyVar()
-{
- QFETCH(QUrl, qmlFile);
-
- QDeclarativeComponent component(&engine, qmlFile);
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
-}
-
-// Tests that we can write QVariant values to var properties from C++
-void tst_qdeclarativeecmascript::propertyVarCpp()
-{
- QObject *object = 0;
-
- // ensure that writing to and reading from a var property from cpp works as required.
- // Literal values stored in var properties can be read and written as QVariants
- // of a specific type, whereas object values are read as QVariantMaps.
- QDeclarativeComponent component(&engine, testFileUrl("propertyVarCpp.qml"));
- object = component.create();
- QVERIFY(object != 0);
- // assign int to property var that currently has int assigned
- QVERIFY(object->setProperty("varProperty", QVariant::fromValue(10)));
- QCOMPARE(object->property("varBound"), QVariant(15));
- QCOMPARE(object->property("intBound"), QVariant(15));
- QCOMPARE(object->property("varProperty").userType(), (int)QVariant::Int);
- QCOMPARE(object->property("varBound").userType(), (int)QVariant::Int);
- // assign string to property var that current has bool assigned
- QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::Bool);
- QVERIFY(object->setProperty("varProperty2", QVariant(QLatin1String("randomString"))));
- QCOMPARE(object->property("varProperty2"), QVariant(QLatin1String("randomString")));
- QCOMPARE(object->property("varProperty2").userType(), (int)QVariant::String);
- // now enforce behaviour when accessing JavaScript objects from cpp.
- QCOMPARE(object->property("jsobject").userType(), (int)QVariant::Map);
- delete object;
-}
-
-static void gc(QDeclarativeEngine &engine)
-{
- engine.collectGarbage();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
-}
-
-void tst_qdeclarativeecmascript::propertyVarOwnership()
-{
- // Referenced JS objects are not collected
- {
- QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- QCOMPARE(object->property("test").toBool(), false);
- QMetaObject::invokeMethod(object, "runTest");
- QCOMPARE(object->property("test").toBool(), true);
- delete object;
- }
- // Referenced JS objects are not collected
- {
- QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.2.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- QCOMPARE(object->property("test").toBool(), false);
- QMetaObject::invokeMethod(object, "runTest");
- QCOMPARE(object->property("test").toBool(), true);
- delete object;
- }
- // Qt objects are not collected until they've been dereferenced
- {
- QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.3.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test2").toBool(), false);
- QCOMPARE(object->property("test2").toBool(), false);
-
- QMetaObject::invokeMethod(object, "runTest");
- QCOMPARE(object->property("test1").toBool(), true);
-
- QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
- QVERIFY(!referencedObject.isNull());
- gc(engine);
- QVERIFY(!referencedObject.isNull());
-
- QMetaObject::invokeMethod(object, "runTest2");
- QCOMPARE(object->property("test2").toBool(), true);
- gc(engine);
- QVERIFY(referencedObject.isNull());
-
- delete object;
- }
- // Self reference does not prevent Qt object collection
- {
- QDeclarativeComponent component(&engine, testFileUrl("propertyVarOwnership.4.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toBool(), true);
-
- QPointer<QObject> referencedObject = object->property("object").value<QObject*>();
- QVERIFY(!referencedObject.isNull());
- gc(engine);
- QVERIFY(!referencedObject.isNull());
-
- QMetaObject::invokeMethod(object, "runTest");
- gc(engine);
- QVERIFY(referencedObject.isNull());
-
- delete object;
- }
-}
-
-void tst_qdeclarativeecmascript::propertyVarImplicitOwnership()
-{
- // The childObject has a reference to a different QObject. We want to ensure
- // that the different item will not be cleaned up until required. IE, the childObject
- // has implicit ownership of the constructed QObject.
- QDeclarativeComponent component(&engine, testFileUrl("propertyVarImplicitOwnership.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- QMetaObject::invokeMethod(object, "assignCircular");
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
- QCoreApplication::processEvents();
- QObject *rootObject = object->property("vp").value<QObject*>();
- QVERIFY(rootObject != 0);
- QObject *childObject = rootObject->findChild<QObject*>("text");
- QVERIFY(childObject != 0);
- QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
- QCOMPARE(childObject->property("textCanary").toInt(), 10);
- QMetaObject::invokeMethod(childObject, "constructQObject"); // creates a reference to a constructed QObject.
- QWeakPointer<QObject> qobjectGuard(childObject->property("vp").value<QObject*>()); // get the pointer prior to processing deleteLater events.
- QVERIFY(!qobjectGuard.isNull());
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
- QCoreApplication::processEvents();
- QVERIFY(!qobjectGuard.isNull());
- QMetaObject::invokeMethod(object, "deassignCircular");
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
- QCoreApplication::processEvents();
- QVERIFY(qobjectGuard.isNull()); // should have been collected now.
- delete object;
-}
-
-void tst_qdeclarativeecmascript::propertyVarReparent()
-{
- // ensure that nothing breaks if we re-parent objects
- QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- QMetaObject::invokeMethod(object, "assignVarProp");
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
- QCoreApplication::processEvents();
- QObject *rect = object->property("vp").value<QObject*>();
- QObject *text = rect->findChild<QObject*>("textOne");
- QObject *text2 = rect->findChild<QObject*>("textTwo");
- QWeakPointer<QObject> rectGuard(rect);
- QWeakPointer<QObject> textGuard(text);
- QWeakPointer<QObject> text2Guard(text2);
- QVERIFY(!rectGuard.isNull());
- QVERIFY(!textGuard.isNull());
- QVERIFY(!text2Guard.isNull());
- QCOMPARE(text->property("textCanary").toInt(), 11);
- QCOMPARE(text2->property("textCanary").toInt(), 12);
- // now construct an image which we will reparent.
- QMetaObject::invokeMethod(text2, "constructQObject");
- QObject *image = text2->property("vp").value<QObject*>();
- QWeakPointer<QObject> imageGuard(image);
- QVERIFY(!imageGuard.isNull());
- QCOMPARE(image->property("imageCanary").toInt(), 13);
- // now reparent the "Image" object (currently, it has JS ownership)
- image->setParent(text); // shouldn't be collected after deassignVp now, since has a parent.
- QMetaObject::invokeMethod(text2, "deassignVp");
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
- QCoreApplication::processEvents();
- QCOMPARE(text->property("textCanary").toInt(), 11);
- QCOMPARE(text2->property("textCanary").toInt(), 22);
- QVERIFY(!imageGuard.isNull()); // should still be alive.
- QCOMPARE(image->property("imageCanary").toInt(), 13); // still able to access var properties
- QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
- QCoreApplication::processEvents();
- QVERIFY(imageGuard.isNull()); // should now have been deleted, due to parent being deleted.
- delete object;
-}
-
-void tst_qdeclarativeecmascript::propertyVarReparentNullContext()
-{
- // sometimes reparenting can cause problems
- // (eg, if the ctxt is collected, varproperties are no longer available)
- // this test ensures that no crash occurs in that situation.
- QDeclarativeComponent component(&engine, testFileUrl("propertyVar.reparent.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- QMetaObject::invokeMethod(object, "assignVarProp");
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
- QCoreApplication::processEvents();
- QObject *rect = object->property("vp").value<QObject*>();
- QObject *text = rect->findChild<QObject*>("textOne");
- QObject *text2 = rect->findChild<QObject*>("textTwo");
- QWeakPointer<QObject> rectGuard(rect);
- QWeakPointer<QObject> textGuard(text);
- QWeakPointer<QObject> text2Guard(text2);
- QVERIFY(!rectGuard.isNull());
- QVERIFY(!textGuard.isNull());
- QVERIFY(!text2Guard.isNull());
- QCOMPARE(text->property("textCanary").toInt(), 11);
- QCOMPARE(text2->property("textCanary").toInt(), 12);
- // now construct an image which we will reparent.
- QMetaObject::invokeMethod(text2, "constructQObject");
- QObject *image = text2->property("vp").value<QObject*>();
- QWeakPointer<QObject> imageGuard(image);
- QVERIFY(!imageGuard.isNull());
- QCOMPARE(image->property("imageCanary").toInt(), 13);
- // now reparent the "Image" object (currently, it has JS ownership)
- image->setParent(object); // reparented to base object. after deassignVarProp, the ctxt will be invalid.
- QMetaObject::invokeMethod(object, "deassignVarProp"); // now deassign the root-object's vp, causing gc of rect+text+text2
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
- QCoreApplication::processEvents();
- QVERIFY(!imageGuard.isNull()); // should still be alive.
- QVERIFY(!image->property("imageCanary").isValid()); // but varProperties won't be available (null context).
- delete object;
- QVERIFY(imageGuard.isNull()); // should now be dead.
-}
-
-void tst_qdeclarativeecmascript::propertyVarCircular()
-{
- // enforce behaviour regarding circular references - ensure qdvmemo deletion.
- QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
- QCoreApplication::processEvents();
- QCOMPARE(object->property("canaryInt"), QVariant(5));
- QVariant canaryResourceVariant = object->property("canaryResource");
- QVERIFY(canaryResourceVariant.isValid());
- QPixmap canaryResourcePixmap = canaryResourceVariant.value<QPixmap>();
- canaryResourceVariant = QVariant(); // invalidate it to remove one copy of the pixmap from memory.
- QMetaObject::invokeMethod(object, "deassignCanaryResource"); // remove one copy of the pixmap from memory
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
- QCoreApplication::processEvents();
- QVERIFY(!canaryResourcePixmap.isDetached()); // two copies extant - this and the propertyVar.vp.vp.vp.vp.memoryHog.
- QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
- QCoreApplication::processEvents();
- QCOMPARE(object->property("canaryInt"), QVariant(2));
- QCOMPARE(object->property("canaryResource"), QVariant(1));
- QVERIFY(canaryResourcePixmap.isDetached()); // now detached, since orig copy was member of qdvmemo which was deleted.
- delete object;
-}
-
-void tst_qdeclarativeecmascript::propertyVarCircular2()
-{
- // track deletion of JS-owned parent item with Cpp-owned child
- // where the child has a var property referencing its parent.
- QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- QMetaObject::invokeMethod(object, "assignCircular");
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
- QCoreApplication::processEvents();
- QObject *rootObject = object->property("vp").value<QObject*>();
- QVERIFY(rootObject != 0);
- QObject *childObject = rootObject->findChild<QObject*>("text");
- QVERIFY(childObject != 0);
- QWeakPointer<QObject> rootObjectTracker(rootObject);
- QVERIFY(!rootObjectTracker.isNull());
- QWeakPointer<QObject> childObjectTracker(childObject);
- QVERIFY(!childObjectTracker.isNull());
- gc(engine);
- QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
- QCOMPARE(childObject->property("textCanary").toInt(), 10);
- QMetaObject::invokeMethod(object, "deassignCircular");
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
- QCoreApplication::processEvents();
- QVERIFY(rootObjectTracker.isNull()); // should have been collected
- QVERIFY(childObjectTracker.isNull()); // should have been collected
- delete object;
-}
-
-void tst_qdeclarativeecmascript::propertyVarWeakRefCallback(v8::Persistent<v8::Value> object, void* parameter)
-{
- *(int*)(parameter) += 1;
- qPersistentDispose(object);
-}
-
-void tst_qdeclarativeecmascript::propertyVarInheritance()
-{
- int propertyVarWeakRefCallbackCount = 0;
-
- // enforce behaviour regarding element inheritance - ensure handle disposal.
- // The particular component under test here has a chain of references.
- QDeclarativeComponent component(&engine, testFileUrl("propertyVar.inherit.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- QMetaObject::invokeMethod(object, "assignCircular"); // cause assignment and gc
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
- QCoreApplication::processEvents();
- // we want to be able to track when the varProperties array of the last metaobject is disposed
- QObject *cco5 = object->property("varProperty").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>()->property("vp").value<QObject*>();
- 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*>();
- QDeclarativeVMEMetaObject *icovmemo = ((QDeclarativeVMEMetaObject *)(ico5->metaObject()));
- QDeclarativeVMEMetaObject *ccovmemo = ((QDeclarativeVMEMetaObject *)(cco5->metaObject()));
- v8::Persistent<v8::Value> icoCanaryHandle;
- v8::Persistent<v8::Value> ccoCanaryHandle;
- {
- v8::HandleScope hs;
- // XXX NOTE: this is very implementation dependent. QDVMEMO->vmeProperty() is the only
- // public function which can return us a handle to something in the varProperties array.
- icoCanaryHandle = qPersistentNew(icovmemo->vmeProperty(ico5->metaObject()->indexOfProperty("circ")));
- ccoCanaryHandle = qPersistentNew(ccovmemo->vmeProperty(cco5->metaObject()->indexOfProperty("circ")));
- // we make them weak and invoke the gc, but we should not hit the weak-callback yet
- // as the varproperties array of each vmemo still references the resource.
- icoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
- ccoCanaryHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
- gc(engine);
- QVERIFY(propertyVarWeakRefCallbackCount == 0);
- }
- // now we deassign the var prop, which should trigger collection of item subtrees.
- QMetaObject::invokeMethod(object, "deassignCircular"); // cause deassignment and gc
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
- QCoreApplication::processEvents();
- // ensure that there are only weak handles to the underlying varProperties array remaining.
- gc(engine);
- QCOMPARE(propertyVarWeakRefCallbackCount, 2); // should have been called for both, since all refs should be weak.
- delete object;
- // since there are no parent vmemo's to keep implicit references alive, and the only handles
- // to what remains are weak, all varProperties arrays must have been collected.
-}
-
-void tst_qdeclarativeecmascript::propertyVarInheritance2()
-{
- int propertyVarWeakRefCallbackCount = 0;
-
- // The particular component under test here does NOT have a chain of references; the
- // only link between rootObject and childObject is that rootObject is the parent of childObject.
- QDeclarativeComponent component(&engine, testFileUrl("propertyVar.circular.2.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- QMetaObject::invokeMethod(object, "assignCircular");
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
- QCoreApplication::processEvents();
- QObject *rootObject = object->property("vp").value<QObject*>();
- QVERIFY(rootObject != 0);
- QObject *childObject = rootObject->findChild<QObject*>("text");
- QVERIFY(childObject != 0);
- QCOMPARE(rootObject->property("rectCanary").toInt(), 5);
- QCOMPARE(childObject->property("textCanary").toInt(), 10);
- v8::Persistent<v8::Value> childObjectVarArrayValueHandle;
- {
- v8::HandleScope hs;
- propertyVarWeakRefCallbackCount = 0; // reset callback count.
- childObjectVarArrayValueHandle = qPersistentNew(((QDeclarativeVMEMetaObject *)(childObject->metaObject()))->vmeProperty(childObject->metaObject()->indexOfProperty("vp")));
- childObjectVarArrayValueHandle.MakeWeak(&propertyVarWeakRefCallbackCount, propertyVarWeakRefCallback);
- gc(engine);
- QVERIFY(propertyVarWeakRefCallbackCount == 0); // should not have been collected yet.
- QCOMPARE(childObject->property("vp").value<QObject*>(), rootObject);
- QCOMPARE(childObject->property("textCanary").toInt(), 10);
- }
- QMetaObject::invokeMethod(object, "deassignCircular");
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete); // process deleteLater() events from QV8QObjectWrapper.
- QCoreApplication::processEvents();
- QVERIFY(propertyVarWeakRefCallbackCount == 1); // should have been collected now.
- delete object;
-}
-
-// Ensure that QObject type conversion works on binding assignment
-void tst_qdeclarativeecmascript::elementAssign()
-{
- QDeclarativeComponent component(&engine, testFileUrl("elementAssign.qml"));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
-}
-
-// QTBUG-12457
-void tst_qdeclarativeecmascript::objectPassThroughSignals()
-{
- QDeclarativeComponent component(&engine, testFileUrl("objectsPassThroughSignals.qml"));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
-}
-
-// QTBUG-21626
-void tst_qdeclarativeecmascript::objectConversion()
-{
- QDeclarativeComponent component(&engine, testFileUrl("objectConversion.qml"));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
- QVariant retn;
- QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn));
- QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100));
-
- delete object;
-}
-
-
-// QTBUG-20242
-void tst_qdeclarativeecmascript::booleanConversion()
-{
- QDeclarativeComponent component(&engine, testFileUrl("booleanConversion.qml"));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test_true1").toBool(), true);
- QCOMPARE(object->property("test_true2").toBool(), true);
- QCOMPARE(object->property("test_true3").toBool(), true);
- QCOMPARE(object->property("test_true4").toBool(), true);
- QCOMPARE(object->property("test_true5").toBool(), true);
-
- QCOMPARE(object->property("test_false1").toBool(), false);
- QCOMPARE(object->property("test_false2").toBool(), false);
- QCOMPARE(object->property("test_false3").toBool(), false);
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::handleReferenceManagement()
-{
-
- int dtorCount = 0;
- {
- // Linear QObject reference
- QDeclarativeEngine hrmEngine;
- QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.1.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
- cro->setEngine(&hrmEngine);
- cro->setDtorCount(&dtorCount);
- QMetaObject::invokeMethod(object, "createReference");
- gc(engine);
- QCOMPARE(dtorCount, 0); // second has JS ownership, kept alive by first's reference
- delete object;
- hrmEngine.collectGarbage();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
- QCOMPARE(dtorCount, 3);
- }
-
- dtorCount = 0;
- {
- // Circular QObject reference
- QDeclarativeEngine hrmEngine;
- QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.object.2.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- CircularReferenceObject *cro = object->findChild<CircularReferenceObject*>("cro");
- cro->setEngine(&hrmEngine);
- cro->setDtorCount(&dtorCount);
- QMetaObject::invokeMethod(object, "circularReference");
- gc(engine);
- QCOMPARE(dtorCount, 2); // both should be cleaned up, since circular references shouldn't keep alive.
- delete object;
- hrmEngine.collectGarbage();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
- QCOMPARE(dtorCount, 3);
- }
-
- dtorCount = 0;
- {
- // Linear handle reference
- QDeclarativeEngine hrmEngine;
- QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.1.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
- QVERIFY(crh != 0);
- crh->setEngine(&hrmEngine);
- crh->setDtorCount(&dtorCount);
- QMetaObject::invokeMethod(object, "createReference");
- CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
- CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
- QVERIFY(first != 0);
- QVERIFY(second != 0);
- first->addReference(QDeclarativeData::get(second)->v8object); // create reference
- // now we have to reparent second and make second owned by JS.
- second->setParent(0);
- QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
- gc(engine);
- QCOMPARE(dtorCount, 0); // due to reference from first to second, second shouldn't be collected.
- delete object;
- hrmEngine.collectGarbage();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
- QCOMPARE(dtorCount, 3);
- }
-
- dtorCount = 0;
- {
- // Circular handle reference
- QDeclarativeEngine hrmEngine;
- QDeclarativeComponent component(&hrmEngine, testFileUrl("handleReferenceManagement.handle.2.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- CircularReferenceHandle *crh = object->findChild<CircularReferenceHandle*>("crh");
- QVERIFY(crh != 0);
- crh->setEngine(&hrmEngine);
- crh->setDtorCount(&dtorCount);
- QMetaObject::invokeMethod(object, "circularReference");
- CircularReferenceHandle *first = object->property("first").value<CircularReferenceHandle*>();
- CircularReferenceHandle *second = object->property("second").value<CircularReferenceHandle*>();
- QVERIFY(first != 0);
- QVERIFY(second != 0);
- first->addReference(QDeclarativeData::get(second)->v8object); // create circular reference
- second->addReference(QDeclarativeData::get(first)->v8object); // note: must be weak.
- // now we have to reparent and change ownership.
- first->setParent(0);
- second->setParent(0);
- QDeclarativeEngine::setObjectOwnership(first, QDeclarativeEngine::JavaScriptOwnership);
- QDeclarativeEngine::setObjectOwnership(second, QDeclarativeEngine::JavaScriptOwnership);
- gc(engine);
- QCOMPARE(dtorCount, 2); // despite circular references, both will be collected.
- delete object;
- hrmEngine.collectGarbage();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
- QCOMPARE(dtorCount, 3);
- }
-
- dtorCount = 0;
- {
- // multiple engine interaction - linear reference
- QDeclarativeEngine hrmEngine1;
- QDeclarativeEngine hrmEngine2;
- QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
- QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
- QObject *object1 = component1.create();
- QObject *object2 = component2.create();
- QVERIFY(object1 != 0);
- QVERIFY(object2 != 0);
- CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
- CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
- QVERIFY(crh1 != 0);
- QVERIFY(crh2 != 0);
- crh1->setEngine(&hrmEngine1);
- crh2->setEngine(&hrmEngine2);
- crh1->setDtorCount(&dtorCount);
- crh2->setDtorCount(&dtorCount);
- QMetaObject::invokeMethod(object1, "createReference");
- QMetaObject::invokeMethod(object2, "createReference");
- CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
- CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
- CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
- CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
- QVERIFY(first1 != 0);
- QVERIFY(second1 != 0);
- QVERIFY(first2 != 0);
- QVERIFY(second2 != 0);
- first1->addReference(QDeclarativeData::get(second2)->v8object); // create reference across engines
- // now we have to reparent second2 and make second2 owned by JS.
- second2->setParent(0);
- QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
- gc(engine);
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
- QCOMPARE(dtorCount, 0); // due to reference from first1 to second2, second2 shouldn't be collected.
- delete object1;
- delete object2;
- hrmEngine1.collectGarbage();
- hrmEngine2.collectGarbage();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
- QCOMPARE(dtorCount, 6);
- }
-
- dtorCount = 0;
- {
- // multiple engine interaction - circular reference
- QDeclarativeEngine hrmEngine1;
- QDeclarativeEngine hrmEngine2;
- QDeclarativeComponent component1(&hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
- QDeclarativeComponent component2(&hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
- QObject *object1 = component1.create();
- QObject *object2 = component2.create();
- QVERIFY(object1 != 0);
- QVERIFY(object2 != 0);
- CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
- CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
- QVERIFY(crh1 != 0);
- QVERIFY(crh2 != 0);
- crh1->setEngine(&hrmEngine1);
- crh2->setEngine(&hrmEngine2);
- crh1->setDtorCount(&dtorCount);
- crh2->setDtorCount(&dtorCount);
- QMetaObject::invokeMethod(object1, "createReference");
- QMetaObject::invokeMethod(object2, "createReference");
- CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
- CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
- CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
- CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
- QVERIFY(first1 != 0);
- QVERIFY(second1 != 0);
- QVERIFY(first2 != 0);
- QVERIFY(second2 != 0);
- first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
- second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
- second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
- first2->addReference(QDeclarativeData::get(first1)->v8object); // close the loop - circular ref across engines
- // now we have to reparent and change ownership to JS.
- first1->setParent(0);
- second1->setParent(0);
- first2->setParent(0);
- second2->setParent(0);
- QDeclarativeEngine::setObjectOwnership(first1, QDeclarativeEngine::JavaScriptOwnership);
- QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
- QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
- QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
- gc(engine);
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
- QCOMPARE(dtorCount, 4); // circular references shouldn't keep them alive.
- delete object1;
- delete object2;
- hrmEngine1.collectGarbage();
- hrmEngine2.collectGarbage();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
- QCOMPARE(dtorCount, 6);
- }
-
- dtorCount = 0;
- {
- // multiple engine interaction - linear reference with engine deletion
- QDeclarativeEngine *hrmEngine1 = new QDeclarativeEngine;
- QDeclarativeEngine *hrmEngine2 = new QDeclarativeEngine;
- QDeclarativeComponent component1(hrmEngine1, testFileUrl("handleReferenceManagement.handle.1.qml"));
- QDeclarativeComponent component2(hrmEngine2, testFileUrl("handleReferenceManagement.handle.1.qml"));
- QObject *object1 = component1.create();
- QObject *object2 = component2.create();
- QVERIFY(object1 != 0);
- QVERIFY(object2 != 0);
- CircularReferenceHandle *crh1 = object1->findChild<CircularReferenceHandle*>("crh");
- CircularReferenceHandle *crh2 = object2->findChild<CircularReferenceHandle*>("crh");
- QVERIFY(crh1 != 0);
- QVERIFY(crh2 != 0);
- crh1->setEngine(hrmEngine1);
- crh2->setEngine(hrmEngine2);
- crh1->setDtorCount(&dtorCount);
- crh2->setDtorCount(&dtorCount);
- QMetaObject::invokeMethod(object1, "createReference");
- QMetaObject::invokeMethod(object2, "createReference");
- CircularReferenceHandle *first1 = object1->property("first").value<CircularReferenceHandle*>();
- CircularReferenceHandle *second1 = object1->property("second").value<CircularReferenceHandle*>();
- CircularReferenceHandle *first2 = object2->property("first").value<CircularReferenceHandle*>();
- CircularReferenceHandle *second2 = object2->property("second").value<CircularReferenceHandle*>();
- QVERIFY(first1 != 0);
- QVERIFY(second1 != 0);
- QVERIFY(first2 != 0);
- QVERIFY(second2 != 0);
- first1->addReference(QDeclarativeData::get(second1)->v8object); // create linear reference within engine1
- second1->addReference(QDeclarativeData::get(second2)->v8object); // create linear reference across engines
- second2->addReference(QDeclarativeData::get(first2)->v8object); // create linear reference within engine2
- // now we have to reparent and change ownership to JS.
- first1->setParent(crh1);
- second1->setParent(0);
- first2->setParent(0);
- second2->setParent(0);
- QDeclarativeEngine::setObjectOwnership(second1, QDeclarativeEngine::JavaScriptOwnership);
- QDeclarativeEngine::setObjectOwnership(first2, QDeclarativeEngine::JavaScriptOwnership);
- QDeclarativeEngine::setObjectOwnership(second2, QDeclarativeEngine::JavaScriptOwnership);
- gc(engine);
- QCOMPARE(dtorCount, 0);
- delete hrmEngine2;
- gc(engine);
- QCOMPARE(dtorCount, 0);
- delete object1;
- delete object2;
- hrmEngine1->collectGarbage();
- QCoreApplication::sendPostedEvents(0, QEvent::DeferredDelete);
- QCoreApplication::processEvents();
- QCOMPARE(dtorCount, 6);
- delete hrmEngine1;
- }
-}
-
-void tst_qdeclarativeecmascript::stringArg()
-{
- QDeclarativeComponent component(&engine, testFileUrl("stringArg.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- QMetaObject::invokeMethod(object, "success");
- QVERIFY(object->property("returnValue").toBool());
-
- QString w1 = testFileUrl("stringArg.qml").toString() + QLatin1String(":45: Error: String.arg(): Invalid arguments");
- QTest::ignoreMessage(QtWarningMsg, w1.toAscii().constData());
- QMetaObject::invokeMethod(object, "failure");
- QVERIFY(object->property("returnValue").toBool());
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::readonlyDeclaration()
-{
- QDeclarativeComponent component(&engine, testFileUrl("readonlyDeclaration.qml"));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test").toBool(), true);
-
- delete object;
-}
-
-Q_DECLARE_METATYPE(QList<int>)
-Q_DECLARE_METATYPE(QList<qreal>)
-Q_DECLARE_METATYPE(QList<bool>)
-Q_DECLARE_METATYPE(QList<QString>)
-Q_DECLARE_METATYPE(QList<QUrl>)
-void tst_qdeclarativeecmascript::sequenceConversionRead()
-{
- {
- QUrl qmlFile = testFileUrl("sequenceConversion.read.qml");
- QDeclarativeComponent component(&engine, qmlFile);
- QObject *object = component.create();
- QVERIFY(object != 0);
- MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
- QVERIFY(seq != 0);
-
- QMetaObject::invokeMethod(object, "readSequences");
- QList<int> intList; intList << 1 << 2 << 3 << 4;
- QCOMPARE(object->property("intListLength").toInt(), intList.length());
- QCOMPARE(object->property("intList").value<QList<int> >(), intList);
- QList<qreal> qrealList; qrealList << 1.1 << 2.2 << 3.3 << 4.4;
- QCOMPARE(object->property("qrealListLength").toInt(), qrealList.length());
- QCOMPARE(object->property("qrealList").value<QList<qreal> >(), qrealList);
- QList<bool> boolList; boolList << true << false << true << false;
- QCOMPARE(object->property("boolListLength").toInt(), boolList.length());
- QCOMPARE(object->property("boolList").value<QList<bool> >(), boolList);
- QList<QString> stringList; stringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
- QCOMPARE(object->property("stringListLength").toInt(), stringList.length());
- QCOMPARE(object->property("stringList").value<QList<QString> >(), stringList);
- QList<QUrl> urlList; urlList << QUrl("http://www.example1.com") << QUrl("http://www.example2.com") << QUrl("http://www.example3.com");
- QCOMPARE(object->property("urlListLength").toInt(), urlList.length());
- QCOMPARE(object->property("urlList").value<QList<QUrl> >(), urlList);
- QStringList qstringList; qstringList << QLatin1String("first") << QLatin1String("second") << QLatin1String("third") << QLatin1String("fourth");
- QCOMPARE(object->property("qstringListLength").toInt(), qstringList.length());
- QCOMPARE(object->property("qstringList").value<QStringList>(), qstringList);
-
- QMetaObject::invokeMethod(object, "readSequenceElements");
- QCOMPARE(object->property("intVal").toInt(), 2);
- QCOMPARE(object->property("qrealVal").toReal(), 2.2);
- QCOMPARE(object->property("boolVal").toBool(), false);
- QCOMPARE(object->property("stringVal").toString(), QString(QLatin1String("second")));
- QCOMPARE(object->property("urlVal").toUrl(), QUrl("http://www.example2.com"));
- QCOMPARE(object->property("qstringVal").toString(), QString(QLatin1String("second")));
-
- QMetaObject::invokeMethod(object, "enumerateSequenceElements");
- QCOMPARE(object->property("enumerationMatches").toBool(), true);
-
- intList.clear(); intList << 1 << 2 << 3 << 4 << 5; // set by the enumerateSequenceElements test.
- QDeclarativeProperty seqProp(seq, "intListProperty");
- QCOMPARE(seqProp.read().value<QList<int> >(), intList);
- QDeclarativeProperty seqProp2(seq, "intListProperty", &engine);
- QCOMPARE(seqProp2.read().value<QList<int> >(), intList);
-
- QMetaObject::invokeMethod(object, "testReferenceDeletion");
- QCOMPARE(object->property("referenceDeletion").toBool(), true);
-
- delete object;
- }
-
- {
- QUrl qmlFile = testFileUrl("sequenceConversion.read.error.qml");
- QDeclarativeComponent component(&engine, qmlFile);
- QObject *object = component.create();
- QVERIFY(object != 0);
- MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
- QVERIFY(seq != 0);
-
- // we haven't registered QList<QPoint> as a sequence type.
- QString warningOne = QLatin1String("QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
- QString warningTwo = qmlFile.toString() + QLatin1String(":18: TypeError: Cannot read property 'length' of undefined");
- QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
- QTest::ignoreMessage(QtWarningMsg, warningTwo.toAscii().constData());
-
- QMetaObject::invokeMethod(object, "performTest");
-
- // QList<QPoint> has not been registered as a sequence type.
- QCOMPARE(object->property("pointListLength").toInt(), 0);
- QVERIFY(!object->property("pointList").isValid());
- QTest::ignoreMessage(QtWarningMsg, "QMetaProperty::read: Unable to handle unregistered datatype 'QList<QPoint>' for property 'MySequenceConversionObject::pointListProperty'");
- QDeclarativeProperty seqProp(seq, "pointListProperty", &engine);
- QVERIFY(!seqProp.read().isValid()); // not a valid/known sequence type
-
- delete object;
- }
-}
-
-void tst_qdeclarativeecmascript::sequenceConversionWrite()
-{
- {
- QUrl qmlFile = testFileUrl("sequenceConversion.write.qml");
- QDeclarativeComponent component(&engine, qmlFile);
- QObject *object = component.create();
- QVERIFY(object != 0);
- MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
- QVERIFY(seq != 0);
-
- QMetaObject::invokeMethod(object, "writeSequences");
- QCOMPARE(object->property("success").toBool(), true);
-
- QMetaObject::invokeMethod(object, "writeSequenceElements");
- QCOMPARE(object->property("success").toBool(), true);
-
- QMetaObject::invokeMethod(object, "writeOtherElements");
- QCOMPARE(object->property("success").toBool(), true);
-
- QMetaObject::invokeMethod(object, "testReferenceDeletion");
- QCOMPARE(object->property("referenceDeletion").toBool(), true);
-
- delete object;
- }
-
- {
- QUrl qmlFile = testFileUrl("sequenceConversion.write.error.qml");
- QDeclarativeComponent component(&engine, qmlFile);
- QObject *object = component.create();
- QVERIFY(object != 0);
- MySequenceConversionObject *seq = object->findChild<MySequenceConversionObject*>("msco");
- QVERIFY(seq != 0);
-
- // we haven't registered QList<QPoint> as a sequence type, so writing shouldn't work.
- QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QVariantList to void");
- QTest::ignoreMessage(QtWarningMsg, warningOne.toAscii().constData());
-
- QMetaObject::invokeMethod(object, "performTest");
-
- QList<QPoint> pointList; pointList << QPoint(1, 2) << QPoint(3, 4) << QPoint(5, 6); // original values, shouldn't have changed
- QCOMPARE(seq->pointListProperty(), pointList);
-
- delete object;
- }
-}
-
-void tst_qdeclarativeecmascript::sequenceConversionArray()
-{
- // ensure that in JS the returned sequences act just like normal JS Arrays.
- QUrl qmlFile = testFileUrl("sequenceConversion.array.qml");
- QDeclarativeComponent component(&engine, qmlFile);
- QObject *object = component.create();
- QVERIFY(object != 0);
- QMetaObject::invokeMethod(object, "indexedAccess");
- QVERIFY(object->property("success").toBool());
- QMetaObject::invokeMethod(object, "arrayOperations");
- QVERIFY(object->property("success").toBool());
- QMetaObject::invokeMethod(object, "testEqualitySemantics");
- QVERIFY(object->property("success").toBool());
- QMetaObject::invokeMethod(object, "testReferenceDeletion");
- QCOMPARE(object->property("referenceDeletion").toBool(), true);
- delete object;
-}
-
-
-void tst_qdeclarativeecmascript::sequenceConversionIndexes()
-{
- // ensure that we gracefully fail if unsupported index values are specified.
- // Qt container classes only support non-negative, signed integer index values.
- QUrl qmlFile = testFileUrl("sequenceConversion.indexes.qml");
- QDeclarativeComponent component(&engine, qmlFile);
- QObject *object = component.create();
- QVERIFY(object != 0);
- QString w1 = qmlFile.toString() + QLatin1String(":34: Index out of range during length set");
- QString w2 = qmlFile.toString() + QLatin1String(":41: Index out of range during indexed set");
- QString w3 = qmlFile.toString() + QLatin1String(":48: Index out of range during indexed get");
- QString w4 = qmlFile.toString() + QLatin1String(":78: std::bad_alloc during length set");
- QString w5 = qmlFile.toString() + QLatin1String(":83: std::bad_alloc during indexed set");
- QTest::ignoreMessage(QtWarningMsg, qPrintable(w1));
- QTest::ignoreMessage(QtWarningMsg, qPrintable(w2));
- QTest::ignoreMessage(QtWarningMsg, qPrintable(w3));
- QTest::ignoreMessage(QtWarningMsg, qPrintable(w4));
- QTest::ignoreMessage(QtWarningMsg, qPrintable(w5));
- QMetaObject::invokeMethod(object, "indexedAccess");
- QVERIFY(object->property("success").toBool());
- delete object;
-}
-
-void tst_qdeclarativeecmascript::sequenceConversionThreads()
-{
- // ensure that sequence conversion operations work correctly in a worker thread
- // and that serialisation between the main and worker thread succeeds.
- QUrl qmlFile = testFileUrl("sequenceConversion.threads.qml");
- QDeclarativeComponent component(&engine, qmlFile);
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QMetaObject::invokeMethod(object, "testIntSequence");
- QTRY_VERIFY(object->property("finished").toBool());
- QVERIFY(object->property("success").toBool());
-
- QMetaObject::invokeMethod(object, "testQrealSequence");
- QTRY_VERIFY(object->property("finished").toBool());
- QVERIFY(object->property("success").toBool());
-
- QMetaObject::invokeMethod(object, "testBoolSequence");
- QTRY_VERIFY(object->property("finished").toBool());
- QVERIFY(object->property("success").toBool());
-
- QMetaObject::invokeMethod(object, "testStringSequence");
- QTRY_VERIFY(object->property("finished").toBool());
- QVERIFY(object->property("success").toBool());
-
- QMetaObject::invokeMethod(object, "testQStringSequence");
- QTRY_VERIFY(object->property("finished").toBool());
- QVERIFY(object->property("success").toBool());
-
- QMetaObject::invokeMethod(object, "testUrlSequence");
- QTRY_VERIFY(object->property("finished").toBool());
- QVERIFY(object->property("success").toBool());
-
- QMetaObject::invokeMethod(object, "testVariantSequence");
- QTRY_VERIFY(object->property("finished").toBool());
- QVERIFY(object->property("success").toBool());
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::sequenceConversionBindings()
-{
- {
- QUrl qmlFile = testFileUrl("sequenceConversion.bindings.qml");
- QDeclarativeComponent component(&engine, qmlFile);
- QObject *object = component.create();
- QVERIFY(object != 0);
- QList<int> intList; intList << 1 << 2 << 3 << 12 << 7;
- QCOMPARE(object->property("boundSequence").value<QList<int> >(), intList);
- QCOMPARE(object->property("boundElement").toInt(), intList.at(3));
- QList<int> intListTwo; intListTwo << 1 << 2 << 3 << 12 << 14;
- QCOMPARE(object->property("boundSequenceTwo").value<QList<int> >(), intListTwo);
- delete object;
- }
-
- {
- QUrl qmlFile = testFileUrl("sequenceConversion.bindings.error.qml");
- QString warning = QString(QLatin1String("%1:17: Unable to assign QList<int> to QList<bool>")).arg(qmlFile.toString());
- QTest::ignoreMessage(QtWarningMsg, warning.toAscii().constData());
- QDeclarativeComponent component(&engine, qmlFile);
- QObject *object = component.create();
- QVERIFY(object != 0);
- delete object;
- }
-}
-
-void tst_qdeclarativeecmascript::sequenceConversionCopy()
-{
- QUrl qmlFile = testFileUrl("sequenceConversion.copy.qml");
- QDeclarativeComponent component(&engine, qmlFile);
- QObject *object = component.create();
- QVERIFY(object != 0);
- QMetaObject::invokeMethod(object, "testCopySequences");
- QCOMPARE(object->property("success").toBool(), true);
- QMetaObject::invokeMethod(object, "readSequenceCopyElements");
- QCOMPARE(object->property("success").toBool(), true);
- QMetaObject::invokeMethod(object, "testEqualitySemantics");
- QCOMPARE(object->property("success").toBool(), true);
- delete object;
-}
-
-void tst_qdeclarativeecmascript::assignSequenceTypes()
-{
- // test binding array to sequence type property
- {
- QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.1.qml"));
- MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
- QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
- QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
- QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
- QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
- QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
- delete object;
- }
-
- // test binding literal to sequence type property
- {
- QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.2.qml"));
- MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->intListProperty(), (QList<int>() << 1));
- QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
- QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
- QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
- QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
- QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
- delete object;
- }
-
- // test binding single value to sequence type property
- {
- QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.3.qml"));
- MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->intListProperty(), (QList<int>() << 1));
- QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
- QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
- QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
- delete object;
- }
-
- // test assigning array to sequence type property in js function
- {
- QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.4.qml"));
- MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->intListProperty(), (QList<int>() << 1 << 2));
- QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1 << 2.2));
- QCOMPARE(object->boolListProperty(), (QList<bool>() << false << true));
- QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com") << QUrl("http://www.example2.com")));
- QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one") << QLatin1String("two")));
- QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("one") << QLatin1String("two")));
- delete object;
- }
-
- // test assigning literal to sequence type property in js function
- {
- QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.5.qml"));
- MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->intListProperty(), (QList<int>() << 1));
- QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
- QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
- QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl("http://www.example1.com")));
- QCOMPARE(object->stringListProperty(), (QList<QString>() << QLatin1String("one")));
- QCOMPARE(object->qstringListProperty(), (QStringList() << QLatin1String("two")));
- delete object;
- }
-
- // test assigning single value to sequence type property in js function
- {
- QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.6.qml"));
- MySequenceConversionObject *object = qobject_cast<MySequenceConversionObject *>(component.create());
- QVERIFY(object != 0);
- QCOMPARE(object->intListProperty(), (QList<int>() << 1));
- QCOMPARE(object->qrealListProperty(), (QList<qreal>() << 1.1));
- QCOMPARE(object->boolListProperty(), (QList<bool>() << false));
- QCOMPARE(object->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
- delete object;
- }
-
- // test QList<QUrl> literal assignment and binding assignment causes url resolution when required
- {
- QDeclarativeComponent component(&engine, testFileUrl("assignSequenceTypes.7.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
- MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
- MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
- MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
- MySequenceConversionObject *msco5 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco5"));
- QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0 && msco5 != 0);
- QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
- QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html"))));
- QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
- QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
- QCOMPARE(msco5->urlListProperty(), (QList<QUrl>() << QUrl(testFileUrl("example.html")) << QUrl(testFileUrl("example2.html"))));
- delete object;
- }
-}
-
-// Test that assigning a null object works
-// Regressed with: df1788b4dbbb2826ae63f26bdf166342595343f4
-void tst_qdeclarativeecmascript::nullObjectBinding()
-{
- QDeclarativeComponent component(&engine, testFileUrl("nullObjectBinding.qml"));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QVERIFY(object->property("test") == QVariant::fromValue((QObject *)0));
-
- delete object;
-}
-
-// Test that bindings don't evaluate once the engine has been destroyed
-void tst_qdeclarativeecmascript::deletedEngine()
-{
- QDeclarativeEngine *engine = new QDeclarativeEngine;
- QDeclarativeComponent component(engine, testFileUrl("deletedEngine.qml"));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("a").toInt(), 39);
- object->setProperty("b", QVariant(9));
- QCOMPARE(object->property("a").toInt(), 117);
-
- delete engine;
-
- QCOMPARE(object->property("a").toInt(), 117);
- object->setProperty("b", QVariant(10));
- QCOMPARE(object->property("a").toInt(), 117);
-
- delete object;
-}
-
-// Test the crashing part of QTBUG-9705
-void tst_qdeclarativeecmascript::libraryScriptAssert()
-{
- QDeclarativeComponent component(&engine, testFileUrl("libraryScriptAssert.qml"));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::variantsAssignedUndefined()
-{
- QDeclarativeComponent component(&engine, testFileUrl("variantsAssignedUndefined.qml"));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QCOMPARE(object->property("test1").toInt(), 10);
- QCOMPARE(object->property("test2").toInt(), 11);
-
- object->setProperty("runTest", true);
-
- QCOMPARE(object->property("test1"), QVariant());
- QCOMPARE(object->property("test2"), QVariant());
-
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::qtbug_9792()
-{
- QDeclarativeComponent component(&engine, testFileUrl("qtbug_9792.qml"));
-
- QDeclarativeContext *context = new QDeclarativeContext(engine.rootContext());
-
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create(context));
- QVERIFY(object != 0);
-
- QTest::ignoreMessage(QtDebugMsg, "Hello world!");
- object->basicSignal();
-
- delete context;
-
- transientErrorsMsgCount = 0;
- QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
-
- object->basicSignal();
-
- qInstallMsgHandler(old);
-
- QCOMPARE(transientErrorsMsgCount, 0);
-
- delete object;
-}
-
-// Verifies that QDeclarativeGuard<>s used in the vmemetaobject are cleaned correctly
-void tst_qdeclarativeecmascript::qtcreatorbug_1289()
-{
- QDeclarativeComponent component(&engine, testFileUrl("qtcreatorbug_1289.qml"));
-
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QObject *nested = qvariant_cast<QObject *>(o->property("object"));
- QVERIFY(nested != 0);
-
- QVERIFY(qvariant_cast<QObject *>(nested->property("nestedObject")) == o);
-
- delete nested;
- nested = qvariant_cast<QObject *>(o->property("object"));
- QVERIFY(nested == 0);
-
- // If the bug is present, the next line will crash
- delete o;
-}
-
-// Test that we shut down without stupid warnings
-void tst_qdeclarativeecmascript::noSpuriousWarningsAtShutdown()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.qml"));
-
- QObject *o = component.create();
-
- transientErrorsMsgCount = 0;
- QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
-
- delete o;
-
- qInstallMsgHandler(old);
-
- QCOMPARE(transientErrorsMsgCount, 0);
- }
-
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("noSpuriousWarningsAtShutdown.2.qml"));
-
- QObject *o = component.create();
-
- transientErrorsMsgCount = 0;
- QtMsgHandler old = qInstallMsgHandler(transientErrorsMsgHandler);
-
- delete o;
-
- qInstallMsgHandler(old);
-
- QCOMPARE(transientErrorsMsgCount, 0);
- }
-}
-
-void tst_qdeclarativeecmascript::canAssignNullToQObject()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.1.qml"));
-
- MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(o != 0);
-
- QVERIFY(o->objectProperty() != 0);
-
- o->setProperty("runTest", true);
-
- QVERIFY(o->objectProperty() == 0);
-
- delete o;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("canAssignNullToQObject.2.qml"));
-
- MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(o != 0);
-
- QVERIFY(o->objectProperty() == 0);
-
- delete o;
- }
-}
-
-void tst_qdeclarativeecmascript::functionAssignment_fromBinding()
-{
- QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.1.qml"));
-
- QString url = component.url().toString();
- QString warning = url + ":4: Unable to assign a function to a property.";
- QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
-
- MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(o != 0);
-
- QVERIFY(!o->property("a").isValid());
-
- delete o;
-}
-
-void tst_qdeclarativeecmascript::functionAssignment_fromJS()
-{
- QFETCH(QString, triggerProperty);
-
- QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
- QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
-
- MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(o != 0);
- QVERIFY(!o->property("a").isValid());
-
- o->setProperty("aNumber", QVariant(5));
- o->setProperty(triggerProperty.toUtf8().constData(), true);
- QCOMPARE(o->property("a"), QVariant(50));
-
- o->setProperty("aNumber", QVariant(10));
- QCOMPARE(o->property("a"), QVariant(100));
-
- delete o;
-}
-
-void tst_qdeclarativeecmascript::functionAssignment_fromJS_data()
-{
- QTest::addColumn<QString>("triggerProperty");
-
- QTest::newRow("assign to property") << "assignToProperty";
- QTest::newRow("assign to property, from JS file") << "assignToPropertyFromJsFile";
-
- QTest::newRow("assign to value type") << "assignToValueType";
-
- QTest::newRow("use 'this'") << "assignWithThis";
- QTest::newRow("use 'this' from JS file") << "assignWithThisFromJsFile";
-}
-
-void tst_qdeclarativeecmascript::functionAssignmentfromJS_invalid()
-{
- QDeclarativeComponent component(&engine, testFileUrl("functionAssignment.2.qml"));
- QVERIFY2(component.errorString().isEmpty(), qPrintable(component.errorString()));
-
- MyQmlObject *o = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(o != 0);
- QVERIFY(!o->property("a").isValid());
-
- o->setProperty("assignFuncWithoutReturn", true);
- QVERIFY(!o->property("a").isValid());
-
- QString url = component.url().toString();
- QString warning = url + ":67: Unable to assign QString to int";
- QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
- o->setProperty("assignWrongType", true);
-
- warning = url + ":71: Unable to assign QString to int";
- QTest::ignoreMessage(QtWarningMsg, warning.toLatin1().constData());
- o->setProperty("assignWrongTypeToValueType", true);
-
- delete o;
-}
-
-void tst_qdeclarativeecmascript::eval()
-{
- QDeclarativeComponent component(&engine, testFileUrl("eval.qml"));
-
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QCOMPARE(o->property("test1").toBool(), true);
- QCOMPARE(o->property("test2").toBool(), true);
- QCOMPARE(o->property("test3").toBool(), true);
- QCOMPARE(o->property("test4").toBool(), true);
- QCOMPARE(o->property("test5").toBool(), true);
-
- delete o;
-}
-
-void tst_qdeclarativeecmascript::function()
-{
- QDeclarativeComponent component(&engine, testFileUrl("function.qml"));
-
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QCOMPARE(o->property("test1").toBool(), true);
- QCOMPARE(o->property("test2").toBool(), true);
- QCOMPARE(o->property("test3").toBool(), true);
-
- delete o;
-}
-
-void tst_qdeclarativeecmascript::functionException()
-{
- // QTBUG-24037 - shouldn't crash.
- QString errstr = testFileUrl("v8functionException.qml").toString() + QLatin1String(":13: SyntaxError: Unexpected token ILLEGAL");
- QTest::ignoreMessage(QtWarningMsg, qPrintable(errstr));
- QTest::ignoreMessage(QtWarningMsg, "<Unknown File>: Exception occurred during compilation of function: dynamicSlot()");
- QDeclarativeComponent component(&engine, testFileUrl("v8functionException.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
- QMetaObject::invokeMethod(o, "dynamicSlot");
- delete o;
-}
-
-// Test the "Qt.include" method
-void tst_qdeclarativeecmascript::include()
-{
- // Non-library relative include
- {
- QDeclarativeComponent component(&engine, testFileUrl("include.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QCOMPARE(o->property("test0").toInt(), 99);
- QCOMPARE(o->property("test1").toBool(), true);
- QCOMPARE(o->property("test2").toBool(), true);
- QCOMPARE(o->property("test2_1").toBool(), true);
- QCOMPARE(o->property("test3").toBool(), true);
- QCOMPARE(o->property("test3_1").toBool(), true);
-
- delete o;
- }
-
- // Library relative include
- {
- QDeclarativeComponent component(&engine, testFileUrl("include_shared.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QCOMPARE(o->property("test0").toInt(), 99);
- QCOMPARE(o->property("test1").toBool(), true);
- QCOMPARE(o->property("test2").toBool(), true);
- QCOMPARE(o->property("test2_1").toBool(), true);
- QCOMPARE(o->property("test3").toBool(), true);
- QCOMPARE(o->property("test3_1").toBool(), true);
-
- delete o;
- }
-
- // Callback
- {
- QDeclarativeComponent component(&engine, testFileUrl("include_callback.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QCOMPARE(o->property("test1").toBool(), true);
- QCOMPARE(o->property("test2").toBool(), true);
- QCOMPARE(o->property("test3").toBool(), true);
- QCOMPARE(o->property("test4").toBool(), true);
- QCOMPARE(o->property("test5").toBool(), true);
- QCOMPARE(o->property("test6").toBool(), true);
-
- delete o;
- }
-
- // Including file with ".pragma library"
- {
- QDeclarativeComponent component(&engine, testFileUrl("include_pragma.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
- QCOMPARE(o->property("test1").toInt(), 100);
-
- delete o;
- }
-
- // Remote - success
- {
- TestHTTPServer server(8111);
- QVERIFY(server.isValid());
- server.serveDirectory(dataDirectory());
-
- QDeclarativeComponent component(&engine, testFileUrl("include_remote.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QTRY_VERIFY(o->property("done").toBool() == true);
- QTRY_VERIFY(o->property("done2").toBool() == true);
-
- QCOMPARE(o->property("test1").toBool(), true);
- QCOMPARE(o->property("test2").toBool(), true);
- QCOMPARE(o->property("test3").toBool(), true);
- QCOMPARE(o->property("test4").toBool(), true);
- QCOMPARE(o->property("test5").toBool(), true);
-
- QCOMPARE(o->property("test6").toBool(), true);
- QCOMPARE(o->property("test7").toBool(), true);
- QCOMPARE(o->property("test8").toBool(), true);
- QCOMPARE(o->property("test9").toBool(), true);
- QCOMPARE(o->property("test10").toBool(), true);
-
- delete o;
- }
-
- // Remote - error
- {
- TestHTTPServer server(8111);
- QVERIFY(server.isValid());
- server.serveDirectory(dataDirectory());
-
- QDeclarativeComponent component(&engine, testFileUrl("include_remote_missing.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QTRY_VERIFY(o->property("done").toBool() == true);
-
- QCOMPARE(o->property("test1").toBool(), true);
- QCOMPARE(o->property("test2").toBool(), true);
- QCOMPARE(o->property("test3").toBool(), true);
-
- delete o;
- }
-}
-
-void tst_qdeclarativeecmascript::signalHandlers()
-{
- QDeclarativeComponent component(&engine, testFileUrl("signalHandlers.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QVERIFY(o->property("count").toInt() == 0);
- QMetaObject::invokeMethod(o, "testSignalCall");
- QCOMPARE(o->property("count").toInt(), 1);
-
- QMetaObject::invokeMethod(o, "testSignalHandlerCall");
- QCOMPARE(o->property("count").toInt(), 1);
- QCOMPARE(o->property("errorString").toString(), QLatin1String("TypeError: Property 'onTestSignal' of object [object Object] is not a function"));
-
- QVERIFY(o->property("funcCount").toInt() == 0);
- QMetaObject::invokeMethod(o, "testSignalConnection");
- QCOMPARE(o->property("funcCount").toInt(), 1);
-
- QMetaObject::invokeMethod(o, "testSignalHandlerConnection");
- QCOMPARE(o->property("funcCount").toInt(), 2);
-
- QMetaObject::invokeMethod(o, "testSignalDefined");
- QCOMPARE(o->property("definedResult").toBool(), true);
-
- QMetaObject::invokeMethod(o, "testSignalHandlerDefined");
- QCOMPARE(o->property("definedHandlerResult").toBool(), true);
-
- delete o;
-}
-
-void tst_qdeclarativeecmascript::qtbug_10696()
-{
- QDeclarativeComponent component(&engine, testFileUrl("qtbug_10696.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
- delete o;
-}
-
-void tst_qdeclarativeecmascript::qtbug_11606()
-{
- QDeclarativeComponent component(&engine, testFileUrl("qtbug_11606.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
- QCOMPARE(o->property("test").toBool(), true);
- delete o;
-}
-
-void tst_qdeclarativeecmascript::qtbug_11600()
-{
- QDeclarativeComponent component(&engine, testFileUrl("qtbug_11600.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
- QCOMPARE(o->property("test").toBool(), true);
- delete o;
-}
-
-void tst_qdeclarativeecmascript::qtbug_21864()
-{
- QDeclarativeComponent component(&engine, testFileUrl("qtbug_21864.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
- QCOMPARE(o->property("test").toBool(), true);
- delete o;
-}
-
-void tst_qdeclarativeecmascript::rewriteMultiLineStrings()
-{
- {
- // QTBUG-23387
- QDeclarativeComponent component(&engine, testFileUrl("rewriteMultiLineStrings.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
- QTRY_COMPARE(o->property("test").toBool(), true);
- delete o;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("rewriteMultiLineStrings_crlf.1.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
- delete o;
- }
-}
-
-void tst_qdeclarativeecmascript::qobjectConnectionListExceptionHandling()
-{
- // QTBUG-23375
- QDeclarativeComponent component(&engine, testFileUrl("qobjectConnectionListExceptionHandling.qml"));
- QString warning = component.url().toString() + QLatin1String(":13: TypeError: Cannot read property 'undefined' of undefined");
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
- QObject *o = component.create();
- QVERIFY(o != 0);
- QCOMPARE(o->property("test").toBool(), true);
- delete o;
-}
-
-// Reading and writing non-scriptable properties should fail
-void tst_qdeclarativeecmascript::nonscriptable()
-{
- QDeclarativeComponent component(&engine, testFileUrl("nonscriptable.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
- QCOMPARE(o->property("readOk").toBool(), true);
- QCOMPARE(o->property("writeOk").toBool(), true);
- delete o;
-}
-
-// deleteLater() should not be callable from QML
-void tst_qdeclarativeecmascript::deleteLater()
-{
- QDeclarativeComponent component(&engine, testFileUrl("deleteLater.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
- QCOMPARE(o->property("test").toBool(), true);
- delete o;
-}
-
-void tst_qdeclarativeecmascript::in()
-{
- QDeclarativeComponent component(&engine, testFileUrl("in.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
- QCOMPARE(o->property("test1").toBool(), true);
- QCOMPARE(o->property("test2").toBool(), true);
- delete o;
-}
-
-void tst_qdeclarativeecmascript::typeOf()
-{
- QDeclarativeComponent component(&engine, testFileUrl("typeOf.qml"));
-
- // These warnings should not happen once QTBUG-21864 is fixed
- QString warning1 = component.url().toString() + QLatin1String(":16: Error: Cannot assign [undefined] to QString");
- QString warning2 = component.url().resolved(QUrl("typeOf.js")).toString() + QLatin1String(":1: ReferenceError: Can't find variable: a");
-
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
-
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QEXPECT_FAIL("", "QTBUG-21864", Abort);
- QCOMPARE(o->property("test1").toString(), QLatin1String("undefined"));
- QCOMPARE(o->property("test2").toString(), QLatin1String("object"));
- QCOMPARE(o->property("test3").toString(), QLatin1String("number"));
- QCOMPARE(o->property("test4").toString(), QLatin1String("string"));
- QCOMPARE(o->property("test5").toString(), QLatin1String("function"));
- QCOMPARE(o->property("test6").toString(), QLatin1String("object"));
- QCOMPARE(o->property("test7").toString(), QLatin1String("undefined"));
- QCOMPARE(o->property("test8").toString(), QLatin1String("boolean"));
- QCOMPARE(o->property("test9").toString(), QLatin1String("object"));
-
- delete o;
-}
-
-void tst_qdeclarativeecmascript::sharedAttachedObject()
-{
- QDeclarativeComponent component(&engine, testFileUrl("sharedAttachedObject.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
- QCOMPARE(o->property("test1").toBool(), true);
- QCOMPARE(o->property("test2").toBool(), true);
- delete o;
-}
-
-// QTBUG-13999
-void tst_qdeclarativeecmascript::objectName()
-{
- QDeclarativeComponent component(&engine, testFileUrl("objectName.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QCOMPARE(o->property("test1").toString(), QString("hello"));
- QCOMPARE(o->property("test2").toString(), QString("ell"));
-
- o->setObjectName("world");
-
- QCOMPARE(o->property("test1").toString(), QString("world"));
- QCOMPARE(o->property("test2").toString(), QString("orl"));
-
- delete o;
-}
-
-void tst_qdeclarativeecmascript::writeRemovesBinding()
-{
- QDeclarativeComponent component(&engine, testFileUrl("writeRemovesBinding.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QCOMPARE(o->property("test").toBool(), true);
-
- delete o;
-}
-
-// Test bindings assigned to alias properties actually assign to the alias' target
-void tst_qdeclarativeecmascript::aliasBindingsAssignCorrectly()
-{
- QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsAssignCorrectly.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QCOMPARE(o->property("test").toBool(), true);
-
- delete o;
-}
-
-// Test bindings assigned to alias properties override a binding on the target (QTBUG-13719)
-void tst_qdeclarativeecmascript::aliasBindingsOverrideTarget()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QCOMPARE(o->property("test").toBool(), true);
-
- delete o;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.2.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QCOMPARE(o->property("test").toBool(), true);
-
- delete o;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("aliasBindingsOverrideTarget.3.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QCOMPARE(o->property("test").toBool(), true);
-
- delete o;
- }
-}
-
-// Test that writes to alias properties override bindings on the alias target (QTBUG-13719)
-void tst_qdeclarativeecmascript::aliasWritesOverrideBindings()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QCOMPARE(o->property("test").toBool(), true);
-
- delete o;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.2.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QCOMPARE(o->property("test").toBool(), true);
-
- delete o;
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("aliasWritesOverrideBindings.3.qml"));
- QObject *o = component.create();
- QVERIFY(o != 0);
-
- QCOMPARE(o->property("test").toBool(), true);
-
- delete o;
- }
-}
-
-// Allow an alais to a composite element
-// QTBUG-20200
-void tst_qdeclarativeecmascript::aliasToCompositeElement()
-{
- QDeclarativeComponent component(&engine, testFileUrl("aliasToCompositeElement.qml"));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::qtbug_20344()
-{
- QDeclarativeComponent component(&engine, testFileUrl("qtbug_20344.qml"));
-
- QString warning = component.url().toString() + ":5: Error: Exception thrown from within QObject slot";
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::revisionErrors()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors.qml"));
- QString url = component.url().toString();
-
- QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
- QString warning2 = url + ":11: ReferenceError: Can't find variable: prop2";
- QString warning3 = url + ":13: ReferenceError: Can't find variable: method2";
-
- QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
- QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
- QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
- MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
- QVERIFY(object != 0);
- delete object;
- }
- {
- QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors2.qml"));
- QString url = component.url().toString();
-
- // MyRevisionedSubclass 1.0 uses MyRevisionedClass revision 0
- // method2, prop2 from MyRevisionedClass not available
- // method4, prop4 from MyRevisionedSubclass not available
- QString warning1 = url + ":8: ReferenceError: Can't find variable: prop2";
- QString warning2 = url + ":14: ReferenceError: Can't find variable: prop2";
- QString warning3 = url + ":10: ReferenceError: Can't find variable: prop4";
- QString warning4 = url + ":16: ReferenceError: Can't find variable: prop4";
- QString warning5 = url + ":20: ReferenceError: Can't find variable: method2";
-
- QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
- QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
- QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
- QTest::ignoreMessage(QtWarningMsg, warning4.toLatin1().constData());
- QTest::ignoreMessage(QtWarningMsg, warning5.toLatin1().constData());
- MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
- QVERIFY(object != 0);
- delete object;
- }
- {
- QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevisionErrors3.qml"));
- QString url = component.url().toString();
-
- // MyRevisionedSubclass 1.1 uses MyRevisionedClass revision 1
- // All properties/methods available, except MyRevisionedBaseClassUnregistered rev 1
- QString warning1 = url + ":30: ReferenceError: Can't find variable: methodD";
- QString warning2 = url + ":10: ReferenceError: Can't find variable: propD";
- QString warning3 = url + ":20: ReferenceError: Can't find variable: propD";
- QTest::ignoreMessage(QtWarningMsg, warning1.toLatin1().constData());
- QTest::ignoreMessage(QtWarningMsg, warning2.toLatin1().constData());
- QTest::ignoreMessage(QtWarningMsg, warning3.toLatin1().constData());
- MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
- QVERIFY(object != 0);
- delete object;
- }
-}
-
-void tst_qdeclarativeecmascript::revision()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision.qml"));
- QString url = component.url().toString();
-
- MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
- QVERIFY(object != 0);
- delete object;
- }
- {
- QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision2.qml"));
- QString url = component.url().toString();
-
- MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
- QVERIFY(object != 0);
- delete object;
- }
- {
- QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision3.qml"));
- QString url = component.url().toString();
-
- MyRevisionedClass *object = qobject_cast<MyRevisionedClass *>(component.create());
- QVERIFY(object != 0);
- delete object;
- }
- // Test that non-root classes can resolve revisioned methods
- {
- QDeclarativeComponent component(&engine, testFileUrl("metaobjectRevision4.qml"));
-
- QObject *object = component.create();
- QVERIFY(object != 0);
- QCOMPARE(object->property("test").toReal(), 11.);
- delete object;
- }
-}
-
-void tst_qdeclarativeecmascript::realToInt()
-{
- QDeclarativeComponent component(&engine, testFileUrl("realToInt.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
-
- QMetaObject::invokeMethod(object, "test1");
- QCOMPARE(object->value(), int(4));
- QMetaObject::invokeMethod(object, "test2");
- QCOMPARE(object->value(), int(8));
-}
-
-void tst_qdeclarativeecmascript::urlProperty()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("urlProperty.1.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
- object->setStringProperty("http://qt-project.org");
- QCOMPARE(object->urlProperty(), QUrl("http://qt-project.org/index.html"));
- QCOMPARE(object->intProperty(), 123);
- QCOMPARE(object->value(), 1);
- QCOMPARE(object->property("result").toBool(), true);
- }
-}
-
-void tst_qdeclarativeecmascript::urlPropertyWithEncoding()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("urlProperty.2.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject*>(component.create());
- QVERIFY(object != 0);
- object->setStringProperty("http://qt-project.org");
- QUrl encoded;
- encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
- QCOMPARE(object->urlProperty(), encoded);
- QCOMPARE(object->value(), 0); // Interpreting URL as string yields canonicalised version
- QCOMPARE(object->property("result").toBool(), true);
- }
-}
-
-void tst_qdeclarativeecmascript::urlListPropertyWithEncoding()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("urlListProperty.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- MySequenceConversionObject *msco1 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco1"));
- MySequenceConversionObject *msco2 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco2"));
- MySequenceConversionObject *msco3 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco3"));
- MySequenceConversionObject *msco4 = object->findChild<MySequenceConversionObject *>(QLatin1String("msco4"));
- QVERIFY(msco1 != 0 && msco2 != 0 && msco3 != 0 && msco4 != 0);
- QUrl encoded;
- encoded.setEncodedUrl("http://qt-project.org/?get%3cDATA%3e", QUrl::TolerantMode);
- QCOMPARE(msco1->urlListProperty(), (QList<QUrl>() << encoded));
- QCOMPARE(msco2->urlListProperty(), (QList<QUrl>() << encoded));
- QCOMPARE(msco3->urlListProperty(), (QList<QUrl>() << encoded << encoded));
- QCOMPARE(msco4->urlListProperty(), (QList<QUrl>() << encoded << encoded));
- delete object;
- }
-}
-
-void tst_qdeclarativeecmascript::dynamicString()
-{
- QDeclarativeComponent component(&engine, testFileUrl("dynamicString.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- QCOMPARE(object->property("stringProperty").toString(),
- QString::fromLatin1("string:Hello World false:0 true:1 uint32:100 int32:-100 double:3.14159 date:2011-02-11 05::30:50!"));
-}
-
-void tst_qdeclarativeecmascript::automaticSemicolon()
-{
- QDeclarativeComponent component(&engine, testFileUrl("automaticSemicolon.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-}
-
-void tst_qdeclarativeecmascript::unaryExpression()
-{
- QDeclarativeComponent component(&engine, testFileUrl("unaryExpression.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-}
-
-// Makes sure that a binding isn't double re-evaluated when it depends on the same variable twice
-void tst_qdeclarativeecmascript::doubleEvaluate()
-{
- QDeclarativeComponent component(&engine, testFileUrl("doubleEvaluate.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- WriteCounter *wc = qobject_cast<WriteCounter *>(object);
- QVERIFY(wc != 0);
- QCOMPARE(wc->count(), 1);
-
- wc->setProperty("x", 9);
-
- QCOMPARE(wc->count(), 2);
-
- delete object;
-}
-
-static QStringList messages;
-static void captureMsgHandler(QtMsgType, const char *msg)
-{
- messages.append(QLatin1String(msg));
-}
-
-void tst_qdeclarativeecmascript::nonNotifyable()
-{
- QV4Compiler::enableV4(false);
- QDeclarativeComponent component(&engine, testFileUrl("nonNotifyable.qml"));
- QV4Compiler::enableV4(true);
-
- QtMsgHandler old = qInstallMsgHandler(captureMsgHandler);
- messages.clear();
- QObject *object = component.create();
- qInstallMsgHandler(old);
-
- QVERIFY(object != 0);
-
- QString expected1 = QLatin1String("QDeclarativeExpression: Expression ") +
- component.url().toString() +
- QLatin1String(":5 depends on non-NOTIFYable properties:");
- QString expected2 = QLatin1String(" ") +
- QLatin1String(object->metaObject()->className()) +
- QLatin1String("::value");
-
- QCOMPARE(messages.length(), 2);
- QCOMPARE(messages.at(0), expected1);
- QCOMPARE(messages.at(1), expected2);
-
- delete object;
-}
-
-void tst_qdeclarativeecmascript::forInLoop()
-{
- QDeclarativeComponent component(&engine, testFileUrl("forInLoop.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
-
- QMetaObject::invokeMethod(object, "listProperty");
-
- QStringList r = object->property("listResult").toString().split("|", QString::SkipEmptyParts);
- QCOMPARE(r.size(), 3);
- QCOMPARE(r[0],QLatin1String("0=obj1"));
- QCOMPARE(r[1],QLatin1String("1=obj2"));
- QCOMPARE(r[2],QLatin1String("2=obj3"));
-
- //TODO: should test for in loop for other objects (such as QObjects) as well.
-
- delete object;
-}
-
-// An object the binding depends on is deleted while the binding is still running
-void tst_qdeclarativeecmascript::deleteWhileBindingRunning()
-{
- QDeclarativeComponent component(&engine, testFileUrl("deleteWhileBindingRunning.qml"));
- QObject *object = component.create();
- QVERIFY(object != 0);
- delete object;
-}
-
-void tst_qdeclarativeecmascript::qtbug_22679()
-{
- MyQmlObject object;
- object.setStringProperty(QLatin1String("Please work correctly"));
- engine.rootContext()->setContextProperty("contextProp", &object);
-
- QDeclarativeComponent component(&engine, testFileUrl("qtbug_22679.qml"));
- qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
- QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
-
- QObject *o = component.create();
- QVERIFY(o != 0);
- QCOMPARE(warningsSpy.count(), 0);
- delete o;
-}
-
-void tst_qdeclarativeecmascript::qtbug_22843_data()
-{
- QTest::addColumn<bool>("library");
-
- QTest::newRow("without .pragma library") << false;
- QTest::newRow("with .pragma library") << true;
-}
-
-void tst_qdeclarativeecmascript::qtbug_22843()
-{
- QFETCH(bool, library);
-
- QString fileName("qtbug_22843");
- if (library)
- fileName += QLatin1String(".library");
- fileName += QLatin1String(".qml");
-
- QDeclarativeComponent component(&engine, testFileUrl(fileName));
- QString url = component.url().toString();
- QString warning1 = url.left(url.length()-3) + QLatin1String("js:4: SyntaxError: Unexpected token )");
- QString warning2 = url + QLatin1String(":5: TypeError: Object [object Object] has no method 'func'");
-
- qRegisterMetaType<QList<QDeclarativeError> >("QList<QDeclarativeError>");
- QSignalSpy warningsSpy(&engine, SIGNAL(warnings(QList<QDeclarativeError>)));
- for (int x = 0; x < 3; ++x) {
- warningsSpy.clear();
- // For libraries, only the first import attempt should produce a
- // SyntaxError warning; subsequent component creation should not
- // attempt to reload the script.
- bool expectSyntaxError = !library || (x == 0);
- if (expectSyntaxError)
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning1));
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning2));
- QObject *object = component.create();
- QVERIFY(object != 0);
- QCOMPARE(warningsSpy.count(), 1 + (expectSyntaxError?1:0));
- delete object;
- }
-}
-
-
-void tst_qdeclarativeecmascript::switchStatement()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("switchStatement.1.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- // `object->value()' is the number of executed statements
-
- object->setStringProperty("A");
- QCOMPARE(object->value(), 5);
-
- object->setStringProperty("S");
- QCOMPARE(object->value(), 3);
-
- object->setStringProperty("D");
- QCOMPARE(object->value(), 3);
-
- object->setStringProperty("F");
- QCOMPARE(object->value(), 4);
-
- object->setStringProperty("something else");
- QCOMPARE(object->value(), 1);
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("switchStatement.2.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- // `object->value()' is the number of executed statements
-
- object->setStringProperty("A");
- QCOMPARE(object->value(), 5);
-
- object->setStringProperty("S");
- QCOMPARE(object->value(), 3);
-
- object->setStringProperty("D");
- QCOMPARE(object->value(), 3);
-
- object->setStringProperty("F");
- QCOMPARE(object->value(), 3);
-
- object->setStringProperty("something else");
- QCOMPARE(object->value(), 4);
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("switchStatement.3.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- // `object->value()' is the number of executed statements
-
- object->setStringProperty("A");
- QCOMPARE(object->value(), 5);
-
- object->setStringProperty("S");
- QCOMPARE(object->value(), 3);
-
- object->setStringProperty("D");
- QCOMPARE(object->value(), 3);
-
- object->setStringProperty("F");
- QCOMPARE(object->value(), 3);
-
- object->setStringProperty("something else");
- QCOMPARE(object->value(), 6);
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("switchStatement.4.qml"));
-
- QString warning = component.url().toString() + ":4: Unable to assign [undefined] to int";
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
-
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- // `object->value()' is the number of executed statements
-
- object->setStringProperty("A");
- QCOMPARE(object->value(), 5);
-
- object->setStringProperty("S");
- QCOMPARE(object->value(), 3);
-
- object->setStringProperty("D");
- QCOMPARE(object->value(), 3);
-
- object->setStringProperty("F");
- QCOMPARE(object->value(), 3);
-
- QTest::ignoreMessage(QtWarningMsg, qPrintable(warning));
-
- object->setStringProperty("something else");
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("switchStatement.5.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- // `object->value()' is the number of executed statements
-
- object->setStringProperty("A");
- QCOMPARE(object->value(), 1);
-
- object->setStringProperty("S");
- QCOMPARE(object->value(), 1);
-
- object->setStringProperty("D");
- QCOMPARE(object->value(), 1);
-
- object->setStringProperty("F");
- QCOMPARE(object->value(), 1);
-
- object->setStringProperty("something else");
- QCOMPARE(object->value(), 1);
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("switchStatement.6.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- // `object->value()' is the number of executed statements
-
- object->setStringProperty("A");
- QCOMPARE(object->value(), 123);
-
- object->setStringProperty("S");
- QCOMPARE(object->value(), 123);
-
- object->setStringProperty("D");
- QCOMPARE(object->value(), 321);
-
- object->setStringProperty("F");
- QCOMPARE(object->value(), 321);
-
- object->setStringProperty("something else");
- QCOMPARE(object->value(), 0);
- }
-}
-
-void tst_qdeclarativeecmascript::withStatement()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("withStatement.1.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->value(), 123);
- }
-}
-
-void tst_qdeclarativeecmascript::tryStatement()
-{
- {
- QDeclarativeComponent component(&engine, testFileUrl("tryStatement.1.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->value(), 123);
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("tryStatement.2.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->value(), 321);
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("tryStatement.3.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->value(), 1);
- }
-
- {
- QDeclarativeComponent component(&engine, testFileUrl("tryStatement.4.qml"));
- MyQmlObject *object = qobject_cast<MyQmlObject *>(component.create());
- QVERIFY(object != 0);
-
- QCOMPARE(object->value(), 1);
- }
-}
-
-class CppInvokableWithQObjectDerived : public QObject
-{
- Q_OBJECT
-public:
- CppInvokableWithQObjectDerived() {}
- ~CppInvokableWithQObjectDerived() {}
-
- Q_INVOKABLE MyQmlObject *createMyQmlObject(QString data)
- {
- MyQmlObject *obj = new MyQmlObject();
- obj->setStringProperty(data);
- return obj;
- }
-
- Q_INVOKABLE QString getStringProperty(MyQmlObject *obj)
- {
- return obj->stringProperty();
- }
-};
-
-void tst_qdeclarativeecmascript::invokableWithQObjectDerived()
-{
- CppInvokableWithQObjectDerived invokable;
-
- {
- QDeclarativeEngine engine;
- engine.rootContext()->setContextProperty("invokable", &invokable);
-
- QDeclarativeComponent component(&engine, testFileUrl("qobjectDerivedArgument.qml"));
-
- QObject *object = component.create();
-
- QVERIFY(object != 0);
- QVERIFY(object->property("result").value<bool>() == true);
-
- delete object;
- }
-}
-
-QTEST_MAIN(tst_qdeclarativeecmascript)
-
-#include "tst_qdeclarativeecmascript.moc"