1 /**
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_compare_byte_action.hpp"
20 #include "i2c_interface.hpp"
21 #include "id_map.hpp"
22 #include "mock_services.hpp"
23 #include "mocked_i2c_interface.hpp"
24
25 #include <cstdint>
26 #include <memory>
27 #include <stdexcept>
28 #include <string>
29 #include <utility>
30
31 #include <gmock/gmock.h>
32 #include <gtest/gtest.h>
33
34 using namespace phosphor::power::regulators;
35
36 using ::testing::A;
37 using ::testing::Return;
38 using ::testing::SetArgReferee;
39 using ::testing::Throw;
40
TEST(I2CCompareByteActionTests,Constructor)41 TEST(I2CCompareByteActionTests, Constructor)
42 {
43 // Test where mask is not specified
44 {
45 I2CCompareByteAction action{0x7C, 0xDE};
46 EXPECT_EQ(action.getRegister(), 0x7C);
47 EXPECT_EQ(action.getValue(), 0xDE);
48 EXPECT_EQ(action.getMask(), 0xFF);
49 }
50
51 // Test where mask is specified
52 {
53 I2CCompareByteAction action{0xA0, 0x03, 0x47};
54 EXPECT_EQ(action.getRegister(), 0xA0);
55 EXPECT_EQ(action.getValue(), 0x03);
56 EXPECT_EQ(action.getMask(), 0x47);
57 }
58 }
59
TEST(I2CCompareByteActionTests,Execute)60 TEST(I2CCompareByteActionTests, Execute)
61 {
62 // Test where works: Equal: Mask specified
63 try
64 {
65 // Create mock I2CInterface: read() returns value 0xD7
66 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
67 std::make_unique<i2c::MockedI2CInterface>();
68 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
69 EXPECT_CALL(*i2cInterface, read(0xA0, A<uint8_t&>()))
70 .Times(1)
71 .WillOnce(SetArgReferee<1>(0xD7));
72
73 // Create Device, IDMap, MockServices, and ActionEnvironment
74 Device device{
75 "reg1", true,
76 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
77 std::move(i2cInterface)};
78 IDMap idMap{};
79 idMap.addDevice(device);
80 MockServices services{};
81 ActionEnvironment env{idMap, "reg1", services};
82
83 // Actual value: 0xD7 = 1101 0111
84 // Mask : 0x7E = 0111 1110
85 // Result : 0x56 = 0101 0110
86 I2CCompareByteAction action{0xA0, 0x56, 0x7E};
87 EXPECT_EQ(action.execute(env), true);
88 }
89 catch (...)
90 {
91 ADD_FAILURE() << "Should not have caught exception.";
92 }
93
94 // Test where works: Equal: Mask not specified
95 try
96 {
97 // Create mock I2CInterface: read() returns value 0xD7
98 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
99 std::make_unique<i2c::MockedI2CInterface>();
100 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
101 EXPECT_CALL(*i2cInterface, read(0xA0, A<uint8_t&>()))
102 .Times(1)
103 .WillOnce(SetArgReferee<1>(0xD7));
104
105 // Create Device, IDMap, MockServices, and ActionEnvironment
106 Device device{
107 "reg1", true,
108 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
109 std::move(i2cInterface)};
110 IDMap idMap{};
111 idMap.addDevice(device);
112 MockServices services{};
113 ActionEnvironment env{idMap, "reg1", services};
114
115 I2CCompareByteAction action{0xA0, 0xD7};
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: Not equal: Mask specified
124 try
125 {
126 // Create mock I2CInterface: read() returns value 0xD7
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(0xA0, A<uint8_t&>()))
131 .Times(1)
132 .WillOnce(SetArgReferee<1>(0xD7));
133
134 // Create Device, IDMap, MockServices, and ActionEnvironment
135 Device device{
136 "reg1", true,
137 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
138 std::move(i2cInterface)};
139 IDMap idMap{};
140 idMap.addDevice(device);
141 MockServices services{};
142 ActionEnvironment env{idMap, "reg1", services};
143
144 // Actual value: 0xD7 = 1101 0111
145 // Mask : 0x7E = 0111 1110
146 // Result : 0x56 = 0101 0110
147 I2CCompareByteAction action{0xA0, 0x57, 0x7E};
148 EXPECT_EQ(action.execute(env), false);
149 }
150 catch (...)
151 {
152 ADD_FAILURE() << "Should not have caught exception.";
153 }
154
155 // Test where works: Not equal: Mask not specified
156 try
157 {
158 // Create mock I2CInterface: read() returns value 0xD7
159 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
160 std::make_unique<i2c::MockedI2CInterface>();
161 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
162 EXPECT_CALL(*i2cInterface, read(0xA0, A<uint8_t&>()))
163 .Times(1)
164 .WillOnce(SetArgReferee<1>(0xD7));
165
166 // Create Device, IDMap, MockServices, and ActionEnvironment
167 Device device{
168 "reg1", true,
169 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
170 std::move(i2cInterface)};
171 IDMap idMap{};
172 idMap.addDevice(device);
173 MockServices services{};
174 ActionEnvironment env{idMap, "reg1", services};
175
176 I2CCompareByteAction action{0xA0, 0xD6};
177 EXPECT_EQ(action.execute(env), false);
178 }
179 catch (...)
180 {
181 ADD_FAILURE() << "Should not have caught exception.";
182 }
183
184 // Test where fails: Getting I2CInterface fails
185 try
186 {
187 // Create IDMap, MockServices, and ActionEnvironment
188 IDMap idMap{};
189 MockServices services{};
190 ActionEnvironment env{idMap, "reg1", services};
191
192 I2CCompareByteAction action{0xA0, 0xD6};
193 action.execute(env);
194 ADD_FAILURE() << "Should not have reached this line.";
195 }
196 catch (const std::invalid_argument& e)
197 {
198 EXPECT_STREQ(e.what(), "Unable to find device with ID \"reg1\"");
199 }
200 catch (...)
201 {
202 ADD_FAILURE() << "Should not have caught exception.";
203 }
204
205 // Test where fails: Reading byte fails
206 try
207 {
208 // Create mock I2CInterface: read() throws an I2CException
209 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
210 std::make_unique<i2c::MockedI2CInterface>();
211 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
212 EXPECT_CALL(*i2cInterface, read(0xA0, A<uint8_t&>()))
213 .Times(1)
214 .WillOnce(Throw(
215 i2c::I2CException{"Failed to read byte", "/dev/i2c-1", 0x70}));
216
217 // Create Device, IDMap, MockServices, and ActionEnvironment
218 Device device{
219 "reg1", true,
220 "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
221 std::move(i2cInterface)};
222 IDMap idMap{};
223 idMap.addDevice(device);
224 MockServices services{};
225 ActionEnvironment env{idMap, "reg1", services};
226
227 I2CCompareByteAction action{0xA0, 0xD6};
228 action.execute(env);
229 ADD_FAILURE() << "Should not have reached this line.";
230 }
231 catch (const ActionError& e)
232 {
233 EXPECT_STREQ(e.what(), "ActionError: i2c_compare_byte: { register: "
234 "0xA0, value: 0xD6, mask: 0xFF }");
235 try
236 {
237 // Re-throw inner I2CException
238 std::rethrow_if_nested(e);
239 ADD_FAILURE() << "Should not have reached this line.";
240 }
241 catch (const i2c::I2CException& ie)
242 {
243 EXPECT_STREQ(
244 ie.what(),
245 "I2CException: Failed to read byte: bus /dev/i2c-1, addr 0x70");
246 }
247 catch (...)
248 {
249 ADD_FAILURE() << "Should not have caught exception.";
250 }
251 }
252 catch (...)
253 {
254 ADD_FAILURE() << "Should not have caught exception.";
255 }
256 }
257
TEST(I2CCompareByteActionTests,GetRegister)258 TEST(I2CCompareByteActionTests, GetRegister)
259 {
260 I2CCompareByteAction action{0x7C, 0xDE};
261 EXPECT_EQ(action.getRegister(), 0x7C);
262 }
263
TEST(I2CCompareByteActionTests,GetValue)264 TEST(I2CCompareByteActionTests, GetValue)
265 {
266 I2CCompareByteAction action{0xA0, 0x03, 0x47};
267 EXPECT_EQ(action.getValue(), 0x03);
268 }
269
TEST(I2CCompareByteActionTests,GetMask)270 TEST(I2CCompareByteActionTests, GetMask)
271 {
272 // Test where mask is not specified
273 {
274 I2CCompareByteAction action{0x7C, 0xDE};
275 EXPECT_EQ(action.getMask(), 0xFF);
276 }
277
278 // Test where mask is specified
279 {
280 I2CCompareByteAction action{0xA0, 0x03, 0x47};
281 EXPECT_EQ(action.getMask(), 0x47);
282 }
283 }
284
TEST(I2CCompareByteActionTests,ToString)285 TEST(I2CCompareByteActionTests, ToString)
286 {
287 I2CCompareByteAction action{0x7C, 0xDE, 0xFE};
288 EXPECT_EQ(action.toString(),
289 "i2c_compare_byte: { register: 0x7C, value: 0xDE, mask: 0xFE }");
290 }
291