1*b38da99fSShawn McCarney /**
2*b38da99fSShawn McCarney  * Copyright © 2020 IBM Corporation
3*b38da99fSShawn McCarney  *
4*b38da99fSShawn McCarney  * Licensed under the Apache License, Version 2.0 (the "License");
5*b38da99fSShawn McCarney  * you may not use this file except in compliance with the License.
6*b38da99fSShawn McCarney  * You may obtain a copy of the License at
7*b38da99fSShawn McCarney  *
8*b38da99fSShawn McCarney  *     http://www.apache.org/licenses/LICENSE-2.0
9*b38da99fSShawn McCarney  *
10*b38da99fSShawn McCarney  * Unless required by applicable law or agreed to in writing, software
11*b38da99fSShawn McCarney  * distributed under the License is distributed on an "AS IS" BASIS,
12*b38da99fSShawn McCarney  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*b38da99fSShawn McCarney  * See the License for the specific language governing permissions and
14*b38da99fSShawn McCarney  * limitations under the License.
15*b38da99fSShawn McCarney  */
16*b38da99fSShawn McCarney #include "action_environment.hpp"
17*b38da99fSShawn McCarney #include "device.hpp"
18*b38da99fSShawn McCarney #include "i2c_action.hpp"
19*b38da99fSShawn McCarney #include "i2c_interface.hpp"
20*b38da99fSShawn McCarney #include "id_map.hpp"
21*b38da99fSShawn McCarney #include "mocked_i2c_interface.hpp"
22*b38da99fSShawn McCarney 
23*b38da99fSShawn McCarney #include <memory>
24*b38da99fSShawn McCarney #include <stdexcept>
25*b38da99fSShawn McCarney #include <string>
26*b38da99fSShawn McCarney #include <utility>
27*b38da99fSShawn McCarney 
28*b38da99fSShawn McCarney #include <gmock/gmock.h>
29*b38da99fSShawn McCarney #include <gtest/gtest.h>
30*b38da99fSShawn McCarney 
31*b38da99fSShawn McCarney using namespace phosphor::power::regulators;
32*b38da99fSShawn McCarney 
33*b38da99fSShawn McCarney using ::testing::Return;
34*b38da99fSShawn McCarney using ::testing::Throw;
35*b38da99fSShawn McCarney 
36*b38da99fSShawn McCarney /**
37*b38da99fSShawn McCarney  * Define a test implementation of the I2CAction abstract base class.
38*b38da99fSShawn McCarney  */
39*b38da99fSShawn McCarney class I2CActionImpl : public I2CAction
40*b38da99fSShawn McCarney {
41*b38da99fSShawn McCarney   public:
42*b38da99fSShawn McCarney     virtual bool execute(ActionEnvironment& /* environment */) override
43*b38da99fSShawn McCarney     {
44*b38da99fSShawn McCarney         return true;
45*b38da99fSShawn McCarney     }
46*b38da99fSShawn McCarney 
47*b38da99fSShawn McCarney     virtual std::string toString() const override
48*b38da99fSShawn McCarney     {
49*b38da99fSShawn McCarney         return "i2c_action_impl: {}";
50*b38da99fSShawn McCarney     }
51*b38da99fSShawn McCarney 
52*b38da99fSShawn McCarney     // Make test a friend so it can access protected getI2CInterface() method
53*b38da99fSShawn McCarney     FRIEND_TEST(I2CActionTests, GetI2CInterface);
54*b38da99fSShawn McCarney };
55*b38da99fSShawn McCarney 
56*b38da99fSShawn McCarney TEST(I2CActionTests, GetI2CInterface)
57*b38da99fSShawn McCarney {
58*b38da99fSShawn McCarney     // Test where works: device was not open
59*b38da99fSShawn McCarney     try
60*b38da99fSShawn McCarney     {
61*b38da99fSShawn McCarney         // Create mock I2CInterface
62*b38da99fSShawn McCarney         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
63*b38da99fSShawn McCarney             std::make_unique<i2c::MockedI2CInterface>();
64*b38da99fSShawn McCarney         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(false));
65*b38da99fSShawn McCarney         EXPECT_CALL(*i2cInterface, open).Times(1);
66*b38da99fSShawn McCarney 
67*b38da99fSShawn McCarney         // Create Device, IDMap, ActionEnvironment, and I2CAction
68*b38da99fSShawn McCarney         Device device{"reg1", true, "/system/chassis/motherboard/reg1",
69*b38da99fSShawn McCarney                       std::move(i2cInterface)};
70*b38da99fSShawn McCarney         IDMap idMap{};
71*b38da99fSShawn McCarney         idMap.addDevice(device);
72*b38da99fSShawn McCarney         ActionEnvironment env{idMap, "reg1"};
73*b38da99fSShawn McCarney         I2CActionImpl action{};
74*b38da99fSShawn McCarney 
75*b38da99fSShawn McCarney         // Get I2CInterface.  Should succeed without an exception.
76*b38da99fSShawn McCarney         action.getI2CInterface(env);
77*b38da99fSShawn McCarney     }
78*b38da99fSShawn McCarney     catch (...)
79*b38da99fSShawn McCarney     {
80*b38da99fSShawn McCarney         ADD_FAILURE() << "Should not have caught exception.";
81*b38da99fSShawn McCarney     }
82*b38da99fSShawn McCarney 
83*b38da99fSShawn McCarney     // Test where works: device was already open
84*b38da99fSShawn McCarney     try
85*b38da99fSShawn McCarney     {
86*b38da99fSShawn McCarney         // Create mock I2CInterface
87*b38da99fSShawn McCarney         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
88*b38da99fSShawn McCarney             std::make_unique<i2c::MockedI2CInterface>();
89*b38da99fSShawn McCarney         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(true));
90*b38da99fSShawn McCarney         EXPECT_CALL(*i2cInterface, open).Times(0);
91*b38da99fSShawn McCarney 
92*b38da99fSShawn McCarney         // Create Device, IDMap, ActionEnvironment, and I2CAction
93*b38da99fSShawn McCarney         Device device{"reg1", true, "/system/chassis/motherboard/reg1",
94*b38da99fSShawn McCarney                       std::move(i2cInterface)};
95*b38da99fSShawn McCarney         IDMap idMap{};
96*b38da99fSShawn McCarney         idMap.addDevice(device);
97*b38da99fSShawn McCarney         ActionEnvironment env{idMap, "reg1"};
98*b38da99fSShawn McCarney         I2CActionImpl action{};
99*b38da99fSShawn McCarney 
100*b38da99fSShawn McCarney         // Get I2CInterface.  Should succeed without an exception.
101*b38da99fSShawn McCarney         action.getI2CInterface(env);
102*b38da99fSShawn McCarney     }
103*b38da99fSShawn McCarney     catch (...)
104*b38da99fSShawn McCarney     {
105*b38da99fSShawn McCarney         ADD_FAILURE() << "Should not have caught exception.";
106*b38da99fSShawn McCarney     }
107*b38da99fSShawn McCarney 
108*b38da99fSShawn McCarney     // Test where fails: getting current device fails
109*b38da99fSShawn McCarney     try
110*b38da99fSShawn McCarney     {
111*b38da99fSShawn McCarney         // Create IDMap, ActionEnvironment, and I2CAction
112*b38da99fSShawn McCarney         IDMap idMap{};
113*b38da99fSShawn McCarney         ActionEnvironment env{idMap, "reg1"};
114*b38da99fSShawn McCarney         I2CActionImpl action{};
115*b38da99fSShawn McCarney 
116*b38da99fSShawn McCarney         // Get I2CInterface.  Should throw an exception since "reg1" is not a
117*b38da99fSShawn McCarney         // valid device in the IDMap.
118*b38da99fSShawn McCarney         action.getI2CInterface(env);
119*b38da99fSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
120*b38da99fSShawn McCarney     }
121*b38da99fSShawn McCarney     catch (const std::invalid_argument& e)
122*b38da99fSShawn McCarney     {
123*b38da99fSShawn McCarney         EXPECT_STREQ(e.what(), "Unable to find device with ID \"reg1\"");
124*b38da99fSShawn McCarney     }
125*b38da99fSShawn McCarney     catch (...)
126*b38da99fSShawn McCarney     {
127*b38da99fSShawn McCarney         ADD_FAILURE() << "Should not have caught exception.";
128*b38da99fSShawn McCarney     }
129*b38da99fSShawn McCarney 
130*b38da99fSShawn McCarney     // Test where fails: opening interface fails
131*b38da99fSShawn McCarney     try
132*b38da99fSShawn McCarney     {
133*b38da99fSShawn McCarney         // Create mock I2CInterface
134*b38da99fSShawn McCarney         std::unique_ptr<i2c::MockedI2CInterface> i2cInterface =
135*b38da99fSShawn McCarney             std::make_unique<i2c::MockedI2CInterface>();
136*b38da99fSShawn McCarney         EXPECT_CALL(*i2cInterface, isOpen).Times(1).WillOnce(Return(false));
137*b38da99fSShawn McCarney         EXPECT_CALL(*i2cInterface, open)
138*b38da99fSShawn McCarney             .Times(1)
139*b38da99fSShawn McCarney             .WillOnce(
140*b38da99fSShawn McCarney                 Throw(i2c::I2CException{"Failed to open", "/dev/i2c-1", 0x70}));
141*b38da99fSShawn McCarney 
142*b38da99fSShawn McCarney         // Create Device, IDMap, ActionEnvironment, and I2CAction
143*b38da99fSShawn McCarney         Device device{"reg1", true, "/system/chassis/motherboard/reg1",
144*b38da99fSShawn McCarney                       std::move(i2cInterface)};
145*b38da99fSShawn McCarney         IDMap idMap{};
146*b38da99fSShawn McCarney         idMap.addDevice(device);
147*b38da99fSShawn McCarney         ActionEnvironment env{idMap, "reg1"};
148*b38da99fSShawn McCarney         I2CActionImpl action{};
149*b38da99fSShawn McCarney 
150*b38da99fSShawn McCarney         // Get I2CInterface.  Should throw an exception from the open() call.
151*b38da99fSShawn McCarney         action.getI2CInterface(env);
152*b38da99fSShawn McCarney         ADD_FAILURE() << "Should not have reached this line.";
153*b38da99fSShawn McCarney     }
154*b38da99fSShawn McCarney     catch (const i2c::I2CException& e)
155*b38da99fSShawn McCarney     {
156*b38da99fSShawn McCarney         EXPECT_STREQ(e.what(),
157*b38da99fSShawn McCarney                      "I2CException: Failed to open: bus /dev/i2c-1, addr 0x70");
158*b38da99fSShawn McCarney     }
159*b38da99fSShawn McCarney     catch (...)
160*b38da99fSShawn McCarney     {
161*b38da99fSShawn McCarney         ADD_FAILURE() << "Should not have caught exception.";
162*b38da99fSShawn McCarney     }
163*b38da99fSShawn McCarney }
164