blob: ec698f424163fd24b744b2414f0cfd904a03b6da [file] [log] [blame]
Shawn McCarney83169bf2020-02-24 15:59:34 -06001/**
2 * Copyright © 2020 IBM 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 "action_environment.hpp"
17#include "action_error.hpp"
18#include "device.hpp"
19#include "i2c_interface.hpp"
20#include "i2c_write_bytes_action.hpp"
21#include "id_map.hpp"
22#include "mocked_i2c_interface.hpp"
23
24#include <cstdint>
25#include <memory>
26#include <stdexcept>
27#include <string>
28#include <utility>
29#include <vector>
30
31#include <gmock/gmock.h>
32#include <gtest/gtest.h>
33
34using namespace phosphor::power::regulators;
35
36using ::testing::A;
37using ::testing::Args;
38using ::testing::ElementsAre;
39using ::testing::NotNull;
40using ::testing::Return;
41using ::testing::SetArrayArgument;
42using ::testing::Throw;
43using ::testing::TypedEq;
44
45// Test for I2CWriteBytesAction(uint8_t reg,
46// const std::vector<uint8_t>& values)
47TEST(I2CWriteBytesActionTests, Constructor1)
48{
49 // Test where works
50 try
51 {
52 std::vector<uint8_t> values{0x56, 0x14, 0xDA};
53 I2CWriteBytesAction action{0x7C, values};
54
55 EXPECT_EQ(action.getRegister(), 0x7C);
56
57 EXPECT_EQ(action.getValues().size(), 3);
58 EXPECT_EQ(action.getValues()[0], 0x56);
59 EXPECT_EQ(action.getValues()[1], 0x14);
60 EXPECT_EQ(action.getValues()[2], 0xDA);
61
62 EXPECT_EQ(action.getMasks().size(), 0);
63 }
64 catch (...)
65 {
66 ADD_FAILURE() << "Should not have caught exception.";
67 }
68
69 // Test where fails: Values vector is empty
70 try
71 {
72 std::vector<uint8_t> values{};
73 I2CWriteBytesAction action{0x7C, values};
74 ADD_FAILURE() << "Should not have reached this line.";
75 }
76 catch (const std::invalid_argument& e)
77 {
78 EXPECT_STREQ(e.what(), "Values vector is empty");
79 }
80 catch (...)
81 {
82 ADD_FAILURE() << "Should not have caught exception.";
83 }
84}
85
86// Test for I2CWriteBytesAction(uint8_t reg,
87// const std::vector<uint8_t>& values,
88// const std::vector<uint8_t>& masks)
89TEST(I2CWriteBytesActionTests, Constructor2)
90{
91 // Test where works
92 try
93 {
94 std::vector<uint8_t> values{0x56, 0x14};
95 std::vector<uint8_t> masks{0x7E, 0x3C};
96 I2CWriteBytesAction action{0xA0, values, masks};
97
98 EXPECT_EQ(action.getRegister(), 0xA0);
99
100 EXPECT_EQ(action.getValues().size(), 2);
101 EXPECT_EQ(action.getValues()[0], 0x56);
102 EXPECT_EQ(action.getValues()[1], 0x14);
103
104 EXPECT_EQ(action.getMasks().size(), 2);
105 EXPECT_EQ(action.getMasks()[0], 0x7E);
106 EXPECT_EQ(action.getMasks()[1], 0x3C);
107 }
108 catch (...)
109 {
110 ADD_FAILURE() << "Should not have caught exception.";
111 }
112
113 // Test where fails: Values vector is empty
114 try
115 {
116 std::vector<uint8_t> values{};
117 std::vector<uint8_t> masks{};
118 I2CWriteBytesAction action{0xA0, values, masks};
119 ADD_FAILURE() << "Should not have reached this line.";
120 }
121 catch (const std::invalid_argument& e)
122 {
123 EXPECT_STREQ(e.what(), "Values vector is empty");
124 }
125 catch (...)
126 {
127 ADD_FAILURE() << "Should not have caught exception.";
128 }
129
130 // Test where fails: Masks vector different size than values vector
131 try
132 {
133 std::vector<uint8_t> values{0x56, 0x14, 0xFE};
134 std::vector<uint8_t> masks{0x7E, 0x3C};
135 I2CWriteBytesAction action{0x7C, values, masks};
136 ADD_FAILURE() << "Should not have reached this line.";
137 }
138 catch (const std::invalid_argument& e)
139 {
140 EXPECT_STREQ(e.what(), "Masks vector has invalid size");
141 }
142 catch (...)
143 {
144 ADD_FAILURE() << "Should not have caught exception.";
145 }
146}
147
148TEST(I2CWriteBytesActionTests, Execute)
149{
150 // Test where works: Masks not specified
151 try
152 {
153 // Create mock I2CInterface
154 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
155 std::make_unique<i2c::MockedI2CInterface>();
156 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
157 EXPECT_CALL(*i2cInterface,
158 read(A<uint8_t>(), A<uint8_t&>(), A<uint8_t*>(),
159 A<i2c::I2CInterface::Mode>()))
160 .Times(0);
161 EXPECT_CALL(*i2cInterface,
162 write(0x7C, 3, NotNull(), i2c::I2CInterface::Mode::I2C))
163 .With(Args<2, 1>(ElementsAre(0x56, 0x14, 0xDA)))
164 .Times(1);
165
166 // Create Device, IDMap, and ActionEnvironment
167 Device device{"reg1", true, "/system/chassis/motherboard/reg1",
168 std::move(i2cInterface)};
169 IDMap idMap{};
170 idMap.addDevice(device);
171 ActionEnvironment env{idMap, "reg1"};
172
173 std::vector<uint8_t> values{0x56, 0x14, 0xDA};
174 I2CWriteBytesAction action{0x7C, values};
175 EXPECT_EQ(action.execute(env), true);
176 }
177 catch (...)
178 {
179 ADD_FAILURE() << "Should not have caught exception.";
180 }
181
182 // Test where works: Masks specified
183 try
184 {
185 // Create mock I2CInterface: read() returns values 0x69, 0xA5
186 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
187 std::make_unique<i2c::MockedI2CInterface>();
188 uint8_t actualValues[] = {0x69, 0xA5};
189 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
190 EXPECT_CALL(*i2cInterface, read(0xA0, TypedEq<uint8_t&>(2), NotNull(),
191 i2c::I2CInterface::Mode::I2C))
192 .Times(1)
193 .WillOnce(SetArrayArgument<2>(actualValues, actualValues + 2));
194 EXPECT_CALL(*i2cInterface,
195 write(0xA0, 2, NotNull(), i2c::I2CInterface::Mode::I2C))
196 .With(Args<2, 1>(ElementsAre(0xEA, 0xB3)))
197 .Times(1);
198
199 // Create Device, IDMap, and ActionEnvironment
200 Device device{"reg1", true, "/system/chassis/motherboard/reg1",
201 std::move(i2cInterface)};
202 IDMap idMap{};
203 idMap.addDevice(device);
204 ActionEnvironment env{idMap, "reg1"};
205
206 // Byte 1 Byte 2
207 // Value to write : 0xD6 = 1101 0110 : 0xD2 = 1101 0010
208 // Mask : 0xC3 = 1100 0011 : 0x96 = 1001 0110
209 // Current value : 0x69 = 0110 1001 : 0xA5 = 1010 0101
210 // Value to write & mask: 0xC2 = 1100 0010 : 0x92 = 1001 0010
211 // ~Mask : 0x3C = 0011 1100 : 0x69 = 0110 1001
212 // Current value & ~mask: 0x28 = 0010 1000 : 0x21 = 0010 0001
213 // Final value to write : 0xEA = 1110 1010 : 0xB3 = 1011 0011
214 std::vector<uint8_t> values{0xD6, 0xD2};
215 std::vector<uint8_t> masks{0xC3, 0x96};
216 I2CWriteBytesAction action{0xA0, values, masks};
217 EXPECT_EQ(action.execute(env), true);
218 }
219 catch (...)
220 {
221 ADD_FAILURE() << "Should not have caught exception.";
222 }
223
224 // Test where works: Single byte
225 try
226 {
227 // Create mock I2CInterface: read() returns value 0x69
228 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
229 std::make_unique<i2c::MockedI2CInterface>();
230 uint8_t actualValues[] = {0x69};
231 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
232 EXPECT_CALL(*i2cInterface, read(0xA0, TypedEq<uint8_t&>(1), NotNull(),
233 i2c::I2CInterface::Mode::I2C))
234 .Times(1)
235 .WillOnce(SetArrayArgument<2>(actualValues, actualValues + 1));
236 EXPECT_CALL(*i2cInterface,
237 write(0xA0, 1, NotNull(), i2c::I2CInterface::Mode::I2C))
238 .With(Args<2, 1>(ElementsAre(0xEA)))
239 .Times(1);
240
241 // Create Device, IDMap, and ActionEnvironment
242 Device device{"reg1", true, "/system/chassis/motherboard/reg1",
243 std::move(i2cInterface)};
244 IDMap idMap{};
245 idMap.addDevice(device);
246 ActionEnvironment env{idMap, "reg1"};
247
248 // Value to write : 0xD6 = 1101 0110
249 // Mask : 0xC3 = 1100 0011
250 // Current value : 0x69 = 0110 1001
251 // Value to write & mask: 0xC2 = 1100 0010
252 // ~Mask : 0x3C = 0011 1100
253 // Current value & ~mask: 0x28 = 0010 1000
254 // Final value to write : 0xEA = 1110 1010
255 std::vector<uint8_t> values{0xD6};
256 std::vector<uint8_t> masks{0xC3};
257 I2CWriteBytesAction action{0xA0, values, masks};
258 EXPECT_EQ(action.execute(env), true);
259 }
260 catch (...)
261 {
262 ADD_FAILURE() << "Should not have caught exception.";
263 }
264
265 // Test where fails: Getting I2CInterface fails
266 try
267 {
268 // Create IDMap and ActionEnvironment
269 IDMap idMap{};
270 ActionEnvironment env{idMap, "reg1"};
271
272 std::vector<uint8_t> values{0x56, 0x14, 0xDB};
273 I2CWriteBytesAction action{0x7C, values};
274 action.execute(env);
275 ADD_FAILURE() << "Should not have reached this line.";
276 }
277 catch (const std::invalid_argument& e)
278 {
279 EXPECT_STREQ(e.what(), "Unable to find device with ID \"reg1\"");
280 }
281 catch (...)
282 {
283 ADD_FAILURE() << "Should not have caught exception.";
284 }
285
286 // Test where fails: Reading bytes fails
287 try
288 {
289 // Create mock I2CInterface: read() throws an I2CException
290 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
291 std::make_unique<i2c::MockedI2CInterface>();
292 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
293 EXPECT_CALL(*i2cInterface, read(0xA0, TypedEq<uint8_t&>(2), NotNull(),
294 i2c::I2CInterface::Mode::I2C))
295 .Times(1)
296 .WillOnce(Throw(i2c::I2CException{"Failed to read i2c block data",
297 "/dev/i2c-1", 0x70}));
298 EXPECT_CALL(*i2cInterface,
299 write(A<uint8_t>(), A<uint8_t>(), A<const uint8_t*>(),
300 A<i2c::I2CInterface::Mode>()))
301 .Times(0);
302
303 // Create Device, IDMap, and ActionEnvironment
304 Device device{"reg1", true, "/system/chassis/motherboard/reg1",
305 std::move(i2cInterface)};
306 IDMap idMap{};
307 idMap.addDevice(device);
308 ActionEnvironment env{idMap, "reg1"};
309
310 std::vector<uint8_t> values{0xD6, 0xD2};
311 std::vector<uint8_t> masks{0xC3, 0x96};
312 I2CWriteBytesAction action{0xA0, values, masks};
313 action.execute(env);
314 ADD_FAILURE() << "Should not have reached this line.";
315 }
316 catch (const ActionError& e)
317 {
318 EXPECT_STREQ(e.what(),
319 "ActionError: i2c_write_bytes: { register: "
320 "0xA0, values: [ 0xD6, 0xD2 ], masks: [ 0xC3, 0x96 ] }");
321 try
322 {
323 // Re-throw inner I2CException
324 std::rethrow_if_nested(e);
325 ADD_FAILURE() << "Should not have reached this line.";
326 }
327 catch (const i2c::I2CException& ie)
328 {
329 EXPECT_STREQ(ie.what(),
330 "I2CException: Failed to read i2c block data: bus "
331 "/dev/i2c-1, addr 0x70");
332 }
333 catch (...)
334 {
335 ADD_FAILURE() << "Should not have caught exception.";
336 }
337 }
338 catch (...)
339 {
340 ADD_FAILURE() << "Should not have caught exception.";
341 }
342
343 // Test where fails: Writing bytes fails
344 try
345 {
346 // Create mock I2CInterface: write() throws an I2CException
347 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
348 std::make_unique<i2c::MockedI2CInterface>();
349 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
350 EXPECT_CALL(*i2cInterface,
351 read(A<uint8_t>(), A<uint8_t&>(), A<uint8_t*>(),
352 A<i2c::I2CInterface::Mode>()))
353 .Times(0);
354 EXPECT_CALL(*i2cInterface,
355 write(0x7C, 3, NotNull(), i2c::I2CInterface::Mode::I2C))
356 .With(Args<2, 1>(ElementsAre(0x56, 0x14, 0xDA)))
357 .Times(1)
358 .WillOnce(Throw(i2c::I2CException{"Failed to write i2c block data",
359 "/dev/i2c-1", 0x70}));
360
361 // Create Device, IDMap, and ActionEnvironment
362 Device device{"reg1", true, "/system/chassis/motherboard/reg1",
363 std::move(i2cInterface)};
364 IDMap idMap{};
365 idMap.addDevice(device);
366 ActionEnvironment env{idMap, "reg1"};
367
368 std::vector<uint8_t> values{0x56, 0x14, 0xDA};
369 I2CWriteBytesAction action{0x7C, values};
370 EXPECT_EQ(action.execute(env), true);
371 action.execute(env);
372 ADD_FAILURE() << "Should not have reached this line.";
373 }
374 catch (const ActionError& e)
375 {
376 EXPECT_STREQ(e.what(),
377 "ActionError: i2c_write_bytes: { register: "
378 "0x7C, values: [ 0x56, 0x14, 0xDA ], masks: [ ] }");
379 try
380 {
381 // Re-throw inner I2CException
382 std::rethrow_if_nested(e);
383 ADD_FAILURE() << "Should not have reached this line.";
384 }
385 catch (const i2c::I2CException& ie)
386 {
387 EXPECT_STREQ(ie.what(),
388 "I2CException: Failed to write i2c block data: bus "
389 "/dev/i2c-1, addr 0x70");
390 }
391 catch (...)
392 {
393 ADD_FAILURE() << "Should not have caught exception.";
394 }
395 }
396 catch (...)
397 {
398 ADD_FAILURE() << "Should not have caught exception.";
399 }
400}
401
402TEST(I2CWriteBytesActionTests, GetRegister)
403{
404 std::vector<uint8_t> values{0x56, 0x14};
405 I2CWriteBytesAction action{0xA0, values};
406 EXPECT_EQ(action.getRegister(), 0xA0);
407}
408
409TEST(I2CWriteBytesActionTests, GetValues)
410{
411 std::vector<uint8_t> values{0x56, 0x14};
412 std::vector<uint8_t> masks{0x7E, 0x3C};
413 I2CWriteBytesAction action{0xA0, values, masks};
414 EXPECT_EQ(action.getValues().size(), 2);
415 EXPECT_EQ(action.getValues()[0], 0x56);
416 EXPECT_EQ(action.getValues()[1], 0x14);
417}
418
419TEST(I2CWriteBytesActionTests, GetMasks)
420{
421 // Test where masks were not specified
422 {
423 std::vector<uint8_t> values{0x56, 0x14, 0xDA};
424 I2CWriteBytesAction action{0x7C, values};
425 EXPECT_EQ(action.getMasks().size(), 0);
426 }
427
428 // Test where masks were specified
429 {
430 std::vector<uint8_t> values{0x56, 0x14};
431 std::vector<uint8_t> masks{0x7E, 0x3C};
432 I2CWriteBytesAction action{0xA0, values, masks};
433 EXPECT_EQ(action.getMasks().size(), 2);
434 EXPECT_EQ(action.getMasks()[0], 0x7E);
435 EXPECT_EQ(action.getMasks()[1], 0x3C);
436 }
437}
438
439TEST(I2CWriteBytesActionTests, ToString)
440{
441 // Test where masks were not specified
442 {
443 std::vector<uint8_t> values{0x56, 0x14, 0xDA};
444 I2CWriteBytesAction action{0x7C, values};
445 EXPECT_EQ(action.toString(),
446 "i2c_write_bytes: { register: 0x7C, values: "
447 "[ 0x56, 0x14, 0xDA ], masks: [ ] }");
448 }
449
450 // Test where masks were specified
451 {
452 std::vector<uint8_t> values{0x56, 0x14};
453 std::vector<uint8_t> masks{0x7E, 0x3C};
454 I2CWriteBytesAction action{0xA0, values, masks};
455 EXPECT_EQ(action.toString(),
456 "i2c_write_bytes: { register: 0xA0, values: "
457 "[ 0x56, 0x14 ], masks: [ 0x7E, 0x3C ] }");
458 }
459}