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  */
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  */
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 
56 TEST(FileDescriptorTests, DefaultConstructor)
57 {
58     FileDescriptor descriptor;
59     EXPECT_EQ(descriptor(), -1);
60     EXPECT_FALSE(descriptor.operator bool());
61 }
62 
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 
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 
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         // Try to move object into itself
134         descriptor = static_cast<FileDescriptor&&>(descriptor);
135 
136         // Verify object still contains file descriptor
137         EXPECT_EQ(descriptor(), fd);
138         EXPECT_TRUE(isValid(fd));
139     }
140 }
141 
142 TEST(FileDescriptorTests, Destructor)
143 {
144     // Test where file descriptor was never set
145     {
146         FileDescriptor descriptor;
147         EXPECT_EQ(descriptor(), -1);
148     }
149 
150     // Test where file descriptor was already closed
151     {
152         // Create FileDescriptor object with open file descriptor.  Close the
153         // descriptor explicitly.
154         int fd = createOpenFileDescriptor();
155         {
156             FileDescriptor descriptor{fd};
157             EXPECT_EQ(descriptor(), fd);
158             EXPECT_TRUE(isValid(fd));
159 
160             EXPECT_EQ(descriptor.close(), 0);
161             EXPECT_EQ(descriptor(), -1);
162             EXPECT_FALSE(isValid(fd));
163         }
164         EXPECT_FALSE(isValid(fd));
165     }
166 
167     // Test where file descriptor needs to be closed
168     {
169         // Create FileDescriptor object with open file descriptor.  Destructor
170         // will close descriptor.
171         int fd = createOpenFileDescriptor();
172         {
173             FileDescriptor descriptor{fd};
174             EXPECT_EQ(descriptor(), fd);
175             EXPECT_TRUE(isValid(fd));
176         }
177         EXPECT_FALSE(isValid(fd));
178     }
179 }
180 
181 TEST(FileDescriptorTests, FunctionCallOperator)
182 {
183     // Test where FileDescriptor object does not contain a valid file descriptor
184     FileDescriptor descriptor{};
185     EXPECT_EQ(descriptor(), -1);
186 
187     // Test where FileDescriptor object contains a valid file descriptor
188     int fd = createOpenFileDescriptor();
189     descriptor.set(fd);
190     EXPECT_EQ(descriptor(), fd);
191 }
192 
193 TEST(FileDescriptorTests, OperatorBool)
194 {
195     // Test where FileDescriptor object does not contain a valid file descriptor
196     FileDescriptor descriptor{};
197     EXPECT_FALSE(descriptor.operator bool());
198     if (descriptor)
199     {
200         ADD_FAILURE() << "Should not have reached this line.";
201     }
202 
203     // Test where FileDescriptor object contains a valid file descriptor
204     int fd = createOpenFileDescriptor();
205     descriptor.set(fd);
206     EXPECT_TRUE(descriptor.operator bool());
207     if (!descriptor)
208     {
209         ADD_FAILURE() << "Should not have reached this line.";
210     }
211 
212     // Test where file descriptor has been closed
213     EXPECT_EQ(descriptor.close(), 0);
214     EXPECT_FALSE(descriptor.operator bool());
215     if (descriptor)
216     {
217         ADD_FAILURE() << "Should not have reached this line.";
218     }
219 }
220 
221 TEST(FileDescriptorTests, Close)
222 {
223     // Test where object contains an open file descriptor
224     int fd = createOpenFileDescriptor();
225     FileDescriptor descriptor{fd};
226     EXPECT_EQ(descriptor(), fd);
227     EXPECT_TRUE(isValid(fd));
228     EXPECT_EQ(descriptor.close(), 0);
229     EXPECT_EQ(descriptor(), -1);
230     EXPECT_FALSE(isValid(fd));
231 
232     // Test where object does not contain an open file descriptor
233     EXPECT_EQ(descriptor(), -1);
234     EXPECT_EQ(descriptor.close(), 0);
235     EXPECT_EQ(descriptor(), -1);
236 
237     // Test where close() fails due to invalid file descriptor
238     descriptor.set(999999);
239     EXPECT_EQ(descriptor.close(), -1);
240     EXPECT_EQ(errno, EBADF);
241     EXPECT_EQ(descriptor(), -1);
242 }
243 
244 TEST(FileDescriptorTests, Set)
245 {
246     // Test where object does not contain an open file descriptor
247     FileDescriptor descriptor{};
248     EXPECT_EQ(descriptor(), -1);
249     int fd1 = createOpenFileDescriptor();
250     descriptor.set(fd1);
251     EXPECT_EQ(descriptor(), fd1);
252     EXPECT_TRUE(isValid(fd1));
253 
254     // Test where object contains an open file descriptor.  Should close
255     // previous descriptor.
256     EXPECT_EQ(descriptor(), fd1);
257     EXPECT_TRUE(isValid(fd1));
258     int fd2 = createOpenFileDescriptor();
259     descriptor.set(fd2);
260     EXPECT_EQ(descriptor(), fd2);
261     EXPECT_FALSE(isValid(fd1));
262     EXPECT_TRUE(isValid(fd2));
263 
264     // Test where -1 is specified.  Should close previous descriptor.
265     EXPECT_EQ(descriptor(), fd2);
266     EXPECT_TRUE(isValid(fd2));
267     descriptor.set(-1);
268     EXPECT_EQ(descriptor(), -1);
269     EXPECT_FALSE(isValid(fd2));
270 }
271