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 | |
12 | // <filesystem> |
13 | |
14 | // class directory_entry |
15 | |
16 | // explicit directory_entry(const path); |
17 | // directory_entry(const path&, error_code& ec); |
18 | |
19 | #include <filesystem> |
20 | #include <type_traits> |
21 | #include <cassert> |
22 | |
23 | #include "assert_macros.h" |
24 | #include "test_macros.h" |
25 | #include "filesystem_test_helper.h" |
26 | #include "test_convertible.h" |
27 | namespace fs = std::filesystem; |
28 | |
29 | static void path_ctor() { |
30 | using namespace fs; |
31 | { |
32 | static_assert(std::is_constructible<directory_entry, const path&>::value, |
33 | "directory_entry must be constructible from path" ); |
34 | static_assert( |
35 | !std::is_nothrow_constructible<directory_entry, const path&>::value, |
36 | "directory_entry constructor should not be noexcept" ); |
37 | static_assert(!std::is_convertible<path const&, directory_entry>::value, |
38 | "directory_entry constructor should be explicit" ); |
39 | } |
40 | { |
41 | const path p("foo/bar/baz" ); |
42 | const directory_entry e(p); |
43 | assert(e.path() == p); |
44 | } |
45 | } |
46 | |
47 | static void path_ec_ctor() { |
48 | static_test_env static_env; |
49 | using namespace fs; |
50 | { |
51 | static_assert( |
52 | std::is_constructible<directory_entry, const path&, |
53 | std::error_code&>::value, |
54 | "directory_entry must be constructible from path and error_code" ); |
55 | static_assert(!std::is_nothrow_constructible<directory_entry, const path&, |
56 | std::error_code&>::value, |
57 | "directory_entry constructor should not be noexcept" ); |
58 | static_assert( |
59 | test_convertible<directory_entry, const path&, std::error_code&>(), |
60 | "directory_entry constructor should not be explicit" ); |
61 | } |
62 | { |
63 | std::error_code ec = GetTestEC(); |
64 | const directory_entry e(static_env.File, ec); |
65 | assert(e.path() == static_env.File); |
66 | assert(!ec); |
67 | } |
68 | { |
69 | const path p("foo/bar/baz" ); |
70 | std::error_code ec = GetTestEC(); |
71 | const directory_entry e(p, ec); |
72 | assert(e.path() == p); |
73 | assert(ErrorIs(ec, std::errc::no_such_file_or_directory)); |
74 | } |
75 | } |
76 | |
77 | static void path_ctor_calls_refresh() { |
78 | using namespace fs; |
79 | scoped_test_env env; |
80 | const path dir = env.create_dir("dir" ); |
81 | const path file = env.create_file("dir/file" , 42); |
82 | const path sym = env.create_symlink("dir/file" , "sym" ); |
83 | |
84 | { |
85 | directory_entry ent(file); |
86 | std::error_code ec = GetTestEC(); |
87 | directory_entry ent_ec(file, ec); |
88 | assert(!ec); |
89 | |
90 | LIBCPP_ONLY(remove(p: file)); |
91 | |
92 | assert(ent.exists()); |
93 | assert(ent_ec.exists()); |
94 | |
95 | assert(ent.file_size() == 42); |
96 | assert(ent_ec.file_size() == 42); |
97 | } |
98 | |
99 | env.create_file("dir/file" , 101); |
100 | |
101 | { |
102 | directory_entry ent(sym); |
103 | std::error_code ec = GetTestEC(); |
104 | directory_entry ent_ec(sym, ec); |
105 | assert(!ec); |
106 | |
107 | LIBCPP_ONLY(remove(p: file)); |
108 | LIBCPP_ONLY(remove(p: sym)); |
109 | |
110 | assert(ent.is_symlink()); |
111 | assert(ent_ec.is_symlink()); |
112 | |
113 | assert(ent.is_regular_file()); |
114 | assert(ent_ec.is_regular_file()); |
115 | |
116 | assert(ent.file_size() == 101); |
117 | assert(ent_ec.file_size() == 101); |
118 | } |
119 | } |
120 | |
121 | static void path_ctor_dne() { |
122 | using namespace fs; |
123 | |
124 | static_test_env static_env; |
125 | |
126 | { |
127 | std::error_code ec = GetTestEC(); |
128 | directory_entry ent(static_env.DNE, ec); |
129 | assert(ErrorIs(ec, std::errc::no_such_file_or_directory)); |
130 | assert(ent.path() == static_env.DNE); |
131 | } |
132 | // don't report dead symlinks as an error. |
133 | { |
134 | std::error_code ec = GetTestEC(); |
135 | directory_entry ent(static_env.BadSymlink, ec); |
136 | assert(!ec); |
137 | assert(ent.path() == static_env.BadSymlink); |
138 | } |
139 | // DNE does not cause the constructor to throw |
140 | { |
141 | directory_entry ent(static_env.DNE); |
142 | assert(ent.path() == static_env.DNE); |
143 | |
144 | directory_entry ent_two(static_env.BadSymlink); |
145 | assert(ent_two.path() == static_env.BadSymlink); |
146 | } |
147 | } |
148 | |
149 | static void path_ctor_cannot_resolve() { |
150 | using namespace fs; |
151 | #ifdef _WIN32 |
152 | // Windows doesn't support setting perms::none to trigger failures |
153 | // reading directories; test using a special inaccessible directory |
154 | // instead. |
155 | const path dir = GetWindowsInaccessibleDir(); |
156 | if (dir.empty()) |
157 | return; |
158 | const path file = dir / "file" ; |
159 | { |
160 | std::error_code ec = GetTestEC(); |
161 | directory_entry ent(file, ec); |
162 | assert(ErrorIs(ec, std::errc::no_such_file_or_directory)); |
163 | assert(ent.path() == file); |
164 | } |
165 | { |
166 | TEST_DOES_NOT_THROW(directory_entry(file)); |
167 | } |
168 | #else |
169 | scoped_test_env env; |
170 | const path dir = env.create_dir("dir" ); |
171 | const path file = env.create_file("dir/file" , 42); |
172 | const path file_out_of_dir = env.create_file("file1" , 101); |
173 | const path sym_out_of_dir = env.create_symlink("dir/file" , "sym" ); |
174 | const path sym_in_dir = env.create_symlink("dir/file1" , "dir/sym2" ); |
175 | permissions(p: dir, prms: perms::none); |
176 | |
177 | { |
178 | std::error_code ec = GetTestEC(); |
179 | directory_entry ent(file, ec); |
180 | assert(ErrorIs(ec, std::errc::permission_denied)); |
181 | assert(ent.path() == file); |
182 | } |
183 | { |
184 | std::error_code ec = GetTestEC(); |
185 | directory_entry ent(sym_in_dir, ec); |
186 | assert(ErrorIs(ec, std::errc::permission_denied)); |
187 | assert(ent.path() == sym_in_dir); |
188 | } |
189 | { |
190 | std::error_code ec = GetTestEC(); |
191 | directory_entry ent(sym_out_of_dir, ec); |
192 | assert(!ec); |
193 | assert(ent.path() == sym_out_of_dir); |
194 | } |
195 | { |
196 | TEST_DOES_NOT_THROW(directory_entry(file)); |
197 | TEST_DOES_NOT_THROW(directory_entry(sym_in_dir)); |
198 | TEST_DOES_NOT_THROW(directory_entry(sym_out_of_dir)); |
199 | } |
200 | #endif |
201 | } |
202 | |
203 | int main(int, char**) { |
204 | path_ctor(); |
205 | path_ec_ctor(); |
206 | path_ctor_calls_refresh(); |
207 | path_ctor_dne(); |
208 | path_ctor_cannot_resolve(); |
209 | |
210 | return 0; |
211 | } |
212 | |