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++98, 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     std::error_code ec;
63     directory_options opts = directory_options::none;
64     const directory_iterator endIt;
65 
66     const path testPaths[] = { StaticEnv::DNE, StaticEnv::BadSymlink };
67     for (path const& testPath : testPaths)
68     {
69         {
70             directory_iterator it(testPath, ec);
71             TEST_CHECK(ec);
72             TEST_CHECK(it == endIt);
73         }
74         {
75             directory_iterator it(testPath, opts, ec);
76             TEST_CHECK(ec);
77             TEST_CHECK(it == endIt);
78         }
79         {
80             TEST_CHECK_THROW(filesystem_error, directory_iterator(testPath));
81             TEST_CHECK_THROW(filesystem_error, directory_iterator(testPath, opts));
82         }
83     }
84 }
85 
TEST_CASE(access_denied_test_case)86 TEST_CASE(access_denied_test_case)
87 {
88     using namespace fs;
89     scoped_test_env env;
90     path const testDir = env.make_env_path("dir1");
91     path const testFile = testDir / "testFile";
92     env.create_dir(testDir);
93     env.create_file(testFile, 42);
94 
95     // Test that we can iterator over the directory before changing the perms
96     {
97         directory_iterator it(testDir);
98         TEST_REQUIRE(it != directory_iterator{});
99     }
100     // Change the permissions so we can no longer iterate
101     permissions(testDir, perms::none);
102 
103     // Check that the construction fails when skip_permissions_denied is
104     // not given.
105     {
106         std::error_code ec;
107         directory_iterator it(testDir, ec);
108         TEST_REQUIRE(ec);
109         TEST_CHECK(it == directory_iterator{});
110     }
111     // Check that construction does not report an error when
112     // 'skip_permissions_denied' is given.
113     {
114         std::error_code ec;
115         directory_iterator it(testDir, directory_options::skip_permission_denied, ec);
116         TEST_REQUIRE(!ec);
117         TEST_CHECK(it == directory_iterator{});
118     }
119 }
120 
121 
TEST_CASE(access_denied_to_file_test_case)122 TEST_CASE(access_denied_to_file_test_case)
123 {
124     using namespace fs;
125     scoped_test_env env;
126     path const testFile = env.make_env_path("file1");
127     env.create_file(testFile, 42);
128 
129     // Change the permissions so we can no longer iterate
130     permissions(testFile, perms::none);
131 
132     // Check that the construction fails when skip_permissions_denied is
133     // not given.
134     {
135         std::error_code ec;
136         directory_iterator it(testFile, ec);
137         TEST_REQUIRE(ec);
138         TEST_CHECK(it == directory_iterator{});
139     }
140     // Check that construction still fails when 'skip_permissions_denied' is given
141     // because we tried to open a file and not a directory.
142     {
143         std::error_code ec;
144         directory_iterator it(testFile, directory_options::skip_permission_denied, ec);
145         TEST_REQUIRE(ec);
146         TEST_CHECK(it == directory_iterator{});
147     }
148 }
149 
TEST_CASE(test_open_on_empty_directory_equals_end)150 TEST_CASE(test_open_on_empty_directory_equals_end)
151 {
152     scoped_test_env env;
153     const path testDir = env.make_env_path("dir1");
154     env.create_dir(testDir);
155 
156     const directory_iterator endIt;
157     {
158         std::error_code ec;
159         directory_iterator it(testDir, ec);
160         TEST_CHECK(!ec);
161         TEST_CHECK(it == endIt);
162     }
163     {
164         directory_iterator it(testDir);
165         TEST_CHECK(it == endIt);
166     }
167 }
168 
TEST_CASE(test_open_on_directory_succeeds)169 TEST_CASE(test_open_on_directory_succeeds)
170 {
171     const path testDir = StaticEnv::Dir;
172     std::set<path> dir_contents(std::begin(StaticEnv::DirIterationList),
173                                 std::end(  StaticEnv::DirIterationList));
174     const directory_iterator endIt{};
175 
176     {
177         std::error_code ec;
178         directory_iterator it(testDir, ec);
179         TEST_REQUIRE(!ec);
180         TEST_CHECK(it != endIt);
181         TEST_CHECK(dir_contents.count(*it));
182     }
183     {
184         directory_iterator it(testDir);
185         TEST_CHECK(it != endIt);
186         TEST_CHECK(dir_contents.count(*it));
187     }
188 }
189 
TEST_CASE(test_open_on_file_fails)190 TEST_CASE(test_open_on_file_fails)
191 {
192     const path testFile = StaticEnv::File;
193     const directory_iterator endIt{};
194     {
195         std::error_code ec;
196         directory_iterator it(testFile, ec);
197         TEST_REQUIRE(ec);
198         TEST_CHECK(it == endIt);
199     }
200     {
201         TEST_CHECK_THROW(filesystem_error, directory_iterator(testFile));
202     }
203 }
204 
TEST_CASE(test_open_on_empty_string)205 TEST_CASE(test_open_on_empty_string)
206 {
207     const path testPath = "";
208     const directory_iterator endIt{};
209 
210     std::error_code ec;
211     directory_iterator it(testPath, ec);
212     TEST_CHECK(ec);
213     TEST_CHECK(it == endIt);
214 }
215 
TEST_CASE(test_open_on_dot_dir)216 TEST_CASE(test_open_on_dot_dir)
217 {
218     const path testPath = ".";
219 
220     std::error_code ec;
221     directory_iterator it(testPath, ec);
222     TEST_CHECK(!ec);
223 }
224 
TEST_CASE(test_open_on_symlink)225 TEST_CASE(test_open_on_symlink)
226 {
227     const path symlinkToDir = StaticEnv::SymlinkToDir;
228     std::set<path> dir_contents;
229     for (path const& p : StaticEnv::DirIterationList) {
230         dir_contents.insert(p.filename());
231     }
232     const directory_iterator endIt{};
233 
234     {
235         std::error_code ec;
236         directory_iterator it(symlinkToDir, ec);
237         TEST_REQUIRE(!ec);
238         TEST_CHECK(it != endIt);
239         path const& entry = *it;
240         TEST_CHECK(dir_contents.count(entry.filename()));
241     }
242     {
243         std::error_code ec;
244         directory_iterator it(symlinkToDir,
245                               directory_options::follow_directory_symlink, ec);
246         TEST_REQUIRE(!ec);
247         TEST_CHECK(it != endIt);
248         path const& entry = *it;
249         TEST_CHECK(dir_contents.count(entry.filename()));
250     }
251 }
252 
253 TEST_SUITE_END()
254