blob: db3a6a31e0b1f5443bd6c03dcbe095a141b593e5 [file] [log] [blame]
Patrick Williams7ba248a2023-05-10 07:51:30 -05001#include <linux/gpio.h>
2
William A. Kennington IIIf3942f62018-08-17 13:15:38 -07003#include <gpioplus/event.hpp>
4#include <gpioplus/test/sys.hpp>
Patrick Williams7ba248a2023-05-10 07:51:30 -05005
6#include <cerrno>
7#include <cstring>
William A. Kennington IIIf3942f62018-08-17 13:15:38 -07008#include <memory>
9#include <optional>
10#include <stdexcept>
11#include <string>
12#include <system_error>
13
Patrick Williams7ba248a2023-05-10 07:51:30 -050014#include <gmock/gmock.h>
15#include <gtest/gtest.h>
16
William A. Kennington IIIf3942f62018-08-17 13:15:38 -070017namespace gpioplus
18{
19namespace
20{
21
22using testing::Assign;
23using testing::DoAll;
24using testing::Return;
25using testing::SaveArgPointee;
26using testing::SetArgPointee;
27using testing::WithArg;
28
29TEST(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
42class 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
64TEST_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
William A. Kennington III12cd2542018-08-22 21:17:56 -070089TEST_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
William A. Kennington IIIf3942f62018-08-17 13:15:38 -070098TEST_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)));
Patrick Williamsb80c5842024-08-16 15:22:12 -0400110 EXPECT_THROW(Event(*chip, line_offset, handle_flags, event_flags,
111 label.c_str()),
112 std::system_error);
William A. Kennington IIIf3942f62018-08-17 13:15:38 -0700113
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
120class 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
144ACTION_P(WriteStruct, data)
145{
146 memcpy(arg0, &data, sizeof(data));
147}
148
149TEST_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);
William A. Kennington III68cce0f2018-08-27 12:41:31 -0700158 EXPECT_EQ(ret.timestamp, data->timestamp.count());
William A. Kennington IIIf3942f62018-08-17 13:15:38 -0700159 EXPECT_EQ(ret.id, data->id);
160}
161
162TEST_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
169TEST_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
176TEST_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
183TEST_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
192TEST_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