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_bit_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 
41 TEST(I2CCompareBitActionTests, Constructor)
42 {
43     // Test where works
44     try
45     {
46         I2CCompareBitAction 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         I2CCompareBitAction 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         I2CCompareBitAction 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 
87 TEST(I2CCompareBitActionTests, Execute)
88 {
89     // Test where works
90     try
91     {
92         // Create mock I2CInterface: read() returns value 0x96 (1001 0110)
93         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
94             std::make_unique<i2c::MockedI2CInterface>();
95         EXPECT_CALL(*i2cInterface, isOpen).WillRepeatedly(Return(true));
96         EXPECT_CALL(*i2cInterface, read(0x7C, A<uint8_t&>()))
97             .WillRepeatedly(SetArgReferee<1>(0x96));
98 
99         // Create Device, IDMap, MockServices, and ActionEnvironment
100         Device device{
101             "reg1", true,
102             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
103             std::move(i2cInterface)};
104         IDMap idMap{};
105         idMap.addDevice(device);
106         MockServices services{};
107         ActionEnvironment env{idMap, "reg1", services};
108 
109         // Test where actual bit value is equal to expected bit value.
110         // Test all bits in register value 0x96 == 1001 0110).
111         {
112             I2CCompareBitAction actions[] = {I2CCompareBitAction{0x7C, 7, 1},
113                                              I2CCompareBitAction{0x7C, 6, 0},
114                                              I2CCompareBitAction{0x7C, 5, 0},
115                                              I2CCompareBitAction{0x7C, 4, 1},
116                                              I2CCompareBitAction{0x7C, 3, 0},
117                                              I2CCompareBitAction{0x7C, 2, 1},
118                                              I2CCompareBitAction{0x7C, 1, 1},
119                                              I2CCompareBitAction{0x7C, 0, 0}};
120             for (I2CCompareBitAction& action : actions)
121             {
122                 EXPECT_EQ(action.execute(env), true);
123             }
124         }
125 
126         // Test where actual bit value is not equal to expected bit value.
127         // Test all bits in register value 0x96 == 1001 0110).
128         {
129             I2CCompareBitAction actions[] = {I2CCompareBitAction{0x7C, 7, 0},
130                                              I2CCompareBitAction{0x7C, 6, 1},
131                                              I2CCompareBitAction{0x7C, 5, 1},
132                                              I2CCompareBitAction{0x7C, 4, 0},
133                                              I2CCompareBitAction{0x7C, 3, 1},
134                                              I2CCompareBitAction{0x7C, 2, 0},
135                                              I2CCompareBitAction{0x7C, 1, 0},
136                                              I2CCompareBitAction{0x7C, 0, 1}};
137             for (I2CCompareBitAction& action : actions)
138             {
139                 EXPECT_EQ(action.execute(env), false);
140             }
141         }
142     }
143     catch (...)
144     {
145         ADD_FAILURE() << "Should not have caught exception.";
146     }
147 
148     // Test where fails: Getting I2CInterface fails
149     try
150     {
151         // Create IDMap, MockServices, and ActionEnvironment
152         IDMap idMap{};
153         MockServices services{};
154         ActionEnvironment env{idMap, "reg1", services};
155 
156         I2CCompareBitAction action{0x7C, 5, 1};
157         action.execute(env);
158         ADD_FAILURE() << "Should not have reached this line.";
159     }
160     catch (const std::invalid_argument& e)
161     {
162         EXPECT_STREQ(e.what(), "Unable to find device with ID \"reg1\"");
163     }
164     catch (...)
165     {
166         ADD_FAILURE() << "Should not have caught exception.";
167     }
168 
169     // Test where fails: Reading byte fails
170     try
171     {
172         // Create mock I2CInterface: read() throws an I2CException
173         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
174             std::make_unique<i2c::MockedI2CInterface>();
175         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
176         EXPECT_CALL(*i2cInterface, read(0x7C, A<uint8_t&>()))
177             .Times(1)
178             .WillOnce(Throw(
179                 i2c::I2CException{"Failed to read byte", "/dev/i2c-1", 0x70}));
180 
181         // Create Device, IDMap, MockServices, and ActionEnvironment
182         Device device{
183             "reg1", true,
184             "/xyz/openbmc_project/inventory/system/chassis/motherboard/reg1",
185             std::move(i2cInterface)};
186         IDMap idMap{};
187         idMap.addDevice(device);
188         MockServices services{};
189         ActionEnvironment env{idMap, "reg1", services};
190 
191         I2CCompareBitAction action{0x7C, 5, 1};
192         action.execute(env);
193         ADD_FAILURE() << "Should not have reached this line.";
194     }
195     catch (const ActionError& e)
196     {
197         EXPECT_STREQ(e.what(), "ActionError: i2c_compare_bit: { register: "
198                                "0x7C, position: 5, value: 1 }");
199         try
200         {
201             // Re-throw inner I2CException
202             std::rethrow_if_nested(e);
203             ADD_FAILURE() << "Should not have reached this line.";
204         }
205         catch (const i2c::I2CException& ie)
206         {
207             EXPECT_STREQ(
208                 ie.what(),
209                 "I2CException: Failed to read byte: bus /dev/i2c-1, addr 0x70");
210         }
211         catch (...)
212         {
213             ADD_FAILURE() << "Should not have caught exception.";
214         }
215     }
216     catch (...)
217     {
218         ADD_FAILURE() << "Should not have caught exception.";
219     }
220 }
221 
222 TEST(I2CCompareBitActionTests, GetRegister)
223 {
224     I2CCompareBitAction action{0x7C, 5, 1};
225     EXPECT_EQ(action.getRegister(), 0x7C);
226 }
227 
228 TEST(I2CCompareBitActionTests, GetPosition)
229 {
230     I2CCompareBitAction action{0x7C, 5, 1};
231     EXPECT_EQ(action.getPosition(), 5);
232 }
233 
234 TEST(I2CCompareBitActionTests, GetValue)
235 {
236     I2CCompareBitAction action{0x7C, 5, 1};
237     EXPECT_EQ(action.getValue(), 1);
238 }
239 
240 TEST(I2CCompareBitActionTests, ToString)
241 {
242     I2CCompareBitAction action{0x7C, 5, 1};
243     EXPECT_EQ(action.toString(),
244               "i2c_compare_bit: { register: 0x7C, position: 5, value: 1 }");
245 }
246