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