diff options
author | Thiago Macieira <thiago.macieira@intel.com> | 2018-01-11 13:47:32 -0800 |
---|---|---|
committer | Liang Qi <liang.qi@qt.io> | 2018-06-08 07:46:41 +0000 |
commit | c4ed96513e5f9bd231084dfd39113391590d5387 (patch) | |
tree | 315be87e804fd1999397fa0152ee9c4727182a41 /tests/auto/corelib | |
parent | 49c93774212904291bc2df008b265323ec55e62e (diff) |
QCborValue: add support for QVariant and JSON conversions
Plus QStringList.
Change-Id: I39332e0a867442d58082fffd1508dfb9b540af23
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
Diffstat (limited to 'tests/auto/corelib')
3 files changed, 347 insertions, 0 deletions
diff --git a/tests/auto/corelib/serialization/qcborvalue_json/qcborvalue_json.pro b/tests/auto/corelib/serialization/qcborvalue_json/qcborvalue_json.pro new file mode 100644 index 0000000000..c11000b7c2 --- /dev/null +++ b/tests/auto/corelib/serialization/qcborvalue_json/qcborvalue_json.pro @@ -0,0 +1,7 @@ +QT = core testlib +TARGET = tst_qcborvalue_json +CONFIG += testcase +SOURCES += \ + tst_qcborvalue_json.cpp + +DEFINES += SRCDIR=\\\"$$PWD/\\\" diff --git a/tests/auto/corelib/serialization/qcborvalue_json/tst_qcborvalue_json.cpp b/tests/auto/corelib/serialization/qcborvalue_json/tst_qcborvalue_json.cpp new file mode 100644 index 0000000000..324e9b1dfb --- /dev/null +++ b/tests/auto/corelib/serialization/qcborvalue_json/tst_qcborvalue_json.cpp @@ -0,0 +1,339 @@ +/**************************************************************************** +** +** Copyright (C) 2018 Intel Corporation. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtCore module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 3 as published by the Free Software +** Foundation and appearing in the file LICENSE.LGPL3 included in the +** packaging of this file. Please review the following information to +** ensure the GNU Lesser General Public License version 3 requirements +** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 2.0 or (at your option) the GNU General +** Public license version 3 or any later version approved by the KDE Free +** Qt Foundation. The licenses are as published by the Free Software +** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-2.0.html and +** https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include <QtCore/qcborvalue.h> +#include <QtTest> + +Q_DECLARE_METATYPE(QCborValue) + +class tst_QCborValue_Json : public QObject +{ + Q_OBJECT + +private slots: + void toVariant_data(); + void toVariant(); + void toJson_data() { toVariant_data(); } + void toJson(); + void taggedByteArrayToJson_data(); + void taggedByteArrayToJson(); + + void fromVariant_data() { toVariant_data(); } + void fromVariant(); + void fromJson_data(); + void fromJson(); + + void nonStringKeysInMaps_data(); + void nonStringKeysInMaps(); +}; + +void tst_QCborValue_Json::toVariant_data() +{ + QTest::addColumn<QCborValue>("v"); + QTest::addColumn<QVariant>("variant"); + QTest::addColumn<QJsonValue>("json"); + QDateTime dt = QDateTime::currentDateTimeUtc(); + QUuid uuid = QUuid::createUuid(); + + QMetaEnum me = QMetaEnum::fromType<QCborValue::Type>(); + auto add = [me](const QCborValue &v, const QVariant &exp, const QJsonValue &json) { + auto addRow = [=]() -> QTestData & { + const char *typeString = me.valueToKey(v.type()); + if (v.type() == QCborValue::Integer) + return QTest::addRow("Integer:%lld", exp.toLongLong()); + if (v.type() == QCborValue::Double) + return QTest::addRow("Double:%g", exp.toDouble()); + if (v.type() == QCborValue::ByteArray || v.type() == QCborValue::String) + return QTest::addRow("%s:%d", typeString, exp.toString().size()); + if (v.type() >= 0x10000) + return QTest::newRow(exp.typeName()); + return QTest::newRow(typeString); + }; + addRow() << v << exp << json; + }; + + // good JSON matching: + add(QCborValue(), QVariant(), QJsonValue::Undefined); + add(nullptr, QVariant::fromValue(nullptr), QJsonValue::Null); + add(false, false, false); + add(true, true, true); + add(0, 0, 0); + add(1, 1, 1); + add(-1, -1, -1); + add(0., 0., 0.); + add(1.25, 1.25, 1.25); + add(-1.25, -1.25, -1.25); + add("Hello", "Hello", "Hello"); + + // converts to string in JSON: + add(QByteArray("Hello"), QByteArray("Hello"), "SGVsbG8"); + add(QCborValue(dt), dt, dt.toString(Qt::ISODateWithMs)); + add(QCborValue(QUrl("http://example.com/{q}")), QUrl("http://example.com/{q}"), + "http://example.com/%7Bq%7D"); // note the encoded form in JSON + add(QCborValue(QRegularExpression(".")), QRegularExpression("."), "."); + add(QCborValue(uuid), uuid, uuid.toString(QUuid::WithoutBraces)); + + // not valid in JSON + QTest::newRow("simpletype") << QCborValue(QCborSimpleType(255)) + << QVariant::fromValue(QCborSimpleType(255)) + << QJsonValue("simple(255)"); + QTest::newRow("Double:inf") << QCborValue(qInf()) + << QVariant(qInf()) + << QJsonValue(); + QTest::newRow("Double:-inf") << QCborValue(-qInf()) + << QVariant(-qInf()) + << QJsonValue(); + QTest::newRow("Double:nan") << QCborValue(qQNaN()) + << QVariant(qQNaN()) + << QJsonValue(); + + // large integral values lose precision in JSON + QTest::newRow("Integer:max") << QCborValue(std::numeric_limits<qint64>::max()) + << QVariant(std::numeric_limits<qint64>::max()) + << QJsonValue(std::numeric_limits<qint64>::max()); + QTest::newRow("Integer:min") << QCborValue(std::numeric_limits<qint64>::min()) + << QVariant(std::numeric_limits<qint64>::min()) + << QJsonValue(std::numeric_limits<qint64>::min()); + + // empty arrays and maps + add(QCborArray(), QVariantList(), QJsonArray()); + add(QCborMap(), QVariantMap(), QJsonObject()); +} + +void tst_QCborValue_Json::toVariant() +{ + QFETCH(QCborValue, v); + QFETCH(QVariant, variant); + + if (qIsNaN(variant.toDouble())) { + // because NaN != NaN, QVariant(NaN) != QVariant(NaN), so we + // only need to compare the classification + QVERIFY(qIsNaN(v.toVariant().toDouble())); + + // the rest of this function depends on the variant comparison + return; + } + + QCOMPARE(v.toVariant(), variant); + + // tags get ignored: + QCOMPARE(QCborValue(QCborKnownTags::Signature, v).toVariant(), variant); + + // make arrays with this item + QCOMPARE(QCborArray({v}).toVariantList(), QVariantList({variant})); + QCOMPARE(QCborArray({v, v}).toVariantList(), QVariantList({variant, variant})); + + // and maps + QCOMPARE(QCborMap({{"foo", v}}).toVariantMap(), QVariantMap({{"foo", variant}})); + QCOMPARE(QCborMap({{"foo", v}}).toVariantHash(), QVariantHash({{"foo", variant}})); + + // finally, mixed + QCOMPARE(QCborArray{QCborMap({{"foo", v}})}.toVariantList(), + QVariantList{QVariantMap({{"foo", variant}})}); +} + +void tst_QCborValue_Json::toJson() +{ + QFETCH(QCborValue, v); + QFETCH(QJsonValue, json); + + QCOMPARE(v.toJsonValue(), json); + + // most tags get ignored: + QCOMPARE(QCborValue(QCborKnownTags::Signature, v).toJsonValue(), json); + + // make arrays with this item + QCOMPARE(QCborArray({v}).toJsonArray(), QJsonArray({json})); + QCOMPARE(QCborArray({v, v}).toJsonArray(), QJsonArray({json, json})); + + // and maps + QCOMPARE(QCborMap({{"foo", v}}).toJsonObject(), QJsonObject({{"foo", json}})); + + // finally, mixed + QCOMPARE(QCborArray{QCborMap({{"foo", v}})}.toJsonArray(), + QJsonArray{QJsonObject({{"foo", json}})}); +} + +void tst_QCborValue_Json::taggedByteArrayToJson_data() +{ + QTest::addColumn<QCborValue>("v"); + QTest::addColumn<QJsonValue>("json"); + + QByteArray data("\xff\x01"); + QTest::newRow("base64url") << QCborValue(QCborKnownTags::ExpectedBase64url, data) << QJsonValue("_wE"); + QTest::newRow("base64") << QCborValue(QCborKnownTags::ExpectedBase64, data) << QJsonValue("/wE="); + QTest::newRow("hex") << QCborValue(QCborKnownTags::ExpectedBase16, data) << QJsonValue("ff01"); +} + +void tst_QCborValue_Json::taggedByteArrayToJson() +{ + QFETCH(QCborValue, v); + QFETCH(QJsonValue, json); + + QCOMPARE(v.toJsonValue(), json); + QCOMPARE(QCborArray({v}).toJsonArray(), QJsonArray({json})); +} + +void tst_QCborValue_Json::fromVariant() +{ + QFETCH(QCborValue, v); + QFETCH(QVariant, variant); + + QCOMPARE(QCborValue::fromVariant(variant), v); + + // try arrays + QCOMPARE(QCborArray::fromVariantList({variant}), QCborArray{v}); + QCOMPARE(QCborArray::fromVariantList({variant, variant}), QCborArray({v, v})); + + if (variant.type() == QVariant::String) { + QString s = variant.toString(); + QCOMPARE(QCborArray::fromStringList({s}), QCborArray{v}); + QCOMPARE(QCborArray::fromStringList({s, s}), QCborArray({v, v})); + } + + // maps... + QVariantMap map{{"foo", variant}}; + QCOMPARE(QCborMap::fromVariantMap(map), QCborMap({{"foo", v}})); + QCOMPARE(QCborMap::fromVariantHash({{"foo", variant}}), QCborMap({{"foo", v}})); + + // nested + QVariantMap outer{{"bar", QVariantList{0, map, true}}}; + QCOMPARE(QCborMap::fromVariantMap(outer), + QCborMap({{"bar", QCborArray{0, QCborMap{{"foo", v}}, true}}})); +} + +void tst_QCborValue_Json::fromJson_data() +{ + QTest::addColumn<QCborValue>("v"); + QTest::addColumn<QJsonValue>("json"); + + QTest::newRow("null") << QCborValue(QCborValue::Null) << QJsonValue(QJsonValue::Null); + QTest::newRow("false") << QCborValue(false) << QJsonValue(false); + QTest::newRow("true") << QCborValue(true) << QJsonValue(true); + QTest::newRow("0") << QCborValue(0) << QJsonValue(0.); + QTest::newRow("1") << QCborValue(1) << QJsonValue(1); + QTest::newRow("1.5") << QCborValue(1.5) << QJsonValue(1.5); + QTest::newRow("string") << QCborValue("Hello") << QJsonValue("Hello"); + QTest::newRow("array") << QCborValue(QCborValue::Array) << QJsonValue(QJsonValue::Array); + QTest::newRow("map") << QCborValue(QCborValue::Map) << QJsonValue(QJsonValue::Object); +} + +void tst_QCborValue_Json::fromJson() +{ + QFETCH(QCborValue, v); + QFETCH(QJsonValue, json); + + QCOMPARE(QCborValue::fromJsonValue(json), v); + QCOMPARE(QCborArray::fromJsonArray({json}), QCborArray({v})); + QCOMPARE(QCborArray::fromJsonArray({json, json}), QCborArray({v, v})); + QCOMPARE(QCborMap::fromJsonObject({{"foo", json}}), QCborMap({{"foo", v}})); + + // confirm we can roundtrip back to JSON + QCOMPARE(QCborValue::fromJsonValue(json).toJsonValue(), json); +} + +void tst_QCborValue_Json::nonStringKeysInMaps_data() +{ + QTest::addColumn<QCborValue>("key"); + QTest::addColumn<QString>("converted"); + + auto add = [](const char *str, const QCborValue &v) { + QTest::newRow(str) << v << str; + }; + add("0", 0); + add("-1", -1); + add("false", false); + add("true", true); + add("null", nullptr); + add("undefined", {}); // should this be ""? + add("simple(255)", QCborSimpleType(255)); + add("2.5", 2.5); + + QByteArray data("\xff\x01"); + QTest::newRow("bytearray") << QCborValue(data) << "_wE"; + QTest::newRow("base64url") << QCborValue(QCborKnownTags::ExpectedBase64url, data) << "_wE"; + QTest::newRow("base64") << QCborValue(QCborKnownTags::ExpectedBase64, data) << "/wE="; + QTest::newRow("hex") << QCborValue(QCborKnownTags::ExpectedBase16, data) << "ff01"; + + QTest::newRow("emptyarray") << QCborValue(QCborValue::Array) << "[ ]"; + QTest::newRow("emptymap") << QCborValue(QCborValue::Map) << "{ }"; + QTest::newRow("array") << QCborValue(QCborArray{1, true, 2.5, "Hello"}) + << "[ 1, true, 2.5, \"Hello\" ]"; + QTest::newRow("map") << QCborValue(QCborMap{{"Hello", 0}, {0, "Hello"}}) + << "{ \"Hello\": 0, 0: \"Hello\" }"; + + QDateTime dt = QDateTime::currentDateTimeUtc(); + QUrl url("https://example.com"); + QUuid uuid = QUuid::createUuid(); + QTest::newRow("QDateTime") << QCborValue(dt) << dt.toString(Qt::ISODateWithMs); + QTest::newRow("QUrl") << QCborValue(url) << url.toString(QUrl::FullyEncoded); + QTest::newRow("QRegularExpression") << QCborValue(QRegularExpression(".*")) << ".*"; + QTest::newRow("QUuid") << QCborValue(uuid) << uuid.toString(QUuid::WithoutBraces); +} + +void tst_QCborValue_Json::nonStringKeysInMaps() +{ + QFETCH(QCborValue, key); + QFETCH(QString, converted); + + QCborMap m; + m.insert(key, 0); + + { + QVariantMap vm = m.toVariantMap(); + auto it = vm.begin(); + QVERIFY(it != vm.end()); + QCOMPARE(it.key(), converted); + QCOMPARE(it.value(), 0); + QCOMPARE(++it, vm.end()); + } + + { + QJsonObject o = m.toJsonObject(); + auto it = o.begin(); + QVERIFY(it != o.end()); + QCOMPARE(it.key(), converted); + QCOMPARE(it.value(), 0); + QCOMPARE(++it, o.end()); + } +} + +QTEST_MAIN(tst_QCborValue_Json) + +#include "tst_qcborvalue_json.moc" diff --git a/tests/auto/corelib/serialization/serialization.pro b/tests/auto/corelib/serialization/serialization.pro index 9aafe5d632..9187de1bc5 100644 --- a/tests/auto/corelib/serialization/serialization.pro +++ b/tests/auto/corelib/serialization/serialization.pro @@ -4,6 +4,7 @@ SUBDIRS = \ qcborstreamreader \ qcborstreamwriter \ qcborvalue \ + qcborvalue_json \ qdatastream \ qtextstream \ qxmlstream |