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"
27namespace fs = std::filesystem;
28
29static 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
52static 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
91static 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.
128static 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
172int 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

source code of libcxx/test/std/input.output/filesystems/class.directory_entry/directory_entry.mods/replace_filename.pass.cpp