• 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 DOCTEST_GCC_SUPPRESS_WARNING("-Wfloat-equal")
32 
33 // for some reason including this after the json header leads to linker errors with VS 2017...
34 #include <locale>
35 
36 #define private public
37 #include <nlohmann/json.hpp>
38 using nlohmann::json;
39 #undef private
40 
41 #include <fstream>
42 #include <sstream>
43 #include <list>
44 #include <cstdio>
45 #include <test_data.hpp>
46 
47 #if (defined(__cplusplus) && __cplusplus >= 201703L) || (defined(_HAS_CXX17) && _HAS_CXX17 == 1) // fix for issue #464
48     #define JSON_HAS_CPP_17
49 #endif
50 
51 #ifdef JSON_HAS_CPP_17
52     #include <variant>
53 #endif
54 
55 /////////////////////////////////////////////////////////////////////
56 // for #1021
57 /////////////////////////////////////////////////////////////////////
58 
59 using float_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, float>;
60 
61 /////////////////////////////////////////////////////////////////////
62 // for #1647
63 /////////////////////////////////////////////////////////////////////
64 namespace
65 {
66 struct NonDefaultFromJsonStruct { };
67 
operator ==(NonDefaultFromJsonStruct const &,NonDefaultFromJsonStruct const &)68 inline bool operator== (NonDefaultFromJsonStruct const&, NonDefaultFromJsonStruct const&)
69 {
70     return true;
71 }
72 
73 enum class for_1647 { one, two };
74 
75 NLOHMANN_JSON_SERIALIZE_ENUM(for_1647,
76 {
77     {for_1647::one, "one"},
78     {for_1647::two, "two"},
79 })
80 }
81 
82 /////////////////////////////////////////////////////////////////////
83 // for #1299
84 /////////////////////////////////////////////////////////////////////
85 
86 struct Data
87 {
88     Data() = default;
DataData89     Data(const std::string& a_, const std::string b_) : a(a_), b(b_) {}
90     std::string a {};
91     std::string b {};
92 };
93 
from_json(const json & j,Data & data)94 void from_json(const json& j, Data& data)
95 {
96     j["a"].get_to(data.a);
97     j["b"].get_to(data.b);
98 }
99 
operator ==(Data const & lhs,Data const & rhs)100 bool operator==(Data const& lhs, Data const& rhs)
101 {
102     return lhs.a == rhs.a && lhs.b == rhs.b;
103 }
104 
105 //bool operator!=(Data const& lhs, Data const& rhs)
106 //{
107 //    return !(lhs == rhs);
108 //}
109 
110 namespace nlohmann
111 {
112 template <>
113 struct adl_serializer<NonDefaultFromJsonStruct>
114 {
from_jsonnlohmann::adl_serializer115     static NonDefaultFromJsonStruct from_json (json const&) noexcept
116     {
117         return {};
118     }
119 };
120 }
121 
122 /////////////////////////////////////////////////////////////////////
123 // for #1805
124 /////////////////////////////////////////////////////////////////////
125 
126 struct NotSerializableData
127 {
128     int mydata;
129     float myfloat;
130 };
131 
132 
133 TEST_CASE("regression tests 2")
134 {
135     SECTION("issue #1001 - Fix memory leak during parser callback")
136     {
137         auto geojsonExample = R"(
138           { "type": "FeatureCollection",
139             "features": [
140               { "type": "Feature",
141                 "geometry": {"type": "Point", "coordinates": [102.0, 0.5]},
142                 "properties": {"prop0": "value0"}
143                 },
144               { "type": "Feature",
145                 "geometry": {
146                   "type": "LineString",
147                   "coordinates": [
148                     [102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0]
149                     ]
150                   },
151                 "properties": {
152                   "prop0": "value0",
153                   "prop1": 0.0
154                   }
155                 },
156               { "type": "Feature",
157                  "geometry": {
158                    "type": "Polygon",
159                    "coordinates": [
160                      [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0],
161                        [100.0, 1.0], [100.0, 0.0] ]
162                      ]
163                  },
164                  "properties": {
165                    "prop0": "value0",
166                    "prop1": {"this": "that"}
167                    }
168                  }
169                ]
170              })";
171 
172         json::parser_callback_t cb = [&](int, json::parse_event_t event, json & parsed)
__anon5e5502030202(int, json::parse_event_t event, json & parsed) 173         {
174             // skip uninteresting events
175             if (event == json::parse_event_t::value && !parsed.is_primitive())
176             {
177                 return false;
178             }
179 
180             switch (event)
181             {
182                 case json::parse_event_t::key:
183                 {
184                     return true;
185                 }
186                 case json::parse_event_t::value:
187                 {
188                     return false;
189                 }
190                 case json::parse_event_t::object_start:
191                 {
192                     return true;
193                 }
194                 case json::parse_event_t::object_end:
195                 {
196                     return false;
197                 }
198                 case json::parse_event_t::array_start:
199                 {
200                     return true;
201                 }
202                 case json::parse_event_t::array_end:
203                 {
204                     return false;
205                 }
206 
207                 default:
208                 {
209                     return true;
210                 }
211             }
212         };
213 
214         auto j = json::parse(geojsonExample, cb, true);
215         CHECK(j == json());
216     }
217 
218     SECTION("issue #1021 - to/from_msgpack only works with standard typization")
219     {
220         float_json j = 1000.0;
221         CHECK(float_json::from_cbor(float_json::to_cbor(j)) == j);
222         CHECK(float_json::from_msgpack(float_json::to_msgpack(j)) == j);
223         CHECK(float_json::from_ubjson(float_json::to_ubjson(j)) == j);
224 
225         float_json j2 = {1000.0, 2000.0, 3000.0};
226         CHECK(float_json::from_ubjson(float_json::to_ubjson(j2, true, true)) == j2);
227     }
228 
229     SECTION("issue #1045 - Using STL algorithms with JSON containers with expected results?")
230     {
231         json diffs = nlohmann::json::array();
232         json m1{{"key1", 42}};
233         json m2{{"key2", 42}};
234         auto p1 = m1.items();
235         auto p2 = m2.items();
236 
237         using it_type = decltype(p1.begin());
238 
239         std::set_difference(
240             p1.begin(), p1.end(),
241             p2.begin(), p2.end(),
242             std::inserter(diffs, diffs.end()), [&](const it_type & e1, const it_type & e2) -> bool
__anon5e5502030302(const it_type & e1, const it_type & e2) 243         {
244             using comper_pair = std::pair<std::string, decltype(e1.value())>; // Trying to avoid unneeded copy
245             return comper_pair(e1.key(), e1.value()) < comper_pair(e2.key(), e2.value()); // Using pair comper
246         });
247 
248         CHECK(diffs.size() == 1); // Note the change here, was 2
249     }
250 
251 #ifdef JSON_HAS_CPP_17
252     SECTION("issue #1292 - Serializing std::variant causes stack overflow")
253     {
254         static_assert(
255             !std::is_constructible<json, std::variant<int, float>>::value, "");
256     }
257 #endif
258 
259     SECTION("issue #1299 - compile error in from_json converting to container "
260             "with std::pair")
261     {
262         json j =
263         {
264             {"1", {{"a", "testa_1"}, {"b", "testb_1"}}},
265             {"2", {{"a", "testa_2"}, {"b", "testb_2"}}},
266             {"3", {{"a", "testa_3"}, {"b", "testb_3"}}},
267         };
268 
269         std::map<std::string, Data> expected
270         {
271             {"1", {"testa_1", "testb_1"}},
272             {"2", {"testa_2", "testb_2"}},
273             {"3", {"testa_3", "testb_3"}},
274         };
275         const auto data = j.get<decltype(expected)>();
276         CHECK(expected == data);
277     }
278 
279     SECTION("issue #1445 - buffer overflow in dumping invalid utf-8 strings")
280     {
281         SECTION("a bunch of -1, ensure_ascii=true")
282         {
283             const auto length = 300;
284 
285             json dump_test;
286             dump_test["1"] = std::string(length, -1);
287 
288             std::string expected = "{\"1\":\"";
289             for (int i = 0; i < length; ++i)
290             {
291                 expected += "\\ufffd";
292             }
293             expected += "\"}";
294 
295             auto s = dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace);
296             CHECK(s == expected);
297         }
298         SECTION("a bunch of -2, ensure_ascii=false")
299         {
300             const auto length = 500;
301 
302             json dump_test;
303             dump_test["1"] = std::string(length, -2);
304 
305             std::string expected = "{\"1\":\"";
306             for (int i = 0; i < length; ++i)
307             {
308                 expected += "\xEF\xBF\xBD";
309             }
310             expected += "\"}";
311 
312             auto s = dump_test.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace);
313             CHECK(s == expected);
314         }
315         SECTION("test case in issue #1445")
316         {
317             nlohmann::json dump_test;
318             const int data[] =
319             {
320                 109,  108,  103,  125,  -122, -53,  115,
321                 18,   3,    0,    102,  19,   1,    15,
322                 -110, 13,   -3,   -1,   -81,  32,   2,
323                 0,    0,    0,    0,    0,    0,    0,
324                 8,    0,    0,    0,    0,    0,    0,
325                 0,    0,    0,    0,    0,    -80,  2,
326                 0,    0,    96,   -118, 46,   -116, 46,
327                 109,  -84,  -87,  108,  14,   109,  -24,
328                 -83,  13,   -18,  -51,  -83,  -52,  -115,
329                 14,   6,    32,   0,    0,    0,    0,
330                 0,    0,    0,    0,    0,    0,    0,
331                 64,   3,    0,    0,    0,    35,   -74,
332                 -73,  55,   57,   -128, 0,    0,    0,
333                 0,    0,    0,    0,    0,    0,    0,
334                 0,    0,    33,   0,    0,    0,    -96,
335                 -54,  -28,  -26
336             };
337             std::string s;
338             for (unsigned i = 0; i < sizeof(data) / sizeof(int); i++)
339             {
340                 s += static_cast<char>(data[i]);
341             }
342             dump_test["1"] = s;
343             dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace);
344         }
345     }
346 
347     SECTION("issue #1447 - Integer Overflow (OSS-Fuzz 12506)")
348     {
349         json j = json::parse("[-9223372036854775808]");
350         CHECK(j.dump() == "[-9223372036854775808]");
351     }
352 
353     SECTION("issue #1708 - minimum value of int64_t can be outputted")
354     {
355         constexpr auto smallest = (std::numeric_limits<int64_t>::min)();
356         json j = smallest;
357         CHECK(j.dump() == std::to_string(smallest));
358     }
359 
360     SECTION("issue #1727 - Contains with non-const lvalue json_pointer picks the wrong overload")
361     {
362         json j = {{"root", {{"settings", {{"logging", true}}}}}};
363 
364         auto jptr1 = "/root/settings/logging"_json_pointer;
365         auto jptr2 = json::json_pointer{"/root/settings/logging"};
366 
367         CHECK(j.contains(jptr1));
368         CHECK(j.contains(jptr2));
369     }
370 
371     SECTION("issue #1647 - compile error when deserializing enum if both non-default from_json and non-member operator== exists for other type")
372     {
373         {
374             json j;
375             NonDefaultFromJsonStruct x(j);
376             NonDefaultFromJsonStruct y;
377             CHECK(x == y);
378         }
379 
380         auto val = nlohmann::json("one").get<for_1647>();
381         CHECK(val == for_1647::one);
382         json j = val;
383     }
384 
385     SECTION("issue #1715 - json::from_cbor does not respect allow_exceptions = false when input is string literal")
386     {
387         SECTION("string literal")
388         {
389             json cbor = json::from_cbor("B", true, false);
390             CHECK(cbor.is_discarded());
391         }
392 
393         SECTION("string array")
394         {
395             const char input[] = { 'B', 0x00 };
396             json cbor = json::from_cbor(input, true, false);
397             CHECK(cbor.is_discarded());
398         }
399 
400         SECTION("std::string")
401         {
402             json cbor = json::from_cbor(std::string("B"), true, false);
403             CHECK(cbor.is_discarded());
404         }
405     }
406 
407     SECTION("issue #1805 - A pair<T1, T2> is json constructible only if T1 and T2 are json constructible")
408     {
409         static_assert(!std::is_constructible<json, std::pair<std::string, NotSerializableData>>::value, "");
410         static_assert(!std::is_constructible<json, std::pair<NotSerializableData, std::string>>::value, "");
411         static_assert(std::is_constructible<json, std::pair<int, std::string>>::value, "");
412     }
413     SECTION("issue #1825 - A tuple<Args..> is json constructible only if all T in Args are json constructible")
414     {
415         static_assert(!std::is_constructible<json, std::tuple<std::string, NotSerializableData>>::value, "");
416         static_assert(!std::is_constructible<json, std::tuple<NotSerializableData, std::string>>::value, "");
417         static_assert(std::is_constructible<json, std::tuple<int, std::string>>::value, "");
418     }
419 
420     SECTION("issue #1983 - JSON patch diff for op=add formation is not as per standard (RFC 6902)")
421     {
422         const auto source = R"({ "foo": [ "1", "2" ] })"_json;
423         const auto target = R"({"foo": [ "1", "2", "3" ]})"_json;
424         const auto result = json::diff(source, target);
425         CHECK(result.dump() == R"([{"op":"add","path":"/foo/-","value":"3"}])");
426     }
427 
428     SECTION("issue #2067 - cannot serialize binary data to text JSON")
429     {
430         const unsigned char data[] = {0x81, 0xA4, 0x64, 0x61, 0x74, 0x61, 0xC4, 0x0F, 0x33, 0x30, 0x30, 0x32, 0x33, 0x34, 0x30, 0x31, 0x30, 0x37, 0x30, 0x35, 0x30, 0x31, 0x30};
431         json j = json::from_msgpack(data, sizeof(data) / sizeof(data[0]));
432         CHECK_NOTHROW(
433             j.dump(4,                              // Indent
434                    ' ',                            // Indent char
435                    false,                          // Ensure ascii
436                    json::error_handler_t::strict  // Error
437                   )
438         );
439     }
440 
441     SECTION("PR #2181 - regression bug with lvalue")
442     {
443         // see https://github.com/nlohmann/json/pull/2181#issuecomment-653326060
444         json j{{"x", "test"}};
445         std::string defval = "default value";
446         auto val = j.value("x", defval);
447         auto val2 = j.value("y", defval);
448     }
449 
450     SECTION("issue #2293 - eof doesnt cause parsing to stop")
451     {
452         std::vector<uint8_t> data =
453         {
454             0x7B, 0x6F, 0x62, 0x6A, 0x65, 0x63, 0x74, 0x20, 0x4F, 0x42
455         };
456         json result = json::from_cbor(data, true, false);
457         CHECK(result.is_discarded());
458     }
459 
460     SECTION("issue #2315 - json.update and vector<pair>does not work with ordered_json")
461     {
462         nlohmann::ordered_json jsonAnimals = {{"animal", "dog"}};
463         nlohmann::ordered_json jsonCat = {{"animal", "cat"}};
464         jsonAnimals.update(jsonCat);
465         CHECK(jsonAnimals["animal"] == "cat");
466 
467         auto jsonAnimals_parsed = nlohmann::ordered_json::parse(jsonAnimals.dump());
468         CHECK(jsonAnimals == jsonAnimals_parsed);
469 
470         std::vector<std::pair<std::string, int64_t>> intData = {std::make_pair("aaaa", 11),
471                                                                 std::make_pair("bbb", 222)
472                                                                };
473         nlohmann::ordered_json jsonObj;
474         for (const auto& data : intData)
475         {
476             jsonObj[data.first] = data.second;
477         }
478         CHECK(jsonObj["aaaa"] == 11);
479         CHECK(jsonObj["bbb"] == 222);
480     }
481 
482     SECTION("issue #2330 - ignore_comment=true fails on multiple consecutive lines starting with comments")
483     {
484         std::string ss = "//\n//\n{\n}\n";
485         json j = json::parse(ss, nullptr, true, true);
486         CHECK(j.dump() == "{}");
487     }
488 }
489