diff options
author | Gunnar Sletta <gunnar.sletta@nokia.com> | 2011-08-25 11:47:24 +0200 |
---|---|---|
committer | Gunnar Sletta <gunnar.sletta@nokia.com> | 2011-08-25 12:52:15 +0200 |
commit | 8e6ecb56e5d61ce661422779c9d9cbf22f081a34 (patch) | |
tree | 227aeb360800a49de58472bd39bc5f4c596c1b15 /tests/auto/declarative/qdeclarativeecmascript | |
parent | c9224b6cf5cceb7d5314f7504d44bfe72bc66950 (diff) | |
parent | 0d84e957297b4ffa6ab5b0b5bcf8b169d567d298 (diff) |
Merge branch 'master' into refactor
Conflicts:
src/declarative/items/qsgcanvas.cpp
src/declarative/items/qsgitem.cpp
src/declarative/items/qsgtextnode.cpp
tests/auto/declarative/examples/examples.pro
tools/qmlviewer/qmlviewer.pro
Change-Id: Icbb0ef5dc79b658c62fd2b2c25a66c9bb3cbeb10
Diffstat (limited to 'tests/auto/declarative/qdeclarativeecmascript')
9 files changed, 356 insertions, 0 deletions
diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/AliasPropertyComponent.qml b/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/AliasPropertyComponent.qml new file mode 100644 index 0000000000..9135e79469 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/AliasPropertyComponent.qml @@ -0,0 +1,17 @@ +import QtQuick 2.0 + +Item { + id: apc + property alias sourceComponent: loader.sourceComponent + + Component { + id: redSquare + Rectangle { color: "red"; width: 10; height: 10 } + } + + Loader { + id: loader + objectName: "loader" + sourceComponent: redSquare + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/aliasPropertyReset.1.qml b/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/aliasPropertyReset.1.qml new file mode 100644 index 0000000000..a27c16dd2e --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/aliasPropertyReset.1.qml @@ -0,0 +1,23 @@ +import QtQuick 1.0 +import Qt.test 1.0 + +Item { + id: first + property bool aliasIsUndefined: false + property alias sourceComponentAlias: loader.sourceComponent + + Component { + id: redSquare + Rectangle { color: "red"; width: 10; height: 10 } + } + + Loader { + id: loader + sourceComponent: redSquare + } + + function resetAliased() { + loader.sourceComponent = undefined; + aliasIsUndefined = (sourceComponentAlias == undefined); + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/aliasPropertyReset.2.qml b/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/aliasPropertyReset.2.qml new file mode 100644 index 0000000000..fa2bb5eb6d --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/aliasPropertyReset.2.qml @@ -0,0 +1,23 @@ +import QtQuick 1.0 +import Qt.test 1.0 + +Item { + id: first + property bool loaderSourceComponentIsUndefined: false + property alias sourceComponentAlias: loader.sourceComponent + + Component { + id: redSquare + Rectangle { color: "red"; width: 10; height: 10 } + } + + Loader { + id: loader + sourceComponent: redSquare + } + + function resetAlias() { + sourceComponentAlias = undefined; + loaderSourceComponentIsUndefined = (loader.sourceComponent == undefined); + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/aliasPropertyReset.3.qml b/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/aliasPropertyReset.3.qml new file mode 100644 index 0000000000..4fa6861b08 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/aliasPropertyReset.3.qml @@ -0,0 +1,31 @@ +import QtQuick 1.0 +import Qt.test 1.0 + +Item { + id: first + property bool loaderTwoSourceComponentIsUndefined: false + property bool loaderOneSourceComponentIsUndefined: false + property alias sourceComponentAlias: loaderOne.sourceComponent + + Component { + id: redSquare + Rectangle { color: "red"; width: 10; height: 10 } + } + + Loader { + id: loaderOne + sourceComponent: loaderTwo.sourceComponent + } + + Loader { + id: loaderTwo + sourceComponent: redSquare + x: 15 + } + + function resetAlias() { + sourceComponentAlias = undefined; // loaderOne.sourceComponent should be set to undefined instead of l2.sc + loaderOneSourceComponentIsUndefined = (loaderOne.sourceComponent == undefined); // should be true + loaderTwoSourceComponentIsUndefined = (loaderTwo.sourceComponent == undefined); // should be false + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/aliasPropertyReset.4.qml b/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/aliasPropertyReset.4.qml new file mode 100644 index 0000000000..56fcc2ec7c --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/aliasPropertyReset.4.qml @@ -0,0 +1,26 @@ +import QtQuick 1.0 +import Qt.test 1.0 + +Item { + id: first + property alias sourceComponentAlias: loader.sourceComponent + + Component { + id: redSquare + Rectangle { color: "red"; width: 10; height: 10 } + } + + Loader { + id: loader + objectName: "loader" + sourceComponent: redSquare + } + + function resetAlias() { + sourceComponentAlias = undefined; // ensure we don't crash after deletion of loader. + } + + function setAlias() { + sourceComponentAlias = redSquare; + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/aliasPropertyReset.5.qml b/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/aliasPropertyReset.5.qml new file mode 100644 index 0000000000..a046bbf504 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/aliasPropertyReset.5.qml @@ -0,0 +1,14 @@ +import QtQuick 1.0 +import Qt.test 1.0 + +Item { + id: root + + AliasPropertyComponent { + sourceComponent: returnsUndefined() + } + + function returnsUndefined() { + return undefined; + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/aliasPropertyReset.error.1.qml b/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/aliasPropertyReset.error.1.qml new file mode 100644 index 0000000000..22311d6bb3 --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/aliasreset/aliasPropertyReset.error.1.qml @@ -0,0 +1,18 @@ +import QtQuick 1.0 +import Qt.test 1.0 + +MyQmlObject { + id: first + property bool aliasedIntIsUndefined: false + property alias intAlias: objprop.intp + + objectProperty: QtObject { + id: objprop + property int intp: 12 + } + + function resetAlias() { + intAlias = undefined; // should error + aliasedIntIsUndefined = (objprop.intp == undefined); + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/data/declarativeHasOwnProperty.qml b/tests/auto/declarative/qdeclarativeecmascript/data/declarativeHasOwnProperty.qml new file mode 100644 index 0000000000..12598b3b9f --- /dev/null +++ b/tests/auto/declarative/qdeclarativeecmascript/data/declarativeHasOwnProperty.qml @@ -0,0 +1,72 @@ +import QtQuick 2.0 +import Qt.test 1.0 +import Qt.test.qobjectApi 1.0 as QtTestQObjectApi + +Item { + id: obj + objectName: "objName" + property int someIntProperty: 10 + property bool result: false + + function testHasOwnPropertySuccess() + { + obj.result = obj.hasOwnProperty("someIntProperty"); + } + + function testHasOwnPropertyFailure() + { + obj.result = obj.hasOwnProperty("someNonexistentProperty"); + } + + MyTypeObject { + id: typeObj + objectName: "typeObj" + pointProperty: Qt.point(34, 29) + variantProperty: Qt.vector3d(1, 2, 3) + stringProperty: "test string" + property list<Rectangle> listProperty: [ Rectangle { width: 10; height: 10 } ] + property list<Rectangle> emptyListProperty + + property bool valueTypeHasOwnProperty + property bool valueTypeHasOwnProperty2 + property bool variantTypeHasOwnProperty + property bool stringTypeHasOwnProperty + property bool listTypeHasOwnProperty + property bool listAtValidHasOwnProperty + property bool emptyListTypeHasOwnProperty + property bool enumTypeHasOwnProperty + property bool typenameHasOwnProperty + property bool typenameHasOwnProperty2 + property bool moduleApiTypeHasOwnProperty + property bool moduleApiPropertyTypeHasOwnProperty + function testHasOwnPropertySuccess() { + valueTypeHasOwnProperty = !typeObj.pointProperty.hasOwnProperty("nonexistentpropertyname"); + valueTypeHasOwnProperty2 = typeObj.pointProperty.hasOwnProperty("x"); // should be true + variantTypeHasOwnProperty = !typeObj.variantProperty.hasOwnProperty("nonexistentpropertyname"); + stringTypeHasOwnProperty = !typeObj.stringProperty.hasOwnProperty("nonexistentpropertyname"); + listTypeHasOwnProperty = !typeObj.listProperty.hasOwnProperty("nonexistentpropertyname"); + listAtValidHasOwnProperty = !typeObj.listProperty[0].hasOwnProperty("nonexistentpropertyname"); + emptyListTypeHasOwnProperty = !typeObj.emptyListProperty.hasOwnProperty("nonexistentpropertyname"); + enumTypeHasOwnProperty = !MyTypeObject.EnumVal1.hasOwnProperty("nonexistentpropertyname"); + typenameHasOwnProperty = !MyTypeObject.hasOwnProperty("nonexistentpropertyname"); + typenameHasOwnProperty2 = MyTypeObject.hasOwnProperty("EnumVal1"); // should be true. + moduleApiTypeHasOwnProperty = !QtTestQObjectApi.hasOwnProperty("nonexistentpropertyname"); + moduleApiPropertyTypeHasOwnProperty = !QtTestQObjectApi.qobjectTestProperty.hasOwnProperty("nonexistentpropertyname"); + } + + property bool enumNonValueHasOwnProperty + function testHasOwnPropertyFailureOne() { + enumNonValueHasOwnProperty = !MyTypeObject.NonexistentEnumVal.hasOwnProperty("nonexistentpropertyname"); + } + + property bool moduleApiNonPropertyHasOwnProperty + function testHasOwnPropertyFailureTwo() { + moduleApiNonPropertyHasOwnProperty = !QtTestQObjectApi.someNonexistentProperty.hasOwnProperty("nonexistentpropertyname"); + } + + property bool listAtInvalidHasOwnProperty + function testHasOwnPropertyFailureThree() { + listAtInvalidHasOwnProperty = !typeObj.listProperty[5].hasOwnProperty("nonexistentpropertyname"); + } + } +} diff --git a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp index 6c629a80f7..3efe18909c 100644 --- a/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp +++ b/tests/auto/declarative/qdeclarativeecmascript/tst_qdeclarativeecmascript.cpp @@ -104,6 +104,7 @@ private slots: void constantsOverrideBindings(); void outerBindingOverridesInnerBinding(); void aliasPropertyAndBinding(); + void aliasPropertyReset(); void nonExistentAttachedObject(); void scope(); void importScope(); @@ -113,6 +114,7 @@ private slots: void dynamicCreation(); void dynamicDestruction(); void objectToString(); + void objectHasOwnProperty(); void selfDeletingBinding(); void extendedObjectPropertyLookup(); void scriptErrors(); @@ -1037,6 +1039,87 @@ void tst_qdeclarativeecmascript::aliasPropertyAndBinding() 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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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, TEST_FILE("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 = TEST_FILE("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"); @@ -1141,6 +1224,55 @@ void tst_qdeclarativeecmascript::objectToString() } /* + tests that id.hasOwnProperty() works +*/ +void tst_qdeclarativeecmascript::objectHasOwnProperty() +{ + QUrl url = TEST_FILE("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. |