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 = std::move(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