#include #include #include #include #include #include #include #include #include #include #include #include namespace gpioplus { namespace { using testing::Assign; using testing::DoAll; using testing::Return; using testing::SaveArgPointee; using testing::SetArgPointee; using testing::WithArg; TEST(EventFlags, EventFlagsToInt) { EventFlags event_flags; event_flags.rising_edge = true; event_flags.falling_edge = true; EXPECT_EQ(GPIOEVENT_REQUEST_RISING_EDGE | GPIOEVENT_REQUEST_FALLING_EDGE, event_flags.toInt()); event_flags.rising_edge = false; event_flags.falling_edge = false; EXPECT_EQ(0, event_flags.toInt()); } class EventTest : public testing::Test { protected: const int chip_fd = 1234; const int event_fd = 2345; testing::StrictMock mock; std::unique_ptr chip; void SetUp() { EXPECT_CALL(mock, open(testing::_, testing::_)) .WillOnce(Return(chip_fd)); chip = std::make_unique(0, &mock); } void TearDown() { EXPECT_CALL(mock, close(chip_fd)).WillOnce(Return(0)); chip.reset(); } }; TEST_F(EventTest, ConstructSuccess) { const uint32_t line_offset = 3; const std::string label{"test"}; HandleFlags handle_flags(LineFlags(0)); EventFlags event_flags; event_flags.rising_edge = true; event_flags.falling_edge = false; struct gpioevent_request req, ret; ret.fd = event_fd; EXPECT_CALL(mock, gpio_get_lineevent(chip_fd, testing::_)) .WillOnce( DoAll(SaveArgPointee<1>(&req), SetArgPointee<1>(ret), Return(0))); Event event(*chip, line_offset, handle_flags, event_flags, label.c_str()); EXPECT_EQ(event_fd, *event.getFd()); EXPECT_EQ(line_offset, req.lineoffset); EXPECT_EQ(GPIOHANDLE_REQUEST_INPUT, req.handleflags); EXPECT_EQ(GPIOEVENT_REQUEST_RISING_EDGE, req.eventflags); EXPECT_EQ(label, req.consumer_label); EXPECT_CALL(mock, close(event_fd)).WillOnce(Return(0)); } TEST_F(EventTest, ConstructLabelTooLong) { const size_t large_size = sizeof( reinterpret_cast(NULL)->consumer_label); EXPECT_THROW(Event(*chip, 0, HandleFlags(), EventFlags(), std::string(large_size, '1')), std::invalid_argument); } TEST_F(EventTest, ConstructFailure) { const uint32_t line_offset = 3; const std::string label{"test"}; HandleFlags handle_flags(LineFlags(0)); EventFlags event_flags; event_flags.rising_edge = false; event_flags.falling_edge = false; struct gpioevent_request req; EXPECT_CALL(mock, gpio_get_lineevent(chip_fd, testing::_)) .WillOnce(DoAll(SaveArgPointee<1>(&req), Return(-EINVAL))); EXPECT_THROW(Event(*chip, line_offset, handle_flags, event_flags, label.c_str()), std::system_error); EXPECT_EQ(line_offset, req.lineoffset); EXPECT_EQ(GPIOHANDLE_REQUEST_INPUT, req.handleflags); EXPECT_EQ(0, req.eventflags); EXPECT_EQ(label, req.consumer_label); } class EventMethodTest : public EventTest { protected: std::unique_ptr event; void SetUp() { EventTest::SetUp(); struct gpioevent_request ret; ret.fd = event_fd; EXPECT_CALL(mock, gpio_get_lineevent(chip_fd, testing::_)) .WillOnce(DoAll(SetArgPointee<1>(ret), Return(0))); event = std::make_unique(*chip, 0, HandleFlags(LineFlags(0)), EventFlags(), "method"); } void TearDown() { EXPECT_CALL(mock, close(event_fd)).WillOnce(Return(0)); event.reset(); EventTest::TearDown(); } }; ACTION_P(WriteStruct, data) { memcpy(arg0, &data, sizeof(data)); } TEST_F(EventMethodTest, ReadSuccess) { struct gpioevent_data ret; ret.timestamp = 5; ret.id = 15; EXPECT_CALL(mock, read(event_fd, testing::_, sizeof(struct gpioevent_data))) .WillOnce(DoAll(WithArg<1>(WriteStruct(ret)), Return(sizeof(ret)))); std::optional data = event->read(); EXPECT_TRUE(data); EXPECT_EQ(ret.timestamp, data->timestamp.count()); EXPECT_EQ(ret.id, data->id); } TEST_F(EventMethodTest, ReadAgain) { EXPECT_CALL(mock, read(event_fd, testing::_, sizeof(struct gpioevent_data))) .WillOnce(DoAll(Assign(&errno, EAGAIN), Return(-1))); EXPECT_EQ(std::nullopt, event->read()); } TEST_F(EventMethodTest, ReadFailure) { EXPECT_CALL(mock, read(event_fd, testing::_, sizeof(struct gpioevent_data))) .WillOnce(DoAll(Assign(&errno, EINVAL), Return(-1))); EXPECT_THROW(event->read(), std::system_error); } TEST_F(EventMethodTest, ReadTooSmall) { EXPECT_CALL(mock, read(event_fd, testing::_, sizeof(struct gpioevent_data))) .WillOnce(Return(1)); EXPECT_THROW(event->read(), std::runtime_error); } TEST_F(EventMethodTest, GetValueSuccess) { struct gpiohandle_data data; data.values[0] = 1; EXPECT_CALL(mock, gpiohandle_get_line_values(event_fd, testing::_)) .WillOnce(DoAll(SetArgPointee<1>(data), Return(0))); EXPECT_EQ(data.values[0], event->getValue()); } TEST_F(EventMethodTest, GetValueFailure) { EXPECT_CALL(mock, gpiohandle_get_line_values(event_fd, testing::_)) .WillOnce(Return(-EINVAL)); EXPECT_THROW(event->getValue(), std::system_error); } } // namespace } // namespace gpioplus