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