blob: 9d20ff0417ce541109031a1e15c68803afe46e04 [file] [log] [blame]
Vernon Maueryebe8e902018-12-12 09:39:22 -08001/**
2 * Copyright © 2018 Intel Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#include <ipmid/api.hpp>
17#include <ipmid/message.hpp>
18
19#include <gtest/gtest.h>
20
21TEST(Payload, InputSize)
22{
23 std::vector<uint8_t> i = {0xbf, 0x04, 0x86, 0x00, 0x02};
24 size_t input_size = i.size();
25 ipmi::message::Payload p(std::forward<std::vector<uint8_t>>(i));
26 ASSERT_EQ(input_size, p.size());
27}
28
29TEST(Payload, OutputSize)
30{
31 ipmi::message::Payload p;
32 ASSERT_EQ(0, p.size());
33 std::vector<uint8_t> i = {0xbf, 0x04, 0x86, 0x00, 0x02};
34 p.pack(i);
35 ASSERT_EQ(i.size(), p.size());
36 p.pack(i);
37 p.pack(i);
38 ASSERT_EQ(3 * i.size(), p.size());
39}
40
41TEST(Payload, Resize)
42{
43 std::vector<uint8_t> i = {0xbf, 0x04, 0x86, 0x00, 0x02};
44 ipmi::message::Payload p;
45 p.pack(i);
46 p.resize(16);
47 ASSERT_EQ(p.size(), 16);
48}
49
50TEST(Payload, Data)
51{
52 std::vector<uint8_t> i = {0xbf, 0x04, 0x86, 0x00, 0x02};
53 ipmi::message::Payload p;
54 p.pack(i);
55 ASSERT_NE(nullptr, p.data());
56}
57
58TEST(PayloadResponse, Append)
59{
60 std::string s("0123456789abcdef");
61 ipmi::message::Payload p;
62 p.append(s.data(), s.data() + s.size());
63 ASSERT_EQ(s.size(), p.size());
64}
65
66TEST(PayloadResponse, AppendDrain)
67{
68 std::string s("0123456789abcdef");
69 ipmi::message::Payload p;
70 bool b = true;
71 // first pack a lone bit
72 p.pack(b);
73 p.append(s.data(), s.data() + s.size());
74 // append will 'drain' first, padding the lone bit into a full byte
75 ASSERT_EQ(s.size() + 1, p.size());
76}
77
78TEST(PayloadResponse, AppendBits)
79{
80 ipmi::message::Payload p;
81 p.appendBits(3, 0b101);
82 ASSERT_EQ(p.bitStream, 0b101);
83 p.appendBits(4, 0b1100);
84 ASSERT_EQ(p.bitStream, 0b1100101);
85 p.appendBits(1, 0b1);
86 ASSERT_EQ(p.bitStream, 0);
87 ASSERT_EQ(p.bitCount, 0);
88 // appended 8 bits, should be one byte
89 ASSERT_EQ(p.size(), 1);
90 std::vector<uint8_t> k1 = {0b11100101};
91 ASSERT_EQ(p.raw, k1);
92 p.appendBits(7, 0b1110111);
93 // appended 7 more bits, should still be one byte
94 ASSERT_EQ(p.size(), 1);
95 p.drain();
96 // drain forces padding; should be two bytes now
97 ASSERT_EQ(p.size(), 2);
98 std::vector<uint8_t> k2 = {0b11100101, 0b01110111};
99 ASSERT_EQ(p.raw, k2);
100}
101
102TEST(PayloadResponse, Drain16Bits)
103{
104 ipmi::message::Payload p;
105 p.bitStream = 0b1011010011001111;
106 p.bitCount = 16;
107 p.drain();
108 ASSERT_EQ(p.size(), 2);
109 ASSERT_EQ(p.bitCount, 0);
110 ASSERT_EQ(p.bitStream, 0);
111 std::vector<uint8_t> k1 = {0b11001111, 0b10110100};
112 ASSERT_EQ(p.raw, k1);
113}
114
115TEST(PayloadResponse, Drain15Bits)
116{
117 ipmi::message::Payload p;
118 p.bitStream = 0b101101001100111;
119 p.bitCount = 15;
120 p.drain();
121 ASSERT_EQ(p.size(), 2);
122 ASSERT_EQ(p.bitCount, 0);
123 ASSERT_EQ(p.bitStream, 0);
124 std::vector<uint8_t> k1 = {0b1100111, 0b1011010};
125 ASSERT_EQ(p.raw, k1);
126}
127
128TEST(PayloadResponse, Drain15BitsWholeBytesOnly)
129{
130 ipmi::message::Payload p;
131 p.bitStream = 0b101101001100111;
132 p.bitCount = 15;
133 p.drain(true);
134 // only the first whole byte should have been 'drained' into p.raw
135 ASSERT_EQ(p.size(), 1);
136 ASSERT_EQ(p.bitCount, 7);
137 ASSERT_EQ(p.bitStream, 0b1011010);
138 std::vector<uint8_t> k1 = {0b1100111};
139 ASSERT_EQ(p.raw, k1);
140}
141
142TEST(PayloadRequest, Pop)
143{
144 std::vector<uint8_t> i = {0xbf, 0x04, 0x86, 0x00, 0x02};
145 ipmi::message::Payload p(std::forward<std::vector<uint8_t>>(i));
146 const auto& [vb, ve] = p.pop<uint8_t>(4);
147 std::vector<uint8_t> v(vb, ve);
148 std::vector<uint8_t> k = {0xbf, 0x04, 0x86, 0x00};
149 ASSERT_EQ(v, k);
150}
151
152TEST(PayloadRequest, FillBits)
153{
154 std::vector<uint8_t> i = {0xbf, 0x04, 0x86, 0x00, 0x02};
155 ipmi::message::Payload p(std::forward<std::vector<uint8_t>>(i));
156 p.fillBits(5);
157 ASSERT_FALSE(p.unpackError);
158 ASSERT_EQ(p.bitStream, 0xbf);
159 ASSERT_EQ(p.bitCount, 8);
160 // should still have 5 bits available, no change
161 p.fillBits(5);
162 ASSERT_FALSE(p.unpackError);
163 ASSERT_EQ(p.bitStream, 0xbf);
164 ASSERT_EQ(p.bitCount, 8);
165 // discard 5 bits (low order)
166 p.popBits(5);
167 // should add another byte into the stream (high order)
168 p.fillBits(5);
169 ASSERT_FALSE(p.unpackError);
170 ASSERT_EQ(p.bitStream, 0x25);
171 ASSERT_EQ(p.bitCount, 11);
172}
173
174TEST(PayloadRequest, FillBitsTooManyBits)
175{
176 std::vector<uint8_t> i = {1, 2, 3, 4, 5, 6, 7, 8, 9};
177 ipmi::message::Payload p(std::forward<std::vector<uint8_t>>(i));
178 p.fillBits(72);
179 ASSERT_TRUE(p.unpackError);
180}
181
182TEST(PayloadRequest, FillBitsNotEnoughBytes)
183{
184 std::vector<uint8_t> i = {1, 2, 3, 4};
185 ipmi::message::Payload p(std::forward<std::vector<uint8_t>>(i));
186 p.fillBits(48);
187 ASSERT_TRUE(p.unpackError);
188}
189
190TEST(PayloadRequest, PopBits)
191{
192 std::vector<uint8_t> i = {0xbf, 0x04, 0x86, 0x00, 0x02};
193 ipmi::message::Payload p(std::forward<std::vector<uint8_t>>(i));
194 p.fillBits(4);
195 uint8_t v = p.popBits(4);
196 ASSERT_FALSE(p.unpackError);
197 ASSERT_EQ(p.bitStream, 0x0b);
198 ASSERT_EQ(p.bitCount, 4);
199 ASSERT_EQ(v, 0x0f);
200}
201
202TEST(PayloadRequest, PopBitsNoFillBits)
203{
204 std::vector<uint8_t> i = {0xbf, 0x04, 0x86, 0x00, 0x02};
205 ipmi::message::Payload p(std::forward<std::vector<uint8_t>>(i));
206 p.popBits(4);
207 ASSERT_TRUE(p.unpackError);
208}
209
210TEST(PayloadRequest, DiscardBits)
211{
212 std::vector<uint8_t> i = {0xbf, 0x04, 0x86, 0x00, 0x02};
213 ipmi::message::Payload p(std::forward<std::vector<uint8_t>>(i));
214 p.fillBits(5);
215 ASSERT_FALSE(p.unpackError);
216 ASSERT_EQ(p.bitStream, 0xbf);
217 ASSERT_EQ(p.bitCount, 8);
218 p.discardBits();
219 ASSERT_FALSE(p.unpackError);
220 ASSERT_EQ(p.bitStream, 0);
221 ASSERT_EQ(p.bitCount, 0);
222}
223
224TEST(PayloadRequest, FullyUnpacked)
225{
226 std::vector<uint8_t> i = {0xbf, 0x04, 0x86, 0x00, 0x02};
227 ipmi::message::Payload p(std::forward<std::vector<uint8_t>>(i));
228 uint32_t v1;
229 p.unpack(v1);
230 // still one remaining byte
231 ASSERT_FALSE(p.fullyUnpacked());
232 p.fillBits(3);
233 p.popBits(3);
234 // still five remaining bits
235 ASSERT_FALSE(p.fullyUnpacked());
236 p.fillBits(5);
237 p.popBits(5);
238 // fully unpacked, should be no errors
239 ASSERT_TRUE(p.fullyUnpacked());
240 p.fillBits(4);
241 // fullyUnpacked fails because an attempt to unpack too many bytes
242 ASSERT_FALSE(p.fullyUnpacked());
243}
244
245TEST(PayloadRequest, ResetInternal)
246{
247 std::vector<uint8_t> i = {0xbf, 0x04, 0x86, 0x00, 0x02};
248 ipmi::message::Payload p(std::forward<std::vector<uint8_t>>(i));
249 p.fillBits(4);
250 p.unpackError = true;
251 p.reset();
252 ASSERT_EQ(p.rawIndex, 0);
253 ASSERT_EQ(p.bitStream, 0);
254 ASSERT_EQ(p.bitCount, 0);
255 ASSERT_FALSE(p.unpackError);
256}
257
258TEST(PayloadRequest, ResetUsage)
259{
260 // Payload.reset is used to rewind the unpacking to the initial
261 // state. This is needed so that OEM commands can unpack the group
262 // number or the IANA to determine which handler needs to be called
263 std::vector<uint8_t> i = {0x04, 0x86};
264 ipmi::message::Payload p(std::forward<std::vector<uint8_t>>(i));
265 uint8_t v1;
266 // check that the number of bytes matches
267 ASSERT_EQ(p.unpack(v1), 0);
268 // check that the payload was not fully unpacked
269 ASSERT_FALSE(p.fullyUnpacked());
270 uint8_t k1 = 0x04;
271 // check that the bytes were correctly unpacked (LSB first)
272 ASSERT_EQ(v1, k1);
273 // do a reset on the payload
274 p.reset();
275 // unpack a uint16
276 uint16_t v2;
277 // check that the number of bytes matches
278 ASSERT_EQ(p.unpack(v2), 0);
279 // check that the payload was fully unpacked
280 ASSERT_TRUE(p.fullyUnpacked());
281 uint16_t k2 = 0x8604;
282 // check that the bytes were correctly unpacked (LSB first)
283 ASSERT_EQ(v2, k2);
284}
285
286TEST(PayloadRequest, PartialPayload)
287{
288 std::vector<uint8_t> i = {0xbf, 0x04, 0x86, 0x00, 0x02};
289 ipmi::message::Payload p(std::forward<std::vector<uint8_t>>(i));
290 uint8_t v1;
291 ipmi::message::Payload localPayload;
292 // check that the number of bytes matches
293 ASSERT_EQ(p.unpack(v1, localPayload), 0);
294 // check that the payload was partially unpacked and not in error
295 ASSERT_FALSE(p.fullyUnpacked());
296 ASSERT_FALSE(p.unpackError);
297 // check that the 'extracted' payload is not fully unpacked
298 ASSERT_FALSE(localPayload.fullyUnpacked());
299 uint8_t k1 = 0xbf;
300 // check that the bytes were correctly unpacked (LSB first)
301 ASSERT_EQ(v1, k1);
302 uint32_t v2;
303 // unpack using the 'extracted' payload
304 ASSERT_EQ(localPayload.unpack(v2), 0);
305 ASSERT_TRUE(localPayload.fullyUnpacked());
306 uint32_t k2 = 0x02008604;
307 ASSERT_EQ(v2, k2);
308}