brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.6 KiB · c11c7fb Raw
187 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9// REQUIRES: can-create-symlinks10// UNSUPPORTED: c++03, c++11, c++1411// UNSUPPORTED: no-filesystem12 13// <filesystem>14 15// recursive_directory_iterator16 17#include <filesystem>18#include <type_traits>19#include <set>20#include <cassert>21 22#include "test_macros.h"23#include "filesystem_test_helper.h"24namespace fs = std::filesystem;25 26#if defined(_WIN32)27static void set_last_write_time_in_iteration(const fs::path& dir) {28  // Windows can postpone updating last write time for file especially for29  // directory because last write time of directory depends of its childs.30  // See31  // https://learn.microsoft.com/en-us/windows/win32/sysinfo/file-times32  // To force updating file entries calls "last_write_time" with own value.33  const fs::recursive_directory_iterator end_it{};34 35  std::error_code ec;36  fs::recursive_directory_iterator it(dir, ec);37  assert(!ec);38 39  fs::file_time_type now_time = fs::file_time_type::clock::now();40  for (; it != end_it; ++it) {41    const fs::path entry = *it;42    fs::last_write_time(entry, now_time, ec);43    assert(!ec);44  }45 46  assert(it == end_it);47}48 49struct directory_entry_and_values {50  fs::directory_entry entry;51 52  fs::file_status symlink_status;53  fs::file_status status;54  std::uintmax_t file_size;55  fs::file_time_type last_write_time;56};57 58std::vector<directory_entry_and_values>59get_directory_entries_for(const fs::path& dir, const std::set<fs::path>& dir_contents) {60  const fs::recursive_directory_iterator end_it{};61 62  std::error_code ec;63  fs::recursive_directory_iterator it(dir, ec);64  assert(!ec);65 66  std::vector<directory_entry_and_values> dir_entries;67  std::set<fs::path> unseen_entries = dir_contents;68  while (!unseen_entries.empty()) {69    assert(it != end_it);70    const fs::directory_entry& entry = *it;71 72    assert(unseen_entries.erase(entry.path()) == 1);73 74    dir_entries.push_back(directory_entry_and_values{75        .entry           = entry,76        .symlink_status  = entry.symlink_status(),77        .status          = entry.status(),78        .file_size       = entry.is_regular_file() ? entry.file_size() : 0,79        .last_write_time = entry.last_write_time()});80 81    fs::recursive_directory_iterator& it_ref = it.increment(ec);82    assert(!ec);83    assert(&it_ref == &it);84  }85  return dir_entries;86}87#endif // _WIN3288 89// Checks that the directory_entry properties will be the same before and after90// calling "refresh" in case of iteration.91// In case of Windows expects that directory_entry caches the properties during92// iteration.93static void test_cache_and_refresh_in_iteration() {94  static_test_env static_env;95  const fs::path test_dir = static_env.Dir;96#if defined(_WIN32)97  set_last_write_time_in_iteration(test_dir);98#endif99  const std::set<fs::path> dir_contents(static_env.RecDirIterationList.begin(), static_env.RecDirIterationList.end());100  const fs::recursive_directory_iterator end_it{};101 102  std::error_code ec;103  fs::recursive_directory_iterator it(test_dir, ec);104  assert(!ec);105 106  std::set<fs::path> unseen_entries = dir_contents;107  while (!unseen_entries.empty()) {108    assert(it != end_it);109    const fs::directory_entry& entry = *it;110 111    assert(unseen_entries.erase(entry.path()) == 1);112 113    fs::file_status symlink_status     = entry.symlink_status();114    fs::file_status status             = entry.status();115    std::uintmax_t file_size           = entry.is_regular_file() ? entry.file_size() : 0;116    fs::file_time_type last_write_time = entry.last_write_time();117 118    fs::directory_entry mutable_entry = *it;119    mutable_entry.refresh();120    fs::file_status upd_symlink_status     = mutable_entry.symlink_status();121    fs::file_status upd_status             = mutable_entry.status();122    std::uintmax_t upd_file_size           = mutable_entry.is_regular_file() ? mutable_entry.file_size() : 0;123    fs::file_time_type upd_last_write_time = mutable_entry.last_write_time();124    assert(upd_symlink_status.type() == symlink_status.type() &&125           upd_symlink_status.permissions() == symlink_status.permissions());126    assert(upd_status.type() == status.type() && upd_status.permissions() == status.permissions());127    assert(upd_file_size == file_size);128    assert(upd_last_write_time == last_write_time);129 130    fs::recursive_directory_iterator& it_ref = it.increment(ec);131    assert(!ec);132    assert(&it_ref == &it);133  }134}135 136#if defined(_WIN32)137// In case of Windows expects that the directory_entry caches the properties138// during iteration and the properties don't change after deleting folders139// and files.140static void test_cached_values_in_iteration() {141  std::vector<directory_entry_and_values> dir_entries;142  {143    static_test_env static_env;144    const fs::path testDir = static_env.Dir;145    set_last_write_time_in_iteration(testDir);146    const std::set<fs::path> dir_contents(static_env.RecDirIterationList.begin(), static_env.RecDirIterationList.end());147    dir_entries = get_directory_entries_for(testDir, dir_contents);148  }149  // Testing folder should be deleted after destroying static_test_env.150 151  for (const auto& dir_entry : dir_entries) {152    // During iteration Windows provides information only about symlink itself153    // not about file/folder which symlink points to.154    if (dir_entry.entry.is_symlink()) {155      // Check that symlink is not using cached value about existing file.156      assert(!dir_entry.entry.exists());157    } else {158      // Check that entry uses cached value about existing file.159      assert(dir_entry.entry.exists());160    }161    fs::file_status symlink_status = dir_entry.entry.symlink_status();162    assert(dir_entry.symlink_status.type() == symlink_status.type() &&163           dir_entry.symlink_status.permissions() == symlink_status.permissions());164 165    if (!dir_entry.entry.is_symlink()) {166      fs::file_status status = dir_entry.entry.status();167      assert(dir_entry.status.type() == status.type() && dir_entry.status.permissions() == status.permissions());168 169      std::uintmax_t file_size = dir_entry.entry.is_regular_file() ? dir_entry.entry.file_size() : 0;170      assert(dir_entry.file_size == file_size);171 172      fs::file_time_type last_write_time = dir_entry.entry.last_write_time();173      assert(dir_entry.last_write_time == last_write_time);174    }175  }176}177#endif // _WIN32178 179int main(int, char**) {180  test_cache_and_refresh_in_iteration();181#if defined(_WIN32)182  test_cached_values_in_iteration();183#endif184 185  return 0;186}187