summaryrefslogtreecommitdiff
path: root/test/redfish-core/include/utils/json_utils_test.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'test/redfish-core/include/utils/json_utils_test.cpp')
-rw-r--r--test/redfish-core/include/utils/json_utils_test.cpp358
1 files changed, 358 insertions, 0 deletions
diff --git a/test/redfish-core/include/utils/json_utils_test.cpp b/test/redfish-core/include/utils/json_utils_test.cpp
new file mode 100644
index 0000000000..826d4375a6
--- /dev/null
+++ b/test/redfish-core/include/utils/json_utils_test.cpp
@@ -0,0 +1,358 @@
+#include "http_request.hpp"
+#include "http_response.hpp"
+#include "utils/json_utils.hpp"
+
+#include <boost/beast/http/status.hpp>
+#include <nlohmann/json.hpp>
+
+#include <cstdint>
+#include <optional>
+#include <string>
+#include <system_error>
+#include <vector>
+
+#include <gmock/gmock.h> // IWYU pragma: keep
+#include <gtest/gtest.h> // IWYU pragma: keep
+
+// IWYU pragma: no_include <gtest/gtest-message.h>
+// IWYU pragma: no_include <gtest/gtest-test-part.h>
+// IWYU pragma: no_include "gtest/gtest_pred_impl.h"
+// IWYU pragma: no_include <boost/intrusive/detail/list_iterator.hpp>
+
+namespace redfish::json_util
+{
+namespace
+{
+
+using ::testing::ElementsAre;
+using ::testing::IsEmpty;
+using ::testing::Not;
+
+TEST(ReadJson, ValidElementsReturnsTrueResponseOkValuesUnpackedCorrectly)
+{
+ crow::Response res;
+ nlohmann::json jsonRequest = {{"integer", 1},
+ {"string", "hello"},
+ {"vector", std::vector<uint64_t>{1, 2, 3}}};
+
+ int64_t integer = 0;
+ std::string str;
+ std::vector<uint64_t> vec;
+ ASSERT_TRUE(readJson(jsonRequest, res, "integer", integer, "string", str,
+ "vector", vec));
+ EXPECT_EQ(res.result(), boost::beast::http::status::ok);
+ EXPECT_THAT(res.jsonValue, IsEmpty());
+
+ EXPECT_EQ(integer, 1);
+ EXPECT_EQ(str, "hello");
+ EXPECT_THAT(vec, ElementsAre(1, 2, 3));
+}
+
+TEST(readJson, ExtraElementsReturnsFalseReponseIsBadRequest)
+{
+ crow::Response res;
+ nlohmann::json jsonRequest = {{"integer", 1}, {"string", "hello"}};
+
+ std::optional<int> integer;
+ std::optional<std::string> str;
+
+ ASSERT_FALSE(readJson(jsonRequest, res, "integer", integer));
+ EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
+ EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
+ EXPECT_EQ(integer, 1);
+
+ ASSERT_FALSE(readJson(jsonRequest, res, "string", str));
+ EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
+ EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
+ EXPECT_EQ(str, "hello");
+}
+
+TEST(ReadJson, WrongElementTypeReturnsFalseReponseIsBadRequest)
+{
+ crow::Response res;
+ nlohmann::json jsonRequest = {{"integer", 1}, {"string0", "hello"}};
+
+ int64_t integer = 0;
+ std::string str0;
+ ASSERT_FALSE(readJson(jsonRequest, res, "integer", str0));
+ EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
+ EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
+
+ ASSERT_FALSE(readJson(jsonRequest, res, "string0", integer));
+ EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
+ EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
+
+ ASSERT_FALSE(
+ readJson(jsonRequest, res, "integer", str0, "string0", integer));
+ EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
+ EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
+}
+
+TEST(ReadJson, MissingElementReturnsFalseReponseIsBadRequest)
+{
+ crow::Response res;
+ nlohmann::json jsonRequest = {{"integer", 1}, {"string0", "hello"}};
+
+ int64_t integer = 0;
+ std::string str0;
+ std::string str1;
+ std::vector<uint8_t> vec;
+ ASSERT_FALSE(readJson(jsonRequest, res, "integer", integer, "string0", str0,
+ "vector", vec));
+ EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
+ EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
+
+ ASSERT_FALSE(readJson(jsonRequest, res, "integer", integer, "string0", str0,
+ "string1", str1));
+ EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
+ EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
+}
+
+TEST(ReadJson, JsonArrayAreUnpackedCorrectly)
+{
+ crow::Response res;
+ nlohmann::json jsonRequest = R"(
+ {
+ "TestJson": [{"hello": "yes"}, [{"there": "no"}, "nice"]]
+ }
+ )"_json;
+
+ std::vector<nlohmann::json> jsonVec;
+ ASSERT_TRUE(readJson(jsonRequest, res, "TestJson", jsonVec));
+ EXPECT_EQ(res.result(), boost::beast::http::status::ok);
+ EXPECT_THAT(res.jsonValue, IsEmpty());
+ EXPECT_EQ(jsonVec, R"([{"hello": "yes"}, [{"there": "no"}, "nice"]])"_json);
+}
+
+TEST(ReadJson, JsonSubElementValueAreUnpackedCorrectly)
+{
+ crow::Response res;
+ nlohmann::json jsonRequest = R"(
+ {
+ "json": {"integer": 42}
+ }
+ )"_json;
+
+ int integer = 0;
+ ASSERT_TRUE(readJson(jsonRequest, res, "json/integer", integer));
+ EXPECT_EQ(integer, 42);
+ EXPECT_EQ(res.result(), boost::beast::http::status::ok);
+ EXPECT_THAT(res.jsonValue, IsEmpty());
+}
+
+TEST(ReadJson, JsonDeeperSubElementValueAreUnpackedCorrectly)
+{
+ crow::Response res;
+ nlohmann::json jsonRequest = R"(
+ {
+ "json": {
+ "json2": {"string": "foobar"}
+ }
+ }
+ )"_json;
+
+ std::string foobar;
+ ASSERT_TRUE(readJson(jsonRequest, res, "json/json2/string", foobar));
+ EXPECT_EQ(foobar, "foobar");
+ EXPECT_EQ(res.result(), boost::beast::http::status::ok);
+ EXPECT_THAT(res.jsonValue, IsEmpty());
+}
+
+TEST(ReadJson, MultipleJsonSubElementValueAreUnpackedCorrectly)
+{
+ crow::Response res;
+ nlohmann::json jsonRequest = R"(
+ {
+ "json": {
+ "integer": 42,
+ "string": "foobar"
+ },
+ "string": "bazbar"
+ }
+ )"_json;
+
+ int integer = 0;
+ std::string foobar;
+ std::string bazbar;
+ ASSERT_TRUE(readJson(jsonRequest, res, "json/integer", integer,
+ "json/string", foobar, "string", bazbar));
+ EXPECT_EQ(integer, 42);
+ EXPECT_EQ(foobar, "foobar");
+ EXPECT_EQ(bazbar, "bazbar");
+ EXPECT_EQ(res.result(), boost::beast::http::status::ok);
+ EXPECT_THAT(res.jsonValue, IsEmpty());
+}
+
+TEST(ReadJson, ExtraElement)
+{
+ crow::Response res;
+ nlohmann::json jsonRequest = {{"integer", 1}, {"string", "hello"}};
+
+ std::optional<int> integer;
+ std::optional<std::string> str;
+
+ EXPECT_FALSE(readJson(jsonRequest, res, "integer", integer));
+ EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
+ EXPECT_FALSE(res.jsonValue.empty());
+ EXPECT_EQ(integer, 1);
+
+ EXPECT_FALSE(readJson(jsonRequest, res, "string", str));
+ EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
+ EXPECT_FALSE(res.jsonValue.empty());
+ EXPECT_EQ(str, "hello");
+}
+
+TEST(ReadJson, ValidMissingElementReturnsTrue)
+{
+ crow::Response res;
+ nlohmann::json jsonRequest = {{"integer", 1}};
+
+ std::optional<int> integer;
+ int requiredInteger = 0;
+ std::optional<std::string> str0;
+ std::optional<std::string> str1;
+ std::optional<std::vector<uint8_t>> vec;
+ ASSERT_TRUE(readJson(jsonRequest, res, "missing_integer", integer,
+ "integer", requiredInteger));
+ EXPECT_EQ(res.result(), boost::beast::http::status::ok);
+ EXPECT_TRUE(res.jsonValue.empty());
+ EXPECT_EQ(integer, std::nullopt);
+
+ ASSERT_TRUE(readJson(jsonRequest, res, "missing_string", str0, "integer",
+ requiredInteger));
+ EXPECT_EQ(res.result(), boost::beast::http::status::ok);
+ EXPECT_THAT(res.jsonValue, IsEmpty());
+ EXPECT_EQ(str0, std::nullopt);
+
+ ASSERT_TRUE(readJson(jsonRequest, res, "integer", integer, "string", str0,
+ "vector", vec));
+ EXPECT_EQ(res.result(), boost::beast::http::status::ok);
+ EXPECT_THAT(res.jsonValue, IsEmpty());
+ EXPECT_EQ(integer, 1);
+ EXPECT_EQ(str0, std::nullopt);
+ EXPECT_EQ(vec, std::nullopt);
+
+ ASSERT_TRUE(readJson(jsonRequest, res, "integer", integer, "string0", str0,
+ "missing_string", str1));
+ EXPECT_EQ(res.result(), boost::beast::http::status::ok);
+ EXPECT_THAT(res.jsonValue, IsEmpty());
+ EXPECT_EQ(str1, std::nullopt);
+}
+
+TEST(ReadJson, InvalidMissingElementReturnsFalse)
+{
+ crow::Response res;
+ nlohmann::json jsonRequest = {{"integer", 1}, {"string", "hello"}};
+
+ int integer = 0;
+ std::string str0;
+ std::string str1;
+ std::vector<uint8_t> vec;
+ ASSERT_FALSE(readJson(jsonRequest, res, "missing_integer", integer));
+ EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
+ EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
+
+ ASSERT_FALSE(readJson(jsonRequest, res, "missing_string", str0));
+ EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
+ EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
+
+ ASSERT_FALSE(readJson(jsonRequest, res, "integer", integer, "string", str0,
+ "vector", vec));
+ EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
+ EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
+
+ ASSERT_FALSE(readJson(jsonRequest, res, "integer", integer, "string0", str0,
+ "missing_string", str1));
+ EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
+ EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
+}
+
+TEST(ReadJsonPatch, ValidElementsReturnsTrueResponseOkValuesUnpackedCorrectly)
+{
+ crow::Response res;
+ std::error_code ec;
+ crow::Request req({}, ec);
+ // Ignore errors intentionally
+ req.body = "{\"integer\": 1}";
+
+ int64_t integer = 0;
+ ASSERT_TRUE(readJsonPatch(req, res, "integer", integer));
+ EXPECT_EQ(res.result(), boost::beast::http::status::ok);
+ EXPECT_THAT(res.jsonValue, IsEmpty());
+ EXPECT_EQ(integer, 1);
+}
+
+TEST(ReadJsonPatch, EmptyObjectReturnsFalseResponseBadRequest)
+{
+ crow::Response res;
+ std::error_code ec;
+ crow::Request req({}, ec);
+ // Ignore errors intentionally
+ req.body = "{}";
+
+ std::optional<int64_t> integer = 0;
+ ASSERT_FALSE(readJsonPatch(req, res, "integer", integer));
+ EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
+ EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
+}
+
+TEST(ReadJsonPatch, OdataIgnored)
+{
+ crow::Response res;
+ std::error_code ec;
+ crow::Request req({}, ec);
+ // Ignore errors intentionally
+ req.body = R"({"@odata.etag": "etag", "integer": 1})";
+
+ std::optional<int64_t> integer = 0;
+ ASSERT_TRUE(readJsonPatch(req, res, "integer", integer));
+ EXPECT_EQ(res.result(), boost::beast::http::status::ok);
+ EXPECT_THAT(res.jsonValue, IsEmpty());
+ EXPECT_EQ(integer, 1);
+}
+
+TEST(ReadJsonPatch, OnlyOdataGivesNoOperation)
+{
+ crow::Response res;
+ std::error_code ec;
+ crow::Request req({}, ec);
+ // Ignore errors intentionally
+ req.body = R"({"@odata.etag": "etag"})";
+
+ std::optional<int64_t> integer = 0;
+ ASSERT_FALSE(readJsonPatch(req, res, "integer", integer));
+ EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
+ EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
+}
+
+TEST(ReadJsonAction, ValidElementsReturnsTrueResponseOkValuesUnpackedCorrectly)
+{
+ crow::Response res;
+ std::error_code ec;
+ crow::Request req({}, ec);
+ // Ignore errors intentionally
+ req.body = "{\"integer\": 1}";
+
+ int64_t integer = 0;
+ ASSERT_TRUE(readJsonAction(req, res, "integer", integer));
+ EXPECT_EQ(res.result(), boost::beast::http::status::ok);
+ EXPECT_THAT(res.jsonValue, IsEmpty());
+ EXPECT_EQ(integer, 1);
+}
+
+TEST(ReadJsonAction, EmptyObjectReturnsTrueResponseOk)
+{
+ crow::Response res;
+ std::error_code ec;
+ crow::Request req({}, ec);
+ // Ignore errors intentionally
+ req.body = "{}";
+
+ std::optional<int64_t> integer = 0;
+ ASSERT_TRUE(readJsonAction(req, res, "integer", integer));
+ EXPECT_EQ(res.result(), boost::beast::http::status::ok);
+ EXPECT_THAT(res.jsonValue, IsEmpty());
+}
+
+} // namespace
+} // namespace redfish::json_util \ No newline at end of file