diff options
author | Simon Hausmann <simon.hausmann@digia.com> | 2014-09-10 17:13:10 +0200 |
---|---|---|
committer | Lars Knoll <lars.knoll@digia.com> | 2014-09-17 08:13:11 +0200 |
commit | 3dbe05f6bf3fd51ce8097c35f6c7f12b39acb0f6 (patch) | |
tree | 444ed433aa02085357b589b19b28f4bc1c243320 /tests | |
parent | cfe1a8152c948a4586ffa1fe79b47f9a0e88beb5 (diff) |
Fix mapping of JS objects/arrays to C++
[ChangeLog][QtQml][Important Behavior Changes] When a JavaScript object/array
is passed to C++ through a QVariant, the engine no longer immediately converts
the object recursively into a QVariantMap or QVariantList but instead stores
a QJSValue in the QVariant. This prevents a loss of data when the JS object
contains non-primitive types such as function objects for example. Code that
expects the variant type to be exactly QVariant::Map or QVariant::List may
need to be adapted. Registered conversion functions however ensure that code
that merely calls toMap() or toList() continues to work.
Task-number: QTBUG-40431
Change-Id: I1dbc1d5f8e78ad28bb62db3681b9a0b34557e7f5
Reviewed-by: Lars Knoll <lars.knoll@digia.com>
Diffstat (limited to 'tests')
-rw-r--r-- | tests/auto/qml/qjsvalue/tst_qjsvalue.cpp | 50 | ||||
-rw-r--r-- | tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp | 20 | ||||
-rw-r--r-- | tests/auto/qml/qqmllocale/tst_qqmllocale.cpp | 4 | ||||
-rw-r--r-- | tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp | 12 | ||||
-rw-r--r-- | tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp | 5 |
5 files changed, 69 insertions, 22 deletions
diff --git a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp index 837403d391..9c615cfc15 100644 --- a/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp +++ b/tests/auto/qml/qjsvalue/tst_qjsvalue.cpp @@ -34,10 +34,6 @@ #include "tst_qjsvalue.h" #include <QtWidgets/QPushButton> -QT_BEGIN_NAMESPACE -extern bool qt_script_isJITEnabled(); -QT_END_NAMESPACE - tst_QJSValue::tst_QJSValue() : engine(0) { @@ -45,8 +41,7 @@ tst_QJSValue::tst_QJSValue() tst_QJSValue::~tst_QJSValue() { - if (engine) - delete engine; + delete engine; } void tst_QJSValue::ctor_invalid() @@ -308,6 +303,19 @@ void tst_QJSValue::ctor_copyAndAssign() QCOMPARE(v5.toNumber(), 1.0); } +static QJSValue createUnboundValue(const QJSValue &value) +{ + QVariant variant = QVariant::fromValue(value); + QBuffer buffer; + buffer.open(QIODevice::ReadWrite); + QDataStream stream(&buffer); + variant.save(stream); + buffer.seek(0); + QVariant resultVariant; + resultVariant.load(stream); + return resultVariant.value<QJSValue>(); +} + void tst_QJSValue::toString() { QJSEngine eng; @@ -406,6 +414,28 @@ void tst_QJSValue::toString() variant = eng.toScriptValue(QUrl()); QVERIFY(variant.isVariant()); QVERIFY(variant.toString().isEmpty()); + + { + QJSValue o = eng.newObject(); + o.setProperty(QStringLiteral("test"), 42); + QCOMPARE(o.toString(), QStringLiteral("[object Object]")); + + o = createUnboundValue(o); + QVERIFY(!o.engine()); + QCOMPARE(o.toString(), QStringLiteral("[object Object]")); + } + + { + QJSValue o = eng.newArray(); + o.setProperty(0, 1); + o.setProperty(1, 2); + o.setProperty(2, 3); + QCOMPARE(o.toString(), QStringLiteral("1,2,3")); + + o = createUnboundValue(o); + QVERIFY(!o.engine()); + QCOMPARE(o.toString(), QStringLiteral("1,2,3")); + } } void tst_QJSValue::toNumber() @@ -419,35 +449,43 @@ void tst_QJSValue::toNumber() QJSValue null = eng.evaluate("null"); QCOMPARE(null.toNumber(), 0.0); QCOMPARE(qjsvalue_cast<qreal>(null), 0.0); + QCOMPARE(createUnboundValue(null).toNumber(), 0.0); { QJSValue falskt = eng.toScriptValue(false); QCOMPARE(falskt.toNumber(), 0.0); + QCOMPARE(createUnboundValue(falskt).toNumber(), 0.0); QCOMPARE(qjsvalue_cast<qreal>(falskt), 0.0); QJSValue sant = eng.toScriptValue(true); QCOMPARE(sant.toNumber(), 1.0); + QCOMPARE(createUnboundValue(sant).toNumber(), 1.0); QCOMPARE(qjsvalue_cast<qreal>(sant), 1.0); QJSValue number = eng.toScriptValue(123.0); QCOMPARE(number.toNumber(), 123.0); QCOMPARE(qjsvalue_cast<qreal>(number), 123.0); + QCOMPARE(createUnboundValue(number).toNumber(), 123.0); QJSValue str = eng.toScriptValue(QString("ciao")); QCOMPARE(qIsNaN(str.toNumber()), true); QCOMPARE(qIsNaN(qjsvalue_cast<qreal>(str)), true); + QCOMPARE(qIsNaN(createUnboundValue(str).toNumber()), true); QJSValue str2 = eng.toScriptValue(QString("123")); QCOMPARE(str2.toNumber(), 123.0); QCOMPARE(qjsvalue_cast<qreal>(str2), 123.0); + QCOMPARE(createUnboundValue(str2).toNumber(), 123.0); } QJSValue object = eng.newObject(); QCOMPARE(qIsNaN(object.toNumber()), true); + QCOMPARE(qIsNaN(createUnboundValue(object).toNumber()), true); QCOMPARE(qIsNaN(qjsvalue_cast<qreal>(object)), true); QJSValue inv = QJSValue(); QVERIFY(qIsNaN(inv.toNumber())); + QCOMPARE(qIsNaN(createUnboundValue(inv).toNumber()), true); QVERIFY(qIsNaN(qjsvalue_cast<qreal>(inv))); // V2 constructors diff --git a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp index c246647325..196f6b96f9 100644 --- a/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp +++ b/tests/auto/qml/qqmlecmascript/tst_qqmlecmascript.cpp @@ -746,13 +746,13 @@ void tst_qqmlecmascript::arrayExpressions() MyExpression expr(&context, "[a, b, c, 10]"); QVariant result = expr.evaluate(); - QCOMPARE(result.userType(), qMetaTypeId<QVariantList>()); - QVariantList list = qvariant_cast<QVariantList>(result); - QCOMPARE(list.count(), 4); - QCOMPARE(list.at(0).value<QObject*>(), &obj1); - QCOMPARE(list.at(1).value<QObject*>(), &obj2); - QCOMPARE(list.at(2).value<QObject*>(), &obj3); - QCOMPARE(list.at(3).value<int>(), 10); + QCOMPARE(result.userType(), qMetaTypeId<QJSValue>()); + QJSValue list = qvariant_cast<QJSValue>(result); + QCOMPARE(list.property("length").toInt(), 4); + QCOMPARE(list.property(0).toQObject(), &obj1); + QCOMPARE(list.property(1).toQObject(), &obj2); + QCOMPARE(list.property(2).toQObject(), &obj3); + QCOMPARE(list.property(3).toInt(), 10); } // Tests that modifying a context property will reevaluate expressions @@ -4811,7 +4811,7 @@ void tst_qqmlecmascript::propertyVarCpp() 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); + QCOMPARE(object->property("jsobject").userType(), qMetaTypeId<QJSValue>()); delete object; } @@ -5166,7 +5166,7 @@ void tst_qqmlecmascript::objectConversion() QVERIFY(object != 0); QVariant retn; QMetaObject::invokeMethod(object, "circularObject", Q_RETURN_ARG(QVariant, retn)); - QCOMPARE(retn.value<QVariantMap>().value("test"), QVariant(100)); + QCOMPARE(retn.value<QJSValue>().property("test").toInt(), int(100)); delete object; } @@ -5434,7 +5434,7 @@ void tst_qqmlecmascript::sequenceConversionWrite() 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 an unregistered type"); + QString warningOne = qmlFile.toString() + QLatin1String(":16: Error: Cannot assign QJSValue to an unregistered type"); QTest::ignoreMessage(QtWarningMsg, warningOne.toLatin1().constData()); QMetaObject::invokeMethod(object, "performTest"); diff --git a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp index 320333f889..4ee75f8df5 100644 --- a/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp +++ b/tests/auto/qml/qqmllocale/tst_qqmllocale.cpp @@ -486,7 +486,7 @@ void tst_qqmllocale::weekDays() Q_ARG(QVariant, QVariant(locale))); QVariant val = obj->property("weekDays"); - QVERIFY(val.type() == QVariant::List); + QVERIFY(val.userType() == qMetaTypeId<QJSValue>()); QList<QVariant> qmlDays = val.toList(); QList<Qt::DayOfWeek> days = QLocale(locale).weekdays(); @@ -528,7 +528,7 @@ void tst_qqmllocale::uiLanguages() Q_ARG(QVariant, QVariant(locale))); QVariant val = obj->property("uiLanguages"); - QVERIFY(val.type() == QVariant::List); + QVERIFY(val.userType() == qMetaTypeId<QJSValue>()); QList<QVariant> qmlLangs = val.toList(); QStringList langs = QLocale(locale).uiLanguages(); diff --git a/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp b/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp index 510a76cc06..b6e7a43c46 100644 --- a/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp +++ b/tests/auto/qml/qqmlmetaobject/tst_qqmlmetaobject.cpp @@ -249,16 +249,22 @@ void tst_QQmlMetaObject::property() QSignalSpy changedSpy(object, SIGNAL(testChanged())); QObject::connect(object, SIGNAL(testChanged()), object, SLOT(deleteLater())); + QVariant value = prop.read(object); + if (value.userType() == qMetaTypeId<QJSValue>()) + value = value.value<QJSValue>().toVariant(); if (expectedValue.isValid()) - QCOMPARE(prop.read(object), expectedValue); + QCOMPARE(value, expectedValue); else - QVERIFY(prop.read(object).isValid()); + QVERIFY(value.isValid()); QCOMPARE(changedSpy.count(), 0); if (isWritable) { QVERIFY(prop.write(object, newValue)); QCOMPARE(changedSpy.count(), 1); - QCOMPARE(prop.read(object), newValue); + QVariant value = prop.read(object); + if (value.userType() == qMetaTypeId<QJSValue>()) + value = value.value<QJSValue>().toVariant(); + QCOMPARE(value, newValue); } else { QVERIFY(!prop.write(object, prop.read(object))); QCOMPARE(changedSpy.count(), 0); diff --git a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp index 66ddb392f9..801707f2ec 100644 --- a/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp +++ b/tests/auto/qml/qquickworkerscript/tst_qquickworkerscript.cpp @@ -115,7 +115,10 @@ void tst_QQuickWorkerScript::messaging() waitForEchoMessage(worker); const QMetaObject *mo = worker->metaObject(); - QCOMPARE(mo->property(mo->indexOfProperty("response")).read(worker).value<QVariant>(), value); + QVariant response = mo->property(mo->indexOfProperty("response")).read(worker).value<QVariant>(); + if (response.userType() == qMetaTypeId<QJSValue>()) + response = response.value<QJSValue>().toVariant(); + QCOMPARE(response, value); qApp->processEvents(); delete worker; |