diff options
-rw-r--r-- | redfish-core/include/utils/json_utils.hpp | 78 | ||||
-rw-r--r-- | test/redfish-core/include/utils/json_utils_test.cpp | 29 |
2 files changed, 106 insertions, 1 deletions
diff --git a/redfish-core/include/utils/json_utils.hpp b/redfish-core/include/utils/json_utils.hpp index 0f4ba06a14..feb4e5460f 100644 --- a/redfish-core/include/utils/json_utils.hpp +++ b/redfish-core/include/utils/json_utils.hpp @@ -90,6 +90,14 @@ template <typename Type, std::size_t size> struct IsStdArray<std::array<Type, size>> : std::true_type {}; +template <typename Type> +struct IsVariant : std::false_type +{}; + +template <typename... Types> +struct IsVariant<std::variant<Types...>> : std::true_type +{}; + enum class UnpackErrorCode { success, @@ -126,6 +134,29 @@ bool checkRange(const FromType& from, std::string_view key) template <typename Type> UnpackErrorCode unpackValueWithErrorCode(nlohmann::json& jsonValue, + std::string_view key, Type& value); + +template <std::size_t Index = 0, typename... Args> +UnpackErrorCode unpackValueVariant(nlohmann::json& j, std::string_view key, + std::variant<Args...>& v) +{ + if constexpr (Index < std::variant_size_v<std::variant<Args...>>) + { + std::variant_alternative_t<Index, std::variant<Args...>> type; + UnpackErrorCode unpack = unpackValueWithErrorCode(j, key, type); + if (unpack == UnpackErrorCode::success) + { + v = std::move(type); + return unpack; + } + + return unpackValueVariant<Index + 1, Args...>(j, key, v); + } + return UnpackErrorCode::invalidType; +} + +template <typename Type> +UnpackErrorCode unpackValueWithErrorCode(nlohmann::json& jsonValue, std::string_view key, Type& value) { UnpackErrorCode ret = UnpackErrorCode::success; @@ -188,6 +219,13 @@ UnpackErrorCode unpackValueWithErrorCode(nlohmann::json& jsonValue, { value = std::move(jsonValue); } + else if constexpr (std::is_same_v<std::nullptr_t, Type>) + { + if (!jsonValue.is_null()) + { + return UnpackErrorCode::invalidType; + } + } else { using JsonType = std::add_const_t<std::add_pointer_t<Type>>; @@ -252,6 +290,22 @@ bool unpackValue(nlohmann::json& jsonValue, std::string_view key, ret; } } + else if constexpr (IsVariant<Type>::value) + { + UnpackErrorCode ec = unpackValueVariant(jsonValue, key, value); + if (ec != UnpackErrorCode::success) + { + if (ec == UnpackErrorCode::invalidType) + { + messages::propertyValueTypeError(res, jsonValue, key); + } + else if (ec == UnpackErrorCode::outOfRange) + { + messages::propertyValueNotInList(res, jsonValue, key); + } + return false; + } + } else { UnpackErrorCode ec = unpackValueWithErrorCode(jsonValue, key, value); @@ -342,6 +396,16 @@ using UnpackVariant = std::variant< std::string*, nlohmann::json*, nlohmann::json::object_t*, + std::variant<std::string, std::nullptr_t>*, + std::variant<uint8_t, std::nullptr_t>*, + std::variant<int16_t, std::nullptr_t>*, + std::variant<uint16_t, std::nullptr_t>*, + std::variant<int32_t, std::nullptr_t>*, + std::variant<uint32_t, std::nullptr_t>*, + std::variant<int64_t, std::nullptr_t>*, + std::variant<uint64_t, std::nullptr_t>*, + std::variant<double, std::nullptr_t>*, + std::variant<bool, std::nullptr_t>*, std::vector<uint8_t>*, std::vector<uint16_t>*, std::vector<int16_t>*, @@ -377,7 +441,19 @@ using UnpackVariant = std::variant< std::optional<std::vector<double>>*, std::optional<std::vector<std::string>>*, std::optional<std::vector<nlohmann::json>>*, - std::optional<std::vector<nlohmann::json::object_t>>* + std::optional<std::vector<nlohmann::json::object_t>>*, + std::optional<std::variant<std::string, std::nullptr_t>>*, + std::optional<std::variant<uint8_t, std::nullptr_t>>*, + std::optional<std::variant<int16_t, std::nullptr_t>>*, + std::optional<std::variant<uint16_t, std::nullptr_t>>*, + std::optional<std::variant<int32_t, std::nullptr_t>>*, + std::optional<std::variant<uint32_t, std::nullptr_t>>*, + std::optional<std::variant<int64_t, std::nullptr_t>>*, + std::optional<std::variant<uint64_t, std::nullptr_t>>*, + std::optional<std::variant<double, std::nullptr_t>>*, + std::optional<std::variant<bool, std::nullptr_t>>*, + std::optional<std::vector<std::variant<nlohmann::json::object_t, std::nullptr_t>>>*, + std::optional<std::variant<nlohmann::json::object_t, std::nullptr_t>>* >; // clang-format on diff --git a/test/redfish-core/include/utils/json_utils_test.cpp b/test/redfish-core/include/utils/json_utils_test.cpp index 5ef80eeba6..cf5929756b 100644 --- a/test/redfish-core/include/utils/json_utils_test.cpp +++ b/test/redfish-core/include/utils/json_utils_test.cpp @@ -6,10 +6,12 @@ #include <boost/beast/http/status.hpp> #include <nlohmann/json.hpp> +#include <cstddef> #include <cstdint> #include <optional> #include <string> #include <system_error> +#include <variant> #include <vector> #include <gmock/gmock.h> // IWYU pragma: keep @@ -70,6 +72,33 @@ TEST(ReadJson, ValidObjectElementsReturnsTrueResponseOkValuesUnpackedCorrectly) EXPECT_THAT(vec, ElementsAre(1, 2, 3)); } +TEST(ReadJson, VariantValueUnpackedNull) +{ + crow::Response res; + nlohmann::json jsonRequest = {{"nullval", nullptr}}; + + std::variant<std::string, std::nullptr_t> str; + + ASSERT_TRUE(readJson(jsonRequest, res, "nullval", str)); + EXPECT_EQ(res.result(), boost::beast::http::status::ok); + + EXPECT_TRUE(std::holds_alternative<std::nullptr_t>(str)); +} + +TEST(ReadJson, VariantValueUnpackedValue) +{ + crow::Response res; + nlohmann::json jsonRequest = {{"stringval", "mystring"}}; + + std::variant<std::string, std::nullptr_t> str; + + ASSERT_TRUE(readJson(jsonRequest, res, "stringval", str)); + EXPECT_EQ(res.result(), boost::beast::http::status::ok); + + ASSERT_TRUE(std::holds_alternative<std::string>(str)); + EXPECT_EQ(std::get<std::string>(str), "mystring"); +} + TEST(readJson, ExtraElementsReturnsFalseReponseIsBadRequest) { crow::Response res; |