From b240fb4dd1e557b5ecc40ac9641ce79e92d140ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Lamotte=20=28Klaim=29?= Date: Wed, 10 Aug 2022 18:32:34 +0200 Subject: [PATCH] Added C++ test for detecting filesystem not removing file if readonly (Windows STL bug) --- libmamba/tests/test_filesystem.cpp | 81 ++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) diff --git a/libmamba/tests/test_filesystem.cpp b/libmamba/tests/test_filesystem.cpp index cf3fcf9c2c..f706432bf8 100644 --- a/libmamba/tests/test_filesystem.cpp +++ b/libmamba/tests/test_filesystem.cpp @@ -166,4 +166,85 @@ namespace mamba } #endif + TEST(filesystem, remove_readonly_file) + { + const auto tmp_dir = fs::temp_directory_path() / "mamba-fs-delete-me"; + // NOTE: the following will FAIL if the test doesnt pass (it relies on the tested function) + mamba::on_scope_exit _([&] { fs::remove_all(tmp_dir); }); // Cleanup if not debugging. + fs::create_directories(tmp_dir); + + const auto readonly_file_path = tmp_dir / "fs-readonly-file"; + { + std::ofstream readonly_file{ readonly_file_path.std_path(), + readonly_file.binary | readonly_file.trunc }; + readonly_file << "delete me" << std::endl; + } + + // set to read-only + fs::permissions(readonly_file_path, fs::perms::owner_write, fs::perm_options::remove); + + // removing should still work. + EXPECT_TRUE(fs::exists(readonly_file_path)); + fs::remove(readonly_file_path); + EXPECT_FALSE(fs::exists(readonly_file_path)); + } + + TEST(filesystem, remove_all_readonly_files) + { + const auto tmp_dir = fs::temp_directory_path() / "mamba-fs-delete-me"; + // NOTE: the following will FAIL if the test doesnt pass (it relies on the tested function) + mamba::on_scope_exit _([&] { fs::remove_all(tmp_dir); }); // Cleanup if not debugging. + fs::create_directories(tmp_dir); + + static constexpr int file_count_per_directory = 3; + static constexpr int subdir_count_per_directory = 3; + static constexpr int tree_depth = 3; + + const auto create_readonly_files = [](const fs::u8path& dir_path) + { + assert(fs::is_directory(dir_path)); + for (int file_idx = 0; file_idx < file_count_per_directory; ++file_idx) + { + const auto readonly_file_path + = dir_path / fmt::format("readonly-file-{}", file_idx); + { + std::ofstream readonly_file{ readonly_file_path.std_path(), + readonly_file.binary | readonly_file.trunc }; + readonly_file << "delete me" << std::endl; + } + + // set to read-only + fs::permissions( + readonly_file_path, fs::perms::owner_write, fs::perm_options::remove); + } + }; + + const auto create_subdirs = [&](const std::vector& dirs) + { + auto subdirs = dirs; + for (const auto& dir_path : dirs) + for (int subdir_idx = 0; subdir_idx < subdir_count_per_directory; ++subdir_idx) + { + subdirs.push_back(dir_path / fmt::format("{}", subdir_idx)); + } + return subdirs; + }; + + std::vector dirs{ tmp_dir }; + for (int depth = 0; depth < tree_depth; ++depth) + { + dirs = create_subdirs(dirs); + } + + for (const auto& dir_path : dirs) + { + fs::create_directories(dir_path); + create_readonly_files(dir_path); + } + + EXPECT_TRUE(fs::exists(tmp_dir)); + fs::remove_all(tmp_dir); + EXPECT_FALSE(fs::exists(tmp_dir)); + } + }