xref: /openbmc/gpioplus/test/internal/fd.cpp (revision 8ff58122)
1 #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
17 extern "C" void __gcov_flush(void);
18 #endif
19 
20 namespace gpioplus
21 {
22 namespace internal
23 {
24 namespace
25 {
26 
27 using testing::Assign;
28 using testing::DoAll;
29 using testing::Return;
30 
31 class 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 
41 TEST_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 
50 TEST_F(FdTest, ConstructSimplBadFd)
51 {
52     Fd fd(-1, std::false_type(), &mock);
53     EXPECT_EQ(-1, *fd);
54 }
55 
56 TEST_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 
66 TEST_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 
73 void abrt_handler(int signum)
74 {
75     if (signum == SIGABRT)
76     {
77 #ifdef HAVE_GCOV
78         __gcov_flush();
79 #endif
80     }
81 }
82 
83 TEST_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 
100 TEST_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 
112 TEST_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 
121 TEST_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 
136 TEST_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 
145 TEST_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 
164 TEST_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 
176 TEST_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 
185 TEST_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 
201 class 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 
220 TEST_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 
229 TEST_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 
238 TEST_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 
247 TEST_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 
256 TEST_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 
263 TEST_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
274