/** * Copyright © 2020 IBM Corporation * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "file_descriptor.hpp" #include // for errno #include // for open() and fcntl() #include // for open() #include // for open() #include // for fcntl() #include #include using namespace phosphor::power::util; /** * Returns whether the specified file descriptor is valid/open. * * @param[in] fd - File descriptor * @return true if descriptor is valid/open, false otherwise */ bool isValid(int fd) { return (fcntl(fd, F_GETFL) != -1) || (errno != EBADF); } /** * Creates an open file descriptor. * * Verifies the file descriptor is valid. * * @return file descriptor */ int createOpenFileDescriptor() { int fd = open("/etc/hosts", O_RDONLY); EXPECT_NE(fd, -1); EXPECT_TRUE(isValid(fd)); return fd; } TEST(FileDescriptorTests, DefaultConstructor) { FileDescriptor descriptor; EXPECT_EQ(descriptor(), -1); EXPECT_FALSE(descriptor.operator bool()); } TEST(FileDescriptorTests, IntConstructor) { int fd = createOpenFileDescriptor(); FileDescriptor descriptor{fd}; EXPECT_EQ(descriptor(), fd); EXPECT_TRUE(descriptor.operator bool()); EXPECT_TRUE(isValid(fd)); } TEST(FileDescriptorTests, MoveConstructor) { // Create first FileDescriptor object with open file descriptor int fd = createOpenFileDescriptor(); FileDescriptor descriptor1{fd}; EXPECT_EQ(descriptor1(), fd); EXPECT_TRUE(isValid(fd)); // Create second FileDescriptor object, moving in the contents of the first FileDescriptor descriptor2{std::move(descriptor1)}; // Verify descriptor has been moved out of first object EXPECT_EQ(descriptor1(), -1); // Verify descriptor has been moved into second object EXPECT_EQ(descriptor2(), fd); // Verify descriptor is still valid/open EXPECT_TRUE(isValid(fd)); } TEST(FileDescriptorTests, MoveAssignmentOperator) { // Test where move is valid { // Create first FileDescriptor object with open file descriptor int fd1 = createOpenFileDescriptor(); FileDescriptor descriptor1{fd1}; EXPECT_EQ(descriptor1(), fd1); EXPECT_TRUE(isValid(fd1)); // Create second FileDescriptor object with open file descriptor int fd2 = createOpenFileDescriptor(); FileDescriptor descriptor2{fd2}; EXPECT_EQ(descriptor2(), fd2); EXPECT_TRUE(isValid(fd2)); // Move second FileDescriptor object into the first descriptor1 = std::move(descriptor2); // Verify second file descriptor has been moved into first object EXPECT_EQ(descriptor1(), fd2); // Verify second file descriptor has been moved out of second object EXPECT_EQ(descriptor2(), -1); // Verify first file descriptor has been closed and is no longer valid EXPECT_FALSE(isValid(fd1)); // Verify second file descriptor is still valid EXPECT_TRUE(isValid(fd2)); } // Test where move is invalid: Attempt to move object into itself { // Create FileDescriptor object with open file descriptor int fd = createOpenFileDescriptor(); FileDescriptor descriptor{fd}; EXPECT_EQ(descriptor(), fd); EXPECT_TRUE(isValid(fd)); // Try to move object into itself descriptor = std::move(descriptor); // Verify object still contains file descriptor EXPECT_EQ(descriptor(), fd); EXPECT_TRUE(isValid(fd)); } } TEST(FileDescriptorTests, Destructor) { // Test where file descriptor was never set { FileDescriptor descriptor; EXPECT_EQ(descriptor(), -1); } // Test where file descriptor was already closed { // Create FileDescriptor object with open file descriptor. Close the // descriptor explicitly. int fd = createOpenFileDescriptor(); { FileDescriptor descriptor{fd}; EXPECT_EQ(descriptor(), fd); EXPECT_TRUE(isValid(fd)); EXPECT_EQ(descriptor.close(), 0); EXPECT_EQ(descriptor(), -1); EXPECT_FALSE(isValid(fd)); } EXPECT_FALSE(isValid(fd)); } // Test where file descriptor needs to be closed { // Create FileDescriptor object with open file descriptor. Destructor // will close descriptor. int fd = createOpenFileDescriptor(); { FileDescriptor descriptor{fd}; EXPECT_EQ(descriptor(), fd); EXPECT_TRUE(isValid(fd)); } EXPECT_FALSE(isValid(fd)); } } TEST(FileDescriptorTests, FunctionCallOperator) { // Test where FileDescriptor object does not contain a valid file descriptor FileDescriptor descriptor{}; EXPECT_EQ(descriptor(), -1); // Test where FileDescriptor object contains a valid file descriptor int fd = createOpenFileDescriptor(); descriptor.set(fd); EXPECT_EQ(descriptor(), fd); } TEST(FileDescriptorTests, OperatorBool) { // Test where FileDescriptor object does not contain a valid file descriptor FileDescriptor descriptor{}; EXPECT_FALSE(descriptor.operator bool()); if (descriptor) { ADD_FAILURE() << "Should not have reached this line."; } // Test where FileDescriptor object contains a valid file descriptor int fd = createOpenFileDescriptor(); descriptor.set(fd); EXPECT_TRUE(descriptor.operator bool()); if (!descriptor) { ADD_FAILURE() << "Should not have reached this line."; } // Test where file descriptor has been closed EXPECT_EQ(descriptor.close(), 0); EXPECT_FALSE(descriptor.operator bool()); if (descriptor) { ADD_FAILURE() << "Should not have reached this line."; } } TEST(FileDescriptorTests, Close) { // Test where object contains an open file descriptor int fd = createOpenFileDescriptor(); FileDescriptor descriptor{fd}; EXPECT_EQ(descriptor(), fd); EXPECT_TRUE(isValid(fd)); EXPECT_EQ(descriptor.close(), 0); EXPECT_EQ(descriptor(), -1); EXPECT_FALSE(isValid(fd)); // Test where object does not contain an open file descriptor EXPECT_EQ(descriptor(), -1); EXPECT_EQ(descriptor.close(), 0); EXPECT_EQ(descriptor(), -1); // Test where close() fails due to invalid file descriptor descriptor.set(999999); EXPECT_EQ(descriptor.close(), -1); EXPECT_EQ(errno, EBADF); EXPECT_EQ(descriptor(), -1); } TEST(FileDescriptorTests, Set) { // Test where object does not contain an open file descriptor FileDescriptor descriptor{}; EXPECT_EQ(descriptor(), -1); int fd1 = createOpenFileDescriptor(); descriptor.set(fd1); EXPECT_EQ(descriptor(), fd1); EXPECT_TRUE(isValid(fd1)); // Test where object contains an open file descriptor. Should close // previous descriptor. EXPECT_EQ(descriptor(), fd1); EXPECT_TRUE(isValid(fd1)); int fd2 = createOpenFileDescriptor(); descriptor.set(fd2); EXPECT_EQ(descriptor(), fd2); EXPECT_FALSE(isValid(fd1)); EXPECT_TRUE(isValid(fd2)); // Test where -1 is specified. Should close previous descriptor. EXPECT_EQ(descriptor(), fd2); EXPECT_TRUE(isValid(fd2)); descriptor.set(-1); EXPECT_EQ(descriptor(), -1); EXPECT_FALSE(isValid(fd2)); }