diff --git a/libsolutil/JSON.h b/libsolutil/JSON.h index 43dddfd4a..905859f6d 100644 --- a/libsolutil/JSON.h +++ b/libsolutil/JSON.h @@ -67,4 +67,66 @@ std::string jsonPrint(Json::Value const& _input, JsonFormat const& _format); /// \return \c true if the document was successfully parsed, \c false if an error occurred. bool jsonParseStrict(std::string const& _input, Json::Value& _json, std::string* _errs = nullptr); +namespace detail +{ + +template +struct helper; + +template +struct helper_impl +{ + static bool isOfType(Json::Value const& _input) + { + return (_input.*checkMember)(); + } + static T get(Json::Value const& _input) + { + return (_input.*convertMember)(); + } + static T getOrDefault(Json::Value const& _input, T _default = {}) + { + T result = _default; + if (isOfType(_input)) + result = (_input.*convertMember)(); + return result; + } +}; + +template<> struct helper: helper_impl {}; +template<> struct helper: helper_impl {}; +template<> struct helper: helper_impl {}; +template<> struct helper: helper_impl {}; +template<> struct helper: helper_impl {}; +template<> struct helper: helper_impl {}; +template<> struct helper: helper_impl {}; + +} // namespace detail + +template +bool isOfType(Json::Value const& _input) +{ + return detail::helper::isOfType(_input); } + +template +bool isOfTypeIfExists(Json::Value const& _input, std::string const& _name) +{ + if (_input.isMember(_name)) + return isOfType(_input[_name]); + return true; +} + +template +T get(Json::Value const& _input) +{ + return detail::helper::get(_input); +} + +template +T getOrDefault(Json::Value const& _input, T _default = {}) +{ + return detail::helper::getOrDefault(_input, _default); +} + +} // namespace solidity::util diff --git a/test/libsolutil/JSON.cpp b/test/libsolutil/JSON.cpp index 1b0ed9388..3679fbe7c 100644 --- a/test/libsolutil/JSON.cpp +++ b/test/libsolutil/JSON.cpp @@ -184,6 +184,131 @@ BOOST_AUTO_TEST_CASE(parse_json_strict) BOOST_CHECK(json[0] == "😊"); } +BOOST_AUTO_TEST_CASE(json_isOfType) +{ + Json::Value json; + + json["float"] = 3.1f; + json["double"] = 3.1; + json["int"] = 2; + json["int64"] = Json::Int64{0x4000000000000000}; + json["string"] = "Hello World!"; + + BOOST_CHECK(isOfType(json["float"])); + BOOST_CHECK(isOfType(json["double"])); + BOOST_CHECK(isOfType(json["int"])); + BOOST_CHECK(isOfType(json["int"])); + BOOST_CHECK(isOfType(json["int"])); + BOOST_CHECK(isOfType(json["int"])); + BOOST_CHECK(isOfType(json["int64"])); + BOOST_CHECK(isOfType(json["int64"])); + BOOST_CHECK(isOfType(json["string"])); + BOOST_CHECK(!isOfType(json["int64"])); + BOOST_CHECK(!isOfType(json["double"])); + BOOST_CHECK(!isOfType(json["string"])); + BOOST_CHECK(!isOfType(json["string"])); + BOOST_CHECK(!isOfType(json["string"])); + BOOST_CHECK(!isOfType(json["string"])); + BOOST_CHECK(!isOfType(json["string"])); + BOOST_CHECK(!isOfType(json["string"])); +} + +BOOST_AUTO_TEST_CASE(json_isisOfTypeIfExists) +{ + Json::Value json; + + json["float"] = 3.1f; + json["double"] = 3.1; + json["int"] = 2; + json["int64"] = Json::Int64{0x4000000000000000}; + json["string"] = "Hello World!"; + + BOOST_CHECK(isOfTypeIfExists(json, "float")); + BOOST_CHECK(isOfTypeIfExists(json, "double")); + BOOST_CHECK(isOfTypeIfExists(json, "int")); + BOOST_CHECK(isOfTypeIfExists(json, "int")); + BOOST_CHECK(isOfTypeIfExists(json, "int")); + BOOST_CHECK(isOfTypeIfExists(json, "int")); + BOOST_CHECK(isOfTypeIfExists(json, "int64")); + BOOST_CHECK(isOfTypeIfExists(json, "int64")); + BOOST_CHECK(isOfTypeIfExists(json, "string")); + BOOST_CHECK(!isOfTypeIfExists(json, "int64")); + BOOST_CHECK(!isOfTypeIfExists(json, "double")); + BOOST_CHECK(!isOfTypeIfExists(json, "string")); + BOOST_CHECK(!isOfTypeIfExists(json, "string")); + BOOST_CHECK(!isOfTypeIfExists(json, "string")); + BOOST_CHECK(!isOfTypeIfExists(json, "string")); + BOOST_CHECK(!isOfTypeIfExists(json, "string")); + BOOST_CHECK(!isOfTypeIfExists(json, "string")); + BOOST_CHECK(isOfTypeIfExists(json, "NOT_EXISTING")); +} + +BOOST_AUTO_TEST_CASE(json_getOrDefault) +{ + Json::Value json; + + json["float"] = 3.1f; + json["double"] = 3.1; + json["int"] = 2; + json["int64"] = Json::Int64{0x4000000000000000}; + json["uint64"] = Json::UInt64{0x5000000000000000}; + json["string"] = "Hello World!"; + + BOOST_CHECK(getOrDefault(json["float"]) == 3.1f); + BOOST_CHECK(getOrDefault(json["float"], -1.1f) == 3.1f); + BOOST_CHECK(getOrDefault(json["no_float"], -1.1f) == -1.1f); + BOOST_CHECK(getOrDefault(json["double"]) == 3.1); + BOOST_CHECK(getOrDefault(json["double"], -1) == 3.1); + BOOST_CHECK(getOrDefault(json["no_double"], -1.1) == -1.1); + BOOST_CHECK(getOrDefault(json["int"]) == 2); + BOOST_CHECK(getOrDefault(json["int"], -1) == 2); + BOOST_CHECK(getOrDefault(json["no_int"], -1) == -1); + BOOST_CHECK(getOrDefault(json["int"]) == 2); + BOOST_CHECK(getOrDefault(json["int"], -1) == 2); + BOOST_CHECK(getOrDefault(json["no_int"], -1) == -1); + BOOST_CHECK(getOrDefault(json["int"]) == 2); + BOOST_CHECK(getOrDefault(json["int"], 1) == 2); + BOOST_CHECK(getOrDefault(json["no_int"], 1) == 1); + BOOST_CHECK(getOrDefault(json["int"]) == 2); + BOOST_CHECK(getOrDefault(json["int"], -1) == 2); + BOOST_CHECK(getOrDefault(json["no_int"], -1) == -1); + BOOST_CHECK(getOrDefault(json["int64"]) == 0x4000000000000000); + BOOST_CHECK(getOrDefault(json["int64"], -1) == 0x4000000000000000); + BOOST_CHECK(getOrDefault(json["no_int64"], -1) == -1); + BOOST_CHECK(getOrDefault(json["int64"]) == 0x4000000000000000); + BOOST_CHECK(getOrDefault(json["int64"], 1) == 0x4000000000000000); + BOOST_CHECK(getOrDefault(json["no_int64"], 1) == 1); + BOOST_CHECK(getOrDefault(json["uint64"]) == 0x5000000000000000); + BOOST_CHECK(getOrDefault(json["uint64"], 1) == 0x5000000000000000); + BOOST_CHECK(getOrDefault(json["no_uint64"], 1) == 1); + BOOST_CHECK(getOrDefault(json["string"], "ERROR") == "Hello World!"); + BOOST_CHECK(getOrDefault(json["no_string"]).empty()); + BOOST_CHECK(getOrDefault(json["no_string"], "ERROR") == "ERROR"); +} + +BOOST_AUTO_TEST_CASE(json_get) +{ + Json::Value json; + + json["float"] = 3.1f; + json["double"] = 3.1; + json["int"] = 2; + json["int64"] = Json::Int64{0x4000000000000000}; + json["uint64"] = Json::UInt64{0x5000000000000000}; + json["string"] = "Hello World!"; + + BOOST_CHECK(get(json["float"]) == 3.1f); + BOOST_CHECK(get(json["double"]) == 3.1); + BOOST_CHECK(get(json["int"]) == 2); + BOOST_CHECK(get(json["int"]) == 2); + BOOST_CHECK(get(json["int"]) == 2); + BOOST_CHECK(get(json["int"]) == 2); + BOOST_CHECK(get(json["int64"]) == 0x4000000000000000); + BOOST_CHECK(get(json["int64"]) == 0x4000000000000000); + BOOST_CHECK(get(json["uint64"]) == 0x5000000000000000); + BOOST_CHECK(get(json["string"]) == "Hello World!"); +} + BOOST_AUTO_TEST_SUITE_END() }