1 #include "http_request.hpp"
2 #include "http_response.hpp"
3 #include "utils/json_utils.hpp"
4 
5 #include <boost/beast/http/field.hpp>
6 #include <boost/beast/http/status.hpp>
7 #include <nlohmann/json.hpp>
8 
9 #include <cstddef>
10 #include <cstdint>
11 #include <optional>
12 #include <string>
13 #include <system_error>
14 #include <variant>
15 #include <vector>
16 
17 #include <gmock/gmock.h>
18 #include <gtest/gtest.h>
19 
20 namespace redfish::json_util
21 {
22 namespace
23 {
24 
25 using ::testing::ElementsAre;
26 using ::testing::IsEmpty;
27 using ::testing::Not;
28 
TEST(ReadJson,ValidElementsReturnsTrueResponseOkValuesUnpackedCorrectly)29 TEST(ReadJson, ValidElementsReturnsTrueResponseOkValuesUnpackedCorrectly)
30 {
31     crow::Response res;
32     nlohmann::json jsonRequest = {{"integer", 1},
33                                   {"string", "hello"},
34                                   {"vector", std::vector<uint64_t>{1, 2, 3}}};
35 
36     int64_t integer = 0;
37     std::string str;
38     std::vector<uint64_t> vec;
39     ASSERT_TRUE(readJson(jsonRequest, res, "integer", integer, "string", str,
40                          "vector", vec));
41     EXPECT_EQ(res.result(), boost::beast::http::status::ok);
42     EXPECT_THAT(res.jsonValue, IsEmpty());
43 
44     EXPECT_EQ(integer, 1);
45     EXPECT_EQ(str, "hello");
46     EXPECT_THAT(vec, ElementsAre(1, 2, 3));
47 }
48 
TEST(ReadJson,ValidObjectElementsReturnsTrueResponseOkValuesUnpackedCorrectly)49 TEST(ReadJson, ValidObjectElementsReturnsTrueResponseOkValuesUnpackedCorrectly)
50 {
51     crow::Response res;
52     nlohmann::json::object_t jsonRequest;
53     jsonRequest["integer"] = 1;
54     jsonRequest["string"] = "hello";
55     jsonRequest["vector"] = std::vector<uint64_t>{1, 2, 3};
56 
57     int64_t integer = 0;
58     std::string str;
59     std::vector<uint64_t> vec;
60     ASSERT_TRUE(readJsonObject(jsonRequest, res, "integer", integer, "string",
61                                str, "vector", vec));
62     EXPECT_EQ(res.result(), boost::beast::http::status::ok);
63     EXPECT_THAT(res.jsonValue, IsEmpty());
64 
65     EXPECT_EQ(integer, 1);
66     EXPECT_EQ(str, "hello");
67     EXPECT_THAT(vec, ElementsAre(1, 2, 3));
68 }
69 
TEST(ReadJson,VariantValueUnpackedNull)70 TEST(ReadJson, VariantValueUnpackedNull)
71 {
72     crow::Response res;
73     nlohmann::json jsonRequest = {{"nullval", nullptr}};
74 
75     std::variant<std::string, std::nullptr_t> str;
76 
77     ASSERT_TRUE(readJson(jsonRequest, res, "nullval", str));
78     EXPECT_EQ(res.result(), boost::beast::http::status::ok);
79 
80     EXPECT_TRUE(std::holds_alternative<std::nullptr_t>(str));
81 }
82 
TEST(ReadJson,VariantValueUnpackedValue)83 TEST(ReadJson, VariantValueUnpackedValue)
84 {
85     crow::Response res;
86     nlohmann::json jsonRequest = {{"stringval", "mystring"}};
87 
88     std::variant<std::string, std::nullptr_t> str;
89 
90     ASSERT_TRUE(readJson(jsonRequest, res, "stringval", str));
91     EXPECT_EQ(res.result(), boost::beast::http::status::ok);
92 
93     ASSERT_TRUE(std::holds_alternative<std::string>(str));
94     EXPECT_EQ(std::get<std::string>(str), "mystring");
95 }
96 
TEST(readJson,ExtraElementsReturnsFalseReponseIsBadRequest)97 TEST(readJson, ExtraElementsReturnsFalseReponseIsBadRequest)
98 {
99     crow::Response res;
100     nlohmann::json jsonRequest = {{"integer", 1}, {"string", "hello"}};
101 
102     std::optional<int> integer;
103     std::optional<std::string> str;
104 
105     ASSERT_FALSE(readJson(jsonRequest, res, "integer", integer));
106     EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
107     EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
108     EXPECT_EQ(integer, 1);
109 
110     ASSERT_FALSE(readJson(jsonRequest, res, "string", str));
111     EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
112     EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
113     EXPECT_EQ(str, "hello");
114 }
115 
TEST(ReadJson,WrongElementTypeReturnsFalseReponseIsBadRequest)116 TEST(ReadJson, WrongElementTypeReturnsFalseReponseIsBadRequest)
117 {
118     crow::Response res;
119     nlohmann::json jsonRequest = {{"integer", 1}, {"string0", "hello"}};
120 
121     int64_t integer = 0;
122     std::string str0;
123     ASSERT_FALSE(readJson(jsonRequest, res, "integer", str0));
124     EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
125     EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
126 
127     ASSERT_FALSE(readJson(jsonRequest, res, "string0", integer));
128     EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
129     EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
130 
131     ASSERT_FALSE(
132         readJson(jsonRequest, res, "integer", str0, "string0", integer));
133     EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
134     EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
135 }
136 
TEST(ReadJson,MissingElementReturnsFalseReponseIsBadRequest)137 TEST(ReadJson, MissingElementReturnsFalseReponseIsBadRequest)
138 {
139     crow::Response res;
140     nlohmann::json jsonRequest = {{"integer", 1}, {"string0", "hello"}};
141 
142     int64_t integer = 0;
143     std::string str0;
144     std::string str1;
145     std::vector<uint8_t> vec;
146     ASSERT_FALSE(readJson(jsonRequest, res, "integer", integer, "string0", str0,
147                           "vector", vec));
148     EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
149     EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
150 
151     ASSERT_FALSE(readJson(jsonRequest, res, "integer", integer, "string0", str0,
152                           "string1", str1));
153     EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
154     EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
155 }
156 
TEST(ReadJson,JsonArrayAreUnpackedCorrectly)157 TEST(ReadJson, JsonArrayAreUnpackedCorrectly)
158 {
159     crow::Response res;
160     nlohmann::json jsonRequest = R"(
161         {
162             "TestJson": [{"hello": "yes"}, [{"there": "no"}, "nice"]]
163         }
164     )"_json;
165 
166     std::vector<nlohmann::json> jsonVec;
167     ASSERT_TRUE(readJson(jsonRequest, res, "TestJson", jsonVec));
168     EXPECT_EQ(res.result(), boost::beast::http::status::ok);
169     EXPECT_THAT(res.jsonValue, IsEmpty());
170     EXPECT_THAT(jsonVec, ElementsAre(R"({"hello": "yes"})"_json,
171                                      R"([{"there": "no"}, "nice"])"_json));
172 }
173 
TEST(ReadJson,JsonSubElementValueAreUnpackedCorrectly)174 TEST(ReadJson, JsonSubElementValueAreUnpackedCorrectly)
175 {
176     crow::Response res;
177     nlohmann::json jsonRequest = R"(
178         {
179             "json": {"integer": 42}
180         }
181     )"_json;
182 
183     int integer = 0;
184     ASSERT_TRUE(readJson(jsonRequest, res, "json/integer", integer));
185     EXPECT_EQ(integer, 42);
186     EXPECT_EQ(res.result(), boost::beast::http::status::ok);
187     EXPECT_THAT(res.jsonValue, IsEmpty());
188 }
189 
TEST(ReadJson,JsonDeeperSubElementValueAreUnpackedCorrectly)190 TEST(ReadJson, JsonDeeperSubElementValueAreUnpackedCorrectly)
191 {
192     crow::Response res;
193     nlohmann::json jsonRequest = R"(
194         {
195             "json": {
196                 "json2": {"string": "foobar"}
197             }
198         }
199     )"_json;
200 
201     std::string foobar;
202     ASSERT_TRUE(readJson(jsonRequest, res, "json/json2/string", foobar));
203     EXPECT_EQ(foobar, "foobar");
204     EXPECT_EQ(res.result(), boost::beast::http::status::ok);
205     EXPECT_THAT(res.jsonValue, IsEmpty());
206 }
207 
TEST(ReadJson,MultipleJsonSubElementValueAreUnpackedCorrectly)208 TEST(ReadJson, MultipleJsonSubElementValueAreUnpackedCorrectly)
209 {
210     crow::Response res;
211     nlohmann::json jsonRequest = R"(
212         {
213             "json": {
214                 "integer": 42,
215                 "string": "foobar"
216             },
217             "string": "bazbar"
218         }
219     )"_json;
220 
221     int integer = 0;
222     std::string foobar;
223     std::string bazbar;
224     ASSERT_TRUE(readJson(jsonRequest, res, "json/integer", integer,
225                          "json/string", foobar, "string", bazbar));
226     EXPECT_EQ(integer, 42);
227     EXPECT_EQ(foobar, "foobar");
228     EXPECT_EQ(bazbar, "bazbar");
229     EXPECT_EQ(res.result(), boost::beast::http::status::ok);
230     EXPECT_THAT(res.jsonValue, IsEmpty());
231 }
232 
TEST(ReadJson,ExtraElement)233 TEST(ReadJson, ExtraElement)
234 {
235     crow::Response res;
236     nlohmann::json jsonRequest = {{"integer", 1}, {"string", "hello"}};
237 
238     std::optional<int> integer;
239     std::optional<std::string> str;
240 
241     EXPECT_FALSE(readJson(jsonRequest, res, "integer", integer));
242     EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
243     EXPECT_FALSE(res.jsonValue.empty());
244     EXPECT_EQ(integer, 1);
245 
246     EXPECT_FALSE(readJson(jsonRequest, res, "string", str));
247     EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
248     EXPECT_FALSE(res.jsonValue.empty());
249     EXPECT_EQ(str, "hello");
250 }
251 
TEST(ReadJson,ValidMissingElementReturnsTrue)252 TEST(ReadJson, ValidMissingElementReturnsTrue)
253 {
254     crow::Response res;
255     nlohmann::json jsonRequest = {{"integer", 1}};
256 
257     std::optional<int> integer;
258     int requiredInteger = 0;
259     std::optional<std::string> str0;
260     std::optional<std::string> str1;
261     std::optional<std::vector<uint8_t>> vec;
262     ASSERT_TRUE(readJson(jsonRequest, res, "missing_integer", integer,
263                          "integer", requiredInteger));
264     EXPECT_EQ(res.result(), boost::beast::http::status::ok);
265     EXPECT_TRUE(res.jsonValue.empty());
266     EXPECT_EQ(integer, std::nullopt);
267 
268     ASSERT_TRUE(readJson(jsonRequest, res, "missing_string", str0, "integer",
269                          requiredInteger));
270     EXPECT_EQ(res.result(), boost::beast::http::status::ok);
271     EXPECT_THAT(res.jsonValue, IsEmpty());
272     EXPECT_EQ(str0, std::nullopt);
273 
274     ASSERT_TRUE(readJson(jsonRequest, res, "integer", integer, "string", str0,
275                          "vector", vec));
276     EXPECT_EQ(res.result(), boost::beast::http::status::ok);
277     EXPECT_THAT(res.jsonValue, IsEmpty());
278     EXPECT_EQ(integer, 1);
279     EXPECT_EQ(str0, std::nullopt);
280     EXPECT_EQ(vec, std::nullopt);
281 
282     ASSERT_TRUE(readJson(jsonRequest, res, "integer", integer, "string0", str0,
283                          "missing_string", str1));
284     EXPECT_EQ(res.result(), boost::beast::http::status::ok);
285     EXPECT_THAT(res.jsonValue, IsEmpty());
286     EXPECT_EQ(str1, std::nullopt);
287 }
288 
TEST(ReadJson,InvalidMissingElementReturnsFalse)289 TEST(ReadJson, InvalidMissingElementReturnsFalse)
290 {
291     crow::Response res;
292     nlohmann::json jsonRequest = {{"integer", 1}, {"string", "hello"}};
293 
294     int integer = 0;
295     std::string str0;
296     std::string str1;
297     std::vector<uint8_t> vec;
298     ASSERT_FALSE(readJson(jsonRequest, res, "missing_integer", integer));
299     EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
300     EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
301 
302     ASSERT_FALSE(readJson(jsonRequest, res, "missing_string", str0));
303     EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
304     EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
305 
306     ASSERT_FALSE(readJson(jsonRequest, res, "integer", integer, "string", str0,
307                           "vector", vec));
308     EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
309     EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
310 
311     ASSERT_FALSE(readJson(jsonRequest, res, "integer", integer, "string0", str0,
312                           "missing_string", str1));
313     EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
314     EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
315 }
316 
TEST(ReadJsonPatch,ValidElementsReturnsTrueResponseOkValuesUnpackedCorrectly)317 TEST(ReadJsonPatch, ValidElementsReturnsTrueResponseOkValuesUnpackedCorrectly)
318 {
319     crow::Response res;
320     std::error_code ec;
321     crow::Request req("{\"integer\": 1}", ec);
322 
323     // Ignore errors intentionally
324     req.addHeader(boost::beast::http::field::content_type, "application/json");
325 
326     int64_t integer = 0;
327     ASSERT_TRUE(readJsonPatch(req, res, "integer", integer));
328     EXPECT_EQ(res.result(), boost::beast::http::status::ok);
329     EXPECT_THAT(res.jsonValue, IsEmpty());
330     EXPECT_EQ(integer, 1);
331 }
332 
TEST(ReadJsonPatch,EmptyObjectReturnsFalseResponseBadRequest)333 TEST(ReadJsonPatch, EmptyObjectReturnsFalseResponseBadRequest)
334 {
335     crow::Response res;
336     std::error_code ec;
337     crow::Request req("{}", ec);
338     // Ignore errors intentionally
339 
340     std::optional<int64_t> integer = 0;
341     ASSERT_FALSE(readJsonPatch(req, res, "integer", integer));
342     EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
343     EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
344 }
345 
TEST(ReadJsonPatch,OdataIgnored)346 TEST(ReadJsonPatch, OdataIgnored)
347 {
348     crow::Response res;
349     std::error_code ec;
350     crow::Request req(R"({"@odata.etag": "etag", "integer": 1})", ec);
351     req.addHeader(boost::beast::http::field::content_type, "application/json");
352     // Ignore errors intentionally
353 
354     std::optional<int64_t> integer = 0;
355     ASSERT_TRUE(readJsonPatch(req, res, "integer", integer));
356     EXPECT_EQ(res.result(), boost::beast::http::status::ok);
357     EXPECT_THAT(res.jsonValue, IsEmpty());
358     EXPECT_EQ(integer, 1);
359 }
360 
TEST(ReadJsonPatch,OnlyOdataGivesNoOperation)361 TEST(ReadJsonPatch, OnlyOdataGivesNoOperation)
362 {
363     crow::Response res;
364     std::error_code ec;
365     crow::Request req(R"({"@odata.etag": "etag"})", ec);
366     // Ignore errors intentionally
367 
368     std::optional<int64_t> integer = 0;
369     ASSERT_FALSE(readJsonPatch(req, res, "integer", integer));
370     EXPECT_EQ(res.result(), boost::beast::http::status::bad_request);
371     EXPECT_THAT(res.jsonValue, Not(IsEmpty()));
372 }
373 
TEST(ReadJsonAction,ValidElementsReturnsTrueResponseOkValuesUnpackedCorrectly)374 TEST(ReadJsonAction, ValidElementsReturnsTrueResponseOkValuesUnpackedCorrectly)
375 {
376     crow::Response res;
377     std::error_code ec;
378     crow::Request req("{\"integer\": 1}", ec);
379     req.addHeader(boost::beast::http::field::content_type, "application/json");
380     // Ignore errors intentionally
381 
382     int64_t integer = 0;
383     ASSERT_TRUE(readJsonAction(req, res, "integer", integer));
384     EXPECT_EQ(res.result(), boost::beast::http::status::ok);
385     EXPECT_THAT(res.jsonValue, IsEmpty());
386     EXPECT_EQ(integer, 1);
387 }
388 
TEST(ReadJsonAction,EmptyObjectReturnsTrueResponseOk)389 TEST(ReadJsonAction, EmptyObjectReturnsTrueResponseOk)
390 {
391     crow::Response res;
392     std::error_code ec;
393     crow::Request req({"{}"}, ec);
394     req.addHeader(boost::beast::http::field::content_type, "application/json");
395     // Ignore errors intentionally
396 
397     std::optional<int64_t> integer = 0;
398     ASSERT_TRUE(readJsonAction(req, res, "integer", integer));
399     EXPECT_EQ(res.result(), boost::beast::http::status::ok);
400     EXPECT_THAT(res.jsonValue, IsEmpty());
401 }
402 
TEST(odataObjectCmp,PositiveCases)403 TEST(odataObjectCmp, PositiveCases)
404 {
405     EXPECT_EQ(0, odataObjectCmp(R"({"@odata.id": "/redfish/v1/1"})"_json,
406                                 R"({"@odata.id": "/redfish/v1/1"})"_json));
407     EXPECT_EQ(0, odataObjectCmp(R"({"@odata.id": ""})"_json,
408                                 R"({"@odata.id": ""})"_json));
409     EXPECT_EQ(0, odataObjectCmp(R"({"@odata.id": 42})"_json,
410                                 R"({"@odata.id": 0})"_json));
411     EXPECT_EQ(0, odataObjectCmp(R"({})"_json, R"({})"_json));
412 
413     EXPECT_GT(0, odataObjectCmp(R"({"@odata.id": "/redfish/v1"})"_json,
414                                 R"({"@odata.id": "/redfish/v1/1"})"_json));
415     EXPECT_LT(0, odataObjectCmp(R"({"@odata.id": "/redfish/v1/1"})"_json,
416                                 R"({"@odata.id": "/redfish/v1"})"_json));
417 
418     EXPECT_LT(0, odataObjectCmp(R"({"@odata.id": "/10"})"_json,
419                                 R"({"@odata.id": "/1"})"_json));
420     EXPECT_GT(0, odataObjectCmp(R"({"@odata.id": "/1"})"_json,
421                                 R"({"@odata.id": "/10"})"_json));
422 
423     EXPECT_GT(0, odataObjectCmp(R"({})"_json, R"({"@odata.id": "/1"})"_json));
424     EXPECT_LT(0, odataObjectCmp(R"({"@odata.id": "/1"})"_json, R"({})"_json));
425 
426     EXPECT_GT(0, odataObjectCmp(R"({"@odata.id": 4})"_json,
427                                 R"({"@odata.id": "/1"})"_json));
428     EXPECT_LT(0, odataObjectCmp(R"({"@odata.id": "/1"})"_json,
429                                 R"({"@odata.id": 4})"_json));
430 }
431 
TEST(SortJsonArrayByKey,ElementMissingKeyReturnsFalseArrayIsPartlySorted)432 TEST(SortJsonArrayByKey, ElementMissingKeyReturnsFalseArrayIsPartlySorted)
433 {
434     nlohmann::json::array_t array =
435         R"([{"@odata.id" : "/redfish/v1/100"}, {"@odata.id": "/redfish/v1/1"}, {"@odata.id" : "/redfish/v1/20"}])"_json;
436     sortJsonArrayByOData(array);
437     // Objects with other keys are always larger than those with the specified
438     // key.
439     EXPECT_THAT(array,
440                 ElementsAre(R"({"@odata.id": "/redfish/v1/1"})"_json,
441                             R"({"@odata.id" : "/redfish/v1/20"})"_json,
442                             R"({"@odata.id" : "/redfish/v1/100"})"_json));
443 }
444 
TEST(SortJsonArrayByKey,SortedByStringValueOnSuccessArrayIsSorted)445 TEST(SortJsonArrayByKey, SortedByStringValueOnSuccessArrayIsSorted)
446 {
447     nlohmann::json::array_t array =
448         R"([{"@odata.id": "/redfish/v1/20"}, {"@odata.id" : "/redfish/v1"}, {"@odata.id" : "/redfish/v1/100"}])"_json;
449     sortJsonArrayByOData(array);
450     EXPECT_THAT(array,
451                 ElementsAre(R"({"@odata.id": "/redfish/v1"})"_json,
452                             R"({"@odata.id" : "/redfish/v1/20"})"_json,
453                             R"({"@odata.id" : "/redfish/v1/100"})"_json));
454 }
TEST(GetEstimatedJsonSize,NumberIs8Bytpes)455 TEST(GetEstimatedJsonSize, NumberIs8Bytpes)
456 {
457     EXPECT_EQ(getEstimatedJsonSize(nlohmann::json(123)), 8);
458     EXPECT_EQ(getEstimatedJsonSize(nlohmann::json(77777777777)), 8);
459     EXPECT_EQ(getEstimatedJsonSize(nlohmann::json(3.14)), 8);
460 }
461 
TEST(GetEstimatedJsonSize,BooleanIs5Byte)462 TEST(GetEstimatedJsonSize, BooleanIs5Byte)
463 {
464     EXPECT_EQ(getEstimatedJsonSize(nlohmann::json(true)), 5);
465     EXPECT_EQ(getEstimatedJsonSize(nlohmann::json(false)), 5);
466 }
467 
TEST(GetEstimatedJsonSize,NullIs4Byte)468 TEST(GetEstimatedJsonSize, NullIs4Byte)
469 {
470     EXPECT_EQ(getEstimatedJsonSize(nlohmann::json()), 4);
471 }
472 
TEST(GetEstimatedJsonSize,StringAndBytesReturnsLengthAndQuote)473 TEST(GetEstimatedJsonSize, StringAndBytesReturnsLengthAndQuote)
474 {
475     EXPECT_EQ(getEstimatedJsonSize(nlohmann::json("1234")), 6);
476     EXPECT_EQ(getEstimatedJsonSize(nlohmann::json::binary({1, 2, 3, 4})), 4);
477 }
478 
TEST(GetEstimatedJsonSize,ArrayReturnsSum)479 TEST(GetEstimatedJsonSize, ArrayReturnsSum)
480 {
481     nlohmann::json arr = {1, 3.14, "123", nlohmann::json::binary({1, 2, 3, 4})};
482     EXPECT_EQ(getEstimatedJsonSize(arr), 8 + 8 + 5 + 4);
483 }
484 
TEST(GetEstimatedJsonSize,ObjectsReturnsSumWithKeyAndValue)485 TEST(GetEstimatedJsonSize, ObjectsReturnsSumWithKeyAndValue)
486 {
487     nlohmann::json obj = R"(
488 {
489   "key0": 123,
490   "key1": "123",
491   "key2": [1, 2, 3],
492   "key3": {"key4": "123"}
493 }
494 )"_json;
495 
496     uint64_t expected = 0;
497     // 5 keys of length 4
498     expected += uint64_t(5) * 4;
499     // 5 colons, 5 quote pairs, and 5 spaces for 5 keys
500     expected += uint64_t(5) * (1 + 2 + 1);
501     // 2 string values of length 3
502     expected += uint64_t(2) * (3 + 2);
503     // 1 number value
504     expected += 8;
505     // 1 array value of 3 numbers
506     expected += uint64_t(3) * 8;
507     EXPECT_EQ(getEstimatedJsonSize(obj), expected);
508 }
509 
510 } // namespace
511 } // namespace redfish::json_util
512