1c5f01b2fSopenharmony_ci//     __ _____ _____ _____
2c5f01b2fSopenharmony_ci//  __|  |   __|     |   | |  JSON for Modern C++ (supporting code)
3c5f01b2fSopenharmony_ci// |  |  |__   |  |  | | | |  version 3.11.2
4c5f01b2fSopenharmony_ci// |_____|_____|_____|_|___|  https://github.com/nlohmann/json
5c5f01b2fSopenharmony_ci//
6c5f01b2fSopenharmony_ci// SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
7c5f01b2fSopenharmony_ci// SPDX-License-Identifier: MIT
8c5f01b2fSopenharmony_ci
9c5f01b2fSopenharmony_ci#include "doctest_compatibility.h"
10c5f01b2fSopenharmony_ci
11c5f01b2fSopenharmony_ci#include <nlohmann/json.hpp>
12c5f01b2fSopenharmony_ciusing nlohmann::json;
13c5f01b2fSopenharmony_ci
14c5f01b2fSopenharmony_ci#include <fstream>
15c5f01b2fSopenharmony_ci#include <sstream>
16c5f01b2fSopenharmony_ci#include "make_test_data_available.hpp"
17c5f01b2fSopenharmony_ci#include "test_utils.hpp"
18c5f01b2fSopenharmony_ci
19c5f01b2fSopenharmony_ciTEST_CASE("BSON")
20c5f01b2fSopenharmony_ci{
21c5f01b2fSopenharmony_ci    SECTION("individual values not supported")
22c5f01b2fSopenharmony_ci    {
23c5f01b2fSopenharmony_ci        SECTION("null")
24c5f01b2fSopenharmony_ci        {
25c5f01b2fSopenharmony_ci            json j = nullptr;
26c5f01b2fSopenharmony_ci            CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is null", json::type_error&);
27c5f01b2fSopenharmony_ci        }
28c5f01b2fSopenharmony_ci
29c5f01b2fSopenharmony_ci        SECTION("boolean")
30c5f01b2fSopenharmony_ci        {
31c5f01b2fSopenharmony_ci            SECTION("true")
32c5f01b2fSopenharmony_ci            {
33c5f01b2fSopenharmony_ci                json j = true;
34c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is boolean", json::type_error&);
35c5f01b2fSopenharmony_ci            }
36c5f01b2fSopenharmony_ci
37c5f01b2fSopenharmony_ci            SECTION("false")
38c5f01b2fSopenharmony_ci            {
39c5f01b2fSopenharmony_ci                json j = false;
40c5f01b2fSopenharmony_ci                CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is boolean", json::type_error&);
41c5f01b2fSopenharmony_ci            }
42c5f01b2fSopenharmony_ci        }
43c5f01b2fSopenharmony_ci
44c5f01b2fSopenharmony_ci        SECTION("number")
45c5f01b2fSopenharmony_ci        {
46c5f01b2fSopenharmony_ci            json j = 42;
47c5f01b2fSopenharmony_ci            CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is number", json::type_error&);
48c5f01b2fSopenharmony_ci        }
49c5f01b2fSopenharmony_ci
50c5f01b2fSopenharmony_ci        SECTION("float")
51c5f01b2fSopenharmony_ci        {
52c5f01b2fSopenharmony_ci            json j = 4.2;
53c5f01b2fSopenharmony_ci            CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is number", json::type_error&);
54c5f01b2fSopenharmony_ci        }
55c5f01b2fSopenharmony_ci
56c5f01b2fSopenharmony_ci        SECTION("string")
57c5f01b2fSopenharmony_ci        {
58c5f01b2fSopenharmony_ci            json j = "not supported";
59c5f01b2fSopenharmony_ci            CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is string", json::type_error&);
60c5f01b2fSopenharmony_ci        }
61c5f01b2fSopenharmony_ci
62c5f01b2fSopenharmony_ci        SECTION("array")
63c5f01b2fSopenharmony_ci        {
64c5f01b2fSopenharmony_ci            json j = std::vector<int> {1, 2, 3, 4, 5, 6, 7};
65c5f01b2fSopenharmony_ci            CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.type_error.317] to serialize to BSON, top-level type must be object, but is array", json::type_error&);
66c5f01b2fSopenharmony_ci        }
67c5f01b2fSopenharmony_ci    }
68c5f01b2fSopenharmony_ci
69c5f01b2fSopenharmony_ci    SECTION("keys containing code-point U+0000 cannot be serialized to BSON")
70c5f01b2fSopenharmony_ci    {
71c5f01b2fSopenharmony_ci        json j =
72c5f01b2fSopenharmony_ci        {
73c5f01b2fSopenharmony_ci            { std::string("en\0try", 6), true }
74c5f01b2fSopenharmony_ci        };
75c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
76c5f01b2fSopenharmony_ci        CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.out_of_range.409] (/en) BSON key cannot contain code point U+0000 (at byte 2)", json::out_of_range&);
77c5f01b2fSopenharmony_ci#else
78c5f01b2fSopenharmony_ci        CHECK_THROWS_WITH_AS(json::to_bson(j), "[json.exception.out_of_range.409] BSON key cannot contain code point U+0000 (at byte 2)", json::out_of_range&);
79c5f01b2fSopenharmony_ci#endif
80c5f01b2fSopenharmony_ci    }
81c5f01b2fSopenharmony_ci
82c5f01b2fSopenharmony_ci    SECTION("string length must be at least 1")
83c5f01b2fSopenharmony_ci    {
84c5f01b2fSopenharmony_ci        // from https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=11175
85c5f01b2fSopenharmony_ci        std::vector<std::uint8_t> v =
86c5f01b2fSopenharmony_ci        {
87c5f01b2fSopenharmony_ci            0x20, 0x20, 0x20, 0x20,
88c5f01b2fSopenharmony_ci            0x02,
89c5f01b2fSopenharmony_ci            0x00,
90c5f01b2fSopenharmony_ci            0x00, 0x00, 0x00, 0x80
91c5f01b2fSopenharmony_ci        };
92c5f01b2fSopenharmony_ci        json _;
93c5f01b2fSopenharmony_ci        CHECK_THROWS_WITH_AS(_ = json::from_bson(v), "[json.exception.parse_error.112] parse error at byte 10: syntax error while parsing BSON string: string length must be at least 1, is -2147483648", json::parse_error&);
94c5f01b2fSopenharmony_ci    }
95c5f01b2fSopenharmony_ci
96c5f01b2fSopenharmony_ci    SECTION("objects")
97c5f01b2fSopenharmony_ci    {
98c5f01b2fSopenharmony_ci        SECTION("empty object")
99c5f01b2fSopenharmony_ci        {
100c5f01b2fSopenharmony_ci            json j = json::object();
101c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> expected =
102c5f01b2fSopenharmony_ci            {
103c5f01b2fSopenharmony_ci                0x05, 0x00, 0x00, 0x00, // size (little endian)
104c5f01b2fSopenharmony_ci                // no entries
105c5f01b2fSopenharmony_ci                0x00 // end marker
106c5f01b2fSopenharmony_ci            };
107c5f01b2fSopenharmony_ci
108c5f01b2fSopenharmony_ci            const auto result = json::to_bson(j);
109c5f01b2fSopenharmony_ci            CHECK(result == expected);
110c5f01b2fSopenharmony_ci
111c5f01b2fSopenharmony_ci            // roundtrip
112c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result) == j);
113c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result, true, false) == j);
114c5f01b2fSopenharmony_ci        }
115c5f01b2fSopenharmony_ci
116c5f01b2fSopenharmony_ci        SECTION("non-empty object with bool")
117c5f01b2fSopenharmony_ci        {
118c5f01b2fSopenharmony_ci            json j =
119c5f01b2fSopenharmony_ci            {
120c5f01b2fSopenharmony_ci                { "entry", true }
121c5f01b2fSopenharmony_ci            };
122c5f01b2fSopenharmony_ci
123c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> expected =
124c5f01b2fSopenharmony_ci            {
125c5f01b2fSopenharmony_ci                0x0D, 0x00, 0x00, 0x00, // size (little endian)
126c5f01b2fSopenharmony_ci                0x08,               // entry: boolean
127c5f01b2fSopenharmony_ci                'e', 'n', 't', 'r', 'y', '\x00',
128c5f01b2fSopenharmony_ci                0x01,           // value = true
129c5f01b2fSopenharmony_ci                0x00                    // end marker
130c5f01b2fSopenharmony_ci            };
131c5f01b2fSopenharmony_ci
132c5f01b2fSopenharmony_ci            const auto result = json::to_bson(j);
133c5f01b2fSopenharmony_ci            CHECK(result == expected);
134c5f01b2fSopenharmony_ci
135c5f01b2fSopenharmony_ci            // roundtrip
136c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result) == j);
137c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result, true, false) == j);
138c5f01b2fSopenharmony_ci        }
139c5f01b2fSopenharmony_ci
140c5f01b2fSopenharmony_ci        SECTION("non-empty object with bool")
141c5f01b2fSopenharmony_ci        {
142c5f01b2fSopenharmony_ci            json j =
143c5f01b2fSopenharmony_ci            {
144c5f01b2fSopenharmony_ci                { "entry", false }
145c5f01b2fSopenharmony_ci            };
146c5f01b2fSopenharmony_ci
147c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> expected =
148c5f01b2fSopenharmony_ci            {
149c5f01b2fSopenharmony_ci                0x0D, 0x00, 0x00, 0x00, // size (little endian)
150c5f01b2fSopenharmony_ci                0x08,               // entry: boolean
151c5f01b2fSopenharmony_ci                'e', 'n', 't', 'r', 'y', '\x00',
152c5f01b2fSopenharmony_ci                0x00,           // value = false
153c5f01b2fSopenharmony_ci                0x00                    // end marker
154c5f01b2fSopenharmony_ci            };
155c5f01b2fSopenharmony_ci
156c5f01b2fSopenharmony_ci            const auto result = json::to_bson(j);
157c5f01b2fSopenharmony_ci            CHECK(result == expected);
158c5f01b2fSopenharmony_ci
159c5f01b2fSopenharmony_ci            // roundtrip
160c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result) == j);
161c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result, true, false) == j);
162c5f01b2fSopenharmony_ci        }
163c5f01b2fSopenharmony_ci
164c5f01b2fSopenharmony_ci        SECTION("non-empty object with double")
165c5f01b2fSopenharmony_ci        {
166c5f01b2fSopenharmony_ci            json j =
167c5f01b2fSopenharmony_ci            {
168c5f01b2fSopenharmony_ci                { "entry", 4.2 }
169c5f01b2fSopenharmony_ci            };
170c5f01b2fSopenharmony_ci
171c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> expected =
172c5f01b2fSopenharmony_ci            {
173c5f01b2fSopenharmony_ci                0x14, 0x00, 0x00, 0x00, // size (little endian)
174c5f01b2fSopenharmony_ci                0x01, /// entry: double
175c5f01b2fSopenharmony_ci                'e', 'n', 't', 'r', 'y', '\x00',
176c5f01b2fSopenharmony_ci                0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40,
177c5f01b2fSopenharmony_ci                0x00 // end marker
178c5f01b2fSopenharmony_ci            };
179c5f01b2fSopenharmony_ci
180c5f01b2fSopenharmony_ci            const auto result = json::to_bson(j);
181c5f01b2fSopenharmony_ci            CHECK(result == expected);
182c5f01b2fSopenharmony_ci
183c5f01b2fSopenharmony_ci            // roundtrip
184c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result) == j);
185c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result, true, false) == j);
186c5f01b2fSopenharmony_ci        }
187c5f01b2fSopenharmony_ci
188c5f01b2fSopenharmony_ci        SECTION("non-empty object with string")
189c5f01b2fSopenharmony_ci        {
190c5f01b2fSopenharmony_ci            json j =
191c5f01b2fSopenharmony_ci            {
192c5f01b2fSopenharmony_ci                { "entry", "bsonstr" }
193c5f01b2fSopenharmony_ci            };
194c5f01b2fSopenharmony_ci
195c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> expected =
196c5f01b2fSopenharmony_ci            {
197c5f01b2fSopenharmony_ci                0x18, 0x00, 0x00, 0x00, // size (little endian)
198c5f01b2fSopenharmony_ci                0x02, /// entry: string (UTF-8)
199c5f01b2fSopenharmony_ci                'e', 'n', 't', 'r', 'y', '\x00',
200c5f01b2fSopenharmony_ci                0x08, 0x00, 0x00, 0x00, 'b', 's', 'o', 'n', 's', 't', 'r', '\x00',
201c5f01b2fSopenharmony_ci                0x00 // end marker
202c5f01b2fSopenharmony_ci            };
203c5f01b2fSopenharmony_ci
204c5f01b2fSopenharmony_ci            const auto result = json::to_bson(j);
205c5f01b2fSopenharmony_ci            CHECK(result == expected);
206c5f01b2fSopenharmony_ci
207c5f01b2fSopenharmony_ci            // roundtrip
208c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result) == j);
209c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result, true, false) == j);
210c5f01b2fSopenharmony_ci        }
211c5f01b2fSopenharmony_ci
212c5f01b2fSopenharmony_ci        SECTION("non-empty object with null member")
213c5f01b2fSopenharmony_ci        {
214c5f01b2fSopenharmony_ci            json j =
215c5f01b2fSopenharmony_ci            {
216c5f01b2fSopenharmony_ci                { "entry", nullptr }
217c5f01b2fSopenharmony_ci            };
218c5f01b2fSopenharmony_ci
219c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> expected =
220c5f01b2fSopenharmony_ci            {
221c5f01b2fSopenharmony_ci                0x0C, 0x00, 0x00, 0x00, // size (little endian)
222c5f01b2fSopenharmony_ci                0x0A, /// entry: null
223c5f01b2fSopenharmony_ci                'e', 'n', 't', 'r', 'y', '\x00',
224c5f01b2fSopenharmony_ci                0x00 // end marker
225c5f01b2fSopenharmony_ci            };
226c5f01b2fSopenharmony_ci
227c5f01b2fSopenharmony_ci            const auto result = json::to_bson(j);
228c5f01b2fSopenharmony_ci            CHECK(result == expected);
229c5f01b2fSopenharmony_ci
230c5f01b2fSopenharmony_ci            // roundtrip
231c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result) == j);
232c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result, true, false) == j);
233c5f01b2fSopenharmony_ci        }
234c5f01b2fSopenharmony_ci
235c5f01b2fSopenharmony_ci        SECTION("non-empty object with integer (32-bit) member")
236c5f01b2fSopenharmony_ci        {
237c5f01b2fSopenharmony_ci            json j =
238c5f01b2fSopenharmony_ci            {
239c5f01b2fSopenharmony_ci                { "entry", std::int32_t{0x12345678} }
240c5f01b2fSopenharmony_ci            };
241c5f01b2fSopenharmony_ci
242c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> expected =
243c5f01b2fSopenharmony_ci            {
244c5f01b2fSopenharmony_ci                0x10, 0x00, 0x00, 0x00, // size (little endian)
245c5f01b2fSopenharmony_ci                0x10, /// entry: int32
246c5f01b2fSopenharmony_ci                'e', 'n', 't', 'r', 'y', '\x00',
247c5f01b2fSopenharmony_ci                0x78, 0x56, 0x34, 0x12,
248c5f01b2fSopenharmony_ci                0x00 // end marker
249c5f01b2fSopenharmony_ci            };
250c5f01b2fSopenharmony_ci
251c5f01b2fSopenharmony_ci            const auto result = json::to_bson(j);
252c5f01b2fSopenharmony_ci            CHECK(result == expected);
253c5f01b2fSopenharmony_ci
254c5f01b2fSopenharmony_ci            // roundtrip
255c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result) == j);
256c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result, true, false) == j);
257c5f01b2fSopenharmony_ci        }
258c5f01b2fSopenharmony_ci
259c5f01b2fSopenharmony_ci        SECTION("non-empty object with integer (64-bit) member")
260c5f01b2fSopenharmony_ci        {
261c5f01b2fSopenharmony_ci            json j =
262c5f01b2fSopenharmony_ci            {
263c5f01b2fSopenharmony_ci                { "entry", std::int64_t{0x1234567804030201} }
264c5f01b2fSopenharmony_ci            };
265c5f01b2fSopenharmony_ci
266c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> expected =
267c5f01b2fSopenharmony_ci            {
268c5f01b2fSopenharmony_ci                0x14, 0x00, 0x00, 0x00, // size (little endian)
269c5f01b2fSopenharmony_ci                0x12, /// entry: int64
270c5f01b2fSopenharmony_ci                'e', 'n', 't', 'r', 'y', '\x00',
271c5f01b2fSopenharmony_ci                0x01, 0x02, 0x03, 0x04, 0x78, 0x56, 0x34, 0x12,
272c5f01b2fSopenharmony_ci                0x00 // end marker
273c5f01b2fSopenharmony_ci            };
274c5f01b2fSopenharmony_ci
275c5f01b2fSopenharmony_ci            const auto result = json::to_bson(j);
276c5f01b2fSopenharmony_ci            CHECK(result == expected);
277c5f01b2fSopenharmony_ci
278c5f01b2fSopenharmony_ci            // roundtrip
279c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result) == j);
280c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result, true, false) == j);
281c5f01b2fSopenharmony_ci        }
282c5f01b2fSopenharmony_ci
283c5f01b2fSopenharmony_ci        SECTION("non-empty object with negative integer (32-bit) member")
284c5f01b2fSopenharmony_ci        {
285c5f01b2fSopenharmony_ci            json j =
286c5f01b2fSopenharmony_ci            {
287c5f01b2fSopenharmony_ci                { "entry", std::int32_t{-1} }
288c5f01b2fSopenharmony_ci            };
289c5f01b2fSopenharmony_ci
290c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> expected =
291c5f01b2fSopenharmony_ci            {
292c5f01b2fSopenharmony_ci                0x10, 0x00, 0x00, 0x00, // size (little endian)
293c5f01b2fSopenharmony_ci                0x10, /// entry: int32
294c5f01b2fSopenharmony_ci                'e', 'n', 't', 'r', 'y', '\x00',
295c5f01b2fSopenharmony_ci                0xFF, 0xFF, 0xFF, 0xFF,
296c5f01b2fSopenharmony_ci                0x00 // end marker
297c5f01b2fSopenharmony_ci            };
298c5f01b2fSopenharmony_ci
299c5f01b2fSopenharmony_ci            const auto result = json::to_bson(j);
300c5f01b2fSopenharmony_ci            CHECK(result == expected);
301c5f01b2fSopenharmony_ci
302c5f01b2fSopenharmony_ci            // roundtrip
303c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result) == j);
304c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result, true, false) == j);
305c5f01b2fSopenharmony_ci        }
306c5f01b2fSopenharmony_ci
307c5f01b2fSopenharmony_ci        SECTION("non-empty object with negative integer (64-bit) member")
308c5f01b2fSopenharmony_ci        {
309c5f01b2fSopenharmony_ci            json j =
310c5f01b2fSopenharmony_ci            {
311c5f01b2fSopenharmony_ci                { "entry", std::int64_t{-1} }
312c5f01b2fSopenharmony_ci            };
313c5f01b2fSopenharmony_ci
314c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> expected =
315c5f01b2fSopenharmony_ci            {
316c5f01b2fSopenharmony_ci                0x10, 0x00, 0x00, 0x00, // size (little endian)
317c5f01b2fSopenharmony_ci                0x10, /// entry: int32
318c5f01b2fSopenharmony_ci                'e', 'n', 't', 'r', 'y', '\x00',
319c5f01b2fSopenharmony_ci                0xFF, 0xFF, 0xFF, 0xFF,
320c5f01b2fSopenharmony_ci                0x00 // end marker
321c5f01b2fSopenharmony_ci            };
322c5f01b2fSopenharmony_ci
323c5f01b2fSopenharmony_ci            const auto result = json::to_bson(j);
324c5f01b2fSopenharmony_ci            CHECK(result == expected);
325c5f01b2fSopenharmony_ci
326c5f01b2fSopenharmony_ci            // roundtrip
327c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result) == j);
328c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result, true, false) == j);
329c5f01b2fSopenharmony_ci        }
330c5f01b2fSopenharmony_ci
331c5f01b2fSopenharmony_ci        SECTION("non-empty object with unsigned integer (64-bit) member")
332c5f01b2fSopenharmony_ci        {
333c5f01b2fSopenharmony_ci            // directly encoding uint64 is not supported in bson (only for timestamp values)
334c5f01b2fSopenharmony_ci            json j =
335c5f01b2fSopenharmony_ci            {
336c5f01b2fSopenharmony_ci                { "entry", std::uint64_t{0x1234567804030201} }
337c5f01b2fSopenharmony_ci            };
338c5f01b2fSopenharmony_ci
339c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> expected =
340c5f01b2fSopenharmony_ci            {
341c5f01b2fSopenharmony_ci                0x14, 0x00, 0x00, 0x00, // size (little endian)
342c5f01b2fSopenharmony_ci                0x12, /// entry: int64
343c5f01b2fSopenharmony_ci                'e', 'n', 't', 'r', 'y', '\x00',
344c5f01b2fSopenharmony_ci                0x01, 0x02, 0x03, 0x04, 0x78, 0x56, 0x34, 0x12,
345c5f01b2fSopenharmony_ci                0x00 // end marker
346c5f01b2fSopenharmony_ci            };
347c5f01b2fSopenharmony_ci
348c5f01b2fSopenharmony_ci            const auto result = json::to_bson(j);
349c5f01b2fSopenharmony_ci            CHECK(result == expected);
350c5f01b2fSopenharmony_ci
351c5f01b2fSopenharmony_ci            // roundtrip
352c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result) == j);
353c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result, true, false) == j);
354c5f01b2fSopenharmony_ci        }
355c5f01b2fSopenharmony_ci
356c5f01b2fSopenharmony_ci        SECTION("non-empty object with small unsigned integer member")
357c5f01b2fSopenharmony_ci        {
358c5f01b2fSopenharmony_ci            json j =
359c5f01b2fSopenharmony_ci            {
360c5f01b2fSopenharmony_ci                { "entry", std::uint64_t{0x42} }
361c5f01b2fSopenharmony_ci            };
362c5f01b2fSopenharmony_ci
363c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> expected =
364c5f01b2fSopenharmony_ci            {
365c5f01b2fSopenharmony_ci                0x10, 0x00, 0x00, 0x00, // size (little endian)
366c5f01b2fSopenharmony_ci                0x10, /// entry: int32
367c5f01b2fSopenharmony_ci                'e', 'n', 't', 'r', 'y', '\x00',
368c5f01b2fSopenharmony_ci                0x42, 0x00, 0x00, 0x00,
369c5f01b2fSopenharmony_ci                0x00 // end marker
370c5f01b2fSopenharmony_ci            };
371c5f01b2fSopenharmony_ci
372c5f01b2fSopenharmony_ci            const auto result = json::to_bson(j);
373c5f01b2fSopenharmony_ci            CHECK(result == expected);
374c5f01b2fSopenharmony_ci
375c5f01b2fSopenharmony_ci            // roundtrip
376c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result) == j);
377c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result, true, false) == j);
378c5f01b2fSopenharmony_ci        }
379c5f01b2fSopenharmony_ci
380c5f01b2fSopenharmony_ci        SECTION("non-empty object with object member")
381c5f01b2fSopenharmony_ci        {
382c5f01b2fSopenharmony_ci            json j =
383c5f01b2fSopenharmony_ci            {
384c5f01b2fSopenharmony_ci                { "entry", json::object() }
385c5f01b2fSopenharmony_ci            };
386c5f01b2fSopenharmony_ci
387c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> expected =
388c5f01b2fSopenharmony_ci            {
389c5f01b2fSopenharmony_ci                0x11, 0x00, 0x00, 0x00, // size (little endian)
390c5f01b2fSopenharmony_ci                0x03, /// entry: embedded document
391c5f01b2fSopenharmony_ci                'e', 'n', 't', 'r', 'y', '\x00',
392c5f01b2fSopenharmony_ci
393c5f01b2fSopenharmony_ci                0x05, 0x00, 0x00, 0x00, // size (little endian)
394c5f01b2fSopenharmony_ci                // no entries
395c5f01b2fSopenharmony_ci                0x00, // end marker (embedded document)
396c5f01b2fSopenharmony_ci
397c5f01b2fSopenharmony_ci                0x00 // end marker
398c5f01b2fSopenharmony_ci            };
399c5f01b2fSopenharmony_ci
400c5f01b2fSopenharmony_ci            const auto result = json::to_bson(j);
401c5f01b2fSopenharmony_ci            CHECK(result == expected);
402c5f01b2fSopenharmony_ci
403c5f01b2fSopenharmony_ci            // roundtrip
404c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result) == j);
405c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result, true, false) == j);
406c5f01b2fSopenharmony_ci        }
407c5f01b2fSopenharmony_ci
408c5f01b2fSopenharmony_ci        SECTION("non-empty object with array member")
409c5f01b2fSopenharmony_ci        {
410c5f01b2fSopenharmony_ci            json j =
411c5f01b2fSopenharmony_ci            {
412c5f01b2fSopenharmony_ci                { "entry", json::array() }
413c5f01b2fSopenharmony_ci            };
414c5f01b2fSopenharmony_ci
415c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> expected =
416c5f01b2fSopenharmony_ci            {
417c5f01b2fSopenharmony_ci                0x11, 0x00, 0x00, 0x00, // size (little endian)
418c5f01b2fSopenharmony_ci                0x04, /// entry: embedded document
419c5f01b2fSopenharmony_ci                'e', 'n', 't', 'r', 'y', '\x00',
420c5f01b2fSopenharmony_ci
421c5f01b2fSopenharmony_ci                0x05, 0x00, 0x00, 0x00, // size (little endian)
422c5f01b2fSopenharmony_ci                // no entries
423c5f01b2fSopenharmony_ci                0x00, // end marker (embedded document)
424c5f01b2fSopenharmony_ci
425c5f01b2fSopenharmony_ci                0x00 // end marker
426c5f01b2fSopenharmony_ci            };
427c5f01b2fSopenharmony_ci
428c5f01b2fSopenharmony_ci            const auto result = json::to_bson(j);
429c5f01b2fSopenharmony_ci            CHECK(result == expected);
430c5f01b2fSopenharmony_ci
431c5f01b2fSopenharmony_ci            // roundtrip
432c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result) == j);
433c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result, true, false) == j);
434c5f01b2fSopenharmony_ci        }
435c5f01b2fSopenharmony_ci
436c5f01b2fSopenharmony_ci        SECTION("non-empty object with non-empty array member")
437c5f01b2fSopenharmony_ci        {
438c5f01b2fSopenharmony_ci            json j =
439c5f01b2fSopenharmony_ci            {
440c5f01b2fSopenharmony_ci                { "entry", json::array({1, 2, 3, 4, 5, 6, 7, 8}) }
441c5f01b2fSopenharmony_ci            };
442c5f01b2fSopenharmony_ci
443c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> expected =
444c5f01b2fSopenharmony_ci            {
445c5f01b2fSopenharmony_ci                0x49, 0x00, 0x00, 0x00, // size (little endian)
446c5f01b2fSopenharmony_ci                0x04, /// entry: embedded document
447c5f01b2fSopenharmony_ci                'e', 'n', 't', 'r', 'y', '\x00',
448c5f01b2fSopenharmony_ci
449c5f01b2fSopenharmony_ci                0x3D, 0x00, 0x00, 0x00, // size (little endian)
450c5f01b2fSopenharmony_ci                0x10, '0', 0x00, 0x01, 0x00, 0x00, 0x00,
451c5f01b2fSopenharmony_ci                0x10, '1', 0x00, 0x02, 0x00, 0x00, 0x00,
452c5f01b2fSopenharmony_ci                0x10, '2', 0x00, 0x03, 0x00, 0x00, 0x00,
453c5f01b2fSopenharmony_ci                0x10, '3', 0x00, 0x04, 0x00, 0x00, 0x00,
454c5f01b2fSopenharmony_ci                0x10, '4', 0x00, 0x05, 0x00, 0x00, 0x00,
455c5f01b2fSopenharmony_ci                0x10, '5', 0x00, 0x06, 0x00, 0x00, 0x00,
456c5f01b2fSopenharmony_ci                0x10, '6', 0x00, 0x07, 0x00, 0x00, 0x00,
457c5f01b2fSopenharmony_ci                0x10, '7', 0x00, 0x08, 0x00, 0x00, 0x00,
458c5f01b2fSopenharmony_ci                0x00, // end marker (embedded document)
459c5f01b2fSopenharmony_ci
460c5f01b2fSopenharmony_ci                0x00 // end marker
461c5f01b2fSopenharmony_ci            };
462c5f01b2fSopenharmony_ci
463c5f01b2fSopenharmony_ci            const auto result = json::to_bson(j);
464c5f01b2fSopenharmony_ci            CHECK(result == expected);
465c5f01b2fSopenharmony_ci
466c5f01b2fSopenharmony_ci            // roundtrip
467c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result) == j);
468c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result, true, false) == j);
469c5f01b2fSopenharmony_ci        }
470c5f01b2fSopenharmony_ci
471c5f01b2fSopenharmony_ci        SECTION("non-empty object with binary member")
472c5f01b2fSopenharmony_ci        {
473c5f01b2fSopenharmony_ci            const size_t N = 10;
474c5f01b2fSopenharmony_ci            const auto s = std::vector<std::uint8_t>(N, 'x');
475c5f01b2fSopenharmony_ci            json j =
476c5f01b2fSopenharmony_ci            {
477c5f01b2fSopenharmony_ci                { "entry", json::binary(s, 0) }
478c5f01b2fSopenharmony_ci            };
479c5f01b2fSopenharmony_ci
480c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> expected =
481c5f01b2fSopenharmony_ci            {
482c5f01b2fSopenharmony_ci                0x1B, 0x00, 0x00, 0x00, // size (little endian)
483c5f01b2fSopenharmony_ci                0x05, // entry: binary
484c5f01b2fSopenharmony_ci                'e', 'n', 't', 'r', 'y', '\x00',
485c5f01b2fSopenharmony_ci
486c5f01b2fSopenharmony_ci                0x0A, 0x00, 0x00, 0x00, // size of binary (little endian)
487c5f01b2fSopenharmony_ci                0x00, // Generic binary subtype
488c5f01b2fSopenharmony_ci                0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78,
489c5f01b2fSopenharmony_ci
490c5f01b2fSopenharmony_ci                0x00 // end marker
491c5f01b2fSopenharmony_ci            };
492c5f01b2fSopenharmony_ci
493c5f01b2fSopenharmony_ci            const auto result = json::to_bson(j);
494c5f01b2fSopenharmony_ci            CHECK(result == expected);
495c5f01b2fSopenharmony_ci
496c5f01b2fSopenharmony_ci            // roundtrip
497c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result) == j);
498c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result, true, false) == j);
499c5f01b2fSopenharmony_ci        }
500c5f01b2fSopenharmony_ci
501c5f01b2fSopenharmony_ci        SECTION("non-empty object with binary member with subtype")
502c5f01b2fSopenharmony_ci        {
503c5f01b2fSopenharmony_ci            // an MD5 hash
504c5f01b2fSopenharmony_ci            const std::vector<std::uint8_t> md5hash = {0xd7, 0x7e, 0x27, 0x54, 0xbe, 0x12, 0x37, 0xfe, 0xd6, 0x0c, 0x33, 0x98, 0x30, 0x3b, 0x8d, 0xc4};
505c5f01b2fSopenharmony_ci            json j =
506c5f01b2fSopenharmony_ci            {
507c5f01b2fSopenharmony_ci                { "entry", json::binary(md5hash, 5) }
508c5f01b2fSopenharmony_ci            };
509c5f01b2fSopenharmony_ci
510c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> expected =
511c5f01b2fSopenharmony_ci            {
512c5f01b2fSopenharmony_ci                0x21, 0x00, 0x00, 0x00, // size (little endian)
513c5f01b2fSopenharmony_ci                0x05, // entry: binary
514c5f01b2fSopenharmony_ci                'e', 'n', 't', 'r', 'y', '\x00',
515c5f01b2fSopenharmony_ci
516c5f01b2fSopenharmony_ci                0x10, 0x00, 0x00, 0x00, // size of binary (little endian)
517c5f01b2fSopenharmony_ci                0x05, // MD5 binary subtype
518c5f01b2fSopenharmony_ci                0xd7, 0x7e, 0x27, 0x54, 0xbe, 0x12, 0x37, 0xfe, 0xd6, 0x0c, 0x33, 0x98, 0x30, 0x3b, 0x8d, 0xc4,
519c5f01b2fSopenharmony_ci
520c5f01b2fSopenharmony_ci                0x00 // end marker
521c5f01b2fSopenharmony_ci            };
522c5f01b2fSopenharmony_ci
523c5f01b2fSopenharmony_ci            const auto result = json::to_bson(j);
524c5f01b2fSopenharmony_ci            CHECK(result == expected);
525c5f01b2fSopenharmony_ci
526c5f01b2fSopenharmony_ci            // roundtrip
527c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result) == j);
528c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result, true, false) == j);
529c5f01b2fSopenharmony_ci        }
530c5f01b2fSopenharmony_ci
531c5f01b2fSopenharmony_ci        SECTION("Some more complex document")
532c5f01b2fSopenharmony_ci        {
533c5f01b2fSopenharmony_ci            // directly encoding uint64 is not supported in bson (only for timestamp values)
534c5f01b2fSopenharmony_ci            json j =
535c5f01b2fSopenharmony_ci            {
536c5f01b2fSopenharmony_ci                {"double", 42.5},
537c5f01b2fSopenharmony_ci                {"entry", 4.2},
538c5f01b2fSopenharmony_ci                {"number", 12345},
539c5f01b2fSopenharmony_ci                {"object", {{ "string", "value" }}}
540c5f01b2fSopenharmony_ci            };
541c5f01b2fSopenharmony_ci
542c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> expected =
543c5f01b2fSopenharmony_ci            {
544c5f01b2fSopenharmony_ci                /*size */ 0x4f, 0x00, 0x00, 0x00,
545c5f01b2fSopenharmony_ci                /*entry*/ 0x01, 'd',  'o',  'u',  'b',  'l',  'e',  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x45, 0x40,
546c5f01b2fSopenharmony_ci                /*entry*/ 0x01, 'e',  'n',  't',  'r',  'y',  0x00, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40,
547c5f01b2fSopenharmony_ci                /*entry*/ 0x10, 'n',  'u',  'm',  'b',  'e',  'r',  0x00, 0x39, 0x30, 0x00, 0x00,
548c5f01b2fSopenharmony_ci                /*entry*/ 0x03, 'o',  'b',  'j',  'e',  'c',  't',  0x00,
549c5f01b2fSopenharmony_ci                /*entry: obj-size */ 0x17, 0x00, 0x00, 0x00,
550c5f01b2fSopenharmony_ci                /*entry: obj-entry*/0x02, 's',  't',  'r',  'i',  'n',  'g', 0x00, 0x06, 0x00, 0x00, 0x00, 'v', 'a', 'l', 'u', 'e', 0,
551c5f01b2fSopenharmony_ci                /*entry: obj-term.*/0x00,
552c5f01b2fSopenharmony_ci                /*obj-term*/ 0x00
553c5f01b2fSopenharmony_ci            };
554c5f01b2fSopenharmony_ci
555c5f01b2fSopenharmony_ci            const auto result = json::to_bson(j);
556c5f01b2fSopenharmony_ci            CHECK(result == expected);
557c5f01b2fSopenharmony_ci
558c5f01b2fSopenharmony_ci            // roundtrip
559c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result) == j);
560c5f01b2fSopenharmony_ci            CHECK(json::from_bson(result, true, false) == j);
561c5f01b2fSopenharmony_ci        }
562c5f01b2fSopenharmony_ci    }
563c5f01b2fSopenharmony_ci
564c5f01b2fSopenharmony_ci    SECTION("Examples from http://bsonspec.org/faq.html")
565c5f01b2fSopenharmony_ci    {
566c5f01b2fSopenharmony_ci        SECTION("Example 1")
567c5f01b2fSopenharmony_ci        {
568c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> input = {0x16, 0x00, 0x00, 0x00, 0x02, 'h', 'e', 'l', 'l', 'o', 0x00, 0x06, 0x00, 0x00, 0x00, 'w', 'o', 'r', 'l', 'd', 0x00, 0x00};
569c5f01b2fSopenharmony_ci            json parsed = json::from_bson(input);
570c5f01b2fSopenharmony_ci            json expected = {{"hello", "world"}};
571c5f01b2fSopenharmony_ci            CHECK(parsed == expected);
572c5f01b2fSopenharmony_ci            auto dumped = json::to_bson(parsed);
573c5f01b2fSopenharmony_ci            CHECK(dumped == input);
574c5f01b2fSopenharmony_ci            CHECK(json::from_bson(dumped) == expected);
575c5f01b2fSopenharmony_ci        }
576c5f01b2fSopenharmony_ci
577c5f01b2fSopenharmony_ci        SECTION("Example 2")
578c5f01b2fSopenharmony_ci        {
579c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> input = {0x31, 0x00, 0x00, 0x00, 0x04, 'B', 'S', 'O', 'N', 0x00, 0x26, 0x00, 0x00, 0x00, 0x02, 0x30, 0x00, 0x08, 0x00, 0x00, 0x00, 'a', 'w', 'e', 's', 'o', 'm', 'e', 0x00, 0x01, 0x31, 0x00, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33, 0x14, 0x40, 0x10, 0x32, 0x00, 0xc2, 0x07, 0x00, 0x00, 0x00, 0x00};
580c5f01b2fSopenharmony_ci            json parsed = json::from_bson(input);
581c5f01b2fSopenharmony_ci            json expected = {{"BSON", {"awesome", 5.05, 1986}}};
582c5f01b2fSopenharmony_ci            CHECK(parsed == expected);
583c5f01b2fSopenharmony_ci            auto dumped = json::to_bson(parsed);
584c5f01b2fSopenharmony_ci            CHECK(dumped == input);
585c5f01b2fSopenharmony_ci            CHECK(json::from_bson(dumped) == expected);
586c5f01b2fSopenharmony_ci        }
587c5f01b2fSopenharmony_ci    }
588c5f01b2fSopenharmony_ci}
589c5f01b2fSopenharmony_ci
590c5f01b2fSopenharmony_ciTEST_CASE("BSON input/output_adapters")
591c5f01b2fSopenharmony_ci{
592c5f01b2fSopenharmony_ci    json json_representation =
593c5f01b2fSopenharmony_ci    {
594c5f01b2fSopenharmony_ci        {"double", 42.5},
595c5f01b2fSopenharmony_ci        {"entry", 4.2},
596c5f01b2fSopenharmony_ci        {"number", 12345},
597c5f01b2fSopenharmony_ci        {"object", {{ "string", "value" }}}
598c5f01b2fSopenharmony_ci    };
599c5f01b2fSopenharmony_ci
600c5f01b2fSopenharmony_ci    std::vector<std::uint8_t> bson_representation =
601c5f01b2fSopenharmony_ci    {
602c5f01b2fSopenharmony_ci        /*size */ 0x4f, 0x00, 0x00, 0x00,
603c5f01b2fSopenharmony_ci        /*entry*/ 0x01, 'd',  'o',  'u',  'b',  'l',  'e',  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x45, 0x40,
604c5f01b2fSopenharmony_ci        /*entry*/ 0x01, 'e',  'n',  't',  'r',  'y',  0x00, 0xcd, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0x10, 0x40,
605c5f01b2fSopenharmony_ci        /*entry*/ 0x10, 'n',  'u',  'm',  'b',  'e',  'r',  0x00, 0x39, 0x30, 0x00, 0x00,
606c5f01b2fSopenharmony_ci        /*entry*/ 0x03, 'o',  'b',  'j',  'e',  'c',  't',  0x00,
607c5f01b2fSopenharmony_ci        /*entry: obj-size */ 0x17, 0x00, 0x00, 0x00,
608c5f01b2fSopenharmony_ci        /*entry: obj-entry*/0x02, 's',  't',  'r',  'i',  'n',  'g', 0x00, 0x06, 0x00, 0x00, 0x00, 'v', 'a', 'l', 'u', 'e', 0,
609c5f01b2fSopenharmony_ci        /*entry: obj-term.*/0x00,
610c5f01b2fSopenharmony_ci        /*obj-term*/ 0x00
611c5f01b2fSopenharmony_ci    };
612c5f01b2fSopenharmony_ci
613c5f01b2fSopenharmony_ci    json j2;
614c5f01b2fSopenharmony_ci    CHECK_NOTHROW(j2 = json::from_bson(bson_representation));
615c5f01b2fSopenharmony_ci
616c5f01b2fSopenharmony_ci    // compare parsed JSON values
617c5f01b2fSopenharmony_ci    CHECK(json_representation == j2);
618c5f01b2fSopenharmony_ci
619c5f01b2fSopenharmony_ci    SECTION("roundtrips")
620c5f01b2fSopenharmony_ci    {
621c5f01b2fSopenharmony_ci        SECTION("std::ostringstream")
622c5f01b2fSopenharmony_ci        {
623c5f01b2fSopenharmony_ci            std::basic_ostringstream<std::uint8_t> ss;
624c5f01b2fSopenharmony_ci            json::to_bson(json_representation, ss);
625c5f01b2fSopenharmony_ci            json j3 = json::from_bson(ss.str());
626c5f01b2fSopenharmony_ci            CHECK(json_representation == j3);
627c5f01b2fSopenharmony_ci        }
628c5f01b2fSopenharmony_ci
629c5f01b2fSopenharmony_ci        SECTION("std::string")
630c5f01b2fSopenharmony_ci        {
631c5f01b2fSopenharmony_ci            std::string s;
632c5f01b2fSopenharmony_ci            json::to_bson(json_representation, s);
633c5f01b2fSopenharmony_ci            json j3 = json::from_bson(s);
634c5f01b2fSopenharmony_ci            CHECK(json_representation == j3);
635c5f01b2fSopenharmony_ci        }
636c5f01b2fSopenharmony_ci
637c5f01b2fSopenharmony_ci        SECTION("std::vector")
638c5f01b2fSopenharmony_ci        {
639c5f01b2fSopenharmony_ci            std::vector<std::uint8_t> v;
640c5f01b2fSopenharmony_ci            json::to_bson(json_representation, v);
641c5f01b2fSopenharmony_ci            json j3 = json::from_bson(v);
642c5f01b2fSopenharmony_ci            CHECK(json_representation == j3);
643c5f01b2fSopenharmony_ci        }
644c5f01b2fSopenharmony_ci    }
645c5f01b2fSopenharmony_ci}
646c5f01b2fSopenharmony_ci
647c5f01b2fSopenharmony_cinamespace
648c5f01b2fSopenharmony_ci{
649c5f01b2fSopenharmony_ciclass SaxCountdown
650c5f01b2fSopenharmony_ci{
651c5f01b2fSopenharmony_ci  public:
652c5f01b2fSopenharmony_ci    explicit SaxCountdown(const int count) : events_left(count)
653c5f01b2fSopenharmony_ci    {}
654c5f01b2fSopenharmony_ci
655c5f01b2fSopenharmony_ci    bool null()
656c5f01b2fSopenharmony_ci    {
657c5f01b2fSopenharmony_ci        return events_left-- > 0;
658c5f01b2fSopenharmony_ci    }
659c5f01b2fSopenharmony_ci
660c5f01b2fSopenharmony_ci    bool boolean(bool /*unused*/)
661c5f01b2fSopenharmony_ci    {
662c5f01b2fSopenharmony_ci        return events_left-- > 0;
663c5f01b2fSopenharmony_ci    }
664c5f01b2fSopenharmony_ci
665c5f01b2fSopenharmony_ci    bool number_integer(json::number_integer_t /*unused*/)
666c5f01b2fSopenharmony_ci    {
667c5f01b2fSopenharmony_ci        return events_left-- > 0;
668c5f01b2fSopenharmony_ci    }
669c5f01b2fSopenharmony_ci
670c5f01b2fSopenharmony_ci    bool number_unsigned(json::number_unsigned_t /*unused*/)
671c5f01b2fSopenharmony_ci    {
672c5f01b2fSopenharmony_ci        return events_left-- > 0;
673c5f01b2fSopenharmony_ci    }
674c5f01b2fSopenharmony_ci
675c5f01b2fSopenharmony_ci    bool number_float(json::number_float_t /*unused*/, const std::string& /*unused*/)
676c5f01b2fSopenharmony_ci    {
677c5f01b2fSopenharmony_ci        return events_left-- > 0;
678c5f01b2fSopenharmony_ci    }
679c5f01b2fSopenharmony_ci
680c5f01b2fSopenharmony_ci    bool string(std::string& /*unused*/)
681c5f01b2fSopenharmony_ci    {
682c5f01b2fSopenharmony_ci        return events_left-- > 0;
683c5f01b2fSopenharmony_ci    }
684c5f01b2fSopenharmony_ci
685c5f01b2fSopenharmony_ci    bool binary(std::vector<std::uint8_t>& /*unused*/)
686c5f01b2fSopenharmony_ci    {
687c5f01b2fSopenharmony_ci        return events_left-- > 0;
688c5f01b2fSopenharmony_ci    }
689c5f01b2fSopenharmony_ci
690c5f01b2fSopenharmony_ci    bool start_object(std::size_t /*unused*/)
691c5f01b2fSopenharmony_ci    {
692c5f01b2fSopenharmony_ci        return events_left-- > 0;
693c5f01b2fSopenharmony_ci    }
694c5f01b2fSopenharmony_ci
695c5f01b2fSopenharmony_ci    bool key(std::string& /*unused*/)
696c5f01b2fSopenharmony_ci    {
697c5f01b2fSopenharmony_ci        return events_left-- > 0;
698c5f01b2fSopenharmony_ci    }
699c5f01b2fSopenharmony_ci
700c5f01b2fSopenharmony_ci    bool end_object()
701c5f01b2fSopenharmony_ci    {
702c5f01b2fSopenharmony_ci        return events_left-- > 0;
703c5f01b2fSopenharmony_ci    }
704c5f01b2fSopenharmony_ci
705c5f01b2fSopenharmony_ci    bool start_array(std::size_t /*unused*/)
706c5f01b2fSopenharmony_ci    {
707c5f01b2fSopenharmony_ci        return events_left-- > 0;
708c5f01b2fSopenharmony_ci    }
709c5f01b2fSopenharmony_ci
710c5f01b2fSopenharmony_ci    bool end_array()
711c5f01b2fSopenharmony_ci    {
712c5f01b2fSopenharmony_ci        return events_left-- > 0;
713c5f01b2fSopenharmony_ci    }
714c5f01b2fSopenharmony_ci
715c5f01b2fSopenharmony_ci    bool parse_error(std::size_t /*unused*/, const std::string& /*unused*/, const json::exception& /*unused*/) // NOLINT(readability-convert-member-functions-to-static)
716c5f01b2fSopenharmony_ci    {
717c5f01b2fSopenharmony_ci        return false;
718c5f01b2fSopenharmony_ci    }
719c5f01b2fSopenharmony_ci
720c5f01b2fSopenharmony_ci  private:
721c5f01b2fSopenharmony_ci    int events_left = 0;
722c5f01b2fSopenharmony_ci};
723c5f01b2fSopenharmony_ci} // namespace
724c5f01b2fSopenharmony_ci
725c5f01b2fSopenharmony_ciTEST_CASE("Incomplete BSON Input")
726c5f01b2fSopenharmony_ci{
727c5f01b2fSopenharmony_ci    SECTION("Incomplete BSON Input 1")
728c5f01b2fSopenharmony_ci    {
729c5f01b2fSopenharmony_ci        std::vector<std::uint8_t> incomplete_bson =
730c5f01b2fSopenharmony_ci        {
731c5f01b2fSopenharmony_ci            0x0D, 0x00, 0x00, 0x00, // size (little endian)
732c5f01b2fSopenharmony_ci            0x08,                   // entry: boolean
733c5f01b2fSopenharmony_ci            'e', 'n', 't'           // unexpected EOF
734c5f01b2fSopenharmony_ci        };
735c5f01b2fSopenharmony_ci
736c5f01b2fSopenharmony_ci        json _;
737c5f01b2fSopenharmony_ci        CHECK_THROWS_WITH_AS(_ = json::from_bson(incomplete_bson), "[json.exception.parse_error.110] parse error at byte 9: syntax error while parsing BSON cstring: unexpected end of input", json::parse_error&);
738c5f01b2fSopenharmony_ci
739c5f01b2fSopenharmony_ci        CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
740c5f01b2fSopenharmony_ci
741c5f01b2fSopenharmony_ci        SaxCountdown scp(0);
742c5f01b2fSopenharmony_ci        CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
743c5f01b2fSopenharmony_ci    }
744c5f01b2fSopenharmony_ci
745c5f01b2fSopenharmony_ci    SECTION("Incomplete BSON Input 2")
746c5f01b2fSopenharmony_ci    {
747c5f01b2fSopenharmony_ci        std::vector<std::uint8_t> incomplete_bson =
748c5f01b2fSopenharmony_ci        {
749c5f01b2fSopenharmony_ci            0x0D, 0x00, 0x00, 0x00, // size (little endian)
750c5f01b2fSopenharmony_ci            0x08,                   // entry: boolean, unexpected EOF
751c5f01b2fSopenharmony_ci        };
752c5f01b2fSopenharmony_ci
753c5f01b2fSopenharmony_ci        json _;
754c5f01b2fSopenharmony_ci        CHECK_THROWS_WITH_AS(_ = json::from_bson(incomplete_bson), "[json.exception.parse_error.110] parse error at byte 6: syntax error while parsing BSON cstring: unexpected end of input", json::parse_error&);
755c5f01b2fSopenharmony_ci        CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
756c5f01b2fSopenharmony_ci
757c5f01b2fSopenharmony_ci        SaxCountdown scp(0);
758c5f01b2fSopenharmony_ci        CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
759c5f01b2fSopenharmony_ci    }
760c5f01b2fSopenharmony_ci
761c5f01b2fSopenharmony_ci    SECTION("Incomplete BSON Input 3")
762c5f01b2fSopenharmony_ci    {
763c5f01b2fSopenharmony_ci        std::vector<std::uint8_t> incomplete_bson =
764c5f01b2fSopenharmony_ci        {
765c5f01b2fSopenharmony_ci            0x41, 0x00, 0x00, 0x00, // size (little endian)
766c5f01b2fSopenharmony_ci            0x04, /// entry: embedded document
767c5f01b2fSopenharmony_ci            'e', 'n', 't', 'r', 'y', '\x00',
768c5f01b2fSopenharmony_ci
769c5f01b2fSopenharmony_ci            0x35, 0x00, 0x00, 0x00, // size (little endian)
770c5f01b2fSopenharmony_ci            0x10, 0x00, 0x01, 0x00, 0x00, 0x00,
771c5f01b2fSopenharmony_ci            0x10, 0x00, 0x02, 0x00, 0x00, 0x00
772c5f01b2fSopenharmony_ci            // missing input data...
773c5f01b2fSopenharmony_ci        };
774c5f01b2fSopenharmony_ci
775c5f01b2fSopenharmony_ci        json _;
776c5f01b2fSopenharmony_ci        CHECK_THROWS_WITH_AS(_ = json::from_bson(incomplete_bson), "[json.exception.parse_error.110] parse error at byte 28: syntax error while parsing BSON element list: unexpected end of input", json::parse_error&);
777c5f01b2fSopenharmony_ci        CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
778c5f01b2fSopenharmony_ci
779c5f01b2fSopenharmony_ci        SaxCountdown scp(1);
780c5f01b2fSopenharmony_ci        CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
781c5f01b2fSopenharmony_ci    }
782c5f01b2fSopenharmony_ci
783c5f01b2fSopenharmony_ci    SECTION("Incomplete BSON Input 4")
784c5f01b2fSopenharmony_ci    {
785c5f01b2fSopenharmony_ci        std::vector<std::uint8_t> incomplete_bson =
786c5f01b2fSopenharmony_ci        {
787c5f01b2fSopenharmony_ci            0x0D, 0x00, // size (incomplete), unexpected EOF
788c5f01b2fSopenharmony_ci        };
789c5f01b2fSopenharmony_ci
790c5f01b2fSopenharmony_ci        json _;
791c5f01b2fSopenharmony_ci        CHECK_THROWS_WITH_AS(_ = json::from_bson(incomplete_bson), "[json.exception.parse_error.110] parse error at byte 3: syntax error while parsing BSON number: unexpected end of input", json::parse_error&);
792c5f01b2fSopenharmony_ci        CHECK(json::from_bson(incomplete_bson, true, false).is_discarded());
793c5f01b2fSopenharmony_ci
794c5f01b2fSopenharmony_ci        SaxCountdown scp(0);
795c5f01b2fSopenharmony_ci        CHECK(!json::sax_parse(incomplete_bson, &scp, json::input_format_t::bson));
796c5f01b2fSopenharmony_ci    }
797c5f01b2fSopenharmony_ci
798c5f01b2fSopenharmony_ci    SECTION("Improve coverage")
799c5f01b2fSopenharmony_ci    {
800c5f01b2fSopenharmony_ci        SECTION("key")
801c5f01b2fSopenharmony_ci        {
802c5f01b2fSopenharmony_ci            json j = {{"key", "value"}};
803c5f01b2fSopenharmony_ci            auto bson_vec = json::to_bson(j);
804c5f01b2fSopenharmony_ci            SaxCountdown scp(2);
805c5f01b2fSopenharmony_ci            CHECK(!json::sax_parse(bson_vec, &scp, json::input_format_t::bson));
806c5f01b2fSopenharmony_ci        }
807c5f01b2fSopenharmony_ci
808c5f01b2fSopenharmony_ci        SECTION("array")
809c5f01b2fSopenharmony_ci        {
810c5f01b2fSopenharmony_ci            json j =
811c5f01b2fSopenharmony_ci            {
812c5f01b2fSopenharmony_ci                { "entry", json::array() }
813c5f01b2fSopenharmony_ci            };
814c5f01b2fSopenharmony_ci            auto bson_vec = json::to_bson(j);
815c5f01b2fSopenharmony_ci            SaxCountdown scp(2);
816c5f01b2fSopenharmony_ci            CHECK(!json::sax_parse(bson_vec, &scp, json::input_format_t::bson));
817c5f01b2fSopenharmony_ci        }
818c5f01b2fSopenharmony_ci    }
819c5f01b2fSopenharmony_ci}
820c5f01b2fSopenharmony_ci
821c5f01b2fSopenharmony_ciTEST_CASE("Negative size of binary value")
822c5f01b2fSopenharmony_ci{
823c5f01b2fSopenharmony_ci    // invalid BSON: the size of the binary value is -1
824c5f01b2fSopenharmony_ci    std::vector<std::uint8_t> input =
825c5f01b2fSopenharmony_ci    {
826c5f01b2fSopenharmony_ci        0x21, 0x00, 0x00, 0x00, // size (little endian)
827c5f01b2fSopenharmony_ci        0x05, // entry: binary
828c5f01b2fSopenharmony_ci        'e', 'n', 't', 'r', 'y', '\x00',
829c5f01b2fSopenharmony_ci
830c5f01b2fSopenharmony_ci        0xFF, 0xFF, 0xFF, 0xFF, // size of binary (little endian)
831c5f01b2fSopenharmony_ci        0x05, // MD5 binary subtype
832c5f01b2fSopenharmony_ci        0xd7, 0x7e, 0x27, 0x54, 0xbe, 0x12, 0x37, 0xfe, 0xd6, 0x0c, 0x33, 0x98, 0x30, 0x3b, 0x8d, 0xc4,
833c5f01b2fSopenharmony_ci
834c5f01b2fSopenharmony_ci        0x00 // end marker
835c5f01b2fSopenharmony_ci    };
836c5f01b2fSopenharmony_ci    json _;
837c5f01b2fSopenharmony_ci    CHECK_THROWS_WITH_AS(_ = json::from_bson(input), "[json.exception.parse_error.112] parse error at byte 15: syntax error while parsing BSON binary: byte array length cannot be negative, is -1", json::parse_error);
838c5f01b2fSopenharmony_ci}
839c5f01b2fSopenharmony_ci
840c5f01b2fSopenharmony_ciTEST_CASE("Unsupported BSON input")
841c5f01b2fSopenharmony_ci{
842c5f01b2fSopenharmony_ci    std::vector<std::uint8_t> bson =
843c5f01b2fSopenharmony_ci    {
844c5f01b2fSopenharmony_ci        0x0C, 0x00, 0x00, 0x00, // size (little endian)
845c5f01b2fSopenharmony_ci        0xFF,                   // entry type: Min key (not supported yet)
846c5f01b2fSopenharmony_ci        'e', 'n', 't', 'r', 'y', '\x00',
847c5f01b2fSopenharmony_ci        0x00 // end marker
848c5f01b2fSopenharmony_ci    };
849c5f01b2fSopenharmony_ci
850c5f01b2fSopenharmony_ci    json _;
851c5f01b2fSopenharmony_ci    CHECK_THROWS_WITH_AS(_ = json::from_bson(bson), "[json.exception.parse_error.114] parse error at byte 5: Unsupported BSON record type 0xFF", json::parse_error&);
852c5f01b2fSopenharmony_ci    CHECK(json::from_bson(bson, true, false).is_discarded());
853c5f01b2fSopenharmony_ci
854c5f01b2fSopenharmony_ci    SaxCountdown scp(0);
855c5f01b2fSopenharmony_ci    CHECK(!json::sax_parse(bson, &scp, json::input_format_t::bson));
856c5f01b2fSopenharmony_ci}
857c5f01b2fSopenharmony_ci
858c5f01b2fSopenharmony_ciTEST_CASE("BSON numerical data")
859c5f01b2fSopenharmony_ci{
860c5f01b2fSopenharmony_ci    SECTION("number")
861c5f01b2fSopenharmony_ci    {
862c5f01b2fSopenharmony_ci        SECTION("signed")
863c5f01b2fSopenharmony_ci        {
864c5f01b2fSopenharmony_ci            SECTION("std::int64_t: INT64_MIN .. INT32_MIN-1")
865c5f01b2fSopenharmony_ci            {
866c5f01b2fSopenharmony_ci                std::vector<int64_t> numbers
867c5f01b2fSopenharmony_ci                {
868c5f01b2fSopenharmony_ci                    INT64_MIN,
869c5f01b2fSopenharmony_ci                    -1000000000000000000LL,
870c5f01b2fSopenharmony_ci                    -100000000000000000LL,
871c5f01b2fSopenharmony_ci                    -10000000000000000LL,
872c5f01b2fSopenharmony_ci                    -1000000000000000LL,
873c5f01b2fSopenharmony_ci                    -100000000000000LL,
874c5f01b2fSopenharmony_ci                    -10000000000000LL,
875c5f01b2fSopenharmony_ci                    -1000000000000LL,
876c5f01b2fSopenharmony_ci                    -100000000000LL,
877c5f01b2fSopenharmony_ci                    -10000000000LL,
878c5f01b2fSopenharmony_ci                    static_cast<std::int64_t>(INT32_MIN) - 1,
879c5f01b2fSopenharmony_ci                };
880c5f01b2fSopenharmony_ci
881c5f01b2fSopenharmony_ci                for (auto i : numbers)
882c5f01b2fSopenharmony_ci                {
883c5f01b2fSopenharmony_ci
884c5f01b2fSopenharmony_ci                    CAPTURE(i)
885c5f01b2fSopenharmony_ci
886c5f01b2fSopenharmony_ci                    json j =
887c5f01b2fSopenharmony_ci                    {
888c5f01b2fSopenharmony_ci                        { "entry", i }
889c5f01b2fSopenharmony_ci                    };
890c5f01b2fSopenharmony_ci                    CHECK(j.at("entry").is_number_integer());
891c5f01b2fSopenharmony_ci
892c5f01b2fSopenharmony_ci                    std::uint64_t iu = *reinterpret_cast<std::uint64_t*>(&i);
893c5f01b2fSopenharmony_ci                    std::vector<std::uint8_t> expected_bson =
894c5f01b2fSopenharmony_ci                    {
895c5f01b2fSopenharmony_ci                        0x14u, 0x00u, 0x00u, 0x00u, // size (little endian)
896c5f01b2fSopenharmony_ci                        0x12u, /// entry: int64
897c5f01b2fSopenharmony_ci                        'e', 'n', 't', 'r', 'y', '\x00',
898c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu),
899c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu),
900c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 2u)) & 0xffu),
901c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 3u)) & 0xffu),
902c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 4u)) & 0xffu),
903c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 5u)) & 0xffu),
904c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 6u)) & 0xffu),
905c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 7u)) & 0xffu),
906c5f01b2fSopenharmony_ci                        0x00u // end marker
907c5f01b2fSopenharmony_ci                    };
908c5f01b2fSopenharmony_ci
909c5f01b2fSopenharmony_ci                    const auto bson = json::to_bson(j);
910c5f01b2fSopenharmony_ci                    CHECK(bson == expected_bson);
911c5f01b2fSopenharmony_ci
912c5f01b2fSopenharmony_ci                    auto j_roundtrip = json::from_bson(bson);
913c5f01b2fSopenharmony_ci
914c5f01b2fSopenharmony_ci                    CHECK(j_roundtrip.at("entry").is_number_integer());
915c5f01b2fSopenharmony_ci                    CHECK(j_roundtrip == j);
916c5f01b2fSopenharmony_ci                    CHECK(json::from_bson(bson, true, false) == j);
917c5f01b2fSopenharmony_ci
918c5f01b2fSopenharmony_ci                }
919c5f01b2fSopenharmony_ci            }
920c5f01b2fSopenharmony_ci
921c5f01b2fSopenharmony_ci
922c5f01b2fSopenharmony_ci            SECTION("signed std::int32_t: INT32_MIN .. INT32_MAX")
923c5f01b2fSopenharmony_ci            {
924c5f01b2fSopenharmony_ci                std::vector<int32_t> numbers
925c5f01b2fSopenharmony_ci                {
926c5f01b2fSopenharmony_ci                    INT32_MIN,
927c5f01b2fSopenharmony_ci                    -2147483647L,
928c5f01b2fSopenharmony_ci                    -1000000000L,
929c5f01b2fSopenharmony_ci                    -100000000L,
930c5f01b2fSopenharmony_ci                    -10000000L,
931c5f01b2fSopenharmony_ci                    -1000000L,
932c5f01b2fSopenharmony_ci                    -100000L,
933c5f01b2fSopenharmony_ci                    -10000L,
934c5f01b2fSopenharmony_ci                    -1000L,
935c5f01b2fSopenharmony_ci                    -100L,
936c5f01b2fSopenharmony_ci                    -10L,
937c5f01b2fSopenharmony_ci                    -1L,
938c5f01b2fSopenharmony_ci                    0L,
939c5f01b2fSopenharmony_ci                    1L,
940c5f01b2fSopenharmony_ci                    10L,
941c5f01b2fSopenharmony_ci                    100L,
942c5f01b2fSopenharmony_ci                    1000L,
943c5f01b2fSopenharmony_ci                    10000L,
944c5f01b2fSopenharmony_ci                    100000L,
945c5f01b2fSopenharmony_ci                    1000000L,
946c5f01b2fSopenharmony_ci                    10000000L,
947c5f01b2fSopenharmony_ci                    100000000L,
948c5f01b2fSopenharmony_ci                    1000000000L,
949c5f01b2fSopenharmony_ci                    2147483646L,
950c5f01b2fSopenharmony_ci                    INT32_MAX
951c5f01b2fSopenharmony_ci                };
952c5f01b2fSopenharmony_ci
953c5f01b2fSopenharmony_ci                for (auto i : numbers)
954c5f01b2fSopenharmony_ci                {
955c5f01b2fSopenharmony_ci
956c5f01b2fSopenharmony_ci                    CAPTURE(i)
957c5f01b2fSopenharmony_ci
958c5f01b2fSopenharmony_ci                    json j =
959c5f01b2fSopenharmony_ci                    {
960c5f01b2fSopenharmony_ci                        { "entry", i }
961c5f01b2fSopenharmony_ci                    };
962c5f01b2fSopenharmony_ci                    CHECK(j.at("entry").is_number_integer());
963c5f01b2fSopenharmony_ci
964c5f01b2fSopenharmony_ci                    std::uint32_t iu = *reinterpret_cast<std::uint32_t*>(&i);
965c5f01b2fSopenharmony_ci                    std::vector<std::uint8_t> expected_bson =
966c5f01b2fSopenharmony_ci                    {
967c5f01b2fSopenharmony_ci                        0x10u, 0x00u, 0x00u, 0x00u, // size (little endian)
968c5f01b2fSopenharmony_ci                        0x10u, /// entry: int32
969c5f01b2fSopenharmony_ci                        'e', 'n', 't', 'r', 'y', '\x00',
970c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu),
971c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu),
972c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 2u)) & 0xffu),
973c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 3u)) & 0xffu),
974c5f01b2fSopenharmony_ci                        0x00u // end marker
975c5f01b2fSopenharmony_ci                    };
976c5f01b2fSopenharmony_ci
977c5f01b2fSopenharmony_ci                    const auto bson = json::to_bson(j);
978c5f01b2fSopenharmony_ci                    CHECK(bson == expected_bson);
979c5f01b2fSopenharmony_ci
980c5f01b2fSopenharmony_ci                    auto j_roundtrip = json::from_bson(bson);
981c5f01b2fSopenharmony_ci
982c5f01b2fSopenharmony_ci                    CHECK(j_roundtrip.at("entry").is_number_integer());
983c5f01b2fSopenharmony_ci                    CHECK(j_roundtrip == j);
984c5f01b2fSopenharmony_ci                    CHECK(json::from_bson(bson, true, false) == j);
985c5f01b2fSopenharmony_ci
986c5f01b2fSopenharmony_ci                }
987c5f01b2fSopenharmony_ci            }
988c5f01b2fSopenharmony_ci
989c5f01b2fSopenharmony_ci            SECTION("signed std::int64_t: INT32_MAX+1 .. INT64_MAX")
990c5f01b2fSopenharmony_ci            {
991c5f01b2fSopenharmony_ci                std::vector<int64_t> numbers
992c5f01b2fSopenharmony_ci                {
993c5f01b2fSopenharmony_ci                    INT64_MAX,
994c5f01b2fSopenharmony_ci                    1000000000000000000LL,
995c5f01b2fSopenharmony_ci                    100000000000000000LL,
996c5f01b2fSopenharmony_ci                    10000000000000000LL,
997c5f01b2fSopenharmony_ci                    1000000000000000LL,
998c5f01b2fSopenharmony_ci                    100000000000000LL,
999c5f01b2fSopenharmony_ci                    10000000000000LL,
1000c5f01b2fSopenharmony_ci                    1000000000000LL,
1001c5f01b2fSopenharmony_ci                    100000000000LL,
1002c5f01b2fSopenharmony_ci                    10000000000LL,
1003c5f01b2fSopenharmony_ci                    static_cast<std::int64_t>(INT32_MAX) + 1,
1004c5f01b2fSopenharmony_ci                };
1005c5f01b2fSopenharmony_ci
1006c5f01b2fSopenharmony_ci                for (auto i : numbers)
1007c5f01b2fSopenharmony_ci                {
1008c5f01b2fSopenharmony_ci
1009c5f01b2fSopenharmony_ci                    CAPTURE(i)
1010c5f01b2fSopenharmony_ci
1011c5f01b2fSopenharmony_ci                    json j =
1012c5f01b2fSopenharmony_ci                    {
1013c5f01b2fSopenharmony_ci                        { "entry", i }
1014c5f01b2fSopenharmony_ci                    };
1015c5f01b2fSopenharmony_ci                    CHECK(j.at("entry").is_number_integer());
1016c5f01b2fSopenharmony_ci
1017c5f01b2fSopenharmony_ci                    std::uint64_t iu = *reinterpret_cast<std::uint64_t*>(&i);
1018c5f01b2fSopenharmony_ci                    std::vector<std::uint8_t> expected_bson =
1019c5f01b2fSopenharmony_ci                    {
1020c5f01b2fSopenharmony_ci                        0x14u, 0x00u, 0x00u, 0x00u, // size (little endian)
1021c5f01b2fSopenharmony_ci                        0x12u, /// entry: int64
1022c5f01b2fSopenharmony_ci                        'e', 'n', 't', 'r', 'y', '\x00',
1023c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu),
1024c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu),
1025c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 2u)) & 0xffu),
1026c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 3u)) & 0xffu),
1027c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 4u)) & 0xffu),
1028c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 5u)) & 0xffu),
1029c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 6u)) & 0xffu),
1030c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 7u)) & 0xffu),
1031c5f01b2fSopenharmony_ci                        0x00u // end marker
1032c5f01b2fSopenharmony_ci                    };
1033c5f01b2fSopenharmony_ci
1034c5f01b2fSopenharmony_ci                    const auto bson = json::to_bson(j);
1035c5f01b2fSopenharmony_ci                    CHECK(bson == expected_bson);
1036c5f01b2fSopenharmony_ci
1037c5f01b2fSopenharmony_ci                    auto j_roundtrip = json::from_bson(bson);
1038c5f01b2fSopenharmony_ci
1039c5f01b2fSopenharmony_ci                    CHECK(j_roundtrip.at("entry").is_number_integer());
1040c5f01b2fSopenharmony_ci                    CHECK(j_roundtrip == j);
1041c5f01b2fSopenharmony_ci                    CHECK(json::from_bson(bson, true, false) == j);
1042c5f01b2fSopenharmony_ci
1043c5f01b2fSopenharmony_ci                }
1044c5f01b2fSopenharmony_ci            }
1045c5f01b2fSopenharmony_ci        }
1046c5f01b2fSopenharmony_ci
1047c5f01b2fSopenharmony_ci        SECTION("unsigned")
1048c5f01b2fSopenharmony_ci        {
1049c5f01b2fSopenharmony_ci            SECTION("unsigned std::uint64_t: 0 .. INT32_MAX")
1050c5f01b2fSopenharmony_ci            {
1051c5f01b2fSopenharmony_ci                std::vector<std::uint64_t> numbers
1052c5f01b2fSopenharmony_ci                {
1053c5f01b2fSopenharmony_ci                    0ULL,
1054c5f01b2fSopenharmony_ci                    1ULL,
1055c5f01b2fSopenharmony_ci                    10ULL,
1056c5f01b2fSopenharmony_ci                    100ULL,
1057c5f01b2fSopenharmony_ci                    1000ULL,
1058c5f01b2fSopenharmony_ci                    10000ULL,
1059c5f01b2fSopenharmony_ci                    100000ULL,
1060c5f01b2fSopenharmony_ci                    1000000ULL,
1061c5f01b2fSopenharmony_ci                    10000000ULL,
1062c5f01b2fSopenharmony_ci                    100000000ULL,
1063c5f01b2fSopenharmony_ci                    1000000000ULL,
1064c5f01b2fSopenharmony_ci                    2147483646ULL,
1065c5f01b2fSopenharmony_ci                    static_cast<std::uint64_t>(INT32_MAX)
1066c5f01b2fSopenharmony_ci                };
1067c5f01b2fSopenharmony_ci
1068c5f01b2fSopenharmony_ci                for (auto i : numbers)
1069c5f01b2fSopenharmony_ci                {
1070c5f01b2fSopenharmony_ci
1071c5f01b2fSopenharmony_ci                    CAPTURE(i)
1072c5f01b2fSopenharmony_ci
1073c5f01b2fSopenharmony_ci                    json j =
1074c5f01b2fSopenharmony_ci                    {
1075c5f01b2fSopenharmony_ci                        { "entry", i }
1076c5f01b2fSopenharmony_ci                    };
1077c5f01b2fSopenharmony_ci
1078c5f01b2fSopenharmony_ci                    auto iu = i;
1079c5f01b2fSopenharmony_ci                    std::vector<std::uint8_t> expected_bson =
1080c5f01b2fSopenharmony_ci                    {
1081c5f01b2fSopenharmony_ci                        0x10u, 0x00u, 0x00u, 0x00u, // size (little endian)
1082c5f01b2fSopenharmony_ci                        0x10u, /// entry: int32
1083c5f01b2fSopenharmony_ci                        'e', 'n', 't', 'r', 'y', '\x00',
1084c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu),
1085c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu),
1086c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 2u)) & 0xffu),
1087c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 3u)) & 0xffu),
1088c5f01b2fSopenharmony_ci                        0x00u // end marker
1089c5f01b2fSopenharmony_ci                    };
1090c5f01b2fSopenharmony_ci
1091c5f01b2fSopenharmony_ci                    const auto bson = json::to_bson(j);
1092c5f01b2fSopenharmony_ci                    CHECK(bson == expected_bson);
1093c5f01b2fSopenharmony_ci
1094c5f01b2fSopenharmony_ci                    auto j_roundtrip = json::from_bson(bson);
1095c5f01b2fSopenharmony_ci
1096c5f01b2fSopenharmony_ci                    CHECK(j.at("entry").is_number_unsigned());
1097c5f01b2fSopenharmony_ci                    CHECK(j_roundtrip.at("entry").is_number_integer());
1098c5f01b2fSopenharmony_ci                    CHECK(j_roundtrip == j);
1099c5f01b2fSopenharmony_ci                    CHECK(json::from_bson(bson, true, false) == j);
1100c5f01b2fSopenharmony_ci
1101c5f01b2fSopenharmony_ci                }
1102c5f01b2fSopenharmony_ci            }
1103c5f01b2fSopenharmony_ci
1104c5f01b2fSopenharmony_ci            SECTION("unsigned std::uint64_t: INT32_MAX+1 .. INT64_MAX")
1105c5f01b2fSopenharmony_ci            {
1106c5f01b2fSopenharmony_ci                std::vector<std::uint64_t> numbers
1107c5f01b2fSopenharmony_ci                {
1108c5f01b2fSopenharmony_ci                    static_cast<std::uint64_t>(INT32_MAX) + 1,
1109c5f01b2fSopenharmony_ci                    4000000000ULL,
1110c5f01b2fSopenharmony_ci                    static_cast<std::uint64_t>(UINT32_MAX),
1111c5f01b2fSopenharmony_ci                    10000000000ULL,
1112c5f01b2fSopenharmony_ci                    100000000000ULL,
1113c5f01b2fSopenharmony_ci                    1000000000000ULL,
1114c5f01b2fSopenharmony_ci                    10000000000000ULL,
1115c5f01b2fSopenharmony_ci                    100000000000000ULL,
1116c5f01b2fSopenharmony_ci                    1000000000000000ULL,
1117c5f01b2fSopenharmony_ci                    10000000000000000ULL,
1118c5f01b2fSopenharmony_ci                    100000000000000000ULL,
1119c5f01b2fSopenharmony_ci                    1000000000000000000ULL,
1120c5f01b2fSopenharmony_ci                    static_cast<std::uint64_t>(INT64_MAX),
1121c5f01b2fSopenharmony_ci                };
1122c5f01b2fSopenharmony_ci
1123c5f01b2fSopenharmony_ci                for (auto i : numbers)
1124c5f01b2fSopenharmony_ci                {
1125c5f01b2fSopenharmony_ci
1126c5f01b2fSopenharmony_ci                    CAPTURE(i)
1127c5f01b2fSopenharmony_ci
1128c5f01b2fSopenharmony_ci                    json j =
1129c5f01b2fSopenharmony_ci                    {
1130c5f01b2fSopenharmony_ci                        { "entry", i }
1131c5f01b2fSopenharmony_ci                    };
1132c5f01b2fSopenharmony_ci
1133c5f01b2fSopenharmony_ci                    auto iu = i;
1134c5f01b2fSopenharmony_ci                    std::vector<std::uint8_t> expected_bson =
1135c5f01b2fSopenharmony_ci                    {
1136c5f01b2fSopenharmony_ci                        0x14u, 0x00u, 0x00u, 0x00u, // size (little endian)
1137c5f01b2fSopenharmony_ci                        0x12u, /// entry: int64
1138c5f01b2fSopenharmony_ci                        'e', 'n', 't', 'r', 'y', '\x00',
1139c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu),
1140c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu),
1141c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 2u)) & 0xffu),
1142c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 3u)) & 0xffu),
1143c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 4u)) & 0xffu),
1144c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 5u)) & 0xffu),
1145c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 6u)) & 0xffu),
1146c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 7u)) & 0xffu),
1147c5f01b2fSopenharmony_ci                        0x00u // end marker
1148c5f01b2fSopenharmony_ci                    };
1149c5f01b2fSopenharmony_ci
1150c5f01b2fSopenharmony_ci                    const auto bson = json::to_bson(j);
1151c5f01b2fSopenharmony_ci                    CHECK(bson == expected_bson);
1152c5f01b2fSopenharmony_ci
1153c5f01b2fSopenharmony_ci                    auto j_roundtrip = json::from_bson(bson);
1154c5f01b2fSopenharmony_ci
1155c5f01b2fSopenharmony_ci                    CHECK(j.at("entry").is_number_unsigned());
1156c5f01b2fSopenharmony_ci                    CHECK(j_roundtrip.at("entry").is_number_integer());
1157c5f01b2fSopenharmony_ci                    CHECK(j_roundtrip == j);
1158c5f01b2fSopenharmony_ci                    CHECK(json::from_bson(bson, true, false) == j);
1159c5f01b2fSopenharmony_ci                }
1160c5f01b2fSopenharmony_ci            }
1161c5f01b2fSopenharmony_ci
1162c5f01b2fSopenharmony_ci            SECTION("unsigned std::uint64_t: INT64_MAX+1 .. UINT64_MAX")
1163c5f01b2fSopenharmony_ci            {
1164c5f01b2fSopenharmony_ci                std::vector<std::uint64_t> numbers
1165c5f01b2fSopenharmony_ci                {
1166c5f01b2fSopenharmony_ci                    static_cast<std::uint64_t>(INT64_MAX) + 1ULL,
1167c5f01b2fSopenharmony_ci                    10000000000000000000ULL,
1168c5f01b2fSopenharmony_ci                    18000000000000000000ULL,
1169c5f01b2fSopenharmony_ci                    UINT64_MAX - 1ULL,
1170c5f01b2fSopenharmony_ci                    UINT64_MAX,
1171c5f01b2fSopenharmony_ci                };
1172c5f01b2fSopenharmony_ci
1173c5f01b2fSopenharmony_ci                for (auto i : numbers)
1174c5f01b2fSopenharmony_ci                {
1175c5f01b2fSopenharmony_ci
1176c5f01b2fSopenharmony_ci                    CAPTURE(i)
1177c5f01b2fSopenharmony_ci
1178c5f01b2fSopenharmony_ci                    json j =
1179c5f01b2fSopenharmony_ci                    {
1180c5f01b2fSopenharmony_ci                        { "entry", i }
1181c5f01b2fSopenharmony_ci                    };
1182c5f01b2fSopenharmony_ci
1183c5f01b2fSopenharmony_ci                    auto iu = i;
1184c5f01b2fSopenharmony_ci                    std::vector<std::uint8_t> expected_bson =
1185c5f01b2fSopenharmony_ci                    {
1186c5f01b2fSopenharmony_ci                        0x14u, 0x00u, 0x00u, 0x00u, // size (little endian)
1187c5f01b2fSopenharmony_ci                        0x12u, /// entry: int64
1188c5f01b2fSopenharmony_ci                        'e', 'n', 't', 'r', 'y', '\x00',
1189c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 0u)) & 0xffu),
1190c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 1u)) & 0xffu),
1191c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 2u)) & 0xffu),
1192c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 3u)) & 0xffu),
1193c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 4u)) & 0xffu),
1194c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 5u)) & 0xffu),
1195c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 6u)) & 0xffu),
1196c5f01b2fSopenharmony_ci                        static_cast<std::uint8_t>((iu >> (8u * 7u)) & 0xffu),
1197c5f01b2fSopenharmony_ci                        0x00u // end marker
1198c5f01b2fSopenharmony_ci                    };
1199c5f01b2fSopenharmony_ci
1200c5f01b2fSopenharmony_ci                    CHECK_THROWS_AS(json::to_bson(j), json::out_of_range&);
1201c5f01b2fSopenharmony_ci#if JSON_DIAGNOSTICS
1202c5f01b2fSopenharmony_ci                    CHECK_THROWS_WITH_STD_STR(json::to_bson(j), "[json.exception.out_of_range.407] (/entry) integer number " + std::to_string(i) + " cannot be represented by BSON as it does not fit int64");
1203c5f01b2fSopenharmony_ci#else
1204c5f01b2fSopenharmony_ci                    CHECK_THROWS_WITH_STD_STR(json::to_bson(j), "[json.exception.out_of_range.407] integer number " + std::to_string(i) + " cannot be represented by BSON as it does not fit int64");
1205c5f01b2fSopenharmony_ci#endif
1206c5f01b2fSopenharmony_ci                }
1207c5f01b2fSopenharmony_ci            }
1208c5f01b2fSopenharmony_ci
1209c5f01b2fSopenharmony_ci        }
1210c5f01b2fSopenharmony_ci    }
1211c5f01b2fSopenharmony_ci}
1212c5f01b2fSopenharmony_ci
1213c5f01b2fSopenharmony_ciTEST_CASE("BSON roundtrips" * doctest::skip())
1214c5f01b2fSopenharmony_ci{
1215c5f01b2fSopenharmony_ci    SECTION("reference files")
1216c5f01b2fSopenharmony_ci    {
1217c5f01b2fSopenharmony_ci        for (std::string filename :
1218c5f01b2fSopenharmony_ci                {
1219c5f01b2fSopenharmony_ci                    TEST_DATA_DIRECTORY "/json.org/1.json",
1220c5f01b2fSopenharmony_ci                    TEST_DATA_DIRECTORY "/json.org/2.json",
1221c5f01b2fSopenharmony_ci                    TEST_DATA_DIRECTORY "/json.org/3.json",
1222c5f01b2fSopenharmony_ci                    TEST_DATA_DIRECTORY "/json.org/4.json",
1223c5f01b2fSopenharmony_ci                    TEST_DATA_DIRECTORY "/json.org/5.json"
1224c5f01b2fSopenharmony_ci                })
1225c5f01b2fSopenharmony_ci        {
1226c5f01b2fSopenharmony_ci            CAPTURE(filename)
1227c5f01b2fSopenharmony_ci
1228c5f01b2fSopenharmony_ci            {
1229c5f01b2fSopenharmony_ci                INFO_WITH_TEMP(filename + ": std::vector<std::uint8_t>");
1230c5f01b2fSopenharmony_ci                // parse JSON file
1231c5f01b2fSopenharmony_ci                std::ifstream f_json(filename);
1232c5f01b2fSopenharmony_ci                json j1 = json::parse(f_json);
1233c5f01b2fSopenharmony_ci
1234c5f01b2fSopenharmony_ci                // parse BSON file
1235c5f01b2fSopenharmony_ci                auto packed = utils::read_binary_file(filename + ".bson");
1236c5f01b2fSopenharmony_ci                json j2;
1237c5f01b2fSopenharmony_ci                CHECK_NOTHROW(j2 = json::from_bson(packed));
1238c5f01b2fSopenharmony_ci
1239c5f01b2fSopenharmony_ci                // compare parsed JSON values
1240c5f01b2fSopenharmony_ci                CHECK(j1 == j2);
1241c5f01b2fSopenharmony_ci            }
1242c5f01b2fSopenharmony_ci
1243c5f01b2fSopenharmony_ci            {
1244c5f01b2fSopenharmony_ci                INFO_WITH_TEMP(filename + ": std::ifstream");
1245c5f01b2fSopenharmony_ci                // parse JSON file
1246c5f01b2fSopenharmony_ci                std::ifstream f_json(filename);
1247c5f01b2fSopenharmony_ci                json j1 = json::parse(f_json);
1248c5f01b2fSopenharmony_ci
1249c5f01b2fSopenharmony_ci                // parse BSON file
1250c5f01b2fSopenharmony_ci                std::ifstream f_bson(filename + ".bson", std::ios::binary);
1251c5f01b2fSopenharmony_ci                json j2;
1252c5f01b2fSopenharmony_ci                CHECK_NOTHROW(j2 = json::from_bson(f_bson));
1253c5f01b2fSopenharmony_ci
1254c5f01b2fSopenharmony_ci                // compare parsed JSON values
1255c5f01b2fSopenharmony_ci                CHECK(j1 == j2);
1256c5f01b2fSopenharmony_ci            }
1257c5f01b2fSopenharmony_ci
1258c5f01b2fSopenharmony_ci            {
1259c5f01b2fSopenharmony_ci                INFO_WITH_TEMP(filename + ": uint8_t* and size");
1260c5f01b2fSopenharmony_ci                // parse JSON file
1261c5f01b2fSopenharmony_ci                std::ifstream f_json(filename);
1262c5f01b2fSopenharmony_ci                json j1 = json::parse(f_json);
1263c5f01b2fSopenharmony_ci
1264c5f01b2fSopenharmony_ci                // parse BSON file
1265c5f01b2fSopenharmony_ci                auto packed = utils::read_binary_file(filename + ".bson");
1266c5f01b2fSopenharmony_ci                json j2;
1267c5f01b2fSopenharmony_ci                CHECK_NOTHROW(j2 = json::from_bson({packed.data(), packed.size()}));
1268c5f01b2fSopenharmony_ci
1269c5f01b2fSopenharmony_ci                // compare parsed JSON values
1270c5f01b2fSopenharmony_ci                CHECK(j1 == j2);
1271c5f01b2fSopenharmony_ci            }
1272c5f01b2fSopenharmony_ci
1273c5f01b2fSopenharmony_ci            {
1274c5f01b2fSopenharmony_ci                INFO_WITH_TEMP(filename + ": output to output adapters");
1275c5f01b2fSopenharmony_ci                // parse JSON file
1276c5f01b2fSopenharmony_ci                std::ifstream f_json(filename);
1277c5f01b2fSopenharmony_ci                json j1 = json::parse(f_json);
1278c5f01b2fSopenharmony_ci
1279c5f01b2fSopenharmony_ci                // parse BSON file
1280c5f01b2fSopenharmony_ci                auto packed = utils::read_binary_file(filename + ".bson");
1281c5f01b2fSopenharmony_ci
1282c5f01b2fSopenharmony_ci                {
1283c5f01b2fSopenharmony_ci                    INFO_WITH_TEMP(filename + ": output adapters: std::vector<std::uint8_t>");
1284c5f01b2fSopenharmony_ci                    std::vector<std::uint8_t> vec;
1285c5f01b2fSopenharmony_ci                    json::to_bson(j1, vec);
1286c5f01b2fSopenharmony_ci
1287c5f01b2fSopenharmony_ci                    if (vec != packed)
1288c5f01b2fSopenharmony_ci                    {
1289c5f01b2fSopenharmony_ci                        // the exact serializations may differ due to the order of
1290c5f01b2fSopenharmony_ci                        // object keys; in these cases, just compare whether both
1291c5f01b2fSopenharmony_ci                        // serializations create the same JSON value
1292c5f01b2fSopenharmony_ci                        CHECK(json::from_bson(vec) == json::from_bson(packed));
1293c5f01b2fSopenharmony_ci                    }
1294c5f01b2fSopenharmony_ci                }
1295c5f01b2fSopenharmony_ci            }
1296c5f01b2fSopenharmony_ci        }
1297c5f01b2fSopenharmony_ci    }
1298c5f01b2fSopenharmony_ci}
1299