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