1 /** 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 21 TEST(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 29 TEST(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 41 TEST(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 50 TEST(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 58 TEST(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 66 TEST(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 78 TEST(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 102 TEST(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 115 TEST(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 128 TEST(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 142 TEST(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 152 TEST(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 174 TEST(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 182 TEST(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 190 TEST(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 202 TEST(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 210 TEST(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 224 TEST(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 245 TEST(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 258 TEST(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 286 TEST(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 } 309