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, c++11, c++14 10 // UNSUPPORTED: no-filesystem 11 // UNSUPPORTED: availability-filesystem-missing 12 13 // <filesystem> 14 15 // void rename(const path& old_p, const path& new_p); 16 // void rename(const path& old_p, const path& new_p, error_code& ec) noexcept; 17 18 #include <filesystem> 19 20 #include "test_macros.h" 21 #include "filesystem_test_helper.h" 22 namespace fs = std::filesystem; 23 using namespace fs; 24 25 static void test_signatures() 26 { 27 const path p; ((void)p); 28 std::error_code ec; ((void)ec); 29 ASSERT_SAME_TYPE(decltype(fs::rename(p, p)), void); 30 ASSERT_SAME_TYPE(decltype(fs::rename(p, p, ec)), void); 31 32 ASSERT_NOT_NOEXCEPT(fs::rename(p, p)); 33 ASSERT_NOEXCEPT(fs::rename(p, p, ec)); 34 } 35 36 static void test_error_reporting() 37 { 38 auto checkThrow = [](path const& f, path const& t, const std::error_code& ec) 39 { 40 #ifndef TEST_HAS_NO_EXCEPTIONS 41 try { 42 fs::rename(f, t); 43 return false; 44 } catch (filesystem_error const& err) { 45 return err.path1() == f 46 && err.path2() == t 47 && err.code() == ec; 48 } 49 #else 50 ((void)f); ((void)t); ((void)ec); 51 return true; 52 #endif 53 }; 54 scoped_test_env env; 55 const path dne = env.make_env_path("dne"); 56 const path file = env.create_file("file1", 42); 57 const path dir = env.create_dir("dir1"); 58 struct TestCase { 59 path from; 60 path to; 61 } cases[] = { 62 {dne, dne}, 63 {file, dir}, 64 #ifndef _WIN32 65 // The spec doesn't say that this case must be an error; fs.op.rename 66 // note 1.2.1 says that a file may be overwritten by a rename. 67 // On Windows, with rename() implemented with MoveFileExW, overwriting 68 // a file with a directory is not an error. 69 {dir, file}, 70 #endif 71 }; 72 for (auto& TC : cases) { 73 auto from_before = status(TC.from); 74 auto to_before = status(TC.to); 75 std::error_code ec; 76 rename(TC.from, TC.to, ec); 77 assert(ec); 78 assert(from_before.type() == status(TC.from).type()); 79 assert(to_before.type() == status(TC.to).type()); 80 assert(checkThrow(TC.from, TC.to, ec)); 81 } 82 } 83 84 static void basic_rename_test() 85 { 86 scoped_test_env env; 87 88 const std::error_code set_ec = std::make_error_code(std::errc::address_in_use); 89 const path file = env.create_file("file1", 42); 90 { // same file 91 std::error_code ec = set_ec; 92 rename(file, file, ec); 93 assert(!ec); 94 assert(is_regular_file(file)); 95 assert(file_size(file) == 42); 96 } 97 const path sym = env.create_symlink(file, "sym"); 98 { // file -> symlink 99 std::error_code ec = set_ec; 100 rename(file, sym, ec); 101 assert(!ec); 102 assert(!exists(file)); 103 assert(is_regular_file(symlink_status(sym))); 104 assert(file_size(sym) == 42); 105 } 106 const path file2 = env.create_file("file2", 42); 107 const path file3 = env.create_file("file3", 100); 108 { // file -> file 109 std::error_code ec = set_ec; 110 rename(file2, file3, ec); 111 assert(!ec); 112 assert(!exists(file2)); 113 assert(is_regular_file(file3)); 114 assert(file_size(file3) == 42); 115 } 116 const path dne = env.make_env_path("dne"); 117 const path bad_sym = env.create_symlink(dne, "bad_sym"); 118 const path bad_sym_dest = env.make_env_path("bad_sym2"); 119 { // bad-symlink 120 std::error_code ec = set_ec; 121 rename(bad_sym, bad_sym_dest, ec); 122 assert(!ec); 123 assert(!exists(symlink_status(bad_sym))); 124 assert(is_symlink(bad_sym_dest)); 125 assert(read_symlink(bad_sym_dest) == dne); 126 } 127 } 128 129 static void basic_rename_dir_test() 130 { 131 static_test_env env; 132 const std::error_code set_ec = std::make_error_code(std::errc::address_in_use); 133 const path new_dir = env.makePath("new_dir"); 134 { // dir -> dir (with contents) 135 std::error_code ec = set_ec; 136 rename(env.Dir, new_dir, ec); 137 assert(!ec); 138 assert(!exists(env.Dir)); 139 assert(is_directory(new_dir)); 140 assert(exists(new_dir / "file1")); 141 } 142 #ifdef _WIN32 143 // On Windows, renaming a directory over a file isn't an error (this 144 // case is skipped in test_error_reporting above). 145 { // dir -> file 146 std::error_code ec = set_ec; 147 rename(new_dir, env.NonEmptyFile, ec); 148 assert(!ec); 149 assert(!exists(new_dir)); 150 assert(is_directory(env.NonEmptyFile)); 151 assert(exists(env.NonEmptyFile / "file1")); 152 } 153 #endif 154 } 155 156 int main(int, char**) { 157 test_signatures(); 158 test_error_reporting(); 159 basic_rename_test(); 160 basic_rename_dir_test(); 161 162 return 0; 163 } 164