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 | // directory_entry& operator=(directory_entry const&) = default; |
17 | // directory_entry& operator=(directory_entry&&) noexcept = default; |
18 | // void assign(path const&); |
19 | // void replace_filename(path const&); |
20 | |
21 | #include <filesystem> |
22 | #include <type_traits> |
23 | #include <cassert> |
24 | |
25 | #include "test_macros.h" |
26 | #include "filesystem_test_helper.h" |
27 | namespace fs = std::filesystem; |
28 | |
29 | static void test_replace_filename_method() { |
30 | using namespace fs; |
31 | |
32 | { |
33 | directory_entry e; |
34 | path replace; |
35 | static_assert(noexcept(e.replace_filename(p: replace)) == false, |
36 | "operation cannot be noexcept" ); |
37 | static_assert( |
38 | std::is_same<decltype(e.replace_filename(p: replace)), void>::value, |
39 | "operation must return void" ); |
40 | } |
41 | { |
42 | const path p("/path/to/foo.exe" ); |
43 | const path replace("bar.out" ); |
44 | const path expect("/path/to/bar.out" ); |
45 | directory_entry e(p); |
46 | assert(e.path() == p); |
47 | e.replace_filename(p: replace); |
48 | assert(e.path() == expect); |
49 | } |
50 | } |
51 | |
52 | static void test_replace_filename_ec_method() { |
53 | using namespace fs; |
54 | |
55 | static_test_env static_env; |
56 | { |
57 | directory_entry e; |
58 | path replace; |
59 | std::error_code ec; |
60 | static_assert(noexcept(e.replace_filename(p: replace, ec&: ec)) == false, |
61 | "operation cannot be noexcept" ); |
62 | static_assert( |
63 | std::is_same<decltype(e.replace_filename(p: replace, ec&: ec)), void>::value, |
64 | "operation must return void" ); |
65 | } |
66 | { |
67 | const path p("/path/to/foo.exe" ); |
68 | const path replace("bar.out" ); |
69 | const path expect("/path/to/bar.out" ); |
70 | directory_entry e(p); |
71 | assert(e.path() == p); |
72 | std::error_code ec = GetTestEC(); |
73 | e.replace_filename(p: replace, ec&: ec); |
74 | assert(e.path() == expect); |
75 | assert(ErrorIs(ec, std::errc::no_such_file_or_directory)); |
76 | } |
77 | { |
78 | const path p = static_env.EmptyFile; |
79 | const path expect = static_env.NonEmptyFile; |
80 | const path replace = static_env.NonEmptyFile.filename(); |
81 | assert(expect.parent_path() == p.parent_path()); |
82 | directory_entry e(p); |
83 | assert(e.path() == p); |
84 | std::error_code ec = GetTestEC(); |
85 | e.replace_filename(p: replace, ec&: ec); |
86 | assert(e.path() == expect); |
87 | assert(!ec); |
88 | } |
89 | } |
90 | |
91 | static void test_replace_filename_calls_refresh() { |
92 | using namespace fs; |
93 | scoped_test_env env; |
94 | const path dir = env.create_dir("dir" ); |
95 | const path file = env.create_file("dir/file" , 42); |
96 | const path file_two = env.create_file("dir/file_two" , 101); |
97 | const path sym = env.create_symlink("dir/file" , "sym" ); |
98 | const path sym_two = env.create_symlink("dir/file_two" , "sym_two" ); |
99 | |
100 | { |
101 | directory_entry ent(file); |
102 | ent.replace_filename(p: file_two.filename()); |
103 | assert(ent.path() == file_two); |
104 | |
105 | // removing the file demonstrates that the values where cached previously. |
106 | LIBCPP_ONLY(remove(p: file_two)); |
107 | |
108 | assert(ent.file_size() == 101); |
109 | } |
110 | env.create_file("dir/file_two" , 99); |
111 | { |
112 | directory_entry ent(sym); |
113 | ent.replace_filename(p: sym_two.filename()); |
114 | assert(ent.path() == sym_two); |
115 | |
116 | LIBCPP_ONLY(remove(p: file_two)); |
117 | LIBCPP_ONLY(remove(p: sym_two)); |
118 | |
119 | assert(ent.is_symlink()); |
120 | assert(ent.is_regular_file()); |
121 | assert(ent.file_size() == 99); |
122 | } |
123 | } |
124 | |
125 | #ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE |
126 | // Windows doesn't support setting perms::none to trigger failures |
127 | // reading directories. |
128 | static void test_replace_filename_propagates_error() { |
129 | using namespace fs; |
130 | scoped_test_env env; |
131 | const path dir = env.create_dir("dir" ); |
132 | const path file = env.create_file("dir/file" , 42); |
133 | const path file_two = env.create_file("dir/file_two" , 99); |
134 | const path file_out_of_dir = env.create_file("file_three" , 101); |
135 | const path sym_out_of_dir = env.create_symlink("dir/file" , "sym" ); |
136 | const path sym_out_of_dir_two = env.create_symlink("dir/file" , "sym_two" ); |
137 | const path sym_in_dir = env.create_symlink("file_two" , "dir/sym_three" ); |
138 | const path sym_in_dir_two = env.create_symlink("file_two" , "dir/sym_four" ); |
139 | |
140 | const perms old_perms = status(p: dir).permissions(); |
141 | |
142 | { |
143 | directory_entry ent(file); |
144 | permissions(p: dir, prms: perms::none); |
145 | std::error_code ec = GetTestEC(); |
146 | ent.replace_filename(p: file_two.filename(), ec&: ec); |
147 | assert(ErrorIs(ec, std::errc::permission_denied)); |
148 | } |
149 | permissions(p: dir, prms: old_perms); |
150 | { |
151 | directory_entry ent(sym_in_dir); |
152 | permissions(p: dir, prms: perms::none); |
153 | std::error_code ec = GetTestEC(); |
154 | ent.replace_filename(p: sym_in_dir_two.filename(), ec&: ec); |
155 | assert(ErrorIs(ec, std::errc::permission_denied)); |
156 | } |
157 | permissions(p: dir, prms: old_perms); |
158 | { |
159 | directory_entry ent(sym_out_of_dir); |
160 | permissions(p: dir, prms: perms::none); |
161 | std::error_code ec = GetTestEC(); |
162 | ent.replace_filename(p: sym_out_of_dir_two.filename(), ec&: ec); |
163 | assert(!ec); |
164 | assert(ent.is_symlink()); |
165 | ec = GetTestEC(); |
166 | assert(!ent.exists(ec)); |
167 | assert(ErrorIs(ec, std::errc::permission_denied)); |
168 | } |
169 | } |
170 | #endif // TEST_WIN_NO_FILESYSTEM_PERMS_NONE |
171 | |
172 | int main(int, char**) { |
173 | test_replace_filename_method(); |
174 | test_replace_filename_ec_method(); |
175 | test_replace_filename_calls_refresh(); |
176 | #ifndef TEST_WIN_NO_FILESYSTEM_PERMS_NONE |
177 | test_replace_filename_propagates_error(); |
178 | #endif |
179 | |
180 | return 0; |
181 | } |
182 | |