blob: fa2337ee851c6e3c3e913cf5365e049bc546c931 [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
86TEST_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
108class 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
132ACTION_P(WriteStruct, data)
133{
134 memcpy(arg0, &data, sizeof(data));
135}
136
137TEST_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
150TEST_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
157TEST_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
164TEST_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
171TEST_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
180TEST_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