diff --git a/src/Filesystem_TEST.cc b/src/Filesystem_TEST.cc index 64b9899c3..0f77e3ee5 100644 --- a/src/Filesystem_TEST.cc +++ b/src/Filesystem_TEST.cc @@ -17,205 +17,97 @@ #include -#ifndef _WIN32 -#include -#include -#include -#include -#include -#include +#include + +#include +#include +#include +#include -#include "ignition/common/Util.hh" +#include +#include // The symlink tests should always work on UNIX systems +#ifndef _WIN32 #define BUILD_SYMLINK_TESTS +#endif // _WIN32 + +using namespace ignition; +using namespace common; + +namespace fs = std::filesystem; ///////////////////////////////////////////////// -bool create_and_switch_to_temp_dir(std::string &_new_temp_path) +class TestTempDirectory : public TempDirectory { - std::string tmppath; - - if (!ignition::common::env("TMPDIR", tmppath)) + public: TestTempDirectory(): + TempDirectory("filesystem", "ign_common", true) { - tmppath = std::string("/tmp"); } +}; - tmppath += "/XXXXXX"; - - char *dtemp = mkdtemp(const_cast(tmppath.c_str())); - if (dtemp == nullptr) - { - return false; - } - if (chdir(dtemp) < 0) +///////////////////////////////////////////////// +bool create_new_empty_file(const std::string &_filename) +{ + try { - return false; + std::fstream fs(_filename, std::ios::out); } - - char resolved[PATH_MAX]; - if (realpath(dtemp, resolved) == nullptr) + catch(...) { return false; } - - _new_temp_path = std::string(resolved); - return true; } ///////////////////////////////////////////////// -bool create_new_empty_file(const std::string &_filename) +bool create_new_file_symlink(const std::string &_symlink, + const std::string &_target) { - int fd = open(_filename.c_str(), O_RDWR | O_CREAT, 0644); - if (fd < 0) + try { + fs::create_symlink(_target, _symlink); + } + catch(const std::exception& e) + { + ignerr << "Failed to create link: " << e.what() << '\n'; return false; } - - close(fd); - return true; } -///////////////////////////////////////////////// -bool create_new_file_symlink(const std::string &_symlink, - const std::string &_target) -{ - return symlink(_target.c_str(), _symlink.c_str()) == 0; -} - ///////////////////////////////////////////////// bool create_new_dir_symlink(const std::string &_symlink, const std::string &_target) { - return symlink(_target.c_str(), _symlink.c_str()) == 0; -} - -///////////////////////////////////////////////// -bool create_new_file_hardlink(const std::string &_hardlink, - const std::string &_target) -{ - return link(_target.c_str(), _hardlink.c_str()) == 0; -} - -#else -#include -#include -#include -#include "PrintWindowsSystemWarning.hh" - -#ifdef IGN_BUILD_SYMLINK_TESTS_ON_WINDOWS -// The symlink tests require special permissions to work on Windows, -// so they will be disabled by default. For more information, see: -// https://github.com/ignitionrobotics/ign-common/issues/21 -#define BUILD_SYMLINK_TESTS -#endif - -///////////////////////////////////////////////// -bool create_and_switch_to_temp_dir(std::string &_new_temp_path) -{ - char temp_path[MAX_PATH + 1]; - DWORD path_len = ::GetTempPathA(MAX_PATH, temp_path); - if (path_len >= MAX_PATH || path_len <= 0) + try { - return false; + fs::create_directory_symlink(_target, _symlink); } - std::string path_to_create(temp_path); - srand(static_cast(time(nullptr))); - - for (int count = 0; count < 50; ++count) + catch(const std::exception& e) { - // Try creating a new temporary directory with a randomly generated name. - // If the one we chose exists, keep trying another path name until we reach - // some limit. - std::string new_dir_name; - new_dir_name.append(std::to_string(::GetCurrentProcessId())); - new_dir_name.push_back('_'); - // On Windows, rand_r() doesn't exist as an alternative to rand(), so the - // cpplint warning is spurious. This program is not multi-threaded, so - // it is safe to suppress the threadsafe_fn warning here. - new_dir_name.append( - std::to_string(rand() // NOLINT(runtime/threadsafe_fn) - % ((int16_t)0x7fff))); - - path_to_create += new_dir_name; - if (::CreateDirectoryA(path_to_create.c_str(), nullptr)) - { - _new_temp_path = path_to_create; - return ::SetCurrentDirectoryA(_new_temp_path.c_str()) != 0; - } + ignerr << "Failed to create link: " << e.what() << '\n'; + return false; } - - return false; + return true; } ///////////////////////////////////////////////// -bool create_new_empty_file(const std::string &_filename) +bool create_new_file_hardlink(const std::string &_hardlink, + const std::string &_target) { - const auto handle = ::CreateFileA(_filename.c_str(), - FILE_READ_DATA, - FILE_SHARE_READ, - nullptr, - OPEN_ALWAYS, - 0, - nullptr); - if (handle != INVALID_HANDLE_VALUE) + try { - ::CloseHandle(handle); - return true; + fs::create_hard_link(_target, _hardlink); } - return false; -} - -///////////////////////////////////////////////// -bool create_new_file_symlink(const std::string &_symlink, - const std::string &_target) -{ - const bool linked = ::CreateSymbolicLinkA( - _symlink.c_str(), _target.c_str(), 0); - - if (!linked) + catch(const std::exception& e) { - ignition::common::PrintWindowsSystemWarning( - "Failed to create file symlink from [" + _target - + "] to [" + _symlink + "]"); - } - - return linked; -} - -///////////////////////////////////////////////// -bool create_new_dir_symlink(const std::string &_symlink, - const std::string &_target) -{ - const bool linked = ::CreateSymbolicLinkA(_symlink.c_str(), _target.c_str(), - SYMBOLIC_LINK_FLAG_DIRECTORY); - if (!linked) - { - ignition::common::PrintWindowsSystemWarning( - "Failed to create directory symlink from [" + _target - + "] to [" + _symlink + "]"); + ignerr << "Failed to create link: " << e.what() << '\n'; + return false; } - - return linked; -} - -///////////////////////////////////////////////// -bool create_new_file_hardlink(const std::string &_hardlink, - const std::string &_target) -{ - return ::CreateHardLinkA(_hardlink.c_str(), _target.c_str(), nullptr) == TRUE; + return true; } -#endif // _WIN32 - -#include // NOLINT -#include "ignition/common/Console.hh" -#include "ignition/common/Filesystem.hh" - -using namespace ignition; -using namespace common; - /// \brief Test Filesystem class FilesystemTest : public ::testing::Test { @@ -223,7 +115,16 @@ class FilesystemTest : public ::testing::Test protected: void SetUp() override { Console::SetVerbosity(4); + this->temp = std::make_unique(); + ASSERT_TRUE(this->temp->Valid()); + } + + protected: void TearDown() override + { + this->temp.reset(); } + + protected: std::unique_ptr temp; }; ///////////////////////////////////////////////// @@ -275,14 +176,20 @@ TEST_F(FilesystemTest, fileOps) EXPECT_EQ(testInContent, test3InContent); - EXPECT_FALSE(common::copyFile("test3.tmp", "test3.tmp")); - EXPECT_FALSE(common::copyFile("test3.tmp", "./test3.tmp")); + // Suppress warnings on the next two, as they are expected to warn when + // trying to copy from/to the same file + EXPECT_FALSE(common::copyFile("test3.tmp", "test3.tmp", + common::FSWO_SUPPRESS_WARNINGS)); + EXPECT_FALSE(common::copyFile("test3.tmp", "./test3.tmp", + common::FSWO_SUPPRESS_WARNINGS)); std::remove("test.tmp"); // This file shouldn't exist, but we'll try to remove just in case the // test failed. - EXPECT_FALSE(common::removeFile("test2.tmp")); + // Suppress warnings since we expect this to be false + EXPECT_FALSE(common::removeFile("test2.tmp", + common::FSWO_SUPPRESS_WARNINGS)); EXPECT_TRUE(common::removeFile("test3.tmp")); @@ -293,27 +200,29 @@ TEST_F(FilesystemTest, fileOps) /// \brief Test file operations TEST_F(FilesystemTest, moreFileOps) { - EXPECT_FALSE(common::copyFile("__wrong__.tmp", "test2.tmp")); - EXPECT_TRUE(!common::exists("test2.tmp")); - EXPECT_FALSE(common::copyFile("test.tmp", "__wrong_dir__/__wrong__.tmp")); - EXPECT_TRUE(!common::exists("__wrong_dir__")); - - EXPECT_FALSE(common::moveFile("__wrong__.tmp", "test3.tmp")); - EXPECT_TRUE(!common::exists("test3.tmp")); - EXPECT_FALSE(common::moveFile("test2.tmp", "__wrong_dir__/__wrong__.tmp")); - EXPECT_TRUE(!common::exists("__wrong_dir__")); + EXPECT_FALSE(common::copyFile("__wrong__.tmp", "test2.tmp", + common::FSWO_SUPPRESS_WARNINGS)); + EXPECT_FALSE(common::exists("test2.tmp")); + EXPECT_FALSE(common::copyFile("test.tmp", "__wrong_dir__/__wrong__.tmp", + common::FSWO_SUPPRESS_WARNINGS)); + EXPECT_FALSE(common::exists("__wrong_dir__")); + + EXPECT_FALSE(common::moveFile("__wrong__.tmp", "test3.tmp", + common::FSWO_SUPPRESS_WARNINGS)); + EXPECT_FALSE(common::exists("test3.tmp")); + EXPECT_FALSE(common::moveFile("test2.tmp", "__wrong_dir__/__wrong__.tmp", + common::FSWO_SUPPRESS_WARNINGS)); + EXPECT_FALSE(common::exists("__wrong_dir__")); } ///////////////////////////////////////////////// TEST_F(FilesystemTest, exists) { - std::string new_temp_dir; - ASSERT_TRUE(create_and_switch_to_temp_dir(new_temp_dir)); ASSERT_TRUE(create_new_empty_file("newfile")); ASSERT_TRUE(createDirectory("fstestexists")); const auto &relativeSubdir = joinPaths("fstestexists", "newfile2"); - const auto &absoluteSubdir = joinPaths(new_temp_dir, relativeSubdir); + const auto &absoluteSubdir = joinPaths(cwd(), relativeSubdir); ASSERT_TRUE(create_new_empty_file(relativeSubdir)); EXPECT_TRUE(exists("fstestexists")); @@ -350,8 +259,6 @@ TEST_F(FilesystemTest, symlink_exists) // 3. symbolic link to existing directory // 4. symbolic link to non-existent directory // 5. hard link to existing file - std::string new_temp_dir; - ASSERT_TRUE(create_and_switch_to_temp_dir(new_temp_dir)); ASSERT_TRUE(create_new_empty_file("newfile")); ASSERT_TRUE(createDirectory("newdir")); @@ -385,11 +292,11 @@ TEST_F(FilesystemTest, cwd) { const auto origCwd = cwd(); - std::string new_temp_dir; - ASSERT_TRUE(create_and_switch_to_temp_dir(new_temp_dir)); + TestTempDirectory new_temp_dir; + ASSERT_TRUE(new_temp_dir.Valid()); std::string path = cwd(); - EXPECT_EQ(path, new_temp_dir); + EXPECT_EQ(path, new_temp_dir.Path()); EXPECT_TRUE(common::chdir(origCwd)); EXPECT_EQ(origCwd, cwd()); @@ -479,20 +386,16 @@ TEST_F(FilesystemTest, parentPath) } ///////////////////////////////////////////////// -TEST_F(FilesystemTest, cwd_error) +TEST_F(FilesystemTest, IGN_UTILS_TEST_DISABLED_ON_WIN32(cwd_error)) { // This test intentionally creates a directory, switches to it, removes // the directory, and then tries to call cwd() on it to cause // cwd() to fail. Windows does not allow you to remove an // in-use directory, so this test is restricted to Unix. -#ifndef _WIN32 - std::string new_temp_dir; - ASSERT_TRUE(create_and_switch_to_temp_dir(new_temp_dir)); - - ASSERT_EQ(rmdir(new_temp_dir.c_str()), 0); - + TestTempDirectory new_temp_dir; + ASSERT_TRUE(new_temp_dir.Valid()); + ASSERT_EQ(rmdir(new_temp_dir.Path().c_str()), 0); EXPECT_EQ(cwd(), ""); -#endif } ///////////////////////////////////////////////// @@ -533,8 +436,6 @@ TEST_F(FilesystemTest, basename) ///////////////////////////////////////////////// TEST_F(FilesystemTest, directory_iterator) { - std::string new_temp_dir; - ASSERT_TRUE(create_and_switch_to_temp_dir(new_temp_dir)); ASSERT_TRUE(create_new_empty_file("newfile")); ASSERT_TRUE(createDirectory("newdir")); #ifdef BUILD_SYMLINK_TESTS @@ -585,9 +486,6 @@ TEST_F(FilesystemTest, directory_iterator) ///////////////////////////////////////////////// TEST_F(FilesystemTest, createDirectories) { - std::string new_temp_dir; - ASSERT_TRUE(create_and_switch_to_temp_dir(new_temp_dir)); - // test creating directories using relative path std::string rel_dir = separator("rel_dir") + "subdir"; ASSERT_TRUE(createDirectories(rel_dir)); @@ -596,7 +494,7 @@ TEST_F(FilesystemTest, createDirectories) // test creating directories using abs path std::string path = cwd(); - EXPECT_EQ(path, new_temp_dir); + EXPECT_EQ(path, this->temp->Path()); std::string abs_dir = separator(cwd()) + separator("abs_dir") + "subdir"; ASSERT_TRUE(createDirectories(abs_dir)); @@ -607,10 +505,6 @@ TEST_F(FilesystemTest, createDirectories) ///////////////////////////////////////////////// TEST_F(FilesystemTest, copyDirectories) { - const auto origCwd = ignition::common::cwd(); - std::string newTempDir; - ASSERT_TRUE(create_and_switch_to_temp_dir(newTempDir)); - // Create an empty directory std::string dirToBeCopied = "dir_to_be_copied"; EXPECT_FALSE(exists(dirToBeCopied)); @@ -657,19 +551,12 @@ TEST_F(FilesystemTest, copyDirectories) EXPECT_TRUE(isDirectory(recDirCopied)); // Non-existent source directory - EXPECT_FALSE(copyDirectory("fake_dir", dirCopied)); - - // Cleanup - ignition::common::chdir(origCwd); - EXPECT_TRUE(removeAll(newTempDir)); + EXPECT_FALSE(copyDirectory("fake_dir", dirCopied, FSWO_SUPPRESS_WARNINGS)); } ///////////////////////////////////////////////// TEST_F(FilesystemTest, uniquePaths) { - std::string newTempDir; - ASSERT_TRUE(create_and_switch_to_temp_dir(newTempDir)); - // Directory std::string dir = "uniqueDirectory"; EXPECT_FALSE(exists(dir));