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