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