xref: /openbmc/gpioplus/test/event.cpp (revision 15658977)
1 #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 
14 namespace gpioplus
15 {
16 namespace
17 {
18 
19 using testing::Assign;
20 using testing::DoAll;
21 using testing::Return;
22 using testing::SaveArgPointee;
23 using testing::SetArgPointee;
24 using testing::WithArg;
25 
26 TEST(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 
39 class 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 
61 TEST_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 
86 TEST_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 
95 TEST_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 
117 class 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 
141 ACTION_P(WriteStruct, data)
142 {
143     memcpy(arg0, &data, sizeof(data));
144 }
145 
146 TEST_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.count());
156     EXPECT_EQ(ret.id, data->id);
157 }
158 
159 TEST_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 
166 TEST_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 
173 TEST_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 
180 TEST_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 
189 TEST_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
198