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
29 using namespace std::experimental::filesystem;
30
31 TEST_SUITE(recursive_directory_iterator_increment_tests)
32
TEST_CASE(test_increment_signatures)33 TEST_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
TEST_CASE(test_prefix_increment)46 TEST_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
TEST_CASE(test_postfix_increment)69 TEST_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
TEST_CASE(test_increment_method)92 TEST_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
TEST_CASE(test_follow_symlinks)116 TEST_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
TEST_CASE(access_denied_on_recursion_test_case)142 TEST_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
240 TEST_SUITE_END()
241