Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 62 additions & 0 deletions libsolutil/JSON.h
Original file line number Diff line number Diff line change
Expand Up @@ -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<typename T>
struct helper;

template<typename T, bool(Json::Value::*checkMember)() const, T(Json::Value::*convertMember)() const>
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<float>: helper_impl<float, &Json::Value::isDouble, &Json::Value::asFloat> {};
template<> struct helper<double>: helper_impl<double, &Json::Value::isDouble, &Json::Value::asDouble> {};
template<> struct helper<std::string>: helper_impl<std::string, &Json::Value::isString, &Json::Value::asString> {};
template<> struct helper<Json::Int>: helper_impl<Json::Int, &Json::Value::isInt, &Json::Value::asInt> {};
template<> struct helper<Json::Int64>: helper_impl<Json::Int64, &Json::Value::isInt64, &Json::Value::asInt64> {};
template<> struct helper<Json::UInt>: helper_impl<Json::UInt, &Json::Value::isUInt, &Json::Value::asUInt> {};
template<> struct helper<Json::UInt64>: helper_impl<Json::UInt64, &Json::Value::isUInt64, &Json::Value::asUInt64> {};

} // namespace detail

template<typename T>
bool isOfType(Json::Value const& _input)
{
return detail::helper<T>::isOfType(_input);
}

template<typename T>
bool isOfTypeIfExists(Json::Value const& _input, std::string const& _name)
{
if (_input.isMember(_name))
return isOfType<T>(_input[_name]);
return true;
}

template<typename T>
T get(Json::Value const& _input)
{
return detail::helper<T>::get(_input);
}

