blob: 9eafa568607a511acfb324e660f235d4eb5c43f2 [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 "temporary_file.hpp"
#include <filesystem>
#include <fstream>
#include <string>
#include <utility>
#include <gtest/gtest.h>
using namespace phosphor::power::util;
namespace fs = std::filesystem;
/**
* Modify the specified file so that fs::remove() fails with an exception.
*
* The file will be renamed and can be restored by calling makeFileRemovable().
*
* @param path path to the file
*/
inline void makeFileUnRemovable(const fs::path& path)
{
// Rename the file to save its contents
fs::path savePath{path.native() + ".save"};
fs::rename(path, savePath);
// Create a directory at the original file path
fs::create_directory(path);
// Create a file within the directory. fs::remove() will throw an exception
// if the path is a non-empty directory.
std::ofstream childFile{path / "childFile"};
}
/**
* Modify the specified file so that fs::remove() can successfully delete it.
*
* Undo the modifications from an earlier call to makeFileUnRemovable().
*
* @param path path to the file
*/
inline void makeFileRemovable(const fs::path& path)
{
// makeFileUnRemovable() creates a directory at the file path. Remove the
// directory and all of its contents.
fs::remove_all(path);
// Rename the file back to the original path to restore its contents
fs::path savePath{path.native() + ".save"};
fs::rename(savePath, path);
}
TEST(TemporaryFileTests, DefaultConstructor)
{
TemporaryFile file{};
fs::path path = file.getPath();
EXPECT_FALSE(path.empty());
EXPECT_TRUE(fs::exists(path));
EXPECT_TRUE(fs::is_regular_file(path));
fs::path parentDir = path.parent_path();
EXPECT_EQ(parentDir, "/tmp");
std::string fileName = path.filename();
std::string namePrefix = "phosphor-power-";
EXPECT_EQ(fileName.compare(0, namePrefix.size(), namePrefix), 0);
}
TEST(TemporaryFileTests, MoveConstructor)
{
// Create first TemporaryFile object and verify temporary file exists
TemporaryFile file1{};
EXPECT_FALSE(file1.getPath().empty());
EXPECT_TRUE(fs::exists(file1.getPath()));
// Save path to temporary file
fs::path path = file1.getPath();
// Create second TemporaryFile object by moving first object
TemporaryFile file2{std::move(file1)};
// Verify first object now has an empty path
EXPECT_TRUE(file1.getPath().empty());
// Verify second object now owns same temporary file and file exists
EXPECT_EQ(file2.getPath(), path);
EXPECT_TRUE(fs::exists(file2.getPath()));
}
TEST(TemporaryFileTests, MoveAssignmentOperator)
{
// Test where works: TemporaryFile object is moved
{
// Create first TemporaryFile object and verify temporary file exists
TemporaryFile file1{};
EXPECT_FALSE(file1.getPath().empty());
EXPECT_TRUE(fs::exists(file1.getPath()));
// Save path to first temporary file
fs::path path1 = file1.getPath();
// Create second TemporaryFile object and verify temporary file exists
TemporaryFile file2{};
EXPECT_FALSE(file2.getPath().empty());
EXPECT_TRUE(fs::exists(file2.getPath()));
// Save path to second temporary file
fs::path path2 = file2.getPath();
// Verify temporary files are different
EXPECT_NE(path1, path2);
// Move first object into the second
file2 = std::move(file1);
// Verify first object now has an empty path
EXPECT_TRUE(file1.getPath().empty());
// Verify second object now owns first temporary file and file exists
EXPECT_EQ(file2.getPath(), path1);
EXPECT_TRUE(fs::exists(path1));
// Verify second temporary file was deleted
EXPECT_FALSE(fs::exists(path2));
}
// Test where does nothing: TemporaryFile object is moved into itself
{
// Create TemporaryFile object and verify temporary file exists
TemporaryFile file{};
EXPECT_FALSE(file.getPath().empty());
EXPECT_TRUE(fs::exists(file.getPath()));
// Save path to temporary file
fs::path path = file.getPath();
// Try to move object into itself; should do nothing
file = static_cast<TemporaryFile&&>(file);
// Verify object still owns same temporary file and file exists
EXPECT_EQ(file.getPath(), path);
EXPECT_TRUE(fs::exists(path));
}
// Test where fails: Cannot delete temporary file
{
// Create first TemporaryFile object and verify temporary file exists
TemporaryFile file1{};
EXPECT_FALSE(file1.getPath().empty());
EXPECT_TRUE(fs::exists(file1.getPath()));
// Save path to first temporary file
fs::path path1 = file1.getPath();
// Create second TemporaryFile object and verify temporary file exists
TemporaryFile file2{};
EXPECT_FALSE(file2.getPath().empty());
EXPECT_TRUE(fs::exists(file2.getPath()));
// Save path to second temporary file
fs::path path2 = file2.getPath();
// Verify temporary files are different
EXPECT_NE(path1, path2);
// Make second temporary file unremoveable
makeFileUnRemovable(path2);
try
{
// Try to move first object into the second; should throw exception
file2 = std::move(file1);
ADD_FAILURE() << "Should not have reached this line.";
}
catch (const std::exception& e)
{
// This is expected. Exception message will vary.
}
// Verify first object has not changed and first temporary file exists
EXPECT_EQ(file1.getPath(), path1);
EXPECT_TRUE(fs::exists(path1));
// Verify second object has not changed and second temporary file exists
EXPECT_EQ(file2.getPath(), path2);
EXPECT_TRUE(fs::exists(path2));
// Make second temporary file removeable so destructor can delete it
makeFileRemovable(path2);
}
}
TEST(TemporaryFileTests, Destructor)
{
// Test where works: Temporary file is deleted
{
fs::path path{};
{
TemporaryFile file{};
path = file.getPath();
EXPECT_TRUE(fs::exists(path));
}
EXPECT_FALSE(fs::exists(path));
}
// Test where works: Temporary file was already deleted
{
fs::path path{};
{
TemporaryFile file{};
path = file.getPath();
EXPECT_TRUE(fs::exists(path));
file.remove();
EXPECT_FALSE(fs::exists(path));
}
EXPECT_FALSE(fs::exists(path));
}
// Test where fails: Cannot delete temporary file: No exception thrown
{
fs::path path{};
try
{
TemporaryFile file{};
path = file.getPath();
EXPECT_TRUE(fs::exists(path));
makeFileUnRemovable(path);
}
catch (...)
{
ADD_FAILURE() << "Should not have caught exception.";
}
// Temporary file should still exist
EXPECT_TRUE(fs::exists(path));
// Make file removable and delete it
makeFileRemovable(path);
fs::remove(path);
}
}
TEST(TemporaryFileTests, Remove)
{
// Test where works
{
// Create TemporaryFile object and verify temporary file exists
TemporaryFile file{};
EXPECT_FALSE(file.getPath().empty());
EXPECT_TRUE(fs::exists(file.getPath()));
// Save path to temporary file
fs::path path = file.getPath();
// Delete temporary file
file.remove();
// Verify path is cleared and file does not exist
EXPECT_TRUE(file.getPath().empty());
EXPECT_FALSE(fs::exists(path));
// Delete temporary file again; should do nothing
file.remove();
EXPECT_TRUE(file.getPath().empty());
EXPECT_FALSE(fs::exists(path));
}
// Test where fails
{
// Create TemporaryFile object and verify temporary file exists
TemporaryFile file{};
EXPECT_FALSE(file.getPath().empty());
EXPECT_TRUE(fs::exists(file.getPath()));
// Make file unremovable
makeFileUnRemovable(file.getPath());
try
{
// Try to delete temporary file; should fail with exception
file.remove();
ADD_FAILURE() << "Should not have reached this line.";
}
catch (const std::exception& e)
{
// This is expected. Exception message will vary.
}
// Make file removable again so it will be deleted by the destructor
makeFileRemovable(file.getPath());
}
}
TEST(TemporaryFileTests, GetPath)
{
TemporaryFile file{};
EXPECT_FALSE(file.getPath().empty());
EXPECT_EQ(file.getPath().parent_path(), "/tmp");
EXPECT_TRUE(fs::exists(file.getPath()));
}