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"
32namespace fs = std::filesystem;
33using namespace fs;
34
35using RDI = recursive_directory_iterator;
36
37static 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
61static 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
88static 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(p: testDir, prms: 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
134static 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(p: testFile, prms: 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
172static 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
191static 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
213static 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
229static 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
269int 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

source code of libcxx/test/std/input.output/filesystems/class.rec.dir.itr/rec.dir.itr.members/ctor.pass.cpp