1 #include "FruUtils.hpp"
2 
3 #include <array>
4 #include<algorithm>
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(
149     const std::vector<uint8_t>& data,
150     [[maybe_unused]] int flag,
151     [[maybe_unused]] int file,
152     [[maybe_unused]] uint16_t address,
153     uint16_t offset, uint8_t length, uint8_t* outBuf)
154 {
155     if (offset >= data.size())
156     {
157         return 0;
158     }
159 
160     uint16_t idx;
161     for (idx = offset;
162          idx < data.size() && idx < offset + length;
163          ++idx, ++outBuf)
164     {
165         *outBuf = data[idx];
166     }
167 
168     return idx - offset;
169 }
170 
171 TEST(FindFRUHeaderTest, InvalidHeader)
172 {
173     const std::vector<uint8_t> data = {255, 16};
174     uint16_t offset = 0;
175     std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData;
176     auto getData = [&data](auto fl, auto fi, auto a, auto o, auto l,
177         auto* b) { return getDataTempl(data, fl, fi, a, o, l, b); };
178 
179     EXPECT_FALSE(findFRUHeader(0, 0, 0, getData, "error", blockData, offset));
180 }
181 
182 TEST(FindFRUHeaderTest, NoData)
183 {
184     const std::vector<uint8_t> data = {};
185     uint16_t offset = 0;
186     std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData;
187     auto getData = [&data](auto fl, auto fi, auto a, auto o, auto l,
188         auto* b) { return getDataTempl(data, fl, fi, a, o, l, b); };
189 
190     EXPECT_FALSE(findFRUHeader(0, 0, 0, getData, "error", blockData, offset));
191 }
192 
193 TEST(FindFRUHeaderTest, ValidHeader)
194 {
195     const std::vector<uint8_t> data = {
196         0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0xf5};
197     uint16_t offset = 0;
198     std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData;
199     auto getData = [&data](auto fl, auto fi, auto a, auto o, auto l,
200         auto* b) { return getDataTempl(data, fl, fi, a, o, l, b); };
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     uint16_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,
213         auto* b) { return getDataTempl(data, fl, fi, a, o, l, b); };
214 
215     EXPECT_FALSE(findFRUHeader(0, 0, 0, getData, "error", blockData, offset));
216 }
217 
218 TEST(FindFRUHeaderTest, TyanNoData)
219 {
220     const std::vector<uint8_t> data = {'$', 'T', 'Y', 'A', 'N', '$', 0, 0};
221     uint16_t offset = 0;
222     std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData;
223     auto getData = [&data](auto fl, auto fi, auto a, auto o, auto l,
224         auto* b) { return getDataTempl(data, fl, fi, a, o, l, b); };
225 
226     EXPECT_FALSE(findFRUHeader(0, 0, 0, getData, "error", blockData, offset));
227 }
228 
229 TEST(FindFRUHeaderTest, TyanValidHeader)
230 {
231     std::vector<uint8_t> data = {'$', 'T', 'Y', 'A', 'N', '$', 0, 0};
232     data.resize(0x6000);
233     constexpr std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> fruHeader = {
234         0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x00, 0xf5};
235     copy(fruHeader.begin(), fruHeader.end(), back_inserter(data));
236 
237     uint16_t offset = 0;
238     std::array<uint8_t, I2C_SMBUS_BLOCK_MAX> blockData;
239     auto getData = [&data](auto fl, auto fi, auto a, auto o, auto l,
240         auto* b) { return getDataTempl(data, fl, fi, a, o, l, b); };
241 
242     EXPECT_TRUE(findFRUHeader(0, 0, 0, getData, "error", blockData, offset));
243     EXPECT_EQ(0x6000, offset);
244 }
245