From ddff459fa3800691e1a21c42df451c933289e319 Mon Sep 17 00:00:00 2001 From: Niels Lohmann Date: Wed, 6 May 2020 21:24:00 +0200 Subject: [PATCH] :white_check_mark: add test for BSON binary subtype --- test/src/unit-bson.cpp | 186 ++++++++++++++++++++++++----------------- 1 file changed, 108 insertions(+), 78 deletions(-) diff --git a/test/src/unit-bson.cpp b/test/src/unit-bson.cpp index 9e8e996f..cfe7d766 100644 --- a/test/src/unit-bson.cpp +++ b/test/src/unit-bson.cpp @@ -106,7 +106,7 @@ TEST_CASE("BSON") SECTION("string length must be at least 1") { // from https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=11175 - std::vector v = + std::vector v = { 0x20, 0x20, 0x20, 0x20, 0x02, @@ -123,7 +123,7 @@ TEST_CASE("BSON") SECTION("empty object") { json j = json::object(); - std::vector expected = + std::vector expected = { 0x05, 0x00, 0x00, 0x00, // size (little endian) // no entries @@ -145,7 +145,7 @@ TEST_CASE("BSON") { "entry", true } }; - std::vector expected = + std::vector expected = { 0x0D, 0x00, 0x00, 0x00, // size (little endian) 0x08, // entry: boolean @@ -169,7 +169,7 @@ TEST_CASE("BSON") { "entry", false } }; - std::vector expected = + std::vector expected = { 0x0D, 0x00, 0x00, 0x00, // size (little endian) 0x08, // entry: boolean @@ -193,7 +193,7 @@ TEST_CASE("BSON") { "entry", 4.2 } }; - std::vector expected = + std::vector expected = { 0x14, 0x00, 0x00, 0x00, // size (little endian) 0x01, /// entry: double @@ -217,7 +217,7 @@ TEST_CASE("BSON") { "entry", "bsonstr" } }; - std::vector expected = + std::vector expected = { 0x18, 0x00, 0x00, 0x00, // size (little endian) 0x02, /// entry: string (UTF-8) @@ -241,7 +241,7 @@ TEST_CASE("BSON") { "entry", nullptr } }; - std::vector expected = + std::vector expected = { 0x0C, 0x00, 0x00, 0x00, // size (little endian) 0x0A, /// entry: null @@ -264,7 +264,7 @@ TEST_CASE("BSON") { "entry", std::int32_t{0x12345678} } }; - std::vector expected = + std::vector expected = { 0x10, 0x00, 0x00, 0x00, // size (little endian) 0x10, /// entry: int32 @@ -288,7 +288,7 @@ TEST_CASE("BSON") { "entry", std::int64_t{0x1234567804030201} } }; - std::vector expected = + std::vector expected = { 0x14, 0x00, 0x00, 0x00, // size (little endian) 0x12, /// entry: int64 @@ -312,7 +312,7 @@ TEST_CASE("BSON") { "entry", std::int32_t{-1} } }; - std::vector expected = + std::vector expected = { 0x10, 0x00, 0x00, 0x00, // size (little endian) 0x10, /// entry: int32 @@ -336,7 +336,7 @@ TEST_CASE("BSON") { "entry", std::int64_t{-1} } }; - std::vector expected = + std::vector expected = { 0x10, 0x00, 0x00, 0x00, // size (little endian) 0x10, /// entry: int32 @@ -361,7 +361,7 @@ TEST_CASE("BSON") { "entry", std::uint64_t{0x1234567804030201} } }; - std::vector expected = + std::vector expected = { 0x14, 0x00, 0x00, 0x00, // size (little endian) 0x12, /// entry: int64 @@ -385,7 +385,7 @@ TEST_CASE("BSON") { "entry", std::uint64_t{0x42} } }; - std::vector expected = + std::vector expected = { 0x10, 0x00, 0x00, 0x00, // size (little endian) 0x10, /// entry: int32 @@ -409,7 +409,7 @@ TEST_CASE("BSON") { "entry", json::object() } }; - std::vector expected = + std::vector expected = { 0x11, 0x00, 0x00, 0x00, // size (little endian) 0x03, /// entry: embedded document @@ -437,7 +437,7 @@ TEST_CASE("BSON") { "entry", json::array() } }; - std::vector expected = + std::vector expected = { 0x11, 0x00, 0x00, 0x00, // size (little endian) 0x04, /// entry: embedded document @@ -465,7 +465,7 @@ TEST_CASE("BSON") { "entry", json::array({1, 2, 3, 4, 5, 6, 7, 8}) } }; - std::vector expected = + std::vector expected = { 0x49, 0x00, 0x00, 0x00, // size (little endian) 0x04, /// entry: embedded document @@ -496,13 +496,13 @@ TEST_CASE("BSON") SECTION("non-empty object with binary member") { const size_t N = 10; - const auto s = std::vector(N, 'x'); + const auto s = std::vector(N, 'x'); json j = { { "entry", json::binary_array(s) } }; - std::vector expected = + std::vector expected = { 0x1B, 0x00, 0x00, 0x00, // size (little endian) 0x05, // entry: binary @@ -523,6 +523,36 @@ TEST_CASE("BSON") CHECK(json::from_bson(result, true, false) == j); } + SECTION("non-empty object with binary member with subtype") + { + // an MD5 hash + const std::vector md5hash = {0xd7, 0x7e, 0x27, 0x54, 0xbe, 0x12, 0x37, 0xfe, 0xd6, 0x0c, 0x33, 0x98, 0x30, 0x3b, 0x8d, 0xc4}; + json j = + { + { "entry", json::binary_array(md5hash, 5) } + }; + + std::vector expected = + { + 0x21, 0x00, 0x00, 0x00, // size (little endian) + 0x05, // entry: binary + 'e', 'n', 't', 'r', 'y', '\x00', + + 0x10, 0x00, 0x00, 0x00, // size of binary (little endian) + 0x05, // MD5 binary subtype + 0xd7, 0x7e, 0x27, 0x54, 0xbe, 0x12, 0x37, 0xfe, 0xd6, 0x0c, 0x33, 0x98, 0x30, 0x3b, 0x8d, 0xc4, + + 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) @@ -534,7 +564,7 @@ TEST_CASE("BSON") {"object", {{ "string", "value" }}} }; - std::vector expected = + std::vector expected = { /*size */ 0x4f, 0x00, 0x00, 0x00, /*entry*/ 0x01, 'd', 'o', 'u', 'b', 'l', 'e', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x45, 0x40, @@ -592,7 +622,7 @@ TEST_CASE("BSON input/output_adapters") {"object", {{ "string", "value" }}} }; - std::vector bson_representation = + std::vector bson_representation = { /*size */ 0x4f, 0x00, 0x00, 0x00, /*entry*/ 0x01, 'd', 'o', 'u', 'b', 'l', 'e', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x45, 0x40, @@ -677,7 +707,7 @@ class SaxCountdown return events_left-- > 0; } - bool binary(std::vector&) + bool binary(std::vector&) { return events_left-- > 0; } @@ -721,7 +751,7 @@ TEST_CASE("Incomplete BSON Input") { SECTION("Incomplete BSON Input 1") { - std::vector incomplete_bson = + std::vector incomplete_bson = { 0x0D, 0x00, 0x00, 0x00, // size (little endian) 0x08, // entry: boolean @@ -741,7 +771,7 @@ TEST_CASE("Incomplete BSON Input") SECTION("Incomplete BSON Input 2") { - std::vector incomplete_bson = + std::vector incomplete_bson = { 0x0D, 0x00, 0x00, 0x00, // size (little endian) 0x08, // entry: boolean, unexpected EOF @@ -759,7 +789,7 @@ TEST_CASE("Incomplete BSON Input") SECTION("Incomplete BSON Input 3") { - std::vector incomplete_bson = + std::vector incomplete_bson = { 0x41, 0x00, 0x00, 0x00, // size (little endian) 0x04, /// entry: embedded document @@ -783,7 +813,7 @@ TEST_CASE("Incomplete BSON Input") SECTION("Incomplete BSON Input 4") { - std::vector incomplete_bson = + std::vector incomplete_bson = { 0x0D, 0x00, // size (incomplete), unexpected EOF }; @@ -823,7 +853,7 @@ TEST_CASE("Incomplete BSON Input") TEST_CASE("Unsupported BSON input") { - std::vector bson = + std::vector bson = { 0x0C, 0x00, 0x00, 0x00, // size (little endian) 0xFF, // entry type: Min key (not supported yet) @@ -876,19 +906,19 @@ TEST_CASE("BSON numerical data") CHECK(j.at("entry").is_number_integer()); std::uint64_t iu = *reinterpret_cast(&i); - std::vector expected_bson = + std::vector expected_bson = { 0x14u, 0x00u, 0x00u, 0x00u, // size (little endian) 0x12u, /// entry: int64 'e', 'n', 't', 'r', 'y', '\x00', - static_cast((iu >> (8u * 0u)) & 0xffu), - static_cast((iu >> (8u * 1u)) & 0xffu), - static_cast((iu >> (8u * 2u)) & 0xffu), - static_cast((iu >> (8u * 3u)) & 0xffu), - static_cast((iu >> (8u * 4u)) & 0xffu), - static_cast((iu >> (8u * 5u)) & 0xffu), - static_cast((iu >> (8u * 6u)) & 0xffu), - static_cast((iu >> (8u * 7u)) & 0xffu), + static_cast((iu >> (8u * 0u)) & 0xffu), + static_cast((iu >> (8u * 1u)) & 0xffu), + static_cast((iu >> (8u * 2u)) & 0xffu), + static_cast((iu >> (8u * 3u)) & 0xffu), + static_cast((iu >> (8u * 4u)) & 0xffu), + static_cast((iu >> (8u * 5u)) & 0xffu), + static_cast((iu >> (8u * 6u)) & 0xffu), + static_cast((iu >> (8u * 7u)) & 0xffu), 0x00u // end marker }; @@ -948,15 +978,15 @@ TEST_CASE("BSON numerical data") CHECK(j.at("entry").is_number_integer()); std::uint32_t iu = *reinterpret_cast(&i); - std::vector expected_bson = + std::vector expected_bson = { 0x10u, 0x00u, 0x00u, 0x00u, // size (little endian) 0x10u, /// entry: int32 'e', 'n', 't', 'r', 'y', '\x00', - static_cast((iu >> (8u * 0u)) & 0xffu), - static_cast((iu >> (8u * 1u)) & 0xffu), - static_cast((iu >> (8u * 2u)) & 0xffu), - static_cast((iu >> (8u * 3u)) & 0xffu), + static_cast((iu >> (8u * 0u)) & 0xffu), + static_cast((iu >> (8u * 1u)) & 0xffu), + static_cast((iu >> (8u * 2u)) & 0xffu), + static_cast((iu >> (8u * 3u)) & 0xffu), 0x00u // end marker }; @@ -1001,19 +1031,19 @@ TEST_CASE("BSON numerical data") CHECK(j.at("entry").is_number_integer()); std::uint64_t iu = *reinterpret_cast(&i); - std::vector expected_bson = + std::vector expected_bson = { 0x14u, 0x00u, 0x00u, 0x00u, // size (little endian) 0x12u, /// entry: int64 'e', 'n', 't', 'r', 'y', '\x00', - static_cast((iu >> (8u * 0u)) & 0xffu), - static_cast((iu >> (8u * 1u)) & 0xffu), - static_cast((iu >> (8u * 2u)) & 0xffu), - static_cast((iu >> (8u * 3u)) & 0xffu), - static_cast((iu >> (8u * 4u)) & 0xffu), - static_cast((iu >> (8u * 5u)) & 0xffu), - static_cast((iu >> (8u * 6u)) & 0xffu), - static_cast((iu >> (8u * 7u)) & 0xffu), + static_cast((iu >> (8u * 0u)) & 0xffu), + static_cast((iu >> (8u * 1u)) & 0xffu), + static_cast((iu >> (8u * 2u)) & 0xffu), + static_cast((iu >> (8u * 3u)) & 0xffu), + static_cast((iu >> (8u * 4u)) & 0xffu), + static_cast((iu >> (8u * 5u)) & 0xffu), + static_cast((iu >> (8u * 6u)) & 0xffu), + static_cast((iu >> (8u * 7u)) & 0xffu), 0x00u // end marker }; @@ -1062,15 +1092,15 @@ TEST_CASE("BSON numerical data") }; auto iu = i; - std::vector expected_bson = + std::vector expected_bson = { 0x10u, 0x00u, 0x00u, 0x00u, // size (little endian) 0x10u, /// entry: int32 'e', 'n', 't', 'r', 'y', '\x00', - static_cast((iu >> (8u * 0u)) & 0xffu), - static_cast((iu >> (8u * 1u)) & 0xffu), - static_cast((iu >> (8u * 2u)) & 0xffu), - static_cast((iu >> (8u * 3u)) & 0xffu), + static_cast((iu >> (8u * 0u)) & 0xffu), + static_cast((iu >> (8u * 1u)) & 0xffu), + static_cast((iu >> (8u * 2u)) & 0xffu), + static_cast((iu >> (8u * 3u)) & 0xffu), 0x00u // end marker }; @@ -1117,19 +1147,19 @@ TEST_CASE("BSON numerical data") }; auto iu = i; - std::vector expected_bson = + std::vector expected_bson = { 0x14u, 0x00u, 0x00u, 0x00u, // size (little endian) 0x12u, /// entry: int64 'e', 'n', 't', 'r', 'y', '\x00', - static_cast((iu >> (8u * 0u)) & 0xffu), - static_cast((iu >> (8u * 1u)) & 0xffu), - static_cast((iu >> (8u * 2u)) & 0xffu), - static_cast((iu >> (8u * 3u)) & 0xffu), - static_cast((iu >> (8u * 4u)) & 0xffu), - static_cast((iu >> (8u * 5u)) & 0xffu), - static_cast((iu >> (8u * 6u)) & 0xffu), - static_cast((iu >> (8u * 7u)) & 0xffu), + static_cast((iu >> (8u * 0u)) & 0xffu), + static_cast((iu >> (8u * 1u)) & 0xffu), + static_cast((iu >> (8u * 2u)) & 0xffu), + static_cast((iu >> (8u * 3u)) & 0xffu), + static_cast((iu >> (8u * 4u)) & 0xffu), + static_cast((iu >> (8u * 5u)) & 0xffu), + static_cast((iu >> (8u * 6u)) & 0xffu), + static_cast((iu >> (8u * 7u)) & 0xffu), 0x00u // end marker }; @@ -1167,19 +1197,19 @@ TEST_CASE("BSON numerical data") }; auto iu = i; - std::vector expected_bson = + std::vector expected_bson = { 0x14u, 0x00u, 0x00u, 0x00u, // size (little endian) 0x12u, /// entry: int64 'e', 'n', 't', 'r', 'y', '\x00', - static_cast((iu >> (8u * 0u)) & 0xffu), - static_cast((iu >> (8u * 1u)) & 0xffu), - static_cast((iu >> (8u * 2u)) & 0xffu), - static_cast((iu >> (8u * 3u)) & 0xffu), - static_cast((iu >> (8u * 4u)) & 0xffu), - static_cast((iu >> (8u * 5u)) & 0xffu), - static_cast((iu >> (8u * 6u)) & 0xffu), - static_cast((iu >> (8u * 7u)) & 0xffu), + static_cast((iu >> (8u * 0u)) & 0xffu), + static_cast((iu >> (8u * 1u)) & 0xffu), + static_cast((iu >> (8u * 2u)) & 0xffu), + static_cast((iu >> (8u * 3u)) & 0xffu), + static_cast((iu >> (8u * 4u)) & 0xffu), + static_cast((iu >> (8u * 5u)) & 0xffu), + static_cast((iu >> (8u * 6u)) & 0xffu), + static_cast((iu >> (8u * 7u)) & 0xffu), 0x00u // end marker }; @@ -1208,14 +1238,14 @@ TEST_CASE("BSON roundtrips" * doctest::skip()) CAPTURE(filename) { - INFO_WITH_TEMP(filename + ": std::vector"); + INFO_WITH_TEMP(filename + ": std::vector"); // parse JSON file std::ifstream f_json(filename); json j1 = json::parse(f_json); // parse BSON file std::ifstream f_bson(filename + ".bson", std::ios::binary); - std::vector packed( + std::vector packed( (std::istreambuf_iterator(f_bson)), std::istreambuf_iterator()); json j2; @@ -1248,7 +1278,7 @@ TEST_CASE("BSON roundtrips" * doctest::skip()) // parse BSON file std::ifstream f_bson(filename + ".bson", std::ios::binary); - std::vector packed( + std::vector packed( (std::istreambuf_iterator(f_bson)), std::istreambuf_iterator()); json j2; @@ -1266,13 +1296,13 @@ TEST_CASE("BSON roundtrips" * doctest::skip()) // parse BSON file std::ifstream f_bson(filename + ".bson", std::ios::binary); - std::vector packed( + std::vector packed( (std::istreambuf_iterator(f_bson)), std::istreambuf_iterator()); { - INFO_WITH_TEMP(filename + ": output adapters: std::vector"); - std::vector vec; + INFO_WITH_TEMP(filename + ": output adapters: std::vector"); + std::vector vec; json::to_bson(j1, vec); if (vec != packed)