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 // void copy(const path& from, const path& to);
14 // void copy(const path& from, const path& to, error_code& ec);
15 // void copy(const path& from, const path& to, copy_options options);
16 // void copy(const path& from, const path& to, copy_options options,
17 // error_code& ec);
18
19 #include "filesystem_include.h"
20 #include <type_traits>
21 #include <cstddef>
22 #include <cassert>
23
24 #include "test_macros.h"
25 #include "rapid-cxx-test.h"
26 #include "filesystem_test_helper.h"
27
28 using namespace fs;
29
30 using CO = fs::copy_options;
31
32 TEST_SUITE(filesystem_copy_test_suite)
33
TEST_CASE(signature_test)34 TEST_CASE(signature_test)
35 {
36 const path p; ((void)p);
37 std::error_code ec; ((void)ec);
38 const copy_options opts{}; ((void)opts);
39 ASSERT_NOT_NOEXCEPT(fs::copy(p, p));
40 ASSERT_NOT_NOEXCEPT(fs::copy(p, p, ec));
41 ASSERT_NOT_NOEXCEPT(copy(p, p, opts));
42 ASSERT_NOT_NOEXCEPT(copy(p, p, opts, ec));
43 }
44
45 // There are 4 cases is the proposal for absolute path.
46 // Each scope tests one of the cases.
TEST_CASE(test_error_reporting)47 TEST_CASE(test_error_reporting)
48 {
49 auto checkThrow = [](path const& f, path const& t, const std::error_code& ec)
50 {
51 #ifndef TEST_HAS_NO_EXCEPTIONS
52 try {
53 fs::copy(f, t);
54 return false;
55 } catch (filesystem_error const& err) {
56 return err.path1() == f
57 && err.path2() == t
58 && err.code() == ec;
59 }
60 #else
61 ((void)f); ((void)t); ((void)ec);
62 return true;
63 #endif
64 };
65
66 static_test_env static_env;
67 scoped_test_env env;
68 const path file = env.create_file("file1", 42);
69 const path dir = env.create_dir("dir");
70 #ifndef _WIN32
71 const path fifo = env.create_fifo("fifo");
72 TEST_REQUIRE(is_other(fifo));
73 #endif
74
75 const auto test_ec = GetTestEC();
76
77 // !exists(f)
78 {
79 std::error_code ec = test_ec;
80 const path f = static_env.DNE;
81 const path t = env.test_root;
82 fs::copy(f, t, ec);
83 TEST_REQUIRE(ec);
84 TEST_REQUIRE(ec != test_ec);
85 TEST_CHECK(checkThrow(f, t, ec));
86 }
87 { // equivalent(f, t) == true
88 std::error_code ec = test_ec;
89 fs::copy(file, file, ec);
90 TEST_REQUIRE(ec);
91 TEST_REQUIRE(ec != test_ec);
92 TEST_CHECK(checkThrow(file, file, ec));
93 }
94 { // is_directory(from) && is_file(to)
95 std::error_code ec = test_ec;
96 fs::copy(dir, file, ec);
97 TEST_REQUIRE(ec);
98 TEST_REQUIRE(ec != test_ec);
99 TEST_CHECK(checkThrow(dir, file, ec));
100 }
101 #ifndef _WIN32
102 { // is_other(from)
103 std::error_code ec = test_ec;
104 fs::copy(fifo, dir, ec);
105 TEST_REQUIRE(ec);
106 TEST_REQUIRE(ec != test_ec);
107 TEST_CHECK(checkThrow(fifo, dir, ec));
108 }
109 { // is_other(to)
110 std::error_code ec = test_ec;
111 fs::copy(file, fifo, ec);
112 TEST_REQUIRE(ec);
113 TEST_REQUIRE(ec != test_ec);
114 TEST_CHECK(checkThrow(file, fifo, ec));
115 }
116 #endif
117 }
118
TEST_CASE(from_is_symlink)119 TEST_CASE(from_is_symlink)
120 {
121 scoped_test_env env;
122 const path file = env.create_file("file", 42);
123 const path symlink = env.create_symlink(file, "sym");
124 const path dne = env.make_env_path("dne");
125
126 { // skip symlinks
127 std::error_code ec = GetTestEC();
128 fs::copy(symlink, dne, copy_options::skip_symlinks, ec);
129 TEST_CHECK(!ec);
130 TEST_CHECK(!exists(dne));
131 }
132 {
133 const path dest = env.make_env_path("dest");
134 std::error_code ec = GetTestEC();
135 fs::copy(symlink, dest, copy_options::copy_symlinks, ec);
136 TEST_CHECK(!ec);
137 TEST_CHECK(exists(dest));
138 TEST_CHECK(is_symlink(dest));
139 }
140 { // copy symlink but target exists
141 std::error_code ec = GetTestEC();
142 fs::copy(symlink, file, copy_options::copy_symlinks, ec);
143 TEST_CHECK(ec);
144 TEST_CHECK(ec != GetTestEC());
145 }
146 { // create symlinks but target exists
147 std::error_code ec = GetTestEC();
148 fs::copy(symlink, file, copy_options::create_symlinks, ec);
149 TEST_CHECK(ec);
150 TEST_CHECK(ec != GetTestEC());
151 }
152 }
153
TEST_CASE(from_is_regular_file)154 TEST_CASE(from_is_regular_file)
155 {
156 scoped_test_env env;
157 const path file = env.create_file("file", 42);
158 const path dir = env.create_dir("dir");
159 { // skip copy because of directory
160 const path dest = env.make_env_path("dest1");
161 std::error_code ec = GetTestEC();
162 fs::copy(file, dest, CO::directories_only, ec);
163 TEST_CHECK(!ec);
164 TEST_CHECK(!exists(dest));
165 }
166 { // create symlink to file
167 const path dest = env.make_env_path("sym");
168 std::error_code ec = GetTestEC();
169 fs::copy(file, dest, CO::create_symlinks, ec);
170 TEST_CHECK(!ec);
171 TEST_CHECK(is_symlink(dest));
172 TEST_CHECK(equivalent(file, canonical(dest)));
173 }
174 { // create hard link to file
175 const path dest = env.make_env_path("hardlink");
176 TEST_CHECK(hard_link_count(file) == 1);
177 std::error_code ec = GetTestEC();
178 fs::copy(file, dest, CO::create_hard_links, ec);
179 TEST_CHECK(!ec);
180 TEST_CHECK(exists(dest));
181 TEST_CHECK(hard_link_count(file) == 2);
182 }
183 { // is_directory(t)
184 const path dest_dir = env.create_dir("dest_dir");
185 const path expect_dest = dest_dir / file.filename();
186 std::error_code ec = GetTestEC();
187 fs::copy(file, dest_dir, ec);
188 TEST_CHECK(!ec);
189 TEST_CHECK(is_regular_file(expect_dest));
190 }
191 { // otherwise copy_file(from, to, ...)
192 const path dest = env.make_env_path("file_copy");
193 std::error_code ec = GetTestEC();
194 fs::copy(file, dest, ec);
195 TEST_CHECK(!ec);
196 TEST_CHECK(is_regular_file(dest));
197 }
198 }
199
TEST_CASE(from_is_directory)200 TEST_CASE(from_is_directory)
201 {
202 struct FileInfo {
203 path filename;
204 std::size_t size;
205 };
206 const FileInfo files[] = {
207 {"file1", 0},
208 {"file2", 42},
209 {"file3", 300}
210 };
211 scoped_test_env env;
212 const path dir = env.create_dir("dir");
213 const path nested_dir_name = "dir2";
214 const path nested_dir = env.create_dir("dir/dir2");
215
216 for (auto& FI : files) {
217 env.create_file(dir / FI.filename, FI.size);
218 env.create_file(nested_dir / FI.filename, FI.size);
219 }
220 { // test for non-existent directory
221 const path dest = env.make_env_path("dest_dir1");
222 std::error_code ec = GetTestEC();
223 fs::copy(dir, dest, ec);
224 TEST_REQUIRE(!ec);
225 TEST_CHECK(is_directory(dest));
226 for (auto& FI : files) {
227 path created = dest / FI.filename;
228 TEST_CHECK(is_regular_file(created));
229 TEST_CHECK(file_size(created) == FI.size);
230 }
231 TEST_CHECK(!is_directory(dest / nested_dir_name));
232 }
233 { // test for existing directory
234 const path dest = env.create_dir("dest_dir2");
235 std::error_code ec = GetTestEC();
236 fs::copy(dir, dest, ec);
237 TEST_REQUIRE(!ec);
238 TEST_CHECK(is_directory(dest));
239 for (auto& FI : files) {
240 path created = dest / FI.filename;
241 TEST_CHECK(is_regular_file(created));
242 TEST_CHECK(file_size(created) == FI.size);
243 }
244 TEST_CHECK(!is_directory(dest / nested_dir_name));
245 }
246 { // test recursive copy
247 const path dest = env.make_env_path("dest_dir3");
248 std::error_code ec = GetTestEC();
249 fs::copy(dir, dest, CO::recursive, ec);
250 TEST_REQUIRE(!ec);
251 TEST_CHECK(is_directory(dest));
252 const path nested_dest = dest / nested_dir_name;
253 TEST_REQUIRE(is_directory(nested_dest));
254 for (auto& FI : files) {
255 path created = dest / FI.filename;
256 path nested_created = nested_dest / FI.filename;
257 TEST_CHECK(is_regular_file(created));
258 TEST_CHECK(file_size(created) == FI.size);
259 TEST_CHECK(is_regular_file(nested_created));
260 TEST_CHECK(file_size(nested_created) == FI.size);
261 }
262 }
263 }
264
TEST_CASE(test_copy_symlinks_to_symlink_dir)265 TEST_CASE(test_copy_symlinks_to_symlink_dir)
266 {
267 scoped_test_env env;
268 const path file1 = env.create_file("file1", 42);
269 const path file2 = env.create_file("file2", 101);
270 const path file2_sym = env.create_symlink(file2, "file2_sym");
271 const path dir = env.create_dir("dir");
272 const path dir_sym = env.create_directory_symlink(dir, "dir_sym");
273 {
274 std::error_code ec = GetTestEC();
275 fs::copy(file1, dir_sym, copy_options::copy_symlinks, ec);
276 TEST_CHECK(!ec);
277 const path dest = env.make_env_path("dir/file1");
278 TEST_CHECK(exists(dest));
279 TEST_CHECK(!is_symlink(dest));
280 TEST_CHECK(file_size(dest) == 42);
281 }
282 }
283
284
TEST_CASE(test_dir_create_symlink)285 TEST_CASE(test_dir_create_symlink)
286 {
287 scoped_test_env env;
288 const path dir = env.create_dir("dir1");
289 const path dest = env.make_env_path("dne");
290 {
291 std::error_code ec = GetTestEC();
292 fs::copy(dir, dest, copy_options::create_symlinks, ec);
293 TEST_CHECK(ErrorIs(ec, std::errc::is_a_directory));
294 TEST_CHECK(!exists(dest));
295 TEST_CHECK(!is_symlink(dest));
296 }
297 {
298 std::error_code ec = GetTestEC();
299 fs::copy(dir, dest, copy_options::create_symlinks|copy_options::recursive, ec);
300 TEST_CHECK(ErrorIs(ec, std::errc::is_a_directory));
301 TEST_CHECK(!exists(dest));
302 TEST_CHECK(!is_symlink(dest));
303 }
304 }
305
TEST_CASE(test_otherwise_no_effects_clause)306 TEST_CASE(test_otherwise_no_effects_clause)
307 {
308 scoped_test_env env;
309 const path dir = env.create_dir("dir1");
310 { // skip copy because of directory
311 const path dest = env.make_env_path("dest1");
312 std::error_code ec;
313 fs::copy(dir, dest, CO::directories_only, ec);
314 TEST_CHECK(!ec);
315 TEST_CHECK(!exists(dest));
316 }
317 }
318
319 TEST_SUITE_END()
320