// __ _____ _____ _____ // __| | __| | | | JSON for Modern C++ (supporting code) // | | |__ | | | | | | version 3.11.3 // |_____|_____|_____|_|___| https://github.com/nlohmann/json // // SPDX-FileCopyrightText: 2013-2023 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&); } } } } } }