diff options
author | Fabian Kosmale <fabian.kosmale@qt.io> | 2019-12-09 15:26:14 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2019-12-20 10:51:21 +0100 |
commit | ea3bfc91e2a0fc8309f75e960f1891f15d7351c9 (patch) | |
tree | ff66f2071c8c14f3b298660c37be21f832f7a867 /tests | |
parent | 155a2e0d8d1d9c07fa22f523d84e3d583697aff4 (diff) |
QV4Engine: support conversion of QJSValue to SequenceType
8704c640946ac852668638e2980d3e2b78aa27ae introduced new conversions
via sequentialIterableToJS. Due to that, QVariant properties which
formerly stored e.g. std::vector<QObject*> now would store a QJSValue.
Those would still claim to support a conversion to QVariantList, but
-contrary to what our documentation says-, we were not able to do a
conversion to QSequentialIterable. The default constructed
QSequentialIterable would then crash when calling begin(), as that
function pointer was null.
This patch fixes this by adding the necessary support to convert a
QJSValue containing an array.
Non-array QJSValues will still return an "empty" QSequentialIterable.
Note that this changes what happens when a QJSValue is converted to a
QVariantList, as QVariantValueHelperInterface<QVariantList> will check
first if there is a converter to QSequentialIterableImpl before
attempting to call any directly installed converter to QVariantList. In
order to not change the existing behavior, the QSequentialIterable
returns the QVariant corresponding to the QJSValue at a given array
position, intead of a QVariant containing the QJSValue.
Fixes: QTBUG-80609
Change-Id: I8101229c0d2043b3f2d618ed035b279844802dd8
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/qml/qjsvalue/tst_qjsvalue.cpp | 64 | ||||
-rw-r--r-- | tests/auto/qml/qjsvalue/tst_qjsvalue.h | 2 |
2 files changed, 66 insertions, 0 deletions
diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp index 37d0ea4dea..95f554776f 100644 --- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp +++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp @@ -2708,6 +2708,70 @@ void tst_QJSValue::nestedObjectToVariant() QCOMPARE(o.toVariant(), expected); } +static int instanceCount = 0; + +struct MyType +{ + MyType(int n = 0, const char *t=nullptr): number(n), text(t) + { + ++instanceCount; + } + MyType(const MyType &other) + : number(other.number), text(other.text) + { + ++instanceCount; + } + ~MyType() + { + --instanceCount; + } + int number; + const char *text; +}; + +Q_DECLARE_METATYPE(MyType) +Q_DECLARE_METATYPE(MyType*) + +void tst_QJSValue::jsvalueArrayToSequenceType() +{ + QCOMPARE(instanceCount, 0); + { + QJSEngine eng {}; + auto testObject = eng.newObject(); + testObject.setProperty("test", 42); + testObject.setProperty("mytypeobject", eng.toScriptValue(QVariant::fromValue(MyType {42, "hello"}))); + auto array = eng.newArray(4); + array.setProperty(0, QLatin1String("Hello World")); + array.setProperty(1, 42); + array.setProperty(2, QJSValue(QJSValue::UndefinedValue)); + array.setProperty(3, testObject); + auto asVariant = QVariant::fromValue(array); + QVERIFY(asVariant.canConvert<QVariantList>()); + auto asIterable = asVariant.value<QSequentialIterable>(); + for (auto it = asIterable.begin(); it != asIterable.end(); ++it) { + Q_UNUSED(*it) + } + int i = 0; + for (QVariant myVariant: asIterable) { + QCOMPARE(myVariant.isValid(), i != 2); + ++i; + } + QVERIFY(asIterable.at(2).value<QVariant>().isNull()); + QCOMPARE(asIterable.at(3).value<QVariantMap>().find("mytypeobject")->value<MyType>().number, 42); + QCOMPARE(asIterable.at(0).value<QVariant>().toString(), QLatin1String("Hello World")); + auto it1 = asIterable.begin(); + auto it2 = asIterable.begin(); + QCOMPARE((*it1).value<QVariant>().toString(), (*it2).value<QVariant>().toString()); + QCOMPARE((*it1).value<QVariant>().toString(), QLatin1String("Hello World")); + ++it2; + QCOMPARE((*it1).value<QVariant>().toString(), QLatin1String("Hello World")); + QCOMPARE((*it2).value<QVariant>().toInt(), 42); + } + // tests need to be done after engine has been destroyed, else it will hold a reference until + // the gc decides to collect it + QCOMPARE(instanceCount, 0); +} + void tst_QJSValue::deleteFromDifferentThread() { #if !QT_CONFIG(thread) diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.h b/tests/auto/qml/qjsvalue/tst_qjsvalue.h index f704169d43..d85b9a0552 100644 --- a/tests/auto/qml/qjsvalue/tst_qjsvalue.h +++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.h @@ -142,6 +142,8 @@ private slots: void nestedObjectToVariant_data(); void nestedObjectToVariant(); + void jsvalueArrayToSequenceType(); + void deleteFromDifferentThread(); private: |