diff options
Diffstat (limited to 'test/buildtool/file_system/file_system_manager.test.cpp')
-rw-r--r-- | test/buildtool/file_system/file_system_manager.test.cpp | 346 |
1 files changed, 346 insertions, 0 deletions
diff --git a/test/buildtool/file_system/file_system_manager.test.cpp b/test/buildtool/file_system/file_system_manager.test.cpp new file mode 100644 index 00000000..5444a94b --- /dev/null +++ b/test/buildtool/file_system/file_system_manager.test.cpp @@ -0,0 +1,346 @@ +#include <algorithm> +#include <cstdlib> +#include <filesystem> +#include <iostream> + +#include "catch2/catch.hpp" +#include "src/buildtool/file_system/file_system_manager.hpp" + +class CopyFileFixture { + public: + CopyFileFixture() noexcept { + REQUIRE(FileSystemManager::CreateDirectory(to_.parent_path())); + } + CopyFileFixture(CopyFileFixture const&) = delete; + CopyFileFixture(CopyFileFixture&&) = delete; + ~CopyFileFixture() noexcept { CHECK(std::filesystem::remove(to_)); } + auto operator=(CopyFileFixture const&) -> CopyFileFixture& = delete; + auto operator=(CopyFileFixture &&) -> CopyFileFixture& = delete; + + std::filesystem::path const from_{ + "test/buildtool/file_system/data/example_file"}; + std::filesystem::path const to_{"./tmp-CopyFile/copied_file"}; +}; + +class WriteFileFixture { + public: + WriteFileFixture() noexcept { + REQUIRE(FileSystemManager::CreateDirectory(root_dir_)); + } + WriteFileFixture(WriteFileFixture const&) = delete; + WriteFileFixture(WriteFileFixture&&) = delete; + ~WriteFileFixture() noexcept { CHECK(std::filesystem::remove(file_path_)); } + auto operator=(WriteFileFixture const&) -> WriteFileFixture& = delete; + auto operator=(WriteFileFixture &&) -> WriteFileFixture& = delete; + + std::filesystem::path const relative_path_parent_{ + GENERATE(as<std::filesystem::path>{}, + ".", + "level0", + "level0/level1", + "a/b/c/d", + "./a/../e")}; + std::filesystem::path const root_dir_{"./tmp-RemoveFile"}; + std::filesystem::path const file_path_{root_dir_ / relative_path_parent_ / + "file"}; +}; + +TEST_CASE("CreateDirectory", "[file_system]") { + auto const dir = GENERATE(as<std::filesystem::path>{}, + "level0", + "level0/level1", + "a/b/c/d", + "./a/../e"); + CHECK(FileSystemManager::CreateDirectory(dir)); + CHECK(std::filesystem::exists(dir)); + CHECK(std::filesystem::is_directory(dir)); + + // If we have created the directory already, CreateDirectory() returns true + // and the state of things doesn't change + CHECK(FileSystemManager::CreateDirectory(dir)); + CHECK(std::filesystem::exists(dir)); + CHECK(std::filesystem::is_directory(dir)); +} + +TEST_CASE("IsFile", "[file_system]") { + CHECK(FileSystemManager::IsFile( + "test/buildtool/file_system/data/example_file")); + CHECK(FileSystemManager::IsFile( + "test/buildtool/file_system/data/empty_executable")); + CHECK_FALSE( + FileSystemManager::IsFile("test/buildtool/file_system/data/")); +} + +TEST_CASE("IsExecutable", "[file_system]") { + CHECK(FileSystemManager::IsExecutable( + "test/buildtool/file_system/data/empty_executable")); + CHECK_FALSE(FileSystemManager::IsExecutable( + "test/buildtool/file_system/data/example_file")); + CHECK_FALSE(FileSystemManager::IsExecutable( + "test/buildtool/file_system/data/")); +} + +TEST_CASE("Type", "[file_system]") { + auto const type_file = FileSystemManager::Type( + "test/buildtool/file_system/data/example_file"); + REQUIRE(type_file); + CHECK(*type_file == ObjectType::File); + + auto const type_exec = FileSystemManager::Type( + "test/buildtool/file_system/data/empty_executable"); + REQUIRE(type_exec); + CHECK(*type_exec == ObjectType::Executable); + + auto const type_dir = + FileSystemManager::Type("test/buildtool/file_system/data/"); + REQUIRE(type_dir); + CHECK(*type_dir == ObjectType::Tree); +} + +TEST_CASE("ChangeDirectory", "[file_system]") { + auto const starting_dir = FileSystemManager::GetCurrentDirectory(); + + auto const new_dir = GENERATE(as<std::filesystem::path>{}, + "level0", + "level0/level1", + "a/b/c/d", + "./a/../e"); + + REQUIRE(FileSystemManager::CreateDirectory(new_dir)); + { + auto anchor = FileSystemManager::ChangeDirectory(new_dir); + CHECK(std::filesystem::equivalent( + starting_dir / new_dir, FileSystemManager::GetCurrentDirectory())); + } + CHECK(starting_dir == FileSystemManager::GetCurrentDirectory()); +} + +TEST_CASE("ReadFile", "[file_system]") { + SECTION("Existing file") { + std::string const expected_content{"test\n"}; + std::filesystem::path file{"./tmp-ReadFile/file"}; + + REQUIRE(FileSystemManager::CreateDirectory(file.parent_path())); + std::ofstream writer{file}; + writer << expected_content; + writer.close(); + + auto const content = FileSystemManager::ReadFile(file); + CHECK(content.has_value()); + CHECK(content == expected_content); + } + SECTION("Non-existing file") { + std::filesystem::path file{ + "test/buildtool/file_system/data/this_file_does_not_exist"}; + REQUIRE(not std::filesystem::exists(file)); + + auto const content = FileSystemManager::ReadFile(file); + CHECK_FALSE(content.has_value()); + } +} + +TEST_CASE_METHOD(CopyFileFixture, "CopyFile", "[file_system]") { + // Copy file was successful + CHECK(FileSystemManager::CopyFile(from_, to_)); + + // file exists + CHECK(std::filesystem::exists(to_)); + CHECK(std::filesystem::is_regular_file(to_)); + + // Contents are equal + auto const content_from = FileSystemManager::ReadFile(from_); + CHECK(content_from.has_value()); + auto const content_to = FileSystemManager::ReadFile(to_); + CHECK(content_to.has_value()); + CHECK(content_from == content_to); +} + +TEST_CASE_METHOD(CopyFileFixture, "CopyFileAs", "[file_system]") { + SECTION("as file") { + // Copy as file was successful + CHECK(FileSystemManager::CopyFileAs(from_, to_, ObjectType::File)); + + // file exists + CHECK(std::filesystem::exists(to_)); + CHECK(std::filesystem::is_regular_file(to_)); + CHECK(not FileSystemManager::IsExecutable(to_)); + + // Contents are equal + auto const content_from = FileSystemManager::ReadFile(from_); + CHECK(content_from.has_value()); + auto const content_to = FileSystemManager::ReadFile(to_); + CHECK(content_to.has_value()); + CHECK(content_from == content_to); + + // permissions should be 0444 (not writable, but removable) + CHECK(not FileSystemManager::WriteFile("replacement content", to_)); + } + SECTION("as executable") { + // Copy as file was successful + CHECK( + FileSystemManager::CopyFileAs(from_, to_, ObjectType::Executable)); + + // file exists + CHECK(std::filesystem::exists(to_)); + CHECK(std::filesystem::is_regular_file(to_)); + CHECK(FileSystemManager::IsExecutable(to_)); + + // Contents are equal + auto const content_from = FileSystemManager::ReadFile(from_); + CHECK(content_from.has_value()); + auto const content_to = FileSystemManager::ReadFile(to_); + CHECK(content_to.has_value()); + CHECK(content_from == content_to); + + // permissions should be 0555 (not writable, but removable) + CHECK(not FileSystemManager::WriteFile("replacement content", to_)); + } +} + +TEST_CASE("RemoveFile", "[file_system]") { + SECTION("Existing file") { + std::filesystem::path from{ + "test/buildtool/file_system/data/example_file"}; + + std::filesystem::path to{"./tmp-RemoveFile/copied_file"}; + REQUIRE(FileSystemManager::CreateDirectory(to.parent_path())); + + CHECK(FileSystemManager::CopyFile(from, to)); + + CHECK(std::filesystem::exists(to)); + + CHECK(FileSystemManager::RemoveFile(to)); + + CHECK(not std::filesystem::exists(to)); + } + SECTION("Non-existing file") { + std::filesystem::path file{ + "test/buildtool/file_system/data/" + "this_file_does_not_exist_neither"}; + CHECK(not std::filesystem::exists(file)); + CHECK(FileSystemManager::RemoveFile(file)); // nothing to delete + } + SECTION("Existing but not file") { + std::filesystem::path dir{"./tmp-RemoveFile/dir"}; + CHECK(FileSystemManager::CreateDirectory(dir)); + CHECK(not FileSystemManager::RemoveFile(dir)); + CHECK(std::filesystem::exists(dir)); + } +} + +TEST_CASE_METHOD(WriteFileFixture, "WriteFile", "[file_system]") { + std::string const content{"This are the contents\nof the file.\n"}; + + CHECK(FileSystemManager::WriteFile(content, file_path_)); + CHECK(std::filesystem::exists(file_path_)); + CHECK(std::filesystem::is_directory(file_path_.parent_path())); + CHECK(std::filesystem::is_regular_file(file_path_)); + + auto const written_content = FileSystemManager::ReadFile(file_path_); + CHECK(written_content.has_value()); + CHECK(written_content == content); +} + +TEST_CASE_METHOD(WriteFileFixture, "WriteFileAs", "[file_system]") { + SECTION("as a file") { + std::string const content{"This are the contents\nof the file.\n"}; + + CHECK(FileSystemManager::WriteFileAs( + content, file_path_, ObjectType::File)); + CHECK(std::filesystem::exists(file_path_)); + CHECK(std::filesystem::is_directory(file_path_.parent_path())); + CHECK(std::filesystem::is_regular_file(file_path_)); + CHECK(not FileSystemManager::IsExecutable(file_path_)); + + auto const written_content = FileSystemManager::ReadFile(file_path_); + CHECK(written_content.has_value()); + CHECK(written_content == content); + + // permissions should be 0444 (not writable, but removable) + CHECK(not FileSystemManager::WriteFile("replacement content", + file_path_)); + } + SECTION("as an executable") { + std::string const content{"\n"}; + + CHECK(FileSystemManager::WriteFileAs( + content, file_path_, ObjectType::Executable)); + CHECK(std::filesystem::exists(file_path_)); + CHECK(std::filesystem::is_directory(file_path_.parent_path())); + CHECK(std::filesystem::is_regular_file(file_path_)); + CHECK(FileSystemManager::IsExecutable(file_path_)); + + auto const written_content = FileSystemManager::ReadFile(file_path_); + CHECK(written_content.has_value()); + CHECK(written_content == content); + + // permissions should be 0555 (not writable, but removable) + CHECK(not FileSystemManager::WriteFile("replacement content", + file_path_)); + } +} + +TEST_CASE("FileSystemManager", "[file_system]") { + // test file and test file content with newline and null characters + std::filesystem::path test_file{"test/file"}; + std::filesystem::path copy_file{"test/copy"}; + std::string test_content; + test_content += "test1"; + test_content += '\n'; + test_content += '\0'; + test_content += "test2"; + + CHECK(FileSystemManager::IsRelativePath(test_file)); + CHECK(not FileSystemManager::IsAbsolutePath(test_file)); + + // create parent directory + REQUIRE(FileSystemManager::CreateDirectory(test_file.parent_path())); + + // scope to test RAII "DirectoryAnchor" (should restore CWD on destruction) + { + // change directory and obtain DirectoryAnchor + auto anchor = + FileSystemManager::ChangeDirectory(test_file.parent_path()); + + // assemble file creation command (escape null character) + std::string create_file_cmd{}; + create_file_cmd += "echo -n \""; + std::for_each( + test_content.begin(), test_content.end(), [&](auto const& c) { + if (c == '\0') { + create_file_cmd += std::string{"\\0"}; + } + else { + create_file_cmd += c; + } + }); + create_file_cmd += "\" > " + test_file.filename().string(); + + // run file creation command + std::system(create_file_cmd.c_str()); + + // check if file exists + REQUIRE(FileSystemManager::IsFile(test_file.filename())); + } // restore CWD to parent path + + // check if file exists with full path + REQUIRE(FileSystemManager::IsFile(test_file)); + + // read file content and compare with input above + auto const file_content = FileSystemManager::ReadFile(test_file); + REQUIRE(file_content.has_value()); + CHECK(file_content == test_content); + + // copy file without 'overwrite' + CHECK(FileSystemManager::CopyFile( + test_file, copy_file, std::filesystem::copy_options::none)); + + // copy file with 'overwrite' + CHECK(FileSystemManager::CopyFile(copy_file, test_file)); + + // remove files and verify removal + CHECK(FileSystemManager::RemoveFile(test_file)); + CHECK(not FileSystemManager::IsFile(test_file)); + CHECK(FileSystemManager::RemoveFile(copy_file)); + CHECK(not FileSystemManager::IsFile(copy_file)); +} |