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