Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / libcxx / test / std / input.output / filesystems / class.rec.dir.itr / rec.dir.itr.members / increment.pass.cpp
blob244f6a295fedfc78f6aef44af716e70a05a77de0
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-exception
6 //
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03
10 // UNSUPPORTED: no-filesystem
11 // UNSUPPORTED: availability-filesystem-missing
13 // On Android L, ~scoped_test_env() is unable to delete the temp dir using
14 // chmod+rm because chmod is too broken.
15 // XFAIL: LIBCXX-ANDROID-FIXME && android-device-api={{21|22}}
17 // <filesystem>
19 // class recursive_directory_iterator
21 // recursive_directory_iterator& operator++();
22 // recursive_directory_iterator& increment(error_code& ec) noexcept;
24 #include "filesystem_include.h"
25 #include <type_traits>
26 #include <set>
27 #include <cassert>
29 #include "assert_macros.h"
30 #include "test_macros.h"
31 #include "filesystem_test_helper.h"
33 using namespace fs;
35 static void test_increment_signatures()
37 recursive_directory_iterator d; ((void)d);
38 std::error_code ec; ((void)ec);
40 ASSERT_SAME_TYPE(decltype(++d), recursive_directory_iterator&);
41 ASSERT_NOT_NOEXCEPT(++d);
43 ASSERT_SAME_TYPE(decltype(d.increment(ec)), recursive_directory_iterator&);
44 ASSERT_NOT_NOEXCEPT(d.increment(ec));
47 static void test_prefix_increment()
49 static_test_env static_env;
50 const path testDir = static_env.Dir;
51 const std::set<path> dir_contents(static_env.RecDirIterationList.begin(),
52 static_env.RecDirIterationList.end());
53 const recursive_directory_iterator endIt{};
55 std::error_code ec;
56 recursive_directory_iterator it(testDir, ec);
57 assert(!ec);
59 std::set<path> unseen_entries = dir_contents;
60 while (!unseen_entries.empty()) {
61 assert(it != endIt);
62 const path entry = *it;
63 assert(unseen_entries.erase(entry) == 1);
64 recursive_directory_iterator& it_ref = ++it;
65 assert(&it_ref == &it);
68 assert(it == endIt);
71 static void test_postfix_increment()
73 static_test_env static_env;
74 const path testDir = static_env.Dir;
75 const std::set<path> dir_contents(static_env.RecDirIterationList.begin(),
76 static_env.RecDirIterationList.end());
77 const recursive_directory_iterator endIt{};
79 std::error_code ec;
80 recursive_directory_iterator it(testDir, ec);
81 assert(!ec);
83 std::set<path> unseen_entries = dir_contents;
84 while (!unseen_entries.empty()) {
85 assert(it != endIt);
86 const path entry = *it;
87 assert(unseen_entries.erase(entry) == 1);
88 const path entry2 = *it++;
89 assert(entry2 == entry);
91 assert(it == endIt);
95 static void test_increment_method()
97 static_test_env static_env;
98 const path testDir = static_env.Dir;
99 const std::set<path> dir_contents(static_env.RecDirIterationList.begin(),
100 static_env.RecDirIterationList.end());
101 const recursive_directory_iterator endIt{};
103 std::error_code ec;
104 recursive_directory_iterator it(testDir, ec);
105 assert(!ec);
107 std::set<path> unseen_entries = dir_contents;
108 while (!unseen_entries.empty()) {
109 assert(it != endIt);
110 const path entry = *it;
111 assert(unseen_entries.erase(entry) == 1);
112 recursive_directory_iterator& it_ref = it.increment(ec);
113 assert(!ec);
114 assert(&it_ref == &it);
117 assert(it == endIt);
120 static void test_follow_symlinks()
122 static_test_env static_env;
123 const path testDir = static_env.Dir;
124 auto const& IterList = static_env.RecDirFollowSymlinksIterationList;
126 const std::set<path> dir_contents(IterList.begin(), IterList.end());
127 const recursive_directory_iterator endIt{};
129 std::error_code ec;
130 recursive_directory_iterator it(testDir,
131 directory_options::follow_directory_symlink, ec);
132 assert(!ec);
134 std::set<path> unseen_entries = dir_contents;
135 while (!unseen_entries.empty()) {
136 assert(it != endIt);
137 const path entry = *it;
139 assert(unseen_entries.erase(entry) == 1);
140 recursive_directory_iterator& it_ref = it.increment(ec);
141 assert(!ec);
142 assert(&it_ref == &it);
144 assert(it == endIt);
147 // Windows doesn't support setting perms::none to trigger failures
148 // reading directories.
149 #ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE
150 static void access_denied_on_recursion_test_case()
152 using namespace fs;
153 scoped_test_env env;
154 const path testFiles[] = {
155 env.create_dir("dir1"),
156 env.create_dir("dir1/dir2"),
157 env.create_file("dir1/dir2/file1"),
158 env.create_file("dir1/file2")
160 const path startDir = testFiles[0];
161 const path permDeniedDir = testFiles[1];
162 const path otherFile = testFiles[3];
163 auto SkipEPerm = directory_options::skip_permission_denied;
165 // Change the permissions so we can no longer iterate
166 permissions(permDeniedDir, perms::none);
168 const recursive_directory_iterator endIt;
170 // Test that recursion resulting in a "EACCESS" error is not ignored
171 // by default.
173 std::error_code ec = GetTestEC();
174 recursive_directory_iterator it(startDir, ec);
175 assert(ec != GetTestEC());
176 assert(!ec);
177 while (it != endIt && it->path() != permDeniedDir)
178 ++it;
179 assert(it != endIt);
180 assert(*it == permDeniedDir);
182 it.increment(ec);
183 assert(ec);
184 assert(it == endIt);
186 // Same as above but test operator++().
188 std::error_code ec = GetTestEC();
189 recursive_directory_iterator it(startDir, ec);
190 assert(!ec);
191 while (it != endIt && it->path() != permDeniedDir)
192 ++it;
193 assert(it != endIt);
194 assert(*it == permDeniedDir);
196 TEST_THROWS_TYPE(filesystem_error, ++it);
198 // Test that recursion resulting in a "EACCESS" error is ignored when the
199 // correct options are given to the constructor.
201 std::error_code ec = GetTestEC();
202 recursive_directory_iterator it(startDir, SkipEPerm, ec);
203 assert(!ec);
204 assert(it != endIt);
206 bool seenOtherFile = false;
207 if (*it == otherFile) {
208 ++it;
209 seenOtherFile = true;
210 assert (it != endIt);
212 assert(*it == permDeniedDir);
214 ec = GetTestEC();
215 it.increment(ec);
216 assert(!ec);
218 if (seenOtherFile) {
219 assert(it == endIt);
220 } else {
221 assert(it != endIt);
222 assert(*it == otherFile);
225 // Test that construction resulting in a "EACCESS" error is not ignored
226 // by default.
228 std::error_code ec;
229 recursive_directory_iterator it(permDeniedDir, ec);
230 assert(ec);
231 assert(it == endIt);
233 // Same as above but testing the throwing constructors
235 TEST_THROWS_TYPE(filesystem_error,
236 recursive_directory_iterator(permDeniedDir));
238 // Test that construction resulting in a "EACCESS" error constructs the
239 // end iterator when the correct options are given.
241 std::error_code ec = GetTestEC();
242 recursive_directory_iterator it(permDeniedDir, SkipEPerm, ec);
243 assert(!ec);
244 assert(it == endIt);
248 // See llvm.org/PR35078
249 static void test_PR35078()
251 using namespace fs;
252 scoped_test_env env;
253 const path testFiles[] = {
254 env.create_dir("dir1"),
255 env.create_dir("dir1/dir2"),
256 env.create_dir("dir1/dir2/dir3"),
257 env.create_file("dir1/file1"),
258 env.create_file("dir1/dir2/dir3/file2")
260 const path startDir = testFiles[0];
261 const path permDeniedDir = testFiles[1];
262 const path nestedDir = testFiles[2];
263 const path nestedFile = testFiles[3];
265 // Change the permissions so we can no longer iterate
266 permissions(permDeniedDir,
267 perms::group_exec|perms::owner_exec|perms::others_exec,
268 perm_options::remove);
270 const std::errc eacess = std::errc::permission_denied;
271 std::error_code ec = GetTestEC();
273 const recursive_directory_iterator endIt;
275 auto SetupState = [&](bool AllowEAccess, bool& SeenFile3) {
276 SeenFile3 = false;
277 auto Opts = AllowEAccess ? directory_options::skip_permission_denied
278 : directory_options::none;
279 recursive_directory_iterator it(startDir, Opts, ec);
280 while (!ec && it != endIt && *it != nestedDir) {
281 if (*it == nestedFile)
282 SeenFile3 = true;
283 it.increment(ec);
285 return it;
289 bool SeenNestedFile = false;
290 recursive_directory_iterator it = SetupState(false, SeenNestedFile);
291 assert(it != endIt);
292 assert(*it == nestedDir);
293 ec = GetTestEC();
294 it.increment(ec);
295 assert(ec);
296 assert(ErrorIs(ec, eacess));
297 assert(it == endIt);
300 bool SeenNestedFile = false;
301 recursive_directory_iterator it = SetupState(true, SeenNestedFile);
302 assert(it != endIt);
303 assert(*it == nestedDir);
304 ec = GetTestEC();
305 it.increment(ec);
306 assert(!ec);
307 if (SeenNestedFile) {
308 assert(it == endIt);
309 } else {
310 assert(it != endIt);
311 assert(*it == nestedFile);
315 bool SeenNestedFile = false;
316 recursive_directory_iterator it = SetupState(false, SeenNestedFile);
317 assert(it != endIt);
318 assert(*it == nestedDir);
320 ExceptionChecker Checker(std::errc::permission_denied,
321 "recursive_directory_iterator::operator++()",
322 format_string("attempting recursion into \"%s\"",
323 nestedDir.string().c_str()));
324 TEST_VALIDATE_EXCEPTION(filesystem_error, Checker, ++it);
329 // See llvm.org/PR35078
330 static void test_PR35078_with_symlink()
332 using namespace fs;
333 scoped_test_env env;
334 const path testFiles[] = {
335 env.create_dir("dir1"),
336 env.create_file("dir1/file1"),
337 env.create_dir("sym_dir"),
338 env.create_dir("sym_dir/nested_sym_dir"),
339 env.create_directory_symlink("sym_dir/nested_sym_dir", "dir1/dir2"),
340 env.create_dir("sym_dir/dir1"),
341 env.create_dir("sym_dir/dir1/dir2"),
344 // const unsigned TestFilesSize = sizeof(testFiles) / sizeof(testFiles[0]);
345 const path startDir = testFiles[0];
346 const path nestedFile = testFiles[1];
347 const path permDeniedDir = testFiles[2];
348 const path symDir = testFiles[4];
350 // Change the permissions so we can no longer iterate
351 permissions(permDeniedDir,
352 perms::group_exec|perms::owner_exec|perms::others_exec,
353 perm_options::remove);
355 const std::errc eacess = std::errc::permission_denied;
356 std::error_code ec = GetTestEC();
358 const recursive_directory_iterator endIt;
360 auto SetupState = [&](bool AllowEAccess, bool FollowSym, bool& SeenFile3) {
361 SeenFile3 = false;
362 auto Opts = AllowEAccess ? directory_options::skip_permission_denied
363 : directory_options::none;
364 if (FollowSym)
365 Opts |= directory_options::follow_directory_symlink;
366 recursive_directory_iterator it(startDir, Opts, ec);
367 while (!ec && it != endIt && *it != symDir) {
368 if (*it == nestedFile)
369 SeenFile3 = true;
370 it.increment(ec);
372 return it;
375 struct {
376 bool SkipPermDenied;
377 bool FollowSymlinks;
378 bool ExpectSuccess;
379 } TestCases[] = {
380 // Passing cases
381 {false, false, true}, {true, true, true}, {true, false, true},
382 // Failing cases
383 {false, true, false}
385 for (auto TC : TestCases) {
386 bool SeenNestedFile = false;
387 recursive_directory_iterator it = SetupState(TC.SkipPermDenied,
388 TC.FollowSymlinks,
389 SeenNestedFile);
390 assert(!ec);
391 assert(it != endIt);
392 assert(*it == symDir);
393 ec = GetTestEC();
394 it.increment(ec);
395 if (TC.ExpectSuccess) {
396 assert(!ec);
397 if (SeenNestedFile) {
398 assert(it == endIt);
399 } else {
400 assert(it != endIt);
401 assert(*it == nestedFile);
403 } else {
404 assert(ec);
405 assert(ErrorIs(ec, eacess));
406 assert(it == endIt);
412 // See llvm.org/PR35078
413 static void test_PR35078_with_symlink_file()
415 using namespace fs;
416 scoped_test_env env;
417 const path testFiles[] = {
418 env.create_dir("dir1"),
419 env.create_dir("dir1/dir2"),
420 env.create_file("dir1/file2"),
421 env.create_dir("sym_dir"),
422 env.create_dir("sym_dir/sdir1"),
423 env.create_file("sym_dir/sdir1/sfile1"),
424 env.create_symlink("sym_dir/sdir1/sfile1", "dir1/dir2/file1")
426 const unsigned TestFilesSize = sizeof(testFiles) / sizeof(testFiles[0]);
427 const path startDir = testFiles[0];
428 const path nestedDir = testFiles[1];
429 const path nestedFile = testFiles[2];
430 const path permDeniedDir = testFiles[3];
431 const path symFile = testFiles[TestFilesSize - 1];
433 // Change the permissions so we can no longer iterate
434 permissions(permDeniedDir,
435 perms::group_exec|perms::owner_exec|perms::others_exec,
436 perm_options::remove);
438 const std::errc eacess = std::errc::permission_denied;
439 std::error_code ec = GetTestEC();
441 const recursive_directory_iterator EndIt;
443 auto SetupState = [&](bool AllowEAccess, bool FollowSym, bool& SeenNestedFile) {
444 SeenNestedFile = false;
445 auto Opts = AllowEAccess ? directory_options::skip_permission_denied
446 : directory_options::none;
447 if (FollowSym)
448 Opts |= directory_options::follow_directory_symlink;
449 recursive_directory_iterator it(startDir, Opts, ec);
450 while (!ec && it != EndIt && *it != nestedDir) {
451 if (*it == nestedFile)
452 SeenNestedFile = true;
453 it.increment(ec);
455 return it;
458 struct {
459 bool SkipPermDenied;
460 bool FollowSymlinks;
461 bool ExpectSuccess;
462 } TestCases[] = {
463 // Passing cases
464 {false, false, true}, {true, true, true}, {true, false, true},
465 // Failing cases
466 {false, true, false}
468 for (auto TC : TestCases){
469 bool SeenNestedFile = false;
470 recursive_directory_iterator it = SetupState(TC.SkipPermDenied,
471 TC.FollowSymlinks,
472 SeenNestedFile);
473 assert(!ec);
474 assert(it != EndIt);
475 assert(*it == nestedDir);
476 ec = GetTestEC();
477 it.increment(ec);
478 assert(it != EndIt);
479 assert(!ec);
480 assert(*it == symFile);
481 ec = GetTestEC();
482 it.increment(ec);
483 if (TC.ExpectSuccess) {
484 if (!SeenNestedFile) {
485 assert(!ec);
486 assert(it != EndIt);
487 assert(*it == nestedFile);
488 ec = GetTestEC();
489 it.increment(ec);
491 assert(!ec);
492 assert(it == EndIt);
493 } else {
494 assert(ec);
495 assert(ErrorIs(ec, eacess));
496 assert(it == EndIt);
500 #endif // TEST_WIN_NO_FILESYSTEM_PERMS_NONE
502 int main(int, char**) {
503 test_increment_signatures();
504 test_prefix_increment();
505 test_postfix_increment();
506 test_increment_method();
507 test_follow_symlinks();
508 #ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE
509 access_denied_on_recursion_test_case();
510 test_PR35078();
511 test_PR35078_with_symlink();
512 test_PR35078_with_symlink_file();
513 #endif
515 return 0;