• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //     __ _____ _____ _____
2 //  __|  |   __|     |   | |  JSON for Modern C++ (supporting code)
3 // |  |  |__   |  |  | | | |  version 3.11.2
4 // |_____|_____|_____|_|___|  https://github.com/nlohmann/json
5 //
6 // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann <https://nlohmann.me>
7 // SPDX-License-Identifier: MIT
8 
9 #include "doctest_compatibility.h"
10 
11 #include <nlohmann/json.hpp>
12 using nlohmann::json;
13 
14 #include <fstream>
15 #include <sstream>
16 #include "make_test_data_available.hpp"
17 
18 TEST_CASE("object inspection")
19 {
20     SECTION("convenience type checker")
21     {
22         SECTION("object")
23         {
24             json j {{"foo", 1}, {"bar", false}};
25             CHECK(!j.is_null());
26             CHECK(!j.is_boolean());
27             CHECK(!j.is_number());
28             CHECK(!j.is_number_integer());
29             CHECK(!j.is_number_unsigned());
30             CHECK(!j.is_number_float());
31             CHECK(!j.is_binary());
32             CHECK(j.is_object());
33             CHECK(!j.is_array());
34             CHECK(!j.is_string());
35             CHECK(!j.is_discarded());
36             CHECK(!j.is_primitive());
37             CHECK(j.is_structured());
38         }
39 
40         SECTION("array")
41         {
42             json j {"foo", 1, 1u, 42.23, false};
43             CHECK(!j.is_null());
44             CHECK(!j.is_boolean());
45             CHECK(!j.is_number());
46             CHECK(!j.is_number_integer());
47             CHECK(!j.is_number_unsigned());
48             CHECK(!j.is_number_float());
49             CHECK(!j.is_binary());
50             CHECK(!j.is_object());
51             CHECK(j.is_array());
52             CHECK(!j.is_string());
53             CHECK(!j.is_discarded());
54             CHECK(!j.is_primitive());
55             CHECK(j.is_structured());
56         }
57 
58         SECTION("null")
59         {
60             json j(nullptr);
61             CHECK(j.is_null());
62             CHECK(!j.is_boolean());
63             CHECK(!j.is_number());
64             CHECK(!j.is_number_integer());
65             CHECK(!j.is_number_unsigned());
66             CHECK(!j.is_number_float());
67             CHECK(!j.is_binary());
68             CHECK(!j.is_object());
69             CHECK(!j.is_array());
70             CHECK(!j.is_string());
71             CHECK(!j.is_discarded());
72             CHECK(j.is_primitive());
73             CHECK(!j.is_structured());
74         }
75 
76         SECTION("boolean")
77         {
78             json j(true);
79             CHECK(!j.is_null());
80             CHECK(j.is_boolean());
81             CHECK(!j.is_number());
82             CHECK(!j.is_number_integer());
83             CHECK(!j.is_number_unsigned());
84             CHECK(!j.is_number_float());
85             CHECK(!j.is_binary());
86             CHECK(!j.is_object());
87             CHECK(!j.is_array());
88             CHECK(!j.is_string());
89             CHECK(!j.is_discarded());
90             CHECK(j.is_primitive());
91             CHECK(!j.is_structured());
92         }
93 
94         SECTION("string")
95         {
96             json j("Hello world");
97             CHECK(!j.is_null());
98             CHECK(!j.is_boolean());
99             CHECK(!j.is_number());
100             CHECK(!j.is_number_integer());
101             CHECK(!j.is_number_unsigned());
102             CHECK(!j.is_number_float());
103             CHECK(!j.is_binary());
104             CHECK(!j.is_object());
105             CHECK(!j.is_array());
106             CHECK(j.is_string());
107             CHECK(!j.is_discarded());
108             CHECK(j.is_primitive());
109             CHECK(!j.is_structured());
110         }
111 
112         SECTION("number (integer)")
113         {
114             json j(42);
115             CHECK(!j.is_null());
116             CHECK(!j.is_boolean());
117             CHECK(j.is_number());
118             CHECK(j.is_number_integer());
119             CHECK(!j.is_number_unsigned());
120             CHECK(!j.is_number_float());
121             CHECK(!j.is_binary());
122             CHECK(!j.is_object());
123             CHECK(!j.is_array());
124             CHECK(!j.is_string());
125             CHECK(!j.is_discarded());
126             CHECK(j.is_primitive());
127             CHECK(!j.is_structured());
128         }
129 
130         SECTION("number (unsigned)")
131         {
132             json j(42u);
133             CHECK(!j.is_null());
134             CHECK(!j.is_boolean());
135             CHECK(j.is_number());
136             CHECK(j.is_number_integer());
137             CHECK(j.is_number_unsigned());
138             CHECK(!j.is_number_float());
139             CHECK(!j.is_binary());
140             CHECK(!j.is_object());
141             CHECK(!j.is_array());
142             CHECK(!j.is_string());
143             CHECK(!j.is_discarded());
144             CHECK(j.is_primitive());
145             CHECK(!j.is_structured());
146         }
147 
148         SECTION("number (floating-point)")
149         {
150             json j(42.23);
151             CHECK(!j.is_null());
152             CHECK(!j.is_boolean());
153             CHECK(j.is_number());
154             CHECK(!j.is_number_integer());
155             CHECK(!j.is_number_unsigned());
156             CHECK(j.is_number_float());
157             CHECK(!j.is_binary());
158             CHECK(!j.is_object());
159             CHECK(!j.is_array());
160             CHECK(!j.is_string());
161             CHECK(!j.is_discarded());
162             CHECK(j.is_primitive());
163             CHECK(!j.is_structured());
164         }
165 
166         SECTION("binary")
167         {
168             json j(json::value_t::binary);
169             CHECK(!j.is_null());
170             CHECK(!j.is_boolean());
171             CHECK(!j.is_number());
172             CHECK(!j.is_number_integer());
173             CHECK(!j.is_number_unsigned());
174             CHECK(!j.is_number_float());
175             CHECK(j.is_binary());
176             CHECK(!j.is_object());
177             CHECK(!j.is_array());
178             CHECK(!j.is_string());
179             CHECK(!j.is_discarded());
180             CHECK(j.is_primitive());
181             CHECK(!j.is_structured());
182         }
183 
184         SECTION("discarded")
185         {
186             json j(json::value_t::discarded);
187             CHECK(!j.is_null());
188             CHECK(!j.is_boolean());
189             CHECK(!j.is_number());
190             CHECK(!j.is_number_integer());
191             CHECK(!j.is_number_unsigned());
192             CHECK(!j.is_number_float());
193             CHECK(!j.is_binary());
194             CHECK(!j.is_object());
195             CHECK(!j.is_array());
196             CHECK(!j.is_string());
197             CHECK(j.is_discarded());
198             CHECK(!j.is_primitive());
199             CHECK(!j.is_structured());
200         }
201     }
202 
203     SECTION("serialization")
204     {
205         json j {{"object", json::object()}, {"array", {1, 2, 3, 4}}, {"number", 42}, {"boolean", false}, {"null", nullptr}, {"string", "Hello world"} };
206 
207         SECTION("no indent / indent=-1")
208         {
209             CHECK(j.dump() ==
210                   "{\"array\":[1,2,3,4],\"boolean\":false,\"null\":null,\"number\":42,\"object\":{},\"string\":\"Hello world\"}");
211 
212             CHECK(j.dump() == j.dump(-1));
213         }
214 
215         SECTION("indent=0")
216         {
217             CHECK(j.dump(0) ==
218                   "{\n\"array\": [\n1,\n2,\n3,\n4\n],\n\"boolean\": false,\n\"null\": null,\n\"number\": 42,\n\"object\": {},\n\"string\": \"Hello world\"\n}");
219         }
220 
221         SECTION("indent=1, space='\t'")
222         {
223             CHECK(j.dump(1, '\t') ==
224                   "{\n\t\"array\": [\n\t\t1,\n\t\t2,\n\t\t3,\n\t\t4\n\t],\n\t\"boolean\": false,\n\t\"null\": null,\n\t\"number\": 42,\n\t\"object\": {},\n\t\"string\": \"Hello world\"\n}");
225         }
226 
227         SECTION("indent=4")
228         {
229             CHECK(j.dump(4) ==
230                   "{\n    \"array\": [\n        1,\n        2,\n        3,\n        4\n    ],\n    \"boolean\": false,\n    \"null\": null,\n    \"number\": 42,\n    \"object\": {},\n    \"string\": \"Hello world\"\n}");
231         }
232 
233         SECTION("indent=x")
234         {
235             CHECK(j.dump().size() == 94);
236             CHECK(j.dump(1).size() == 127);
237             CHECK(j.dump(2).size() == 142);
238             CHECK(j.dump(512).size() == 7792);
239 
240             // important test, because it yields a resize of the indent_string
241             // inside the dump() function
242             CHECK(j.dump(1024).size() == 15472);
243 
244             const auto binary = json::binary({1, 2, 3}, 128);
245             CHECK(binary.dump(1024).size() == 2086);
246         }
247 
248         SECTION("dump and floating-point numbers")
249         {
250             auto s = json(42.23).dump();
251             CHECK(s.find("42.23") != std::string::npos);
252         }
253 
254         SECTION("dump and small floating-point numbers")
255         {
256             auto s = json(1.23456e-78).dump();
257             CHECK(s.find("1.23456e-78") != std::string::npos);
258         }
259 
260         SECTION("dump and non-ASCII characters")
261         {
262             CHECK(json("ä").dump() == "\"ä\"");
263             CHECK(json("Ö").dump() == "\"Ö\"");
264             CHECK(json("❤️").dump() == "\"❤️\"");
265         }
266 
267         SECTION("dump with ensure_ascii and non-ASCII characters")
268         {
269             CHECK(json("ä").dump(-1, ' ', true) == "\"\\u00e4\"");
270             CHECK(json("Ö").dump(-1, ' ', true) == "\"\\u00d6\"");
271             CHECK(json("❤️").dump(-1, ' ', true) == "\"\\u2764\\ufe0f\"");
272         }
273 
274         SECTION("full Unicode escaping to ASCII")
275         {
276             SECTION("parsing yields the same JSON value")
277             {
278                 std::ifstream f_escaped(TEST_DATA_DIRECTORY "/json_nlohmann_tests/all_unicode_ascii.json");
279                 std::ifstream f_unescaped(TEST_DATA_DIRECTORY "/json_nlohmann_tests/all_unicode.json");
280 
281                 json j1 = json::parse(f_escaped);
282                 json j2 = json::parse(f_unescaped);
283                 CHECK(j1 == j2);
284             }
285 
286             SECTION("dumping yields the same JSON text")
287             {
288                 std::ifstream f_escaped(TEST_DATA_DIRECTORY "/json_nlohmann_tests/all_unicode_ascii.json");
289                 std::ifstream f_unescaped(TEST_DATA_DIRECTORY "/json_nlohmann_tests/all_unicode.json");
290 
291                 json value = json::parse(f_unescaped);
292                 std::string text = value.dump(4, ' ', true);
293 
294                 std::string expected((std::istreambuf_iterator<char>(f_escaped)),
295                                      std::istreambuf_iterator<char>());
296                 CHECK(text == expected);
297             }
298         }
299 
300         SECTION("serialization of discarded element")
301         {
302             json j_discarded(json::value_t::discarded);
303             CHECK(j_discarded.dump() == "<discarded>");
304         }
305 
306         SECTION("check that precision is reset after serialization")
307         {
308             // create stringstream and set precision
309             std::stringstream ss;
310             ss.precision(3);
311             ss << 3.141592653589793 << std::fixed;
312             CHECK(ss.str() == "3.14");
313 
314             // reset stringstream
315             ss.str(std::string());
316 
317             // use stringstream for JSON serialization
318             json j_number = 3.14159265358979;
319             ss << j_number;
320 
321             // check that precision has been overridden during serialization
322             CHECK(ss.str() == "3.14159265358979");
323 
324             // check that precision has been restored
325             CHECK(ss.precision() == 3);
326         }
327     }
328 
329     SECTION("round trips")
330     {
331         for (const auto& s :
332                 {"3.141592653589793", "1000000000000000010E5"
333                 })
334         {
335             json j1 = json::parse(s);
336             std::string s1 = j1.dump();
337             json j2 = json::parse(s1);
338             std::string s2 = j2.dump();
339             CHECK(s1 == s2);
340         }
341     }
342 
343     SECTION("return the type of the object (explicit)")
344     {
345         SECTION("null")
346         {
347             json j = nullptr;
348             CHECK(j.type() == json::value_t::null);
349         }
350 
351         SECTION("object")
352         {
353             json j = {{"foo", "bar"}};
354             CHECK(j.type() == json::value_t::object);
355         }
356 
357         SECTION("array")
358         {
359             json j = {1, 2, 3, 4};
360             CHECK(j.type() == json::value_t::array);
361         }
362 
363         SECTION("boolean")
364         {
365             json j = true;
366             CHECK(j.type() == json::value_t::boolean);
367         }
368 
369         SECTION("string")
370         {
371             json j = "Hello world";
372             CHECK(j.type() == json::value_t::string);
373         }
374 
375         SECTION("number (integer)")
376         {
377             json j = 23;
378             CHECK(j.type() == json::value_t::number_integer);
379         }
380 
381         SECTION("number (unsigned)")
382         {
383             json j = 23u;
384             CHECK(j.type() == json::value_t::number_unsigned);
385         }
386 
387         SECTION("number (floating-point)")
388         {
389             json j = 42.23;
390             CHECK(j.type() == json::value_t::number_float);
391         }
392     }
393 
394     SECTION("return the type of the object (implicit)")
395     {
396         SECTION("null")
397         {
398             json j = nullptr;
399             json::value_t t = j;
400             CHECK(t == j.type());
401         }
402 
403         SECTION("object")
404         {
405             json j = {{"foo", "bar"}};
406             json::value_t t = j;
407             CHECK(t == j.type());
408         }
409 
410         SECTION("array")
411         {
412             json j = {1, 2, 3, 4};
413             json::value_t t = j;
414             CHECK(t == j.type());
415         }
416 
417         SECTION("boolean")
418         {
419             json j = true;
420             json::value_t t = j;
421             CHECK(t == j.type());
422         }
423 
424         SECTION("string")
425         {
426             json j = "Hello world";
427             json::value_t t = j;
428             CHECK(t == j.type());
429         }
430 
431         SECTION("number (integer)")
432         {
433             json j = 23;
434             json::value_t t = j;
435             CHECK(t == j.type());
436         }
437 
438         SECTION("number (unsigned)")
439         {
440             json j = 23u;
441             json::value_t t = j;
442             CHECK(t == j.type());
443         }
444 
445         SECTION("number (floating-point)")
446         {
447             json j = 42.23;
448             json::value_t t = j;
449             CHECK(t == j.type());
450         }
451 
452         SECTION("binary")
453         {
454             json j = json::binary({});
455             json::value_t t = j;
456             CHECK(t == j.type());
457         }
458     }
459 }
460