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, ConstructError) 115 { 116 const std::string label{"error"}; 117 std::vector<Handle::Line> lines; 118 for (uint32_t i = 0; i < 5; ++i) 119 { 120 lines.push_back({i, 0}); 121 } 122 123 struct gpiohandle_request req; 124 EXPECT_CALL(mock, gpio_get_linehandle(chip_fd, testing::_)) 125 .WillOnce(DoAll(SaveArgPointee<1>(&req), Return(-EINVAL))); 126 EXPECT_THROW(Handle(*chip, lines, 127 HandleFlags(LineFlags(GPIOLINE_FLAG_IS_OUT)), 128 label.c_str()), 129 std::runtime_error); 130 131 EXPECT_EQ(GPIOHANDLE_REQUEST_OUTPUT, req.flags); 132 EXPECT_EQ(label, req.consumer_label); 133 EXPECT_EQ(lines.size(), req.lines); 134 for (uint32_t i = 0; i < lines.size(); ++i) 135 { 136 EXPECT_EQ(i, req.lineoffsets[i]); 137 EXPECT_EQ(0, req.default_values[i]); 138 } 139 } 140 141 class HandleMethodTest : public HandleTest 142 { 143 protected: 144 std::unique_ptr<Handle> handle; 145 const std::vector<Handle::Line> lines{{1, 1}, {4, 0}}; 146 147 void SetUp() 148 { 149 HandleTest::SetUp(); 150 struct gpiohandle_request ret; 151 ret.fd = handle_fd; 152 EXPECT_CALL(mock, gpio_get_linehandle(chip_fd, testing::_)) 153 .WillOnce(DoAll(SetArgPointee<1>(ret), Return(0))); 154 handle = std::make_unique<Handle>( 155 *chip, lines, HandleFlags(LineFlags(GPIOLINE_FLAG_IS_OUT)), 156 "method"); 157 } 158 159 void TearDown() 160 { 161 EXPECT_CALL(mock, close(handle_fd)).WillOnce(Return(0)); 162 handle.reset(); 163 HandleTest::TearDown(); 164 } 165 }; 166 167 TEST_F(HandleMethodTest, GetValuesRet) 168 { 169 const std::vector<uint8_t> expected{0, 0}; 170 struct gpiohandle_data ret; 171 ret.values[0] = 0; 172 ret.values[1] = 0; 173 174 EXPECT_CALL(mock, gpiohandle_get_line_values(handle_fd, testing::_)) 175 .WillOnce(DoAll(SetArgPointee<1>(ret), Return(0))); 176 EXPECT_EQ(expected, handle->getValues()); 177 } 178 179 TEST_F(HandleMethodTest, GetValuesSuccess) 180 { 181 const std::vector<uint8_t> expected{1, 1}; 182 struct gpiohandle_data ret; 183 ret.values[0] = 1; 184 ret.values[1] = 1; 185 186 EXPECT_CALL(mock, gpiohandle_get_line_values(handle_fd, testing::_)) 187 .WillOnce(DoAll(SetArgPointee<1>(ret), Return(0))); 188 std::vector<uint8_t> output; 189 handle->getValues(output); 190 EXPECT_EQ(expected, output); 191 } 192 193 TEST_F(HandleMethodTest, GetValuesFailure) 194 { 195 EXPECT_CALL(mock, gpiohandle_get_line_values(handle_fd, testing::_)) 196 .WillOnce(Return(-EINVAL)); 197 EXPECT_THROW(handle->getValues(), std::system_error); 198 } 199 200 TEST_F(HandleMethodTest, SetValuesSuccess) 201 { 202 struct gpiohandle_data req; 203 EXPECT_CALL(mock, gpiohandle_set_line_values(handle_fd, testing::_)) 204 .WillOnce(DoAll(SaveArgPointee<1>(&req), Return(0))); 205 handle->setValues({0, 1}); 206 EXPECT_EQ(0, req.values[0]); 207 EXPECT_EQ(1, req.values[1]); 208 } 209 210 TEST_F(HandleMethodTest, SetValuesInvalid) 211 { 212 EXPECT_THROW(handle->setValues({1}), std::runtime_error); 213 EXPECT_THROW(handle->setValues({1, 0, 1}), std::runtime_error); 214 } 215 216 TEST_F(HandleMethodTest, SetValuesFailure) 217 { 218 struct gpiohandle_data req; 219 EXPECT_CALL(mock, gpiohandle_set_line_values(handle_fd, testing::_)) 220 .WillOnce(DoAll(SaveArgPointee<1>(&req), Return(-EINVAL))); 221 EXPECT_THROW(handle->setValues({1, 1}), std::system_error); 222 EXPECT_EQ(1, req.values[0]); 223 EXPECT_EQ(1, req.values[1]); 224 } 225 226 } // namespace 227 } // namespace gpioplus 228