1 #include <linux/gpio.h> 2 3 #include <gpioplus/event.hpp> 4 #include <gpioplus/test/sys.hpp> 5 6 #include <cerrno> 7 #include <cstring> 8 #include <memory> 9 #include <optional> 10 #include <stdexcept> 11 #include <string> 12 #include <system_error> 13 14 #include <gmock/gmock.h> 15 #include <gtest/gtest.h> 16 17 namespace gpioplus 18 { 19 namespace 20 { 21 22 using testing::Assign; 23 using testing::DoAll; 24 using testing::Return; 25 using testing::SaveArgPointee; 26 using testing::SetArgPointee; 27 using testing::WithArg; 28 29 TEST(EventFlags, EventFlagsToInt) 30 { 31 EventFlags event_flags; 32 event_flags.rising_edge = true; 33 event_flags.falling_edge = true; 34 EXPECT_EQ(GPIOEVENT_REQUEST_RISING_EDGE | GPIOEVENT_REQUEST_FALLING_EDGE, 35 event_flags.toInt()); 36 37 event_flags.rising_edge = false; 38 event_flags.falling_edge = false; 39 EXPECT_EQ(0, event_flags.toInt()); 40 } 41 42 class EventTest : public testing::Test 43 { 44 protected: 45 const int chip_fd = 1234; 46 const int event_fd = 2345; 47 testing::StrictMock<test::SysMock> mock; 48 std::unique_ptr<Chip> chip; 49 50 void SetUp() 51 { 52 EXPECT_CALL(mock, open(testing::_, testing::_)) 53 .WillOnce(Return(chip_fd)); 54 chip = std::make_unique<Chip>(0, &mock); 55 } 56 57 void TearDown() 58 { 59 EXPECT_CALL(mock, close(chip_fd)).WillOnce(Return(0)); 60 chip.reset(); 61 } 62 }; 63 64 TEST_F(EventTest, ConstructSuccess) 65 { 66 const uint32_t line_offset = 3; 67 const std::string label{"test"}; 68 HandleFlags handle_flags(LineFlags(0)); 69 EventFlags event_flags; 70 event_flags.rising_edge = true; 71 event_flags.falling_edge = false; 72 73 struct gpioevent_request req, ret; 74 ret.fd = event_fd; 75 EXPECT_CALL(mock, gpio_get_lineevent(chip_fd, testing::_)) 76 .WillOnce( 77 DoAll(SaveArgPointee<1>(&req), SetArgPointee<1>(ret), Return(0))); 78 Event event(*chip, line_offset, handle_flags, event_flags, label.c_str()); 79 80 EXPECT_EQ(event_fd, *event.getFd()); 81 EXPECT_EQ(line_offset, req.lineoffset); 82 EXPECT_EQ(GPIOHANDLE_REQUEST_INPUT, req.handleflags); 83 EXPECT_EQ(GPIOEVENT_REQUEST_RISING_EDGE, req.eventflags); 84 EXPECT_EQ(label, req.consumer_label); 85 86 EXPECT_CALL(mock, close(event_fd)).WillOnce(Return(0)); 87 } 88 89 TEST_F(EventTest, ConstructLabelTooLong) 90 { 91 const size_t large_size = sizeof( 92 reinterpret_cast<struct gpioevent_request*>(NULL)->consumer_label); 93 EXPECT_THROW(Event(*chip, 0, HandleFlags(), EventFlags(), 94 std::string(large_size, '1')), 95 std::invalid_argument); 96 } 97 98 TEST_F(EventTest, ConstructFailure) 99 { 100 const uint32_t line_offset = 3; 101 const std::string label{"test"}; 102 HandleFlags handle_flags(LineFlags(0)); 103 EventFlags event_flags; 104 event_flags.rising_edge = false; 105 event_flags.falling_edge = false; 106 107 struct gpioevent_request req; 108 EXPECT_CALL(mock, gpio_get_lineevent(chip_fd, testing::_)) 109 .WillOnce(DoAll(SaveArgPointee<1>(&req), Return(-EINVAL))); 110 EXPECT_THROW( 111 Event(*chip, line_offset, handle_flags, event_flags, label.c_str()), 112 std::system_error); 113 114 EXPECT_EQ(line_offset, req.lineoffset); 115 EXPECT_EQ(GPIOHANDLE_REQUEST_INPUT, req.handleflags); 116 EXPECT_EQ(0, req.eventflags); 117 EXPECT_EQ(label, req.consumer_label); 118 } 119 120 class EventMethodTest : public EventTest 121 { 122 protected: 123 std::unique_ptr<Event> event; 124 125 void SetUp() 126 { 127 EventTest::SetUp(); 128 struct gpioevent_request ret; 129 ret.fd = event_fd; 130 EXPECT_CALL(mock, gpio_get_lineevent(chip_fd, testing::_)) 131 .WillOnce(DoAll(SetArgPointee<1>(ret), Return(0))); 132 event = std::make_unique<Event>(*chip, 0, HandleFlags(LineFlags(0)), 133 EventFlags(), "method"); 134 } 135 136 void TearDown() 137 { 138 EXPECT_CALL(mock, close(event_fd)).WillOnce(Return(0)); 139 event.reset(); 140 EventTest::TearDown(); 141 } 142 }; 143 144 ACTION_P(WriteStruct, data) 145 { 146 memcpy(arg0, &data, sizeof(data)); 147 } 148 149 TEST_F(EventMethodTest, ReadSuccess) 150 { 151 struct gpioevent_data ret; 152 ret.timestamp = 5; 153 ret.id = 15; 154 EXPECT_CALL(mock, read(event_fd, testing::_, sizeof(struct gpioevent_data))) 155 .WillOnce(DoAll(WithArg<1>(WriteStruct(ret)), Return(sizeof(ret)))); 156 std::optional<Event::Data> data = event->read(); 157 EXPECT_TRUE(data); 158 EXPECT_EQ(ret.timestamp, data->timestamp.count()); 159 EXPECT_EQ(ret.id, data->id); 160 } 161 162 TEST_F(EventMethodTest, ReadAgain) 163 { 164 EXPECT_CALL(mock, read(event_fd, testing::_, sizeof(struct gpioevent_data))) 165 .WillOnce(DoAll(Assign(&errno, EAGAIN), Return(-1))); 166 EXPECT_EQ(std::nullopt, event->read()); 167 } 168 169 TEST_F(EventMethodTest, ReadFailure) 170 { 171 EXPECT_CALL(mock, read(event_fd, testing::_, sizeof(struct gpioevent_data))) 172 .WillOnce(DoAll(Assign(&errno, EINVAL), Return(-1))); 173 EXPECT_THROW(event->read(), std::system_error); 174 } 175 176 TEST_F(EventMethodTest, ReadTooSmall) 177 { 178 EXPECT_CALL(mock, read(event_fd, testing::_, sizeof(struct gpioevent_data))) 179 .WillOnce(Return(1)); 180 EXPECT_THROW(event->read(), std::runtime_error); 181 } 182 183 TEST_F(EventMethodTest, GetValueSuccess) 184 { 185 struct gpiohandle_data data; 186 data.values[0] = 1; 187 EXPECT_CALL(mock, gpiohandle_get_line_values(event_fd, testing::_)) 188 .WillOnce(DoAll(SetArgPointee<1>(data), Return(0))); 189 EXPECT_EQ(data.values[0], event->getValue()); 190 } 191 192 TEST_F(EventMethodTest, GetValueFailure) 193 { 194 EXPECT_CALL(mock, gpiohandle_get_line_values(event_fd, testing::_)) 195 .WillOnce(Return(-EINVAL)); 196 EXPECT_THROW(event->getValue(), std::system_error); 197 } 198 199 } // namespace 200 } // namespace gpioplus 201