diff options
author | Kent Hansen <kent.hansen@nokia.com> | 2010-06-17 10:27:43 (GMT) |
---|---|---|
committer | Kent Hansen <kent.hansen@nokia.com> | 2010-06-17 13:01:56 (GMT) |
commit | d8d547b92e02546cb030ac9d4a45fe0d89e0e7f6 (patch) | |
tree | dd95bb2244e0c44d66f1bb0cebd38fc71b5da140 /tests/auto/qscriptextqobject | |
parent | 458a18284406dedcf0628c651fb3511553dbcb58 (diff) | |
download | Qt-d8d547b92e02546cb030ac9d4a45fe0d89e0e7f6.zip Qt-d8d547b92e02546cb030ac9d4a45fe0d89e0e7f6.tar.gz Qt-d8d547b92e02546cb030ac9d4a45fe0d89e0e7f6.tar.bz2 |
Usefully convert from QtScript object/array to QVariant
For arrays, the conversion would crash if the array was cyclic.
Introduce a set that keeps track of which objects are being
converted, and return an empty list when a cycle is detected.
For other types of objects, the object was previously attempted
to be converted to a primitive, which typically meant you would
get the string representation ("[object Object]"), since most
(practically all) objects can be converted to a string -- not
useful at all.
Change the conversion so it converts the object to a QVariantMap
instead. This was already done for slots that took a QVariantMap
as argument, but only one level deep. Make the conversion recursive,
using the same mechanism as for arrays to detect cycles.
This change also means that you get a meaningful
JS object => QVariant => JS object roundtrip.
It also aligns the behavior with the Qt WebKit bridge.
Update the documentation to describe the new behavior.
The 4.7 changelog will also be updated under "important behavioral
changes".
This change exposed an issue with one of the QML autotests: A JS
object was assigned to a QVariant property, which caused it to be
converted to a string (rather than a QVariantMap) -- just shows
that the previous behavior was unintuitive). Later, this variant
property is compared to another object, the intention being to
compare the _properties_ of the two objects; but because the variant
property contained a string, this would cause the other operand
(object) to be converted to a string as well ("[object Object]"),
causing a meaningless test pass.
Change the test to deserialize both objects using JSON.stringify,
and compare the resulting strings, so that actual
JS object => QVariant(Map) => JS object roundtrip is tested (the
intention).
Task-number: QTBUG-3511
Reviewed-by: Olivier Goffart
Diffstat (limited to 'tests/auto/qscriptextqobject')
-rw-r--r-- | tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp | 140 |
1 files changed, 140 insertions, 0 deletions
diff --git a/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp b/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp index 09070e6..11813d8 100644 --- a/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp +++ b/tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp @@ -287,6 +287,8 @@ public: { m_qtFunctionInvoked = 15; m_actuals << v; return v; } Q_INVOKABLE QVariantMap myInvokableWithVariantMapArg(const QVariantMap &vm) { m_qtFunctionInvoked = 16; m_actuals << vm; return vm; } + Q_INVOKABLE QVariantList myInvokableWithVariantListArg(const QVariantList &lst) + { m_qtFunctionInvoked = 62; m_actuals.append(QVariant(lst)); return lst; } Q_INVOKABLE QList<int> myInvokableWithListOfIntArg(const QList<int> &lst) { m_qtFunctionInvoked = 17; m_actuals << qVariantFromValue(lst); return lst; } Q_INVOKABLE QObject* myInvokableWithQObjectStarArg(QObject *obj) @@ -535,6 +537,10 @@ private slots: void emitAfterReceiverDeleted(); void inheritedSlots(); void enumerateMetaObject(); + void nestedArrayAsSlotArgument_data(); + void nestedArrayAsSlotArgument(); + void nestedObjectAsSlotArgument_data(); + void nestedObjectAsSlotArgument(); private: QScriptEngine *m_engine; @@ -3164,5 +3170,139 @@ void tst_QScriptExtQObject::enumerateMetaObject() } } +void tst_QScriptExtQObject::nestedArrayAsSlotArgument_data() +{ + QTest::addColumn<QString>("program"); + QTest::addColumn<QVariantList>("expected"); + + QTest::newRow("[[]]") + << QString::fromLatin1("[[]]") + << (QVariantList() << (QVariant(QVariantList()))); + QTest::newRow("[[123]]") + << QString::fromLatin1("[[123]]") + << (QVariantList() << (QVariant(QVariantList() << 123))); + QTest::newRow("[[], 123]") + << QString::fromLatin1("[[], 123]") + << (QVariantList() << QVariant(QVariantList()) << 123); + + // Cyclic + QTest::newRow("var a=[]; a.push(a)") + << QString::fromLatin1("var a=[]; a.push(a); a") + << (QVariantList() << QVariant(QVariantList())); + QTest::newRow("var a=[]; a.push(123, a)") + << QString::fromLatin1("var a=[]; a.push(123, a); a") + << (QVariantList() << 123 << QVariant(QVariantList())); + QTest::newRow("var a=[]; var b=[]; a.push(b); b.push(a)") + << QString::fromLatin1("var a=[]; var b=[]; a.push(b); b.push(a); a") + << (QVariantList() << QVariant(QVariantList() << QVariant(QVariantList()))); + QTest::newRow("var a=[]; var b=[]; a.push(123, b); b.push(456, a)") + << QString::fromLatin1("var a=[]; var b=[]; a.push(123, b); b.push(456, a); a") + << (QVariantList() << 123 << QVariant(QVariantList() << 456 << QVariant(QVariantList()))); +} + +void tst_QScriptExtQObject::nestedArrayAsSlotArgument() +{ + QFETCH(QString, program); + QFETCH(QVariantList, expected); + QScriptValue a = m_engine->evaluate(program); + QVERIFY(!a.isError()); + QVERIFY(a.isArray()); + // Slot that takes QVariantList + { + QVERIFY(!m_engine->evaluate("myObject.myInvokableWithVariantListArg") + .call(QScriptValue(), QScriptValueList() << a).isError()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 62); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).type(), QVariant::List); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toList(), expected); + } + // Slot that takes QVariant + { + m_myObject->resetQtFunctionInvoked(); + QVERIFY(!m_engine->evaluate("myObject.myInvokableWithVariantArg") + .call(QScriptValue(), QScriptValueList() << a).isError()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 15); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).type(), QVariant::List); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toList(), expected); + } +} + +void tst_QScriptExtQObject::nestedObjectAsSlotArgument_data() +{ + QTest::addColumn<QString>("program"); + QTest::addColumn<QVariantMap>("expected"); + + { + QVariantMap m; + m["a"] = QVariantMap(); + QTest::newRow("{ a:{} }") + << QString::fromLatin1("({ a:{} })") + << m; + } + { + QVariantMap m, m2; + m2["b"] = 10; + m2["c"] = 20; + m["a"] = m2; + QTest::newRow("{ a:{b:10, c:20} }") + << QString::fromLatin1("({ a:{b:10, c:20} })") + << m; + } + { + QVariantMap m; + m["a"] = 10; + m["b"] = QVariantList() << 20 << 30; + QTest::newRow("{ a:10, b:[20, 30]}") + << QString::fromLatin1("({ a:10, b:[20,30]})") + << m; + } + + // Cyclic + { + QVariantMap m; + m["p"] = QVariantMap(); + QTest::newRow("var o={}; o.p=o") + << QString::fromLatin1("var o={}; o.p=o; o") + << m; + } + { + QVariantMap m; + m["p"] = 123; + m["q"] = QVariantMap(); + QTest::newRow("var o={}; o.p=123; o.q=o") + << QString::fromLatin1("var o={}; o.p=123; o.q=o; o") + << m; + } +} + +void tst_QScriptExtQObject::nestedObjectAsSlotArgument() +{ + QFETCH(QString, program); + QFETCH(QVariantMap, expected); + QScriptValue o = m_engine->evaluate(program); + QVERIFY(!o.isError()); + QVERIFY(o.isObject()); + // Slot that takes QVariantMap + { + QVERIFY(!m_engine->evaluate("myObject.myInvokableWithVariantMapArg") + .call(QScriptValue(), QScriptValueList() << o).isError()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 16); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).type(), QVariant::Map); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toMap(), expected); + } + // Slot that takes QVariant + { + m_myObject->resetQtFunctionInvoked(); + QVERIFY(!m_engine->evaluate("myObject.myInvokableWithVariantArg") + .call(QScriptValue(), QScriptValueList() << o).isError()); + QCOMPARE(m_myObject->qtFunctionInvoked(), 15); + QCOMPARE(m_myObject->qtFunctionActuals().size(), 1); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).type(), QVariant::Map); + QCOMPARE(m_myObject->qtFunctionActuals().at(0).toMap(), expected); + } +} + QTEST_MAIN(tst_QScriptExtQObject) #include "tst_qscriptextqobject.moc" |