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, ConstructLabelTooLong) 87 { 88 const size_t large_size = sizeof( 89 reinterpret_cast<struct gpioevent_request*>(NULL)->consumer_label); 90 EXPECT_THROW(Event(*chip, 0, HandleFlags(), EventFlags(), 91 std::string(large_size, '1')), 92 std::invalid_argument); 93 } 94 95 TEST_F(EventTest, ConstructFailure) 96 { 97 const uint32_t line_offset = 3; 98 const std::string label{"test"}; 99 HandleFlags handle_flags(LineFlags(0)); 100 EventFlags event_flags; 101 event_flags.rising_edge = false; 102 event_flags.falling_edge = false; 103 104 struct gpioevent_request req; 105 EXPECT_CALL(mock, gpio_get_lineevent(chip_fd, testing::_)) 106 .WillOnce(DoAll(SaveArgPointee<1>(&req), Return(-EINVAL))); 107 EXPECT_THROW( 108 Event(*chip, line_offset, handle_flags, event_flags, label.c_str()), 109 std::system_error); 110 111 EXPECT_EQ(line_offset, req.lineoffset); 112 EXPECT_EQ(GPIOHANDLE_REQUEST_INPUT, req.handleflags); 113 EXPECT_EQ(0, req.eventflags); 114 EXPECT_EQ(label, req.consumer_label); 115 } 116 117 class EventMethodTest : public EventTest 118 { 119 protected: 120 std::unique_ptr<Event> event; 121 122 void SetUp() 123 { 124 EventTest::SetUp(); 125 struct gpioevent_request ret; 126 ret.fd = event_fd; 127 EXPECT_CALL(mock, gpio_get_lineevent(chip_fd, testing::_)) 128 .WillOnce(DoAll(SetArgPointee<1>(ret), Return(0))); 129 event = std::make_unique<Event>(*chip, 0, HandleFlags(LineFlags(0)), 130 EventFlags(), "method"); 131 } 132 133 void TearDown() 134 { 135 EXPECT_CALL(mock, close(event_fd)).WillOnce(Return(0)); 136 event.reset(); 137 EventTest::TearDown(); 138 } 139 }; 140 141 ACTION_P(WriteStruct, data) 142 { 143 memcpy(arg0, &data, sizeof(data)); 144 } 145 146 TEST_F(EventMethodTest, ReadSuccess) 147 { 148 struct gpioevent_data ret; 149 ret.timestamp = 5; 150 ret.id = 15; 151 EXPECT_CALL(mock, read(event_fd, testing::_, sizeof(struct gpioevent_data))) 152 .WillOnce(DoAll(WithArg<1>(WriteStruct(ret)), Return(sizeof(ret)))); 153 std::optional<Event::Data> data = event->read(); 154 EXPECT_TRUE(data); 155 EXPECT_EQ(ret.timestamp, data->timestamp.count()); 156 EXPECT_EQ(ret.id, data->id); 157 } 158 159 TEST_F(EventMethodTest, ReadAgain) 160 { 161 EXPECT_CALL(mock, read(event_fd, testing::_, sizeof(struct gpioevent_data))) 162 .WillOnce(DoAll(Assign(&errno, EAGAIN), Return(-1))); 163 EXPECT_EQ(std::nullopt, event->read()); 164 } 165 166 TEST_F(EventMethodTest, ReadFailure) 167 { 168 EXPECT_CALL(mock, read(event_fd, testing::_, sizeof(struct gpioevent_data))) 169 .WillOnce(DoAll(Assign(&errno, EINVAL), Return(-1))); 170 EXPECT_THROW(event->read(), std::system_error); 171 } 172 173 TEST_F(EventMethodTest, ReadTooSmall) 174 { 175 EXPECT_CALL(mock, read(event_fd, testing::_, sizeof(struct gpioevent_data))) 176 .WillOnce(Return(1)); 177 EXPECT_THROW(event->read(), std::runtime_error); 178 } 179 180 TEST_F(EventMethodTest, GetValueSuccess) 181 { 182 struct gpiohandle_data data; 183 data.values[0] = 1; 184 EXPECT_CALL(mock, gpiohandle_get_line_values(event_fd, testing::_)) 185 .WillOnce(DoAll(SetArgPointee<1>(data), Return(0))); 186 EXPECT_EQ(data.values[0], event->getValue()); 187 } 188 189 TEST_F(EventMethodTest, GetValueFailure) 190 { 191 EXPECT_CALL(mock, gpiohandle_get_line_values(event_fd, testing::_)) 192 .WillOnce(Return(-EINVAL)); 193 EXPECT_THROW(event->getValue(), std::system_error); 194 } 195 196 } // namespace 197 } // namespace gpioplus 198