1 #include <cerrno> 2 #include <cstdint> 3 #include <gmock/gmock.h> 4 #include <gpioplus/handle.hpp> 5 #include <gpioplus/test/sys.hpp> 6 #include <gtest/gtest.h> 7 #include <linux/gpio.h> 8 #include <memory> 9 #include <stdexcept> 10 #include <string> 11 #include <system_error> 12 #include <vector> 13 14 namespace gpioplus 15 { 16 namespace 17 { 18 19 using testing::DoAll; 20 using testing::Return; 21 using testing::SaveArgPointee; 22 using testing::SetArgPointee; 23 24 TEST(HandleFlags, HandleFlagsFromLineFlags) 25 { 26 LineFlags line_flags(GPIOLINE_FLAG_KERNEL | GPIOLINE_FLAG_OPEN_DRAIN); 27 HandleFlags handle_flags(line_flags); 28 EXPECT_FALSE(handle_flags.output); 29 EXPECT_FALSE(handle_flags.active_low); 30 EXPECT_TRUE(handle_flags.open_drain); 31 EXPECT_FALSE(handle_flags.open_source); 32 } 33 34 TEST(HandleFlags, HandleFlagsToInt) 35 { 36 HandleFlags handle_flags; 37 handle_flags.output = false; 38 handle_flags.active_low = true; 39 handle_flags.open_drain = false; 40 handle_flags.open_source = false; 41 EXPECT_EQ(GPIOHANDLE_REQUEST_INPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW, 42 handle_flags.toInt()); 43 44 handle_flags.output = true; 45 handle_flags.active_low = false; 46 handle_flags.open_drain = true; 47 handle_flags.open_source = true; 48 EXPECT_EQ(GPIOHANDLE_REQUEST_OUTPUT | GPIOHANDLE_REQUEST_OPEN_DRAIN | 49 GPIOHANDLE_REQUEST_OPEN_SOURCE, 50 handle_flags.toInt()); 51 } 52 53 class HandleTest : public testing::Test 54 { 55 protected: 56 const int chip_fd = 1234; 57 const int handle_fd = 2345; 58 testing::StrictMock<test::SysMock> mock; 59 std::unique_ptr<Chip> chip; 60 61 void SetUp() 62 { 63 EXPECT_CALL(mock, open(testing::_, testing::_)) 64 .WillOnce(Return(chip_fd)); 65 chip = std::make_unique<Chip>(0, &mock); 66 } 67 68 void TearDown() 69 { 70 EXPECT_CALL(mock, close(chip_fd)).WillOnce(Return(0)); 71 chip.reset(); 72 } 73 }; 74 75 TEST_F(HandleTest, ConstructSuccess) 76 { 77 const std::string label{"test"}; 78 std::vector<Handle::Line> lines; 79 for (uint32_t i = 0; i < 7; ++i) 80 { 81 lines.push_back({i, 1}); 82 } 83 84 struct gpiohandle_request req, ret; 85 ret.fd = handle_fd; 86 EXPECT_CALL(mock, gpio_get_linehandle(chip_fd, testing::_)) 87 .WillOnce( 88 DoAll(SaveArgPointee<1>(&req), SetArgPointee<1>(ret), Return(0))); 89 Handle handle(*chip, lines, 90 HandleFlags(LineFlags(GPIOLINE_FLAG_ACTIVE_LOW)), 91 label.c_str()); 92 93 EXPECT_EQ(handle_fd, *handle.getFd()); 94 EXPECT_EQ(GPIOHANDLE_REQUEST_INPUT | GPIOHANDLE_REQUEST_ACTIVE_LOW, 95 req.flags); 96 EXPECT_EQ(label, req.consumer_label); 97 EXPECT_EQ(lines.size(), req.lines); 98 for (uint32_t i = 0; i < lines.size(); ++i) 99 { 100 EXPECT_EQ(i, req.lineoffsets[i]); 101 EXPECT_EQ(1, req.default_values[i]); 102 } 103 104 EXPECT_CALL(mock, close(handle_fd)).WillOnce(Return(0)); 105 } 106 107 TEST_F(HandleTest, ConstructTooMany) 108 { 109 const std::vector<Handle::Line> lines(GPIOHANDLES_MAX + 1); 110 EXPECT_THROW(Handle(*chip, lines, HandleFlags(), "too_many"), 111 std::runtime_error); 112 } 113 114 TEST_F(HandleTest, ConstructLabelTooLong) 115 { 116 const size_t large_size = sizeof( 117 reinterpret_cast<struct gpiohandle_request*>(NULL)->consumer_label); 118 EXPECT_THROW(Handle(*chip, {}, HandleFlags(), std::string(large_size, '1')), 119 std::invalid_argument); 120 } 121 122 TEST_F(HandleTest, ConstructError) 123 { 124 const std::string label{"error"}; 125 std::vector<Handle::Line> lines; 126 for (uint32_t i = 0; i < 5; ++i) 127 { 128 lines.push_back({i, 0}); 129 } 130 131 struct gpiohandle_request req; 132 EXPECT_CALL(mock, gpio_get_linehandle(chip_fd, testing::_)) 133 .WillOnce(DoAll(SaveArgPointee<1>(&req), Return(-EINVAL))); 134 EXPECT_THROW(Handle(*chip, lines, 135 HandleFlags(LineFlags(GPIOLINE_FLAG_IS_OUT)), 136 label.c_str()), 137 std::runtime_error); 138 139 EXPECT_EQ(GPIOHANDLE_REQUEST_OUTPUT, req.flags); 140 EXPECT_EQ(label, req.consumer_label); 141 EXPECT_EQ(lines.size(), req.lines); 142 for (uint32_t i = 0; i < lines.size(); ++i) 143 { 144 EXPECT_EQ(i, req.lineoffsets[i]); 145 EXPECT_EQ(0, req.default_values[i]); 146 } 147 } 148 149 class HandleMethodTest : public HandleTest 150 { 151 protected: 152 std::unique_ptr<Handle> handle; 153 const std::vector<Handle::Line> lines{{1, 1}, {4, 0}}; 154 155 void SetUp() 156 { 157 HandleTest::SetUp(); 158 struct gpiohandle_request ret; 159 ret.fd = handle_fd; 160 EXPECT_CALL(mock, gpio_get_linehandle(chip_fd, testing::_)) 161 .WillOnce(DoAll(SetArgPointee<1>(ret), Return(0))); 162 handle = std::make_unique<Handle>( 163 *chip, lines, HandleFlags(LineFlags(GPIOLINE_FLAG_IS_OUT)), 164 "method"); 165 } 166 167 void TearDown() 168 { 169 EXPECT_CALL(mock, close(handle_fd)).WillOnce(Return(0)); 170 handle.reset(); 171 HandleTest::TearDown(); 172 } 173 }; 174 175 TEST_F(HandleMethodTest, GetValuesRet) 176 { 177 const std::vector<uint8_t> expected{0, 0}; 178 struct gpiohandle_data ret; 179 ret.values[0] = 0; 180 ret.values[1] = 0; 181 182 EXPECT_CALL(mock, gpiohandle_get_line_values(handle_fd, testing::_)) 183 .WillOnce(DoAll(SetArgPointee<1>(ret), Return(0))); 184 EXPECT_EQ(expected, handle->getValues()); 185 } 186 187 TEST_F(HandleMethodTest, GetValuesSuccess) 188 { 189 const std::vector<uint8_t> expected{1, 1}; 190 struct gpiohandle_data ret; 191 ret.values[0] = 1; 192 ret.values[1] = 1; 193 194 EXPECT_CALL(mock, gpiohandle_get_line_values(handle_fd, testing::_)) 195 .WillOnce(DoAll(SetArgPointee<1>(ret), Return(0))); 196 std::vector<uint8_t> output; 197 handle->getValues(output); 198 EXPECT_EQ(expected, output); 199 } 200 201 TEST_F(HandleMethodTest, GetValuesFailure) 202 { 203 EXPECT_CALL(mock, gpiohandle_get_line_values(handle_fd, testing::_)) 204 .WillOnce(Return(-EINVAL)); 205 EXPECT_THROW(handle->getValues(), std::system_error); 206 } 207 208 TEST_F(HandleMethodTest, SetValuesSuccess) 209 { 210 struct gpiohandle_data req; 211 EXPECT_CALL(mock, gpiohandle_set_line_values(handle_fd, testing::_)) 212 .WillOnce(DoAll(SaveArgPointee<1>(&req), Return(0))); 213 handle->setValues({0, 1}); 214 EXPECT_EQ(0, req.values[0]); 215 EXPECT_EQ(1, req.values[1]); 216 } 217 218 TEST_F(HandleMethodTest, SetValuesInvalid) 219 { 220 EXPECT_THROW(handle->setValues({1}), std::runtime_error); 221 EXPECT_THROW(handle->setValues({1, 0, 1}), std::runtime_error); 222 } 223 224 TEST_F(HandleMethodTest, SetValuesFailure) 225 { 226 struct gpiohandle_data req; 227 EXPECT_CALL(mock, gpiohandle_set_line_values(handle_fd, testing::_)) 228 .WillOnce(DoAll(SaveArgPointee<1>(&req), Return(-EINVAL))); 229 EXPECT_THROW(handle->setValues({1, 1}), std::system_error); 230 EXPECT_EQ(1, req.values[0]); 231 EXPECT_EQ(1, req.values[1]); 232 } 233 234 } // namespace 235 } // namespace gpioplus 236