Add binary type support to all binary file formats, as well as an internally represented binary type
This commit is contained in:
parent
6121fc52cf
commit
012c9665ac
21 changed files with 3008 additions and 106 deletions
BIN
test/data/binary_data/cbor_binary.cbor
Normal file
BIN
test/data/binary_data/cbor_binary.cbor
Normal file
Binary file not shown.
17
test/data/binary_data/cbor_binary.out
Normal file
17
test/data/binary_data/cbor_binary.out
Normal file
|
@ -0,0 +1,17 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<17>ΘK€ΐxY<59>ζΏ¬?“Έ€π3"η†xU’—·όF*RϊΝΟΓΥPΠgω)<29>ΘK€ΐxY<59>ζΏ¬?“Έ€π3"η†xU’—·όF*RϊΝΟΓΥPΠgω)<29>ΘK€ΐxY<59>ζΏ¬?“Έ€π3"η†xU’—·όF*RϊΝΟΓΥPΠgω)<29>ΘK€ΐxY<59>ζΏ¬?“Έ€π3"η†xU’—·όF*RϊΝΟΓΥPΠgω)
|
||||
|
||||
|
|
@ -492,6 +492,36 @@ TEST_CASE("BSON")
|
|||
CHECK(json::from_bson(result, true, false) == j);
|
||||
}
|
||||
|
||||
SECTION("non-empty object with binary member")
|
||||
{
|
||||
const size_t N = 10;
|
||||
const auto s = std::vector<uint8_t>(N, 'x');
|
||||
json j =
|
||||
{
|
||||
{ "entry", json::binary_array(s) }
|
||||
};
|
||||
|
||||
std::vector<uint8_t> expected =
|
||||
{
|
||||
0x1B, 0x00, 0x00, 0x00, // size (little endian)
|
||||
0x05, // entry: binary
|
||||
'e', 'n', 't', 'r', 'y', '\x00',
|
||||
|
||||
0x0A, 0x00, 0x00, 0x00, // size of binary (little endian)
|
||||
0x00, // Generic binary subtype
|
||||
0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
|
||||
|
||||
0x00 // end marker
|
||||
};
|
||||
|
||||
const auto result = json::to_bson(j);
|
||||
CHECK(result == expected);
|
||||
|
||||
// roundtrip
|
||||
CHECK(json::from_bson(result) == j);
|
||||
CHECK(json::from_bson(result, true, false) == j);
|
||||
}
|
||||
|
||||
SECTION("Some more complex document")
|
||||
{
|
||||
// directly encoding uint64 is not supported in bson (only for timestamp values)
|
||||
|
@ -646,6 +676,11 @@ class SaxCountdown
|
|||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool binary(std::vector<uint8_t>&)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
|
|
|
@ -36,6 +36,7 @@ using nlohmann::json;
|
|||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <set>
|
||||
|
||||
namespace
|
||||
|
@ -76,6 +77,11 @@ class SaxCountdown
|
|||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool binary(std::vector<std::uint8_t>&)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
|
@ -1285,10 +1291,156 @@ TEST_CASE("CBOR")
|
|||
CHECK(json::from_cbor(result, true, false) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("binary")
|
||||
{
|
||||
SECTION("N = 0..23")
|
||||
{
|
||||
for (size_t N = 0; N <= 0x17; ++N)
|
||||
{
|
||||
CAPTURE(N)
|
||||
|
||||
// create JSON value with byte array containing of N * 'x'
|
||||
const auto s = std::vector<uint8_t>(N, 'x');
|
||||
json j = json::binary_array(s);
|
||||
|
||||
// create expected byte vector
|
||||
std::vector<uint8_t> expected;
|
||||
expected.push_back(static_cast<uint8_t>(0x40 + N));
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
{
|
||||
expected.push_back(0x78);
|
||||
}
|
||||
|
||||
// compare result + size
|
||||
const auto result = json::to_cbor(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(result.size() == N + 1);
|
||||
// check that no null byte is appended
|
||||
if (N > 0)
|
||||
{
|
||||
CHECK(result.back() != '\x00');
|
||||
}
|
||||
|
||||
// roundtrip
|
||||
CHECK(json::from_cbor(result) == j);
|
||||
CHECK(json::from_cbor(result, true, false) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("N = 24..255")
|
||||
{
|
||||
for (size_t N = 24; N <= 255; ++N)
|
||||
{
|
||||
CAPTURE(N)
|
||||
|
||||
// create JSON value with string containing of N * 'x'
|
||||
const auto s = std::vector<uint8_t>(N, 'x');
|
||||
json j = json::binary_array(s);
|
||||
|
||||
// create expected byte vector
|
||||
std::vector<uint8_t> expected;
|
||||
expected.push_back(0x58);
|
||||
expected.push_back(static_cast<uint8_t>(N));
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
{
|
||||
expected.push_back('x');
|
||||
}
|
||||
|
||||
// compare result + size
|
||||
const auto result = json::to_cbor(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(result.size() == N + 2);
|
||||
// check that no null byte is appended
|
||||
CHECK(result.back() != '\x00');
|
||||
|
||||
// roundtrip
|
||||
CHECK(json::from_cbor(result) == j);
|
||||
CHECK(json::from_cbor(result, true, false) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("N = 256..65535")
|
||||
{
|
||||
for (size_t N :
|
||||
{
|
||||
256u, 999u, 1025u, 3333u, 2048u, 65535u
|
||||
})
|
||||
{
|
||||
CAPTURE(N)
|
||||
|
||||
// create JSON value with string containing of N * 'x'
|
||||
const auto s = std::vector<uint8_t>(N, 'x');
|
||||
json j = json::binary_array(s);
|
||||
|
||||
// create expected byte vector (hack: create string first)
|
||||
std::vector<uint8_t> expected(N, 'x');
|
||||
// reverse order of commands, because we insert at begin()
|
||||
expected.insert(expected.begin(), static_cast<uint8_t>(N & 0xff));
|
||||
expected.insert(expected.begin(), static_cast<uint8_t>((N >> 8) & 0xff));
|
||||
expected.insert(expected.begin(), 0x59);
|
||||
|
||||
// compare result + size
|
||||
const auto result = json::to_cbor(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(result.size() == N + 3);
|
||||
// check that no null byte is appended
|
||||
CHECK(result.back() != '\x00');
|
||||
|
||||
// roundtrip
|
||||
CHECK(json::from_cbor(result) == j);
|
||||
CHECK(json::from_cbor(result, true, false) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("N = 65536..4294967295")
|
||||
{
|
||||
for (size_t N :
|
||||
{
|
||||
65536u, 77777u, 1048576u
|
||||
})
|
||||
{
|
||||
CAPTURE(N)
|
||||
|
||||
// create JSON value with string containing of N * 'x'
|
||||
const auto s = std::vector<uint8_t>(N, 'x');
|
||||
json j = json::binary_array(s);
|
||||
|
||||
// create expected byte vector (hack: create string first)
|
||||
std::vector<uint8_t> expected(N, 'x');
|
||||
// reverse order of commands, because we insert at begin()
|
||||
expected.insert(expected.begin(), static_cast<uint8_t>(N & 0xff));
|
||||
expected.insert(expected.begin(), static_cast<uint8_t>((N >> 8) & 0xff));
|
||||
expected.insert(expected.begin(), static_cast<uint8_t>((N >> 16) & 0xff));
|
||||
expected.insert(expected.begin(), static_cast<uint8_t>((N >> 24) & 0xff));
|
||||
expected.insert(expected.begin(), 0x5a);
|
||||
|
||||
// compare result + size
|
||||
const auto result = json::to_cbor(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(result.size() == N + 5);
|
||||
// check that no null byte is appended
|
||||
CHECK(result.back() != '\x00');
|
||||
|
||||
// roundtrip
|
||||
CHECK(json::from_cbor(result) == j);
|
||||
CHECK(json::from_cbor(result, true, false) == j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("additional deserialization")
|
||||
{
|
||||
SECTION("0x5b (byte array)")
|
||||
{
|
||||
std::vector<uint8_t> given = {0x5b, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x01, 0x61
|
||||
};
|
||||
json j = json::from_cbor(given);
|
||||
CHECK(j == json::binary_array(std::vector<uint8_t> {'a'}));
|
||||
}
|
||||
|
||||
SECTION("0x7b (string)")
|
||||
{
|
||||
std::vector<uint8_t> given = {0x7b, 0x00, 0x00, 0x00, 0x00,
|
||||
|
@ -1455,14 +1607,8 @@ TEST_CASE("CBOR")
|
|||
0x1c, 0x1d, 0x1e, 0x1f,
|
||||
// ?
|
||||
0x3c, 0x3d, 0x3e, 0x3f,
|
||||
// byte strings
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
|
||||
// byte strings
|
||||
0x58, 0x59, 0x5a, 0x5b,
|
||||
// ?
|
||||
0x5c, 0x5d, 0x5e,
|
||||
// byte string
|
||||
0x5f,
|
||||
// ?
|
||||
0x7c, 0x7d, 0x7e,
|
||||
// ?
|
||||
|
@ -1929,12 +2075,6 @@ TEST_CASE("all CBOR first bytes")
|
|||
{
|
||||
//// types not supported by this library
|
||||
|
||||
// byte strings
|
||||
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
|
||||
0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
|
||||
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
|
||||
// byte strings
|
||||
0x58, 0x59, 0x5a, 0x5b, 0x5f,
|
||||
// date/time
|
||||
0xc0, 0xc1,
|
||||
// bignum
|
||||
|
@ -2144,6 +2284,20 @@ TEST_CASE("examples from RFC 7049 Appendix A")
|
|||
CHECK(json::parse("\"streaming\"") == json::from_cbor(std::vector<uint8_t>({0x7f, 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x67, 0xff})));
|
||||
}
|
||||
|
||||
SECTION("byte arrays")
|
||||
{
|
||||
std::ifstream f_cbor("test/data/binary_data/cbor_binary.cbor", std::ios::binary);
|
||||
std::vector<uint8_t> packed((std::istreambuf_iterator<char>(f_cbor)),
|
||||
std::istreambuf_iterator<char>());
|
||||
json j;
|
||||
CHECK_NOTHROW(j = json::from_cbor(packed));
|
||||
|
||||
std::ifstream f_bin("test/data/binary_data/cbor_binary.out", std::ios::binary);
|
||||
std::vector<uint8_t> expected((std::istreambuf_iterator<char>(f_bin)),
|
||||
std::istreambuf_iterator<char>());
|
||||
CHECK(j == json::binary_array(expected));
|
||||
}
|
||||
|
||||
SECTION("arrays")
|
||||
{
|
||||
CHECK(json::to_cbor(json::parse("[]")) == std::vector<uint8_t>({0x80}));
|
||||
|
|
|
@ -77,6 +77,21 @@ class SaxEventLogger
|
|||
return true;
|
||||
}
|
||||
|
||||
bool binary(std::vector<std::uint8_t>& val)
|
||||
{
|
||||
std::string binary_contents = "binary(";
|
||||
std::string comma_space = "";
|
||||
for (auto b : val)
|
||||
{
|
||||
binary_contents.append(comma_space);
|
||||
binary_contents.append(std::to_string(static_cast<int>(b)));
|
||||
comma_space = ", ";
|
||||
}
|
||||
binary_contents.append(")");
|
||||
events.push_back(binary_contents);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t elements)
|
||||
{
|
||||
if (elements == std::size_t(-1))
|
||||
|
@ -168,6 +183,11 @@ class SaxCountdown : public nlohmann::json::json_sax_t
|
|||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool binary(std::vector<std::uint8_t>&) override
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t) override
|
||||
{
|
||||
return events_left-- > 0;
|
||||
|
|
|
@ -76,6 +76,21 @@ struct SaxEventLogger : public nlohmann::json_sax<json>
|
|||
return true;
|
||||
}
|
||||
|
||||
bool binary(std::vector<std::uint8_t>& val)
|
||||
{
|
||||
std::string binary_contents = "binary(";
|
||||
std::string comma_space = "";
|
||||
for (auto b : val)
|
||||
{
|
||||
binary_contents.append(comma_space);
|
||||
binary_contents.append(std::to_string(static_cast<int>(b)));
|
||||
comma_space = ", ";
|
||||
}
|
||||
binary_contents.append(")");
|
||||
events.push_back(binary_contents);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t elements) override
|
||||
{
|
||||
if (elements == std::size_t(-1))
|
||||
|
|
|
@ -75,6 +75,11 @@ class SaxCountdown
|
|||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool binary(std::vector<std::uint8_t>&)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
|
@ -1115,6 +1120,261 @@ TEST_CASE("MessagePack")
|
|||
CHECK(json::from_msgpack(result, true, false) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("extension")
|
||||
{
|
||||
SECTION("N = 0..255")
|
||||
{
|
||||
for (size_t N = 0; N <= 0xFF; ++N)
|
||||
{
|
||||
CAPTURE(N)
|
||||
|
||||
// create JSON value with byte array containing of N * 'x'
|
||||
const auto s = std::vector<uint8_t>(N, 'x');
|
||||
json j = json::binary_array(s);
|
||||
std::uint8_t subtype = 42;
|
||||
j.set_subtype(subtype);
|
||||
|
||||
// create expected byte vector
|
||||
std::vector<uint8_t> expected;
|
||||
switch (N)
|
||||
{
|
||||
case 1:
|
||||
expected.push_back(static_cast<std::uint8_t>(0xD4));
|
||||
break;
|
||||
case 2:
|
||||
expected.push_back(static_cast<std::uint8_t>(0xD5));
|
||||
break;
|
||||
case 4:
|
||||
expected.push_back(static_cast<std::uint8_t>(0xD6));
|
||||
break;
|
||||
case 8:
|
||||
expected.push_back(static_cast<std::uint8_t>(0xD7));
|
||||
break;
|
||||
case 16:
|
||||
expected.push_back(static_cast<std::uint8_t>(0xD8));
|
||||
break;
|
||||
default:
|
||||
expected.push_back(static_cast<std::uint8_t>(0xC7));
|
||||
expected.push_back(static_cast<std::uint8_t>(N));
|
||||
break;
|
||||
}
|
||||
expected.push_back(subtype);
|
||||
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
{
|
||||
expected.push_back(0x78);
|
||||
}
|
||||
|
||||
// compare result + size
|
||||
const auto result = json::to_msgpack(j);
|
||||
CHECK(result == expected);
|
||||
switch (N)
|
||||
{
|
||||
case 1:
|
||||
case 2:
|
||||
case 4:
|
||||
case 8:
|
||||
case 16:
|
||||
CHECK(result.size() == N + 2);
|
||||
break;
|
||||
default:
|
||||
CHECK(result.size() == N + 3);
|
||||
break;
|
||||
}
|
||||
|
||||
// check that no null byte is appended
|
||||
if (N > 0)
|
||||
{
|
||||
CHECK(result.back() != '\x00');
|
||||
}
|
||||
|
||||
// roundtrip
|
||||
CHECK(json::from_msgpack(result) == j);
|
||||
CHECK(json::from_msgpack(result, true, false) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("N = 256..65535")
|
||||
{
|
||||
for (std::size_t N :
|
||||
{
|
||||
256u, 999u, 1025u, 3333u, 2048u, 65535u
|
||||
})
|
||||
{
|
||||
CAPTURE(N)
|
||||
|
||||
// create JSON value with string containing of N * 'x'
|
||||
const auto s = std::vector<uint8_t>(N, 'x');
|
||||
json j = json::binary_array(s);
|
||||
std::uint8_t subtype = 42;
|
||||
j.set_subtype(subtype);
|
||||
|
||||
// create expected byte vector (hack: create string first)
|
||||
std::vector<uint8_t> expected(N, 'x');
|
||||
// reverse order of commands, because we insert at begin()
|
||||
expected.insert(expected.begin(), subtype);
|
||||
expected.insert(expected.begin(), static_cast<uint8_t>(N & 0xff));
|
||||
expected.insert(expected.begin(), static_cast<uint8_t>((N >> 8) & 0xff));
|
||||
expected.insert(expected.begin(), 0xC8);
|
||||
|
||||
// compare result + size
|
||||
const auto result = json::to_msgpack(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(result.size() == N + 4);
|
||||
// check that no null byte is appended
|
||||
CHECK(result.back() != '\x00');
|
||||
|
||||
// roundtrip
|
||||
CHECK(json::from_msgpack(result) == j);
|
||||
CHECK(json::from_msgpack(result, true, false) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("N = 65536..4294967295")
|
||||
{
|
||||
for (std::size_t N :
|
||||
{
|
||||
65536u, 77777u, 1048576u
|
||||
})
|
||||
{
|
||||
CAPTURE(N)
|
||||
|
||||
// create JSON value with string containing of N * 'x'
|
||||
const auto s = std::vector<uint8_t>(N, 'x');
|
||||
json j = json::binary_array(s);
|
||||
std::uint8_t subtype = 42;
|
||||
j.set_subtype(subtype);
|
||||
|
||||
// create expected byte vector (hack: create string first)
|
||||
std::vector<uint8_t> expected(N, 'x');
|
||||
// reverse order of commands, because we insert at begin()
|
||||
expected.insert(expected.begin(), subtype);
|
||||
expected.insert(expected.begin(), static_cast<uint8_t>(N & 0xff));
|
||||
expected.insert(expected.begin(), static_cast<uint8_t>((N >> 8) & 0xff));
|
||||
expected.insert(expected.begin(), static_cast<uint8_t>((N >> 16) & 0xff));
|
||||
expected.insert(expected.begin(), static_cast<uint8_t>((N >> 24) & 0xff));
|
||||
expected.insert(expected.begin(), 0xC9);
|
||||
|
||||
// compare result + size
|
||||
const auto result = json::to_msgpack(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(result.size() == N + 6);
|
||||
// check that no null byte is appended
|
||||
CHECK(result.back() != '\x00');
|
||||
|
||||
// roundtrip
|
||||
CHECK(json::from_msgpack(result) == j);
|
||||
CHECK(json::from_msgpack(result, true, false) == j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("binary")
|
||||
{
|
||||
SECTION("N = 0..255")
|
||||
{
|
||||
for (std::size_t N = 0; N <= 0xFF; ++N)
|
||||
{
|
||||
CAPTURE(N)
|
||||
|
||||
// create JSON value with byte array containing of N * 'x'
|
||||
const auto s = std::vector<uint8_t>(N, 'x');
|
||||
json j = json::binary_array(s);
|
||||
|
||||
// create expected byte vector
|
||||
std::vector<std::uint8_t> expected;
|
||||
expected.push_back(static_cast<std::uint8_t>(0xC4));
|
||||
expected.push_back(static_cast<std::uint8_t>(N));
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
{
|
||||
expected.push_back(0x78);
|
||||
}
|
||||
|
||||
// compare result + size
|
||||
const auto result = json::to_msgpack(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(result.size() == N + 2);
|
||||
// check that no null byte is appended
|
||||
if (N > 0)
|
||||
{
|
||||
CHECK(result.back() != '\x00');
|
||||
}
|
||||
|
||||
// roundtrip
|
||||
CHECK(json::from_msgpack(result) == j);
|
||||
CHECK(json::from_msgpack(result, true, false) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("N = 256..65535")
|
||||
{
|
||||
for (std::size_t N :
|
||||
{
|
||||
256u, 999u, 1025u, 3333u, 2048u, 65535u
|
||||
})
|
||||
{
|
||||
CAPTURE(N)
|
||||
|
||||
// create JSON value with string containing of N * 'x'
|
||||
const auto s = std::vector<std::uint8_t>(N, 'x');
|
||||
json j = json::binary_array(s);
|
||||
|
||||
// create expected byte vector (hack: create string first)
|
||||
std::vector<std::uint8_t> expected(N, 'x');
|
||||
// reverse order of commands, because we insert at begin()
|
||||
expected.insert(expected.begin(), static_cast<std::uint8_t>(N & 0xff));
|
||||
expected.insert(expected.begin(), static_cast<std::uint8_t>((N >> 8) & 0xff));
|
||||
expected.insert(expected.begin(), 0xC5);
|
||||
|
||||
// compare result + size
|
||||
const auto result = json::to_msgpack(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(result.size() == N + 3);
|
||||
// check that no null byte is appended
|
||||
CHECK(result.back() != '\x00');
|
||||
|
||||
// roundtrip
|
||||
CHECK(json::from_msgpack(result) == j);
|
||||
CHECK(json::from_msgpack(result, true, false) == j);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("N = 65536..4294967295")
|
||||
{
|
||||
for (std::size_t N :
|
||||
{
|
||||
65536u, 77777u, 1048576u
|
||||
})
|
||||
{
|
||||
CAPTURE(N)
|
||||
|
||||
// create JSON value with string containing of N * 'x'
|
||||
const auto s = std::vector<std::uint8_t>(N, 'x');
|
||||
json j = json::binary_array(s);
|
||||
|
||||
// create expected byte vector (hack: create string first)
|
||||
std::vector<uint8_t> expected(N, 'x');
|
||||
// reverse order of commands, because we insert at begin()
|
||||
expected.insert(expected.begin(), static_cast<std::uint8_t>(N & 0xff));
|
||||
expected.insert(expected.begin(), static_cast<std::uint8_t>((N >> 8) & 0xff));
|
||||
expected.insert(expected.begin(), static_cast<std::uint8_t>((N >> 16) & 0xff));
|
||||
expected.insert(expected.begin(), static_cast<std::uint8_t>((N >> 24) & 0xff));
|
||||
expected.insert(expected.begin(), 0xC6);
|
||||
|
||||
// compare result + size
|
||||
const auto result = json::to_msgpack(j);
|
||||
CHECK(result == expected);
|
||||
CHECK(result.size() == N + 5);
|
||||
// check that no null byte is appended
|
||||
CHECK(result.back() != '\x00');
|
||||
|
||||
// roundtrip
|
||||
CHECK(json::from_msgpack(result) == j);
|
||||
CHECK(json::from_msgpack(result, true, false) == j);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("from float32")
|
||||
|
@ -1226,12 +1486,6 @@ TEST_CASE("MessagePack")
|
|||
CHECK_THROWS_AS(_ = json::from_msgpack(std::vector<uint8_t>({0xc1})), json::parse_error&);
|
||||
CHECK_THROWS_WITH(_ = json::from_msgpack(std::vector<uint8_t>({0xc1})),
|
||||
"[json.exception.parse_error.112] parse error at byte 1: syntax error while parsing MessagePack value: invalid byte: 0xC1");
|
||||
CHECK(json::from_msgpack(std::vector<uint8_t>({0xc6}), true, false).is_discarded());
|
||||
|
||||
CHECK_THROWS_AS(_ = json::from_msgpack(std::vector<uint8_t>({0xc6})), json::parse_error&);
|
||||
CHECK_THROWS_WITH(_ = json::from_msgpack(std::vector<uint8_t>({0xc6})),
|
||||
"[json.exception.parse_error.112] parse error at byte 1: syntax error while parsing MessagePack value: invalid byte: 0xC6");
|
||||
CHECK(json::from_msgpack(std::vector<uint8_t>({0xc6}), true, false).is_discarded());
|
||||
}
|
||||
|
||||
SECTION("all unsupported bytes")
|
||||
|
@ -1239,13 +1493,7 @@ TEST_CASE("MessagePack")
|
|||
for (auto byte :
|
||||
{
|
||||
// never used
|
||||
0xc1,
|
||||
// bin
|
||||
0xc4, 0xc5, 0xc6,
|
||||
// ext
|
||||
0xc7, 0xc8, 0xc9,
|
||||
// fixext
|
||||
0xd4, 0xd5, 0xd6, 0xd7, 0xd8
|
||||
0xc1
|
||||
})
|
||||
{
|
||||
json _;
|
||||
|
|
|
@ -107,7 +107,7 @@ struct foo_serializer < T, typename std::enable_if < !std::is_same<foo, T>::valu
|
|||
}
|
||||
|
||||
using foo_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t,
|
||||
std::uint64_t, double, std::allocator, ns::foo_serializer>;
|
||||
std::uint64_t, double, std::allocator, ns::foo_serializer, std::vector<std::uint8_t>>;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
// for #805
|
||||
|
|
|
@ -73,6 +73,11 @@ class SaxCountdown
|
|||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool binary(std::vector<std::uint8_t>&)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
}
|
||||
|
||||
bool start_object(std::size_t)
|
||||
{
|
||||
return events_left-- > 0;
|
||||
|
@ -905,6 +910,231 @@ TEST_CASE("UBJSON")
|
|||
}
|
||||
}
|
||||
|
||||
SECTION("binary")
|
||||
{
|
||||
SECTION("N = 0..127")
|
||||
{
|
||||
for (std::size_t N = 0; N <= 127; ++N)
|
||||
{
|
||||
CAPTURE(N)
|
||||
|
||||
// create JSON value with byte array containing of N * 'x'
|
||||
const auto s = std::vector<std::uint8_t>(N, 'x');
|
||||
json j = json::binary_array(s);
|
||||
|
||||
// create expected byte vector
|
||||
std::vector<std::uint8_t> expected;
|
||||
expected.push_back(static_cast<std::uint8_t>('['));
|
||||
if (N != 0)
|
||||
{
|
||||
expected.push_back(static_cast<std::uint8_t>('$'));
|
||||
expected.push_back(static_cast<std::uint8_t>('U'));
|
||||
}
|
||||
expected.push_back(static_cast<std::uint8_t>('#'));
|
||||
expected.push_back(static_cast<std::uint8_t>('i'));
|
||||
expected.push_back(static_cast<std::uint8_t>(N));
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
{
|
||||
expected.push_back(0x78);
|
||||
}
|
||||
|
||||
// compare result + size
|
||||
const auto result = json::to_ubjson(j, true, true);
|
||||
CHECK(result == expected);
|
||||
if (N == 0)
|
||||
{
|
||||
CHECK(result.size() == N + 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK(result.size() == N + 6);
|
||||
}
|
||||
|
||||
// check that no null byte is appended
|
||||
if (N > 0)
|
||||
{
|
||||
CHECK(result.back() != '\x00');
|
||||
}
|
||||
|
||||
// roundtrip only works to an array of numbers
|
||||
json j_out = s;
|
||||
CHECK(json::from_ubjson(result) == j_out);
|
||||
CHECK(json::from_ubjson(result, true, false) == j_out);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("N = 128..255")
|
||||
{
|
||||
for (std::size_t N = 128; N <= 255; ++N)
|
||||
{
|
||||
CAPTURE(N)
|
||||
|
||||
// create JSON value with byte array containing of N * 'x'
|
||||
const auto s = std::vector<std::uint8_t>(N, 'x');
|
||||
json j = json::binary_array(s);
|
||||
|
||||
// create expected byte vector
|
||||
std::vector<uint8_t> expected;
|
||||
expected.push_back(static_cast<std::uint8_t>('['));
|
||||
expected.push_back(static_cast<std::uint8_t>('$'));
|
||||
expected.push_back(static_cast<std::uint8_t>('U'));
|
||||
expected.push_back(static_cast<std::uint8_t>('#'));
|
||||
expected.push_back(static_cast<std::uint8_t>('U'));
|
||||
expected.push_back(static_cast<std::uint8_t>(N));
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
{
|
||||
expected.push_back(0x78);
|
||||
}
|
||||
|
||||
// compare result + size
|
||||
const auto result = json::to_ubjson(j, true, true);
|
||||
CHECK(result == expected);
|
||||
CHECK(result.size() == N + 6);
|
||||
// check that no null byte is appended
|
||||
CHECK(result.back() != '\x00');
|
||||
|
||||
// roundtrip only works to an array of numbers
|
||||
json j_out = s;
|
||||
CHECK(json::from_ubjson(result) == j_out);
|
||||
CHECK(json::from_ubjson(result, true, false) == j_out);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("N = 256..32767")
|
||||
{
|
||||
for (std::size_t N :
|
||||
{
|
||||
256u, 999u, 1025u, 3333u, 2048u, 32767u
|
||||
})
|
||||
{
|
||||
CAPTURE(N)
|
||||
|
||||
// create JSON value with byte array containing of N * 'x'
|
||||
const auto s = std::vector<std::uint8_t>(N, 'x');
|
||||
json j = json::binary_array(s);
|
||||
|
||||
// create expected byte vector
|
||||
std::vector<std::uint8_t> expected(N + 7, 'x');
|
||||
expected[0] = '[';
|
||||
expected[1] = '$';
|
||||
expected[2] = 'U';
|
||||
expected[3] = '#';
|
||||
expected[4] = 'I';
|
||||
expected[5] = static_cast<std::uint8_t>((N >> 8) & 0xFF);
|
||||
expected[6] = static_cast<std::uint8_t>(N & 0xFF);
|
||||
|
||||
// compare result + size
|
||||
const auto result = json::to_ubjson(j, true, true);
|
||||
CHECK(result == expected);
|
||||
CHECK(result.size() == N + 7);
|
||||
// check that no null byte is appended
|
||||
CHECK(result.back() != '\x00');
|
||||
|
||||
// roundtrip only works to an array of numbers
|
||||
json j_out = s;
|
||||
CHECK(json::from_ubjson(result) == j_out);
|
||||
CHECK(json::from_ubjson(result, true, false) == j_out);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("N = 32768..2147483647")
|
||||
{
|
||||
for (std::size_t N :
|
||||
{
|
||||
32768u, 77777u, 1048576u
|
||||
})
|
||||
{
|
||||
CAPTURE(N)
|
||||
|
||||
// create JSON value with byte array containing of N * 'x'
|
||||
const auto s = std::vector<std::uint8_t>(N, 'x');
|
||||
json j = json::binary_array(s);
|
||||
|
||||
// create expected byte vector
|
||||
std::vector<std::uint8_t> expected(N + 9, 'x');
|
||||
expected[0] = '[';
|
||||
expected[1] = '$';
|
||||
expected[2] = 'U';
|
||||
expected[3] = '#';
|
||||
expected[4] = 'l';
|
||||
expected[5] = static_cast<std::uint8_t>((N >> 24) & 0xFF);
|
||||
expected[6] = static_cast<std::uint8_t>((N >> 16) & 0xFF);
|
||||
expected[7] = static_cast<std::uint8_t>((N >> 8) & 0xFF);
|
||||
expected[8] = static_cast<std::uint8_t>(N & 0xFF);
|
||||
|
||||
// compare result + size
|
||||
const auto result = json::to_ubjson(j, true, true);
|
||||
CHECK(result == expected);
|
||||
CHECK(result.size() == N + 9);
|
||||
// check that no null byte is appended
|
||||
CHECK(result.back() != '\x00');
|
||||
|
||||
// roundtrip only works to an array of numbers
|
||||
json j_out = s;
|
||||
CHECK(json::from_ubjson(result) == j_out);
|
||||
CHECK(json::from_ubjson(result, true, false) == j_out);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Other Serializations")
|
||||
{
|
||||
const std::size_t N = 10;
|
||||
const auto s = std::vector<std::uint8_t>(N, 'x');
|
||||
json j = json::binary_array(s);
|
||||
|
||||
SECTION("No Count No Type")
|
||||
{
|
||||
std::vector<uint8_t> expected;
|
||||
expected.push_back(static_cast<std::uint8_t>('['));
|
||||
for (std::size_t i = 0; i < N; ++i)
|
||||
{
|
||||
expected.push_back(static_cast<std::uint8_t>('U'));
|
||||
expected.push_back(static_cast<std::uint8_t>(0x78));
|
||||
}
|
||||
expected.push_back(static_cast<std::uint8_t>(']'));
|
||||
|
||||
// compare result + size
|
||||
const auto result = json::to_ubjson(j, false, false);
|
||||
CHECK(result == expected);
|
||||
CHECK(result.size() == N + 12);
|
||||
// check that no null byte is appended
|
||||
CHECK(result.back() != '\x00');
|
||||
|
||||
// roundtrip only works to an array of numbers
|
||||
json j_out = s;
|
||||
CHECK(json::from_ubjson(result) == j_out);
|
||||
CHECK(json::from_ubjson(result, true, false) == j_out);
|
||||
}
|
||||
|
||||
SECTION("Yes Count No Type")
|
||||
{
|
||||
std::vector<std::uint8_t> expected;
|
||||
expected.push_back(static_cast<std::uint8_t>('['));
|
||||
expected.push_back(static_cast<std::uint8_t>('#'));
|
||||
expected.push_back(static_cast<std::uint8_t>('i'));
|
||||
expected.push_back(static_cast<std::uint8_t>(N));
|
||||
|
||||
for (size_t i = 0; i < N; ++i)
|
||||
{
|
||||
expected.push_back(static_cast<std::uint8_t>('U'));
|
||||
expected.push_back(static_cast<std::uint8_t>(0x78));
|
||||
}
|
||||
|
||||
// compare result + size
|
||||
const auto result = json::to_ubjson(j, true, false);
|
||||
CHECK(result == expected);
|
||||
CHECK(result.size() == N + 14);
|
||||
// check that no null byte is appended
|
||||
CHECK(result.back() != '\x00');
|
||||
|
||||
// roundtrip only works to an array of numbers
|
||||
json j_out = s;
|
||||
CHECK(json::from_ubjson(result) == j_out);
|
||||
CHECK(json::from_ubjson(result, true, false) == j_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("array")
|
||||
{
|
||||
SECTION("empty")
|
||||
|
|
|
@ -653,8 +653,7 @@ TEST_CASE("custom serializer for pods" * doctest::test_suite("udt"))
|
|||
{
|
||||
using custom_json =
|
||||
nlohmann::basic_json<std::map, std::vector, std::string, bool,
|
||||
std::int64_t, std::uint64_t, double, std::allocator,
|
||||
pod_serializer>;
|
||||
std::int64_t, std::uint64_t, double, std::allocator, pod_serializer>;
|
||||
|
||||
auto p = udt::small_pod{42, '/', 42};
|
||||
custom_json j = p;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue