blob: ad63dd778e810bbc487e97034997990bca478501 [file] [log] [blame]
/**
* 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 <errno.h> // for errno
#include <fcntl.h> // for open() and fcntl()
#include <sys/stat.h> // for open()
#include <sys/types.h> // for open()
#include <unistd.h> // for fcntl()
#include <utility>
#include <gtest/gtest.h>
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 = static_cast<FileDescriptor&&>(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));
}