blob: 1a858e378f8081fe358c3034357d9243d10e4983 [file] [log] [blame]
Shawn McCarneyf1c90612020-02-24 09:56:53 -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_byte_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(I2CWriteByteActionTests, Constructor)
42{
43 // Test where mask is not specified
44 {
45 I2CWriteByteAction action{0x7C, 0x0A};
46 EXPECT_EQ(action.getRegister(), 0x7C);
47 EXPECT_EQ(action.getValue(), 0x0A);
48 EXPECT_EQ(action.getMask(), 0xFF);
49 }
50
51 // Test where mask is specified
52 {
53 I2CWriteByteAction action{0xA0, 0xD6, 0xC3};
54 EXPECT_EQ(action.getRegister(), 0xA0);
55 EXPECT_EQ(action.getValue(), 0xD6);
56 EXPECT_EQ(action.getMask(), 0xC3);
57 }
58}
59
60TEST(I2CWriteByteActionTests, Execute)
61{
62 // Test where works: Mask not specified
63 try
64 {
65 // Create mock I2CInterface
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(A<uint8_t>(), A<uint8_t&>())).Times(0);
70 EXPECT_CALL(*i2cInterface,
71 write(TypedEq<uint8_t>(0x7C), TypedEq<uint8_t>(0x0A)))
72 .Times(1);
73
74 // Create Device, IDMap, and ActionEnvironment
75 Device device{"reg1", true, "/system/chassis/motherboard/reg1",
76 std::move(i2cInterface)};
77 IDMap idMap{};
78 idMap.addDevice(device);
79 ActionEnvironment env{idMap, "reg1"};
80
81 I2CWriteByteAction action{0x7C, 0x0A};
82 EXPECT_EQ(action.execute(env), true);
83 }
84 catch (...)
85 {
86 ADD_FAILURE() << "Should not have caught exception.";
87 }
88
89 // Test where works: Mask specified
90 try
91 {
92 // Create mock I2CInterface: read() returns value 0x69
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>(0x69));
99 EXPECT_CALL(*i2cInterface,
100 write(TypedEq<uint8_t>(0xA0), TypedEq<uint8_t>(0xEA)))
101 .Times(1);
102
103 // Create Device, IDMap, and ActionEnvironment
104 Device device{"reg1", true, "/system/chassis/motherboard/reg1",
105 std::move(i2cInterface)};
106 IDMap idMap{};
107 idMap.addDevice(device);
108 ActionEnvironment env{idMap, "reg1"};
109
110 // Value to write : 0xD6 = 1101 0110
111 // Mask : 0xC3 = 1100 0011
112 // Current value : 0x69 = 0110 1001
113 // Value to write & mask: 0xC2 = 1100 0010
114 // ~Mask : 0x3C = 0011 1100
115 // Current value & ~mask: 0x28 = 0010 1000
116 // Final value to write : 0xEA = 1110 1010
117 I2CWriteByteAction action{0xA0, 0xD6, 0xC3};
118 EXPECT_EQ(action.execute(env), true);
119 }
120 catch (...)
121 {
122 ADD_FAILURE() << "Should not have caught exception.";
123 }
124
125 // Test where fails: Getting I2CInterface fails
126 try
127 {
128 // Create IDMap and ActionEnvironment
129 IDMap idMap{};
130 ActionEnvironment env{idMap, "reg1"};
131
132 I2CWriteByteAction action{0x7C, 0x0A};
133 action.execute(env);
134 ADD_FAILURE() << "Should not have reached this line.";
135 }
136 catch (const std::invalid_argument& e)
137 {
138 EXPECT_STREQ(e.what(), "Unable to find device with ID \"reg1\"");
139 }
140 catch (...)
141 {
142 ADD_FAILURE() << "Should not have caught exception.";
143 }
144
145 // Test where fails: Reading byte fails
146 try
147 {
148 // Create mock I2CInterface: read() throws an I2CException
149 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
150 std::make_unique<i2c::MockedI2CInterface>();
151 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
152 EXPECT_CALL(*i2cInterface, read(0xA0, A<uint8_t&>()))
153 .Times(1)
154 .WillOnce(Throw(
155 i2c::I2CException{"Failed to read byte", "/dev/i2c-1", 0x70}));
156 EXPECT_CALL(*i2cInterface, write(A<uint8_t>(), A<uint8_t>())).Times(0);
157
158 // Create Device, IDMap, and ActionEnvironment
159 Device device{"reg1", true, "/system/chassis/motherboard/reg1",
160 std::move(i2cInterface)};
161 IDMap idMap{};
162 idMap.addDevice(device);
163 ActionEnvironment env{idMap, "reg1"};
164
165 I2CWriteByteAction action{0xA0, 0xD6, 0xC3};
166 action.execute(env);
167 ADD_FAILURE() << "Should not have reached this line.";
168 }
169 catch (const ActionError& e)
170 {
171 EXPECT_STREQ(e.what(), "ActionError: i2c_write_byte: { register: "
172 "0xA0, value: 0xD6, mask: 0xC3 }");
173 try
174 {
175 // Re-throw inner I2CException
176 std::rethrow_if_nested(e);
177 ADD_FAILURE() << "Should not have reached this line.";
178 }
179 catch (const i2c::I2CException& ie)
180 {
181 EXPECT_STREQ(
182 ie.what(),
183 "I2CException: Failed to read byte: bus /dev/i2c-1, addr 0x70");
184 }
185 catch (...)
186 {
187 ADD_FAILURE() << "Should not have caught exception.";
188 }
189 }
190 catch (...)
191 {
192 ADD_FAILURE() << "Should not have caught exception.";
193 }
194
195 // Test where fails: Writing byte fails
196 try
197 {
198 // Create mock I2CInterface: write() throws an I2CException
199 std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
200 std::make_unique<i2c::MockedI2CInterface>();
201 EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
202 EXPECT_CALL(*i2cInterface, read(A<uint8_t>(), A<uint8_t&>())).Times(0);
203 EXPECT_CALL(*i2cInterface,
204 write(TypedEq<uint8_t>(0x7C), TypedEq<uint8_t>(0x1A)))
205 .Times(1)
206 .WillOnce(Throw(
207 i2c::I2CException{"Failed to write byte", "/dev/i2c-1", 0x70}));
208
209 // Create Device, IDMap, and ActionEnvironment
210 Device device{"reg1", true, "/system/chassis/motherboard/reg1",
211 std::move(i2cInterface)};
212 IDMap idMap{};
213 idMap.addDevice(device);
214 ActionEnvironment env{idMap, "reg1"};
215
216 I2CWriteByteAction action{0x7C, 0x1A};
217 action.execute(env);
218 ADD_FAILURE() << "Should not have reached this line.";
219 }
220 catch (const ActionError& e)
221 {
222 EXPECT_STREQ(e.what(), "ActionError: i2c_write_byte: { register: "
223 "0x7C, value: 0x1A, mask: 0xFF }");
224 try
225 {
226 // Re-throw inner I2CException
227 std::rethrow_if_nested(e);
228 ADD_FAILURE() << "Should not have reached this line.";
229 }
230 catch (const i2c::I2CException& ie)
231 {
232 EXPECT_STREQ(ie.what(), "I2CException: Failed to write byte: bus "
233 "/dev/i2c-1, addr 0x70");
234 }
235 catch (...)
236 {
237 ADD_FAILURE() << "Should not have caught exception.";
238 }
239 }
240 catch (...)
241 {
242 ADD_FAILURE() << "Should not have caught exception.";
243 }
244}
245
246TEST(I2CWriteByteActionTests, GetRegister)
247{
248 I2CWriteByteAction action{0x7C, 0xDE};
249 EXPECT_EQ(action.getRegister(), 0x7C);
250}
251
252TEST(I2CWriteByteActionTests, GetValue)
253{
254 I2CWriteByteAction action{0xA0, 0x03, 0x47};
255 EXPECT_EQ(action.getValue(), 0x03);
256}
257
258TEST(I2CWriteByteActionTests, GetMask)
259{
260 // Test where mask is not specified
261 {
262 I2CWriteByteAction action{0x7C, 0xDE};
263 EXPECT_EQ(action.getMask(), 0xFF);
264 }
265
266 // Test where mask is specified
267 {
268 I2CWriteByteAction action{0xA0, 0x03, 0x47};
269 EXPECT_EQ(action.getMask(), 0x47);
270 }
271}
272
273TEST(I2CWriteByteActionTests, ToString)
274{
275 I2CWriteByteAction action{0x7C, 0xDE, 0xFB};
276 EXPECT_EQ(action.toString(),
277 "i2c_write_byte: { register: 0x7C, value: 0xDE, mask: 0xFB }");
278}