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 //===----------------------------------------------------------------------===//
8
9 // REQUIRES: can-create-symlinks
10 // UNSUPPORTED: c++03, c++11, c++14
11 // UNSUPPORTED: no-filesystem
12 // UNSUPPORTED: availability-filesystem-missing
13
14 // <filesystem>
15
16 // class directory_iterator
17
18 //
19 // explicit recursive_directory_iterator(const path& p);
20 // recursive_directory_iterator(const path& p, directory_options options);
21 // recursive_directory_iterator(const path& p, error_code& ec);
22 // recursive_directory_iterator(const path& p, directory_options options, error_code& ec);
23
24 #include <filesystem>
25 #include <type_traits>
26 #include <set>
27 #include <cassert>
28
29 #include "assert_macros.h"
30 #include "test_macros.h"
31 #include "filesystem_test_helper.h"
32 namespace fs = std::filesystem;
33 using namespace fs;
34
35 using RDI = recursive_directory_iterator;
36
test_constructor_signatures()37 static void test_constructor_signatures()
38 {
39 using D = recursive_directory_iterator;
40
41 // explicit directory_iterator(path const&);
42 static_assert(!std::is_convertible<path, D>::value, "");
43 static_assert(std::is_constructible<D, path>::value, "");
44 static_assert(!std::is_nothrow_constructible<D, path>::value, "");
45
46 // directory_iterator(path const&, error_code&)
47 static_assert(std::is_constructible<D, path,
48 std::error_code&>::value, "");
49 static_assert(!std::is_nothrow_constructible<D, path,
50 std::error_code&>::value, "");
51
52 // directory_iterator(path const&, directory_options);
53 static_assert(std::is_constructible<D, path, directory_options>::value, "");
54 static_assert(!std::is_nothrow_constructible<D, path, directory_options>::value, "");
55
56 // directory_iterator(path const&, directory_options, error_code&)
57 static_assert(std::is_constructible<D, path, directory_options, std::error_code&>::value, "");
58 static_assert(!std::is_nothrow_constructible<D, path, directory_options, std::error_code&>::value, "");
59 }
60
test_construction_from_bad_path()61 static void test_construction_from_bad_path()
62 {
63 static_test_env static_env;
64 std::error_code ec;
65 directory_options opts = directory_options::none;
66 const RDI endIt;
67
68 const path testPaths[] = { static_env.DNE, static_env.BadSymlink };
69 for (path const& testPath : testPaths)
70 {
71 {
72 RDI it(testPath, ec);
73 assert(ec);
74 assert(it == endIt);
75 }
76 {
77 RDI it(testPath, opts, ec);
78 assert(ec);
79 assert(it == endIt);
80 }
81 {
82 TEST_THROWS_TYPE(filesystem_error, RDI(testPath));
83 TEST_THROWS_TYPE(filesystem_error, RDI(testPath, opts));
84 }
85 }
86 }
87
access_denied_test_case()88 static void access_denied_test_case()
89 {
90 using namespace fs;
91 #ifdef _WIN32
92 // Windows doesn't support setting perms::none to trigger failures
93 // reading directories; test using a special inaccessible directory
94 // instead.
95 const path testDir = GetWindowsInaccessibleDir();
96 if (testDir.empty())
97 return;
98 #else
99 scoped_test_env env;
100 path const testDir = env.make_env_path("dir1");
101 path const testFile = testDir / "testFile";
102 env.create_dir(testDir);
103 env.create_file(testFile, 42);
104
105 // Test that we can iterator over the directory before changing the perms
106 {
107 RDI it(testDir);
108 assert(it != RDI{});
109 }
110
111 // Change the permissions so we can no longer iterate
112 permissions(testDir, perms::none);
113 #endif
114
115 // Check that the construction fails when skip_permissions_denied is
116 // not given.
117 {
118 std::error_code ec;
119 RDI it(testDir, ec);
120 assert(ec);
121 assert(it == RDI{});
122 }
123 // Check that construction does not report an error when
124 // 'skip_permissions_denied' is given.
125 {
126 std::error_code ec;
127 RDI it(testDir, directory_options::skip_permission_denied, ec);
128 assert(!ec);
129 assert(it == RDI{});
130 }
131 }
132
133
access_denied_to_file_test_case()134 static void access_denied_to_file_test_case()
135 {
136 using namespace fs;
137 #ifdef _WIN32
138 // Windows doesn't support setting perms::none to trigger failures
139 // reading directories; test using a special inaccessible directory
140 // instead.
141 const path testDir = GetWindowsInaccessibleDir();
142 if (testDir.empty())
143 return;
144 path const testFile = testDir / "inaccessible_file";
145 #else
146 scoped_test_env env;
147 path const testFile = env.make_env_path("file1");
148 env.create_file(testFile, 42);
149
150 // Change the permissions so we can no longer iterate
151 permissions(testFile, perms::none);
152 #endif
153
154 // Check that the construction fails when skip_permissions_denied is
155 // not given.
156 {
157 std::error_code ec;
158 RDI it(testFile, ec);
159 assert(ec);
160 assert(it == RDI{});
161 }
162 // Check that construction still fails when 'skip_permissions_denied' is given
163 // because we tried to open a file and not a directory.
164 {
165 std::error_code ec;
166 RDI it(testFile, directory_options::skip_permission_denied, ec);
167 assert(ec);
168 assert(it == RDI{});
169 }
170 }
171
test_open_on_empty_directory_equals_end()172 static void test_open_on_empty_directory_equals_end()
173 {
174 scoped_test_env env;
175 const path testDir = env.make_env_path("dir1");
176 env.create_dir(testDir);
177
178 const RDI endIt;
179 {
180 std::error_code ec;
181 RDI it(testDir, ec);
182 assert(!ec);
183 assert(it == endIt);
184 }
185 {
186 RDI it(testDir);
187 assert(it == endIt);
188 }
189 }
190
test_open_on_directory_succeeds()191 static void test_open_on_directory_succeeds()
192 {
193 static_test_env static_env;
194 const path testDir = static_env.Dir;
195 std::set<path> dir_contents(static_env.DirIterationList.begin(),
196 static_env.DirIterationList.end());
197 const RDI endIt{};
198
199 {
200 std::error_code ec;
201 RDI it(testDir, ec);
202 assert(!ec);
203 assert(it != endIt);
204 assert(dir_contents.count(*it));
205 }
206 {
207 RDI it(testDir);
208 assert(it != endIt);
209 assert(dir_contents.count(*it));
210 }
211 }
212
test_open_on_file_fails()213 static void test_open_on_file_fails()
214 {
215 static_test_env static_env;
216 const path testFile = static_env.File;
217 const RDI endIt{};
218 {
219 std::error_code ec;
220 RDI it(testFile, ec);
221 assert(ec);
222 assert(it == endIt);
223 }
224 {
225 TEST_THROWS_TYPE(filesystem_error, RDI(testFile));
226 }
227 }
228
test_options_post_conditions()229 static void test_options_post_conditions()
230 {
231 static_test_env static_env;
232 const path goodDir = static_env.Dir;
233 const path badDir = static_env.DNE;
234
235 {
236 std::error_code ec;
237
238 RDI it1(goodDir, ec);
239 assert(!ec);
240 assert(it1.options() == directory_options::none);
241
242 RDI it2(badDir, ec);
243 assert(ec);
244 assert(it2 == RDI{});
245 }
246 {
247 std::error_code ec;
248 const directory_options opts = directory_options::skip_permission_denied;
249
250 RDI it1(goodDir, opts, ec);
251 assert(!ec);
252 assert(it1.options() == opts);
253
254 RDI it2(badDir, opts, ec);
255 assert(ec);
256 assert(it2 == RDI{});
257 }
258 {
259 RDI it(goodDir);
260 assert(it.options() == directory_options::none);
261 }
262 {
263 const directory_options opts = directory_options::follow_directory_symlink;
264 RDI it(goodDir, opts);
265 assert(it.options() == opts);
266 }
267 }
268
main(int,char **)269 int main(int, char**) {
270 test_constructor_signatures();
271 test_construction_from_bad_path();
272 access_denied_test_case();
273 access_denied_to_file_test_case();
274 test_open_on_empty_directory_equals_end();
275 test_open_on_directory_succeeds();
276 test_open_on_file_fails();
277 test_options_post_conditions();
278
279 return 0;
280 }
281