xref: /openbmc/gpioplus/test/internal/fd.cpp (revision 7ba248ad)
1 #include <fcntl.h>
2 #include <signal.h>
3 #include <sys/prctl.h>
4 
5 #include <gpioplus/internal/fd.hpp>
6 #include <gpioplus/test/sys.hpp>
7 
8 #include <cerrno>
9 #include <cstring>
10 #include <memory>
11 #include <system_error>
12 #include <type_traits>
13 #include <utility>
14 
15 #include <gmock/gmock.h>
16 #include <gtest/gtest.h>
17 
18 #ifdef HAVE_GCOV
19 // Needed for the abrt test
20 extern "C" void __gcov_flush(void);
21 #endif
22 
23 namespace gpioplus
24 {
25 namespace internal
26 {
27 namespace
28 {
29 
30 using testing::Assign;
31 using testing::DoAll;
32 using testing::Return;
33 
34 class 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 
44 TEST_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 
53 TEST_F(FdTest, ConstructSimplBadFd)
54 {
55     Fd fd(-1, std::false_type(), &mock);
56     EXPECT_EQ(-1, *fd);
57 }
58 
59 TEST_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 
69 TEST_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 
76 void abrt_handler(int signum)
77 {
78     if (signum == SIGABRT)
79     {
80 #ifdef HAVE_GCOV
81         __gcov_flush();
82 #endif
83     }
84 }
85 
86 TEST_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 
103 TEST_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 
115 TEST_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 
124 TEST_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 
139 TEST_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 
148 TEST_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 
167 TEST_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 
179 TEST_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 
188 TEST_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 
204 class 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 
223 TEST_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 
232 TEST_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 
241 TEST_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 
250 TEST_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 
259 TEST_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 
266 TEST_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
277