summaryrefslogtreecommitdiffstats
path: root/tests
diff options
context:
space:
mode:
authorKent Hansen <kent.hansen@nokia.com>2010-06-17 10:27:43 (GMT)
committerKent Hansen <kent.hansen@nokia.com>2010-06-17 13:01:56 (GMT)
commitd8d547b92e02546cb030ac9d4a45fe0d89e0e7f6 (patch)
treedd95bb2244e0c44d66f1bb0cebd38fc71b5da140 /tests
parent458a18284406dedcf0628c651fb3511553dbcb58 (diff)
downloadQt-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')
-rw-r--r--tests/auto/declarative/qdeclarativeworkerscript/data/BaseWorker.qml2
-rw-r--r--tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp6
-rw-r--r--tests/auto/qscriptextqobject/tst_qscriptextqobject.cpp140
-rw-r--r--tests/auto/qscriptvalue/tst_qscriptvalue.cpp89
-rw-r--r--tests/auto/qscriptvalue/tst_qscriptvalue.h2
5 files changed, 234 insertions, 5 deletions
diff --git a/tests/auto/declarative/qdeclarativeworkerscript/data/BaseWorker.qml b/tests/auto/declarative/qdeclarativeworkerscript/data/BaseWorker.qml
index d275ca8..e06afa2 100644
--- a/tests/auto/declarative/qdeclarativeworkerscript/data/BaseWorker.qml
+++ b/tests/auto/declarative/qdeclarativeworkerscript/data/BaseWorker.qml
@@ -13,7 +13,7 @@ WorkerScript {
function compareLiteralResponse(expected) {
var e = eval('(' + expected + ')')
- return worker.response == e
+ return JSON.stringify(worker.response) == JSON.stringify(e)
}
onMessage: {
diff --git a/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp b/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp
index 52c11e9..8e98874 100644
--- a/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp
+++ b/tests/auto/declarative/qdeclarativeworkerscript/tst_qdeclarativeworkerscript.cpp
@@ -170,13 +170,15 @@ void tst_QDeclarativeWorkerScript::messaging_sendJsObject()
QDeclarativeWorkerScript *worker = qobject_cast<QDeclarativeWorkerScript*>(component.create());
QVERIFY(worker != 0);
- QString jsObject = "{'name': 'zyz', 'spell power': 3101, 'haste': 1125}";
+ // Properties are in alphabetical order to enable string-based comparison after
+ // QVariant roundtrip, since the properties will be stored in a QVariantMap.
+ QString jsObject = "{'haste': 1125, 'name': 'zyz', 'spell power': 3101}";
QScriptEngine *engine = QDeclarativeEnginePrivate::getScriptEngine(qmlEngine(worker));
QScriptValue sv = engine->newObject();
+ sv.setProperty("haste", 1125);
sv.setProperty("name", "zyz");
sv.setProperty("spell power", 3101);
- sv.setProperty("haste", 1125);
QVERIFY(QMetaObject::invokeMethod(worker, "testSend", Q_ARG(QVariant, qVariantFromValue(sv))));
waitForEchoMessage(worker);
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"
diff --git a/tests/auto/qscriptvalue/tst_qscriptvalue.cpp b/tests/auto/qscriptvalue/tst_qscriptvalue.cpp
index aa9fa15..8aa4e711 100644
--- a/tests/auto/qscriptvalue/tst_qscriptvalue.cpp
+++ b/tests/auto/qscriptvalue/tst_qscriptvalue.cpp
@@ -1270,7 +1270,7 @@ void tst_QScriptValue::toVariant_old()
QCOMPARE(opaque.toVariant(), var);
QScriptValue object = eng.newObject();
- QCOMPARE(object.toVariant(), QVariant(QString("[object Object]")));
+ QCOMPARE(object.toVariant(), QVariant(QVariantMap()));
QScriptValue qobject = eng.newQObject(this);
{
@@ -2296,7 +2296,7 @@ void tst_QScriptValue::getSetScriptClass()
QCOMPARE(obj.scriptClass(), (QScriptClass*)&testClass);
QVERIFY(obj.isObject());
QVERIFY(!obj.isVariant());
- QVERIFY(!obj.toVariant().isValid());
+ QCOMPARE(obj.toVariant(), QVariant(QVariantMap()));
}
{
QScriptValue obj = eng.newQObject(this);
@@ -3472,4 +3472,89 @@ void tst_QScriptValue::objectId()
QVERIFY(obj.strictlyEquals(eng.globalObject()));
}
+void tst_QScriptValue::nestedObjectToVariant_data()
+{
+ QTest::addColumn<QString>("program");
+ QTest::addColumn<QVariant>("expected");
+
+ // Array literals
+ QTest::newRow("[[]]")
+ << QString::fromLatin1("[[]]")
+ << QVariant(QVariantList() << (QVariant(QVariantList())));
+ QTest::newRow("[[123]]")
+ << QString::fromLatin1("[[123]]")
+ << QVariant(QVariantList() << (QVariant(QVariantList() << 123)));
+ QTest::newRow("[[], 123]")
+ << QString::fromLatin1("[[], 123]")
+ << QVariant(QVariantList() << QVariant(QVariantList()) << 123);
+
+ // Cyclic arrays
+ QTest::newRow("var a=[]; a.push(a)")
+ << QString::fromLatin1("var a=[]; a.push(a); a")
+ << QVariant(QVariantList() << QVariant(QVariantList()));
+ QTest::newRow("var a=[]; a.push(123, a)")
+ << QString::fromLatin1("var a=[]; a.push(123, a); a")
+ << QVariant(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")
+ << QVariant(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")
+ << QVariant(QVariantList() << 123 << QVariant(QVariantList() << 456 << QVariant(QVariantList())));
+
+ // Object literals
+ {
+ QVariantMap m;
+ m["a"] = QVariantMap();
+ QTest::newRow("{ a:{} }")
+ << QString::fromLatin1("({ a:{} })")
+ << QVariant(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} })")
+ << QVariant(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]})")
+ << QVariant(m);
+ }
+
+ // Cyclic objects
+ {
+ QVariantMap m;
+ m["p"] = QVariantMap();
+ QTest::newRow("var o={}; o.p=o")
+ << QString::fromLatin1("var o={}; o.p=o; o")
+ << QVariant(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")
+ << QVariant(m);
+ }
+}
+
+void tst_QScriptValue::nestedObjectToVariant()
+{
+ QScriptEngine eng;
+ QFETCH(QString, program);
+ QFETCH(QVariant, expected);
+ QScriptValue o = eng.evaluate(program);
+ QVERIFY(!o.isError());
+ QVERIFY(o.isObject());
+ QCOMPARE(o.toVariant(), expected);
+}
+
QTEST_MAIN(tst_QScriptValue)
diff --git a/tests/auto/qscriptvalue/tst_qscriptvalue.h b/tests/auto/qscriptvalue/tst_qscriptvalue.h
index aae35b2..8bfaa6a 100644
--- a/tests/auto/qscriptvalue/tst_qscriptvalue.h
+++ b/tests/auto/qscriptvalue/tst_qscriptvalue.h
@@ -225,6 +225,8 @@ private slots:
void engineDeleted();
void valueOfWithClosure();
void objectId();
+ void nestedObjectToVariant_data();
+ void nestedObjectToVariant();
private:
typedef void (tst_QScriptValue::*InitDataFunction)();