164 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9// REQUIRES: can-create-symlinks10// UNSUPPORTED: c++03, c++11, c++1411// UNSUPPORTED: no-filesystem12 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"22namespace fs = std::filesystem;23using namespace fs;24 25static 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 36static 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_EXCEPTIONS41 try {42 fs::rename(f, t);43 return false;44 } catch (filesystem_error const& err) {45 return err.path1() == f46 && err.path2() == t47 && err.code() == ec;48 }49#else50 ((void)f); ((void)t); ((void)ec);51 return true;52#endif53 };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 _WIN3265 // The spec doesn't say that this case must be an error; fs.op.rename66 // note 1.2.1 says that a file may be overwritten by a rename.67 // On Windows, with rename() implemented with MoveFileExW, overwriting68 // a file with a directory is not an error.69 {dir, file},70#endif71 };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 84static 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 file91 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 -> symlink99 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 -> file109 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-symlink120 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 129static 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 _WIN32143 // On Windows, renaming a directory over a file isn't an error (this144 // case is skipped in test_error_reporting above).145 { // dir -> file146 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#endif154}155 156int 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