diff --git a/include/nlohmann/detail/conversions/from_json.hpp b/include/nlohmann/detail/conversions/from_json.hpp index ac4cea5f..7fe19f57 100644 --- a/include/nlohmann/detail/conversions/from_json.hpp +++ b/include/nlohmann/detail/conversions/from_json.hpp @@ -9,6 +9,7 @@ #include // string #include // tuple, make_tuple #include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map #include // pair, declval #include // valarray @@ -278,10 +279,29 @@ void from_json(const BasicJsonType& j, std::tuple& t) from_json_tuple_impl(j, t, index_sequence_for {}); } -template ::value>> -void from_json(const BasicJsonType& j, std::map& m) +void from_json(const BasicJsonType& j, std::map& m) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + for (const auto& p : j) + { + if (JSON_UNLIKELY(not p.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); + } + m.emplace(p.at(0).template get(), p.at(1).template get()); + } +} + +template ::value>> +void from_json(const BasicJsonType& j, std::unordered_map& m) { if (JSON_UNLIKELY(not j.is_array())) { diff --git a/include/nlohmann/detail/output/serializer.hpp b/include/nlohmann/detail/output/serializer.hpp index 19ab9894..c0f81776 100644 --- a/include/nlohmann/detail/output/serializer.hpp +++ b/include/nlohmann/detail/output/serializer.hpp @@ -414,7 +414,7 @@ class serializer else { // we finish reading, but do not accept: string was incomplete - std::string sn(3,'\0'); + std::string sn(3, '\0'); snprintf(&sn[0], sn.size(), "%.2X", static_cast(s.back())); JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn)); } diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 2b387a8b..2921cba8 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -913,6 +913,7 @@ inline bool operator<(const value_t lhs, const value_t rhs) noexcept #include // string #include // tuple, make_tuple #include // is_arithmetic, is_same, is_enum, underlying_type, is_convertible +#include // unordered_map #include // pair, declval #include // valarray @@ -1186,10 +1187,29 @@ void from_json(const BasicJsonType& j, std::tuple& t) from_json_tuple_impl(j, t, index_sequence_for {}); } -template ::value>> -void from_json(const BasicJsonType& j, std::map& m) +void from_json(const BasicJsonType& j, std::map& m) +{ + if (JSON_UNLIKELY(not j.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(j.type_name()))); + } + for (const auto& p : j) + { + if (JSON_UNLIKELY(not p.is_array())) + { + JSON_THROW(type_error::create(302, "type must be array, but is " + std::string(p.type_name()))); + } + m.emplace(p.at(0).template get(), p.at(1).template get()); + } +} + +template ::value>> +void from_json(const BasicJsonType& j, std::unordered_map& m) { if (JSON_UNLIKELY(not j.is_array())) { @@ -1973,10 +1993,8 @@ class input_adapter #include // localeconv #include // size_t #include // strtof, strtod, strtold, strtoll, strtoull +#include // snprintf #include // initializer_list -#include // hex, uppercase -#include // setw, setfill -#include // stringstream #include // char_traits, string #include // vector @@ -3146,10 +3164,9 @@ scan_number_done: if ('\x00' <= c and c <= '\x1F') { // escape control characters - std::stringstream ss; - ss << "(c) << ">"; - result += ss.str(); + char cs[9]; + snprintf(cs, 9, "", c); + result += cs; } else { @@ -5619,12 +5636,10 @@ class output_adapter #include // ldexp #include // size_t #include // uint8_t, uint16_t, uint32_t, uint64_t +#include // snprintf #include // memcpy -#include // setw, setfill -#include // hex #include // back_inserter #include // numeric_limits -#include // stringstream #include // char_traits, string #include // make_pair, move @@ -7283,9 +7298,9 @@ class binary_reader */ std::string get_token_string() const { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << current; - return ss.str(); + char cr[3]; + snprintf(cr, 3, "%.2X", current); + return std::string{cr}; } private: @@ -8272,11 +8287,8 @@ class binary_writer #include // size_t, ptrdiff_t #include // uint8_t #include // snprintf -#include // setfill -#include // next #include // numeric_limits #include // string -#include // stringstream #include // is_same // #include @@ -9753,9 +9765,9 @@ class serializer case UTF8_REJECT: // decode found invalid UTF-8 byte { - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(byte); - JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + ss.str())); + std::string sn(3, '\0'); + snprintf(&sn[0], sn.size(), "%.2X", byte); + JSON_THROW(type_error::create(316, "invalid UTF-8 byte at index " + std::to_string(i) + ": 0x" + sn)); } default: // decode found yet incomplete multi-byte code point @@ -9781,9 +9793,9 @@ class serializer else { // we finish reading, but do not accept: string was incomplete - std::stringstream ss; - ss << std::setw(2) << std::uppercase << std::setfill('0') << std::hex << static_cast(static_cast(s.back())); - JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + ss.str())); + std::string sn(3, '\0'); + snprintf(&sn[0], sn.size(), "%.2X", static_cast(s.back())); + JSON_THROW(type_error::create(316, "incomplete UTF-8 string; last byte: 0x" + sn)); } } diff --git a/test/src/unit-conversions.cpp b/test/src/unit-conversions.cpp index 79ccf681..061a2458 100644 --- a/test/src/unit-conversions.cpp +++ b/test/src/unit-conversions.cpp @@ -40,11 +40,25 @@ using nlohmann::json; #include #include +namespace +{ +template +void map_type_conversion_checks() +{ +} +} + TEST_CASE("value conversion") { SECTION("get an object (explicit)") { - json::object_t o_reference = {{"object", json::object()}, {"array", {1, 2, 3, 4}}, {"number", 42}, {"boolean", false}, {"null", nullptr}, {"string", "Hello world"} }; + json::object_t o_reference = {{"object", json::object()}, + {"array", {1, 2, 3, 4}}, + {"number", 42}, + {"boolean", false}, + {"null", nullptr}, + {"string", "Hello world"} + }; json j(o_reference); SECTION("json::object_t") @@ -55,19 +69,22 @@ TEST_CASE("value conversion") SECTION("std::map") { - std::map o = j.get>(); + std::map o = + j.get>(); CHECK(json(o) == j); } SECTION("std::multimap") { - std::multimap o = j.get>(); + std::multimap o = + j.get>(); CHECK(json(o) == j); } SECTION("std::unordered_map") { - std::unordered_map o = j.get>(); + std::unordered_map o = + j.get>(); CHECK(json(o) == j); } @@ -80,34 +97,55 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-object type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::null).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::array).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::string).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_integer).get(), + json::type_error&); + CHECK_THROWS_AS( + json(json::value_t::number_unsigned).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_float).get(), + json::type_error&); - CHECK_THROWS_WITH(json(json::value_t::null).get(), - "[json.exception.type_error.302] type must be object, but is null"); - CHECK_THROWS_WITH(json(json::value_t::array).get(), - "[json.exception.type_error.302] type must be object, but is array"); - CHECK_THROWS_WITH(json(json::value_t::string).get(), - "[json.exception.type_error.302] type must be object, but is string"); + CHECK_THROWS_WITH( + json(json::value_t::null).get(), + "[json.exception.type_error.302] type must be object, but is null"); + CHECK_THROWS_WITH( + json(json::value_t::array).get(), + "[json.exception.type_error.302] type must be object, but is array"); + CHECK_THROWS_WITH( + json(json::value_t::string).get(), + "[json.exception.type_error.302] type must be object, but is string"); CHECK_THROWS_WITH(json(json::value_t::boolean).get(), - "[json.exception.type_error.302] type must be object, but is boolean"); - CHECK_THROWS_WITH(json(json::value_t::number_integer).get(), - "[json.exception.type_error.302] type must be object, but is number"); - CHECK_THROWS_WITH(json(json::value_t::number_unsigned).get(), - "[json.exception.type_error.302] type must be object, but is number"); - CHECK_THROWS_WITH(json(json::value_t::number_float).get(), - "[json.exception.type_error.302] type must be object, but is number"); + "[json.exception.type_error.302] type must be object, " + "but is boolean"); + CHECK_THROWS_WITH( + json(json::value_t::number_integer).get(), + "[json.exception.type_error.302] type must be object, but is number"); + CHECK_THROWS_WITH( + json(json::value_t::number_unsigned).get(), + "[json.exception.type_error.302] type must be object, but is number"); + CHECK_THROWS_WITH( + json(json::value_t::number_float).get(), + "[json.exception.type_error.302] type must be object, but is number"); } } SECTION("get an object (implicit)") { - json::object_t o_reference = {{"object", json::object()}, {"array", {1, 2, 3, 4}}, {"number", 42}, {"boolean", false}, {"null", nullptr}, {"string", "Hello world"} }; + json::object_t o_reference = {{"object", json::object()}, + {"array", {1, 2, 3, 4}}, + {"number", 42}, + {"boolean", false}, + {"null", nullptr}, + {"string", "Hello world"} + }; json j(o_reference); SECTION("json::object_t") @@ -143,7 +181,8 @@ TEST_CASE("value conversion") SECTION("get an array (explicit)") { - json::array_t a_reference {json(1), json(1u), json(2.2), json(false), json("string"), json()}; + json::array_t a_reference{json(1), json(1u), json(2.2), + json(false), json("string"), json()}; json j(a_reference); SECTION("json::array_t") @@ -163,9 +202,11 @@ TEST_CASE("value conversion") std::forward_list a = j.get>(); CHECK(json(a) == j); - CHECK_THROWS_AS(json(json::value_t::null).get>(), json::type_error&); - CHECK_THROWS_WITH(json(json::value_t::null).get>(), - "[json.exception.type_error.302] type must be array, but is null"); + CHECK_THROWS_AS(json(json::value_t::null).get>(), + json::type_error&); + CHECK_THROWS_WITH( + json(json::value_t::null).get>(), + "[json.exception.type_error.302] type must be array, but is null"); } SECTION("std::vector") @@ -173,9 +214,11 @@ TEST_CASE("value conversion") std::vector a = j.get>(); CHECK(json(a) == j); - CHECK_THROWS_AS(json(json::value_t::null).get>(), json::type_error&); - CHECK_THROWS_WITH(json(json::value_t::null).get>(), - "[json.exception.type_error.302] type must be array, but is null"); + CHECK_THROWS_AS(json(json::value_t::null).get>(), + json::type_error&); + CHECK_THROWS_WITH( + json(json::value_t::null).get>(), + "[json.exception.type_error.302] type must be array, but is null"); #if not defined(JSON_NOEXCEPTION) SECTION("reserve is called on containers that supports it") @@ -214,36 +257,52 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-array type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::null).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::object).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::string).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_integer).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_float).get(), + json::type_error&); - CHECK_THROWS_WITH(json(json::value_t::object).get>(), - "[json.exception.type_error.302] type must be array, but is object"); - CHECK_THROWS_WITH(json(json::value_t::null).get(), - "[json.exception.type_error.302] type must be array, but is null"); - CHECK_THROWS_WITH(json(json::value_t::object).get(), - "[json.exception.type_error.302] type must be array, but is object"); - CHECK_THROWS_WITH(json(json::value_t::string).get(), - "[json.exception.type_error.302] type must be array, but is string"); - CHECK_THROWS_WITH(json(json::value_t::boolean).get(), - "[json.exception.type_error.302] type must be array, but is boolean"); - CHECK_THROWS_WITH(json(json::value_t::number_integer).get(), - "[json.exception.type_error.302] type must be array, but is number"); - CHECK_THROWS_WITH(json(json::value_t::number_unsigned).get(), - "[json.exception.type_error.302] type must be array, but is number"); - CHECK_THROWS_WITH(json(json::value_t::number_float).get(), - "[json.exception.type_error.302] type must be array, but is number"); + CHECK_THROWS_WITH( + json(json::value_t::object).get>(), + "[json.exception.type_error.302] type must be array, but is object"); + CHECK_THROWS_WITH( + json(json::value_t::null).get(), + "[json.exception.type_error.302] type must be array, but is null"); + CHECK_THROWS_WITH( + json(json::value_t::object).get(), + "[json.exception.type_error.302] type must be array, but is object"); + CHECK_THROWS_WITH( + json(json::value_t::string).get(), + "[json.exception.type_error.302] type must be array, but is string"); + CHECK_THROWS_WITH( + json(json::value_t::boolean).get(), + "[json.exception.type_error.302] type must be array, but is boolean"); + CHECK_THROWS_WITH( + json(json::value_t::number_integer).get(), + "[json.exception.type_error.302] type must be array, but is number"); + CHECK_THROWS_WITH( + json(json::value_t::number_unsigned).get(), + "[json.exception.type_error.302] type must be array, but is number"); + CHECK_THROWS_WITH( + json(json::value_t::number_float).get(), + "[json.exception.type_error.302] type must be array, but is number"); } } SECTION("get an array (implicit)") { - json::array_t a_reference {json(1), json(1u), json(2.2), json(false), json("string"), json()}; + json::array_t a_reference{json(1), json(1u), json(2.2), + json(false), json("string"), json()}; json j(a_reference); SECTION("json::array_t") @@ -279,7 +338,7 @@ TEST_CASE("value conversion") SECTION("get a string (explicit)") { - json::string_t s_reference {"Hello world"}; + json::string_t s_reference{"Hello world"}; json j(s_reference); SECTION("string_t") @@ -296,34 +355,49 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-string type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::null).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::object).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::array).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_integer).get(), + json::type_error&); + CHECK_THROWS_AS( + json(json::value_t::number_unsigned).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_float).get(), + json::type_error&); - CHECK_THROWS_WITH(json(json::value_t::null).get(), - "[json.exception.type_error.302] type must be string, but is null"); - CHECK_THROWS_WITH(json(json::value_t::object).get(), - "[json.exception.type_error.302] type must be string, but is object"); - CHECK_THROWS_WITH(json(json::value_t::array).get(), - "[json.exception.type_error.302] type must be string, but is array"); + CHECK_THROWS_WITH( + json(json::value_t::null).get(), + "[json.exception.type_error.302] type must be string, but is null"); + CHECK_THROWS_WITH( + json(json::value_t::object).get(), + "[json.exception.type_error.302] type must be string, but is object"); + CHECK_THROWS_WITH( + json(json::value_t::array).get(), + "[json.exception.type_error.302] type must be string, but is array"); CHECK_THROWS_WITH(json(json::value_t::boolean).get(), - "[json.exception.type_error.302] type must be string, but is boolean"); - CHECK_THROWS_WITH(json(json::value_t::number_integer).get(), - "[json.exception.type_error.302] type must be string, but is number"); - CHECK_THROWS_WITH(json(json::value_t::number_unsigned).get(), - "[json.exception.type_error.302] type must be string, but is number"); - CHECK_THROWS_WITH(json(json::value_t::number_float).get(), - "[json.exception.type_error.302] type must be string, but is number"); + "[json.exception.type_error.302] type must be string, " + "but is boolean"); + CHECK_THROWS_WITH( + json(json::value_t::number_integer).get(), + "[json.exception.type_error.302] type must be string, but is number"); + CHECK_THROWS_WITH( + json(json::value_t::number_unsigned).get(), + "[json.exception.type_error.302] type must be string, but is number"); + CHECK_THROWS_WITH( + json(json::value_t::number_float).get(), + "[json.exception.type_error.302] type must be string, but is number"); } } SECTION("get a string (implicit)") { - json::string_t s_reference {"Hello world"}; + json::string_t s_reference{"Hello world"}; json j(s_reference); SECTION("string_t") @@ -341,7 +415,7 @@ TEST_CASE("value conversion") SECTION("get a boolean (explicit)") { - json::boolean_t b_reference {true}; + json::boolean_t b_reference{true}; json j(b_reference); SECTION("boolean_t") @@ -358,34 +432,53 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-string type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_integer).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_unsigned).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::number_float).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::null).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::object).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::array).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::string).get(), + json::type_error&); + CHECK_THROWS_AS( + json(json::value_t::number_integer).get(), + json::type_error&); + CHECK_THROWS_AS( + json(json::value_t::number_unsigned).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::number_float).get(), + json::type_error&); - CHECK_THROWS_WITH(json(json::value_t::null).get(), - "[json.exception.type_error.302] type must be boolean, but is null"); + CHECK_THROWS_WITH( + json(json::value_t::null).get(), + "[json.exception.type_error.302] type must be boolean, but is null"); CHECK_THROWS_WITH(json(json::value_t::object).get(), - "[json.exception.type_error.302] type must be boolean, but is object"); - CHECK_THROWS_WITH(json(json::value_t::array).get(), - "[json.exception.type_error.302] type must be boolean, but is array"); + "[json.exception.type_error.302] type must be boolean, " + "but is object"); + CHECK_THROWS_WITH( + json(json::value_t::array).get(), + "[json.exception.type_error.302] type must be boolean, but is array"); CHECK_THROWS_WITH(json(json::value_t::string).get(), - "[json.exception.type_error.302] type must be boolean, but is string"); - CHECK_THROWS_WITH(json(json::value_t::number_integer).get(), - "[json.exception.type_error.302] type must be boolean, but is number"); - CHECK_THROWS_WITH(json(json::value_t::number_unsigned).get(), - "[json.exception.type_error.302] type must be boolean, but is number"); - CHECK_THROWS_WITH(json(json::value_t::number_float).get(), - "[json.exception.type_error.302] type must be boolean, but is number"); + "[json.exception.type_error.302] type must be boolean, " + "but is string"); + CHECK_THROWS_WITH( + json(json::value_t::number_integer).get(), + "[json.exception.type_error.302] type must be boolean, but is " + "number"); + CHECK_THROWS_WITH( + json(json::value_t::number_unsigned).get(), + "[json.exception.type_error.302] type must be boolean, but is " + "number"); + CHECK_THROWS_WITH( + json(json::value_t::number_float).get(), + "[json.exception.type_error.302] type must be boolean, but is " + "number"); } } SECTION("get a boolean (implicit)") { - json::boolean_t b_reference {true}; + json::boolean_t b_reference{true}; json j(b_reference); SECTION("boolean_t") @@ -403,9 +496,9 @@ TEST_CASE("value conversion") SECTION("get an integer number (explicit)") { - json::number_integer_t n_reference {42}; + json::number_integer_t n_reference{42}; json j(n_reference); - json::number_unsigned_t n_unsigned_reference {42u}; + json::number_unsigned_t n_unsigned_reference{42u}; json j_unsigned(n_unsigned_reference); SECTION("number_integer_t") @@ -614,33 +707,47 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-number type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::null).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::object).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::array).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::string).get(), + json::type_error&); + CHECK_THROWS_AS( + json(json::value_t::boolean).get(), + json::type_error&); - CHECK_THROWS_WITH(json(json::value_t::null).get(), - "[json.exception.type_error.302] type must be number, but is null"); - CHECK_THROWS_WITH(json(json::value_t::object).get(), - "[json.exception.type_error.302] type must be number, but is object"); - CHECK_THROWS_WITH(json(json::value_t::array).get(), - "[json.exception.type_error.302] type must be number, but is array"); - CHECK_THROWS_WITH(json(json::value_t::string).get(), - "[json.exception.type_error.302] type must be number, but is string"); - CHECK_THROWS_WITH(json(json::value_t::boolean).get(), - "[json.exception.type_error.302] type must be number, but is boolean"); + CHECK_THROWS_WITH( + json(json::value_t::null).get(), + "[json.exception.type_error.302] type must be number, but is null"); + CHECK_THROWS_WITH( + json(json::value_t::object).get(), + "[json.exception.type_error.302] type must be number, but is object"); + CHECK_THROWS_WITH( + json(json::value_t::array).get(), + "[json.exception.type_error.302] type must be number, but is array"); + CHECK_THROWS_WITH( + json(json::value_t::string).get(), + "[json.exception.type_error.302] type must be number, but is string"); + CHECK_THROWS_WITH( + json(json::value_t::boolean).get(), + "[json.exception.type_error.302] type must be number, but is " + "boolean"); - CHECK_NOTHROW(json(json::value_t::number_float).get()); - CHECK_NOTHROW(json(json::value_t::number_float).get()); + CHECK_NOTHROW( + json(json::value_t::number_float).get()); + CHECK_NOTHROW( + json(json::value_t::number_float).get()); } } SECTION("get an integer number (implicit)") { - json::number_integer_t n_reference {42}; + json::number_integer_t n_reference{42}; json j(n_reference); - json::number_unsigned_t n_unsigned_reference {42u}; + json::number_unsigned_t n_unsigned_reference{42u}; json j_unsigned(n_unsigned_reference); SECTION("number_integer_t") @@ -850,7 +957,7 @@ TEST_CASE("value conversion") SECTION("get a floating-point number (explicit)") { - json::number_float_t n_reference {42.23}; + json::number_float_t n_reference{42.23}; json j(n_reference); SECTION("number_float_t") @@ -873,31 +980,44 @@ TEST_CASE("value conversion") SECTION("exception in case of a non-string type") { - CHECK_THROWS_AS(json(json::value_t::null).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::object).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::array).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::string).get(), json::type_error&); - CHECK_THROWS_AS(json(json::value_t::boolean).get(), json::type_error&); + CHECK_THROWS_AS(json(json::value_t::null).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::object).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::array).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::string).get(), + json::type_error&); + CHECK_THROWS_AS(json(json::value_t::boolean).get(), + json::type_error&); - CHECK_THROWS_WITH(json(json::value_t::null).get(), - "[json.exception.type_error.302] type must be number, but is null"); - CHECK_THROWS_WITH(json(json::value_t::object).get(), - "[json.exception.type_error.302] type must be number, but is object"); - CHECK_THROWS_WITH(json(json::value_t::array).get(), - "[json.exception.type_error.302] type must be number, but is array"); - CHECK_THROWS_WITH(json(json::value_t::string).get(), - "[json.exception.type_error.302] type must be number, but is string"); - CHECK_THROWS_WITH(json(json::value_t::boolean).get(), - "[json.exception.type_error.302] type must be number, but is boolean"); + CHECK_THROWS_WITH( + json(json::value_t::null).get(), + "[json.exception.type_error.302] type must be number, but is null"); + CHECK_THROWS_WITH( + json(json::value_t::object).get(), + "[json.exception.type_error.302] type must be number, but is object"); + CHECK_THROWS_WITH( + json(json::value_t::array).get(), + "[json.exception.type_error.302] type must be number, but is array"); + CHECK_THROWS_WITH( + json(json::value_t::string).get(), + "[json.exception.type_error.302] type must be number, but is string"); + CHECK_THROWS_WITH( + json(json::value_t::boolean).get(), + "[json.exception.type_error.302] type must be number, but is " + "boolean"); - CHECK_NOTHROW(json(json::value_t::number_integer).get()); - CHECK_NOTHROW(json(json::value_t::number_unsigned).get()); + CHECK_NOTHROW( + json(json::value_t::number_integer).get()); + CHECK_NOTHROW( + json(json::value_t::number_unsigned).get()); } } SECTION("get a floating-point number (implicit)") { - json::number_float_t n_reference {42.23}; + json::number_float_t n_reference{42.23}; json j(n_reference); SECTION("number_float_t") @@ -954,7 +1074,7 @@ TEST_CASE("value conversion") j3.get>(); j4.get>(); j5.get>(); - //CHECK(m5["one"] == "eins"); + // CHECK(m5["one"] == "eins"); } SECTION("std::multimap") @@ -964,7 +1084,7 @@ TEST_CASE("value conversion") j3.get>(); j4.get>(); j5.get>(); - //CHECK(m5["one"] == "eins"); + // CHECK(m5["one"] == "eins"); } SECTION("std::unordered_multimap") @@ -974,13 +1094,16 @@ TEST_CASE("value conversion") j3.get>(); j4.get>(); j5.get>(); - //CHECK(m5["one"] == "eins"); + // CHECK(m5["one"] == "eins"); } SECTION("exception in case of a non-object type") { - CHECK_THROWS_AS((json().get>()), json::type_error&); - CHECK_THROWS_WITH((json().get>()), "[json.exception.type_error.302] type must be object, but is null"); + CHECK_THROWS_AS((json().get>()), + json::type_error&); + CHECK_THROWS_WITH( + (json().get>()), + "[json.exception.type_error.302] type must be object, but is null"); } } @@ -1022,7 +1145,8 @@ TEST_CASE("value conversion") { std::array arr6 = {{1, 2, 3, 4, 5, 6}}; CHECK_THROWS_AS(arr6 = j1, json::out_of_range&); - CHECK_THROWS_WITH(arr6 = j1, "[json.exception.out_of_range.401] array index 4 is out of range"); + CHECK_THROWS_WITH(arr6 = j1, "[json.exception.out_of_range.401] " + "array index 4 is out of range"); } SECTION("std::array is smaller than JSON") @@ -1088,14 +1212,48 @@ TEST_CASE("value conversion") CHECK(m == m2); json j7 = {0, 1, 2, 3}; + json j8 = 2; CHECK_THROWS_AS((j7.get>()), json::type_error&); - CHECK_THROWS_WITH((j7.get>()), "[json.exception.type_error.302] type must be array, but is number"); + CHECK_THROWS_AS((j8.get>()), json::type_error&); + CHECK_THROWS_WITH((j7.get>()), + "[json.exception.type_error.302] type must be array, " + "but is number"); + CHECK_THROWS_WITH((j8.get>()), + "[json.exception.type_error.302] type must be array, " + "but is number"); SECTION("superfluous entries") { - json j8 = {{0, 1, 2}, {1, 2, 3}, {2, 3, 4}}; - m2 = j8.get>(); - CHECK(m == m2); + json j9 = {{0, 1, 2}, {1, 2, 3}, {2, 3, 4}}; + m2 = j9.get>(); + CHECK(m == m2); + } + } + + SECTION("std::unordered_map (array of pairs)") + { + std::unordered_map m{{0, 1}, {1, 2}, {2, 3}}; + json j6 = m; + + auto m2 = j6.get>(); + CHECK(m == m2); + + json j7 = {0, 1, 2, 3}; + json j8 = 2; + CHECK_THROWS_AS((j7.get>()), json::type_error&); + CHECK_THROWS_AS((j8.get>()), json::type_error&); + CHECK_THROWS_WITH((j7.get>()), + "[json.exception.type_error.302] type must be array, " + "but is number"); + CHECK_THROWS_WITH((j8.get>()), + "[json.exception.type_error.302] type must be array, " + "but is number"); + + SECTION("superfluous entries") + { + json j9{{0, 1, 2}, {1, 2, 3}, {2, 3, 4}}; + m2 = j9.get>(); + CHECK(m == m2); } } @@ -1109,12 +1267,24 @@ TEST_CASE("value conversion") // does type really must be an array? or it rather must not be null? // that's what I thought when other test like this one broke - CHECK_THROWS_WITH((json().get>()), "[json.exception.type_error.302] type must be array, but is null"); - CHECK_THROWS_WITH((json().get>()), "[json.exception.type_error.302] type must be array, but is null"); - CHECK_THROWS_WITH((json().get>()), "[json.exception.type_error.302] type must be array, but is null"); - CHECK_THROWS_WITH((json().get>()), "[json.exception.type_error.302] type must be array, but is null"); - CHECK_THROWS_WITH((json().get>()), "[json.exception.type_error.302] type must be array, but is null"); - CHECK_THROWS_WITH((json().get>()), "[json.exception.type_error.302] type must be array, but is null"); + CHECK_THROWS_WITH( + (json().get>()), + "[json.exception.type_error.302] type must be array, but is null"); + CHECK_THROWS_WITH( + (json().get>()), + "[json.exception.type_error.302] type must be array, but is null"); + CHECK_THROWS_WITH( + (json().get>()), + "[json.exception.type_error.302] type must be array, but is null"); + CHECK_THROWS_WITH( + (json().get>()), + "[json.exception.type_error.302] type must be array, but is null"); + CHECK_THROWS_WITH( + (json().get>()), + "[json.exception.type_error.302] type must be array, but is null"); + CHECK_THROWS_WITH( + (json().get>()), + "[json.exception.type_error.302] type must be array, but is null"); } } }