template<typename T>
T getOrDefault(Json::Value const& _input, T _default = {})
{
return detail::helper<T>::getOrDefault(_input, _default);
}

} // namespace solidity::util
125 changes: 125 additions & 0 deletions test/libsolutil/JSON.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<float>(json["float"]));
BOOST_CHECK(isOfType<double>(json["double"]));
BOOST_CHECK(isOfType<int>(json["int"]));
BOOST_CHECK(isOfType<Json::Int>(json["int"]));
BOOST_CHECK(isOfType<Json::UInt>(json["int"]));
BOOST_CHECK(isOfType<Json::Int64>(json["int"]));
BOOST_CHECK(isOfType<Json::Int64>(json["int64"]));
BOOST_CHECK(isOfType<Json::UInt64>(json["int64"]));
BOOST_CHECK(isOfType<std::string>(json["string"]));
BOOST_CHECK(!isOfType<Json::Int>(json["int64"]));
BOOST_CHECK(!isOfType<int>(json["double"]));
BOOST_CHECK(!isOfType<float>(json["string"]));
BOOST_CHECK(!isOfType<double>(json["string"]));
BOOST_CHECK(!isOfType<Json::Int>(json["string"]));
BOOST_CHECK(!isOfType<Json::Int64>(json["string"]));
BOOST_CHECK(!isOfType<Json::UInt>(json["string"]));
BOOST_CHECK(!isOfType<Json::UInt64>(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<float>(json, "float"));
BOOST_CHECK(isOfTypeIfExists<double>(json, "double"));
BOOST_CHECK(isOfTypeIfExists<int>(json, "int"));
BOOST_CHECK(isOfTypeIfExists<Json::Int>(json, "int"));
BOOST_CHECK(isOfTypeIfExists<Json::UInt>(json, "int"));
BOOST_CHECK(isOfTypeIfExists<Json::Int64>(json, "int"));
BOOST_CHECK(isOfTypeIfExists<Json::Int64>(json, "int64"));
BOOST_CHECK(isOfTypeIfExists<Json::UInt64>(json, "int64"));
BOOST_CHECK(isOfTypeIfExists<std::string>(json, "string"));
BOOST_CHECK(!isOfTypeIfExists<Json::Int>(json, "int64"));
BOOST_CHECK(!isOfTypeIfExists<int>(json, "double"));
BOOST_CHECK(!isOfTypeIfExists<float>(json, "string"));
BOOST_CHECK(!isOfTypeIfExists<double>(json, "string"));
BOOST_CHECK(!isOfTypeIfExists<Json::Int>(json, "string"));
BOOST_CHECK(!isOfTypeIfExists<Json::Int64>(json, "string"));
BOOST_CHECK(!isOfTypeIfExists<Json::UInt>(json, "string"));
BOOST_CHECK(!isOfTypeIfExists<Json::UInt64>(json, "string"));
BOOST_CHECK(isOfTypeIfExists<Json::UInt64>(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<float>(json["float"]) == 3.1f);
BOOST_CHECK(getOrDefault<float>(json["float"], -1.1f) == 3.1f);
BOOST_CHECK(getOrDefault<float>(json["no_float"], -1.1f) == -1.1f);
BOOST_CHECK(getOrDefault<double>(json["double"]) == 3.1);
BOOST_CHECK(getOrDefault<double>(json["double"], -1) == 3.1);
BOOST_CHECK(getOrDefault<double>(json["no_double"], -1.1) == -1.1);
BOOST_CHECK(getOrDefault<int>(json["int"]) == 2);
BOOST_CHECK(getOrDefault<int>(json["int"], -1) == 2);
BOOST_CHECK(getOrDefault<int>(json["no_int"], -1) == -1);
BOOST_CHECK(getOrDefault<Json::Int>(json["int"]) == 2);
BOOST_CHECK(getOrDefault<Json::Int>(json["int"], -1) == 2);
BOOST_CHECK(getOrDefault<Json::Int>(json["no_int"], -1) == -1);
BOOST_CHECK(getOrDefault<Json::UInt>(json["int"]) == 2);
BOOST_CHECK(getOrDefault<Json::UInt>(json["int"], 1) == 2);
BOOST_CHECK(getOrDefault<Json::UInt>(json["no_int"], 1) == 1);
BOOST_CHECK(getOrDefault<Json::Int64>(json["int"]) == 2);
BOOST_CHECK(getOrDefault<Json::Int64>(json["int"], -1) == 2);
BOOST_CHECK(getOrDefault<Json::Int64>(json["no_int"], -1) == -1);
BOOST_CHECK(getOrDefault<Json::Int64>(json["int64"]) == 0x4000000000000000);
BOOST_CHECK(getOrDefault<Json::Int64>(json["int64"], -1) == 0x4000000000000000);
BOOST_CHECK(getOrDefault<Json::Int64>(json["no_int64"], -1) == -1);
BOOST_CHECK(getOrDefault<Json::UInt64>(json["int64"]) == 0x4000000000000000);
BOOST_CHECK(getOrDefault<Json::UInt64>(json["int64"], 1) == 0x4000000000000000);
BOOST_CHECK(getOrDefault<Json::UInt64>(json["no_int64"], 1) == 1);
BOOST_CHECK(getOrDefault<Json::UInt64>(json["uint64"]) == 0x5000000000000000);
BOOST_CHECK(getOrDefault<Json::UInt64>(json["uint64"], 1) == 0x5000000000000000);
BOOST_CHECK(getOrDefault<Json::UInt64>(json["no_uint64"], 1) == 1);
BOOST_CHECK(getOrDefault<std::string>(json["string"], "ERROR") == "Hello World!");
BOOST_CHECK(getOrDefault<std::string>(json["no_string"]).empty());
BOOST_CHECK(getOrDefault<std::string>(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<float>(json["float"]) == 3.1f);
BOOST_CHECK(get<double>(json["double"]) == 3.1);
BOOST_CHECK(get<int>(json["int"]) == 2);
BOOST_CHECK(get<Json::Int>(json["int"]) == 2);
BOOST_CHECK(get<Json::UInt>(json["int"]) == 2);
BOOST_CHECK(get<Json::Int64>(json["int"]) == 2);
BOOST_CHECK(get<Json::Int64>(json["int64"]) == 0x4000000000000000);
BOOST_CHECK(get<Json::UInt64>(json["int64"]) == 0x4000000000000000);
BOOST_CHECK(get<Json::UInt64>(json["uint64"]) == 0x5000000000000000);
BOOST_CHECK(get<std::string>(json["string"]) == "Hello World!");
}

BOOST_AUTO_TEST_SUITE_END()

}