blob: 78ee457e26f822bb64466cb22ad59cb1c04ef66b [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);
Patrick Williamsab995c52023-07-12 15:43:52 -0500182 // Test move operator but newer compilers complain about move-to-self
183 // so use an explicit r-value ref cast to do the same.
184 fd = static_cast<Fd&&>(fd);
William A. Kennington III26954bd2018-08-16 17:55:07 -0700185 EXPECT_EQ(expected_fd, *fd);
186
187 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0));
188}
189
190TEST_F(FdTest, OperatorMove)
191{
192 Fd fd(expected_fd, std::false_type(), &mock);
193 {
194 Fd fd2(expected_fd2, std::false_type(), &mock2);
195 EXPECT_CALL(mock2, close(expected_fd2)).WillOnce(Return(0));
196 fd2 = std::move(fd);
197 EXPECT_EQ(expected_fd, *fd2);
198 EXPECT_EQ(&mock, fd2.getSys());
199 EXPECT_EQ(-1, *fd);
200 EXPECT_EQ(&mock, fd.getSys());
201
202 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0));
203 }
204}
205
206class FdMethodTest : public FdTest
207{
208 protected:
209 const int flags_blocking = O_SYNC | O_NOATIME;
210 const int flags_noblocking = O_NONBLOCK | flags_blocking;
211 std::unique_ptr<Fd> fd;
212
213 void SetUp()
214 {
215 fd = std::make_unique<Fd>(expected_fd, std::false_type(), &mock);
216 }
217
218 void TearDown()
219 {
220 EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0));
221 fd.reset();
222 }
223};
224
225TEST_F(FdMethodTest, SetBlockingOnBlocking)
226{
227 EXPECT_CALL(mock, fcntl_getfl(expected_fd))
228 .WillOnce(Return(flags_blocking));
229 EXPECT_CALL(mock, fcntl_setfl(expected_fd, flags_blocking))
230 .WillOnce(Return(0));
231 fd->setBlocking(true);
232}
233
234TEST_F(FdMethodTest, SetBlockingOnNonBlocking)
235{
236 EXPECT_CALL(mock, fcntl_getfl(expected_fd))
237 .WillOnce(Return(flags_noblocking));
238 EXPECT_CALL(mock, fcntl_setfl(expected_fd, flags_blocking))
239 .WillOnce(Return(0));
240 fd->setBlocking(true);
241}
242
243TEST_F(FdMethodTest, SetNonBlockingOnBlocking)
244{
245 EXPECT_CALL(mock, fcntl_getfl(expected_fd))
246 .WillOnce(Return(flags_blocking));
247 EXPECT_CALL(mock, fcntl_setfl(expected_fd, flags_noblocking))
248 .WillOnce(Return(0));
249 fd->setBlocking(false);
250}
251
252TEST_F(FdMethodTest, SetNonBlockingOnNonBlocking)
253{
254 EXPECT_CALL(mock, fcntl_getfl(expected_fd))
255 .WillOnce(Return(flags_noblocking));
256 EXPECT_CALL(mock, fcntl_setfl(expected_fd, flags_noblocking))
257 .WillOnce(Return(0));
258 fd->setBlocking(false);
259}
260
261TEST_F(FdMethodTest, GetFlagsFail)
262{
263 EXPECT_CALL(mock, fcntl_getfl(expected_fd))
264 .WillOnce(DoAll(Assign(&errno, EINVAL), Return(-1)));
265 EXPECT_THROW(fd->setBlocking(true), std::system_error);
266}
267
268TEST_F(FdMethodTest, SetFlagsFail)
269{
270 EXPECT_CALL(mock, fcntl_getfl(expected_fd)).WillOnce(Return(0));
271 EXPECT_CALL(mock, fcntl_setfl(expected_fd, 0))
272 .WillOnce(DoAll(Assign(&errno, EINVAL), Return(-1)));
273 EXPECT_THROW(fd->setBlocking(true), std::system_error);
274}
275
276} // namespace
277} // namespace internal
278} // namespace gpioplus