• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2     __ _____ _____ _____
3  __|  |   __|     |   | |  JSON for Modern C++ (test suite)
4 |  |  |__   |  |  | | | |  version 3.10.0
5 |_____|_____|_____|_|___|  https://github.com/nlohmann/json
6 
7 Licensed under the MIT License <http://opensource.org/licenses/MIT>.
8 SPDX-License-Identifier: MIT
9 Copyright (c) 2013-2019 Niels Lohmann <http://nlohmann.me>.
10 
11 Permission is hereby  granted, free of charge, to any  person obtaining a copy
12 of this software and associated  documentation files (the "Software"), to deal
13 in the Software  without restriction, including without  limitation the rights
14 to  use, copy,  modify, merge,  publish, distribute,  sublicense, and/or  sell
15 copies  of  the Software,  and  to  permit persons  to  whom  the Software  is
16 furnished to do so, subject to the following conditions:
17 
18 The above copyright notice and this permission notice shall be included in all
19 copies or substantial portions of the Software.
20 
21 THE SOFTWARE  IS PROVIDED "AS  IS", WITHOUT WARRANTY  OF ANY KIND,  EXPRESS OR
22 IMPLIED,  INCLUDING BUT  NOT  LIMITED TO  THE  WARRANTIES OF  MERCHANTABILITY,
23 FITNESS FOR  A PARTICULAR PURPOSE AND  NONINFRINGEMENT. IN NO EVENT  SHALL THE
24 AUTHORS  OR COPYRIGHT  HOLDERS  BE  LIABLE FOR  ANY  CLAIM,  DAMAGES OR  OTHER
25 LIABILITY, WHETHER IN AN ACTION OF  CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 OUT OF OR IN CONNECTION WITH THE SOFTWARE  OR THE USE OR OTHER DEALINGS IN THE
27 SOFTWARE.
28 */
29 
30 #include "doctest_compatibility.h"
31 
32 #include <nlohmann/json.hpp>
33 using nlohmann::json;
34 
35 #include <sstream>
36 #include <iomanip>
37 
38 TEST_CASE("serialization")
39 {
40     SECTION("operator<<")
41     {
42         SECTION("no given width")
43         {
44             std::stringstream ss;
45             json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
46             ss << j;
47             CHECK(ss.str() == "[\"foo\",1,2,3,false,{\"one\":1}]");
48         }
49 
50         SECTION("given width")
51         {
52             std::stringstream ss;
53             json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
54             ss << std::setw(4) << j;
55             CHECK(ss.str() ==
56                   "[\n    \"foo\",\n    1,\n    2,\n    3,\n    false,\n    {\n        \"one\": 1\n    }\n]");
57         }
58 
59         SECTION("given fill")
60         {
61             std::stringstream ss;
62             json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
63             ss << std::setw(1) << std::setfill('\t') << j;
64             CHECK(ss.str() ==
65                   "[\n\t\"foo\",\n\t1,\n\t2,\n\t3,\n\tfalse,\n\t{\n\t\t\"one\": 1\n\t}\n]");
66         }
67     }
68 
69     SECTION("operator>>")
70     {
71         SECTION("no given width")
72         {
73             std::stringstream ss;
74             json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
75             j >> ss;
76             CHECK(ss.str() == "[\"foo\",1,2,3,false,{\"one\":1}]");
77         }
78 
79         SECTION("given width")
80         {
81             std::stringstream ss;
82             json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
83             ss.width(4);
84             j >> ss;
85             CHECK(ss.str() ==
86                   "[\n    \"foo\",\n    1,\n    2,\n    3,\n    false,\n    {\n        \"one\": 1\n    }\n]");
87         }
88 
89         SECTION("given fill")
90         {
91             std::stringstream ss;
92             json j = {"foo", 1, 2, 3, false, {{"one", 1}}};
93             ss.width(1);
94             ss.fill('\t');
95             j >> ss;
96             CHECK(ss.str() ==
97                   "[\n\t\"foo\",\n\t1,\n\t2,\n\t3,\n\tfalse,\n\t{\n\t\t\"one\": 1\n\t}\n]");
98         }
99     }
100 
101     SECTION("dump")
102     {
103         SECTION("invalid character")
104         {
105             json j = "ä\xA9ü";
106 
107             CHECK_THROWS_AS(j.dump(), json::type_error&);
108             CHECK_THROWS_WITH(j.dump(), "[json.exception.type_error.316] invalid UTF-8 byte at index 2: 0xA9");
109             CHECK_THROWS_AS(j.dump(1, ' ', false, json::error_handler_t::strict), json::type_error&);
110             CHECK_THROWS_WITH(j.dump(1, ' ', false, json::error_handler_t::strict), "[json.exception.type_error.316] invalid UTF-8 byte at index 2: 0xA9");
111             CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"äü\"");
112             CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"ä\xEF\xBF\xBDü\"");
113             CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"\\u00e4\\ufffd\\u00fc\"");
114         }
115 
116         SECTION("ending with incomplete character")
117         {
118             json j = "123\xC2";
119 
120             CHECK_THROWS_AS(j.dump(), json::type_error&);
121             CHECK_THROWS_WITH(j.dump(), "[json.exception.type_error.316] incomplete UTF-8 string; last byte: 0xC2");
122             CHECK_THROWS_AS(j.dump(1, ' ', false, json::error_handler_t::strict), json::type_error&);
123             CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"123\"");
124             CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"123\xEF\xBF\xBD\"");
125             CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"123\\ufffd\"");
126         }
127 
128         SECTION("unexpected character")
129         {
130             json j = "123\xF1\xB0\x34\x35\x36";
131 
132             CHECK_THROWS_AS(j.dump(), json::type_error&);
133             CHECK_THROWS_WITH(j.dump(), "[json.exception.type_error.316] invalid UTF-8 byte at index 5: 0x34");
134             CHECK_THROWS_AS(j.dump(1, ' ', false, json::error_handler_t::strict), json::type_error&);
135             CHECK(j.dump(-1, ' ', false, json::error_handler_t::ignore) == "\"123456\"");
136             CHECK(j.dump(-1, ' ', false, json::error_handler_t::replace) == "\"123\xEF\xBF\xBD\x34\x35\x36\"");
137             CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"123\\ufffd456\"");
138         }
139 
140         SECTION("U+FFFD Substitution of Maximal Subparts")
141         {
142             // Some tests (mostly) from
143             // https://www.unicode.org/versions/Unicode11.0.0/ch03.pdf
144             // Section 3.9 -- U+FFFD Substitution of Maximal Subparts
145 
146             auto test = [&](std::string const & input, std::string const & expected)
__anon4e96612c0102(std::string const & input, std::string const & expected) 147             {
148                 json j = input;
149                 CHECK(j.dump(-1, ' ', true, json::error_handler_t::replace) == "\"" + expected + "\"");
150             };
151 
152             test("\xC2", "\\ufffd");
153             test("\xC2\x41\x42", "\\ufffd" "\x41" "\x42");
154             test("\xC2\xF4", "\\ufffd" "\\ufffd");
155 
156             test("\xF0\x80\x80\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\x41");
157             test("\xF1\x80\x80\x41", "\\ufffd" "\x41");
158             test("\xF2\x80\x80\x41", "\\ufffd" "\x41");
159             test("\xF3\x80\x80\x41", "\\ufffd" "\x41");
160             test("\xF4\x80\x80\x41", "\\ufffd" "\x41");
161             test("\xF5\x80\x80\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\x41");
162 
163             test("\xF0\x90\x80\x41", "\\ufffd" "\x41");
164             test("\xF1\x90\x80\x41", "\\ufffd" "\x41");
165             test("\xF2\x90\x80\x41", "\\ufffd" "\x41");
166             test("\xF3\x90\x80\x41", "\\ufffd" "\x41");
167             test("\xF4\x90\x80\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\x41");
168             test("\xF5\x90\x80\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\x41");
169 
170             test("\xC0\xAF\xE0\x80\xBF\xF0\x81\x82\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\x41");
171             test("\xED\xA0\x80\xED\xBF\xBF\xED\xAF\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\x41");
172             test("\xF4\x91\x92\x93\xFF\x41\x80\xBF\x42", "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\x41" "\\ufffd""\\ufffd" "\x42");
173             test("\xE1\x80\xE2\xF0\x91\x92\xF1\xBF\x41", "\\ufffd" "\\ufffd" "\\ufffd" "\\ufffd" "\x41");
174         }
175     }
176 
177     SECTION("to_string")
178     {
179         auto test = [&](std::string const & input, std::string const & expected)
__anon4e96612c0202(std::string const & input, std::string const & expected) 180         {
181             using std::to_string;
182             json j = input;
183             CHECK(to_string(j) == "\"" + expected + "\"");
184         };
185 
186         test(R"({"x":5,"y":6})", R"({\"x\":5,\"y\":6})");
187         test("{\"x\":[10,null,null,null]}", R"({\"x\":[10,null,null,null]})");
188         test("test", "test");
189         test("[3,\"false\",false]", R"([3,\"false\",false])");
190     }
191 }
192 
193 TEST_CASE_TEMPLATE("serialization for extreme integer values", T, int32_t, uint32_t, int64_t, uint64_t)
194 {
195     SECTION("minimum")
196     {
197         constexpr auto minimum = (std::numeric_limits<T>::min)();
198         json j = minimum;
199         CHECK(j.dump() == std::to_string(minimum));
200     }
201 
202     SECTION("maximum")
203     {
204         constexpr auto maximum = (std::numeric_limits<T>::max)();
205         json j = maximum;
206         CHECK(j.dump() == std::to_string(maximum));
207     }
208 }
209 
210 TEST_CASE("dump with binary values")
211 {
212     auto binary = json::binary({1, 2, 3, 4});
213     auto binary_empty = json::binary({});
214     auto binary_with_subtype = json::binary({1, 2, 3, 4}, 128);
215     auto binary_empty_with_subtype = json::binary({}, 128);
216 
217     json object = {{"key", binary}};
218     json object_empty = {{"key", binary_empty}};
219     json object_with_subtype = {{"key", binary_with_subtype}};
220     json object_empty_with_subtype = {{"key", binary_empty_with_subtype}};
221 
222     json array = {"value", 1, binary};
223     json array_empty = {"value", 1, binary_empty};
224     json array_with_subtype = {"value", 1, binary_with_subtype};
225     json array_empty_with_subtype = {"value", 1, binary_empty_with_subtype};
226 
227     SECTION("normal")
228     {
229         CHECK(binary.dump() == "{\"bytes\":[1,2,3,4],\"subtype\":null}");
230         CHECK(binary_empty.dump() == "{\"bytes\":[],\"subtype\":null}");
231         CHECK(binary_with_subtype.dump() == "{\"bytes\":[1,2,3,4],\"subtype\":128}");
232         CHECK(binary_empty_with_subtype.dump() == "{\"bytes\":[],\"subtype\":128}");
233 
234         CHECK(object.dump() == "{\"key\":{\"bytes\":[1,2,3,4],\"subtype\":null}}");
235         CHECK(object_empty.dump() == "{\"key\":{\"bytes\":[],\"subtype\":null}}");
236         CHECK(object_with_subtype.dump() == "{\"key\":{\"bytes\":[1,2,3,4],\"subtype\":128}}");
237         CHECK(object_empty_with_subtype.dump() == "{\"key\":{\"bytes\":[],\"subtype\":128}}");
238 
239         CHECK(array.dump() == "[\"value\",1,{\"bytes\":[1,2,3,4],\"subtype\":null}]");
240         CHECK(array_empty.dump() == "[\"value\",1,{\"bytes\":[],\"subtype\":null}]");
241         CHECK(array_with_subtype.dump() == "[\"value\",1,{\"bytes\":[1,2,3,4],\"subtype\":128}]");
242         CHECK(array_empty_with_subtype.dump() == "[\"value\",1,{\"bytes\":[],\"subtype\":128}]");
243     }
244 
245     SECTION("pretty-printed")
246     {
247         CHECK(binary.dump(4) == "{\n"
248               "    \"bytes\": [1, 2, 3, 4],\n"
249               "    \"subtype\": null\n"
250               "}");
251         CHECK(binary_empty.dump(4) == "{\n"
252               "    \"bytes\": [],\n"
253               "    \"subtype\": null\n"
254               "}");
255         CHECK(binary_with_subtype.dump(4) == "{\n"
256               "    \"bytes\": [1, 2, 3, 4],\n"
257               "    \"subtype\": 128\n"
258               "}");
259         CHECK(binary_empty_with_subtype.dump(4) == "{\n"
260               "    \"bytes\": [],\n"
261               "    \"subtype\": 128\n"
262               "}");
263 
264         CHECK(object.dump(4) == "{\n"
265               "    \"key\": {\n"
266               "        \"bytes\": [1, 2, 3, 4],\n"
267               "        \"subtype\": null\n"
268               "    }\n"
269               "}");
270         CHECK(object_empty.dump(4) == "{\n"
271               "    \"key\": {\n"
272               "        \"bytes\": [],\n"
273               "        \"subtype\": null\n"
274               "    }\n"
275               "}");
276         CHECK(object_with_subtype.dump(4) == "{\n"
277               "    \"key\": {\n"
278               "        \"bytes\": [1, 2, 3, 4],\n"
279               "        \"subtype\": 128\n"
280               "    }\n"
281               "}");
282         CHECK(object_empty_with_subtype.dump(4) == "{\n"
283               "    \"key\": {\n"
284               "        \"bytes\": [],\n"
285               "        \"subtype\": 128\n"
286               "    }\n"
287               "}");
288 
289         CHECK(array.dump(4) == "[\n"
290               "    \"value\",\n"
291               "    1,\n"
292               "    {\n"
293               "        \"bytes\": [1, 2, 3, 4],\n"
294               "        \"subtype\": null\n"
295               "    }\n"
296               "]");
297         CHECK(array_empty.dump(4) == "[\n"
298               "    \"value\",\n"
299               "    1,\n"
300               "    {\n"
301               "        \"bytes\": [],\n"
302               "        \"subtype\": null\n"
303               "    }\n"
304               "]");
305         CHECK(array_with_subtype.dump(4) == "[\n"
306               "    \"value\",\n"
307               "    1,\n"
308               "    {\n"
309               "        \"bytes\": [1, 2, 3, 4],\n"
310               "        \"subtype\": 128\n"
311               "    }\n"
312               "]");
313         CHECK(array_empty_with_subtype.dump(4) == "[\n"
314               "    \"value\",\n"
315               "    1,\n"
316               "    {\n"
317               "        \"bytes\": [],\n"
318               "        \"subtype\": 128\n"
319               "    }\n"
320               "]");
321     }
322 }
323