xref: /openbmc/gpioplus/test/event.cpp (revision b80c584e)
1 #include <linux/gpio.h>
2 
3 #include <gpioplus/event.hpp>
4 #include <gpioplus/test/sys.hpp>
5 
6 #include <cerrno>
7 #include <cstring>
8 #include <memory>
9 #include <optional>
10 #include <stdexcept>
11 #include <string>
12 #include <system_error>
13 
14 #include <gmock/gmock.h>
15 #include <gtest/gtest.h>
16 
17 namespace gpioplus
18 {
19 namespace
20 {
21 
22 using testing::Assign;
23 using testing::DoAll;
24 using testing::Return;
25 using testing::SaveArgPointee;
26 using testing::SetArgPointee;
27 using testing::WithArg;
28 
TEST(EventFlags,EventFlagsToInt)29 TEST(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 
42 class 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 
SetUp()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 
TearDown()57     void TearDown()
58     {
59         EXPECT_CALL(mock, close(chip_fd)).WillOnce(Return(0));
60         chip.reset();
61     }
62 };
63 
TEST_F(EventTest,ConstructSuccess)64 TEST_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 
TEST_F(EventTest,ConstructLabelTooLong)89 TEST_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 
TEST_F(EventTest,ConstructFailure)98 TEST_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)));
110     EXPECT_THROW(Event(*chip, line_offset, handle_flags, event_flags,
111                        label.c_str()),
112                  std::system_error);
113 
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 
120 class EventMethodTest : public EventTest
121 {
122   protected:
123     std::unique_ptr<Event> event;
124 
SetUp()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 
TearDown()136     void TearDown()
137     {
138         EXPECT_CALL(mock, close(event_fd)).WillOnce(Return(0));
139         event.reset();
140         EventTest::TearDown();
141     }
142 };
143 
ACTION_P(WriteStruct,data)144 ACTION_P(WriteStruct, data)
145 {
146     memcpy(arg0, &data, sizeof(data));
147 }
148 
TEST_F(EventMethodTest,ReadSuccess)149 TEST_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);
158     EXPECT_EQ(ret.timestamp, data->timestamp.count());
159     EXPECT_EQ(ret.id, data->id);
160 }
161 
TEST_F(EventMethodTest,ReadAgain)162 TEST_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 
TEST_F(EventMethodTest,ReadFailure)169 TEST_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 
TEST_F(EventMethodTest,ReadTooSmall)176 TEST_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 
TEST_F(EventMethodTest,GetValueSuccess)183 TEST_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 
TEST_F(EventMethodTest,GetValueFailure)192 TEST_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
201