blob: a909a990890e0038a9e52158218e54192495db18 [file] [log] [blame]
William A. Kennington III26954bd2018-08-16 17:55:07 -07001#include <fcntl.h>
William A. Kennington III26954bd2018-08-16 17:55:07 -07002#include <signal.h>
3#include <sys/prctl.h>
Patrick Williams7ba248a2023-05-10 07:51:30 -05004
5#include <gpioplus/internal/fd.hpp>
6#include <gpioplus/test/sys.hpp>
7
8#include <cerrno>
9#include <cstring>
10#include <memory>
William A. Kennington III26954bd2018-08-16 17:55:07 -070011#include <system_error>
12#include <type_traits>
13#include <utility>
14
Patrick Williams7ba248a2023-05-10 07:51:30 -050015#include <gmock/gmock.h>
16#include <gtest/gtest.h>
17
William A. Kennington III26954bd2018-08-16 17:55:07 -070018#ifdef HAVE_GCOV
19// Needed for the abrt test
20extern "C" void __gcov_flush(void);
21#endif
22
23namespace gpioplus
24{
25namespace internal
26{
27namespace
28{
29
30using testing::Assign;
31using testing::DoAll;
32using testing::Return;
33
34class FdTest : public testing::Test
35{
36 protected:
37 const int expected_fd = 1234;
38 const int expected_fd2 = 2345;
39 const int expected_fd3 = 3456;
40 testing::StrictMock<test::SysMock> mock;
41 testing::StrictMock<test::SysMock> mock2;
42};
43
44TEST_F(FdTest, ConstructSimple)
45{
46 Fd fd(expected_fd, std::false_type(), &mock);
47 EXPECT_EQ(expected_fd, *fd);
48 EXPECT_EQ(&mock, fd.getSys());
49
50 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0));
51}
52
53TEST_F(FdTest, ConstructSimplBadFd)
54{
55 Fd fd(-1, std::false_type(), &mock);
56 EXPECT_EQ(-1, *fd);
57}
58
59TEST_F(FdTest, ConstructDup)
60{
61 EXPECT_CALL(mock, dup(expected_fd)).WillOnce(Return(expected_fd2));
62 Fd fd(expected_fd, &mock);
63 EXPECT_EQ(expected_fd2, *fd);
64 EXPECT_EQ(&mock, fd.getSys());
65
66 EXPECT_CALL(mock, close(expected_fd2)).WillOnce(Return(0));
67}
68
69TEST_F(FdTest, ConstructDupFail)
70{
71 EXPECT_CALL(mock, dup(expected_fd))
72 .WillOnce(DoAll(Assign(&errno, EINVAL), Return(-1)));
73 EXPECT_THROW(Fd(expected_fd, &mock), std::system_error);
74}
75
76void abrt_handler(int signum)
77{
78 if (signum == SIGABRT)
79 {
80#ifdef HAVE_GCOV
81 __gcov_flush();
82#endif
83 }
84}
85
86TEST_F(FdTest, CloseFails)
87{
88 EXPECT_DEATH(
89 {
90 struct sigaction act;
91 act.sa_handler = abrt_handler;
92 sigemptyset(&act.sa_mask);
93 act.sa_flags = 0;
94 ASSERT_EQ(0, sigaction(SIGABRT, &act, nullptr));
95 ASSERT_EQ(0, prctl(PR_SET_DUMPABLE, 0, 0, 0, 0));
96 EXPECT_CALL(mock, close(expected_fd))
97 .WillOnce(DoAll(Assign(&errno, EINVAL), Return(-1)));
98 Fd(expected_fd, std::false_type(), &mock);
99 },
100 "");
101}
102
103TEST_F(FdTest, ConstructSuccess)
104{
105 const char* path = "/no-such-path/gpio";
106 const int flags = O_RDWR;
107 EXPECT_CALL(mock, open(path, flags)).WillOnce(Return(expected_fd));
108 Fd fd(path, flags, &mock);
109 EXPECT_EQ(expected_fd, *fd);
110 EXPECT_EQ(&mock, fd.getSys());
111
112 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0));
113}
114
115TEST_F(FdTest, ConstructError)
116{
117 const char* path = "/no-such-path/gpio";
118 const int flags = O_RDWR;
119 EXPECT_CALL(mock, open(path, flags))
120 .WillOnce(DoAll(Assign(&errno, EBUSY), Return(-1)));
121 EXPECT_THROW(Fd(path, flags, &mock), std::system_error);
122}
123
124TEST_F(FdTest, ConstructCopy)
125{
126 Fd fd(expected_fd, std::false_type(), &mock);
127 {
128 EXPECT_CALL(mock, dup(expected_fd)).WillOnce(Return(expected_fd2));
129 Fd fd2(fd);
130 EXPECT_EQ(expected_fd2, *fd2);
131 EXPECT_EQ(expected_fd, *fd);
132
133 EXPECT_CALL(mock, close(expected_fd2)).WillOnce(Return(0));
134 }
135
136 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0));
137}
138
139TEST_F(FdTest, OperatorCopySame)
140{
141 Fd fd(expected_fd, std::false_type(), &mock);
142 fd = fd;
143 EXPECT_EQ(expected_fd, *fd);
144
145 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0));
146}
147
148TEST_F(FdTest, OperatorCopy)
149{
150 Fd fd(expected_fd, std::false_type(), &mock);
151 {
152 Fd fd2(expected_fd2, std::false_type(), &mock2);
153 EXPECT_CALL(mock2, close(expected_fd2)).WillOnce(Return(0));
154 EXPECT_CALL(mock, dup(expected_fd)).WillOnce(Return(expected_fd3));
155 fd2 = fd;
156 EXPECT_EQ(expected_fd3, *fd2);
157 EXPECT_EQ(&mock, fd2.getSys());
158 EXPECT_EQ(expected_fd, *fd);
159 EXPECT_EQ(&mock, fd.getSys());
160
161 EXPECT_CALL(mock, close(expected_fd3)).WillOnce(Return(0));
162 }
163
164 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0));
165}
166
167TEST_F(FdTest, ConstructMove)
168{
169 Fd fd(expected_fd, std::false_type(), &mock);
170 {
171 Fd fd2(std::move(fd));
172 EXPECT_EQ(expected_fd, *fd2);
173 EXPECT_EQ(-1, *fd);
174
175 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0));
176 }
177}
178
179TEST_F(FdTest, OperatorMoveSame)
180{
181 Fd fd(expected_fd, std::false_type(), &mock);
182 fd = std::move(fd);
183 EXPECT_EQ(expected_fd, *fd);
184
185 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0));
186}
187
188TEST_F(FdTest, OperatorMove)
189{
190 Fd fd(expected_fd, std::false_type(), &mock);
191 {
192 Fd fd2(expected_fd2, std::false_type(), &mock2);
193 EXPECT_CALL(mock2, close(expected_fd2)).WillOnce(Return(0));
194 fd2 = std::move(fd);
195 EXPECT_EQ(expected_fd, *fd2);
196 EXPECT_EQ(&mock, fd2.getSys());
197 EXPECT_EQ(-1, *fd);
198 EXPECT_EQ(&mock, fd.getSys());
199
200 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0));
201 }
202}
203
204class FdMethodTest : public FdTest
205{
206 protected:
207 const int flags_blocking = O_SYNC | O_NOATIME;
208 const int flags_noblocking = O_NONBLOCK | flags_blocking;
209 std::unique_ptr<Fd> fd;
210
211 void SetUp()
212 {
213 fd = std::make_unique<Fd>(expected_fd, std::false_type(), &mock);
214 }
215
216 void TearDown()
217 {
218 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0));
219 fd.reset();
220 }
221};
222
223TEST_F(FdMethodTest, SetBlockingOnBlocking)
224{
225 EXPECT_CALL(mock, fcntl_getfl(expected_fd))
226 .WillOnce(Return(flags_blocking));
227 EXPECT_CALL(mock, fcntl_setfl(expected_fd, flags_blocking))
228 .WillOnce(Return(0));
229 fd->setBlocking(true);
230}
231
232TEST_F(FdMethodTest, SetBlockingOnNonBlocking)
233{
234 EXPECT_CALL(mock, fcntl_getfl(expected_fd))
235 .WillOnce(Return(flags_noblocking));
236 EXPECT_CALL(mock, fcntl_setfl(expected_fd, flags_blocking))
237 .WillOnce(Return(0));
238 fd->setBlocking(true);
239}
240
241TEST_F(FdMethodTest, SetNonBlockingOnBlocking)
242{
243 EXPECT_CALL(mock, fcntl_getfl(expected_fd))
244 .WillOnce(Return(flags_blocking));
245 EXPECT_CALL(mock, fcntl_setfl(expected_fd, flags_noblocking))
246 .WillOnce(Return(0));
247 fd->setBlocking(false);
248}
249
250TEST_F(FdMethodTest, SetNonBlockingOnNonBlocking)
251{
252 EXPECT_CALL(mock, fcntl_getfl(expected_fd))
253 .WillOnce(Return(flags_noblocking));
254 EXPECT_CALL(mock, fcntl_setfl(expected_fd, flags_noblocking))
255 .WillOnce(Return(0));
256 fd->setBlocking(false);
257}
258
259TEST_F(FdMethodTest, GetFlagsFail)
260{
261 EXPECT_CALL(mock, fcntl_getfl(expected_fd))
262 .WillOnce(DoAll(Assign(&errno, EINVAL), Return(-1)));
263 EXPECT_THROW(fd->setBlocking(true), std::system_error);
264}
265
266TEST_F(FdMethodTest, SetFlagsFail)
267{
268 EXPECT_CALL(mock, fcntl_getfl(expected_fd)).WillOnce(Return(0));
269 EXPECT_CALL(mock, fcntl_setfl(expected_fd, 0))
270 .WillOnce(DoAll(Assign(&errno, EINVAL), Return(-1)));
271 EXPECT_THROW(fd->setBlocking(true), std::system_error);
272}
273
274} // namespace
275} // namespace internal
276} // namespace gpioplus