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