summaryrefslogtreecommitdiff
path: root/lib/cbor/tinycbor/tests/tojson
diff options
context:
space:
mode:
authorjacqueline <me@jacqueline.id.au>2023-01-21 14:04:56 +1100
committerjacqueline <me@jacqueline.id.au>2023-01-21 14:09:00 +1100
commit393b268e159a40b23bc63464f4d04d5be09e070f (patch)
treed78167662cd68de3e08d90bb1b44070ab542e433 /lib/cbor/tinycbor/tests/tojson
parentbb50cf52cd8984704b757b1e5f9e11a126b24eba (diff)
downloadtangara-fw-393b268e159a40b23bc63464f4d04d5be09e070f.tar.gz
Vendor tinycbor, since v5 no longer includes it
Diffstat (limited to 'lib/cbor/tinycbor/tests/tojson')
-rw-r--r--lib/cbor/tinycbor/tests/tojson/tojson.pro8
-rw-r--r--lib/cbor/tinycbor/tests/tojson/tst_tojson.cpp721
2 files changed, 729 insertions, 0 deletions
diff --git a/lib/cbor/tinycbor/tests/tojson/tojson.pro b/lib/cbor/tinycbor/tests/tojson/tojson.pro
new file mode 100644
index 00000000..b4226520
--- /dev/null
+++ b/lib/cbor/tinycbor/tests/tojson/tojson.pro
@@ -0,0 +1,8 @@
+CONFIG += testcase parallel_test c++11
+QT = core testlib
+
+SOURCES += tst_tojson.cpp
+INCLUDEPATH += ../../src
+msvc: POST_TARGETDEPS = ../../lib/tinycbor.lib
+else: POST_TARGETDEPS += ../../lib/libtinycbor.a
+LIBS += $$POST_TARGETDEPS
diff --git a/lib/cbor/tinycbor/tests/tojson/tst_tojson.cpp b/lib/cbor/tinycbor/tests/tojson/tst_tojson.cpp
new file mode 100644
index 00000000..89b5d129
--- /dev/null
+++ b/lib/cbor/tinycbor/tests/tojson/tst_tojson.cpp
@@ -0,0 +1,721 @@
+/****************************************************************************
+**
+** Copyright (C) 2021 Intel Corporation
+**
+** Permission is hereby granted, free of charge, to any person obtaining a copy
+** of this software and associated documentation files (the "Software"), to deal
+** in the Software without restriction, including without limitation the rights
+** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+** copies of the Software, and to permit persons to whom the Software is
+** furnished to do so, subject to the following conditions:
+**
+** The above copyright notice and this permission notice shall be included in
+** all copies or substantial portions of the Software.
+**
+** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+** OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+** THE SOFTWARE.
+**
+****************************************************************************/
+
+#include <QtTest>
+#include "cbor.h"
+#include "cborjson.h"
+#include <locale.h>
+
+extern "C" FILE *open_memstream(char **bufptr, size_t *sizeptr);
+
+class tst_ToJson : public QObject
+{
+ Q_OBJECT
+private slots:
+ void initTestCase();
+
+ void fixed_data();
+ void fixed();
+ void textstrings_data();
+ void textstrings() { fixed(); }
+ void nonjson_data();
+ void nonjson() { fixed(); }
+ void bytestrings_data();
+ void bytestrings() { fixed(); }
+ void emptyContainers_data();
+ void emptyContainers() { fixed(); }
+ void arrays_data();
+ void arrays();
+ void nestedArrays_data() { arrays_data(); }
+ void nestedArrays();
+ void maps_data() { arrays_data(); }
+ void maps();
+ void nestedMaps_data() { maps_data(); }
+ void nestedMaps();
+ void nonStringKeyMaps_data();
+ void nonStringKeyMaps();
+
+ void tagsToObjects_data();
+ void tagsToObjects();
+ void taggedByteStringsToBase16_data();
+ void taggedByteStringsToBase16();
+ void taggedByteStringsToBase64_data() { taggedByteStringsToBase16_data(); }
+ void taggedByteStringsToBase64();
+ void taggedByteStringsToBigNum_data() { taggedByteStringsToBase16_data(); }
+ void taggedByteStringsToBigNum();
+ void otherTags_data();
+ void otherTags();
+
+ void metaData_data();
+ void metaData();
+ void metaDataAndTagsToObjects_data() { tagsToObjects_data(); }
+ void metaDataAndTagsToObjects();
+ void metaDataForKeys_data();
+ void metaDataForKeys();
+};
+#include "tst_tojson.moc"
+
+template <size_t N> QByteArray raw(const char (&data)[N])
+{
+ return QByteArray::fromRawData(data, N - 1);
+}
+
+void addColumns()
+{
+ QTest::addColumn<QByteArray>("data");
+ QTest::addColumn<QString>("expected");
+}
+
+void addFixedData()
+{
+ // unsigned integers
+ QTest::newRow("0") << raw("\x00") << "0";
+ QTest::newRow("1") << raw("\x01") << "1";
+ QTest::newRow("2^53-1") << raw("\x1b\0\x1f\xff\xff""\xff\xff\xff\xff") << "9007199254740991";
+ QTest::newRow("2^64-epsilon") << raw("\x1b\xff\xff\xff\xff""\xff\xff\xf8\x00") << "18446744073709549568";
+
+ // negative integers
+ QTest::newRow("-1") << raw("\x20") << "-1";
+ QTest::newRow("-2") << raw("\x21") << "-2";
+ QTest::newRow("-2^53+1") << raw("\x3b\0\x1f\xff\xff""\xff\xff\xff\xfe") << "-9007199254740991";
+ QTest::newRow("-2^64+epsilon") << raw("\x3b\xff\xff\xff\xff""\xff\xff\xf8\x00") << "-18446744073709549568";
+
+ QTest::newRow("false") << raw("\xf4") << "false";
+ QTest::newRow("true") << raw("\xf5") << "true";
+ QTest::newRow("null") << raw("\xf6") << "null";
+
+ QTest::newRow("0.f16") << raw("\xf9\0\0") << "0";
+ QTest::newRow("0.f") << raw("\xfa\0\0\0\0") << "0";
+ QTest::newRow("0.") << raw("\xfb\0\0\0\0\0\0\0\0") << "0";
+ QTest::newRow("-1.f16") << raw("\xf9\xbc\x00") << "-1";
+ QTest::newRow("-1.f") << raw("\xfa\xbf\x80\0\0") << "-1";
+ QTest::newRow("-1.") << raw("\xfb\xbf\xf0\0\0\0\0\0\0") << "-1";
+ QTest::newRow("16777215.f") << raw("\xfa\x4b\x7f\xff\xff") << "16777215";
+ QTest::newRow("16777215.") << raw("\xfb\x41\x6f\xff\xff\xe0\0\0\0") << "16777215";
+ QTest::newRow("-16777215.f") << raw("\xfa\xcb\x7f\xff\xff") << "-16777215";
+ QTest::newRow("-16777215.") << raw("\xfb\xc1\x6f\xff\xff\xe0\0\0\0") << "-16777215";
+
+ QTest::newRow("0.5f16") << raw("\xf9\x38\0") << "0.5";
+ QTest::newRow("0.5f") << raw("\xfa\x3f\0\0\0") << "0.5";
+ QTest::newRow("0.5") << raw("\xfb\x3f\xe0\0\0\0\0\0\0") << "0.5";
+ QTest::newRow("2.f^24-1") << raw("\xfa\x4b\x7f\xff\xff") << "16777215";
+ QTest::newRow("2.^53-1") << raw("\xfb\x43\x3f\xff\xff""\xff\xff\xff\xff") << "9007199254740991";
+ QTest::newRow("2.f^64-epsilon") << raw("\xfa\x5f\x7f\xff\xff") << "18446742974197923840";
+ QTest::newRow("2.^64-epsilon") << raw("\xfb\x43\xef\xff\xff""\xff\xff\xff\xff") << "18446744073709549568";
+ QTest::newRow("2.f^64") << raw("\xfa\x5f\x80\0\0") << "1.8446744073709552e+19";
+ QTest::newRow("2.^64") << raw("\xfb\x43\xf0\0\0\0\0\0\0") << "1.8446744073709552e+19";
+
+ // infinities and NaN are not supported in JSON, they convert to null
+ QTest::newRow("nan_f16") << raw("\xf9\x7e\x00") << "null";
+ QTest::newRow("nan_f") << raw("\xfa\x7f\xc0\0\0") << "null";
+ QTest::newRow("nan") << raw("\xfb\x7f\xf8\0\0\0\0\0\0") << "null";
+ QTest::newRow("-inf_f") << raw("\xfa\xff\x80\0\0") << "null";
+ QTest::newRow("-inf_f16") << raw("\xf9\xfc\x00") << "null";
+ QTest::newRow("-inf") << raw("\xfb\xff\xf0\0\0\0\0\0\0") << "null";
+ QTest::newRow("+inf_f") << raw("\xfa\x7f\x80\0\0") << "null";
+ QTest::newRow("+inf_f16") << raw("\xf9\x7c\x00") << "null";
+ QTest::newRow("+inf") << raw("\xfb\x7f\xf0\0\0\0\0\0\0") << "null";
+}
+
+void addTextStringsData()
+{
+ QTest::newRow("emptytextstring") << raw("\x60") << "\"\"";
+ QTest::newRow("textstring1") << raw("\x61 ") << "\" \"";
+ QTest::newRow("textstring5") << raw("\x65Hello") << "\"Hello\"";
+ QTest::newRow("textstring24") << raw("\x78\x18""123456789012345678901234")
+ << "\"123456789012345678901234\"";
+ QTest::newRow("textstring256") << raw("\x79\1\0") + QByteArray(256, '3')
+ << '"' + QString(256, '3') + '"';
+
+ // strings with undefined length
+ QTest::newRow("_emptytextstring") << raw("\x7f\xff") << "\"\"";
+ QTest::newRow("_emptytextstring2") << raw("\x7f\x60\xff") << "\"\"";
+ QTest::newRow("_emptytextstring3") << raw("\x7f\x60\x60\xff") << "\"\"";
+ QTest::newRow("_textstring5*2") << raw("\x7f\x63Hel\x62lo\xff") << "\"Hello\"";
+ QTest::newRow("_textstring5*5") << raw("\x7f\x61H\x61""e\x61l\x61l\x61o\xff") << "\"Hello\"";
+ QTest::newRow("_textstring5*6") << raw("\x7f\x61H\x61""e\x61l\x60\x61l\x61o\xff") << "\"Hello\"";
+}
+
+void addNonJsonData()
+{
+ QTest::newRow("undefined") << raw("\xf7") << "\"undefined\"";
+ QTest::newRow("simple0") << raw("\xe0") << "\"simple(0)\"";
+ QTest::newRow("simple19") << raw("\xf3") << "\"simple(19)\"";
+ QTest::newRow("simple32") << raw("\xf8\x20") << "\"simple(32)\"";
+ QTest::newRow("simple255") << raw("\xf8\xff") << "\"simple(255)\"";
+}
+
+void addByteStringsData()
+{
+ QTest::newRow("emptybytestring") << raw("\x40") << "\"\"";
+ QTest::newRow("bytestring1") << raw("\x41 ") << "\"IA\"";
+ QTest::newRow("bytestring1-nul") << raw("\x41\0") << "\"AA\"";
+ QTest::newRow("bytestring2") << raw("\x42Hi") << "\"SGk\"";
+ QTest::newRow("bytestring3") << raw("\x43Hey") << "\"SGV5\"";
+ QTest::newRow("bytestring4") << raw("\x44Hola") << "\"SG9sYQ\"";
+ QTest::newRow("bytestring5") << raw("\x45Hello") << "\"SGVsbG8\"";
+ QTest::newRow("bytestring24") << raw("\x58\x18""123456789012345678901234")
+ << "\"MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0\"";
+
+ // strings with undefined length
+ QTest::newRow("_emptybytestring") << raw("\x5f\xff") << "\"\"";
+ QTest::newRow("_emptybytestring2") << raw("\x5f\x40\xff") << "\"\"";
+ QTest::newRow("_emptybytestring3") << raw("\x5f\x40\x40\xff") << "\"\"";
+ QTest::newRow("_bytestring5*2") << raw("\x5f\x43Hel\x42lo\xff") << "\"SGVsbG8\"";
+ QTest::newRow("_bytestring5*5") << raw("\x5f\x41H\x41""e\x41l\x41l\x41o\xff") << "\"SGVsbG8\"";
+ QTest::newRow("_bytestring5*6") << raw("\x5f\x41H\x41""e\x40\x41l\x41l\x41o\xff") << "\"SGVsbG8\"";
+}
+
+void addEmptyContainersData()
+{
+ QTest::newRow("emptyarray") << raw("\x80") << "[]";
+ QTest::newRow("emptymap") << raw("\xa0") << "{}";
+ QTest::newRow("_emptyarray") << raw("\x9f\xff") << "[]";
+ QTest::newRow("_emptymap") << raw("\xbf\xff") << "{}";
+}
+
+CborError parseOne(CborValue *it, QString *parsed, int flags)
+{
+ char *buffer;
+ size_t size;
+
+ FILE *f = open_memstream(&buffer, &size);
+ CborError err = cbor_value_to_json_advance(f, it, flags);
+ fclose(f);
+
+ *parsed = QString::fromLatin1(buffer);
+ free(buffer);
+ return err;
+}
+
+bool compareFailed = true;
+void compareOne_real(const QByteArray &data, const QString &expected, int flags, int line)
+{
+ compareFailed = true;
+ CborParser parser;
+ CborValue first;
+ CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first);
+ QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) + "\"");
+
+ QString decoded;
+ err = parseOne(&first, &decoded, flags);
+ QVERIFY2(!err, QByteArray::number(line) + ": Got error \"" + cbor_error_string(err) +
+ "\"; decoded stream:\n" + decoded.toLatin1());
+ QCOMPARE(decoded, expected);
+
+ // check that we consumed everything
+ QCOMPARE((void*)cbor_value_get_next_byte(&first), (void*)data.constEnd());
+
+ compareFailed = false;
+}
+#define compareOne(data, expected, flags) \
+ compareOne_real(data, expected, flags, __LINE__); \
+ if (compareFailed) return
+
+void tst_ToJson::initTestCase()
+{
+ setlocale(LC_ALL, "C");
+}
+
+void tst_ToJson::fixed_data()
+{
+ addColumns();
+ addFixedData();
+}
+
+void tst_ToJson::fixed()
+{
+ QFETCH(QByteArray, data);
+ QFETCH(QString, expected);
+
+ compareOne(data, expected, 0);
+}
+
+void tst_ToJson::textstrings_data()
+{
+ addColumns();
+ addTextStringsData();
+}
+
+void tst_ToJson::nonjson_data()
+{
+ addColumns();
+ addNonJsonData();
+}
+
+void tst_ToJson::bytestrings_data()
+{
+ addColumns();
+ addByteStringsData();
+}
+
+void tst_ToJson::emptyContainers_data()
+{
+ addColumns();
+ addEmptyContainersData();
+}
+
+void tst_ToJson::arrays_data()
+{
+ addColumns();
+ addFixedData();
+ addTextStringsData();
+ addNonJsonData();
+ addByteStringsData();
+}
+
+void tst_ToJson::arrays()
+{
+ QFETCH(QByteArray, data);
+ QFETCH(QString, expected);
+
+ compareOne("\x81" + data, '[' + expected + ']', 0);
+ compareOne("\x82" + data + data, '[' + expected + ',' + expected + ']', 0);
+}
+
+void tst_ToJson::nestedArrays()
+{
+ QFETCH(QByteArray, data);
+ QFETCH(QString, expected);
+
+ compareOne("\x81\x81" + data, "[[" + expected + "]]", 0);
+ compareOne("\x81\x81\x81" + data, "[[[" + expected + "]]]", 0);
+ compareOne("\x81\x82" + data + data, "[[" + expected + ',' + expected + "]]", 0);
+ compareOne("\x82\x81" + data + data, "[[" + expected + "]," + expected + "]", 0);
+ compareOne("\x82\x81" + data + '\x81' + data, "[[" + expected + "],[" + expected + "]]", 0);
+}
+
+void tst_ToJson::maps()
+{
+ QFETCH(QByteArray, data);
+ QFETCH(QString, expected);
+
+ compareOne("\xa1\x65" "Hello" + data, "{\"Hello\":" + expected + '}', 0);
+}
+
+void tst_ToJson::nestedMaps()
+{
+ QFETCH(QByteArray, data);
+ QFETCH(QString, expected);
+
+ compareOne("\xa1\x65Hello\xa1\x65World" + data, "{\"Hello\":{\"World\":" + expected + "}}", 0);
+// compareOne("\xa1\x63""foo\xa1\63""bar" + data + "\63""baz\xa1\x64quux" + data,
+// "{\"foo\":{\"bar\":" + expected + "},\"baz\":{\"quux\":" + expected + "}", 0);
+}
+
+void tst_ToJson::nonStringKeyMaps_data()
+{
+ addColumns();
+
+ QTest::newRow("0") << raw("\x00") << "0";
+ QTest::newRow("1") << raw("\x01") << "1";
+ QTest::newRow("UINT32_MAX") << raw("\x1a\xff\xff\xff\xff") << "4294967295";
+ QTest::newRow("UINT32_MAX+1") << raw("\x1b\0\0\0\1\0\0\0\0") << "4294967296";
+ QTest::newRow("UINT64_MAX") << raw("\x1b" "\xff\xff\xff\xff" "\xff\xff\xff\xff")
+ << QString::number(std::numeric_limits<uint64_t>::max());
+
+ QTest::newRow("-1") << raw("\x20") << "-1";
+ QTest::newRow("-UINT32_MAX") << raw("\x3a\xff\xff\xff\xff") << "-4294967296";
+ QTest::newRow("-UINT32_MAX-1") << raw("\x3b\0\0\0\1\0\0\0\0") << "-4294967297";
+ QTest::newRow("-UINT64_MAX") << raw("\x3b" "\xff\xff\xff\xff" "\xff\xff\xff\xfe")
+ << '-' + QString::number(std::numeric_limits<uint64_t>::max());
+ QTest::newRow("-UINT64_MAX-1") << raw("\x3b" "\xff\xff\xff\xff" "\xff\xff\xff\xff")
+ << "-18446744073709551616";
+
+ QTest::newRow("simple0") << raw("\xe0") << "simple(0)";
+ QTest::newRow("simple19") << raw("\xf3") << "simple(19)";
+ QTest::newRow("false") << raw("\xf4") << "false";
+ QTest::newRow("true") << raw("\xf5") << "true";
+ QTest::newRow("null") << raw("\xf6") << "null";
+ QTest::newRow("undefined") << raw("\xf7") << "undefined";
+ QTest::newRow("simple32") << raw("\xf8\x20") << "simple(32)";
+ QTest::newRow("simple255") << raw("\xf8\xff") << "simple(255)";
+
+ QTest::newRow("0.f16") << raw("\xf9\0\0") << "0.f16";
+ QTest::newRow("0.f") << raw("\xfa\0\0\0\0") << "0.f";
+ QTest::newRow("0.") << raw("\xfb\0\0\0\0\0\0\0\0") << "0.";
+ QTest::newRow("-1.f16") << raw("\xf9\xbc\x00") << "-1.f16";
+ QTest::newRow("-1.f") << raw("\xfa\xbf\x80\0\0") << "-1.f";
+ QTest::newRow("-1.") << raw("\xfb\xbf\xf0\0\0\0\0\0\0") << "-1.";
+ QTest::newRow("65504.f16") << raw("\xf9\x7b\xff") << "65504.f16";
+ QTest::newRow("16777215.f") << raw("\xfa\x4b\x7f\xff\xff") << "16777215.f";
+ QTest::newRow("16777215.") << raw("\xfb\x41\x6f\xff\xff\xe0\0\0\0") << "16777215.";
+ QTest::newRow("-16777215.f") << raw("\xfa\xcb\x7f\xff\xff") << "-16777215.f";
+ QTest::newRow("-16777215.") << raw("\xfb\xc1\x6f\xff\xff\xe0\0\0\0") << "-16777215.";
+
+ QTest::newRow("0.5f16") << raw("\xf9\x38\0") << "0.5f16";
+ QTest::newRow("0.5f") << raw("\xfa\x3f\0\0\0") << "0.5f";
+ QTest::newRow("0.5") << raw("\xfb\x3f\xe0\0\0\0\0\0\0") << "0.5";
+ QTest::newRow("2.f16^11-1") << raw("\xf9\x67\xff") << "2047.f16";
+ QTest::newRow("2.f^24-1") << raw("\xfa\x4b\x7f\xff\xff") << "16777215.f";
+ QTest::newRow("2.^53-1") << raw("\xfb\x43\x3f\xff\xff""\xff\xff\xff\xff") << "9007199254740991.";
+ QTest::newRow("2.f^64-epsilon") << raw("\xfa\x5f\x7f\xff\xff") << "18446742974197923840.f";
+ QTest::newRow("2.^64-epsilon") << raw("\xfb\x43\xef\xff\xff""\xff\xff\xff\xff") << "18446744073709549568.";
+ QTest::newRow("2.f^64") << raw("\xfa\x5f\x80\0\0") << "1.8446744073709552e+19f";
+ QTest::newRow("2.^64") << raw("\xfb\x43\xf0\0\0\0\0\0\0") << "1.8446744073709552e+19";
+
+ QTest::newRow("nan_f16") << raw("\xf9\x7e\x00") << "nan";
+ QTest::newRow("nan_f") << raw("\xfa\x7f\xc0\0\0") << "nan";
+ QTest::newRow("nan") << raw("\xfb\x7f\xf8\0\0\0\0\0\0") << "nan";
+ QTest::newRow("-inf_f16") << raw("\xf9\xfc\x00") << "-inf";
+ QTest::newRow("-inf_f") << raw("\xfa\xff\x80\0\0") << "-inf";
+ QTest::newRow("-inf") << raw("\xfb\xff\xf0\0\0\0\0\0\0") << "-inf";
+ QTest::newRow("+inf_f16") << raw("\xf9\x7c\x00") << "inf";
+ QTest::newRow("+inf_f") << raw("\xfa\x7f\x80\0\0") << "inf";
+ QTest::newRow("+inf") << raw("\xfb\x7f\xf0\0\0\0\0\0\0") << "inf";
+
+ QTest::newRow("emptybytestring") << raw("\x40") << "h''";
+ QTest::newRow("bytestring1") << raw("\x41 ") << "h'20'";
+ QTest::newRow("bytestring1-nul") << raw("\x41\0") << "h'00'";
+ QTest::newRow("bytestring5") << raw("\x45Hello") << "h'48656c6c6f'";
+ QTest::newRow("bytestring24") << raw("\x58\x18""123456789012345678901234")
+ << "h'313233343536373839303132333435363738393031323334'";
+
+ QTest::newRow("tag0") << raw("\xc0\x00") << "0(0)";
+ QTest::newRow("tag1") << raw("\xc1\x00") << "1(0)";
+ QTest::newRow("tag24") << raw("\xd8\x18\x00") << "24(0)";
+ QTest::newRow("tagUINT64_MAX") << raw("\xdb" "\xff\xff\xff\xff" "\xff\xff\xff\xff" "\x00")
+ << QString::number(std::numeric_limits<uint64_t>::max()) + "(0)";
+
+ QTest::newRow("emptyarray") << raw("\x80") << "[]";
+ QTest::newRow("emptymap") << raw("\xa0") << "{}";
+ QTest::newRow("_emptyarray") << raw("\x9f\xff") << "[_ ]";
+ QTest::newRow("_emptymap") << raw("\xbf\xff") << "{_ }";
+
+ QTest::newRow("map-0-24") << raw("\xa1\0\x18\x18") << "{0: 24}";
+ QTest::newRow("map-24-0") << raw("\xa1\x18\x18\0") << "{24: 0}";
+ QTest::newRow("_map-0-24") << raw("\xbf\0\x18\x18\xff") << "{_ 0: 24}";
+ QTest::newRow("_map-24-0") << raw("\xbf\x18\x18\0\xff") << "{_ 24: 0}";
+}
+
+void tst_ToJson::nonStringKeyMaps()
+{
+ QFETCH(QByteArray, data);
+ QFETCH(QString, expected);
+
+ data = "\xa1" + data + "\1";
+ compareOne(data, "{\"" + expected + "\":1}", CborConvertStringifyMapKeys);
+
+ // and verify that they fail if we use CborConvertRequireMapStringKeys
+ CborParser parser;
+ CborValue first;
+ QString decoded;
+ cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first);
+ CborError err = parseOne(&first, &decoded, CborConvertRequireMapStringKeys);
+ QCOMPARE(err, CborErrorJsonObjectKeyNotString);
+}
+
+void tst_ToJson::tagsToObjects_data()
+{
+ addColumns();
+ QTest::newRow("0(0)") << raw("\xc0\0") << "{\"tag0\":0}";
+ QTest::newRow("0(-1)") << raw("\xc0\x20") << "{\"tag0\":-1}";
+ QTest::newRow("0(\"hello\")") << raw("\xc0\x65hello") << "{\"tag0\":\"hello\"}";
+ QTest::newRow("22(h'48656c6c6f')") << raw("\xd6\x45Hello") << "{\"tag22\":\"SGVsbG8\"}";
+ QTest::newRow("0([1,2,3])") << raw("\xc0\x83\1\2\3") << "{\"tag0\":[1,2,3]}";
+ QTest::newRow("0({\"z\":true,\"y\":1})") << raw("\xc0\xa2\x61z\xf5\x61y\1") << "{\"tag0\":{\"z\":true,\"y\":1}}";
+
+ // large tags
+ QTest::newRow("55799(0)") << raw("\xd9\xd9\xf7\0") << "{\"tag55799\":0}";
+ QTest::newRow("4294967295") << raw("\xda\xff\xff\xff\xff\0") << "{\"tag4294967295\":0}";
+ QTest::newRow("18446744073709551615(0)") << raw("\xdb\xff\xff\xff\xff""\xff\xff\xff\xff\0")
+ << "{\"tag18446744073709551615\":0}";
+
+ // nested tags
+ QTest::newRow("0(1(2))") << raw("\xc0\xc1\2") << "{\"tag0\":{\"tag1\":2}}";
+ QTest::newRow("0({\"z\":1(2)})") << raw("\xc0\xa1\x61z\xc1\2") << "{\"tag0\":{\"z\":{\"tag1\":2}}}";
+}
+
+void tst_ToJson::tagsToObjects()
+{
+ QFETCH(QByteArray, data);
+ QFETCH(QString, expected);
+
+ compareOne(data, expected, CborConvertTagsToObjects);
+}
+
+void tst_ToJson::taggedByteStringsToBase16_data()
+{
+ QTest::addColumn<QByteArray>("data");
+ QTest::addColumn<QString>("base64url");
+ QTest::addColumn<QString>("base64");
+ QTest::addColumn<QString>("base16");
+
+ QTest::newRow("emptybytestring") << raw("\x40") << "" << "" << "";
+ QTest::newRow("bytestring1") << raw("\x41 ") << "IA" << "IA==" << "20";
+ QTest::newRow("bytestring1-nul") << raw("\x41\0") << "AA" << "AA==" << "00";
+ QTest::newRow("bytestring1-ff") << raw("\x41\xff") << "_w" << "/w==" << "ff";
+ QTest::newRow("bytestring2") << raw("\x42Hi") << "SGk" << "SGk=" << "4869";
+ QTest::newRow("bytestring3") << raw("\x43Hey") << "SGV5" << "SGV5" << "486579";
+ QTest::newRow("bytestring4") << raw("\x44Hola") << "SG9sYQ" << "SG9sYQ==" << "486f6c61";
+ QTest::newRow("bytestring5") << raw("\x45Hello") << "SGVsbG8" << "SGVsbG8=" << "48656c6c6f";
+ QTest::newRow("bytestring24") << raw("\x58\x18""123456789012345678901234")
+ << "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0"
+ << "MTIzNDU2Nzg5MDEyMzQ1Njc4OTAxMjM0"
+ << "313233343536373839303132333435363738393031323334";
+
+ // strings with undefined length
+ QTest::newRow("_emptybytestring") << raw("\x5f\xff") << "" << "" << "";
+ QTest::newRow("_emptybytestring2") << raw("\x5f\x40\xff") << "" << "" << "";
+ QTest::newRow("_emptybytestring3") << raw("\x5f\x40\x40\xff") << "" << "" << "";
+ QTest::newRow("_bytestring5*2") << raw("\x5f\x43Hel\x42lo\xff") << "SGVsbG8" << "SGVsbG8=" << "48656c6c6f";
+ QTest::newRow("_bytestring5*5") << raw("\x5f\x41H\x41""e\x41l\x41l\x41o\xff")
+ << "SGVsbG8" << "SGVsbG8=" << "48656c6c6f";
+ QTest::newRow("_bytestring5*6") << raw("\x5f\x41H\x41""e\x40\x41l\x41l\x41o\xff")
+ << "SGVsbG8" << "SGVsbG8=" << "48656c6c6f";
+}
+
+void tst_ToJson::taggedByteStringsToBase16()
+{
+ QFETCH(QByteArray, data);
+ QFETCH(QString, base16);
+
+ compareOne('\xd7' + data, '"' + base16 + '"', 0);
+}
+
+void tst_ToJson::taggedByteStringsToBase64()
+{
+ QFETCH(QByteArray, data);
+ QFETCH(QString, base64);
+
+ compareOne('\xd6' + data, '"' + base64 + '"', 0);
+}
+
+void tst_ToJson::taggedByteStringsToBigNum()
+{
+ QFETCH(QByteArray, data);
+ QFETCH(QString, base64url);
+
+ compareOne('\xc3' + data, "\"~" + base64url + '"', 0);
+}
+
+void tst_ToJson::otherTags_data()
+{
+ addColumns();
+ addFixedData();
+ addTextStringsData();
+ addNonJsonData();
+ addByteStringsData();
+ addEmptyContainersData();
+}
+
+void tst_ToJson::otherTags()
+{
+ QFETCH(QByteArray, data);
+ QFETCH(QString, expected);
+
+ // other tags produce no change in output
+ compareOne("\xc0" + data, expected, 0);
+ compareOne("\xc1" + data, expected, 0);
+ compareOne("\xc2" + data, expected, 0);
+ compareOne("\xc4" + data, expected, 0);
+ compareOne("\xc5" + data, expected, 0);
+ compareOne("\xd8\x20" + data, expected, 0);
+ compareOne("\xd8\x21" + data, expected, 0);
+ compareOne("\xd8\x22" + data, expected, 0);
+ compareOne("\xd8\x23" + data, expected, 0);
+ compareOne("\xd8\x24" + data, expected, 0);
+ compareOne("\xd9\xd9\xf7" + data, expected, 0);
+}
+
+void tst_ToJson::metaData_data()
+{
+ addColumns();
+
+ // booleans, null, strings, double precision numbers, regular maps, arrays and integers that
+ // didn't get rounded don't have metadata
+ QTest::newRow("0") << raw("\x00") << QString();
+ QTest::newRow("1") << raw("\x01") << QString();
+ QTest::newRow("2^53-1") << raw("\x1b\0\x1f\xff\xff""\xff\xff\xff\xff") << QString();
+ QTest::newRow("2^64-epsilon") << raw("\x1b\xff\xff\xff\xff""\xff\xff\xf8\x00") << QString();
+ QTest::newRow("-1") << raw("\x20") << QString();
+ QTest::newRow("-2") << raw("\x21") << QString();
+ QTest::newRow("-2^53+1") << raw("\x3b\0\x1f\xff\xff""\xff\xff\xff\xfe") << QString();
+ QTest::newRow("-2^64+epsilon") << raw("\x3b\xff\xff\xff\xff""\xff\xff\xf8\x00") << QString();
+ QTest::newRow("emptytextstring") << raw("\x60") << QString();
+ QTest::newRow("textstring1") << raw("\x61 ") << QString();
+ QTest::newRow("0.5") << raw("\xfb\x3f\xe0\0\0\0\0\0\0") << QString();
+ QTest::newRow("2.^64") << raw("\xfb\x43\xf0\0\0\0\0\0\0") << QString();
+ QTest::newRow("false") << raw("\xf4") << QString();
+ QTest::newRow("true") << raw("\xf5") << QString();
+ QTest::newRow("null") << raw("\xf6") << QString();
+ QTest::newRow("emptyarray") << raw("\x80") << QString();
+ QTest::newRow("emptymap") << raw("\xa0") << QString();
+ QTest::newRow("array*1") << raw("\x81\xf6") << QString();
+ QTest::newRow("map*1") << raw("\xa1\x61z\xf4") << QString();
+
+ // ---- everything from here on has at least the type ----
+ QTest::newRow("emptybytestring") << raw("\x40") << "\"t\":64";
+ QTest::newRow("bytestring1") << raw("\x41 ") << "\"t\":64";
+ QTest::newRow("undefined") << raw("\xf7") << "\"t\":247";
+ QTest::newRow("0.f16") << raw("\xf9\0\0") << "\"t\":249";
+ QTest::newRow("-1.f16") << raw("\xf9\xbc\x00") << "\"t\":249";
+ QTest::newRow("0.f") << raw("\xfa\0\0\0\0") << "\"t\":250";
+ QTest::newRow("-1.f") << raw("\xfa\xbf\x80\0\0") << "\"t\":250";
+ QTest::newRow("16777215.f") << raw("\xfa\x4b\x7f\xff\xff") << "\"t\":250";
+ QTest::newRow("-16777215.f") << raw("\xfa\xcb\x7f\xff\xff") << "\"t\":250";
+ QTest::newRow("0.") << raw("\xfb\0\0\0\0\0\0\0\0") << "\"t\":251";
+ QTest::newRow("-1.") << raw("\xfb\xbf\xf0\0\0\0\0\0\0") << "\"t\":251";
+ QTest::newRow("16777215.") << raw("\xfb\x41\x6f\xff\xff\xe0\0\0\0") << "\"t\":251";
+ QTest::newRow("-16777215.") << raw("\xfb\xc1\x6f\xff\xff\xe0\0\0\0") << "\"t\":251";
+ QTest::newRow("2.^53-1") << raw("\xfb\x43\x3f\xff\xff""\xff\xff\xff\xff") << "\"t\":251";
+ QTest::newRow("2.^64-epsilon") << raw("\xfb\x43\xef\xff\xff""\xff\xff\xff\xff") << "\"t\":251";
+
+ // integers that are too precise for double
+ QTest::newRow("2^53+1") << raw("\x1b\0\x20\0\0""\0\0\0\1")
+ << "\"t\":0,\"v\":\"+20000000000001\"";
+ QTest::newRow("INT64_MAX-1") << raw("\x1b\x7f\xff\xff\xff""\xff\xff\xff\xfe")
+ << "\"t\":0,\"v\":\"+7ffffffffffffffe\"";
+ QTest::newRow("INT64_MAX+1") << raw("\x1b\x80\0\0\0""\0\0\0\1")
+ << "\"t\":0,\"v\":\"+8000000000000001\"";
+ QTest::newRow("-2^53-1") << raw("\x3b\0\x20\0\0""\0\0\0\0")
+ << "\"t\":0,\"v\":\"-20000000000000\"";
+
+ // simple values
+ QTest::newRow("simple0") << raw("\xe0") << "\"t\":224,\"v\":0";
+ QTest::newRow("simple19") << raw("\xf3") << "\"t\":224,\"v\":19";
+ QTest::newRow("simple32") << raw("\xf8\x20") << "\"t\":224,\"v\":32";
+ QTest::newRow("simple255") << raw("\xf8\xff") << "\"t\":224,\"v\":255";
+
+ // infinities and NaN are not supported in JSON, they convert to null
+ QTest::newRow("nan_f16") << raw("\xf9\x7e\x00") << "\"t\":249,\"v\":\"nan\"";
+ QTest::newRow("nan_f") << raw("\xfa\x7f\xc0\0\0") << "\"t\":250,\"v\":\"nan\"";
+ QTest::newRow("nan") << raw("\xfb\x7f\xf8\0\0\0\0\0\0") << "\"t\":251,\"v\":\"nan\"";
+ QTest::newRow("-inf_f16") << raw("\xf9\xfc\x00") << "\"t\":249,\"v\":\"-inf\"";
+ QTest::newRow("-inf_f") << raw("\xfa\xff\x80\0\0") << "\"t\":250,\"v\":\"-inf\"";
+ QTest::newRow("-inf") << raw("\xfb\xff\xf0\0\0\0\0\0\0") << "\"t\":251,\"v\":\"-inf\"";
+ QTest::newRow("+inf_f16") << raw("\xf9\x7c\x00") << "\"t\":249,\"v\":\"inf\"";
+ QTest::newRow("+inf_f") << raw("\xfa\x7f\x80\0\0") << "\"t\":250,\"v\":\"inf\"";
+ QTest::newRow("+inf") << raw("\xfb\x7f\xf0\0\0\0\0\0\0") << "\"t\":251,\"v\":\"inf\"";
+
+ // tags on native types
+ QTest::newRow("tag+0") << raw("\xc0\x00") << "\"tag\":\"0\"";
+ QTest::newRow("tag+-2") << raw("\xc0\x21") << "\"tag\":\"0\"";
+ QTest::newRow("tag+0.5") << raw("\xc0\xfb\x3f\xe0\0\0\0\0\0\0") << "\"tag\":\"0\"";
+ QTest::newRow("tag+emptytextstring") << raw("\xc0\x60") << "\"tag\":\"0\"";
+ QTest::newRow("tag+textstring1") << raw("\xc0\x61 ") << "\"tag\":\"0\"";
+ QTest::newRow("tag+false") << raw("\xc0\xf4") << "\"tag\":\"0\"";
+ QTest::newRow("tag+true") << raw("\xc0\xf5") << "\"tag\":\"0\"";
+ QTest::newRow("tag+null") << raw("\xc0\xf6") << "\"tag\":\"0\"";
+ QTest::newRow("tag+emptyarray") << raw("\xc0\x80") << "\"tag\":\"0\"";
+ QTest::newRow("tag+emptymap") << raw("\xc0\xa0") << "\"tag\":\"0\"";
+ QTest::newRow("tag+array*1") << raw("\xc0\x81\xf6") << "\"tag\":\"0\"";
+ QTest::newRow("tag+map*1") << raw("\xc0\xa1\x61z\xf4") << "\"tag\":\"0\"";
+
+ // tags on non-native types
+ QTest::newRow("tag+emptybytestring") << raw("\xc0\x40") << "\"tag\":\"0\",\"t\":64";
+ QTest::newRow("tag+bytestring1") << raw("\xc0\x41 ") << "\"tag\":\"0\",\"t\":64";
+ QTest::newRow("tag+undefined") << raw("\xc0\xf7") << "\"tag\":\"0\",\"t\":247";
+ QTest::newRow("tag+0.f") << raw("\xc0\xfa\0\0\0\0") << "\"tag\":\"0\",\"t\":250";
+ QTest::newRow("tag+-1.f") << raw("\xc0\xfa\xbf\x80\0\0") << "\"tag\":\"0\",\"t\":250";
+ QTest::newRow("tag+16777215.f") << raw("\xc0\xfa\x4b\x7f\xff\xff") << "\"tag\":\"0\",\"t\":250";
+ QTest::newRow("tag+-16777215.f") << raw("\xc0\xfa\xcb\x7f\xff\xff") << "\"tag\":\"0\",\"t\":250";
+ QTest::newRow("tag+0.") << raw("\xc0\xfb\0\0\0\0\0\0\0\0") << "\"tag\":\"0\",\"t\":251";
+ QTest::newRow("tag+-1.") << raw("\xc0\xfb\xbf\xf0\0\0\0\0\0\0") << "\"tag\":\"0\",\"t\":251";
+ QTest::newRow("tag+16777215.") << raw("\xc0\xfb\x41\x6f\xff\xff\xe0\0\0\0") << "\"tag\":\"0\",\"t\":251";
+ QTest::newRow("tag+-16777215.") << raw("\xc0\xfb\xc1\x6f\xff\xff\xe0\0\0\0") << "\"tag\":\"0\",\"t\":251";
+
+ // big tags (don't fit in JS numbers)
+ QTest::newRow("bigtag1") << raw("\xdb\0\x20\0\0""\0\0\0\1\x60") << "\"tag\":\"9007199254740993\"";
+ QTest::newRow("bigtag2") << raw("\xdb\xff\xff\xff\xff""\xff\xff\xff\xfe\x60")
+ << "\"tag\":\"18446744073709551614\"";
+
+ // specially-handled tags
+ QTest::newRow("negativebignum") << raw("\xc3\x41 ") << "\"tag\":\"3\",\"t\":64";
+ QTest::newRow("base64") << raw("\xd6\x41 ") << "\"tag\":\"22\",\"t\":64";
+ QTest::newRow("base16") << raw("\xd7\x41 ") << "\"tag\":\"23\",\"t\":64";
+}
+
+void compareMetaData(QByteArray data, const QString &expected, int otherFlags = 0)
+{
+ QString decoded;
+
+ // needs to be in one map, with the entry called "v"
+ data = "\xa1\x61v" + data;
+
+ {
+ CborParser parser;
+ CborValue first;
+ CborError err = cbor_parser_init(reinterpret_cast<const quint8 *>(data.constData()), data.length(), 0, &parser, &first);
+ QVERIFY2(!err, QByteArrayLiteral(": Got error \"") + cbor_error_string(err) + "\"");
+
+ err = parseOne(&first, &decoded, CborConvertAddMetadata | otherFlags);
+ QVERIFY2(!err, QByteArrayLiteral(": Got error \"") + cbor_error_string(err) +
+ "\"; decoded stream:\n" + decoded.toLatin1());
+
+ // check that we consumed everything
+ QCOMPARE((void*)cbor_value_get_next_byte(&first), (void*)data.constEnd());
+ }
+
+ QVERIFY(decoded.startsWith("{\"v\":"));
+ QVERIFY(decoded.endsWith('}'));
+// qDebug() << "was" << decoded;
+
+ // extract just the metadata
+ static const char needle[] = "\"v$cbor\":{";
+ int pos = decoded.indexOf(needle);
+ QCOMPARE(pos == -1, expected.isEmpty());
+ if (pos != -1) {
+ decoded.chop(2);
+ decoded = std::move(decoded).mid(pos + strlen(needle));
+ QCOMPARE(decoded, expected);
+ }
+}
+
+void tst_ToJson::metaData()
+{
+ QFETCH(QByteArray, data);
+ QFETCH(QString, expected);
+ compareMetaData(data, expected);
+}
+
+void tst_ToJson::metaDataAndTagsToObjects()
+{
+ QFETCH(QByteArray, data);
+
+ // when a tag is converted to an object, the object gets metadata indicating it was a tag
+ compareMetaData(data, "\"t\":192", CborConvertTagsToObjects);
+}
+
+void tst_ToJson::metaDataForKeys_data()
+{
+ nonStringKeyMaps_data();
+
+ // string keys generate no metadata
+ QTest::newRow("string") << raw("\x60") << QString();
+}
+
+void tst_ToJson::metaDataForKeys()
+{
+ QFETCH(QByteArray, data);
+ QFETCH(QString, expected);
+ if (expected.isEmpty())
+ expected = "{\"\":false}";
+ else
+ expected = "{\"" + expected + "\":false,\"" + expected + "$keycbordump\":true}";
+ compareOne('\xa1' + data + '\xf4', expected,
+ CborConvertAddMetadata | CborConvertStringifyMapKeys);
+}
+
+QTEST_MAIN(tst_ToJson)