xref: /openbmc/phosphor-power/test/file_descriptor_tests.cpp (revision b93d6ebef0b2628874aa7bf3b4464edbcead683f)
1 /**
2  * Copyright © 2020 IBM Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "file_descriptor.hpp"
17 
18 #include <errno.h>     // for errno
19 #include <fcntl.h>     // for open() and fcntl()
20 #include <sys/stat.h>  // for open()
21 #include <sys/types.h> // for open()
22 #include <unistd.h>    // for fcntl()
23 
24 #include <utility>
25 
26 #include <gtest/gtest.h>
27 
28 using namespace phosphor::power::util;
29 
30 /**
31  * Returns whether the specified file descriptor is valid/open.
32  *
33  * @param[in] fd - File descriptor
34  * @return true if descriptor is valid/open, false otherwise
35  */
isValid(int fd)36 bool isValid(int fd)
37 {
38     return (fcntl(fd, F_GETFL) != -1) || (errno != EBADF);
39 }
40 
41 /**
42  * Creates an open file descriptor.
43  *
44  * Verifies the file descriptor is valid.
45  *
46  * @return file descriptor
47  */
createOpenFileDescriptor()48 int createOpenFileDescriptor()
49 {
50     int fd = open("/etc/hosts", O_RDONLY);
51     EXPECT_NE(fd, -1);
52     EXPECT_TRUE(isValid(fd));
53     return fd;
54 }
55 
TEST(FileDescriptorTests,DefaultConstructor)56 TEST(FileDescriptorTests, DefaultConstructor)
57 {
58     FileDescriptor descriptor;
59     EXPECT_EQ(descriptor(), -1);
60     EXPECT_FALSE(descriptor.operator bool());
61 }
62 
TEST(FileDescriptorTests,IntConstructor)63 TEST(FileDescriptorTests, IntConstructor)
64 {
65     int fd = createOpenFileDescriptor();
66     FileDescriptor descriptor{fd};
67     EXPECT_EQ(descriptor(), fd);
68     EXPECT_TRUE(descriptor.operator bool());
69     EXPECT_TRUE(isValid(fd));
70 }
71 
TEST(FileDescriptorTests,MoveConstructor)72 TEST(FileDescriptorTests, MoveConstructor)
73 {
74     // Create first FileDescriptor object with open file descriptor
75     int fd = createOpenFileDescriptor();
76     FileDescriptor descriptor1{fd};
77     EXPECT_EQ(descriptor1(), fd);
78     EXPECT_TRUE(isValid(fd));
79 
80     // Create second FileDescriptor object, moving in the contents of the first
81     FileDescriptor descriptor2{std::move(descriptor1)};
82 
83     // Verify descriptor has been moved out of first object
84     EXPECT_EQ(descriptor1(), -1);
85 
86     // Verify descriptor has been moved into second object
87     EXPECT_EQ(descriptor2(), fd);
88 
89     // Verify descriptor is still valid/open
90     EXPECT_TRUE(isValid(fd));
91 }
92 
TEST(FileDescriptorTests,MoveAssignmentOperator)93 TEST(FileDescriptorTests, MoveAssignmentOperator)
94 {
95     // Test where move is valid
96     {
97         // Create first FileDescriptor object with open file descriptor
98         int fd1 = createOpenFileDescriptor();
99         FileDescriptor descriptor1{fd1};
100         EXPECT_EQ(descriptor1(), fd1);
101         EXPECT_TRUE(isValid(fd1));
102 
103         // Create second FileDescriptor object with open file descriptor
104         int fd2 = createOpenFileDescriptor();
105         FileDescriptor descriptor2{fd2};
106         EXPECT_EQ(descriptor2(), fd2);
107         EXPECT_TRUE(isValid(fd2));
108 
109         // Move second FileDescriptor object into the first
110         descriptor1 = std::move(descriptor2);
111 
112         // Verify second file descriptor has been moved into first object
113         EXPECT_EQ(descriptor1(), fd2);
114 
115         // Verify second file descriptor has been moved out of second object
116         EXPECT_EQ(descriptor2(), -1);
117 
118         // Verify first file descriptor has been closed and is no longer valid
119         EXPECT_FALSE(isValid(fd1));
120 
121         // Verify second file descriptor is still valid
122         EXPECT_TRUE(isValid(fd2));
123     }
124 
125     // Test where move is invalid: Attempt to move object into itself
126     {
127         // Create FileDescriptor object with open file descriptor
128         int fd = createOpenFileDescriptor();
129         FileDescriptor descriptor{fd};
130         EXPECT_EQ(descriptor(), fd);
131         EXPECT_TRUE(isValid(fd));
132 
133 // This is undefined behavior in C++, but suppress the warning
134 // to observe how the class handles it.
135 #ifdef __clang__
136 #pragma clang diagnostic push
137 #pragma clang diagnostic ignored "-Wself-move"
138 #endif
139         // Try to move object into itself
140         descriptor = static_cast<FileDescriptor&&>(descriptor);
141 #ifdef __clang__
142 #pragma clang diagnostic pop
143 #endif
144 
145         // Verify object still contains file descriptor
146         EXPECT_EQ(descriptor(), fd);
147         EXPECT_TRUE(isValid(fd));
148     }
149 }
150 
TEST(FileDescriptorTests,Destructor)151 TEST(FileDescriptorTests, Destructor)
152 {
153     // Test where file descriptor was never set
154     {
155         FileDescriptor descriptor;
156         EXPECT_EQ(descriptor(), -1);
157     }
158 
159     // Test where file descriptor was already closed
160     {
161         // Create FileDescriptor object with open file descriptor.  Close the
162         // descriptor explicitly.
163         int fd = createOpenFileDescriptor();
164         {
165             FileDescriptor descriptor{fd};
166             EXPECT_EQ(descriptor(), fd);
167             EXPECT_TRUE(isValid(fd));
168 
169             EXPECT_EQ(descriptor.close(), 0);
170             EXPECT_EQ(descriptor(), -1);
171             EXPECT_FALSE(isValid(fd));
172         }
173         EXPECT_FALSE(isValid(fd));
174     }
175 
176     // Test where file descriptor needs to be closed
177     {
178         // Create FileDescriptor object with open file descriptor.  Destructor
179         // will close descriptor.
180         int fd = createOpenFileDescriptor();
181         {
182             FileDescriptor descriptor{fd};
183             EXPECT_EQ(descriptor(), fd);
184             EXPECT_TRUE(isValid(fd));
185         }
186         EXPECT_FALSE(isValid(fd));
187     }
188 }
189 
TEST(FileDescriptorTests,FunctionCallOperator)190 TEST(FileDescriptorTests, FunctionCallOperator)
191 {
192     // Test where FileDescriptor object does not contain a valid file descriptor
193     FileDescriptor descriptor{};
194     EXPECT_EQ(descriptor(), -1);
195 
196     // Test where FileDescriptor object contains a valid file descriptor
197     int fd = createOpenFileDescriptor();
198     descriptor.set(fd);
199     EXPECT_EQ(descriptor(), fd);
200 }
201 
TEST(FileDescriptorTests,OperatorBool)202 TEST(FileDescriptorTests, OperatorBool)
203 {
204     // Test where FileDescriptor object does not contain a valid file descriptor
205     FileDescriptor descriptor{};
206     EXPECT_FALSE(descriptor.operator bool());
207     if (descriptor)
208     {
209         ADD_FAILURE() << "Should not have reached this line.";
210     }
211 
212     // Test where FileDescriptor object contains a valid file descriptor
213     int fd = createOpenFileDescriptor();
214     descriptor.set(fd);
215     EXPECT_TRUE(descriptor.operator bool());
216     if (!descriptor)
217     {
218         ADD_FAILURE() << "Should not have reached this line.";
219     }
220 
221     // Test where file descriptor has been closed
222     EXPECT_EQ(descriptor.close(), 0);
223     EXPECT_FALSE(descriptor.operator bool());
224     if (descriptor)
225     {
226         ADD_FAILURE() << "Should not have reached this line.";
227     }
228 }
229 
TEST(FileDescriptorTests,Close)230 TEST(FileDescriptorTests, Close)
231 {
232     // Test where object contains an open file descriptor
233     int fd = createOpenFileDescriptor();
234     FileDescriptor descriptor{fd};
235     EXPECT_EQ(descriptor(), fd);
236     EXPECT_TRUE(isValid(fd));
237     EXPECT_EQ(descriptor.close(), 0);
238     EXPECT_EQ(descriptor(), -1);
239     EXPECT_FALSE(isValid(fd));
240 
241     // Test where object does not contain an open file descriptor
242     EXPECT_EQ(descriptor(), -1);
243     EXPECT_EQ(descriptor.close(), 0);
244     EXPECT_EQ(descriptor(), -1);
245 
246     // Test where close() fails due to invalid file descriptor
247     descriptor.set(999999);
248     EXPECT_EQ(descriptor.close(), -1);
249     EXPECT_EQ(errno, EBADF);
250     EXPECT_EQ(descriptor(), -1);
251 }
252 
TEST(FileDescriptorTests,Set)253 TEST(FileDescriptorTests, Set)
254 {
255     // Test where object does not contain an open file descriptor
256     FileDescriptor descriptor{};
257     EXPECT_EQ(descriptor(), -1);
258     int fd1 = createOpenFileDescriptor();
259     descriptor.set(fd1);
260     EXPECT_EQ(descriptor(), fd1);
261     EXPECT_TRUE(isValid(fd1));
262 
263     // Test where object contains an open file descriptor.  Should close
264     // previous descriptor.
265     EXPECT_EQ(descriptor(), fd1);
266     EXPECT_TRUE(isValid(fd1));
267     int fd2 = createOpenFileDescriptor();
268     descriptor.set(fd2);
269     EXPECT_EQ(descriptor(), fd2);
270     EXPECT_FALSE(isValid(fd1));
271     EXPECT_TRUE(isValid(fd2));
272 
273     // Test where -1 is specified.  Should close previous descriptor.
274     EXPECT_EQ(descriptor(), fd2);
275     EXPECT_TRUE(isValid(fd2));
276     descriptor.set(-1);
277     EXPECT_EQ(descriptor(), -1);
278     EXPECT_FALSE(isValid(fd2));
279 }
280