From 84ced9bce4248a9b1514c4987c476a04a5f16c40 Mon Sep 17 00:00:00 2001 From: Florian Albrechtskirchinger Date: Sat, 4 Jun 2022 00:36:09 +0200 Subject: [PATCH 1/2] Fix incorrect basic_json conversions Add wrapper types to encode conversion target value types and to_json overloads to perform the conversions. Fixes #3425. --- .../nlohmann/detail/conversions/to_json.hpp | 92 ++++++++++ include/nlohmann/json.hpp | 73 +++++++- single_include/nlohmann/json.hpp | 165 +++++++++++++++++- tests/src/unit-alt-string.cpp | 113 +++++++++++- 4 files changed, 429 insertions(+), 14 deletions(-) diff --git a/include/nlohmann/detail/conversions/to_json.hpp b/include/nlohmann/detail/conversions/to_json.hpp index fde46ef7c..d7d85a6dc 100644 --- a/include/nlohmann/detail/conversions/to_json.hpp +++ b/include/nlohmann/detail/conversions/to_json.hpp @@ -226,6 +226,16 @@ struct external_constructor template<> struct external_constructor { + template + static void construct(BasicJsonType& j) + { + j.m_value.destroy(j.m_type); + j.m_type = value_t::object; + j.m_value.object = j.template create(); + j.set_parents(); + j.assert_invariant(); + } + template static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) { @@ -261,6 +271,28 @@ struct external_constructor } }; +////////////// +// wrappers // +////////////// + +template +struct array_type_wrapper +{ + const ArrayType& array; +}; + +template +struct object_type_wrapper +{ + const ObjectType& object; +}; + +template +struct string_type_wrapper +{ + const StringType& string; +}; + ///////////// // to_json // ///////////// @@ -285,6 +317,17 @@ inline void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) external_constructor::construct(j, std::move(s)); } +template +using string_type_constructible_from_data_and_size = decltype(typename BasicJsonType::string_t( + std::declval().data(), std::declval().size())); + +template::value, int> = 0> +void to_json(BasicJsonType& j, detail::string_type_wrapper s) +{ + external_constructor::construct(j, typename BasicJsonType::string_t(s.string.data(), s.string.size())); +} + template::value, int> = 0> inline void to_json(BasicJsonType& j, FloatType val) noexcept @@ -333,6 +376,18 @@ inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr) external_constructor::construct(j, arr); } +template +using array_type_constructible_from_iter = decltype(typename BasicJsonType::array_t( + std::declval>(), std::declval>())); + +template::value, int> = 0> +void to_json(BasicJsonType& j, detail::array_type_wrapper a) +{ + external_constructor::construct(j, + typename BasicJsonType::array_t(a.array.begin(), a.array.end())); +} + template inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin) { @@ -365,6 +420,43 @@ inline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) external_constructor::construct(j, std::move(obj)); } +template < typename BasicJsonType, typename ObjectType, + enable_if_t < is_compatible_object_type::value + || is_basic_json::value, int > = 0 > +void to_json(BasicJsonType& j, const object_type_wrapper& obj) +{ + external_constructor::construct(j, obj.object); +} + +template +using object_type_key_constructible_from_data_and_size = decltype( + typename BasicJsonType::object_t::key_type( + std::declval().data(), + std::declval().size())); + +template < typename BasicJsonType, typename ObjectType, + enable_if_t < !is_compatible_object_type::value + && !is_basic_json::value + && detail::is_detected::value, int > = 0 > +void to_json(BasicJsonType& j, const object_type_wrapper& o) +{ + using std::begin; + using std::end; + + external_constructor::construct(j); + + auto& obj = j.template get_ref(); + std::transform(begin(o.object), end(o.object), std::inserter(obj, obj.end()), + [](const typename ObjectType::value_type & val) + { + return typename BasicJsonType::object_t::value_type + { + typename BasicJsonType::object_t::key_type(val.first.data(), val.first.size()), + BasicJsonType(val.second)}; + }); +} + template < typename BasicJsonType, typename T, std::size_t N, enable_if_t < !std::is_constructible + using serializer_has_to_json_with_type_wrapper = decltype(Serializer::to_json( + std::declval(), std::declval())); + + template , OtherStringType, + detail::string_type_wrapper>::value, int > = 0 > + void other_string_to_json(const OtherStringType& str) + { + JSONSerializer::to_json(*this, detail::string_type_wrapper {str}); + } + + template < typename OtherStringType, + detail::enable_if_t < + !detail::is_detected, OtherStringType, + detail::string_type_wrapper>::value, int > = 0 > + void other_string_to_json(const OtherStringType& str) + { + JSONSerializer::to_json(*this, str); + } + + template , OtherObjectType, + detail::object_type_wrapper>::value, int > = 0 > + void other_object_to_json(const OtherObjectType& obj) + { + JSONSerializer::to_json(*this, detail::object_type_wrapper {obj}); + } + + template < typename OtherObjectType, + detail::enable_if_t < + !detail::is_detected, OtherObjectType, + detail::object_type_wrapper>::value, int > = 0 > + void other_object_to_json(const OtherObjectType& obj) + { + JSONSerializer::to_json(*this, obj); + } + + template , OtherArrayType, + detail::array_type_wrapper>::value, int > = 0 > + void other_array_to_json(const OtherArrayType& arr) + { + JSONSerializer::to_json(*this, detail::array_type_wrapper {arr}); + } + + template < typename OtherArrayType, + detail::enable_if_t < + !detail::is_detected, OtherArrayType, + detail::array_type_wrapper>::value, int > = 0 > + void other_array_to_json(const OtherArrayType& arr) + { + JSONSerializer::to_json(*this, arr); + } + + public: /// @brief create a JSON value from an existing one /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ template < typename BasicJsonType, @@ -896,13 +963,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSONSerializer::to_json(*this, val.template get()); break; case value_t::string: - JSONSerializer::to_json(*this, val.template get_ref()); + other_string_to_json(val.template get_ref()); break; case value_t::object: - JSONSerializer::to_json(*this, val.template get_ref()); + other_object_to_json(val.template get_ref()); break; case value_t::array: - JSONSerializer::to_json(*this, val.template get_ref()); + other_array_to_json(val.template get_ref()); break; case value_t::binary: JSONSerializer::to_json(*this, val.template get_ref()); diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index c342172b4..0264c156c 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -5112,6 +5112,16 @@ struct external_constructor template<> struct external_constructor { + template + static void construct(BasicJsonType& j) + { + j.m_value.destroy(j.m_type); + j.m_type = value_t::object; + j.m_value.object = j.template create(); + j.set_parents(); + j.assert_invariant(); + } + template static void construct(BasicJsonType& j, const typename BasicJsonType::object_t& obj) { @@ -5147,6 +5157,28 @@ struct external_constructor } }; +////////////// +// wrappers // +////////////// + +template +struct array_type_wrapper +{ + const ArrayType& array; +}; + +template +struct object_type_wrapper +{ + const ObjectType& object; +}; + +template +struct string_type_wrapper +{ + const StringType& string; +}; + ///////////// // to_json // ///////////// @@ -5171,6 +5203,17 @@ inline void to_json(BasicJsonType& j, typename BasicJsonType::string_t&& s) external_constructor::construct(j, std::move(s)); } +template +using string_type_constructible_from_data_and_size = decltype(typename BasicJsonType::string_t( + std::declval().data(), std::declval().size())); + +template::value, int> = 0> +void to_json(BasicJsonType& j, detail::string_type_wrapper s) +{ + external_constructor::construct(j, typename BasicJsonType::string_t(s.string.data(), s.string.size())); +} + template::value, int> = 0> inline void to_json(BasicJsonType& j, FloatType val) noexcept @@ -5219,6 +5262,18 @@ inline void to_json(BasicJsonType& j, const CompatibleArrayType& arr) external_constructor::construct(j, arr); } +template +using array_type_constructible_from_iter = decltype(typename BasicJsonType::array_t( + std::declval>(), std::declval>())); + +template::value, int> = 0> +void to_json(BasicJsonType& j, detail::array_type_wrapper a) +{ + external_constructor::construct(j, + typename BasicJsonType::array_t(a.array.begin(), a.array.end())); +} + template inline void to_json(BasicJsonType& j, const typename BasicJsonType::binary_t& bin) { @@ -5251,6 +5306,43 @@ inline void to_json(BasicJsonType& j, typename BasicJsonType::object_t&& obj) external_constructor::construct(j, std::move(obj)); } +template < typename BasicJsonType, typename ObjectType, + enable_if_t < is_compatible_object_type::value + || is_basic_json::value, int > = 0 > +void to_json(BasicJsonType& j, const object_type_wrapper& obj) +{ + external_constructor::construct(j, obj.object); +} + +template +using object_type_key_constructible_from_data_and_size = decltype( + typename BasicJsonType::object_t::key_type( + std::declval().data(), + std::declval().size())); + +template < typename BasicJsonType, typename ObjectType, + enable_if_t < !is_compatible_object_type::value + && !is_basic_json::value + && detail::is_detected::value, int > = 0 > +void to_json(BasicJsonType& j, const object_type_wrapper& o) +{ + using std::begin; + using std::end; + + external_constructor::construct(j); + + auto& obj = j.template get_ref(); + std::transform(begin(o.object), end(o.object), std::inserter(obj, obj.end()), + [](const typename ObjectType::value_type & val) + { + return typename BasicJsonType::object_t::value_type + { + typename BasicJsonType::object_t::key_type(val.first.data(), val.first.size()), + BasicJsonType(val.second)}; + }); +} + template < typename BasicJsonType, typename T, std::size_t N, enable_if_t < !std::is_constructible + using serializer_has_to_json_with_type_wrapper = decltype(Serializer::to_json( + std::declval(), std::declval())); + + template , OtherStringType, + detail::string_type_wrapper>::value, int > = 0 > + void other_string_to_json(const OtherStringType& str) + { + JSONSerializer::to_json(*this, detail::string_type_wrapper {str}); + } + + template < typename OtherStringType, + detail::enable_if_t < + !detail::is_detected, OtherStringType, + detail::string_type_wrapper>::value, int > = 0 > + void other_string_to_json(const OtherStringType& str) + { + JSONSerializer::to_json(*this, str); + } + + template , OtherObjectType, + detail::object_type_wrapper>::value, int > = 0 > + void other_object_to_json(const OtherObjectType& obj) + { + JSONSerializer::to_json(*this, detail::object_type_wrapper {obj}); + } + + template < typename OtherObjectType, + detail::enable_if_t < + !detail::is_detected, OtherObjectType, + detail::object_type_wrapper>::value, int > = 0 > + void other_object_to_json(const OtherObjectType& obj) + { + JSONSerializer::to_json(*this, obj); + } + + template , OtherArrayType, + detail::array_type_wrapper>::value, int > = 0 > + void other_array_to_json(const OtherArrayType& arr) + { + JSONSerializer::to_json(*this, detail::array_type_wrapper {arr}); + } + + template < typename OtherArrayType, + detail::enable_if_t < + !detail::is_detected, OtherArrayType, + detail::array_type_wrapper>::value, int > = 0 > + void other_array_to_json(const OtherArrayType& arr) + { + JSONSerializer::to_json(*this, arr); + } + + public: /// @brief create a JSON value from an existing one /// @sa https://json.nlohmann.me/api/basic_json/basic_json/ template < typename BasicJsonType, @@ -19170,13 +19329,13 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec JSONSerializer::to_json(*this, val.template get()); break; case value_t::string: - JSONSerializer::to_json(*this, val.template get_ref()); + other_string_to_json(val.template get_ref()); break; case value_t::object: - JSONSerializer::to_json(*this, val.template get_ref()); + other_object_to_json(val.template get_ref()); break; case value_t::array: - JSONSerializer::to_json(*this, val.template get_ref()); + other_array_to_json(val.template get_ref()); break; case value_t::binary: JSONSerializer::to_json(*this, val.template get_ref()); diff --git a/tests/src/unit-alt-string.cpp b/tests/src/unit-alt-string.cpp index 26f66ecad..6885c31d4 100644 --- a/tests/src/unit-alt-string.cpp +++ b/tests/src/unit-alt-string.cpp @@ -30,7 +30,9 @@ SOFTWARE. #include "doctest_compatibility.h" #include +using nlohmann::json; +#include #include #include @@ -328,17 +330,112 @@ TEST_CASE("alternative string type") SECTION("JSON pointer") { - // conversion from json to alt_json fails to compile (see #3425); - // attempted fix(*) produces: [[['b','a','r'],['b','a','z']]] (with each char being an integer) - // (*) disable implicit conversion for json_refs of any basic_json type - // alt_json j = R"( - // { - // "foo": ["bar", "baz"] - // } - // )"_json; auto j = alt_json::parse(R"({"foo": ["bar", "baz"]})"); CHECK(j.at(alt_json::json_pointer("/foo/0")) == j["foo"][0]); CHECK(j.at(alt_json::json_pointer("/foo/1")) == j["foo"][1]); } + + SECTION("conversion (#3425)") + { + SECTION("string") + { + SECTION("json to alt_json") + { + json j("foo"); + alt_json aj = j; + + alt_string as = aj.dump(); + CHECK(j.is_string()); + CHECK(j.dump() == "\"foo\""); + CHECK(j.dump() == std::string(as.data(), as.size())); + } + + SECTION("alt_json to json") + { + alt_json aj("foo"); + json j = aj; + + alt_string as = aj.dump(); + CHECK(aj.is_string()); + CHECK(j.dump() == "\"foo\""); + CHECK(j.dump() == std::string(as.data(), as.size())); + } + } + + SECTION("array") + { + SECTION("json to alt_json") + { + json j{"foo"}; + alt_json aj = j; + + alt_string as = aj.dump(); + CHECK(j.is_array()); + CHECK(j.dump() == "[\"foo\"]"); + CHECK(j.dump() == std::string(as.data(), as.size())); + } + + SECTION("alt_json to json") + { + alt_json aj{"foo"}; + json j = aj; + + alt_string as = aj.dump(); + CHECK(aj.is_array()); + CHECK(j.dump() == "[\"foo\"]"); + CHECK(j.dump() == std::string(as.data(), as.size())); + } + } + + SECTION("object") + { + SECTION("json to alt_json") + { + json j{{"foo", {"bar", "baz"}}}; + alt_json aj = j; + + alt_string as = aj.dump(); + CHECK(j.is_object()); + CHECK(j.dump() == "{\"foo\":[\"bar\",\"baz\"]}"); + CHECK(j.dump() == std::string(as.data(), as.size())); + } + + SECTION("alt_json to json") + { + alt_json aj{{"foo", {"bar", "baz"}}}; + json j = aj; + + alt_string as = aj.dump(); + CHECK(aj.is_object()); + CHECK(j.dump() == "{\"foo\":[\"bar\",\"baz\"]}"); + CHECK(j.dump() == std::string(as.data(), as.size())); + } + } + + SECTION("binary") + { + SECTION("json to alt_json") + { + auto j = json::binary({1, 2, 3, 4}, 128); + alt_json aj = j; + + alt_string as = aj.dump(); + CHECK(j.is_binary()); + CHECK(j.dump() == "{\"bytes\":[1,2,3,4],\"subtype\":128}"); + CHECK(j.dump() == std::string(as.data(), as.size())); + } + + SECTION("alt_json to json") + { + auto aj = alt_json::binary({1, 2, 3, 4}, 128); + json j = aj; + + alt_string as = aj.dump(); + CHECK(aj.is_binary()); + CHECK(j.dump() == "{\"bytes\":[1,2,3,4],\"subtype\":128}"); + CHECK(j.dump() == std::string(as.data(), as.size())); + } + } + } } From 140943b18e46be9c051f3c004dad8b70c9f6d312 Mon Sep 17 00:00:00 2001 From: Florian Albrechtskirchinger Date: Sat, 4 Jun 2022 10:41:35 +0200 Subject: [PATCH 2/2] Mark basic_json converting ctor JSON_EXPLICIT Make JSON_USE_IMPLICIT_CONVERSIONS affect the basic_json converting constructor. --- include/nlohmann/json.hpp | 4 ++-- single_include/nlohmann/json.hpp | 4 ++-- tests/src/unit-alt-string.cpp | 32 +++++++++++++++++++++++++ tests/src/unit-regression1.cpp | 8 +++++++ tests/src/unit-regression2.cpp | 7 +++--- tests/src/unit-udt.cpp | 40 ++++++++++++++++++++++++++++++++ 6 files changed, 88 insertions(+), 7 deletions(-) diff --git a/include/nlohmann/json.hpp b/include/nlohmann/json.hpp index 61130a9d1..83971d680 100644 --- a/include/nlohmann/json.hpp +++ b/include/nlohmann/json.hpp @@ -937,7 +937,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template < typename BasicJsonType, detail::enable_if_t < detail::is_basic_json::value&& !std::is_same::value, int > = 0 > - basic_json(const BasicJsonType& val) + JSON_EXPLICIT basic_json(const BasicJsonType& val) { using other_boolean_t = typename BasicJsonType::boolean_t; using other_number_float_t = typename BasicJsonType::number_float_t; @@ -1760,7 +1760,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec int > = 0 > BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const { - return *this; + return BasicJsonType(*this); } /*! diff --git a/single_include/nlohmann/json.hpp b/single_include/nlohmann/json.hpp index 0264c156c..5c6d6d6a4 100644 --- a/single_include/nlohmann/json.hpp +++ b/single_include/nlohmann/json.hpp @@ -19303,7 +19303,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec template < typename BasicJsonType, detail::enable_if_t < detail::is_basic_json::value&& !std::is_same::value, int > = 0 > - basic_json(const BasicJsonType& val) + JSON_EXPLICIT basic_json(const BasicJsonType& val) { using other_boolean_t = typename BasicJsonType::boolean_t; using other_number_float_t = typename BasicJsonType::number_float_t; @@ -20126,7 +20126,7 @@ class basic_json // NOLINT(cppcoreguidelines-special-member-functions,hicpp-spec int > = 0 > BasicJsonType get_impl(detail::priority_tag<2> /*unused*/) const { - return *this; + return BasicJsonType(*this); } /*! diff --git a/tests/src/unit-alt-string.cpp b/tests/src/unit-alt-string.cpp index 6885c31d4..0e5d498b6 100644 --- a/tests/src/unit-alt-string.cpp +++ b/tests/src/unit-alt-string.cpp @@ -343,7 +343,11 @@ TEST_CASE("alternative string type") SECTION("json to alt_json") { json j("foo"); +#if JSON_USE_IMPLICIT_CONVERSIONS alt_json aj = j; +#else + alt_json aj = alt_json(j); +#endif alt_string as = aj.dump(); CHECK(j.is_string()); @@ -354,7 +358,11 @@ TEST_CASE("alternative string type") SECTION("alt_json to json") { alt_json aj("foo"); +#if JSON_USE_IMPLICIT_CONVERSIONS json j = aj; +#else + json j = json(aj); +#endif alt_string as = aj.dump(); CHECK(aj.is_string()); @@ -368,7 +376,11 @@ TEST_CASE("alternative string type") SECTION("json to alt_json") { json j{"foo"}; +#if JSON_USE_IMPLICIT_CONVERSIONS alt_json aj = j; +#else + alt_json aj = alt_json(j); +#endif alt_string as = aj.dump(); CHECK(j.is_array()); @@ -379,7 +391,11 @@ TEST_CASE("alternative string type") SECTION("alt_json to json") { alt_json aj{"foo"}; +#if JSON_USE_IMPLICIT_CONVERSIONS json j = aj; +#else + json j = json(aj); +#endif alt_string as = aj.dump(); CHECK(aj.is_array()); @@ -393,7 +409,11 @@ TEST_CASE("alternative string type") SECTION("json to alt_json") { json j{{"foo", {"bar", "baz"}}}; +#if JSON_USE_IMPLICIT_CONVERSIONS alt_json aj = j; +#else + alt_json aj = alt_json(j); +#endif alt_string as = aj.dump(); CHECK(j.is_object()); @@ -404,7 +424,11 @@ TEST_CASE("alternative string type") SECTION("alt_json to json") { alt_json aj{{"foo", {"bar", "baz"}}}; +#if JSON_USE_IMPLICIT_CONVERSIONS json j = aj; +#else + json j = json(aj); +#endif alt_string as = aj.dump(); CHECK(aj.is_object()); @@ -418,7 +442,11 @@ TEST_CASE("alternative string type") SECTION("json to alt_json") { auto j = json::binary({1, 2, 3, 4}, 128); +#if JSON_USE_IMPLICIT_CONVERSIONS alt_json aj = j; +#else + alt_json aj = alt_json(j); +#endif alt_string as = aj.dump(); CHECK(j.is_binary()); @@ -429,7 +457,11 @@ TEST_CASE("alternative string type") SECTION("alt_json to json") { auto aj = alt_json::binary({1, 2, 3, 4}, 128); +#if JSON_USE_IMPLICIT_CONVERSIONS json j = aj; +#else + json j = json(aj); +#endif alt_string as = aj.dump(); CHECK(aj.is_binary()); diff --git a/tests/src/unit-regression1.cpp b/tests/src/unit-regression1.cpp index e6dfaa1c5..b2a1b8827 100644 --- a/tests/src/unit-regression1.cpp +++ b/tests/src/unit-regression1.cpp @@ -1485,7 +1485,11 @@ TEST_CASE("regression tests 1") SECTION("issue #972 - Segmentation fault on G++ when trying to assign json string literal to custom json type") { +#if JSON_USE_IMPLICIT_CONVERSIONS my_json foo = R"([1, 2, 3])"_json; +#else + my_json foo = my_json(R"([1, 2, 3])"_json); +#endif } SECTION("issue #977 - Assigning between different json types") @@ -1496,7 +1500,11 @@ TEST_CASE("regression tests 1") CHECK(lj.size() == 1); CHECK(lj["x"] == 3); CHECK(ff.x == 3); +#if JSON_USE_IMPLICIT_CONVERSIONS nlohmann::json nj = lj; // This line works as expected +#else + nlohmann::json nj = nlohmann::json(lj); // This line works as expected +#endif } } diff --git a/tests/src/unit-regression2.cpp b/tests/src/unit-regression2.cpp index 3ee234eee..777f0f597 100644 --- a/tests/src/unit-regression2.cpp +++ b/tests/src/unit-regression2.cpp @@ -774,12 +774,12 @@ TEST_CASE("regression tests 2") CHECK(test1.dump() == "{\"root\":{}}"); ordered_json test2; - test2[ordered_json::json_pointer(p)] = json::object(); + test2[ordered_json::json_pointer(p)] = ordered_json::object(); CHECK(test2.dump() == "{\"root\":{}}"); // json::json_pointer and ordered_json::json_pointer are the same type; behave as above ordered_json test3; - test3[json::json_pointer(p)] = json::object(); + test3[json::json_pointer(p)] = ordered_json::object(); CHECK(std::is_same::value); CHECK(test3.dump() == "{\"root\":{}}"); } @@ -859,7 +859,8 @@ TEST_CASE("regression tests 2") CHECK(td.str == "value"); } -#ifdef JSON_HAS_CPP_20 + // this is no longer supported when implicit conversions are disabled +#if defined(JSON_HAS_CPP_20) && JSON_USE_IMPLICIT_CONVERSIONS SECTION("issue #3312 - Parse to custom class from unordered_json breaks on G++11.2.0 with C++20") { // see test for #3171 diff --git a/tests/src/unit-udt.cpp b/tests/src/unit-udt.cpp index a3f06210d..5d634d77b 100644 --- a/tests/src/unit-udt.cpp +++ b/tests/src/unit-udt.cpp @@ -713,14 +713,22 @@ TEST_CASE("different basic_json types conversions") SECTION("null") { json j; +#if JSON_USE_IMPLICIT_CONVERSIONS custom_json cj = j; +#else + custom_json cj = custom_json(j); +#endif CHECK(cj == nullptr); } SECTION("boolean") { json j = true; +#if JSON_USE_IMPLICIT_CONVERSIONS custom_json cj = j; +#else + custom_json cj = custom_json(j); +#endif CHECK(cj == true); } @@ -728,49 +736,77 @@ TEST_CASE("different basic_json types conversions") { json j(json::value_t::discarded); custom_json cj; +#if JSON_USE_IMPLICIT_CONVERSIONS CHECK_NOTHROW(cj = j); +#else + CHECK_NOTHROW(cj = custom_json(j)); +#endif CHECK(cj.type() == custom_json::value_t::discarded); } SECTION("array") { json j = {1, 2, 3}; +#if JSON_USE_IMPLICIT_CONVERSIONS custom_json cj = j; +#else + custom_json cj = custom_json(j); +#endif CHECK((cj == std::vector {1, 2, 3})); } SECTION("integer") { json j = 42; +#if JSON_USE_IMPLICIT_CONVERSIONS custom_json cj = j; +#else + custom_json cj = custom_json(j); +#endif CHECK(cj == 42); } SECTION("float") { json j = 42.0; +#if JSON_USE_IMPLICIT_CONVERSIONS custom_json cj = j; +#else + custom_json cj = custom_json(j); +#endif CHECK(cj == 42.0); } SECTION("unsigned") { json j = 42u; +#if JSON_USE_IMPLICIT_CONVERSIONS custom_json cj = j; +#else + custom_json cj = custom_json(j); +#endif CHECK(cj == 42u); } SECTION("string") { json j = "forty-two"; +#if JSON_USE_IMPLICIT_CONVERSIONS custom_json cj = j; +#else + custom_json cj = custom_json(j); +#endif CHECK(cj == "forty-two"); } SECTION("binary") { json j = json::binary({1, 2, 3}, 42); +#if JSON_USE_IMPLICIT_CONVERSIONS custom_json cj = j; +#else + custom_json cj = custom_json(j); +#endif CHECK(cj.get_binary().subtype() == 42); std::vector cv = cj.get_binary(); std::vector v = j.get_binary(); @@ -780,7 +816,11 @@ TEST_CASE("different basic_json types conversions") SECTION("object") { json j = {{"forty", "two"}}; +#if JSON_USE_IMPLICIT_CONVERSIONS custom_json cj = j; +#else + custom_json cj = custom_json(j); +#endif auto m = j.get>(); CHECK(cj == m); }