1 #include "fru_utils.hpp"
2 
3 #include <algorithm>
4 #include <array>
5 #include <iterator>
6 
7 #include "gtest/gtest.h"
8 
9 extern "C"
10 {
11 // Include for I2C_SMBUS_BLOCK_MAX
12 #include <linux/i2c.h>
13 }
14 
15 TEST(ValidateHeaderTest, InvalidFruVersionReturnsFalse)
16 {
17     // Validates the FruVersion is checked for the only legal value.
18     constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
19         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
20 
21     EXPECT_FALSE(validateHeader(fruHeader));
22 }
23 
24 TEST(ValidateHeaderTest, InvalidReservedReturnsFalse)
25 {
26     // Validates the reserved bit(7:4) of first bytes.
27     constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
28         0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
29 
30     EXPECT_FALSE(validateHeader(fruHeader));
31 }
32 
33 TEST(ValidateHeaderTest, InvalidPaddingReturnsFalse)
34 {
35     // Validates the padding byte (7th byte).
36     constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
37         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00};
38 
39     EXPECT_FALSE(validateHeader(fruHeader));
40 }
41 
42 TEST(ValidateHeaderTest, InvalidChecksumReturnsFalse)
43 {
44     // Validates the checksum, check for incorrect value.
45     constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
46         0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0x00};
47 
48     EXPECT_FALSE(validateHeader(fruHeader));
49 }
50 
51 TEST(ValidateHeaderTest, ValidChecksumReturnsTrue)
52 {
53     // Validates the checksum, check for correct value.
54     constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
55         0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0xf5};
56 
57     EXPECT_TRUE(validateHeader(fruHeader));
58 }
59 
60 TEST(VerifyOffsetTest, EmptyFruDataReturnsFalse)
61 {
62     // Validates the FruData size is checked for non empty.
63     std::vector<uint8_t> fruData = {};
64 
65     EXPECT_FALSE(verifyOffset(fruData, fruAreas::fruAreaChassis, 0));
66 }
67 
68 TEST(VerifyOffsetTest, AreaOutOfRangeReturnsFalse)
69 {
70     // Validates the FruArea value, check if it is within range.
71     const std::vector<uint8_t> fruData = {0x01, 0x00, 0x00, 0x00, 0x00,
72                                           0x00, 0x00, 0x00, 0x00};
73 
74     unsigned int areaOutOfRange = 8;
75     EXPECT_FALSE(
76         verifyOffset(fruData, static_cast<fruAreas>(areaOutOfRange), 0));
77 }
78 
79 TEST(VerifyOffsetTest, OverlapNextAreaReturnsFalse)
80 {
81     // Validates the Overlap of offsets with overlapped values.
82     const std::vector<uint8_t> fruData = {0x01, 0x00, 0x01, 0x02, 0x03,
83                                           0x04, 0x00, 0x00, 0x00};
84 
85     EXPECT_FALSE(verifyOffset(fruData, fruAreas::fruAreaChassis, 2));
86 }
87 
88 TEST(VerifyOffsetTest, OverlapPrevAreaReturnsFalse)
89 {
90     // Validates the Overlap of offsets with overlapped values.
91     const std::vector<uint8_t> fruData = {0x01, 0x00, 0x01, 0x03, 0x02,
92                                           0x07, 0x00, 0x00, 0x00};
93 
94     EXPECT_FALSE(verifyOffset(fruData, fruAreas::fruAreaProduct, 2));
95 }
96 
97 TEST(VerifyOffsetTest, ValidInputDataNoOverlapReturnsTrue)
98 {
99     // Validates all inputs with expected value and no overlap.
100     const std::vector<uint8_t> fruData = {0x01, 0x00, 0x01, 0x02, 0x03,
101                                           0x04, 0x00, 0x00, 0x00};
102 
103     EXPECT_TRUE(verifyOffset(fruData, fruAreas::fruAreaChassis, 1));
104 }
105 
106 TEST(VerifyChecksumTest, EmptyInput)
107 {
108     std::vector<uint8_t> data = {};
109 
110     EXPECT_EQ(calculateChecksum(data), 0);
111 }
112 
113 TEST(VerifyChecksumTest, SingleOneInput)
114 {
115     std::vector<uint8_t> data(1, 1);
116 
117     EXPECT_EQ(calculateChecksum(data), 255);
118 }
119 
120 TEST(VerifyChecksumTest, AllOneInput)
121 {
122     std::vector<uint8_t> data(256, 1);
123 
124     EXPECT_EQ(calculateChecksum(data), 0);
125 }
126 
127 TEST(VerifyChecksumTest, WrapBoundaryLow)
128 {
129     std::vector<uint8_t> data = {255, 0};
130 
131     EXPECT_EQ(calculateChecksum(data), 1);
132 }
133 
134 TEST(VerifyChecksumTest, WrapBoundaryExact)
135 {
136     std::vector<uint8_t> data = {255, 1};
137 
138     EXPECT_EQ(calculateChecksum(data), 0);
139 }
140 
141 TEST(VerifyChecksumTest, WrapBoundaryHigh)
142 {
143     std::vector<uint8_t> data = {255, 2};
144 
145     EXPECT_EQ(calculateChecksum(data), 255);
146 }
147 
148 int64_t getDataTempl(const std::vector<uint8_t>& data,
149                      [[maybe_unused]] int flag, [[maybe_unused]] int file,
150                      [[maybe_unused]] uint16_t address, off_t offset,
151                      size_t length, uint8_t* outBuf)
152 {
153     if (offset >= static_cast<off_t>(data.size()))
154     {
155         return 0;
156     }
157 
158     uint16_t idx;
159     for (idx = offset; idx < data.size() && idx < offset + length;
160          ++idx, ++outBuf)
161     {
162         *outBuf = data[idx];
163     }
164 
165     return idx - offset;
166 }
167 
168 TEST(FindFRUHeaderTest, InvalidHeader)
169 {
170     const std::vector<uint8_t> data = {255, 16};
171     off_t offset = 0;
172     std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData;
173     auto getData = [&data](auto fl, auto fi, auto a, auto o, auto l, auto* b) {
174         return getDataTempl(data, fl, fi, a, o, l, b);
175     };
176 
177     EXPECT_FALSE(findFRUHeader(0, 0, 0, getData, "error", blockData, offset));
178 }
179 
180 TEST(FindFRUHeaderTest, NoData)
181 {
182     const std::vector<uint8_t> data = {};
183     off_t offset = 0;
184     std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData;
185     auto getData = [&data](auto fl, auto fi, auto a, auto o, auto l, auto* b) {
186         return getDataTempl(data, fl, fi, a, o, l, b);
187     };
188 
189     EXPECT_FALSE(findFRUHeader(0, 0, 0, getData, "error", blockData, offset));
190 }
191 
192 TEST(FindFRUHeaderTest, ValidHeader)
193 {
194     const std::vector<uint8_t> data = {0x01, 0x00, 0x01, 0x02,
195                                        0x03, 0x04, 0x00, 0xf5};
196     off_t offset = 0;
197     std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData;
198     auto getData = [&data](auto fl, auto fi, auto a, auto o, auto l, auto* b) {
199         return getDataTempl(data, fl, fi, a, o, l, b);
200     };
201 
202     EXPECT_TRUE(findFRUHeader(0, 0, 0, getData, "error", blockData, offset));
203     EXPECT_EQ(0, offset);
204 }
205 
206 TEST(FindFRUHeaderTest, TyanInvalidHeader)
207 {
208     std::vector<uint8_t> data = {'$', 'T', 'Y', 'A', 'N', '$', 0, 0};
209     data.resize(0x6000 + I2C_SMBUS_BLOCK_MAX);
210     off_t offset = 0;
211     std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData;
212     auto getData = [&data](auto fl, auto fi, auto a, auto o, auto l, auto* b) {
213         return getDataTempl(data, fl, fi, a, o, l, b);
214     };
215 
216     EXPECT_FALSE(findFRUHeader(0, 0, 0, getData, "error", blockData, offset));
217 }
218 
219 TEST(FindFRUHeaderTest, TyanNoData)
220 {
221     const std::vector<uint8_t> data = {'$', 'T', 'Y', 'A', 'N', '$', 0, 0};
222     off_t offset = 0;
223     std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData;
224     auto getData = [&data](auto fl, auto fi, auto a, auto o, auto l, auto* b) {
225         return getDataTempl(data, fl, fi, a, o, l, b);
226     };
227 
228     EXPECT_FALSE(findFRUHeader(0, 0, 0, getData, "error", blockData, offset));
229 }
230 
231 TEST(FindFRUHeaderTest, TyanValidHeader)
232 {
233     std::vector<uint8_t> data = {'$', 'T', 'Y', 'A', 'N', '$', 0, 0};
234     data.resize(0x6000);
235     constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
236         0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0xf5};
237     copy(fruHeader.begin(), fruHeader.end(), back_inserter(data));
238 
239     off_t offset = 0;
240     std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData;
241     auto getData = [&data](auto fl, auto fi, auto a, auto o, auto l, auto* b) {
242         return getDataTempl(data, fl, fi, a, o, l, b);
243     };
244 
245     EXPECT_TRUE(findFRUHeader(0, 0, 0, getData, "error", blockData, offset));
246     EXPECT_EQ(0x6000, offset);
247 }
248