blob: ed627e8c601cb416f2f0aab5a32d3357f72e8d3f [file] [log] [blame]
William A. Kennington IIIf3942f62018-08-17 13:15:38 -07001#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
14namespace gpioplus
15{
16namespace
17{
18
19using testing::Assign;
20using testing::DoAll;
21using testing::Return;
22using testing::SaveArgPointee;
23using testing::SetArgPointee;
24using testing::WithArg;
25
26TEST(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
39class 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
61TEST_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
William A. Kennington III12cd2542018-08-22 21:17:56 -070086TEST_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
William A. Kennington IIIf3942f62018-08-17 13:15:38 -070095TEST_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
117class 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
141ACTION_P(WriteStruct, data)
142{
143 memcpy(arg0, &data, sizeof(data));
144}
145
146TEST_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);
156 EXPECT_EQ(ret.id, data->id);
157}
158
159TEST_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
166TEST_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
173TEST_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
180TEST_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
189TEST_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