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// cmake/test.cmake selects the C++ standard versions with which to build a 10// unit test based on the presence of JSON_HAS_CPP_<VERSION> macros. 11// When using macros that are only defined for particular versions of the standard 12// (e.g., JSON_HAS_FILESYSTEM for C++17 and up), please mention the corresponding 13// version macro in a comment close by, like this: 14// JSON_HAS_CPP_<VERSION> (do not remove; see note at top of file) 15 16#include "doctest_compatibility.h" 17 18// for some reason including this after the json header leads to linker errors with VS 2017... 19#include <locale> 20 21#define JSON_TESTS_PRIVATE 22#include <nlohmann/json.hpp> 23using json = nlohmann::json; 24using ordered_json = nlohmann::ordered_json; 25#ifdef JSON_TEST_NO_GLOBAL_UDLS 26 using namespace nlohmann::literals; // NOLINT(google-build-using-namespace) 27#endif 28 29#include <cstdio> 30#include <list> 31#include <type_traits> 32#include <utility> 33 34#ifdef JSON_HAS_CPP_17 35 #include <any> 36 #include <variant> 37#endif 38 39#ifdef JSON_HAS_CPP_20 40 #include <span> 41#endif 42 43// NLOHMANN_JSON_SERIALIZE_ENUM uses a static std::pair 44DOCTEST_CLANG_SUPPRESS_WARNING_PUSH 45DOCTEST_CLANG_SUPPRESS_WARNING("-Wexit-time-destructors") 46 47///////////////////////////////////////////////////////////////////// 48// for #1021 49///////////////////////////////////////////////////////////////////// 50 51using float_json = nlohmann::basic_json<std::map, std::vector, std::string, bool, std::int64_t, std::uint64_t, float>; 52 53///////////////////////////////////////////////////////////////////// 54// for #1647 55///////////////////////////////////////////////////////////////////// 56namespace 57{ 58struct NonDefaultFromJsonStruct 59{}; 60 61inline bool operator==(NonDefaultFromJsonStruct const& /*unused*/, NonDefaultFromJsonStruct const& /*unused*/) 62{ 63 return true; 64} 65 66enum class for_1647 67{ 68 one, 69 two 70}; 71 72// NOLINTNEXTLINE(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays): this is a false positive 73NLOHMANN_JSON_SERIALIZE_ENUM(for_1647, 74{ 75 {for_1647::one, "one"}, 76 {for_1647::two, "two"}, 77}) 78} // namespace 79 80///////////////////////////////////////////////////////////////////// 81// for #1299 82///////////////////////////////////////////////////////////////////// 83 84struct Data 85{ 86 Data() = default; 87 Data(std::string a_, std::string b_) 88 : a(std::move(a_)) 89 , b(std::move(b_)) 90 {} 91 std::string a{}; 92 std::string b{}; 93}; 94 95void from_json(const json& j, Data& data); 96void from_json(const json& j, Data& data) 97{ 98 j["a"].get_to(data.a); 99 j["b"].get_to(data.b); 100} 101 102bool operator==(Data const& lhs, Data const& rhs); 103bool operator==(Data const& lhs, Data const& rhs) 104{ 105 return lhs.a == rhs.a && lhs.b == rhs.b; 106} 107 108//bool operator!=(Data const& lhs, Data const& rhs) 109//{ 110// return !(lhs == rhs); 111//} 112 113namespace nlohmann 114{ 115template<> 116struct adl_serializer<NonDefaultFromJsonStruct> 117{ 118 static NonDefaultFromJsonStruct from_json(json const& /*unused*/) noexcept 119 { 120 return {}; 121 } 122}; 123} // namespace nlohmann 124 125///////////////////////////////////////////////////////////////////// 126// for #1805 127///////////////////////////////////////////////////////////////////// 128 129struct NotSerializableData 130{ 131 int mydata; 132 float myfloat; 133}; 134 135///////////////////////////////////////////////////////////////////// 136// for #2574 137///////////////////////////////////////////////////////////////////// 138 139struct NonDefaultConstructible 140{ 141 explicit NonDefaultConstructible(int a) 142 : x(a) 143 {} 144 int x; 145}; 146 147namespace nlohmann 148{ 149template<> 150struct adl_serializer<NonDefaultConstructible> 151{ 152 static NonDefaultConstructible from_json(json const& j) 153 { 154 return NonDefaultConstructible(j.get<int>()); 155 } 156}; 157} // namespace nlohmann 158 159///////////////////////////////////////////////////////////////////// 160// for #2824 161///////////////////////////////////////////////////////////////////// 162 163class sax_no_exception : public nlohmann::detail::json_sax_dom_parser<json> 164{ 165 public: 166 explicit sax_no_exception(json& j) 167 : nlohmann::detail::json_sax_dom_parser<json>(j, false) 168 {} 169 170 static bool parse_error(std::size_t /*position*/, const std::string& /*last_token*/, const json::exception& ex) 171 { 172 error_string = new std::string(ex.what()); // NOLINT(cppcoreguidelines-owning-memory) 173 return false; 174 } 175 176 static std::string* error_string; 177}; 178 179std::string* sax_no_exception::error_string = nullptr; 180 181///////////////////////////////////////////////////////////////////// 182// for #2982 183///////////////////////////////////////////////////////////////////// 184 185template<class T> 186class my_allocator : public std::allocator<T> 187{ 188 public: 189 using std::allocator<T>::allocator; 190}; 191 192///////////////////////////////////////////////////////////////////// 193// for #3077 194///////////////////////////////////////////////////////////////////// 195 196class FooAlloc 197{}; 198 199class Foo 200{ 201 public: 202 explicit Foo(const FooAlloc& /* unused */ = FooAlloc()) {} 203 204 bool value = false; 205}; 206 207class FooBar 208{ 209 public: 210 Foo foo{}; 211}; 212 213inline void from_json(const nlohmann::json& j, FooBar& fb) 214{ 215 j.at("value").get_to(fb.foo.value); 216} 217 218///////////////////////////////////////////////////////////////////// 219// for #3171 220///////////////////////////////////////////////////////////////////// 221 222struct for_3171_base // NOLINT(cppcoreguidelines-special-member-functions) 223{ 224 for_3171_base(const std::string& /*unused*/ = {}) {} 225 virtual ~for_3171_base() = default; 226 227 virtual void _from_json(const json& j) 228 { 229 j.at("str").get_to(str); 230 } 231 232 std::string str{}; 233}; 234 235struct for_3171_derived : public for_3171_base 236{ 237 for_3171_derived() = default; 238 explicit for_3171_derived(const std::string& /*unused*/) { } 239}; 240 241inline void from_json(const json& j, for_3171_base& tb) 242{ 243 tb._from_json(j); 244} 245 246///////////////////////////////////////////////////////////////////// 247// for #3312 248///////////////////////////////////////////////////////////////////// 249 250#ifdef JSON_HAS_CPP_20 251struct for_3312 252{ 253 std::string name; 254}; 255 256inline void from_json(const json& j, for_3312& obj) 257{ 258 j.at("name").get_to(obj.name); 259} 260#endif 261 262///////////////////////////////////////////////////////////////////// 263// for #3204 264///////////////////////////////////////////////////////////////////// 265 266struct for_3204_foo 267{ 268 for_3204_foo() = default; 269 explicit for_3204_foo(std::string /*unused*/) {} // NOLINT(performance-unnecessary-value-param) 270}; 271 272struct for_3204_bar 273{ 274 enum constructed_from_t 275 { 276 constructed_from_none = 0, 277 constructed_from_foo = 1, 278 constructed_from_json = 2 279 }; 280 281 explicit for_3204_bar(std::function<void(for_3204_foo)> /*unused*/) noexcept // NOLINT(performance-unnecessary-value-param) 282 : constructed_from(constructed_from_foo) {} 283 explicit for_3204_bar(std::function<void(json)> /*unused*/) noexcept // NOLINT(performance-unnecessary-value-param) 284 : constructed_from(constructed_from_json) {} 285 286 constructed_from_t constructed_from = constructed_from_none; 287}; 288 289///////////////////////////////////////////////////////////////////// 290// for #3333 291///////////////////////////////////////////////////////////////////// 292 293struct for_3333 final 294{ 295 for_3333(int x_ = 0, int y_ = 0) : x(x_), y(y_) {} 296 297 template <class T> 298 for_3333(const T& /*unused*/) 299 { 300 CHECK(false); 301 } 302 303 int x = 0; 304 int y = 0; 305}; 306 307template <> 308inline for_3333::for_3333(const json& j) 309 : for_3333(j.value("x", 0), j.value("y", 0)) 310{} 311 312TEST_CASE("regression tests 2") 313{ 314 SECTION("issue #1001 - Fix memory leak during parser callback") 315 { 316 const auto* geojsonExample = R"( 317 { "type": "FeatureCollection", 318 "features": [ 319 { "type": "Feature", 320 "geometry": {"type": "Point", "coordinates": [102.0, 0.5]}, 321 "properties": {"prop0": "value0"} 322 }, 323 { "type": "Feature", 324 "geometry": { 325 "type": "LineString", 326 "coordinates": [ 327 [102.0, 0.0], [103.0, 1.0], [104.0, 0.0], [105.0, 1.0] 328 ] 329 }, 330 "properties": { 331 "prop0": "value0", 332 "prop1": 0.0 333 } 334 }, 335 { "type": "Feature", 336 "geometry": { 337 "type": "Polygon", 338 "coordinates": [ 339 [ [100.0, 0.0], [101.0, 0.0], [101.0, 1.0], 340 [100.0, 1.0], [100.0, 0.0] ] 341 ] 342 }, 343 "properties": { 344 "prop0": "value0", 345 "prop1": {"this": "that"} 346 } 347 } 348 ] 349 })"; 350 351 json::parser_callback_t cb = [&](int /*level*/, json::parse_event_t event, json & parsed) noexcept 352 { 353 // skip uninteresting events 354 if (event == json::parse_event_t::value && !parsed.is_primitive()) 355 { 356 return false; 357 } 358 359 switch (event) 360 { 361 case json::parse_event_t::key: 362 { 363 return true; 364 } 365 case json::parse_event_t::value: 366 { 367 return false; 368 } 369 case json::parse_event_t::object_start: 370 { 371 return true; 372 } 373 case json::parse_event_t::object_end: 374 { 375 return false; 376 } 377 case json::parse_event_t::array_start: 378 { 379 return true; 380 } 381 case json::parse_event_t::array_end: 382 { 383 return false; 384 } 385 386 default: 387 { 388 return true; 389 } 390 } 391 }; 392 393 auto j = json::parse(geojsonExample, cb, true); 394 CHECK(j == json()); 395 } 396 397 SECTION("issue #1021 - to/from_msgpack only works with standard typization") 398 { 399 float_json j = 1000.0; 400 CHECK(float_json::from_cbor(float_json::to_cbor(j)) == j); 401 CHECK(float_json::from_msgpack(float_json::to_msgpack(j)) == j); 402 CHECK(float_json::from_ubjson(float_json::to_ubjson(j)) == j); 403 404 float_json j2 = {1000.0, 2000.0, 3000.0}; 405 CHECK(float_json::from_ubjson(float_json::to_ubjson(j2, true, true)) == j2); 406 } 407 408 SECTION("issue #1045 - Using STL algorithms with JSON containers with expected results?") 409 { 410 json diffs = nlohmann::json::array(); 411 json m1{{"key1", 42}}; 412 json m2{{"key2", 42}}; 413 auto p1 = m1.items(); 414 auto p2 = m2.items(); 415 416 using it_type = decltype(p1.begin()); 417 418 std::set_difference( 419 p1.begin(), 420 p1.end(), 421 p2.begin(), 422 p2.end(), 423 std::inserter(diffs, diffs.end()), 424 [&](const it_type & e1, const it_type & e2) -> bool 425 { 426 using comper_pair = std::pair<std::string, decltype(e1.value())>; // Trying to avoid unneeded copy 427 return comper_pair(e1.key(), e1.value()) < comper_pair(e2.key(), e2.value()); // Using pair comper 428 }); 429 430 CHECK(diffs.size() == 1); // Note the change here, was 2 431 } 432 433#ifdef JSON_HAS_CPP_17 434 SECTION("issue #1292 - Serializing std::variant causes stack overflow") 435 { 436 static_assert(!std::is_constructible<json, std::variant<int, float>>::value, "unexpected value"); 437 } 438#endif 439 440 SECTION("issue #1299 - compile error in from_json converting to container " 441 "with std::pair") 442 { 443 json j = 444 { 445 {"1", {{"a", "testa_1"}, {"b", "testb_1"}}}, 446 {"2", {{"a", "testa_2"}, {"b", "testb_2"}}}, 447 {"3", {{"a", "testa_3"}, {"b", "testb_3"}}}, 448 }; 449 450 std::map<std::string, Data> expected 451 { 452 {"1", {"testa_1", "testb_1"}}, 453 {"2", {"testa_2", "testb_2"}}, 454 {"3", {"testa_3", "testb_3"}}, 455 }; 456 const auto data = j.get<decltype(expected)>(); 457 CHECK(expected == data); 458 } 459 460 SECTION("issue #1445 - buffer overflow in dumping invalid utf-8 strings") 461 { 462 SECTION("a bunch of -1, ensure_ascii=true") 463 { 464 const auto length = 300; 465 466 json dump_test; 467 dump_test["1"] = std::string(length, -1); 468 469 std::string expected = R"({"1":")"; 470 for (int i = 0; i < length; ++i) 471 { 472 expected += "\\ufffd"; 473 } 474 expected += "\"}"; 475 476 auto s = dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace); 477 CHECK(s == expected); 478 } 479 SECTION("a bunch of -2, ensure_ascii=false") 480 { 481 const auto length = 500; 482 483 json dump_test; 484 dump_test["1"] = std::string(length, -2); 485 486 std::string expected = R"({"1":")"; 487 for (int i = 0; i < length; ++i) 488 { 489 expected += "\xEF\xBF\xBD"; 490 } 491 expected += "\"}"; 492 493 auto s = dump_test.dump(-1, ' ', false, nlohmann::json::error_handler_t::replace); 494 CHECK(s == expected); 495 } 496 SECTION("test case in issue #1445") 497 { 498 nlohmann::json dump_test; 499 const std::array<int, 108> data = 500 { 501 {109, 108, 103, 125, -122, -53, 115, 18, 3, 0, 102, 19, 1, 15, -110, 13, -3, -1, -81, 32, 2, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -80, 2, 0, 0, 96, -118, 46, -116, 46, 109, -84, -87, 108, 14, 109, -24, -83, 13, -18, -51, -83, -52, -115, 14, 6, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 3, 0, 0, 0, 35, -74, -73, 55, 57, -128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, 0, 0, -96, -54, -28, -26} 502 }; 503 std::string s; 504 for (int i : data) 505 { 506 s += static_cast<char>(i); 507 } 508 dump_test["1"] = s; 509 dump_test.dump(-1, ' ', true, nlohmann::json::error_handler_t::replace); 510 } 511 } 512 513 SECTION("issue #1447 - Integer Overflow (OSS-Fuzz 12506)") 514 { 515 json j = json::parse("[-9223372036854775808]"); 516 CHECK(j.dump() == "[-9223372036854775808]"); 517 } 518 519 SECTION("issue #1708 - minimum value of int64_t can be outputted") 520 { 521 constexpr auto smallest = (std::numeric_limits<int64_t>::min)(); 522 json j = smallest; 523 CHECK(j.dump() == std::to_string(smallest)); 524 } 525 526 SECTION("issue #1727 - Contains with non-const lvalue json_pointer picks the wrong overload") 527 { 528 json j = {{"root", {{"settings", {{"logging", true}}}}}}; 529 530 auto jptr1 = "/root/settings/logging"_json_pointer; 531 auto jptr2 = json::json_pointer{"/root/settings/logging"}; 532 533 CHECK(j.contains(jptr1)); 534 CHECK(j.contains(jptr2)); 535 } 536 537 SECTION("issue #1647 - compile error when deserializing enum if both non-default from_json and non-member operator== exists for other type") 538 { 539 // does not compile on ICPC when targeting C++20 540#if !(defined(__INTEL_COMPILER) && __cplusplus >= 202000) 541 { 542 json j; 543 NonDefaultFromJsonStruct x(j); 544 NonDefaultFromJsonStruct y; 545 CHECK(x == y); 546 } 547#endif 548 549 auto val = nlohmann::json("one").get<for_1647>(); 550 CHECK(val == for_1647::one); 551 json j = val; 552 } 553 554 SECTION("issue #1715 - json::from_cbor does not respect allow_exceptions = false when input is string literal") 555 { 556 SECTION("string literal") 557 { 558 json cbor = json::from_cbor("B", true, false); 559 CHECK(cbor.is_discarded()); 560 } 561 562 SECTION("string array") 563 { 564 const std::array<char, 2> input = {{'B', 0x00}}; 565 json cbor = json::from_cbor(input, true, false); 566 CHECK(cbor.is_discarded()); 567 } 568 569 SECTION("std::string") 570 { 571 json cbor = json::from_cbor(std::string("B"), true, false); 572 CHECK(cbor.is_discarded()); 573 } 574 } 575 576 SECTION("issue #1805 - A pair<T1, T2> is json constructible only if T1 and T2 are json constructible") 577 { 578 static_assert(!std::is_constructible<json, std::pair<std::string, NotSerializableData>>::value, "unexpected result"); 579 static_assert(!std::is_constructible<json, std::pair<NotSerializableData, std::string>>::value, "unexpected result"); 580 static_assert(std::is_constructible<json, std::pair<int, std::string>>::value, "unexpected result"); 581 } 582 SECTION("issue #1825 - A tuple<Args..> is json constructible only if all T in Args are json constructible") 583 { 584 static_assert(!std::is_constructible<json, std::tuple<std::string, NotSerializableData>>::value, "unexpected result"); 585 static_assert(!std::is_constructible<json, std::tuple<NotSerializableData, std::string>>::value, "unexpected result"); 586 static_assert(std::is_constructible<json, std::tuple<int, std::string>>::value, "unexpected result"); 587 } 588 589 SECTION("issue #1983 - JSON patch diff for op=add formation is not as per standard (RFC 6902)") 590 { 591 const auto source = R"({ "foo": [ "1", "2" ] })"_json; 592 const auto target = R"({"foo": [ "1", "2", "3" ]})"_json; 593 const auto result = json::diff(source, target); 594 CHECK(result.dump() == R"([{"op":"add","path":"/foo/-","value":"3"}])"); 595 } 596 597 SECTION("issue #2067 - cannot serialize binary data to text JSON") 598 { 599 const std::array<unsigned char, 23> data = {{0x81, 0xA4, 0x64, 0x61, 0x74, 0x61, 0xC4, 0x0F, 0x33, 0x30, 0x30, 0x32, 0x33, 0x34, 0x30, 0x31, 0x30, 0x37, 0x30, 0x35, 0x30, 0x31, 0x30}}; 600 json j = json::from_msgpack(data.data(), data.size()); 601 CHECK_NOTHROW( 602 j.dump(4, // Indent 603 ' ', // Indent char 604 false, // Ensure ascii 605 json::error_handler_t::strict // Error 606 )); 607 } 608 609 SECTION("PR #2181 - regression bug with lvalue") 610 { 611 // see https://github.com/nlohmann/json/pull/2181#issuecomment-653326060 612 json j{{"x", "test"}}; 613 std::string defval = "default value"; 614 auto val = j.value("x", defval); 615 auto val2 = j.value("y", defval); 616 } 617 618 SECTION("issue #2293 - eof doesn't cause parsing to stop") 619 { 620 std::vector<uint8_t> data = 621 { 622 0x7B, 623 0x6F, 624 0x62, 625 0x6A, 626 0x65, 627 0x63, 628 0x74, 629 0x20, 630 0x4F, 631 0x42 632 }; 633 json result = json::from_cbor(data, true, false); 634 CHECK(result.is_discarded()); 635 } 636 637 SECTION("issue #2315 - json.update and vector<pair>does not work with ordered_json") 638 { 639 nlohmann::ordered_json jsonAnimals = {{"animal", "dog"}}; 640 nlohmann::ordered_json jsonCat = {{"animal", "cat"}}; 641 jsonAnimals.update(jsonCat); 642 CHECK(jsonAnimals["animal"] == "cat"); 643 644 auto jsonAnimals_parsed = nlohmann::ordered_json::parse(jsonAnimals.dump()); 645 CHECK(jsonAnimals == jsonAnimals_parsed); 646 647 std::vector<std::pair<std::string, int64_t>> intData = {std::make_pair("aaaa", 11), 648 std::make_pair("bbb", 222) 649 }; 650 nlohmann::ordered_json jsonObj; 651 for (const auto& data : intData) 652 { 653 jsonObj[data.first] = data.second; 654 } 655 CHECK(jsonObj["aaaa"] == 11); 656 CHECK(jsonObj["bbb"] == 222); 657 } 658 659 SECTION("issue #2330 - ignore_comment=true fails on multiple consecutive lines starting with comments") 660 { 661 std::string ss = "//\n//\n{\n}\n"; 662 json j = json::parse(ss, nullptr, true, true); 663 CHECK(j.dump() == "{}"); 664 } 665 666#ifdef JSON_HAS_CPP_20 667 SECTION("issue #2546 - parsing containers of std::byte") 668 { 669 const char DATA[] = R"("Hello, world!")"; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) 670 const auto s = std::as_bytes(std::span(DATA)); 671 json j = json::parse(s); 672 CHECK(j.dump() == "\"Hello, world!\""); 673 } 674#endif 675 676 SECTION("issue #2574 - Deserialization to std::array, std::pair, and std::tuple with non-default constructable types fails") 677 { 678 SECTION("std::array") 679 { 680 { 681 json j = {7, 4}; 682 auto arr = j.get<std::array<NonDefaultConstructible, 2>>(); 683 CHECK(arr[0].x == 7); 684 CHECK(arr[1].x == 4); 685 } 686 687 { 688 json j = 7; 689 CHECK_THROWS_AS((j.get<std::array<NonDefaultConstructible, 1>>()), json::type_error); 690 } 691 } 692 693 SECTION("std::pair") 694 { 695 { 696 json j = {3, 8}; 697 auto p = j.get<std::pair<NonDefaultConstructible, NonDefaultConstructible>>(); 698 CHECK(p.first.x == 3); 699 CHECK(p.second.x == 8); 700 } 701 702 { 703 json j = {4, 1}; 704 auto p = j.get<std::pair<int, NonDefaultConstructible>>(); 705 CHECK(p.first == 4); 706 CHECK(p.second.x == 1); 707 } 708 709 { 710 json j = {6, 7}; 711 auto p = j.get<std::pair<NonDefaultConstructible, int>>(); 712 CHECK(p.first.x == 6); 713 CHECK(p.second == 7); 714 } 715 716 { 717 json j = 7; 718 CHECK_THROWS_AS((j.get<std::pair<NonDefaultConstructible, int>>()), json::type_error); 719 } 720 } 721 722 SECTION("std::tuple") 723 { 724 { 725 json j = {9}; 726 auto t = j.get<std::tuple<NonDefaultConstructible>>(); 727 CHECK(std::get<0>(t).x == 9); 728 } 729 730 { 731 json j = {9, 8, 7}; 732 auto t = j.get<std::tuple<NonDefaultConstructible, int, NonDefaultConstructible>>(); 733 CHECK(std::get<0>(t).x == 9); 734 CHECK(std::get<1>(t) == 8); 735 CHECK(std::get<2>(t).x == 7); 736 } 737 738 { 739 json j = 7; 740 CHECK_THROWS_AS((j.get<std::tuple<NonDefaultConstructible>>()), json::type_error); 741 } 742 } 743 } 744 745 SECTION("issue #2865 - ASAN detects memory leaks") 746 { 747 // the code below is expected to not leak memory 748 { 749 nlohmann::json o; 750 std::string s = "bar"; 751 752 nlohmann::to_json(o["foo"], s); 753 754 nlohmann::json p = o; 755 756 // call to_json with a non-null JSON value 757 nlohmann::to_json(p["foo"], s); 758 } 759 760 { 761 nlohmann::json o; 762 std::string s = "bar"; 763 764 nlohmann::to_json(o["foo"], s); 765 766 // call to_json with a non-null JSON value 767 nlohmann::to_json(o["foo"], s); 768 } 769 } 770 771 SECTION("issue #2824 - encoding of json::exception::what()") 772 { 773 json j; 774 sax_no_exception sax(j); 775 776 CHECK(!json::sax_parse("xyz", &sax)); 777 CHECK(*sax_no_exception::error_string == "[json.exception.parse_error.101] parse error at line 1, column 1: syntax error while parsing value - invalid literal; last read: 'x'"); 778 delete sax_no_exception::error_string; // NOLINT(cppcoreguidelines-owning-memory) 779 } 780 781 SECTION("issue #2825 - Properly constrain the basic_json conversion operator") 782 { 783 static_assert(std::is_copy_assignable<nlohmann::ordered_json>::value, "ordered_json must be copy assignable"); 784 } 785 786 SECTION("issue #2958 - Inserting in unordered json using a pointer retains the leading slash") 787 { 788 std::string p = "/root"; 789 790 json test1; 791 test1[json::json_pointer(p)] = json::object(); 792 CHECK(test1.dump() == "{\"root\":{}}"); 793 794 ordered_json test2; 795 test2[ordered_json::json_pointer(p)] = json::object(); 796 CHECK(test2.dump() == "{\"root\":{}}"); 797 798 // json::json_pointer and ordered_json::json_pointer are the same type; behave as above 799 ordered_json test3; 800 test3[json::json_pointer(p)] = json::object(); 801 CHECK(std::is_same<json::json_pointer::string_t, ordered_json::json_pointer::string_t>::value); 802 CHECK(test3.dump() == "{\"root\":{}}"); 803 } 804 805 SECTION("issue #2982 - to_{binary format} does not provide a mechanism for specifying a custom allocator for the returned type") 806 { 807 std::vector<std::uint8_t, my_allocator<std::uint8_t>> my_vector; 808 json j = {1, 2, 3, 4}; 809 json::to_cbor(j, my_vector); 810 json k = json::from_cbor(my_vector); 811 CHECK(j == k); 812 } 813 814#if JSON_HAS_FILESYSTEM || JSON_HAS_EXPERIMENTAL_FILESYSTEM 815 // JSON_HAS_CPP_17 (do not remove; see note at top of file) 816 SECTION("issue #3070 - Version 3.10.3 breaks backward-compatibility with 3.10.2 ") 817 { 818 nlohmann::detail::std_fs::path text_path("/tmp/text.txt"); 819 json j(text_path); 820 821 const auto j_path = j.get<nlohmann::detail::std_fs::path>(); 822 CHECK(j_path == text_path); 823 824#if DOCTEST_CLANG || DOCTEST_GCC >= DOCTEST_COMPILER(8, 4, 0) 825 // only known to work on Clang and GCC >=8.4 826 CHECK_THROWS_WITH_AS(nlohmann::detail::std_fs::path(json(1)), "[json.exception.type_error.302] type must be string, but is number", json::type_error); 827#endif 828 } 829#endif 830 831 SECTION("issue #3077 - explicit constructor with default does not compile") 832 { 833 json j; 834 j[0]["value"] = true; 835 std::vector<FooBar> foo; 836 j.get_to(foo); 837 } 838 839 SECTION("issue #3108 - ordered_json doesn't support range based erase") 840 { 841 ordered_json j = {1, 2, 2, 4}; 842 843 auto last = std::unique(j.begin(), j.end()); 844 j.erase(last, j.end()); 845 846 CHECK(j.dump() == "[1,2,4]"); 847 848 j.erase(std::remove_if(j.begin(), j.end(), [](const ordered_json & val) 849 { 850 return val == 2; 851 }), j.end()); 852 853 CHECK(j.dump() == "[1,4]"); 854 } 855 856 SECTION("issue #3343 - json and ordered_json are not interchangable") 857 { 858 json::object_t jobj({ { "product", "one" } }); 859 ordered_json::object_t ojobj({{"product", "one"}}); 860 861 auto jit = jobj.begin(); 862 auto ojit = ojobj.begin(); 863 864 CHECK(jit->first == ojit->first); 865 CHECK(jit->second.get<std::string>() == ojit->second.get<std::string>()); 866 } 867 868 SECTION("issue #3171 - if class is_constructible from std::string wrong from_json overload is being selected, compilation failed") 869 { 870 json j{{ "str", "value"}}; 871 872 // failed with: error: no match for ‘operator=’ (operand types are ‘for_3171_derived’ and ‘const nlohmann::basic_json<>::string_t’ 873 // {aka ‘const std::__cxx11::basic_string<char>’}) 874 // s = *j.template get_ptr<const typename BasicJsonType::string_t*>(); 875 auto td = j.get<for_3171_derived>(); 876 877 CHECK(td.str == "value"); 878 } 879 880#ifdef JSON_HAS_CPP_20 881 SECTION("issue #3312 - Parse to custom class from unordered_json breaks on G++11.2.0 with C++20") 882 { 883 // see test for #3171 884 ordered_json j = {{"name", "class"}}; 885 for_3312 obj{}; 886 887 j.get_to(obj); 888 889 CHECK(obj.name == "class"); 890 } 891#endif 892 893#if defined(JSON_HAS_CPP_17) && JSON_USE_IMPLICIT_CONVERSIONS 894 SECTION("issue #3428 - Error occurred when converting nlohmann::json to std::any") 895 { 896 json j; 897 std::any a1 = j; 898 std::any&& a2 = j; 899 900 CHECK(a1.type() == typeid(j)); 901 CHECK(a2.type() == typeid(j)); 902 } 903#endif 904 905 SECTION("issue #3204 - ambiguous regression") 906 { 907 for_3204_bar bar_from_foo([](for_3204_foo) noexcept {}); // NOLINT(performance-unnecessary-value-param) 908 for_3204_bar bar_from_json([](json) noexcept {}); // NOLINT(performance-unnecessary-value-param) 909 910 CHECK(bar_from_foo.constructed_from == for_3204_bar::constructed_from_foo); 911 CHECK(bar_from_json.constructed_from == for_3204_bar::constructed_from_json); 912 } 913 914 SECTION("issue #3333 - Ambiguous conversion from nlohmann::basic_json<> to custom class") 915 { 916 const json j 917 { 918 {"x", 1}, 919 {"y", 2} 920 }; 921 for_3333 p = j; 922 923 CHECK(p.x == 1); 924 CHECK(p.y == 2); 925 } 926} 927 928DOCTEST_CLANG_SUPPRESS_WARNING_POP 929