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