// __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) // | | |__ | | | | | | version 3.11.2 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // // SPDX-FileCopyrightText: 2013-2022 Niels Lohmann // SPDX-License-Identifier: MIT #include "doctest_compatibility.h" #define JSON_TESTS_PRIVATE #include using nlohmann::json; #include #include #include #include #include #include #include #include TEST_CASE("constructors") { SECTION("create an empty value with a given type") { SECTION("null") { auto const t = json::value_t::null; json const j(t); CHECK(j.type() == t); } SECTION("discarded") { auto const t = json::value_t::discarded; json const j(t); CHECK(j.type() == t); } SECTION("object") { auto const t = json::value_t::object; json const j(t); CHECK(j.type() == t); } SECTION("array") { auto const t = json::value_t::array; json const j(t); CHECK(j.type() == t); } SECTION("boolean") { auto const t = json::value_t::boolean; json const j(t); CHECK(j.type() == t); CHECK(j == false); } SECTION("string") { auto const t = json::value_t::string; json const j(t); CHECK(j.type() == t); CHECK(j == ""); } SECTION("number_integer") { auto const t = json::value_t::number_integer; json const j(t); CHECK(j.type() == t); CHECK(j == 0); } SECTION("number_unsigned") { auto const t = json::value_t::number_unsigned; json const j(t); CHECK(j.type() == t); CHECK(j == 0); } SECTION("number_float") { auto const t = json::value_t::number_float; json const j(t); CHECK(j.type() == t); CHECK(j == 0.0); } SECTION("binary") { auto const t = json::value_t::binary; json const j(t); CHECK(j.type() == t); CHECK(j == json::binary({})); } } SECTION("create a null object (implicitly)") { SECTION("no parameter") { json const j{}; CHECK(j.type() == json::value_t::null); } } SECTION("create a null object (explicitly)") { SECTION("parameter") { json const j(nullptr); CHECK(j.type() == json::value_t::null); } } SECTION("create an object (explicit)") { SECTION("empty object") { json::object_t const o{}; json const j(o); CHECK(j.type() == json::value_t::object); } SECTION("filled object") { json::object_t const o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; json const j(o); CHECK(j.type() == json::value_t::object); } } SECTION("create an object (implicit)") { // reference object json::object_t const o_reference {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; json const j_reference(o_reference); SECTION("std::map") { std::map const o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; json const j(o); CHECK(j.type() == json::value_t::object); CHECK(j == j_reference); } SECTION("std::map #600") { const std::map m { {"a", "b"}, {"c", "d"}, {"e", "f"}, }; json const j(m); CHECK((j.get() == m)); } SECTION("std::map") { std::map const o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; json const j(o); CHECK(j.type() == json::value_t::object); CHECK(j == j_reference); } SECTION("std::multimap") { std::multimap const o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; json const j(o); CHECK(j.type() == json::value_t::object); CHECK(j == j_reference); } SECTION("std::unordered_map") { std::unordered_map const o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; json const j(o); CHECK(j.type() == json::value_t::object); CHECK(j == j_reference); } SECTION("std::unordered_multimap") { std::unordered_multimap const o {{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}; json const j(o); CHECK(j.type() == json::value_t::object); CHECK(j == j_reference); } SECTION("associative container literal") { json const j({{"a", json(1)}, {"b", json(1u)}, {"c", json(2.2)}, {"d", json(false)}, {"e", json("string")}, {"f", json()}}); CHECK(j.type() == json::value_t::object); CHECK(j == j_reference); } } SECTION("create an array (explicit)") { SECTION("empty array") { json::array_t const a{}; json const j(a); CHECK(j.type() == json::value_t::array); } SECTION("filled array") { json::array_t const a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json const j(a); CHECK(j.type() == json::value_t::array); } } SECTION("create an array (implicit)") { // reference array json::array_t const a_reference {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json const j_reference(a_reference); SECTION("std::list") { std::list const a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json const j(a); CHECK(j.type() == json::value_t::array); CHECK(j == j_reference); } SECTION("std::pair") { std::pair const p{1.0f, "string"}; json const j(p); CHECK(j.type() == json::value_t::array); CHECK(j.get() == p); REQUIRE(j.size() == 2); CHECK(j[0] == std::get<0>(p)); CHECK(j[1] == std::get<1>(p)); } SECTION("std::pair with discarded values") { json const j{1, 2.0, "string"}; const auto p = j.get>(); CHECK(p.first == j[0]); CHECK(p.second == j[1]); } SECTION("std::tuple") { const auto t = std::make_tuple(1.0, std::string{"string"}, 42, std::vector {0, 1}); json const j(t); CHECK(j.type() == json::value_t::array); REQUIRE(j.size() == 4); CHECK(j.get() == t); CHECK(j[0] == std::get<0>(t)); CHECK(j[1] == std::get<1>(t)); CHECK(j[2] == std::get<2>(t)); CHECK(j[3][0] == 0); CHECK(j[3][1] == 1); } SECTION("std::tuple with discarded values") { json const j{1, 2.0, "string", 42}; const auto t = j.get>(); CHECK(std::get<0>(t) == j[0]); CHECK(std::get<1>(t) == j[1]); // CHECK(std::get<2>(t) == j[2]); // commented out due to CI issue, see https://github.com/nlohmann/json/pull/3985 and https://github.com/nlohmann/json/issues/4025 } SECTION("std::pair/tuple/array failures") { json const j{1}; CHECK_THROWS_WITH_AS((j.get>()), "[json.exception.out_of_range.401] array index 1 is out of range", json::out_of_range&); CHECK_THROWS_WITH_AS((j.get>()), "[json.exception.out_of_range.401] array index 1 is out of range", json::out_of_range&); CHECK_THROWS_WITH_AS((j.get>()), "[json.exception.out_of_range.401] array index 1 is out of range", json::out_of_range&); } SECTION("std::forward_list") { std::forward_list const a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json const j(a); CHECK(j.type() == json::value_t::array); CHECK(j == j_reference); } SECTION("std::array") { std::array const a {{json(1), json(1u), json(2.2), json(false), json("string"), json()}}; json const j(a); CHECK(j.type() == json::value_t::array); CHECK(j == j_reference); const auto a2 = j.get>(); CHECK(a2 == a); } SECTION("std::valarray") { std::valarray const va = {1, 2, 3, 4, 5}; json const j(va); CHECK(j.type() == json::value_t::array); CHECK(j == json({1, 2, 3, 4, 5})); auto jva = j.get>(); CHECK(jva.size() == va.size()); for (size_t i = 0; i < jva.size(); ++i) { CHECK(va[i] == jva[i]); } } SECTION("std::valarray") { std::valarray const va = {1.2, 2.3, 3.4, 4.5, 5.6}; json const j(va); CHECK(j.type() == json::value_t::array); CHECK(j == json({1.2, 2.3, 3.4, 4.5, 5.6})); auto jva = j.get>(); CHECK(jva.size() == va.size()); for (size_t i = 0; i < jva.size(); ++i) { CHECK(va[i] == jva[i]); } } SECTION("std::vector") { std::vector const a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json const j(a); CHECK(j.type() == json::value_t::array); CHECK(j == j_reference); } SECTION("std::deque") { std::deque const a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json const j(a); CHECK(j.type() == json::value_t::array); CHECK(j == j_reference); } SECTION("std::set") { std::set const a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json const j(a); CHECK(j.type() == json::value_t::array); // we cannot really check for equality here } SECTION("std::unordered_set") { std::unordered_set const a {json(1), json(1u), json(2.2), json(false), json("string"), json()}; json const j(a); CHECK(j.type() == json::value_t::array); // we cannot really check for equality here } SECTION("sequence container literal") { json const j({json(1), json(1u), json(2.2), json(false), json("string"), json()}); CHECK(j.type() == json::value_t::array); CHECK(j == j_reference); } } SECTION("create a string (explicit)") { SECTION("empty string") { json::string_t const s{}; json const j(s); CHECK(j.type() == json::value_t::string); } SECTION("filled string") { json::string_t const s {"Hello world"}; json const j(s); CHECK(j.type() == json::value_t::string); } } SECTION("create a string (implicit)") { // reference string json::string_t const s_reference {"Hello world"}; json const j_reference(s_reference); SECTION("std::string") { std::string const s {"Hello world"}; json const j(s); CHECK(j.type() == json::value_t::string); CHECK(j == j_reference); } SECTION("char[]") { char const s[] {"Hello world"}; // NOLINT(cppcoreguidelines-avoid-c-arrays,hicpp-avoid-c-arrays,modernize-avoid-c-arrays) json const j(s); CHECK(j.type() == json::value_t::string); CHECK(j == j_reference); } SECTION("const char*") { const char* s {"Hello world"}; json const j(s); CHECK(j.type() == json::value_t::string); CHECK(j == j_reference); } SECTION("string literal") { json const j("Hello world"); CHECK(j.type() == json::value_t::string); CHECK(j == j_reference); } } SECTION("create a boolean (explicit)") { SECTION("empty boolean") { json::boolean_t const b{}; json const j(b); CHECK(j.type() == json::value_t::boolean); } SECTION("filled boolean (true)") { json const j(true); CHECK(j.type() == json::value_t::boolean); } SECTION("filled boolean (false)") { json const j(false); CHECK(j.type() == json::value_t::boolean); } SECTION("from std::vector::reference") { std::vector v{true}; json const j(v[0]); CHECK(std::is_same::reference>::value); CHECK(j.type() == json::value_t::boolean); } SECTION("from std::vector::const_reference") { const std::vector v{true}; json const j(v[0]); CHECK(std::is_same::const_reference>::value); CHECK(j.type() == json::value_t::boolean); } } SECTION("create a binary (explicit)") { SECTION("empty binary") { json::binary_t const b{}; json const j(b); CHECK(j.type() == json::value_t::binary); } SECTION("filled binary") { json::binary_t const b({1, 2, 3}); json const j(b); CHECK(j.type() == json::value_t::binary); } } SECTION("create an integer number (explicit)") { SECTION("uninitialized value") { json::number_integer_t const n{}; json const j(n); CHECK(j.type() == json::value_t::number_integer); } SECTION("initialized value") { json::number_integer_t const n(42); json const j(n); CHECK(j.type() == json::value_t::number_integer); } } SECTION("create an integer number (implicit)") { // reference objects json::number_integer_t const n_reference = 42; json const j_reference(n_reference); json::number_unsigned_t const n_unsigned_reference = 42; json const j_unsigned_reference(n_unsigned_reference); SECTION("short") { short const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("unsigned short") { unsigned short const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_unsigned); CHECK(j == j_unsigned_reference); } SECTION("int") { int const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("unsigned int") { unsigned int const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_unsigned); CHECK(j == j_unsigned_reference); } SECTION("long") { long const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("unsigned long") { unsigned long const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_unsigned); CHECK(j == j_unsigned_reference); } SECTION("long long") { long long const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("unsigned long long") { unsigned long long const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_unsigned); CHECK(j == j_unsigned_reference); } SECTION("int8_t") { int8_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int16_t") { int16_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int32_t") { int32_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int64_t") { int64_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int_fast8_t") { int_fast8_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int_fast16_t") { int_fast16_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int_fast32_t") { int_fast32_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int_fast64_t") { int_fast64_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int_least8_t") { int_least8_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int_least16_t") { int_least16_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int_least32_t") { int_least32_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("int_least64_t") { int_least64_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("uint8_t") { uint8_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_unsigned); CHECK(j == j_unsigned_reference); } SECTION("uint16_t") { uint16_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_unsigned); CHECK(j == j_unsigned_reference); } SECTION("uint32_t") { uint32_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_unsigned); CHECK(j == j_unsigned_reference); } SECTION("uint64_t") { uint64_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_unsigned); CHECK(j == j_unsigned_reference); } SECTION("uint_fast8_t") { uint_fast8_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_unsigned); CHECK(j == j_unsigned_reference); } SECTION("uint_fast16_t") { uint_fast16_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_unsigned); CHECK(j == j_unsigned_reference); } SECTION("uint_fast32_t") { uint_fast32_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_unsigned); CHECK(j == j_unsigned_reference); } SECTION("uint_fast64_t") { uint_fast64_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_unsigned); CHECK(j == j_unsigned_reference); } SECTION("uint_least8_t") { uint_least8_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_unsigned); CHECK(j == j_unsigned_reference); } SECTION("uint_least16_t") { uint_least16_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_unsigned); CHECK(j == j_unsigned_reference); } SECTION("uint_least32_t") { uint_least32_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_unsigned); CHECK(j == j_unsigned_reference); } SECTION("uint_least64_t") { uint_least64_t const n = 42; json const j(n); CHECK(j.type() == json::value_t::number_unsigned); CHECK(j == j_unsigned_reference); } SECTION("integer literal without suffix") { json const j(42); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("integer literal with u suffix") { json j(42u); CHECK(j.type() == json::value_t::number_unsigned); CHECK(j == j_unsigned_reference); } SECTION("integer literal with l suffix") { json const j(42L); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("integer literal with ul suffix") { json j(42ul); CHECK(j.type() == json::value_t::number_unsigned); CHECK(j == j_unsigned_reference); } SECTION("integer literal with ll suffix") { json const j(42LL); CHECK(j.type() == json::value_t::number_integer); CHECK(j == j_reference); } SECTION("integer literal with ull suffix") { json j(42ull); CHECK(j.type() == json::value_t::number_unsigned); CHECK(j == j_unsigned_reference); } } SECTION("create a floating-point number (explicit)") { SECTION("uninitialized value") { json::number_float_t const n{}; json const j(n); CHECK(j.type() == json::value_t::number_float); } SECTION("initialized value") { json::number_float_t const n(42.23); json const j(n); CHECK(j.type() == json::value_t::number_float); } SECTION("NaN") { // NaN is stored properly, but serialized to null json::number_float_t const n(std::numeric_limits::quiet_NaN()); json const j(n); CHECK(j.type() == json::value_t::number_float); // check round trip of NaN json::number_float_t const d{j}; CHECK((std::isnan(d) && std::isnan(n)) == true); // check that NaN is serialized to null CHECK(j.dump() == "null"); } SECTION("infinity") { // infinity is stored properly, but serialized to null json::number_float_t const n(std::numeric_limits::infinity()); json const j(n); CHECK(j.type() == json::value_t::number_float); // check round trip of infinity json::number_float_t const d{j}; CHECK(d == n); // check that inf is serialized to null CHECK(j.dump() == "null"); } } SECTION("create a floating-point number (implicit)") { // reference object json::number_float_t const n_reference = 42.23; json const j_reference(n_reference); SECTION("float") { float const n = 42.23f; json const j(n); CHECK(j.type() == json::value_t::number_float); CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float)); } SECTION("double") { double const n = 42.23; json const j(n); CHECK(j.type() == json::value_t::number_float); CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float)); } SECTION("long double") { long double const n = 42.23L; json const j(n); CHECK(j.type() == json::value_t::number_float); CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float)); } SECTION("floating-point literal without suffix") { json const j(42.23); CHECK(j.type() == json::value_t::number_float); CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float)); } SECTION("integer literal with f suffix") { json const j(42.23f); CHECK(j.type() == json::value_t::number_float); CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float)); } SECTION("integer literal with l suffix") { json const j(42.23L); CHECK(j.type() == json::value_t::number_float); CHECK(j.m_data.m_value.number_float == Approx(j_reference.m_data.m_value.number_float)); } } SECTION("create a container (array or object) from an initializer list") { SECTION("empty initializer list") { SECTION("explicit") { json const j(json::initializer_list_t {}); CHECK(j.type() == json::value_t::object); } SECTION("implicit") { json const j {}; CHECK(j.type() == json::value_t::null); } } SECTION("one element") { SECTION("array") { SECTION("explicit") { json const j(json::initializer_list_t {json(json::array_t())}); CHECK(j.type() == json::value_t::array); } SECTION("implicit") { json const j {json::array_t()}; CHECK(j.type() == json::value_t::array); } } SECTION("object") { SECTION("explicit") { json const j(json::initializer_list_t {json(json::object_t())}); CHECK(j.type() == json::value_t::array); } SECTION("implicit") { json const j {json::object_t()}; CHECK(j.type() == json::value_t::array); } } SECTION("string") { SECTION("explicit") { json const j(json::initializer_list_t {json("Hello world")}); CHECK(j.type() == json::value_t::array); } SECTION("implicit") { json const j {"Hello world"}; CHECK(j.type() == json::value_t::array); } } SECTION("boolean") { SECTION("explicit") { json const j(json::initializer_list_t {json(true)}); CHECK(j.type() == json::value_t::array); } SECTION("implicit") { json const j {true}; CHECK(j.type() == json::value_t::array); } } SECTION("number (integer)") { SECTION("explicit") { json const j(json::initializer_list_t {json(1)}); CHECK(j.type() == json::value_t::array); } SECTION("implicit") { json const j {1}; CHECK(j.type() == json::value_t::array); } } SECTION("number (unsigned)") { SECTION("explicit") { json const j(json::initializer_list_t {json(1u)}); CHECK(j.type() == json::value_t::array); } SECTION("implicit") { json const j {1u}; CHECK(j.type() == json::value_t::array); } } SECTION("number (floating-point)") { SECTION("explicit") { json const j(json::initializer_list_t {json(42.23)}); CHECK(j.type() == json::value_t::array); } SECTION("implicit") { json const j {42.23}; CHECK(j.type() == json::value_t::array); } } } SECTION("more elements") { SECTION("explicit") { json const j(json::initializer_list_t {1, 1u, 42.23, true, nullptr, json::object_t(), json::array_t()}); CHECK(j.type() == json::value_t::array); } SECTION("implicit") { json const j {1, 1u, 42.23, true, nullptr, json::object_t(), json::array_t()}; CHECK(j.type() == json::value_t::array); } } SECTION("implicit type deduction") { SECTION("object") { json const j { {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false} }; CHECK(j.type() == json::value_t::object); } SECTION("array") { json const j { {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }; CHECK(j.type() == json::value_t::array); } } SECTION("explicit type deduction") { SECTION("empty object") { json const j = json::object(); CHECK(j.type() == json::value_t::object); } SECTION("object") { json const j = json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false} }); CHECK(j.type() == json::value_t::object); } SECTION("object with error") { json _; CHECK_THROWS_WITH_AS(_ = json::object({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false}, 13 }), "[json.exception.type_error.301] cannot create object from initializer list", json::type_error&); } SECTION("empty array") { json const j = json::array(); CHECK(j.type() == json::value_t::array); } SECTION("array") { json const j = json::array({ {"one", 1}, {"two", 1u}, {"three", 2.2}, {"four", false} }); CHECK(j.type() == json::value_t::array); } } SECTION("move from initializer_list") { SECTION("string") { SECTION("constructor with implicit types (array)") { // This should break through any short string optimization in std::string std::string source(1024, '!'); const auto* source_addr = source.data(); json j = {std::move(source)}; const auto* target_addr = j[0].get_ref().data(); const bool success = (target_addr == source_addr); CHECK(success); } SECTION("constructor with implicit types (object)") { // This should break through any short string optimization in std::string std::string source(1024, '!'); const auto* source_addr = source.data(); json j = {{"key", std::move(source)}}; const auto* target_addr = j["key"].get_ref().data(); const bool success = (target_addr == source_addr); CHECK(success); } SECTION("constructor with implicit types (object key)") { // This should break through any short string optimization in std::string std::string source(1024, '!'); const auto* source_addr = source.data(); json j = {{std::move(source), 42}}; const auto* target_addr = j.get_ref().begin()->first.data(); const bool success = (target_addr == source_addr); CHECK(success); } } SECTION("array") { SECTION("constructor with implicit types (array)") { json::array_t source = {1, 2, 3}; const auto* source_addr = source.data(); json j {std::move(source)}; const auto* target_addr = j[0].get_ref().data(); const bool success = (target_addr == source_addr); CHECK(success); } SECTION("constructor with implicit types (object)") { json::array_t source = {1, 2, 3}; const auto* source_addr = source.data(); json const j {{"key", std::move(source)}}; const auto* target_addr = j["key"].get_ref().data(); const bool success = (target_addr == source_addr); CHECK(success); } SECTION("assignment with implicit types (array)") { json::array_t source = {1, 2, 3}; const auto* source_addr = source.data(); json j = {std::move(source)}; const auto* target_addr = j[0].get_ref().data(); const bool success = (target_addr == source_addr); CHECK(success); } SECTION("assignment with implicit types (object)") { json::array_t source = {1, 2, 3}; const auto* source_addr = source.data(); json j = {{"key", std::move(source)}}; const auto* target_addr = j["key"].get_ref().data(); const bool success = (target_addr == source_addr); CHECK(success); } } SECTION("object") { SECTION("constructor with implicit types (array)") { json::object_t source = {{"hello", "world"}}; const json* source_addr = &source.at("hello"); json j {std::move(source)}; CHECK(&(j[0].get_ref().at("hello")) == source_addr); } SECTION("constructor with implicit types (object)") { json::object_t source = {{"hello", "world"}}; const json* source_addr = &source.at("hello"); json j {{"key", std::move(source)}}; CHECK(&(j["key"].get_ref().at("hello")) == source_addr); } SECTION("assignment with implicit types (array)") { json::object_t source = {{"hello", "world"}}; const json* source_addr = &source.at("hello"); json j = {std::move(source)}; CHECK(&(j[0].get_ref().at("hello")) == source_addr); } SECTION("assignment with implicit types (object)") { json::object_t source = {{"hello", "world"}}; const json* source_addr = &source.at("hello"); json j = {{"key", std::move(source)}}; CHECK(&(j["key"].get_ref().at("hello")) == source_addr); } } SECTION("json") { SECTION("constructor with implicit types (array)") { json source {1, 2, 3}; const json* source_addr = &source[0]; json j {std::move(source), {}}; CHECK(&j[0][0] == source_addr); } SECTION("constructor with implicit types (object)") { json source {1, 2, 3}; const json* source_addr = &source[0]; json j {{"key", std::move(source)}}; CHECK(&j["key"][0] == source_addr); } SECTION("assignment with implicit types (array)") { json source {1, 2, 3}; const json* source_addr = &source[0]; json j = {std::move(source), {}}; CHECK(&j[0][0] == source_addr); } SECTION("assignment with implicit types (object)") { json source {1, 2, 3}; const json* source_addr = &source[0]; json j = {{"key", std::move(source)}}; CHECK(&j["key"][0] == source_addr); } } } } SECTION("create an array of n copies of a given value") { SECTION("cnt = 0") { json const v = {1, "foo", 34.23, {1, 2, 3}, {{"A", 1}, {"B", 2u}}}; json const arr(0, v); CHECK(arr.size() == 0); } SECTION("cnt = 1") { json const v = {1, "foo", 34.23, {1, 2, 3}, {{"A", 1}, {"B", 2u}}}; json const arr(1, v); CHECK(arr.size() == 1); for (const auto& x : arr) { CHECK(x == v); } } SECTION("cnt = 3") { json const v = {1, "foo", 34.23, {1, 2, 3}, {{"A", 1}, {"B", 2u}}}; json const arr(3, v); CHECK(arr.size() == 3); for (const auto& x : arr) { CHECK(x == v); } } } SECTION("create a JSON container from an iterator range") { SECTION("object") { SECTION("json(begin(), end())") { { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; json const j_new(jobject.begin(), jobject.end()); CHECK(j_new == jobject); } { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; json const j_new(jobject.cbegin(), jobject.cend()); CHECK(j_new == jobject); } } SECTION("json(begin(), begin())") { { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; json const j_new(jobject.begin(), jobject.begin()); CHECK(j_new == json::object()); } { json const jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}}; json const j_new(jobject.cbegin(), jobject.cbegin()); CHECK(j_new == json::object()); } } SECTION("construct from subrange") { json const jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json const j_new(jobject.find("b"), jobject.find("e")); CHECK(j_new == json({{"b", 1}, {"c", 17u}, {"d", false}})); } SECTION("incompatible iterators") { { json jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; CHECK_THROWS_WITH_AS(json(jobject.begin(), jobject2.end()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator&); CHECK_THROWS_WITH_AS(json(jobject2.begin(), jobject.end()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator&); } { json const jobject = {{"a", "a"}, {"b", 1}, {"c", 17u}, {"d", false}, {"e", true}}; json const jobject2 = {{"a", "a"}, {"b", 1}, {"c", 17u}}; CHECK_THROWS_WITH_AS(json(jobject.cbegin(), jobject2.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator&); CHECK_THROWS_WITH_AS(json(jobject2.cbegin(), jobject.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator&); } } } SECTION("array") { SECTION("json(begin(), end())") { { json jarray = {1, 2, 3, 4, 5}; json const j_new(jarray.begin(), jarray.end()); CHECK(j_new == jarray); } { json const jarray = {1, 2, 3, 4, 5}; json const j_new(jarray.cbegin(), jarray.cend()); CHECK(j_new == jarray); } } SECTION("json(begin(), begin())") { { json jarray = {1, 2, 3, 4, 5}; json j_new(jarray.begin(), jarray.begin()); CHECK(j_new == json::array()); } { json const jarray = {1, 2, 3, 4, 5}; json const j_new(jarray.cbegin(), jarray.cbegin()); CHECK(j_new == json::array()); } } SECTION("construct from subrange") { { json jarray = {1, 2, 3, 4, 5}; json const j_new(jarray.begin() + 1, jarray.begin() + 3); CHECK(j_new == json({2, 3})); } { json const jarray = {1, 2, 3, 4, 5}; json const j_new(jarray.cbegin() + 1, jarray.cbegin() + 3); CHECK(j_new == json({2, 3})); } } SECTION("incompatible iterators") { { json jarray = {1, 2, 3, 4}; json jarray2 = {2, 3, 4, 5}; CHECK_THROWS_WITH_AS(json(jarray.begin(), jarray2.end()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator&); CHECK_THROWS_WITH_AS(json(jarray2.begin(), jarray.end()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator&); } { json const jarray = {1, 2, 3, 4}; json const jarray2 = {2, 3, 4, 5}; CHECK_THROWS_WITH_AS(json(jarray.cbegin(), jarray2.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator&); CHECK_THROWS_WITH_AS(json(jarray2.cbegin(), jarray.cend()), "[json.exception.invalid_iterator.201] iterators are not compatible", json::invalid_iterator&); } } } SECTION("other values") { SECTION("construct with two valid iterators") { SECTION("null") { { json j; CHECK_THROWS_WITH_AS(json(j.begin(), j.end()), "[json.exception.invalid_iterator.206] cannot construct with iterators from null", json::invalid_iterator&); } { json const j; CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cend()), "[json.exception.invalid_iterator.206] cannot construct with iterators from null", json::invalid_iterator&); } } SECTION("string") { { json j = "foo"; json const j_new(j.begin(), j.end()); CHECK(j == j_new); } { json const j = "bar"; json const j_new(j.cbegin(), j.cend()); CHECK(j == j_new); } } SECTION("number (boolean)") { { json j = false; json const j_new(j.begin(), j.end()); CHECK(j == j_new); } { json const j = true; json const j_new(j.cbegin(), j.cend()); CHECK(j == j_new); } } SECTION("number (integer)") { { json j = 17; json const j_new(j.begin(), j.end()); CHECK(j == j_new); } { json const j = 17; json const j_new(j.cbegin(), j.cend()); CHECK(j == j_new); } } SECTION("number (unsigned)") { { json j = 17u; json const j_new(j.begin(), j.end()); CHECK(j == j_new); } { json const j = 17u; json const j_new(j.cbegin(), j.cend()); CHECK(j == j_new); } } SECTION("number (floating point)") { { json j = 23.42; json const j_new(j.begin(), j.end()); CHECK(j == j_new); } { json const j = 23.42; json const j_new(j.cbegin(), j.cend()); CHECK(j == j_new); } } SECTION("binary") { { json j = json::binary({1, 2, 3}); json const j_new(j.begin(), j.end()); CHECK((j == j_new)); } { json const j = json::binary({1, 2, 3}); json const j_new(j.cbegin(), j.cend()); CHECK((j == j_new)); } } } SECTION("construct with two invalid iterators") { SECTION("string") { { json j = "foo"; CHECK_THROWS_WITH_AS(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); CHECK_THROWS_WITH_AS(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); } { json const j = "bar"; CHECK_THROWS_WITH_AS(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); } } SECTION("number (boolean)") { { json j = false; CHECK_THROWS_WITH_AS(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); CHECK_THROWS_WITH_AS(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); } { json const j = true; CHECK_THROWS_WITH_AS(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); } } SECTION("number (integer)") { { json j = 17; CHECK_THROWS_WITH_AS(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); CHECK_THROWS_WITH_AS(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); } { json const j = 17; CHECK_THROWS_WITH_AS(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); } } SECTION("number (integer)") { { json j = 17u; CHECK_THROWS_WITH_AS(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); CHECK_THROWS_WITH_AS(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); } { json const j = 17u; CHECK_THROWS_WITH_AS(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); } } SECTION("number (floating point)") { { json j = 23.42; CHECK_THROWS_WITH_AS(json(j.end(), j.end()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); CHECK_THROWS_WITH_AS(json(j.begin(), j.begin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); } { json const j = 23.42; CHECK_THROWS_WITH_AS(json(j.cend(), j.cend()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); CHECK_THROWS_WITH_AS(json(j.cbegin(), j.cbegin()), "[json.exception.invalid_iterator.204] iterators out of range", json::invalid_iterator&); } } } } } }