blob: d3a7c180f7f7a715022666c58812c6f70180e2e9 [file] [log] [blame]
Shawn McCarney88d5b692020-02-25 10:39:02 -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_bit_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
30#include <gmock/gmock.h>
31#include <gtest/gtest.h>
32
33using namespace phosphor::power::regulators;
34
35using ::testing::A;
36using ::testing::Return;
37using ::testing::SetArgReferee;
38using ::testing::Throw;
39using ::testing::TypedEq;
40
41TEST(I2CWriteBitActionTests, Constructor)
42{
43 // Test where works
44 try
45 {
46 I2CWriteBitAction action{0x7C, 2, 0};
47 EXPECT_EQ(action.getRegister(), 0x7C);
48 EXPECT_EQ(action.getPosition(), 2);
49 EXPECT_EQ(action.getValue(), 0);
50 }
51 catch (...)
52 {
53 ADD_FAILURE() << "Should not have caught exception.";
54 }
55
56 // Test where fails: Invalid bit position > 7
57 try
58 {
59 I2CWriteBitAction action{0x7C, 8, 0};
60 ADD_FAILURE() << "Should not have reached this line.";
61 }
62 catch (const std::invalid_argument& e)
63 {
64 EXPECT_STREQ(e.what(), "Invalid bit position: 8");
65 }
66 catch (...)
67 {
68 ADD_FAILURE() << "Should not have caught exception.";
69 }
70
71 // Test where fails: Invalid bit value > 1
72 try
73 {
74 I2CWriteBitAction action{0x7C, 2, 2};
75 ADD_FAILURE() << "Should not have reached this line.";
76 }
77 catch (const std::invalid_argument& e)
78 {
79 EXPECT_STREQ(e.what(), "Invalid bit value: 2");
80 }
81 catch (...)
82 {
83 ADD_FAILURE() << "Should not have caught exception.";
84 }
85}
86
87TEST(I2CWriteBitActionTests, Execute)
88{
89 // Test where works: Value is 0
90 try
91 {
92 // Create mock I2CInterface: read() returns value 0xB6
93 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
94 std::make_unique<i2c::MockedI2CInterface>();
95 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
96 EXPECT_CALL(*i2cInterface, read(0xA0, A<uint8_t&>()))
97 .Times(1)
98 .WillOnce(SetArgReferee<1>(0xB6));
99 EXPECT_CALL(*i2cInterface,
100 write(TypedEq<uint8_t>(0xA0), TypedEq<uint8_t>(0x96)))
101 .Times(1);
102
103 // Create Device, IDMap, and ActionEnvironment
Bob Kinga76898f2020-10-13 15:08:33 +0800104 Device device{
105 "reg1", true,
106 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
107 std::move(i2cInterface)};
Shawn McCarney88d5b692020-02-25 10:39:02 -0600108 IDMap idMap{};
109 idMap.addDevice(device);
110 ActionEnvironment env{idMap, "reg1"};
111
112 // Register value : 0xB6 = 1011 0110
113 // 0 in position 5 : 0x00 = --0- ----
114 // New register value: 0x96 = 1001 0110
115 I2CWriteBitAction action{0xA0, 5, 0};
116 EXPECT_EQ(action.execute(env), true);
117 }
118 catch (...)
119 {
120 ADD_FAILURE() << "Should not have caught exception.";
121 }
122
123 // Test where works: Value is 1
124 try
125 {
126 // Create mock I2CInterface: read() returns value 0x96
127 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
128 std::make_unique<i2c::MockedI2CInterface>();
129 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
130 EXPECT_CALL(*i2cInterface, read(0x7C, A<uint8_t&>()))
131 .Times(1)
132 .WillOnce(SetArgReferee<1>(0x96));
133 EXPECT_CALL(*i2cInterface,
134 write(TypedEq<uint8_t>(0x7C), TypedEq<uint8_t>(0xB6)))
135 .Times(1);
136
137 // Create Device, IDMap, and ActionEnvironment
Bob Kinga76898f2020-10-13 15:08:33 +0800138 Device device{
139 "reg1", true,
140 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
141 std::move(i2cInterface)};
Shawn McCarney88d5b692020-02-25 10:39:02 -0600142 IDMap idMap{};
143 idMap.addDevice(device);
144 ActionEnvironment env{idMap, "reg1"};
145
146 // Register value : 0x96 = 1001 0110
147 // 1 in position 5 : 0x20 = 0010 0000
148 // New register value: 0xB6 = 1011 0110
149 I2CWriteBitAction action{0x7C, 5, 1};
150 EXPECT_EQ(action.execute(env), true);
151 }
152 catch (...)
153 {
154 ADD_FAILURE() << "Should not have caught exception.";
155 }
156
157 // Test where fails: Getting I2CInterface fails
158 try
159 {
160 // Create IDMap and ActionEnvironment
161 IDMap idMap{};
162 ActionEnvironment env{idMap, "reg1"};
163
164 I2CWriteBitAction action{0x7C, 5, 1};
165 action.execute(env);
166 ADD_FAILURE() << "Should not have reached this line.";
167 }
168 catch (const std::invalid_argument& e)
169 {
170 EXPECT_STREQ(e.what(), "Unable to find device with ID \"reg1\"");
171 }
172 catch (...)
173 {
174 ADD_FAILURE() << "Should not have caught exception.";
175 }
176
177 // Test where fails: Reading byte fails
178 try
179 {
180 // Create mock I2CInterface: read() throws an I2CException
181 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
182 std::make_unique<i2c::MockedI2CInterface>();
183 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
184 EXPECT_CALL(*i2cInterface, read(0x7C, A<uint8_t&>()))
185 .Times(1)
186 .WillOnce(Throw(
187 i2c::I2CException{"Failed to read byte", "/dev/i2c-1", 0x70}));
188 EXPECT_CALL(*i2cInterface, write(A<uint8_t>(), A<uint8_t>())).Times(0);
189
190 // Create Device, IDMap, and ActionEnvironment
Bob Kinga76898f2020-10-13 15:08:33 +0800191 Device device{
192 "reg1", true,
193 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
194 std::move(i2cInterface)};
Shawn McCarney88d5b692020-02-25 10:39:02 -0600195 IDMap idMap{};
196 idMap.addDevice(device);
197 ActionEnvironment env{idMap, "reg1"};
198
199 I2CWriteBitAction action{0x7C, 5, 1};
200 action.execute(env);
201 ADD_FAILURE() << "Should not have reached this line.";
202 }
203 catch (const ActionError& e)
204 {
205 EXPECT_STREQ(e.what(), "ActionError: i2c_write_bit: { register: "
206 "0x7C, position: 5, value: 1 }");
207 try
208 {
209 // Re-throw inner I2CException
210 std::rethrow_if_nested(e);
211 ADD_FAILURE() << "Should not have reached this line.";
212 }
213 catch (const i2c::I2CException& ie)
214 {
215 EXPECT_STREQ(
216 ie.what(),
217 "I2CException: Failed to read byte: bus /dev/i2c-1, addr 0x70");
218 }
219 catch (...)
220 {
221 ADD_FAILURE() << "Should not have caught exception.";
222 }
223 }
224 catch (...)
225 {
226 ADD_FAILURE() << "Should not have caught exception.";
227 }
228
229 // Test where fails: Writing byte fails
230 try
231 {
232 // Create mock I2CInterface: read() returns value 0xB6, write() throws
233 // an I2CException
234 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
235 std::make_unique<i2c::MockedI2CInterface>();
236 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
237 EXPECT_CALL(*i2cInterface, read(0xA0, A<uint8_t&>()))
238 .Times(1)
239 .WillOnce(SetArgReferee<1>(0xB6));
240 EXPECT_CALL(*i2cInterface,
241 write(TypedEq<uint8_t>(0xA0), TypedEq<uint8_t>(0x96)))
242 .Times(1)
243 .WillOnce(Throw(
244 i2c::I2CException{"Failed to write byte", "/dev/i2c-1", 0x70}));
245
246 // Create Device, IDMap, and ActionEnvironment
Bob Kinga76898f2020-10-13 15:08:33 +0800247 Device device{
248 "reg1", true,
249 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
250 std::move(i2cInterface)};
Shawn McCarney88d5b692020-02-25 10:39:02 -0600251 IDMap idMap{};
252 idMap.addDevice(device);
253 ActionEnvironment env{idMap, "reg1"};
254
255 // Register value : 0xB6 = 1011 0110
256 // 0 in position 5 : 0x00 = --0- ----
257 // New register value: 0x96 = 1001 0110
258 I2CWriteBitAction action{0xA0, 5, 0};
259 action.execute(env);
260 ADD_FAILURE() << "Should not have reached this line.";
261 }
262 catch (const ActionError& e)
263 {
264 EXPECT_STREQ(e.what(), "ActionError: i2c_write_bit: { register: "
265 "0xA0, position: 5, value: 0 }");
266 try
267 {
268 // Re-throw inner I2CException
269 std::rethrow_if_nested(e);
270 ADD_FAILURE() << "Should not have reached this line.";
271 }
272 catch (const i2c::I2CException& ie)
273 {
274 EXPECT_STREQ(ie.what(), "I2CException: Failed to write byte: bus "
275 "/dev/i2c-1, addr 0x70");
276 }
277 catch (...)
278 {
279 ADD_FAILURE() << "Should not have caught exception.";
280 }
281 }
282 catch (...)
283 {
284 ADD_FAILURE() << "Should not have caught exception.";
285 }
286}
287
288TEST(I2CWriteBitActionTests, GetRegister)
289{
290 I2CWriteBitAction action{0x7C, 5, 1};
291 EXPECT_EQ(action.getRegister(), 0x7C);
292}
293
294TEST(I2CWriteBitActionTests, GetPosition)
295{
296 I2CWriteBitAction action{0x7C, 5, 1};
297 EXPECT_EQ(action.getPosition(), 5);
298}
299
300TEST(I2CWriteBitActionTests, GetValue)
301{
302 I2CWriteBitAction action{0x7C, 5, 1};
303 EXPECT_EQ(action.getValue(), 1);
304}
305
306TEST(I2CWriteBitActionTests, ToString)
307{
308 I2CWriteBitAction action{0x7C, 5, 1};
309 EXPECT_EQ(action.toString(),
310 "i2c_write_bit: { register: 0x7C, position: 5, value: 1 }");
311}