blob: 368bbc970b7e561d108460d20d86ed664d953bb5 [file] [log] [blame]
Nikhil Namjoshida6e5572023-03-13 10:52:53 -07001#include "bej_common_test.hpp"
kasunathe8946af2022-05-23 12:32:09 -07002#include "bej_decoder_json.hpp"
Brandon Kim07abbf82025-06-23 21:03:07 +00003#include "bej_encoder_json.hpp"
kasunathe8946af2022-05-23 12:32:09 -07004
kasunathe8946af2022-05-23 12:32:09 -07005#include <memory>
kasunathe8946af2022-05-23 12:32:09 -07006#include <string_view>
Brandon Kim07abbf82025-06-23 21:03:07 +00007#include <vector>
kasunathe8946af2022-05-23 12:32:09 -07008
9#include <gmock/gmock-matchers.h>
10#include <gmock/gmock.h>
11#include <gtest/gtest.h>
12
13namespace libbej
14{
15
kasunathe8946af2022-05-23 12:32:09 -070016struct BejDecoderTestParams
17{
18 const std::string testName;
19 const BejTestInputFiles inputFiles;
20};
21
Brian Maa46f9852024-09-27 16:57:20 +080022void PrintTo(const BejDecoderTestParams& params, std::ostream* os)
23{
24 *os << params.testName;
25}
26
kasunathe8946af2022-05-23 12:32:09 -070027using BejDecoderTest = testing::TestWithParam<BejDecoderTestParams>;
28
29const BejTestInputFiles driveOemTestFiles = {
30 .jsonFile = "../test/json/drive_oem.json",
31 .schemaDictionaryFile = "../test/dictionaries/drive_oem_dict.bin",
32 .annotationDictionaryFile = "../test/dictionaries/annotation_dict.bin",
33 .errorDictionaryFile = "",
34 .encodedStreamFile = "../test/encoded/drive_oem_enc.bin",
35};
36
37const BejTestInputFiles circuitTestFiles = {
38 .jsonFile = "../test/json/circuit.json",
39 .schemaDictionaryFile = "../test/dictionaries/circuit_dict.bin",
40 .annotationDictionaryFile = "../test/dictionaries/annotation_dict.bin",
41 .errorDictionaryFile = "",
42 .encodedStreamFile = "../test/encoded/circuit_enc.bin",
43};
44
45const BejTestInputFiles storageTestFiles = {
46 .jsonFile = "../test/json/storage.json",
47 .schemaDictionaryFile = "../test/dictionaries/storage_dict.bin",
48 .annotationDictionaryFile = "../test/dictionaries/annotation_dict.bin",
49 .errorDictionaryFile = "",
50 .encodedStreamFile = "../test/encoded/storage_enc.bin",
51};
52
53const BejTestInputFiles dummySimpleTestFiles = {
54 .jsonFile = "../test/json/dummysimple.json",
55 .schemaDictionaryFile = "../test/dictionaries/dummy_simple_dict.bin",
56 .annotationDictionaryFile = "../test/dictionaries/annotation_dict.bin",
57 .errorDictionaryFile = "",
58 .encodedStreamFile = "../test/encoded/dummy_simple_enc.bin",
59};
60
kasunathe8946af2022-05-23 12:32:09 -070061TEST_P(BejDecoderTest, Decode)
62{
63 const BejDecoderTestParams& test_case = GetParam();
64 auto inputsOrErr = loadInputs(test_case.inputFiles);
65 EXPECT_TRUE(inputsOrErr);
66
67 BejDictionaries dictionaries = {
68 .schemaDictionary = inputsOrErr->schemaDictionary,
69 .annotationDictionary = inputsOrErr->annotationDictionary,
70 .errorDictionary = inputsOrErr->errorDictionary,
71 };
72
73 BejDecoderJson decoder;
74 EXPECT_THAT(decoder.decode(dictionaries, inputsOrErr->encodedStream), 0);
75 std::string decoded = decoder.getOutput();
76 nlohmann::json jsonDecoded = nlohmann::json::parse(decoded);
77
78 // Just comparing nlohmann::json types could lead to errors. It compares the
79 // byte values. So int64 and unit64 comparisons might be incorrect. Eg:
80 // bytes values for -5 and 18446744073709551611 are the same. So compare the
81 // string values.
82 EXPECT_TRUE(jsonDecoded.dump() == inputsOrErr->expectedJson.dump());
83}
84
Brandon Kim07abbf82025-06-23 21:03:07 +000085TEST(BejDecoderSecurityTest, MaxOperationsLimit)
86{
87 auto inputsOrErr = loadInputs(dummySimpleTestFiles);
88 ASSERT_TRUE(inputsOrErr);
89
90 BejDictionaries dictionaries = {
91 .schemaDictionary = inputsOrErr->schemaDictionary,
92 .annotationDictionary = inputsOrErr->annotationDictionary,
93 .errorDictionary = inputsOrErr->errorDictionary,
94 };
95
96 // Each array element below consists of a set and two properties, resulting
97 // in 3 operations. 400,000 elements will result in 1,200,000 operations,
98 // which should exceed the limit of 1,000,000.
99 constexpr int numElements = 400000;
100
101 auto root = std::make_unique<RedfishPropertyParent>();
102 bejTreeInitSet(root.get(), "DummySimple");
103
104 auto childArray = std::make_unique<RedfishPropertyParent>();
105 bejTreeInitArray(childArray.get(), "ChildArrayProperty");
106 bejTreeLinkChildToParent(root.get(), childArray.get());
107
108 std::vector<std::unique_ptr<RedfishPropertyParent>> sets;
109 std::vector<std::unique_ptr<RedfishPropertyLeafBool>> bools;
110 std::vector<std::unique_ptr<RedfishPropertyLeafEnum>> enums;
111 sets.reserve(numElements);
112 bools.reserve(numElements);
113 enums.reserve(numElements);
114
115 for (int i = 0; i < numElements; ++i)
116 {
117 auto chArraySet = std::make_unique<RedfishPropertyParent>();
118 bejTreeInitSet(chArraySet.get(), nullptr);
119
120 auto chArraySetBool = std::make_unique<RedfishPropertyLeafBool>();
121 bejTreeAddBool(chArraySet.get(), chArraySetBool.get(), "AnotherBoolean",
122 true);
123
124 auto chArraySetLs = std::make_unique<RedfishPropertyLeafEnum>();
125 bejTreeAddEnum(chArraySet.get(), chArraySetLs.get(), "LinkStatus",
126 "NoLink");
127
128 bejTreeLinkChildToParent(childArray.get(), chArraySet.get());
129
130 sets.push_back(std::move(chArraySet));
131 bools.push_back(std::move(chArraySetBool));
132 enums.push_back(std::move(chArraySetLs));
133 }
134
135 libbej::BejEncoderJson encoder;
136 encoder.encode(&dictionaries, bejMajorSchemaClass, root.get());
137 std::vector<uint8_t> outputBuffer = encoder.getOutput();
138
139 BejDecoderJson decoder;
140 EXPECT_THAT(decoder.decode(dictionaries, std::span(outputBuffer)),
Brandon Kimef01d4c2025-06-23 21:13:04 +0000141 bejErrorNotSupported);
Brandon Kim07abbf82025-06-23 21:03:07 +0000142}
143
kasunathe8946af2022-05-23 12:32:09 -0700144/**
145 * TODO: Add more test cases.
146 * - Test Enums inside array elemets
147 * - Array inside an array: is this a valid case?
148 * - Real numbers with exponent part
149 * - Every type inside an array.
150 */
151INSTANTIATE_TEST_SUITE_P(
152 , BejDecoderTest,
153 testing::ValuesIn<BejDecoderTestParams>({
154 {"DriveOEM", driveOemTestFiles},
155 {"Circuit", circuitTestFiles},
156 {"Storage", storageTestFiles},
157 {"DummySimple", dummySimpleTestFiles},
158 }),
159 [](const testing::TestParamInfo<BejDecoderTest::ParamType>& info) {
Patrick Williamsbe27f2e2024-08-16 15:22:35 -0400160 return info.param.testName;
161 });
kasunathe8946af2022-05-23 12:32:09 -0700162
163} // namespace libbej