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 // explicit directory_entry(const path);
17 // directory_entry(const path&, error_code& ec);
18 
19 #include <filesystem>
20 #include <type_traits>
21 #include <cassert>
22 
23 #include "assert_macros.h"
24 #include "test_macros.h"
25 #include "filesystem_test_helper.h"
26 #include "test_convertible.h"
27 namespace fs = std::filesystem;
28 
path_ctor()29 static void path_ctor() {
30   using namespace fs;
31   {
32     static_assert(std::is_constructible<directory_entry, const path&>::value,
33                   "directory_entry must be constructible from path");
34     static_assert(
35         !std::is_nothrow_constructible<directory_entry, const path&>::value,
36         "directory_entry constructor should not be noexcept");
37     static_assert(!std::is_convertible<path const&, directory_entry>::value,
38                   "directory_entry constructor should be explicit");
39   }
40   {
41     const path p("foo/bar/baz");
42     const directory_entry e(p);
43     assert(e.path() == p);
44   }
45 }
46 
path_ec_ctor()47 static void path_ec_ctor() {
48   static_test_env static_env;
49   using namespace fs;
50   {
51     static_assert(
52         std::is_constructible<directory_entry, const path&,
53                               std::error_code&>::value,
54         "directory_entry must be constructible from path and error_code");
55     static_assert(!std::is_nothrow_constructible<directory_entry, const path&,
56                                                  std::error_code&>::value,
57                   "directory_entry constructor should not be noexcept");
58     static_assert(
59         test_convertible<directory_entry, const path&, std::error_code&>(),
60         "directory_entry constructor should not be explicit");
61   }
62   {
63     std::error_code ec = GetTestEC();
64     const directory_entry e(static_env.File, ec);
65     assert(e.path() == static_env.File);
66     assert(!ec);
67   }
68   {
69     const path p("foo/bar/baz");
70     std::error_code ec = GetTestEC();
71     const directory_entry e(p, ec);
72     assert(e.path() == p);
73     assert(ErrorIs(ec, std::errc::no_such_file_or_directory));
74   }
75 }
76 
path_ctor_calls_refresh()77 static void path_ctor_calls_refresh() {
78   using namespace fs;
79   scoped_test_env env;
80   const path dir = env.create_dir("dir");
81   const path file = env.create_file("dir/file", 42);
82   const path sym = env.create_symlink("dir/file", "sym");
83 
84   {
85     directory_entry ent(file);
86     std::error_code ec = GetTestEC();
87     directory_entry ent_ec(file, ec);
88     assert(!ec);
89 
90     LIBCPP_ONLY(remove(file));
91 
92     assert(ent.exists());
93     assert(ent_ec.exists());
94 
95     assert(ent.file_size() == 42);
96     assert(ent_ec.file_size() == 42);
97   }
98 
99   env.create_file("dir/file", 101);
100 
101   {
102     directory_entry ent(sym);
103     std::error_code ec = GetTestEC();
104     directory_entry ent_ec(sym, ec);
105     assert(!ec);
106 
107     LIBCPP_ONLY(remove(file));
108     LIBCPP_ONLY(remove(sym));
109 
110     assert(ent.is_symlink());
111     assert(ent_ec.is_symlink());
112 
113     assert(ent.is_regular_file());
114     assert(ent_ec.is_regular_file());
115 
116     assert(ent.file_size() == 101);
117     assert(ent_ec.file_size() == 101);
118   }
119 }
120 
path_ctor_dne()121 static void path_ctor_dne() {
122   using namespace fs;
123 
124   static_test_env static_env;
125 
126   {
127     std::error_code ec = GetTestEC();
128     directory_entry ent(static_env.DNE, ec);
129     assert(ErrorIs(ec, std::errc::no_such_file_or_directory));
130     assert(ent.path() == static_env.DNE);
131   }
132   // don't report dead symlinks as an error.
133   {
134     std::error_code ec = GetTestEC();
135     directory_entry ent(static_env.BadSymlink, ec);
136     assert(!ec);
137     assert(ent.path() == static_env.BadSymlink);
138   }
139   // DNE does not cause the constructor to throw
140   {
141     directory_entry ent(static_env.DNE);
142     assert(ent.path() == static_env.DNE);
143 
144     directory_entry ent_two(static_env.BadSymlink);
145     assert(ent_two.path() == static_env.BadSymlink);
146   }
147 }
148 
path_ctor_cannot_resolve()149 static void path_ctor_cannot_resolve() {
150   using namespace fs;
151 #ifdef _WIN32
152   // Windows doesn't support setting perms::none to trigger failures
153   // reading directories; test using a special inaccessible directory
154   // instead.
155   const path dir = GetWindowsInaccessibleDir();
156   if (dir.empty())
157     return;
158   const path file = dir / "file";
159   {
160     std::error_code ec = GetTestEC();
161     directory_entry ent(file, ec);
162     assert(ErrorIs(ec, std::errc::no_such_file_or_directory));
163     assert(ent.path() == file);
164   }
165   {
166     TEST_DOES_NOT_THROW(directory_entry(file));
167   }
168 #else
169   scoped_test_env env;
170   const path dir = env.create_dir("dir");
171   const path file = env.create_file("dir/file", 42);
172   const path file_out_of_dir = env.create_file("file1", 101);
173   const path sym_out_of_dir = env.create_symlink("dir/file", "sym");
174   const path sym_in_dir = env.create_symlink("dir/file1", "dir/sym2");
175   permissions(dir, perms::none);
176 
177   {
178     std::error_code ec = GetTestEC();
179     directory_entry ent(file, ec);
180     assert(ErrorIs(ec, std::errc::permission_denied));
181     assert(ent.path() == file);
182   }
183   {
184     std::error_code ec = GetTestEC();
185     directory_entry ent(sym_in_dir, ec);
186     assert(ErrorIs(ec, std::errc::permission_denied));
187     assert(ent.path() == sym_in_dir);
188   }
189   {
190     std::error_code ec = GetTestEC();
191     directory_entry ent(sym_out_of_dir, ec);
192     assert(!ec);
193     assert(ent.path() == sym_out_of_dir);
194   }
195   {
196     TEST_DOES_NOT_THROW(directory_entry(file));
197     TEST_DOES_NOT_THROW(directory_entry(sym_in_dir));
198     TEST_DOES_NOT_THROW(directory_entry(sym_out_of_dir));
199   }
200 #endif
201 }
202 
main(int,char **)203 int main(int, char**) {
204   path_ctor();
205   path_ec_ctor();
206   path_ctor_calls_refresh();
207   path_ctor_dne();
208   path_ctor_cannot_resolve();
209 
210   return 0;
211 }
212