1//===----------------------------------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is dual licensed under the MIT and the University of Illinois Open 6// Source Licenses. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9 10// UNSUPPORTED: c++98, c++03 11 12// <experimental/filesystem> 13 14// class recursive_directory_iterator 15 16// recursive_directory_iterator& operator++(); 17// recursive_directory_iterator& increment(error_code& ec) noexcept; 18 19#include <experimental/filesystem> 20#include <type_traits> 21#include <set> 22#include <cassert> 23 24#include "test_macros.h" 25#include "rapid-cxx-test.hpp" 26#include "filesystem_test_helper.hpp" 27#include <iostream> 28 29using namespace std::experimental::filesystem; 30 31TEST_SUITE(recursive_directory_iterator_increment_tests) 32 33TEST_CASE(test_increment_signatures) 34{ 35 using D = recursive_directory_iterator; 36 recursive_directory_iterator d; ((void)d); 37 std::error_code ec; ((void)ec); 38 39 ASSERT_SAME_TYPE(decltype(++d), recursive_directory_iterator&); 40 ASSERT_NOT_NOEXCEPT(++d); 41 42 ASSERT_SAME_TYPE(decltype(d.increment(ec)), recursive_directory_iterator&); 43 ASSERT_NOEXCEPT(d.increment(ec)); 44} 45 46TEST_CASE(test_prefix_increment) 47{ 48 const path testDir = StaticEnv::Dir; 49 const std::set<path> dir_contents(std::begin(StaticEnv::RecDirIterationList), 50 std::end( StaticEnv::RecDirIterationList)); 51 const recursive_directory_iterator endIt{}; 52 53 std::error_code ec; 54 recursive_directory_iterator it(testDir, ec); 55 TEST_REQUIRE(!ec); 56 57 std::set<path> unseen_entries = dir_contents; 58 while (!unseen_entries.empty()) { 59 TEST_REQUIRE(it != endIt); 60 const path entry = *it; 61 TEST_REQUIRE(unseen_entries.erase(entry) == 1); 62 recursive_directory_iterator& it_ref = ++it; 63 TEST_CHECK(&it_ref == &it); 64 } 65 66 TEST_CHECK(it == endIt); 67} 68 69TEST_CASE(test_postfix_increment) 70{ 71 const path testDir = StaticEnv::Dir; 72 const std::set<path> dir_contents(std::begin(StaticEnv::RecDirIterationList), 73 std::end( StaticEnv::RecDirIterationList)); 74 const recursive_directory_iterator endIt{}; 75 76 std::error_code ec; 77 recursive_directory_iterator it(testDir, ec); 78 TEST_REQUIRE(!ec); 79 80 std::set<path> unseen_entries = dir_contents; 81 while (!unseen_entries.empty()) { 82 TEST_REQUIRE(it != endIt); 83 const path entry = *it; 84 TEST_REQUIRE(unseen_entries.erase(entry) == 1); 85 const path entry2 = *it++; 86 TEST_CHECK(entry2 == entry); 87 } 88 TEST_CHECK(it == endIt); 89} 90 91 92TEST_CASE(test_increment_method) 93{ 94 const path testDir = StaticEnv::Dir; 95 const std::set<path> dir_contents(std::begin(StaticEnv::RecDirIterationList), 96 std::end( StaticEnv::RecDirIterationList)); 97 const recursive_directory_iterator endIt{}; 98 99 std::error_code ec; 100 recursive_directory_iterator it(testDir, ec); 101 TEST_REQUIRE(!ec); 102 103 std::set<path> unseen_entries = dir_contents; 104 while (!unseen_entries.empty()) { 105 TEST_REQUIRE(it != endIt); 106 const path entry = *it; 107 TEST_REQUIRE(unseen_entries.erase(entry) == 1); 108 recursive_directory_iterator& it_ref = it.increment(ec); 109 TEST_REQUIRE(!ec); 110 TEST_CHECK(&it_ref == &it); 111 } 112 113 TEST_CHECK(it == endIt); 114} 115 116TEST_CASE(test_follow_symlinks) 117{ 118 const path testDir = StaticEnv::Dir; 119 auto const& IterList = StaticEnv::RecDirFollowSymlinksIterationList; 120 121 const std::set<path> dir_contents(std::begin(IterList), std::end(IterList)); 122 const recursive_directory_iterator endIt{}; 123 124 std::error_code ec; 125 recursive_directory_iterator it(testDir, 126 directory_options::follow_directory_symlink, ec); 127 TEST_REQUIRE(!ec); 128 129 std::set<path> unseen_entries = dir_contents; 130 while (!unseen_entries.empty()) { 131 TEST_REQUIRE(it != endIt); 132 const path entry = *it; 133 134 TEST_REQUIRE(unseen_entries.erase(entry) == 1); 135 recursive_directory_iterator& it_ref = it.increment(ec); 136 TEST_REQUIRE(!ec); 137 TEST_CHECK(&it_ref == &it); 138 } 139 TEST_CHECK(it == endIt); 140} 141 142TEST_CASE(access_denied_on_recursion_test_case) 143{ 144 using namespace std::experimental::filesystem; 145 scoped_test_env env; 146 const path testFiles[] = { 147 env.create_dir("dir1"), 148 env.create_dir("dir1/dir2"), 149 env.create_file("dir1/dir2/file1"), 150 env.create_file("dir1/file2") 151 }; 152 const path startDir = testFiles[0]; 153 const path permDeniedDir = testFiles[1]; 154 const path otherFile = testFiles[3]; 155 auto SkipEPerm = directory_options::skip_permission_denied; 156 157 // Change the permissions so we can no longer iterate 158 permissions(permDeniedDir, perms::none); 159 160 const recursive_directory_iterator endIt; 161 162 // Test that recursion resulting in a "EACCESS" error is not ignored 163 // by default. 164 { 165 std::error_code ec = GetTestEC(); 166 recursive_directory_iterator it(startDir, ec); 167 TEST_REQUIRE(ec != GetTestEC()); 168 TEST_REQUIRE(!ec); 169 while (it != endIt && it->path() != permDeniedDir) 170 ++it; 171 TEST_REQUIRE(it != endIt); 172 TEST_REQUIRE(*it == permDeniedDir); 173 174 it.increment(ec); 175 TEST_CHECK(ec); 176 TEST_CHECK(it == endIt); 177 } 178 // Same as above but test operator++(). 179 { 180 std::error_code ec = GetTestEC(); 181 recursive_directory_iterator it(startDir, ec); 182 TEST_REQUIRE(!ec); 183 while (it != endIt && it->path() != permDeniedDir) 184 ++it; 185 TEST_REQUIRE(it != endIt); 186 TEST_REQUIRE(*it == permDeniedDir); 187 188 TEST_REQUIRE_THROW(filesystem_error, ++it); 189 } 190 // Test that recursion resulting in a "EACCESS" error is ignored when the 191 // correct options are given to the constructor. 192 { 193 std::error_code ec = GetTestEC(); 194 recursive_directory_iterator it(startDir, SkipEPerm, ec); 195 TEST_REQUIRE(!ec); 196 TEST_REQUIRE(it != endIt); 197 198 bool seenOtherFile = false; 199 if (*it == otherFile) { 200 ++it; 201 seenOtherFile = true; 202 TEST_REQUIRE (it != endIt); 203 } 204 TEST_REQUIRE(*it == permDeniedDir); 205 206 ec = GetTestEC(); 207 it.increment(ec); 208 TEST_REQUIRE(!ec); 209 210 if (seenOtherFile) { 211 TEST_CHECK(it == endIt); 212 } else { 213 TEST_CHECK(it != endIt); 214 TEST_CHECK(*it == otherFile); 215 } 216 } 217 // Test that construction resulting in a "EACCESS" error is not ignored 218 // by default. 219 { 220 std::error_code ec; 221 recursive_directory_iterator it(permDeniedDir, ec); 222 TEST_REQUIRE(ec); 223 TEST_REQUIRE(it == endIt); 224 } 225 // Same as above but testing the throwing constructors 226 { 227 TEST_REQUIRE_THROW(filesystem_error, 228 recursive_directory_iterator(permDeniedDir)); 229 } 230 // Test that construction resulting in a "EACCESS" error constructs the 231 // end iterator when the correct options are given. 232 { 233 std::error_code ec = GetTestEC(); 234 recursive_directory_iterator it(permDeniedDir, SkipEPerm, ec); 235 TEST_REQUIRE(!ec); 236 TEST_REQUIRE(it == endIt); 237 } 238} 239 240TEST_SUITE_END() 241