Mercurial > hg > CbC > CbC_llvm
comparison unittests/Support/Path.cpp @ 148:63bd29f05246
merged
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Wed, 14 Aug 2019 19:46:37 +0900 |
parents | c2174574ed3a |
children |
comparison
equal
deleted
inserted
replaced
146:3fc4d5c3e21e | 148:63bd29f05246 |
---|---|
1 //===- llvm/unittest/Support/Path.cpp - Path tests ------------------------===// | 1 //===- llvm/unittest/Support/Path.cpp - Path tests ------------------------===// |
2 // | 2 // |
3 // The LLVM Compiler Infrastructure | 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 // | 4 // See https://llvm.org/LICENSE.txt for license information. |
5 // This file is distributed under the University of Illinois Open Source | 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 // License. See LICENSE.TXT for details. | |
7 // | 6 // |
8 //===----------------------------------------------------------------------===// | 7 //===----------------------------------------------------------------------===// |
9 | 8 |
10 #include "llvm/Support/Path.h" | 9 #include "llvm/Support/Path.h" |
11 #include "llvm/ADT/STLExtras.h" | 10 #include "llvm/ADT/STLExtras.h" |
12 #include "llvm/ADT/SmallVector.h" | 11 #include "llvm/ADT/SmallVector.h" |
13 #include "llvm/ADT/Triple.h" | 12 #include "llvm/ADT/Triple.h" |
14 #include "llvm/BinaryFormat/Magic.h" | 13 #include "llvm/BinaryFormat/Magic.h" |
14 #include "llvm/Config/llvm-config.h" | |
15 #include "llvm/Support/ConvertUTF.h" | 15 #include "llvm/Support/ConvertUTF.h" |
16 #include "llvm/Support/Errc.h" | 16 #include "llvm/Support/Errc.h" |
17 #include "llvm/Support/ErrorHandling.h" | 17 #include "llvm/Support/ErrorHandling.h" |
18 #include "llvm/Support/FileSystem.h" | 18 #include "llvm/Support/FileSystem.h" |
19 #include "llvm/Support/FileUtilities.h" | 19 #include "llvm/Support/FileUtilities.h" |
20 #include "llvm/Support/Host.h" | 20 #include "llvm/Support/Host.h" |
21 #include "llvm/Support/MemoryBuffer.h" | 21 #include "llvm/Support/MemoryBuffer.h" |
22 #include "llvm/Support/raw_ostream.h" | 22 #include "llvm/Support/raw_ostream.h" |
23 #include "gtest/gtest.h" | 23 #include "gtest/gtest.h" |
24 | 24 #include "gmock/gmock.h" |
25 #ifdef LLVM_ON_WIN32 | 25 |
26 #ifdef _WIN32 | |
26 #include "llvm/ADT/ArrayRef.h" | 27 #include "llvm/ADT/ArrayRef.h" |
28 #include "llvm/Support/Chrono.h" | |
27 #include <windows.h> | 29 #include <windows.h> |
28 #include <winerror.h> | 30 #include <winerror.h> |
29 #endif | 31 #endif |
30 | 32 |
31 #ifdef LLVM_ON_UNIX | 33 #ifdef LLVM_ON_UNIX |
45 << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \ | 47 << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \ |
46 GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \ | 48 GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \ |
47 } else { \ | 49 } else { \ |
48 } | 50 } |
49 | 51 |
52 #define ASSERT_ERROR(x) \ | |
53 if (!x) { \ | |
54 SmallString<128> MessageStorage; \ | |
55 raw_svector_ostream Message(MessageStorage); \ | |
56 Message << #x ": did not return a failure error code.\n"; \ | |
57 GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \ | |
58 } | |
59 | |
50 namespace { | 60 namespace { |
61 | |
62 struct FileDescriptorCloser { | |
63 explicit FileDescriptorCloser(int FD) : FD(FD) {} | |
64 ~FileDescriptorCloser() { ::close(FD); } | |
65 int FD; | |
66 }; | |
51 | 67 |
52 TEST(is_separator, Works) { | 68 TEST(is_separator, Works) { |
53 EXPECT_TRUE(path::is_separator('/')); | 69 EXPECT_TRUE(path::is_separator('/')); |
54 EXPECT_FALSE(path::is_separator('\0')); | 70 EXPECT_FALSE(path::is_separator('\0')); |
55 EXPECT_FALSE(path::is_separator('-')); | 71 EXPECT_FALSE(path::is_separator('-')); |
56 EXPECT_FALSE(path::is_separator(' ')); | 72 EXPECT_FALSE(path::is_separator(' ')); |
57 | 73 |
58 EXPECT_TRUE(path::is_separator('\\', path::Style::windows)); | 74 EXPECT_TRUE(path::is_separator('\\', path::Style::windows)); |
59 EXPECT_FALSE(path::is_separator('\\', path::Style::posix)); | 75 EXPECT_FALSE(path::is_separator('\\', path::Style::posix)); |
60 | 76 |
61 #ifdef LLVM_ON_WIN32 | 77 #ifdef _WIN32 |
62 EXPECT_TRUE(path::is_separator('\\')); | 78 EXPECT_TRUE(path::is_separator('\\')); |
63 #else | 79 #else |
64 EXPECT_FALSE(path::is_separator('\\')); | 80 EXPECT_FALSE(path::is_separator('\\')); |
65 #endif | 81 #endif |
66 } | 82 } |
76 paths.push_back("foo/"); | 92 paths.push_back("foo/"); |
77 paths.push_back("/foo/"); | 93 paths.push_back("/foo/"); |
78 paths.push_back("foo/bar"); | 94 paths.push_back("foo/bar"); |
79 paths.push_back("/foo/bar"); | 95 paths.push_back("/foo/bar"); |
80 paths.push_back("//net"); | 96 paths.push_back("//net"); |
97 paths.push_back("//net/"); | |
81 paths.push_back("//net/foo"); | 98 paths.push_back("//net/foo"); |
82 paths.push_back("///foo///"); | 99 paths.push_back("///foo///"); |
83 paths.push_back("///foo///bar"); | 100 paths.push_back("///foo///bar"); |
84 paths.push_back("/."); | 101 paths.push_back("/."); |
85 paths.push_back("./"); | 102 paths.push_back("./"); |
106 paths.push_back("c:foo\\"); | 123 paths.push_back("c:foo\\"); |
107 paths.push_back("c:\\foo\\"); | 124 paths.push_back("c:\\foo\\"); |
108 paths.push_back("c:\\foo/"); | 125 paths.push_back("c:\\foo/"); |
109 paths.push_back("c:/foo\\bar"); | 126 paths.push_back("c:/foo\\bar"); |
110 | 127 |
111 SmallVector<StringRef, 5> ComponentStack; | |
112 for (SmallVector<StringRef, 40>::const_iterator i = paths.begin(), | 128 for (SmallVector<StringRef, 40>::const_iterator i = paths.begin(), |
113 e = paths.end(); | 129 e = paths.end(); |
114 i != e; | 130 i != e; |
115 ++i) { | 131 ++i) { |
132 SCOPED_TRACE(*i); | |
133 SmallVector<StringRef, 5> ComponentStack; | |
116 for (sys::path::const_iterator ci = sys::path::begin(*i), | 134 for (sys::path::const_iterator ci = sys::path::begin(*i), |
117 ce = sys::path::end(*i); | 135 ce = sys::path::end(*i); |
118 ci != ce; | 136 ci != ce; |
119 ++ci) { | 137 ++ci) { |
120 ASSERT_FALSE(ci->empty()); | 138 EXPECT_FALSE(ci->empty()); |
121 ComponentStack.push_back(*ci); | 139 ComponentStack.push_back(*ci); |
122 } | 140 } |
123 | 141 |
142 SmallVector<StringRef, 5> ReverseComponentStack; | |
124 for (sys::path::reverse_iterator ci = sys::path::rbegin(*i), | 143 for (sys::path::reverse_iterator ci = sys::path::rbegin(*i), |
125 ce = sys::path::rend(*i); | 144 ce = sys::path::rend(*i); |
126 ci != ce; | 145 ci != ce; |
127 ++ci) { | 146 ++ci) { |
128 ASSERT_TRUE(*ci == ComponentStack.back()); | 147 EXPECT_FALSE(ci->empty()); |
129 ComponentStack.pop_back(); | 148 ReverseComponentStack.push_back(*ci); |
130 } | 149 } |
131 ASSERT_TRUE(ComponentStack.empty()); | 150 std::reverse(ReverseComponentStack.begin(), ReverseComponentStack.end()); |
151 EXPECT_THAT(ComponentStack, testing::ContainerEq(ReverseComponentStack)); | |
132 | 152 |
133 // Crash test most of the API - since we're iterating over all of our paths | 153 // Crash test most of the API - since we're iterating over all of our paths |
134 // here there isn't really anything reasonable to assert on in the results. | 154 // here there isn't really anything reasonable to assert on in the results. |
135 (void)path::has_root_path(*i); | 155 (void)path::has_root_path(*i); |
136 (void)path::root_path(*i); | 156 (void)path::root_path(*i); |
163 EXPECT_EQ(*sys::path::rbegin(filename), (stem + ext).str()); | 183 EXPECT_EQ(*sys::path::rbegin(filename), (stem + ext).str()); |
164 | 184 |
165 path::native(*i, temp_store); | 185 path::native(*i, temp_store); |
166 } | 186 } |
167 | 187 |
168 SmallString<32> Relative("foo.cpp"); | 188 { |
169 ASSERT_NO_ERROR(sys::fs::make_absolute("/root", Relative)); | 189 SmallString<32> Relative("foo.cpp"); |
170 Relative[5] = '/'; // Fix up windows paths. | 190 sys::fs::make_absolute("/root", Relative); |
171 ASSERT_EQ("/root/foo.cpp", Relative); | 191 Relative[5] = '/'; // Fix up windows paths. |
172 } | 192 ASSERT_EQ("/root/foo.cpp", Relative); |
173 | 193 } |
174 TEST(Support, RelativePathIterator) { | 194 |
175 SmallString<64> Path(StringRef("c/d/e/foo.txt")); | 195 { |
176 typedef SmallVector<StringRef, 4> PathComponents; | 196 SmallString<32> Relative("foo.cpp"); |
177 PathComponents ExpectedPathComponents; | 197 sys::fs::make_absolute("//root", Relative); |
178 PathComponents ActualPathComponents; | 198 Relative[6] = '/'; // Fix up windows paths. |
179 | 199 ASSERT_EQ("//root/foo.cpp", Relative); |
180 StringRef(Path).split(ExpectedPathComponents, '/'); | 200 } |
181 | 201 } |
182 for (path::const_iterator I = path::begin(Path), E = path::end(Path); I != E; | 202 |
183 ++I) { | 203 TEST(Support, FilenameParent) { |
184 ActualPathComponents.push_back(*I); | 204 EXPECT_EQ("/", path::filename("/")); |
185 } | 205 EXPECT_EQ("", path::parent_path("/")); |
186 | 206 |
187 ASSERT_EQ(ExpectedPathComponents.size(), ActualPathComponents.size()); | 207 EXPECT_EQ("\\", path::filename("c:\\", path::Style::windows)); |
188 | 208 EXPECT_EQ("c:", path::parent_path("c:\\", path::Style::windows)); |
189 for (size_t i = 0; i <ExpectedPathComponents.size(); ++i) { | 209 |
190 EXPECT_EQ(ExpectedPathComponents[i].str(), ActualPathComponents[i].str()); | 210 EXPECT_EQ("/", path::filename("///")); |
191 } | 211 EXPECT_EQ("", path::parent_path("///")); |
192 } | 212 |
193 | 213 EXPECT_EQ("\\", path::filename("c:\\\\", path::Style::windows)); |
194 TEST(Support, RelativePathDotIterator) { | 214 EXPECT_EQ("c:", path::parent_path("c:\\\\", path::Style::windows)); |
195 SmallString<64> Path(StringRef(".c/.d/../.")); | 215 |
196 typedef SmallVector<StringRef, 4> PathComponents; | 216 EXPECT_EQ("bar", path::filename("/foo/bar")); |
197 PathComponents ExpectedPathComponents; | 217 EXPECT_EQ("/foo", path::parent_path("/foo/bar")); |
198 PathComponents ActualPathComponents; | 218 |
199 | 219 EXPECT_EQ("foo", path::filename("/foo")); |
200 StringRef(Path).split(ExpectedPathComponents, '/'); | 220 EXPECT_EQ("/", path::parent_path("/foo")); |
201 | 221 |
202 for (path::const_iterator I = path::begin(Path), E = path::end(Path); I != E; | 222 EXPECT_EQ("foo", path::filename("foo")); |
203 ++I) { | 223 EXPECT_EQ("", path::parent_path("foo")); |
204 ActualPathComponents.push_back(*I); | 224 |
205 } | 225 EXPECT_EQ(".", path::filename("foo/")); |
206 | 226 EXPECT_EQ("foo", path::parent_path("foo/")); |
207 ASSERT_EQ(ExpectedPathComponents.size(), ActualPathComponents.size()); | 227 |
208 | 228 EXPECT_EQ("//net", path::filename("//net")); |
209 for (size_t i = 0; i <ExpectedPathComponents.size(); ++i) { | 229 EXPECT_EQ("", path::parent_path("//net")); |
210 EXPECT_EQ(ExpectedPathComponents[i].str(), ActualPathComponents[i].str()); | 230 |
211 } | 231 EXPECT_EQ("/", path::filename("//net/")); |
212 } | 232 EXPECT_EQ("//net", path::parent_path("//net/")); |
213 | 233 |
214 TEST(Support, AbsolutePathIterator) { | 234 EXPECT_EQ("foo", path::filename("//net/foo")); |
215 SmallString<64> Path(StringRef("/c/d/e/foo.txt")); | 235 EXPECT_EQ("//net/", path::parent_path("//net/foo")); |
216 typedef SmallVector<StringRef, 4> PathComponents; | 236 |
217 PathComponents ExpectedPathComponents; | 237 // These checks are just to make sure we do something reasonable with the |
218 PathComponents ActualPathComponents; | 238 // paths below. They are not meant to prescribe the one true interpretation of |
219 | 239 // these paths. Other decompositions (e.g. "//" -> "" + "//") are also |
220 StringRef(Path).split(ExpectedPathComponents, '/'); | 240 // possible. |
221 | 241 EXPECT_EQ("/", path::filename("//")); |
222 // The root path will also be a component when iterating | 242 EXPECT_EQ("", path::parent_path("//")); |
223 ExpectedPathComponents[0] = "/"; | 243 |
224 | 244 EXPECT_EQ("\\", path::filename("\\\\", path::Style::windows)); |
225 for (path::const_iterator I = path::begin(Path), E = path::end(Path); I != E; | 245 EXPECT_EQ("", path::parent_path("\\\\", path::Style::windows)); |
226 ++I) { | 246 |
227 ActualPathComponents.push_back(*I); | 247 EXPECT_EQ("\\", path::filename("\\\\\\", path::Style::windows)); |
228 } | 248 EXPECT_EQ("", path::parent_path("\\\\\\", path::Style::windows)); |
229 | 249 } |
230 ASSERT_EQ(ExpectedPathComponents.size(), ActualPathComponents.size()); | 250 |
231 | 251 static std::vector<StringRef> |
232 for (size_t i = 0; i <ExpectedPathComponents.size(); ++i) { | 252 GetComponents(StringRef Path, path::Style S = path::Style::native) { |
233 EXPECT_EQ(ExpectedPathComponents[i].str(), ActualPathComponents[i].str()); | 253 return {path::begin(Path, S), path::end(Path)}; |
234 } | 254 } |
235 } | 255 |
236 | 256 TEST(Support, PathIterator) { |
237 TEST(Support, AbsolutePathDotIterator) { | 257 EXPECT_THAT(GetComponents("/foo"), testing::ElementsAre("/", "foo")); |
238 SmallString<64> Path(StringRef("/.c/.d/../.")); | 258 EXPECT_THAT(GetComponents("/"), testing::ElementsAre("/")); |
239 typedef SmallVector<StringRef, 4> PathComponents; | 259 EXPECT_THAT(GetComponents("//"), testing::ElementsAre("/")); |
240 PathComponents ExpectedPathComponents; | 260 EXPECT_THAT(GetComponents("///"), testing::ElementsAre("/")); |
241 PathComponents ActualPathComponents; | 261 EXPECT_THAT(GetComponents("c/d/e/foo.txt"), |
242 | 262 testing::ElementsAre("c", "d", "e", "foo.txt")); |
243 StringRef(Path).split(ExpectedPathComponents, '/'); | 263 EXPECT_THAT(GetComponents(".c/.d/../."), |
244 | 264 testing::ElementsAre(".c", ".d", "..", ".")); |
245 // The root path will also be a component when iterating | 265 EXPECT_THAT(GetComponents("/c/d/e/foo.txt"), |
246 ExpectedPathComponents[0] = "/"; | 266 testing::ElementsAre("/", "c", "d", "e", "foo.txt")); |
247 | 267 EXPECT_THAT(GetComponents("/.c/.d/../."), |
248 for (path::const_iterator I = path::begin(Path), E = path::end(Path); I != E; | 268 testing::ElementsAre("/", ".c", ".d", "..", ".")); |
249 ++I) { | 269 EXPECT_THAT(GetComponents("c:\\c\\e\\foo.txt", path::Style::windows), |
250 ActualPathComponents.push_back(*I); | 270 testing::ElementsAre("c:", "\\", "c", "e", "foo.txt")); |
251 } | 271 EXPECT_THAT(GetComponents("//net/"), testing::ElementsAre("//net", "/")); |
252 | 272 EXPECT_THAT(GetComponents("//net/c/foo.txt"), |
253 ASSERT_EQ(ExpectedPathComponents.size(), ActualPathComponents.size()); | 273 testing::ElementsAre("//net", "/", "c", "foo.txt")); |
254 | |
255 for (size_t i = 0; i <ExpectedPathComponents.size(); ++i) { | |
256 EXPECT_EQ(ExpectedPathComponents[i].str(), ActualPathComponents[i].str()); | |
257 } | |
258 } | |
259 | |
260 TEST(Support, AbsolutePathIteratorWin32) { | |
261 SmallString<64> Path(StringRef("c:\\c\\e\\foo.txt")); | |
262 typedef SmallVector<StringRef, 4> PathComponents; | |
263 PathComponents ExpectedPathComponents; | |
264 PathComponents ActualPathComponents; | |
265 | |
266 StringRef(Path).split(ExpectedPathComponents, "\\"); | |
267 | |
268 // The root path (which comes after the drive name) will also be a component | |
269 // when iterating. | |
270 ExpectedPathComponents.insert(ExpectedPathComponents.begin()+1, "\\"); | |
271 | |
272 for (path::const_iterator I = path::begin(Path, path::Style::windows), | |
273 E = path::end(Path); | |
274 I != E; ++I) { | |
275 ActualPathComponents.push_back(*I); | |
276 } | |
277 | |
278 ASSERT_EQ(ExpectedPathComponents.size(), ActualPathComponents.size()); | |
279 | |
280 for (size_t i = 0; i <ExpectedPathComponents.size(); ++i) { | |
281 EXPECT_EQ(ExpectedPathComponents[i].str(), ActualPathComponents[i].str()); | |
282 } | |
283 } | 274 } |
284 | 275 |
285 TEST(Support, AbsolutePathIteratorEnd) { | 276 TEST(Support, AbsolutePathIteratorEnd) { |
286 // Trailing slashes are converted to '.' unless they are part of the root path. | 277 // Trailing slashes are converted to '.' unless they are part of the root path. |
287 SmallVector<std::pair<StringRef, path::Style>, 4> Paths; | 278 SmallVector<std::pair<StringRef, path::Style>, 4> Paths; |
288 Paths.emplace_back("/foo/", path::Style::native); | 279 Paths.emplace_back("/foo/", path::Style::native); |
289 Paths.emplace_back("/foo//", path::Style::native); | 280 Paths.emplace_back("/foo//", path::Style::native); |
290 Paths.emplace_back("//net//", path::Style::native); | 281 Paths.emplace_back("//net/foo/", path::Style::native); |
291 Paths.emplace_back("c:\\\\", path::Style::windows); | 282 Paths.emplace_back("c:\\foo\\", path::Style::windows); |
292 | 283 |
293 for (auto &Path : Paths) { | 284 for (auto &Path : Paths) { |
285 SCOPED_TRACE(Path.first); | |
294 StringRef LastComponent = *path::rbegin(Path.first, Path.second); | 286 StringRef LastComponent = *path::rbegin(Path.first, Path.second); |
295 EXPECT_EQ(".", LastComponent); | 287 EXPECT_EQ(".", LastComponent); |
296 } | 288 } |
297 | 289 |
298 SmallVector<std::pair<StringRef, path::Style>, 3> RootPaths; | 290 SmallVector<std::pair<StringRef, path::Style>, 3> RootPaths; |
299 RootPaths.emplace_back("/", path::Style::native); | 291 RootPaths.emplace_back("/", path::Style::native); |
300 RootPaths.emplace_back("//net/", path::Style::native); | 292 RootPaths.emplace_back("//net/", path::Style::native); |
301 RootPaths.emplace_back("c:\\", path::Style::windows); | 293 RootPaths.emplace_back("c:\\", path::Style::windows); |
294 RootPaths.emplace_back("//net//", path::Style::native); | |
295 RootPaths.emplace_back("c:\\\\", path::Style::windows); | |
302 | 296 |
303 for (auto &Path : RootPaths) { | 297 for (auto &Path : RootPaths) { |
298 SCOPED_TRACE(Path.first); | |
304 StringRef LastComponent = *path::rbegin(Path.first, Path.second); | 299 StringRef LastComponent = *path::rbegin(Path.first, Path.second); |
305 EXPECT_EQ(1u, LastComponent.size()); | 300 EXPECT_EQ(1u, LastComponent.size()); |
306 EXPECT_TRUE(path::is_separator(LastComponent[0], Path.second)); | 301 EXPECT_TRUE(path::is_separator(LastComponent[0], Path.second)); |
307 } | 302 } |
308 } | 303 } |
309 | 304 |
310 TEST(Support, HomeDirectory) { | 305 TEST(Support, HomeDirectory) { |
311 std::string expected; | 306 std::string expected; |
312 #ifdef LLVM_ON_WIN32 | 307 #ifdef _WIN32 |
313 if (wchar_t const *path = ::_wgetenv(L"USERPROFILE")) { | 308 if (wchar_t const *path = ::_wgetenv(L"USERPROFILE")) { |
314 auto pathLen = ::wcslen(path); | 309 auto pathLen = ::wcslen(path); |
315 ArrayRef<char> ref{reinterpret_cast<char const *>(path), | 310 ArrayRef<char> ref{reinterpret_cast<char const *>(path), |
316 pathLen * sizeof(wchar_t)}; | 311 pathLen * sizeof(wchar_t)}; |
317 convertUTF16ToUTF8String(ref, expected); | 312 convertUTF16ToUTF8String(ref, expected); |
358 // unset before, we don't reset it). | 353 // unset before, we don't reset it). |
359 if (OriginalEnv) ::setenv("HOME", OriginalEnv, 1); | 354 if (OriginalEnv) ::setenv("HOME", OriginalEnv, 1); |
360 } | 355 } |
361 #endif | 356 #endif |
362 | 357 |
363 TEST(Support, UserCacheDirectory) { | |
364 SmallString<13> CacheDir; | |
365 SmallString<20> CacheDir2; | |
366 auto Status = path::user_cache_directory(CacheDir, ""); | |
367 EXPECT_TRUE(Status ^ CacheDir.empty()); | |
368 | |
369 if (Status) { | |
370 EXPECT_TRUE(path::user_cache_directory(CacheDir2, "")); // should succeed | |
371 EXPECT_EQ(CacheDir, CacheDir2); // and return same paths | |
372 | |
373 EXPECT_TRUE(path::user_cache_directory(CacheDir, "A", "B", "file.c")); | |
374 auto It = path::rbegin(CacheDir); | |
375 EXPECT_EQ("file.c", *It); | |
376 EXPECT_EQ("B", *++It); | |
377 EXPECT_EQ("A", *++It); | |
378 auto ParentDir = *++It; | |
379 | |
380 // Test Unicode: "<user_cache_dir>/(pi)r^2/aleth.0" | |
381 EXPECT_TRUE(path::user_cache_directory(CacheDir2, "\xCF\x80r\xC2\xB2", | |
382 "\xE2\x84\xB5.0")); | |
383 auto It2 = path::rbegin(CacheDir2); | |
384 EXPECT_EQ("\xE2\x84\xB5.0", *It2); | |
385 EXPECT_EQ("\xCF\x80r\xC2\xB2", *++It2); | |
386 auto ParentDir2 = *++It2; | |
387 | |
388 EXPECT_EQ(ParentDir, ParentDir2); | |
389 } | |
390 } | |
391 | |
392 TEST(Support, TempDirectory) { | 358 TEST(Support, TempDirectory) { |
393 SmallString<32> TempDir; | 359 SmallString<32> TempDir; |
394 path::system_temp_directory(false, TempDir); | 360 path::system_temp_directory(false, TempDir); |
395 EXPECT_TRUE(!TempDir.empty()); | 361 EXPECT_TRUE(!TempDir.empty()); |
396 TempDir.clear(); | 362 TempDir.clear(); |
397 path::system_temp_directory(true, TempDir); | 363 path::system_temp_directory(true, TempDir); |
398 EXPECT_TRUE(!TempDir.empty()); | 364 EXPECT_TRUE(!TempDir.empty()); |
399 } | 365 } |
400 | 366 |
401 #ifdef LLVM_ON_WIN32 | 367 #ifdef _WIN32 |
402 static std::string path2regex(std::string Path) { | 368 static std::string path2regex(std::string Path) { |
403 size_t Pos = 0; | 369 size_t Pos = 0; |
404 while ((Pos = Path.find('\\', Pos)) != std::string::npos) { | 370 while ((Pos = Path.find('\\', Pos)) != std::string::npos) { |
405 Path.replace(Pos, 1, "\\\\"); | 371 Path.replace(Pos, 1, "\\\\"); |
406 Pos += 2; | 372 Pos += 2; |
462 class FileSystemTest : public testing::Test { | 428 class FileSystemTest : public testing::Test { |
463 protected: | 429 protected: |
464 /// Unique temporary directory in which all created filesystem entities must | 430 /// Unique temporary directory in which all created filesystem entities must |
465 /// be placed. It is removed at the end of each test (must be empty). | 431 /// be placed. It is removed at the end of each test (must be empty). |
466 SmallString<128> TestDirectory; | 432 SmallString<128> TestDirectory; |
433 SmallString<128> NonExistantFile; | |
467 | 434 |
468 void SetUp() override { | 435 void SetUp() override { |
469 ASSERT_NO_ERROR( | 436 ASSERT_NO_ERROR( |
470 fs::createUniqueDirectory("file-system-test", TestDirectory)); | 437 fs::createUniqueDirectory("file-system-test", TestDirectory)); |
471 // We don't care about this specific file. | 438 // We don't care about this specific file. |
472 errs() << "Test Directory: " << TestDirectory << '\n'; | 439 errs() << "Test Directory: " << TestDirectory << '\n'; |
473 errs().flush(); | 440 errs().flush(); |
441 NonExistantFile = TestDirectory; | |
442 | |
443 // Even though this value is hardcoded, is a 128-bit GUID, so we should be | |
444 // guaranteed that this file will never exist. | |
445 sys::path::append(NonExistantFile, "1B28B495C16344CB9822E588CD4C3EF0"); | |
474 } | 446 } |
475 | 447 |
476 void TearDown() override { ASSERT_NO_ERROR(fs::remove(TestDirectory.str())); } | 448 void TearDown() override { ASSERT_NO_ERROR(fs::remove(TestDirectory.str())); } |
477 }; | 449 }; |
478 | 450 |
550 Twine(TestDirectory) + "/././test1/../test1/test2/./test3/..", Actual)); | 522 Twine(TestDirectory) + "/././test1/../test1/test2/./test3/..", Actual)); |
551 | 523 |
552 EXPECT_EQ(Expected, Actual); | 524 EXPECT_EQ(Expected, Actual); |
553 | 525 |
554 SmallString<64> HomeDir; | 526 SmallString<64> HomeDir; |
527 | |
528 // This can fail if $HOME is not set and getpwuid fails. | |
555 bool Result = llvm::sys::path::home_directory(HomeDir); | 529 bool Result = llvm::sys::path::home_directory(HomeDir); |
556 if (Result) { | 530 if (Result) { |
557 ASSERT_NO_ERROR(fs::real_path(HomeDir, Expected)); | 531 ASSERT_NO_ERROR(fs::real_path(HomeDir, Expected)); |
558 ASSERT_NO_ERROR(fs::real_path("~", Actual, true)); | 532 ASSERT_NO_ERROR(fs::real_path("~", Actual, true)); |
559 EXPECT_EQ(Expected, Actual); | 533 EXPECT_EQ(Expected, Actual); |
562 } | 536 } |
563 | 537 |
564 ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/test1")); | 538 ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/test1")); |
565 } | 539 } |
566 | 540 |
541 TEST_F(FileSystemTest, ExpandTilde) { | |
542 SmallString<64> Expected; | |
543 SmallString<64> Actual; | |
544 SmallString<64> HomeDir; | |
545 | |
546 // This can fail if $HOME is not set and getpwuid fails. | |
547 bool Result = llvm::sys::path::home_directory(HomeDir); | |
548 if (Result) { | |
549 fs::expand_tilde(HomeDir, Expected); | |
550 | |
551 fs::expand_tilde("~", Actual); | |
552 EXPECT_EQ(Expected, Actual); | |
553 | |
554 #ifdef _WIN32 | |
555 Expected += "\\foo"; | |
556 fs::expand_tilde("~\\foo", Actual); | |
557 #else | |
558 Expected += "/foo"; | |
559 fs::expand_tilde("~/foo", Actual); | |
560 #endif | |
561 | |
562 EXPECT_EQ(Expected, Actual); | |
563 } | |
564 } | |
565 | |
567 #ifdef LLVM_ON_UNIX | 566 #ifdef LLVM_ON_UNIX |
568 TEST_F(FileSystemTest, RealPathNoReadPerm) { | 567 TEST_F(FileSystemTest, RealPathNoReadPerm) { |
569 SmallString<64> Expanded; | 568 SmallString<64> Expanded; |
570 | 569 |
571 ASSERT_NO_ERROR( | 570 ASSERT_NO_ERROR( |
586 TEST_F(FileSystemTest, TempFileKeepDiscard) { | 585 TEST_F(FileSystemTest, TempFileKeepDiscard) { |
587 // We can keep then discard. | 586 // We can keep then discard. |
588 auto TempFileOrError = fs::TempFile::create(TestDirectory + "/test-%%%%"); | 587 auto TempFileOrError = fs::TempFile::create(TestDirectory + "/test-%%%%"); |
589 ASSERT_TRUE((bool)TempFileOrError); | 588 ASSERT_TRUE((bool)TempFileOrError); |
590 fs::TempFile File = std::move(*TempFileOrError); | 589 fs::TempFile File = std::move(*TempFileOrError); |
590 ASSERT_EQ(-1, TempFileOrError->FD); | |
591 ASSERT_FALSE((bool)File.keep(TestDirectory + "/keep")); | 591 ASSERT_FALSE((bool)File.keep(TestDirectory + "/keep")); |
592 ASSERT_FALSE((bool)File.discard()); | 592 ASSERT_FALSE((bool)File.discard()); |
593 ASSERT_TRUE(fs::exists(TestDirectory + "/keep")); | 593 ASSERT_TRUE(fs::exists(TestDirectory + "/keep")); |
594 ASSERT_NO_ERROR(fs::remove(TestDirectory + "/keep")); | 594 ASSERT_NO_ERROR(fs::remove(TestDirectory + "/keep")); |
595 } | 595 } |
597 TEST_F(FileSystemTest, TempFileDiscardDiscard) { | 597 TEST_F(FileSystemTest, TempFileDiscardDiscard) { |
598 // We can discard twice. | 598 // We can discard twice. |
599 auto TempFileOrError = fs::TempFile::create(TestDirectory + "/test-%%%%"); | 599 auto TempFileOrError = fs::TempFile::create(TestDirectory + "/test-%%%%"); |
600 ASSERT_TRUE((bool)TempFileOrError); | 600 ASSERT_TRUE((bool)TempFileOrError); |
601 fs::TempFile File = std::move(*TempFileOrError); | 601 fs::TempFile File = std::move(*TempFileOrError); |
602 ASSERT_EQ(-1, TempFileOrError->FD); | |
602 ASSERT_FALSE((bool)File.discard()); | 603 ASSERT_FALSE((bool)File.discard()); |
603 ASSERT_FALSE((bool)File.discard()); | 604 ASSERT_FALSE((bool)File.discard()); |
604 ASSERT_FALSE(fs::exists(TestDirectory + "/keep")); | 605 ASSERT_FALSE(fs::exists(TestDirectory + "/keep")); |
605 } | 606 } |
606 | 607 |
665 | 666 |
666 // Make sure Temp1 doesn't exist. | 667 // Make sure Temp1 doesn't exist. |
667 ASSERT_EQ(fs::access(Twine(TempPath), sys::fs::AccessMode::Exist), | 668 ASSERT_EQ(fs::access(Twine(TempPath), sys::fs::AccessMode::Exist), |
668 errc::no_such_file_or_directory); | 669 errc::no_such_file_or_directory); |
669 | 670 |
670 #ifdef LLVM_ON_WIN32 | 671 #ifdef _WIN32 |
671 // Path name > 260 chars should get an error. | 672 // Path name > 260 chars should get an error. |
672 const char *Path270 = | 673 const char *Path270 = |
673 "abcdefghijklmnopqrstuvwxyz9abcdefghijklmnopqrstuvwxyz8" | 674 "abcdefghijklmnopqrstuvwxyz9abcdefghijklmnopqrstuvwxyz8" |
674 "abcdefghijklmnopqrstuvwxyz7abcdefghijklmnopqrstuvwxyz6" | 675 "abcdefghijklmnopqrstuvwxyz7abcdefghijklmnopqrstuvwxyz6" |
675 "abcdefghijklmnopqrstuvwxyz5abcdefghijklmnopqrstuvwxyz4" | 676 "abcdefghijklmnopqrstuvwxyz5abcdefghijklmnopqrstuvwxyz4" |
686 ASSERT_NO_ERROR(fs::createTemporaryFile(Path216, "", TempPath)); | 687 ASSERT_NO_ERROR(fs::createTemporaryFile(Path216, "", TempPath)); |
687 ASSERT_NO_ERROR(fs::remove(Twine(TempPath))); | 688 ASSERT_NO_ERROR(fs::remove(Twine(TempPath))); |
688 #endif | 689 #endif |
689 } | 690 } |
690 | 691 |
692 TEST_F(FileSystemTest, TempFileCollisions) { | |
693 SmallString<128> TestDirectory; | |
694 ASSERT_NO_ERROR( | |
695 fs::createUniqueDirectory("CreateUniqueFileTest", TestDirectory)); | |
696 FileRemover Cleanup(TestDirectory); | |
697 SmallString<128> Model = TestDirectory; | |
698 path::append(Model, "%.tmp"); | |
699 SmallString<128> Path; | |
700 std::vector<fs::TempFile> TempFiles; | |
701 | |
702 auto TryCreateTempFile = [&]() { | |
703 Expected<fs::TempFile> T = fs::TempFile::create(Model); | |
704 if (T) { | |
705 TempFiles.push_back(std::move(*T)); | |
706 return true; | |
707 } else { | |
708 logAllUnhandledErrors(T.takeError(), errs(), | |
709 "Failed to create temporary file: "); | |
710 return false; | |
711 } | |
712 }; | |
713 | |
714 // Our single-character template allows for 16 unique names. Check that | |
715 // calling TryCreateTempFile repeatedly results in 16 successes. | |
716 // Because the test depends on random numbers, it could theoretically fail. | |
717 // However, the probability of this happening is tiny: with 32 calls, each | |
718 // of which will retry up to 128 times, to not get a given digit we would | |
719 // have to fail at least 15 + 17 * 128 = 2191 attempts. The probability of | |
720 // 2191 attempts not producing a given hexadecimal digit is | |
721 // (1 - 1/16) ** 2191 or 3.88e-62. | |
722 int Successes = 0; | |
723 for (int i = 0; i < 32; ++i) | |
724 if (TryCreateTempFile()) ++Successes; | |
725 EXPECT_EQ(Successes, 16); | |
726 | |
727 for (fs::TempFile &T : TempFiles) | |
728 cantFail(T.discard()); | |
729 } | |
730 | |
691 TEST_F(FileSystemTest, CreateDir) { | 731 TEST_F(FileSystemTest, CreateDir) { |
692 ASSERT_NO_ERROR(fs::create_directory(Twine(TestDirectory) + "foo")); | 732 ASSERT_NO_ERROR(fs::create_directory(Twine(TestDirectory) + "foo")); |
693 ASSERT_NO_ERROR(fs::create_directory(Twine(TestDirectory) + "foo")); | 733 ASSERT_NO_ERROR(fs::create_directory(Twine(TestDirectory) + "foo")); |
694 ASSERT_EQ(fs::create_directory(Twine(TestDirectory) + "foo", false), | 734 ASSERT_EQ(fs::create_directory(Twine(TestDirectory) + "foo", false), |
695 errc::file_exists); | 735 errc::file_exists); |
713 | 753 |
714 // Restore umask to be safe. | 754 // Restore umask to be safe. |
715 ::umask(OldUmask); | 755 ::umask(OldUmask); |
716 #endif | 756 #endif |
717 | 757 |
718 #ifdef LLVM_ON_WIN32 | 758 #ifdef _WIN32 |
719 // Prove that create_directories() can handle a pathname > 248 characters, | 759 // Prove that create_directories() can handle a pathname > 248 characters, |
720 // which is the documented limit for CreateDirectory(). | 760 // which is the documented limit for CreateDirectory(). |
721 // (248 is MAX_PATH subtracting room for an 8.3 filename.) | 761 // (248 is MAX_PATH subtracting room for an 8.3 filename.) |
722 // Generate a directory path guaranteed to fall into that range. | 762 // Generate a directory path guaranteed to fall into that range. |
723 size_t TmpLen = TestDirectory.size(); | 763 size_t TmpLen = TestDirectory.size(); |
883 Twine(TestDirectory) + "/symlink/d/da")); | 923 Twine(TestDirectory) + "/symlink/d/da")); |
884 ASSERT_NO_ERROR( | 924 ASSERT_NO_ERROR( |
885 fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/e")); | 925 fs::create_link("no_such_file", Twine(TestDirectory) + "/symlink/e")); |
886 | 926 |
887 typedef std::vector<std::string> v_t; | 927 typedef std::vector<std::string> v_t; |
888 v_t visited; | 928 v_t VisitedNonBrokenSymlinks; |
889 | 929 v_t VisitedBrokenSymlinks; |
890 // The directory iterator doesn't stat the file, so we should be able to | |
891 // iterate over the whole directory. | |
892 std::error_code ec; | 930 std::error_code ec; |
931 using testing::UnorderedElementsAre; | |
932 using testing::UnorderedElementsAreArray; | |
933 | |
934 // Broken symbol links are expected to throw an error. | |
893 for (fs::directory_iterator i(Twine(TestDirectory) + "/symlink", ec), e; | 935 for (fs::directory_iterator i(Twine(TestDirectory) + "/symlink", ec), e; |
894 i != e; i.increment(ec)) { | 936 i != e; i.increment(ec)) { |
895 ASSERT_NO_ERROR(ec); | 937 ASSERT_NO_ERROR(ec); |
896 visited.push_back(path::filename(i->path())); | 938 if (i->status().getError() == |
897 } | 939 std::make_error_code(std::errc::no_such_file_or_directory)) { |
898 std::sort(visited.begin(), visited.end()); | 940 VisitedBrokenSymlinks.push_back(path::filename(i->path())); |
899 v_t expected = {"a", "b", "c", "d", "e"}; | 941 continue; |
900 ASSERT_TRUE(visited.size() == expected.size()); | 942 } |
901 ASSERT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin())); | 943 VisitedNonBrokenSymlinks.push_back(path::filename(i->path())); |
902 visited.clear(); | 944 } |
903 | 945 EXPECT_THAT(VisitedNonBrokenSymlinks, UnorderedElementsAre("b", "d")); |
904 // The recursive directory iterator has to stat the file, so we need to skip | 946 VisitedNonBrokenSymlinks.clear(); |
905 // the broken symlinks. | 947 |
906 for (fs::recursive_directory_iterator | 948 EXPECT_THAT(VisitedBrokenSymlinks, UnorderedElementsAre("a", "c", "e")); |
907 i(Twine(TestDirectory) + "/symlink", ec), | 949 VisitedBrokenSymlinks.clear(); |
908 e; | 950 |
951 // Broken symbol links are expected to throw an error. | |
952 for (fs::recursive_directory_iterator i( | |
953 Twine(TestDirectory) + "/symlink", ec), e; i != e; i.increment(ec)) { | |
954 ASSERT_NO_ERROR(ec); | |
955 if (i->status().getError() == | |
956 std::make_error_code(std::errc::no_such_file_or_directory)) { | |
957 VisitedBrokenSymlinks.push_back(path::filename(i->path())); | |
958 continue; | |
959 } | |
960 VisitedNonBrokenSymlinks.push_back(path::filename(i->path())); | |
961 } | |
962 EXPECT_THAT(VisitedNonBrokenSymlinks, | |
963 UnorderedElementsAre("b", "bb", "d", "da", "dd", "ddd", "ddd")); | |
964 VisitedNonBrokenSymlinks.clear(); | |
965 | |
966 EXPECT_THAT(VisitedBrokenSymlinks, | |
967 UnorderedElementsAre("a", "ba", "bc", "c", "e")); | |
968 VisitedBrokenSymlinks.clear(); | |
969 | |
970 for (fs::recursive_directory_iterator i( | |
971 Twine(TestDirectory) + "/symlink", ec, /*follow_symlinks=*/false), e; | |
909 i != e; i.increment(ec)) { | 972 i != e; i.increment(ec)) { |
910 ASSERT_NO_ERROR(ec); | 973 ASSERT_NO_ERROR(ec); |
911 | 974 if (i->status().getError() == |
912 ErrorOr<fs::basic_file_status> status = i->status(); | |
913 if (status.getError() == | |
914 std::make_error_code(std::errc::no_such_file_or_directory)) { | 975 std::make_error_code(std::errc::no_such_file_or_directory)) { |
915 i.no_push(); | 976 VisitedBrokenSymlinks.push_back(path::filename(i->path())); |
916 continue; | 977 continue; |
917 } | 978 } |
918 | 979 VisitedNonBrokenSymlinks.push_back(path::filename(i->path())); |
919 visited.push_back(path::filename(i->path())); | 980 } |
920 } | 981 EXPECT_THAT(VisitedNonBrokenSymlinks, |
921 std::sort(visited.begin(), visited.end()); | 982 UnorderedElementsAreArray({"a", "b", "ba", "bb", "bc", "c", "d", |
922 expected = {"b", "bb", "d", "da", "dd", "ddd", "ddd"}; | 983 "da", "dd", "ddd", "e"})); |
923 ASSERT_TRUE(visited.size() == expected.size()); | 984 VisitedNonBrokenSymlinks.clear(); |
924 ASSERT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin())); | 985 |
925 visited.clear(); | 986 EXPECT_THAT(VisitedBrokenSymlinks, UnorderedElementsAre()); |
926 | 987 VisitedBrokenSymlinks.clear(); |
927 // This recursive directory iterator doesn't follow symlinks, so we don't need | |
928 // to skip them. | |
929 for (fs::recursive_directory_iterator | |
930 i(Twine(TestDirectory) + "/symlink", ec, /*follow_symlinks=*/false), | |
931 e; | |
932 i != e; i.increment(ec)) { | |
933 ASSERT_NO_ERROR(ec); | |
934 visited.push_back(path::filename(i->path())); | |
935 } | |
936 std::sort(visited.begin(), visited.end()); | |
937 expected = {"a", "b", "ba", "bb", "bc", "c", "d", "da", "dd", "ddd", "e"}; | |
938 ASSERT_TRUE(visited.size() == expected.size()); | |
939 ASSERT_TRUE(std::equal(visited.begin(), visited.end(), expected.begin())); | |
940 | 988 |
941 ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/symlink")); | 989 ASSERT_NO_ERROR(fs::remove_directories(Twine(TestDirectory) + "/symlink")); |
942 } | 990 } |
943 #endif | 991 #endif |
944 | 992 |
973 | 1021 |
974 ASSERT_NO_ERROR(fs::remove_directories(BaseDir)); | 1022 ASSERT_NO_ERROR(fs::remove_directories(BaseDir)); |
975 ASSERT_FALSE(fs::exists(BaseDir)); | 1023 ASSERT_FALSE(fs::exists(BaseDir)); |
976 } | 1024 } |
977 | 1025 |
978 #ifdef LLVM_ON_WIN32 | 1026 #ifdef _WIN32 |
979 TEST_F(FileSystemTest, CarriageReturn) { | 1027 TEST_F(FileSystemTest, CarriageReturn) { |
980 SmallString<128> FilePathname(TestDirectory); | 1028 SmallString<128> FilePathname(TestDirectory); |
981 std::error_code EC; | 1029 std::error_code EC; |
982 path::append(FilePathname, "test"); | 1030 path::append(FilePathname, "test"); |
983 | 1031 |
984 { | 1032 { |
985 raw_fd_ostream File(FilePathname, EC, sys::fs::F_Text); | 1033 raw_fd_ostream File(FilePathname, EC, sys::fs::OF_Text); |
986 ASSERT_NO_ERROR(EC); | 1034 ASSERT_NO_ERROR(EC); |
987 File << '\n'; | 1035 File << '\n'; |
988 } | 1036 } |
989 { | 1037 { |
990 auto Buf = MemoryBuffer::getFile(FilePathname.str()); | 1038 auto Buf = MemoryBuffer::getFile(FilePathname.str()); |
991 EXPECT_TRUE((bool)Buf); | 1039 EXPECT_TRUE((bool)Buf); |
992 EXPECT_EQ(Buf.get()->getBuffer(), "\r\n"); | 1040 EXPECT_EQ(Buf.get()->getBuffer(), "\r\n"); |
993 } | 1041 } |
994 | 1042 |
995 { | 1043 { |
996 raw_fd_ostream File(FilePathname, EC, sys::fs::F_None); | 1044 raw_fd_ostream File(FilePathname, EC, sys::fs::OF_None); |
997 ASSERT_NO_ERROR(EC); | 1045 ASSERT_NO_ERROR(EC); |
998 File << '\n'; | 1046 File << '\n'; |
999 } | 1047 } |
1000 { | 1048 { |
1001 auto Buf = MemoryBuffer::getFile(FilePathname.str()); | 1049 auto Buf = MemoryBuffer::getFile(FilePathname.str()); |
1043 | 1091 |
1044 // Map in temp file and add some content | 1092 // Map in temp file and add some content |
1045 std::error_code EC; | 1093 std::error_code EC; |
1046 StringRef Val("hello there"); | 1094 StringRef Val("hello there"); |
1047 { | 1095 { |
1048 fs::mapped_file_region mfr(FileDescriptor, | 1096 fs::mapped_file_region mfr(fs::convertFDToNativeFile(FileDescriptor), |
1049 fs::mapped_file_region::readwrite, Size, 0, EC); | 1097 fs::mapped_file_region::readwrite, Size, 0, EC); |
1050 ASSERT_NO_ERROR(EC); | 1098 ASSERT_NO_ERROR(EC); |
1051 std::copy(Val.begin(), Val.end(), mfr.data()); | 1099 std::copy(Val.begin(), Val.end(), mfr.data()); |
1052 // Explicitly add a 0. | 1100 // Explicitly add a 0. |
1053 mfr.data()[Val.size()] = 0; | 1101 mfr.data()[Val.size()] = 0; |
1058 // Map it back in read-only | 1106 // Map it back in read-only |
1059 { | 1107 { |
1060 int FD; | 1108 int FD; |
1061 EC = fs::openFileForRead(Twine(TempPath), FD); | 1109 EC = fs::openFileForRead(Twine(TempPath), FD); |
1062 ASSERT_NO_ERROR(EC); | 1110 ASSERT_NO_ERROR(EC); |
1063 fs::mapped_file_region mfr(FD, fs::mapped_file_region::readonly, Size, 0, EC); | 1111 fs::mapped_file_region mfr(fs::convertFDToNativeFile(FD), |
1112 fs::mapped_file_region::readonly, Size, 0, EC); | |
1064 ASSERT_NO_ERROR(EC); | 1113 ASSERT_NO_ERROR(EC); |
1065 | 1114 |
1066 // Verify content | 1115 // Verify content |
1067 EXPECT_EQ(StringRef(mfr.const_data()), Val); | 1116 EXPECT_EQ(StringRef(mfr.const_data()), Val); |
1068 | 1117 |
1069 // Unmap temp file | 1118 // Unmap temp file |
1070 fs::mapped_file_region m(FD, fs::mapped_file_region::readonly, Size, 0, EC); | 1119 fs::mapped_file_region m(fs::convertFDToNativeFile(FD), |
1120 fs::mapped_file_region::readonly, Size, 0, EC); | |
1071 ASSERT_NO_ERROR(EC); | 1121 ASSERT_NO_ERROR(EC); |
1072 ASSERT_EQ(close(FD), 0); | 1122 ASSERT_EQ(close(FD), 0); |
1073 } | 1123 } |
1074 ASSERT_NO_ERROR(fs::remove(TempPath)); | 1124 ASSERT_NO_ERROR(fs::remove(TempPath)); |
1075 } | 1125 } |
1091 path::native(Posix, path::Style::posix); | 1141 path::native(Posix, path::Style::posix); |
1092 EXPECT_EQ(std::get<1>(T), Win); | 1142 EXPECT_EQ(std::get<1>(T), Win); |
1093 EXPECT_EQ(std::get<2>(T), Posix); | 1143 EXPECT_EQ(std::get<2>(T), Posix); |
1094 } | 1144 } |
1095 | 1145 |
1096 #if defined(LLVM_ON_WIN32) | 1146 #if defined(_WIN32) |
1097 SmallString<64> PathHome; | 1147 SmallString<64> PathHome; |
1098 path::home_directory(PathHome); | 1148 path::home_directory(PathHome); |
1099 | 1149 |
1100 const char *Path7a = "~/aaa"; | 1150 const char *Path7a = "~/aaa"; |
1101 SmallString<64> Path7(Path7a); | 1151 SmallString<64> Path7(Path7a); |
1212 ASSERT_TRUE(sys::fs::exists(Twine(TempPath))); | 1262 ASSERT_TRUE(sys::fs::exists(Twine(TempPath))); |
1213 | 1263 |
1214 // Open the file for read | 1264 // Open the file for read |
1215 int FileDescriptor2; | 1265 int FileDescriptor2; |
1216 SmallString<64> ResultPath; | 1266 SmallString<64> ResultPath; |
1217 ASSERT_NO_ERROR( | 1267 ASSERT_NO_ERROR(fs::openFileForRead(Twine(TempPath), FileDescriptor2, |
1218 fs::openFileForRead(Twine(TempPath), FileDescriptor2, &ResultPath)) | 1268 fs::OF_None, &ResultPath)) |
1219 | 1269 |
1220 // If we succeeded, check that the paths are the same (modulo case): | 1270 // If we succeeded, check that the paths are the same (modulo case): |
1221 if (!ResultPath.empty()) { | 1271 if (!ResultPath.empty()) { |
1222 // The paths returned by createTemporaryFile and getPathFromOpenFD | 1272 // The paths returned by createTemporaryFile and getPathFromOpenFD |
1223 // should reference the same file on disk. | 1273 // should reference the same file on disk. |
1224 fs::UniqueID D1, D2; | 1274 fs::UniqueID D1, D2; |
1225 ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), D1)); | 1275 ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), D1)); |
1226 ASSERT_NO_ERROR(fs::getUniqueID(Twine(ResultPath), D2)); | 1276 ASSERT_NO_ERROR(fs::getUniqueID(Twine(ResultPath), D2)); |
1227 ASSERT_EQ(D1, D2); | 1277 ASSERT_EQ(D1, D2); |
1228 } | 1278 } |
1229 | |
1230 ::close(FileDescriptor); | 1279 ::close(FileDescriptor); |
1280 ::close(FileDescriptor2); | |
1281 | |
1282 #ifdef _WIN32 | |
1283 // Since Windows Vista, file access time is not updated by default. | |
1284 // This is instead updated manually by openFileForRead. | |
1285 // https://blogs.technet.microsoft.com/filecab/2006/11/07/disabling-last-access-time-in-windows-vista-to-improve-ntfs-performance/ | |
1286 // This part of the unit test is Windows specific as the updating of | |
1287 // access times can be disabled on Linux using /etc/fstab. | |
1288 | |
1289 // Set access time to UNIX epoch. | |
1290 ASSERT_NO_ERROR(sys::fs::openFileForWrite(Twine(TempPath), FileDescriptor, | |
1291 fs::CD_OpenExisting)); | |
1292 TimePoint<> Epoch(std::chrono::milliseconds(0)); | |
1293 ASSERT_NO_ERROR(fs::setLastAccessAndModificationTime(FileDescriptor, Epoch)); | |
1294 ::close(FileDescriptor); | |
1295 | |
1296 // Open the file and ensure access time is updated, when forced. | |
1297 ASSERT_NO_ERROR(fs::openFileForRead(Twine(TempPath), FileDescriptor, | |
1298 fs::OF_UpdateAtime, &ResultPath)); | |
1299 | |
1300 sys::fs::file_status Status; | |
1301 ASSERT_NO_ERROR(sys::fs::status(FileDescriptor, Status)); | |
1302 auto FileAccessTime = Status.getLastAccessedTime(); | |
1303 | |
1304 ASSERT_NE(Epoch, FileAccessTime); | |
1305 ::close(FileDescriptor); | |
1306 | |
1307 // Ideally this test would include a case when ATime is not forced to update, | |
1308 // however the expected behaviour will differ depending on the configuration | |
1309 // of the Windows file system. | |
1310 #endif | |
1311 } | |
1312 | |
1313 static void createFileWithData(const Twine &Path, bool ShouldExistBefore, | |
1314 fs::CreationDisposition Disp, StringRef Data) { | |
1315 int FD; | |
1316 ASSERT_EQ(ShouldExistBefore, fs::exists(Path)); | |
1317 ASSERT_NO_ERROR(fs::openFileForWrite(Path, FD, Disp)); | |
1318 FileDescriptorCloser Closer(FD); | |
1319 ASSERT_TRUE(fs::exists(Path)); | |
1320 | |
1321 ASSERT_EQ(Data.size(), (size_t)write(FD, Data.data(), Data.size())); | |
1322 } | |
1323 | |
1324 static void verifyFileContents(const Twine &Path, StringRef Contents) { | |
1325 auto Buffer = MemoryBuffer::getFile(Path); | |
1326 ASSERT_TRUE((bool)Buffer); | |
1327 StringRef Data = Buffer.get()->getBuffer(); | |
1328 ASSERT_EQ(Data, Contents); | |
1329 } | |
1330 | |
1331 TEST_F(FileSystemTest, CreateNew) { | |
1332 int FD; | |
1333 Optional<FileDescriptorCloser> Closer; | |
1334 | |
1335 // Succeeds if the file does not exist. | |
1336 ASSERT_FALSE(fs::exists(NonExistantFile)); | |
1337 ASSERT_NO_ERROR(fs::openFileForWrite(NonExistantFile, FD, fs::CD_CreateNew)); | |
1338 ASSERT_TRUE(fs::exists(NonExistantFile)); | |
1339 | |
1340 FileRemover Cleanup(NonExistantFile); | |
1341 Closer.emplace(FD); | |
1342 | |
1343 // And creates a file of size 0. | |
1344 sys::fs::file_status Status; | |
1345 ASSERT_NO_ERROR(sys::fs::status(FD, Status)); | |
1346 EXPECT_EQ(0ULL, Status.getSize()); | |
1347 | |
1348 // Close this first, before trying to re-open the file. | |
1349 Closer.reset(); | |
1350 | |
1351 // But fails if the file does exist. | |
1352 ASSERT_ERROR(fs::openFileForWrite(NonExistantFile, FD, fs::CD_CreateNew)); | |
1353 } | |
1354 | |
1355 TEST_F(FileSystemTest, CreateAlways) { | |
1356 int FD; | |
1357 Optional<FileDescriptorCloser> Closer; | |
1358 | |
1359 // Succeeds if the file does not exist. | |
1360 ASSERT_FALSE(fs::exists(NonExistantFile)); | |
1361 ASSERT_NO_ERROR( | |
1362 fs::openFileForWrite(NonExistantFile, FD, fs::CD_CreateAlways)); | |
1363 | |
1364 Closer.emplace(FD); | |
1365 | |
1366 ASSERT_TRUE(fs::exists(NonExistantFile)); | |
1367 | |
1368 FileRemover Cleanup(NonExistantFile); | |
1369 | |
1370 // And creates a file of size 0. | |
1371 uint64_t FileSize; | |
1372 ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize)); | |
1373 ASSERT_EQ(0ULL, FileSize); | |
1374 | |
1375 // If we write some data to it re-create it with CreateAlways, it succeeds and | |
1376 // truncates to 0 bytes. | |
1377 ASSERT_EQ(4, write(FD, "Test", 4)); | |
1378 | |
1379 Closer.reset(); | |
1380 | |
1381 ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize)); | |
1382 ASSERT_EQ(4ULL, FileSize); | |
1383 | |
1384 ASSERT_NO_ERROR( | |
1385 fs::openFileForWrite(NonExistantFile, FD, fs::CD_CreateAlways)); | |
1386 Closer.emplace(FD); | |
1387 ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize)); | |
1388 ASSERT_EQ(0ULL, FileSize); | |
1389 } | |
1390 | |
1391 TEST_F(FileSystemTest, OpenExisting) { | |
1392 int FD; | |
1393 | |
1394 // Fails if the file does not exist. | |
1395 ASSERT_FALSE(fs::exists(NonExistantFile)); | |
1396 ASSERT_ERROR(fs::openFileForWrite(NonExistantFile, FD, fs::CD_OpenExisting)); | |
1397 ASSERT_FALSE(fs::exists(NonExistantFile)); | |
1398 | |
1399 // Make a dummy file now so that we can try again when the file does exist. | |
1400 createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz"); | |
1401 FileRemover Cleanup(NonExistantFile); | |
1402 uint64_t FileSize; | |
1403 ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize)); | |
1404 ASSERT_EQ(4ULL, FileSize); | |
1405 | |
1406 // If we re-create it with different data, it overwrites rather than | |
1407 // appending. | |
1408 createFileWithData(NonExistantFile, true, fs::CD_OpenExisting, "Buzz"); | |
1409 verifyFileContents(NonExistantFile, "Buzz"); | |
1410 } | |
1411 | |
1412 TEST_F(FileSystemTest, OpenAlways) { | |
1413 // Succeeds if the file does not exist. | |
1414 createFileWithData(NonExistantFile, false, fs::CD_OpenAlways, "Fizz"); | |
1415 FileRemover Cleanup(NonExistantFile); | |
1416 uint64_t FileSize; | |
1417 ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize)); | |
1418 ASSERT_EQ(4ULL, FileSize); | |
1419 | |
1420 // Now re-open it and write again, verifying the contents get over-written. | |
1421 createFileWithData(NonExistantFile, true, fs::CD_OpenAlways, "Bu"); | |
1422 verifyFileContents(NonExistantFile, "Buzz"); | |
1423 } | |
1424 | |
1425 TEST_F(FileSystemTest, AppendSetsCorrectFileOffset) { | |
1426 fs::CreationDisposition Disps[] = {fs::CD_CreateAlways, fs::CD_OpenAlways, | |
1427 fs::CD_OpenExisting}; | |
1428 | |
1429 // Write some data and re-open it with every possible disposition (this is a | |
1430 // hack that shouldn't work, but is left for compatibility. OF_Append | |
1431 // overrides | |
1432 // the specified disposition. | |
1433 for (fs::CreationDisposition Disp : Disps) { | |
1434 int FD; | |
1435 Optional<FileDescriptorCloser> Closer; | |
1436 | |
1437 createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz"); | |
1438 | |
1439 FileRemover Cleanup(NonExistantFile); | |
1440 | |
1441 uint64_t FileSize; | |
1442 ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize)); | |
1443 ASSERT_EQ(4ULL, FileSize); | |
1444 ASSERT_NO_ERROR( | |
1445 fs::openFileForWrite(NonExistantFile, FD, Disp, fs::OF_Append)); | |
1446 Closer.emplace(FD); | |
1447 ASSERT_NO_ERROR(sys::fs::file_size(NonExistantFile, FileSize)); | |
1448 ASSERT_EQ(4ULL, FileSize); | |
1449 | |
1450 ASSERT_EQ(4, write(FD, "Buzz", 4)); | |
1451 Closer.reset(); | |
1452 | |
1453 verifyFileContents(NonExistantFile, "FizzBuzz"); | |
1454 } | |
1455 } | |
1456 | |
1457 static void verifyRead(int FD, StringRef Data, bool ShouldSucceed) { | |
1458 std::vector<char> Buffer; | |
1459 Buffer.resize(Data.size()); | |
1460 int Result = ::read(FD, Buffer.data(), Buffer.size()); | |
1461 if (ShouldSucceed) { | |
1462 ASSERT_EQ((size_t)Result, Data.size()); | |
1463 ASSERT_EQ(Data, StringRef(Buffer.data(), Buffer.size())); | |
1464 } else { | |
1465 ASSERT_EQ(-1, Result); | |
1466 ASSERT_EQ(EBADF, errno); | |
1467 } | |
1468 } | |
1469 | |
1470 static void verifyWrite(int FD, StringRef Data, bool ShouldSucceed) { | |
1471 int Result = ::write(FD, Data.data(), Data.size()); | |
1472 if (ShouldSucceed) | |
1473 ASSERT_EQ((size_t)Result, Data.size()); | |
1474 else { | |
1475 ASSERT_EQ(-1, Result); | |
1476 ASSERT_EQ(EBADF, errno); | |
1477 } | |
1478 } | |
1479 | |
1480 TEST_F(FileSystemTest, ReadOnlyFileCantWrite) { | |
1481 createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz"); | |
1482 FileRemover Cleanup(NonExistantFile); | |
1483 | |
1484 int FD; | |
1485 ASSERT_NO_ERROR(fs::openFileForRead(NonExistantFile, FD)); | |
1486 FileDescriptorCloser Closer(FD); | |
1487 | |
1488 verifyWrite(FD, "Buzz", false); | |
1489 verifyRead(FD, "Fizz", true); | |
1490 } | |
1491 | |
1492 TEST_F(FileSystemTest, WriteOnlyFileCantRead) { | |
1493 createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz"); | |
1494 FileRemover Cleanup(NonExistantFile); | |
1495 | |
1496 int FD; | |
1497 ASSERT_NO_ERROR( | |
1498 fs::openFileForWrite(NonExistantFile, FD, fs::CD_OpenExisting)); | |
1499 FileDescriptorCloser Closer(FD); | |
1500 verifyRead(FD, "Fizz", false); | |
1501 verifyWrite(FD, "Buzz", true); | |
1502 } | |
1503 | |
1504 TEST_F(FileSystemTest, ReadWriteFileCanReadOrWrite) { | |
1505 createFileWithData(NonExistantFile, false, fs::CD_CreateNew, "Fizz"); | |
1506 FileRemover Cleanup(NonExistantFile); | |
1507 | |
1508 int FD; | |
1509 ASSERT_NO_ERROR(fs::openFileForReadWrite(NonExistantFile, FD, | |
1510 fs::CD_OpenExisting, fs::OF_None)); | |
1511 FileDescriptorCloser Closer(FD); | |
1512 verifyRead(FD, "Fizz", true); | |
1513 verifyWrite(FD, "Buzz", true); | |
1514 } | |
1515 | |
1516 TEST_F(FileSystemTest, is_local) { | |
1517 bool TestDirectoryIsLocal; | |
1518 ASSERT_NO_ERROR(fs::is_local(TestDirectory, TestDirectoryIsLocal)); | |
1519 EXPECT_EQ(TestDirectoryIsLocal, fs::is_local(TestDirectory)); | |
1520 | |
1521 int FD; | |
1522 SmallString<128> TempPath; | |
1523 ASSERT_NO_ERROR( | |
1524 fs::createUniqueFile(Twine(TestDirectory) + "/temp", FD, TempPath)); | |
1525 FileRemover Cleanup(TempPath); | |
1526 | |
1527 // Make sure it exists. | |
1528 ASSERT_TRUE(sys::fs::exists(Twine(TempPath))); | |
1529 | |
1530 bool TempFileIsLocal; | |
1531 ASSERT_NO_ERROR(fs::is_local(FD, TempFileIsLocal)); | |
1532 EXPECT_EQ(TempFileIsLocal, fs::is_local(FD)); | |
1533 ::close(FD); | |
1534 | |
1535 // Expect that the file and its parent directory are equally local or equally | |
1536 // remote. | |
1537 EXPECT_EQ(TestDirectoryIsLocal, TempFileIsLocal); | |
1538 } | |
1539 | |
1540 TEST_F(FileSystemTest, getUmask) { | |
1541 #ifdef _WIN32 | |
1542 EXPECT_EQ(fs::getUmask(), 0U) << "Should always be 0 on Windows."; | |
1543 #else | |
1544 unsigned OldMask = ::umask(0022); | |
1545 unsigned CurrentMask = fs::getUmask(); | |
1546 EXPECT_EQ(CurrentMask, 0022U) | |
1547 << "getUmask() didn't return previously set umask()"; | |
1548 EXPECT_EQ(::umask(OldMask), 0022U) << "getUmask() may have changed umask()"; | |
1549 #endif | |
1550 } | |
1551 | |
1552 TEST_F(FileSystemTest, RespectUmask) { | |
1553 #ifndef _WIN32 | |
1554 unsigned OldMask = ::umask(0022); | |
1555 | |
1556 int FD; | |
1557 SmallString<128> TempPath; | |
1558 ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath)); | |
1559 | |
1560 fs::perms AllRWE = static_cast<fs::perms>(0777); | |
1561 | |
1562 ASSERT_NO_ERROR(fs::setPermissions(TempPath, AllRWE)); | |
1563 | |
1564 ErrorOr<fs::perms> Perms = fs::getPermissions(TempPath); | |
1565 ASSERT_TRUE(!!Perms); | |
1566 EXPECT_EQ(Perms.get(), AllRWE) << "Should have ignored umask by default"; | |
1567 | |
1568 ASSERT_NO_ERROR(fs::setPermissions(TempPath, AllRWE)); | |
1569 | |
1570 Perms = fs::getPermissions(TempPath); | |
1571 ASSERT_TRUE(!!Perms); | |
1572 EXPECT_EQ(Perms.get(), AllRWE) << "Should have ignored umask"; | |
1573 | |
1574 ASSERT_NO_ERROR( | |
1575 fs::setPermissions(FD, static_cast<fs::perms>(AllRWE & ~fs::getUmask()))); | |
1576 Perms = fs::getPermissions(TempPath); | |
1577 ASSERT_TRUE(!!Perms); | |
1578 EXPECT_EQ(Perms.get(), static_cast<fs::perms>(0755)) | |
1579 << "Did not respect umask"; | |
1580 | |
1581 (void)::umask(0057); | |
1582 | |
1583 ASSERT_NO_ERROR( | |
1584 fs::setPermissions(FD, static_cast<fs::perms>(AllRWE & ~fs::getUmask()))); | |
1585 Perms = fs::getPermissions(TempPath); | |
1586 ASSERT_TRUE(!!Perms); | |
1587 EXPECT_EQ(Perms.get(), static_cast<fs::perms>(0720)) | |
1588 << "Did not respect umask"; | |
1589 | |
1590 (void)::umask(OldMask); | |
1591 (void)::close(FD); | |
1592 #endif | |
1231 } | 1593 } |
1232 | 1594 |
1233 TEST_F(FileSystemTest, set_current_path) { | 1595 TEST_F(FileSystemTest, set_current_path) { |
1234 SmallString<128> path; | 1596 SmallString<128> path; |
1235 | 1597 |
1271 EXPECT_TRUE(CheckPermissions(fs::all_all)); | 1633 EXPECT_TRUE(CheckPermissions(fs::all_all)); |
1272 | 1634 |
1273 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read | fs::all_exe), NoError); | 1635 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_read | fs::all_exe), NoError); |
1274 EXPECT_TRUE(CheckPermissions(fs::all_read | fs::all_exe)); | 1636 EXPECT_TRUE(CheckPermissions(fs::all_read | fs::all_exe)); |
1275 | 1637 |
1276 #if defined(LLVM_ON_WIN32) | 1638 #if defined(_WIN32) |
1277 fs::perms ReadOnly = fs::all_read | fs::all_exe; | 1639 fs::perms ReadOnly = fs::all_read | fs::all_exe; |
1278 EXPECT_EQ(fs::setPermissions(TempPath, fs::no_perms), NoError); | 1640 EXPECT_EQ(fs::setPermissions(TempPath, fs::no_perms), NoError); |
1279 EXPECT_TRUE(CheckPermissions(ReadOnly)); | 1641 EXPECT_TRUE(CheckPermissions(ReadOnly)); |
1280 | 1642 |
1281 EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_read), NoError); | 1643 EXPECT_EQ(fs::setPermissions(TempPath, fs::owner_read), NoError); |
1400 | 1762 |
1401 EXPECT_EQ(fs::setPermissions(TempPath, fs::set_gid_on_exe), NoError); | 1763 EXPECT_EQ(fs::setPermissions(TempPath, fs::set_gid_on_exe), NoError); |
1402 EXPECT_TRUE(CheckPermissions(fs::set_gid_on_exe)); | 1764 EXPECT_TRUE(CheckPermissions(fs::set_gid_on_exe)); |
1403 | 1765 |
1404 // Modern BSDs require root to set the sticky bit on files. | 1766 // Modern BSDs require root to set the sticky bit on files. |
1405 #if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) | 1767 // AIX and Solaris without root will mask off (i.e., lose) the sticky bit |
1768 // on files. | |
1769 #if !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && \ | |
1770 !defined(_AIX) && !(defined(__sun__) && defined(__svr4__)) | |
1406 EXPECT_EQ(fs::setPermissions(TempPath, fs::sticky_bit), NoError); | 1771 EXPECT_EQ(fs::setPermissions(TempPath, fs::sticky_bit), NoError); |
1407 EXPECT_TRUE(CheckPermissions(fs::sticky_bit)); | 1772 EXPECT_TRUE(CheckPermissions(fs::sticky_bit)); |
1408 | 1773 |
1409 EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe | | 1774 EXPECT_EQ(fs::setPermissions(TempPath, fs::set_uid_on_exe | |
1410 fs::set_gid_on_exe | | 1775 fs::set_gid_on_exe | |
1420 EXPECT_TRUE(CheckPermissions(fs::all_read | fs::set_uid_on_exe | | 1785 EXPECT_TRUE(CheckPermissions(fs::all_read | fs::set_uid_on_exe | |
1421 fs::set_gid_on_exe | fs::sticky_bit)); | 1786 fs::set_gid_on_exe | fs::sticky_bit)); |
1422 | 1787 |
1423 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_perms), NoError); | 1788 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_perms), NoError); |
1424 EXPECT_TRUE(CheckPermissions(fs::all_perms)); | 1789 EXPECT_TRUE(CheckPermissions(fs::all_perms)); |
1425 #endif // !FreeBSD && !NetBSD && !OpenBSD | 1790 #endif // !FreeBSD && !NetBSD && !OpenBSD && !AIX |
1426 | 1791 |
1427 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_perms & ~fs::sticky_bit), | 1792 EXPECT_EQ(fs::setPermissions(TempPath, fs::all_perms & ~fs::sticky_bit), |
1428 NoError); | 1793 NoError); |
1429 EXPECT_TRUE(CheckPermissions(fs::all_perms & ~fs::sticky_bit)); | 1794 EXPECT_TRUE(CheckPermissions(fs::all_perms & ~fs::sticky_bit)); |
1430 #endif | 1795 #endif |