diff options
Diffstat (limited to 'tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp')
-rw-r--r-- | tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp | 6097 |
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" |