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