xref: /openbmc/gpioplus/test/internal/fd.cpp (revision ab995c50)
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 
TEST_F(FdTest,ConstructSimple)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 
TEST_F(FdTest,ConstructSimplBadFd)53 TEST_F(FdTest, ConstructSimplBadFd)
54 {
55     Fd fd(-1, std::false_type(), &mock);
56     EXPECT_EQ(-1, *fd);
57 }
58 
TEST_F(FdTest,ConstructDup)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 
TEST_F(FdTest,ConstructDupFail)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 
abrt_handler(int signum)76 void abrt_handler(int signum)
77 {
78     if (signum == SIGABRT)
79     {
80 #ifdef HAVE_GCOV
81         __gcov_flush();
82 #endif
83     }
84 }
85 
TEST_F(FdTest,CloseFails)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 
TEST_F(FdTest,ConstructSuccess)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 
TEST_F(FdTest,ConstructError)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 
TEST_F(FdTest,ConstructCopy)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 
TEST_F(FdTest,OperatorCopySame)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 
TEST_F(FdTest,OperatorCopy)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 
TEST_F(FdTest,ConstructMove)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 
TEST_F(FdTest,OperatorMoveSame)179 TEST_F(FdTest, OperatorMoveSame)
180 {
181     Fd fd(expected_fd, std::false_type(), &mock);
182     // 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);
185     EXPECT_EQ(expected_fd, *fd);
186 
187     EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0));
188 }
189 
TEST_F(FdTest,OperatorMove)190 TEST_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 
206 class 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 
SetUp()213     void SetUp()
214     {
215         fd = std::make_unique<Fd>(expected_fd, std::false_type(), &mock);
216     }
217 
TearDown()218     void TearDown()
219     {
220         EXPECT_CALL(mock, close(expected_fd)).WillOnce(Return(0));
221         fd.reset();
222     }
223 };
224 
TEST_F(FdMethodTest,SetBlockingOnBlocking)225 TEST_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 
TEST_F(FdMethodTest,SetBlockingOnNonBlocking)234 TEST_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 
TEST_F(FdMethodTest,SetNonBlockingOnBlocking)243 TEST_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 
TEST_F(FdMethodTest,SetNonBlockingOnNonBlocking)252 TEST_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 
TEST_F(FdMethodTest,GetFlagsFail)261 TEST_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 
TEST_F(FdMethodTest,SetFlagsFail)268 TEST_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
279