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
10 
11 // <filesystem>
12 
13 // class directory_entry
14 
15 // explicit directory_entry(const path);
16 // directory_entry(const path&, error_code& ec);
17 
18 #include "filesystem_include.h"
19 #include <type_traits>
20 #include <cassert>
21 
22 #include "test_macros.h"
23 #include "rapid-cxx-test.h"
24 #include "filesystem_test_helper.h"
25 #include "test_convertible.h"
26 
27 TEST_SUITE(directory_entry_path_ctor_suite)
28 
TEST_CASE(path_ctor)29 TEST_CASE(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     TEST_CHECK(e.path() == p);
44   }
45 }
46 
TEST_CASE(path_ec_ctor)47 TEST_CASE(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     TEST_CHECK(e.path() == static_env.File);
66     TEST_CHECK(!ec);
67   }
68   {
69     const path p("foo/bar/baz");
70     std::error_code ec = GetTestEC();
71     const directory_entry e(p, ec);
72     TEST_CHECK(e.path() == p);
73     TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
74   }
75 }
76 
TEST_CASE(path_ctor_calls_refresh)77 TEST_CASE(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     TEST_CHECK(!ec);
89 
90     LIBCPP_ONLY(remove(file));
91 
92     TEST_CHECK(ent.exists());
93     TEST_CHECK(ent_ec.exists());
94 
95     TEST_CHECK(ent.file_size() == 42);
96     TEST_CHECK(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     TEST_CHECK(!ec);
106 
107     LIBCPP_ONLY(remove(file));
108     LIBCPP_ONLY(remove(sym));
109 
110     TEST_CHECK(ent.is_symlink());
111     TEST_CHECK(ent_ec.is_symlink());
112 
113     TEST_CHECK(ent.is_regular_file());
114     TEST_CHECK(ent_ec.is_regular_file());
115 
116     TEST_CHECK(ent.file_size() == 101);
117     TEST_CHECK(ent_ec.file_size() == 101);
118   }
119 }
120 
TEST_CASE(path_ctor_dne)121 TEST_CASE(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     TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
130     TEST_CHECK(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     TEST_CHECK(!ec);
137     TEST_CHECK(ent.path() == static_env.BadSymlink);
138   }
139   // DNE does not cause the constructor to throw
140   {
141     directory_entry ent(static_env.DNE);
142     TEST_CHECK(ent.path() == static_env.DNE);
143 
144     directory_entry ent_two(static_env.BadSymlink);
145     TEST_CHECK(ent_two.path() == static_env.BadSymlink);
146   }
147 }
148 
TEST_CASE(path_ctor_cannot_resolve)149 TEST_CASE(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     TEST_UNSUPPORTED();
158   const path file = dir / "file";
159   {
160     std::error_code ec = GetTestEC();
161     directory_entry ent(file, ec);
162     TEST_CHECK(ErrorIs(ec, std::errc::no_such_file_or_directory));
163     TEST_CHECK(ent.path() == file);
164   }
165   {
166     TEST_CHECK_NO_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     TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
181     TEST_CHECK(ent.path() == file);
182   }
183   {
184     std::error_code ec = GetTestEC();
185     directory_entry ent(sym_in_dir, ec);
186     TEST_CHECK(ErrorIs(ec, std::errc::permission_denied));
187     TEST_CHECK(ent.path() == sym_in_dir);
188   }
189   {
190     std::error_code ec = GetTestEC();
191     directory_entry ent(sym_out_of_dir, ec);
192     TEST_CHECK(!ec);
193     TEST_CHECK(ent.path() == sym_out_of_dir);
194   }
195   {
196     TEST_CHECK_NO_THROW(directory_entry(file));
197     TEST_CHECK_NO_THROW(directory_entry(sym_in_dir));
198     TEST_CHECK_NO_THROW(directory_entry(sym_out_of_dir));
199   }
200 #endif
201 }
202 
203 TEST_SUITE_END()
204