| // __ _____ _____ _____ | |
| // __| | __| | | | JSON for Modern C++ (supporting code) | |
| // | | |__ | | | | | | version 3.12.0 | |
| // |_____|_____|_____|_|___| https://github.com/nlohmann/json | |
| // | |
| // SPDX-FileCopyrightText: 2013-2026 Niels Lohmann <https://nlohmann.me> | |
| // SPDX-License-Identifier: MIT | |
| #include "doctest_compatibility.h" | |
| #define JSON_TESTS_PRIVATE | |
| #include <nlohmann/json.hpp> | |
| using nlohmann::json; | |
| #include <deque> | |
| #include <forward_list> | |
| #include <fstream> | |
| #include <list> | |
| #include <set> | |
| #include <unordered_map> | |
| #include <unordered_set> | |
| #include <valarray> | |
| 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<json::string_t, json>") | |
| { | |
| std::map<json::string_t, json> 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<std::string, std::string> #600") | |
| { | |
| const std::map<std::string, std::string> m | |
| { | |
| {"a", "b"}, | |
| {"c", "d"}, | |
| {"e", "f"}, | |
| }; | |
| json const j(m); | |
| CHECK((j.get<decltype(m)>() == m)); | |
| } | |
| SECTION("std::map<const char*, json>") | |
| { | |
| std::map<const char*, json> 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<json::string_t, json>") | |
| { | |
| std::multimap<json::string_t, json> 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<json::string_t, json>") | |
| { | |
| std::unordered_map<json::string_t, json> 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<json::string_t, json>") | |
| { | |
| std::unordered_multimap<json::string_t, json> 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<json>") | |
| { | |
| std::list<json> 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<float, std::string> const p{1.0f, "string"}; | |
| json const j(p); | |
| CHECK(j.type() == json::value_t::array); | |
| CHECK(j.get<decltype(p)>() == 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<std::pair<int, float>>(); | |
| 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<int> {0, 1}); | |
| json const j(t); | |
| CHECK(j.type() == json::value_t::array); | |
| REQUIRE(j.size() == 4); | |
| CHECK(j.get<decltype(t)>() == 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<std::tuple<int, float, std::string>>(); | |
| CHECK(std::get<0>(t) == j[0]); | |
| CHECK(std::get<1>(t) == j[1]); | |
| CHECK(std::get<2>(t) == j[2]); | |
| } | |
| SECTION("std::tuple tie") | |
| { | |
| const auto a = 1.0; | |
| const auto* const b = "string"; | |
| const auto c = 42; | |
| const auto d = std::vector<int> {0, 2}; | |
| const size_t e = 1234; | |
| auto t = std::tie(a, b, c, d, e); | |
| json const j(t); | |
| double a_out = 0; | |
| std::string b_out; | |
| int c_out = 0; | |
| std::vector<int> d_out; | |
| int64_t e_out = 0; | |
| auto t_out = std::tie(a_out, b_out, c_out, d_out, e_out); | |
| j.get_to(t_out); | |
| CHECK(a_out == a); | |
| CHECK(b_out == b); | |
| CHECK(c_out == c); | |
| CHECK(d_out == d); | |
| CHECK(e_out == e); | |
| } | |
| SECTION("std::tuple of references to elements") | |
| { | |
| const auto a = 1.0; | |
| const auto* const b = "string"; | |
| const auto c = 42; | |
| const size_t d = 1234; | |
| const auto t = std::tie(a, b, c, d); | |
| json const j(t); | |
| auto t_out = j.get<std::tuple<const json::number_float_t&, | |
| const json::string_t&, | |
| const json::number_integer_t&, | |
| const json::number_unsigned_t&>>(); | |
| CHECK(&std::get<0>(t_out) == j[0].get_ptr<const json::number_float_t*>()); | |
| CHECK(&std::get<1>(t_out) == j[1].get_ptr<const json::string_t*>()); | |
| CHECK(&std::get<2>(t_out) == j[2].get_ptr<const json::number_integer_t*>()); | |
| CHECK(&std::get<3>(t_out) == j[3].get_ptr<const json::number_unsigned_t*>()); | |
| CHECK(std::get<0>(t_out) == a); | |
| CHECK(std::get<1>(t_out) == b); | |
| CHECK(std::get<2>(t_out) == c); | |
| CHECK(std::get<3>(t_out) == d); | |
| } | |
| SECTION("std::tuple mixed arithmetic types") | |
| { | |
| using j_float_t = json::number_float_t; | |
| using j_int_t = json::number_integer_t; | |
| using j_uint_t = json::number_unsigned_t; | |
| const j_float_t a = 1.0; | |
| const j_int_t b = 1234; | |
| const j_uint_t c = 42; | |
| json const j(std::tie(a, b, c, c)); | |
| auto t1 = j.get<std::tuple<j_int_t, j_uint_t, j_float_t, const j_uint_t&>>(); | |
| j_uint_t a2 = 0; | |
| j_float_t b2 = 0; | |
| j_int_t c2 = 0; | |
| auto t2 = std::tie(a2, b2, c2); | |
| j.get_to(t2); | |
| CHECK(std::get<0>(t1) == static_cast<j_int_t>(a)); | |
| CHECK(std::get<1>(t1) == static_cast<j_uint_t>(b)); | |
| CHECK(std::get<2>(t1) == static_cast<j_float_t>(c)); | |
| // t1[3] exists only to force usage of the no-default-constructor version | |
| CHECK(a2 == static_cast<j_uint_t>(a)); | |
| CHECK(b2 == static_cast<j_float_t>(b)); | |
| CHECK(c2 == static_cast<j_int_t>(c)); | |
| } | |
| SECTION("std::pair/tuple/array failures") | |
| { | |
| json const j{1}; | |
| CHECK_THROWS_WITH_AS((j.get<std::pair<int, int>>()), "[json.exception.out_of_range.401] array index 1 is out of range", json::out_of_range&); | |
| CHECK_THROWS_WITH_AS((j.get<std::tuple<int, int>>()), "[json.exception.out_of_range.401] array index 1 is out of range", json::out_of_range&); | |
| CHECK_THROWS_WITH_AS((j.get<std::array<int, 3>>()), "[json.exception.out_of_range.401] array index 1 is out of range", json::out_of_range&); | |
| #if JSON_DIAGNOSTICS | |
| // the exception names the element that has the wrong type | |
| CHECK_THROWS_WITH_AS((j.get<std::array<std::string, 3>>()), "[json.exception.type_error.302] (/0) type must be string, but is number", json::type_error&); | |
| #else | |
| CHECK_THROWS_WITH_AS((j.get<std::array<std::string, 3>>()), "[json.exception.type_error.302] type must be string, but is number", json::type_error&); | |
| #endif | |
| // the elements are converted in order, so a type error comes before a missing element | |
| json const j2{1, "two"}; | |
| std::array<int, 3> a{{0, 0, 0}}; | |
| #if JSON_DIAGNOSTICS | |
| CHECK_THROWS_WITH_AS((j2.get<std::array<int, 3>>()), "[json.exception.type_error.302] (/1) type must be number, but is string", json::type_error&); | |
| CHECK_THROWS_WITH_AS(j2.get_to(a), "[json.exception.type_error.302] (/1) type must be number, but is string", json::type_error&); | |
| #else | |
| CHECK_THROWS_WITH_AS((j2.get<std::array<int, 3>>()), "[json.exception.type_error.302] type must be number, but is string", json::type_error&); | |
| CHECK_THROWS_WITH_AS(j2.get_to(a), "[json.exception.type_error.302] type must be number, but is string", json::type_error&); | |
| #endif | |
| CHECK_THROWS_WITH_AS(j.get_to(a), "[json.exception.out_of_range.401] array index 1 is out of range", json::out_of_range&); | |
| #if !defined(JSON_NOEXCEPTION) // without exceptions, the get_to calls in CHECK_THROWS_WITH_AS do not run | |
| CHECK(a[0] == 1); | |
| #endif | |
| json const j3{"one", "two"}; | |
| CHECK_THROWS_WITH_AS((j3.get<std::array<std::string, 3>>()), "[json.exception.out_of_range.401] array index 2 is out of range", json::out_of_range&); | |
| } | |
| SECTION("std::array from a longer array or from booleans") | |
| { | |
| json const j{1, 2.5, true, 4u}; | |
| CHECK(j.get<std::array<int, 3>>() == (std::array<int, 3> {{1, 2, 1}})); | |
| std::array<int, 4> a{{0, 0, 0, 0}}; | |
| j.get_to(a); | |
| CHECK(a == (std::array<int, 4> {{1, 2, 1, 4}})); | |
| CHECK(j.get<std::array<int, 0>>().empty()); | |
| } | |
| SECTION("std::forward_list<json>") | |
| { | |
| std::forward_list<json> 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<json, 6>") | |
| { | |
| std::array<json, 6> 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<std::array<json, 6>>(); | |
| CHECK(a2 == a); | |
| } | |
| SECTION("std::valarray<int>") | |
| { | |
| std::valarray<int> 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<std::valarray<int>>(); | |
| CHECK(jva.size() == va.size()); | |
| for (size_t i = 0; i < jva.size(); ++i) | |
| { | |
| CHECK(va[i] == jva[i]); | |
| } | |
| } | |
| SECTION("std::valarray<double>") | |
| { | |
| std::valarray<double> 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<std::valarray<double>>(); | |
| CHECK(jva.size() == va.size()); | |
| for (size_t i = 0; i < jva.size(); ++i) | |
| { | |
| CHECK(va[i] == jva[i]); | |
| } | |
| } | |
| SECTION("std::vector<json>") | |
| { | |
| std::vector<json> 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<json>") | |
| { | |
| std::deque<json> 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<json>") | |
| { | |
| std::set<json> 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<json>") | |
| { | |
| std::unordered_set<json> 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[]") | |
| { | |
| const char s[] {"Hello world"}; // NOLINT(misc-const-correctness,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<bool>::reference") | |
| { | |
| std::vector<bool> v{true}; | |
| json const j(v[0]); | |
| CHECK(std::is_same<decltype(v[0]), std::vector<bool>::reference>::value); | |
| CHECK(j.type() == json::value_t::boolean); | |
| } | |
| SECTION("from std::vector<bool>::const_reference") | |
| { | |
| const std::vector<bool> v{true}; | |
| json const j(v[0]); | |
| CHECK(std::is_same<decltype(v[0]), std::vector<bool>::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") | |
| { | |
| const 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") | |
| { | |
| const 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") | |
| { | |
| const 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<json::number_float_t>::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<json::number_float_t>::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<std::string const&>().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<std::string const&>().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<json::object_t&>().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<json::array_t const&>().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<json::array_t const&>().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<json::array_t const&>().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<json::array_t const&>().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<json::object_t const&>().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<json::object_t const&>().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<json::object_t const&>().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<json::object_t const&>().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}; | |
| const 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&); | |
| } | |
| } | |
| SECTION("binary") | |
| { | |
| { | |
| json j = json::binary({1, 2, 3}); | |
| 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 = json::binary({1, 2, 3}); | |
| 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&); | |
| } | |
| } | |
| } | |
| } | |
| } | |
| } |