diff options
| author | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:42:50 +0300 |
|---|---|---|
| committer | Mehmet Samet Duman <yongdohyun@projecttick.org> | 2026-04-02 18:42:50 +0300 |
| commit | 5fad10f89c485cfdc7b99011f07609f8871160d4 (patch) | |
| tree | 1860b39753b652dfe54d3cbbc80c875f40198d1f /json4cpp/tests/src/unit-constructor1.cpp | |
| parent | 292baed7ac0cf84263263966ed32ed113cae857f (diff) | |
| parent | 9a737481aed085fd289f82dff1fa8c3c66627a7e (diff) | |
| download | Project-Tick-5fad10f89c485cfdc7b99011f07609f8871160d4.tar.gz Project-Tick-5fad10f89c485cfdc7b99011f07609f8871160d4.zip | |
Add 'json4cpp/' from commit '9a737481aed085fd289f82dff1fa8c3c66627a7e'
git-subtree-dir: json4cpp
git-subtree-mainline: 292baed7ac0cf84263263966ed32ed113cae857f
git-subtree-split: 9a737481aed085fd289f82dff1fa8c3c66627a7e
Diffstat (limited to 'json4cpp/tests/src/unit-constructor1.cpp')
| -rw-r--r-- | json4cpp/tests/src/unit-constructor1.cpp | 1654 |
1 files changed, 1654 insertions, 0 deletions
diff --git a/json4cpp/tests/src/unit-constructor1.cpp b/json4cpp/tests/src/unit-constructor1.cpp new file mode 100644 index 0000000000..9917cd358f --- /dev/null +++ b/json4cpp/tests/src/unit-constructor1.cpp @@ -0,0 +1,1654 @@ +// __ _____ _____ _____ +// __| | __| | | | 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]); // commented out due to CI issue, see https://github.com/nlohmann/json/pull/3985 and https://github.com/nlohmann/json/issues/4025 + } + + 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&); + } + + 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&); + } + } + } + } + } +} |
