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
test_path_assign_method()29 static void test_path_assign_method() {
30 using namespace fs;
31 const path p("foo/bar/baz");
32 const path p2("abc");
33 directory_entry e(p);
34 {
35 static_assert(std::is_same<decltype(e.assign(p)), void>::value,
36 "return type should be void");
37 static_assert(noexcept(e.assign(p)) == false,
38 "operation must not be noexcept");
39 }
40 {
41 assert(e.path() == p);
42 e.assign(p2);
43 assert(e.path() == p2 && e.path() != p);
44 e.assign(p);
45 assert(e.path() == p && e.path() != p2);
46 }
47 }
48
test_path_assign_ec_method()49 static void test_path_assign_ec_method() {
50 using namespace fs;
51 const path p("foo/bar/baz");
52 const path p2("abc");
53 {
54 std::error_code ec;
55 directory_entry e(p);
56 static_assert(std::is_same<decltype(e.assign(p, ec)), void>::value,
57 "return type should be void");
58 static_assert(noexcept(e.assign(p, ec)) == false,
59 "operation must not be noexcept");
60 }
61 {
62 directory_entry ent(p);
63 std::error_code ec = GetTestEC();
64 ent.assign(p2, ec);
65 assert(ErrorIs(ec, std::errc::no_such_file_or_directory));
66 assert(ent.path() == p2);
67 }
68 }
69
test_assign_calls_refresh()70 static void test_assign_calls_refresh() {
71 using namespace fs;
72 scoped_test_env env;
73 const path dir = env.create_dir("dir");
74 const path file = env.create_file("dir/file", 42);
75 const path sym = env.create_symlink("dir/file", "sym");
76
77 {
78 directory_entry ent;
79 ent.assign(file);
80
81 // removing the file demonstrates that the values where cached previously.
82 LIBCPP_ONLY(remove(file));
83
84 assert(ent.is_regular_file());
85 }
86 env.create_file("dir/file", 101);
87 {
88 directory_entry ent;
89 ent.assign(sym);
90
91 LIBCPP_ONLY(remove(file));
92 LIBCPP_ONLY(remove(sym));
93
94 assert(ent.is_symlink());
95 assert(ent.is_regular_file());
96 }
97 }
98
test_assign_propagates_error()99 static void test_assign_propagates_error() {
100 using namespace fs;
101 scoped_test_env env;
102 #ifdef _WIN32
103 // Windows doesn't support setting perms::none to trigger failures
104 // reading directories; test using a special inaccessible directory
105 // instead.
106 const path dir = GetWindowsInaccessibleDir();
107 if (dir.empty())
108 return;
109 const path file = dir / "inaccessible_file";
110 // We can't create files in the inaccessible directory, so this doesn't
111 // test exactly the same as the code below.
112 const path sym_out_of_dir = env.create_symlink(file, "sym");
113 {
114 directory_entry ent;
115 std::error_code ec = GetTestEC();
116 ent.assign(file, ec);
117 assert(ErrorIs(ec, std::errc::no_such_file_or_directory));
118 }
119 #else
120 const path dir = env.create_dir("dir");
121 const path file = env.create_file("dir/file", 42);
122 const path sym_out_of_dir = env.create_symlink("dir/file", "sym");
123 const path file_out_of_dir = env.create_file("file1");
124 const path sym_in_dir = env.create_symlink("file1", "dir/sym1");
125
126 permissions(dir, perms::none);
127
128 {
129 directory_entry ent;
130 std::error_code ec = GetTestEC();
131 ent.assign(file, ec);
132 assert(ErrorIs(ec, std::errc::permission_denied));
133 }
134 {
135 directory_entry ent;
136 std::error_code ec = GetTestEC();
137 ent.assign(sym_in_dir, ec);
138 assert(ErrorIs(ec, std::errc::permission_denied));
139 }
140 #endif
141 {
142 directory_entry ent;
143 std::error_code ec = GetTestEC();
144 ent.assign(sym_out_of_dir, ec);
145 assert(!ec);
146 }
147 }
148
main(int,char **)149 int main(int, char**) {
150 test_path_assign_method();
151 test_path_assign_ec_method();
152 test_assign_calls_refresh();
153 test_assign_propagates_error();
154
155 return 0;
156 }
157