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 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 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 258 TEST(I2CCompareByteActionTests, GetRegister) 259 { 260 I2CCompareByteAction action{0x7C, 0xDE}; 261 EXPECT_EQ(action.getRegister(), 0x7C); 262 } 263 264 TEST(I2CCompareByteActionTests, GetValue) 265 { 266 I2CCompareByteAction action{0xA0, 0x03, 0x47}; 267 EXPECT_EQ(action.getValue(), 0x03); 268 } 269 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 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