1 //===- llvm/unittest/Support/Path.cpp - Path tests ------------------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 10 #include "llvm/Support/Path.h" 11 #include "llvm/Support/Errc.h" 12 #include "llvm/Support/ErrorHandling.h" 13 #include "llvm/Support/FileSystem.h" 14 #include "llvm/Support/MemoryBuffer.h" 15 #include "llvm/Support/raw_ostream.h" 16 #include "gtest/gtest.h" 17 18 #ifdef LLVM_ON_WIN32 19 #include <windows.h> 20 #include <winerror.h> 21 #endif 22 23 #ifdef LLVM_ON_UNIX 24 #include <sys/stat.h> 25 #endif 26 27 using namespace llvm; 28 using namespace llvm::sys; 29 30 #define ASSERT_NO_ERROR(x) \ 31 if (std::error_code ASSERT_NO_ERROR_ec = x) { \ 32 SmallString<128> MessageStorage; \ 33 raw_svector_ostream Message(MessageStorage); \ 34 Message << #x ": did not return errc::success.\n" \ 35 << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \ 36 << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \ 37 GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \ 38 } else { \ 39 } 40 41 namespace { 42 43 TEST(is_separator, Works) { 44 EXPECT_TRUE(path::is_separator('/')); 45 EXPECT_FALSE(path::is_separator('\0')); 46 EXPECT_FALSE(path::is_separator('-')); 47 EXPECT_FALSE(path::is_separator(' ')); 48 49 #ifdef LLVM_ON_WIN32 50 EXPECT_TRUE(path::is_separator('\\')); 51 #else 52 EXPECT_FALSE(path::is_separator('\\')); 53 #endif 54 } 55 56 TEST(Support, Path) { 57 SmallVector<StringRef, 40> paths; 58 paths.push_back(""); 59 paths.push_back("."); 60 paths.push_back(".."); 61 paths.push_back("foo"); 62 paths.push_back("/"); 63 paths.push_back("/foo"); 64 paths.push_back("foo/"); 65 paths.push_back("/foo/"); 66 paths.push_back("foo/bar"); 67 paths.push_back("/foo/bar"); 68 paths.push_back("//net"); 69 paths.push_back("//net/foo"); 70 paths.push_back("///foo///"); 71 paths.push_back("///foo///bar"); 72 paths.push_back("/."); 73 paths.push_back("./"); 74 paths.push_back("/.."); 75 paths.push_back("../"); 76 paths.push_back("foo/."); 77 paths.push_back("foo/.."); 78 paths.push_back("foo/./"); 79 paths.push_back("foo/./bar"); 80 paths.push_back("foo/.."); 81 paths.push_back("foo/../"); 82 paths.push_back("foo/../bar"); 83 paths.push_back("c:"); 84 paths.push_back("c:/"); 85 paths.push_back("c:foo"); 86 paths.push_back("c:/foo"); 87 paths.push_back("c:foo/"); 88 paths.push_back("c:/foo/"); 89 paths.push_back("c:/foo/bar"); 90 paths.push_back("prn:"); 91 paths.push_back("c:\\"); 92 paths.push_back("c:foo"); 93 paths.push_back("c:\\foo"); 94 paths.push_back("c:foo\\"); 95 paths.push_back("c:\\foo\\"); 96 paths.push_back("c:\\foo/"); 97 paths.push_back("c:/foo\\bar"); 98 99 SmallVector<StringRef, 5> ComponentStack; 100 for (SmallVector<StringRef, 40>::const_iterator i = paths.begin(), 101 e = paths.end(); 102 i != e; 103 ++i) { 104 for (sys::path::const_iterator ci = sys::path::begin(*i), 105 ce = sys::path::end(*i); 106 ci != ce; 107 ++ci) { 108 ASSERT_FALSE(ci->empty()); 109 ComponentStack.push_back(*ci); 110 } 111 112 for (sys::path::reverse_iterator ci = sys::path::rbegin(*i), 113 ce = sys::path::rend(*i); 114 ci != ce; 115 ++ci) { 116 ASSERT_TRUE(*ci == ComponentStack.back()); 117 ComponentStack.pop_back(); 118 } 119 ASSERT_TRUE(ComponentStack.empty()); 120 121 path::has_root_path(*i); 122 path::root_path(*i); 123 path::has_root_name(*i); 124 path::root_name(*i); 125 path::has_root_directory(*i); 126 path::root_directory(*i); 127 path::has_parent_path(*i); 128 path::parent_path(*i); 129 path::has_filename(*i); 130 path::filename(*i); 131 path::has_stem(*i); 132 path::stem(*i); 133 path::has_extension(*i); 134 path::extension(*i); 135 path::is_absolute(*i); 136 path::is_relative(*i); 137 138 SmallString<128> temp_store; 139 temp_store = *i; 140 ASSERT_NO_ERROR(fs::make_absolute(temp_store)); 141 temp_store = *i; 142 path::remove_filename(temp_store); 143 144 temp_store = *i; 145 path::replace_extension(temp_store, "ext"); 146 StringRef filename(temp_store.begin(), temp_store.size()), stem, ext; 147 stem = path::stem(filename); 148 ext = path::extension(filename); 149 EXPECT_EQ(*sys::path::rbegin(filename), (stem + ext).str()); 150 151 path::native(*i, temp_store); 152 } 153 } 154 155 TEST(Support, RelativePathIterator) { 156 SmallString<64> Path(StringRef("c/d/e/foo.txt")); 157 typedef SmallVector<StringRef, 4> PathComponents; 158 PathComponents ExpectedPathComponents; 159 PathComponents ActualPathComponents; 160 161 StringRef(Path).split(ExpectedPathComponents, '/'); 162 163 for (path::const_iterator I = path::begin(Path), E = path::end(Path); I != E; 164 ++I) { 165 ActualPathComponents.push_back(*I); 166 } 167 168 ASSERT_EQ(ExpectedPathComponents.size(), ActualPathComponents.size()); 169 170 for (size_t i = 0; i <ExpectedPathComponents.size(); ++i) { 171 EXPECT_EQ(ExpectedPathComponents[i].str(), ActualPathComponents[i].str()); 172 } 173 } 174 175 TEST(Support, RelativePathDotIterator) { 176 SmallString<64> Path(StringRef(".c/.d/../.")); 177 typedef SmallVector<StringRef, 4> PathComponents; 178 PathComponents ExpectedPathComponents; 179 PathComponents ActualPathComponents; 180 181 StringRef(Path).split(ExpectedPathComponents, '/'); 182 183 for (path::const_iterator I = path::begin(Path), E = path::end(Path); I != E; 184 ++I) { 185 ActualPathComponents.push_back(*I); 186 } 187 188 ASSERT_EQ(ExpectedPathComponents.size(), ActualPathComponents.size()); 189 190 for (size_t i = 0; i <ExpectedPathComponents.size(); ++i) { 191 EXPECT_EQ(ExpectedPathComponents[i].str(), ActualPathComponents[i].str()); 192 } 193 } 194 195 TEST(Support, AbsolutePathIterator) { 196 SmallString<64> Path(StringRef("/c/d/e/foo.txt")); 197 typedef SmallVector<StringRef, 4> PathComponents; 198 PathComponents ExpectedPathComponents; 199 PathComponents ActualPathComponents; 200 201 StringRef(Path).split(ExpectedPathComponents, '/'); 202 203 // The root path will also be a component when iterating 204 ExpectedPathComponents[0] = "/"; 205 206 for (path::const_iterator I = path::begin(Path), E = path::end(Path); I != E; 207 ++I) { 208 ActualPathComponents.push_back(*I); 209 } 210 211 ASSERT_EQ(ExpectedPathComponents.size(), ActualPathComponents.size()); 212 213 for (size_t i = 0; i <ExpectedPathComponents.size(); ++i) { 214 EXPECT_EQ(ExpectedPathComponents[i].str(), ActualPathComponents[i].str()); 215 } 216 } 217 218 TEST(Support, AbsolutePathDotIterator) { 219 SmallString<64> Path(StringRef("/.c/.d/../.")); 220 typedef SmallVector<StringRef, 4> PathComponents; 221 PathComponents ExpectedPathComponents; 222 PathComponents ActualPathComponents; 223 224 StringRef(Path).split(ExpectedPathComponents, '/'); 225 226 // The root path will also be a component when iterating 227 ExpectedPathComponents[0] = "/"; 228 229 for (path::const_iterator I = path::begin(Path), E = path::end(Path); I != E; 230 ++I) { 231 ActualPathComponents.push_back(*I); 232 } 233 234 ASSERT_EQ(ExpectedPathComponents.size(), ActualPathComponents.size()); 235 236 for (size_t i = 0; i <ExpectedPathComponents.size(); ++i) { 237 EXPECT_EQ(ExpectedPathComponents[i].str(), ActualPathComponents[i].str()); 238 } 239 } 240 241 #ifdef LLVM_ON_WIN32 242 TEST(Support, AbsolutePathIteratorWin32) { 243 SmallString<64> Path(StringRef("c:\\c\\e\\foo.txt")); 244 typedef SmallVector<StringRef, 4> PathComponents; 245 PathComponents ExpectedPathComponents; 246 PathComponents ActualPathComponents; 247 248 StringRef(Path).split(ExpectedPathComponents, "\\"); 249 250 // The root path (which comes after the drive name) will also be a component 251 // when iterating. 252 ExpectedPathComponents.insert(ExpectedPathComponents.begin()+1, "\\"); 253 254 for (path::const_iterator I = path::begin(Path), E = path::end(Path); I != E; 255 ++I) { 256 ActualPathComponents.push_back(*I); 257 } 258 259 ASSERT_EQ(ExpectedPathComponents.size(), ActualPathComponents.size()); 260 261 for (size_t i = 0; i <ExpectedPathComponents.size(); ++i) { 262 EXPECT_EQ(ExpectedPathComponents[i].str(), ActualPathComponents[i].str()); 263 } 264 } 265 #endif // LLVM_ON_WIN32 266 267 TEST(Support, AbsolutePathIteratorEnd) { 268 // Trailing slashes are converted to '.' unless they are part of the root path. 269 SmallVector<StringRef, 4> Paths; 270 Paths.push_back("/foo/"); 271 Paths.push_back("/foo//"); 272 Paths.push_back("//net//"); 273 #ifdef LLVM_ON_WIN32 274 Paths.push_back("c:\\\\"); 275 #endif 276 277 for (StringRef Path : Paths) { 278 StringRef LastComponent = *path::rbegin(Path); 279 EXPECT_EQ(".", LastComponent); 280 } 281 282 SmallVector<StringRef, 3> RootPaths; 283 RootPaths.push_back("/"); 284 RootPaths.push_back("//net/"); 285 #ifdef LLVM_ON_WIN32 286 RootPaths.push_back("c:\\"); 287 #endif 288 289 for (StringRef Path : RootPaths) { 290 StringRef LastComponent = *path::rbegin(Path); 291 EXPECT_EQ(1u, LastComponent.size()); 292 EXPECT_TRUE(path::is_separator(LastComponent[0])); 293 } 294 } 295 296 TEST(Support, HomeDirectory) { 297 #ifdef LLVM_ON_UNIX 298 // This test only makes sense on Unix if $HOME is set. 299 if (::getenv("HOME")) { 300 #endif 301 SmallString<128> HomeDir; 302 EXPECT_TRUE(path::home_directory(HomeDir)); 303 EXPECT_FALSE(HomeDir.empty()); 304 #ifdef LLVM_ON_UNIX 305 } 306 #endif 307 } 308 309 class FileSystemTest : public testing::Test { 310 protected: 311 /// Unique temporary directory in which all created filesystem entities must 312 /// be placed. It is removed at the end of each test (must be empty). 313 SmallString<128> TestDirectory; 314 315 void SetUp() override { 316 ASSERT_NO_ERROR( 317 fs::createUniqueDirectory("file-system-test", TestDirectory)); 318 // We don't care about this specific file. 319 errs() << "Test Directory: " << TestDirectory << '\n'; 320 errs().flush(); 321 } 322 323 void TearDown() override { ASSERT_NO_ERROR(fs::remove(TestDirectory.str())); } 324 }; 325 326 TEST_F(FileSystemTest, Unique) { 327 // Create a temp file. 328 int FileDescriptor; 329 SmallString<64> TempPath; 330 ASSERT_NO_ERROR( 331 fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath)); 332 333 // The same file should return an identical unique id. 334 fs::UniqueID F1, F2; 335 ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), F1)); 336 ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath), F2)); 337 ASSERT_EQ(F1, F2); 338 339 // Different files should return different unique ids. 340 int FileDescriptor2; 341 SmallString<64> TempPath2; 342 ASSERT_NO_ERROR( 343 fs::createTemporaryFile("prefix", "temp", FileDescriptor2, TempPath2)); 344 345 fs::UniqueID D; 346 ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath2), D)); 347 ASSERT_NE(D, F1); 348 ::close(FileDescriptor2); 349 350 ASSERT_NO_ERROR(fs::remove(Twine(TempPath2))); 351 352 // Two paths representing the same file on disk should still provide the 353 // same unique id. We can test this by making a hard link. 354 ASSERT_NO_ERROR(fs::create_link(Twine(TempPath), Twine(TempPath2))); 355 fs::UniqueID D2; 356 ASSERT_NO_ERROR(fs::getUniqueID(Twine(TempPath2), D2)); 357 ASSERT_EQ(D2, F1); 358 359 ::close(FileDescriptor); 360 361 SmallString<128> Dir1; 362 ASSERT_NO_ERROR( 363 fs::createUniqueDirectory("dir1", Dir1)); 364 ASSERT_NO_ERROR(fs::getUniqueID(Dir1.c_str(), F1)); 365 ASSERT_NO_ERROR(fs::getUniqueID(Dir1.c_str(), F2)); 366 ASSERT_EQ(F1, F2); 367 368 SmallString<128> Dir2; 369 ASSERT_NO_ERROR( 370 fs::createUniqueDirectory("dir2", Dir2)); 371 ASSERT_NO_ERROR(fs::getUniqueID(Dir2.c_str(), F2)); 372 ASSERT_NE(F1, F2); 373 } 374 375 TEST_F(FileSystemTest, TempFiles) { 376 // Create a temp file. 377 int FileDescriptor; 378 SmallString<64> TempPath; 379 ASSERT_NO_ERROR( 380 fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath)); 381 382 // Make sure it exists. 383 ASSERT_TRUE(sys::fs::exists(Twine(TempPath))); 384 385 // Create another temp tile. 386 int FD2; 387 SmallString<64> TempPath2; 388 ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD2, TempPath2)); 389 ASSERT_TRUE(TempPath2.endswith(".temp")); 390 ASSERT_NE(TempPath.str(), TempPath2.str()); 391 392 fs::file_status A, B; 393 ASSERT_NO_ERROR(fs::status(Twine(TempPath), A)); 394 ASSERT_NO_ERROR(fs::status(Twine(TempPath2), B)); 395 EXPECT_FALSE(fs::equivalent(A, B)); 396 397 ::close(FD2); 398 399 // Remove Temp2. 400 ASSERT_NO_ERROR(fs::remove(Twine(TempPath2))); 401 ASSERT_NO_ERROR(fs::remove(Twine(TempPath2))); 402 ASSERT_EQ(fs::remove(Twine(TempPath2), false), 403 errc::no_such_file_or_directory); 404 405 std::error_code EC = fs::status(TempPath2.c_str(), B); 406 EXPECT_EQ(EC, errc::no_such_file_or_directory); 407 EXPECT_EQ(B.type(), fs::file_type::file_not_found); 408 409 // Make sure Temp2 doesn't exist. 410 ASSERT_EQ(fs::access(Twine(TempPath2), sys::fs::AccessMode::Exist), 411 errc::no_such_file_or_directory); 412 413 SmallString<64> TempPath3; 414 ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "", TempPath3)); 415 ASSERT_FALSE(TempPath3.endswith(".")); 416 417 // Create a hard link to Temp1. 418 ASSERT_NO_ERROR(fs::create_link(Twine(TempPath), Twine(TempPath2))); 419 bool equal; 420 ASSERT_NO_ERROR(fs::equivalent(Twine(TempPath), Twine(TempPath2), equal)); 421 EXPECT_TRUE(equal); 422 ASSERT_NO_ERROR(fs::status(Twine(TempPath), A)); 423 ASSERT_NO_ERROR(fs::status(Twine(TempPath2), B)); 424 EXPECT_TRUE(fs::equivalent(A, B)); 425 426 // Remove Temp1. 427 ::close(FileDescriptor); 428 ASSERT_NO_ERROR(fs::remove(Twine(TempPath))); 429 430 // Remove the hard link. 431 ASSERT_NO_ERROR(fs::remove(Twine(TempPath2))); 432 433 // Make sure Temp1 doesn't exist. 434 ASSERT_EQ(fs::access(Twine(TempPath), sys::fs::AccessMode::Exist), 435 errc::no_such_file_or_directory); 436 437 #ifdef LLVM_ON_WIN32 438 // Path name > 260 chars should get an error. 439 const char *Path270 = 440 "abcdefghijklmnopqrstuvwxyz9abcdefghijklmnopqrstuvwxyz8" 441 "abcdefghijklmnopqrstuvwxyz7abcdefghijklmnopqrstuvwxyz6" 442 "abcdefghijklmnopqrstuvwxyz5abcdefghijklmnopqrstuvwxyz4" 443 "abcdefghijklmnopqrstuvwxyz3abcdefghijklmnopqrstuvwxyz2" 444 "abcdefghijklmnopqrstuvwxyz1abcdefghijklmnopqrstuvwxyz0"; 445 EXPECT_EQ(fs::createUniqueFile(Path270, FileDescriptor, TempPath), 446 errc::invalid_argument); 447 // Relative path < 247 chars, no problem. 448 const char *Path216 = 449 "abcdefghijklmnopqrstuvwxyz7abcdefghijklmnopqrstuvwxyz6" 450 "abcdefghijklmnopqrstuvwxyz5abcdefghijklmnopqrstuvwxyz4" 451 "abcdefghijklmnopqrstuvwxyz3abcdefghijklmnopqrstuvwxyz2" 452 "abcdefghijklmnopqrstuvwxyz1abcdefghijklmnopqrstuvwxyz0"; 453 ASSERT_NO_ERROR(fs::createTemporaryFile(Path216, "", TempPath)); 454 ASSERT_NO_ERROR(fs::remove(Twine(TempPath))); 455 #endif 456 } 457 458 TEST_F(FileSystemTest, CreateDir) { 459 ASSERT_NO_ERROR(fs::create_directory(Twine(TestDirectory) + "foo")); 460 ASSERT_NO_ERROR(fs::create_directory(Twine(TestDirectory) + "foo")); 461 ASSERT_EQ(fs::create_directory(Twine(TestDirectory) + "foo", false), 462 errc::file_exists); 463 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "foo")); 464 465 #ifdef LLVM_ON_UNIX 466 // Set a 0000 umask so that we can test our directory permissions. 467 mode_t OldUmask = ::umask(0000); 468 469 fs::file_status Status; 470 ASSERT_NO_ERROR( 471 fs::create_directory(Twine(TestDirectory) + "baz500", false, 472 fs::perms::owner_read | fs::perms::owner_exe)); 473 ASSERT_NO_ERROR(fs::status(Twine(TestDirectory) + "baz500", Status)); 474 ASSERT_EQ(Status.permissions() & fs::perms::all_all, 475 fs::perms::owner_read | fs::perms::owner_exe); 476 ASSERT_NO_ERROR(fs::create_directory(Twine(TestDirectory) + "baz777", false, 477 fs::perms::all_all)); 478 ASSERT_NO_ERROR(fs::status(Twine(TestDirectory) + "baz777", Status)); 479 ASSERT_EQ(Status.permissions() & fs::perms::all_all, fs::perms::all_all); 480 481 // Restore umask to be safe. 482 ::umask(OldUmask); 483 #endif 484 485 #ifdef LLVM_ON_WIN32 486 // Prove that create_directories() can handle a pathname > 248 characters, 487 // which is the documented limit for CreateDirectory(). 488 // (248 is MAX_PATH subtracting room for an 8.3 filename.) 489 // Generate a directory path guaranteed to fall into that range. 490 size_t TmpLen = TestDirectory.size(); 491 const char *OneDir = "\\123456789"; 492 size_t OneDirLen = strlen(OneDir); 493 ASSERT_LT(OneDirLen, 12U); 494 size_t NLevels = ((248 - TmpLen) / OneDirLen) + 1; 495 SmallString<260> LongDir(TestDirectory); 496 for (size_t I = 0; I < NLevels; ++I) 497 LongDir.append(OneDir); 498 ASSERT_NO_ERROR(fs::create_directories(Twine(LongDir))); 499 ASSERT_NO_ERROR(fs::create_directories(Twine(LongDir))); 500 ASSERT_EQ(fs::create_directories(Twine(LongDir), false), 501 errc::file_exists); 502 // Tidy up, "recursively" removing the directories. 503 StringRef ThisDir(LongDir); 504 for (size_t J = 0; J < NLevels; ++J) { 505 ASSERT_NO_ERROR(fs::remove(ThisDir)); 506 ThisDir = path::parent_path(ThisDir); 507 } 508 509 // Similarly for a relative pathname. Need to set the current directory to 510 // TestDirectory so that the one we create ends up in the right place. 511 char PreviousDir[260]; 512 size_t PreviousDirLen = ::GetCurrentDirectoryA(260, PreviousDir); 513 ASSERT_GT(PreviousDirLen, 0U); 514 ASSERT_LT(PreviousDirLen, 260U); 515 ASSERT_NE(::SetCurrentDirectoryA(TestDirectory.c_str()), 0); 516 LongDir.clear(); 517 // Generate a relative directory name with absolute length > 248. 518 size_t LongDirLen = 249 - TestDirectory.size(); 519 LongDir.assign(LongDirLen, 'a'); 520 ASSERT_NO_ERROR(fs::create_directory(Twine(LongDir))); 521 // While we're here, prove that .. and . handling works in these long paths. 522 const char *DotDotDirs = "\\..\\.\\b"; 523 LongDir.append(DotDotDirs); 524 ASSERT_NO_ERROR(fs::create_directory("b")); 525 ASSERT_EQ(fs::create_directory(Twine(LongDir), false), errc::file_exists); 526 // And clean up. 527 ASSERT_NO_ERROR(fs::remove("b")); 528 ASSERT_NO_ERROR(fs::remove( 529 Twine(LongDir.substr(0, LongDir.size() - strlen(DotDotDirs))))); 530 ASSERT_NE(::SetCurrentDirectoryA(PreviousDir), 0); 531 #endif 532 } 533 534 TEST_F(FileSystemTest, DirectoryIteration) { 535 std::error_code ec; 536 for (fs::directory_iterator i(".", ec), e; i != e; i.increment(ec)) 537 ASSERT_NO_ERROR(ec); 538 539 // Create a known hierarchy to recurse over. 540 ASSERT_NO_ERROR( 541 fs::create_directories(Twine(TestDirectory) + "/recursive/a0/aa1")); 542 ASSERT_NO_ERROR( 543 fs::create_directories(Twine(TestDirectory) + "/recursive/a0/ab1")); 544 ASSERT_NO_ERROR(fs::create_directories(Twine(TestDirectory) + 545 "/recursive/dontlookhere/da1")); 546 ASSERT_NO_ERROR( 547 fs::create_directories(Twine(TestDirectory) + "/recursive/z0/za1")); 548 ASSERT_NO_ERROR( 549 fs::create_directories(Twine(TestDirectory) + "/recursive/pop/p1")); 550 typedef std::vector<std::string> v_t; 551 v_t visited; 552 for (fs::recursive_directory_iterator i(Twine(TestDirectory) 553 + "/recursive", ec), e; i != e; i.increment(ec)){ 554 ASSERT_NO_ERROR(ec); 555 if (path::filename(i->path()) == "p1") { 556 i.pop(); 557 // FIXME: recursive_directory_iterator should be more robust. 558 if (i == e) break; 559 } 560 if (path::filename(i->path()) == "dontlookhere") 561 i.no_push(); 562 visited.push_back(path::filename(i->path())); 563 } 564 v_t::const_iterator a0 = std::find(visited.begin(), visited.end(), "a0"); 565 v_t::const_iterator aa1 = std::find(visited.begin(), visited.end(), "aa1"); 566 v_t::const_iterator ab1 = std::find(visited.begin(), visited.end(), "ab1"); 567 v_t::const_iterator dontlookhere = std::find(visited.begin(), visited.end(), 568 "dontlookhere"); 569 v_t::const_iterator da1 = std::find(visited.begin(), visited.end(), "da1"); 570 v_t::const_iterator z0 = std::find(visited.begin(), visited.end(), "z0"); 571 v_t::const_iterator za1 = std::find(visited.begin(), visited.end(), "za1"); 572 v_t::const_iterator pop = std::find(visited.begin(), visited.end(), "pop"); 573 v_t::const_iterator p1 = std::find(visited.begin(), visited.end(), "p1"); 574 575 // Make sure that each path was visited correctly. 576 ASSERT_NE(a0, visited.end()); 577 ASSERT_NE(aa1, visited.end()); 578 ASSERT_NE(ab1, visited.end()); 579 ASSERT_NE(dontlookhere, visited.end()); 580 ASSERT_EQ(da1, visited.end()); // Not visited. 581 ASSERT_NE(z0, visited.end()); 582 ASSERT_NE(za1, visited.end()); 583 ASSERT_NE(pop, visited.end()); 584 ASSERT_EQ(p1, visited.end()); // Not visited. 585 586 // Make sure that parents were visited before children. No other ordering 587 // guarantees can be made across siblings. 588 ASSERT_LT(a0, aa1); 589 ASSERT_LT(a0, ab1); 590 ASSERT_LT(z0, za1); 591 592 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/a0/aa1")); 593 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/a0/ab1")); 594 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/a0")); 595 ASSERT_NO_ERROR( 596 fs::remove(Twine(TestDirectory) + "/recursive/dontlookhere/da1")); 597 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/dontlookhere")); 598 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/pop/p1")); 599 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/pop")); 600 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/z0/za1")); 601 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive/z0")); 602 ASSERT_NO_ERROR(fs::remove(Twine(TestDirectory) + "/recursive")); 603 } 604 605 const char archive[] = "!<arch>\x0A"; 606 const char bitcode[] = "\xde\xc0\x17\x0b"; 607 const char coff_object[] = "\x00\x00......"; 608 const char coff_bigobj[] = "\x00\x00\xff\xff\x00\x02......" 609 "\xc7\xa1\xba\xd1\xee\xba\xa9\x4b\xaf\x20\xfa\xf6\x6a\xa4\xdc\xb8"; 610 const char coff_import_library[] = "\x00\x00\xff\xff...."; 611 const char elf_relocatable[] = { 0x7f, 'E', 'L', 'F', 1, 2, 1, 0, 0, 612 0, 0, 0, 0, 0, 0, 0, 0, 1 }; 613 const char macho_universal_binary[] = "\xca\xfe\xba\xbe...\0x00"; 614 const char macho_object[] = "\xfe\xed\xfa\xce..........\x00\x01"; 615 const char macho_executable[] = "\xfe\xed\xfa\xce..........\x00\x02"; 616 const char macho_fixed_virtual_memory_shared_lib[] = 617 "\xfe\xed\xfa\xce..........\x00\x03"; 618 const char macho_core[] = "\xfe\xed\xfa\xce..........\x00\x04"; 619 const char macho_preload_executable[] = "\xfe\xed\xfa\xce..........\x00\x05"; 620 const char macho_dynamically_linked_shared_lib[] = 621 "\xfe\xed\xfa\xce..........\x00\x06"; 622 const char macho_dynamic_linker[] = "\xfe\xed\xfa\xce..........\x00\x07"; 623 const char macho_bundle[] = "\xfe\xed\xfa\xce..........\x00\x08"; 624 const char macho_dsym_companion[] = "\xfe\xed\xfa\xce..........\x00\x0a"; 625 const char macho_kext_bundle[] = "\xfe\xed\xfa\xce..........\x00\x0b"; 626 const char windows_resource[] = "\x00\x00\x00\x00\x020\x00\x00\x00\xff"; 627 const char macho_dynamically_linked_shared_lib_stub[] = 628 "\xfe\xed\xfa\xce..........\x00\x09"; 629 630 TEST_F(FileSystemTest, Magic) { 631 struct type { 632 const char *filename; 633 const char *magic_str; 634 size_t magic_str_len; 635 fs::file_magic magic; 636 } types[] = { 637 #define DEFINE(magic) \ 638 { #magic, magic, sizeof(magic), fs::file_magic::magic } 639 DEFINE(archive), 640 DEFINE(bitcode), 641 DEFINE(coff_object), 642 { "coff_bigobj", coff_bigobj, sizeof(coff_bigobj), fs::file_magic::coff_object }, 643 DEFINE(coff_import_library), 644 DEFINE(elf_relocatable), 645 DEFINE(macho_universal_binary), 646 DEFINE(macho_object), 647 DEFINE(macho_executable), 648 DEFINE(macho_fixed_virtual_memory_shared_lib), 649 DEFINE(macho_core), 650 DEFINE(macho_preload_executable), 651 DEFINE(macho_dynamically_linked_shared_lib), 652 DEFINE(macho_dynamic_linker), 653 DEFINE(macho_bundle), 654 DEFINE(macho_dynamically_linked_shared_lib_stub), 655 DEFINE(macho_dsym_companion), 656 DEFINE(macho_kext_bundle), 657 DEFINE(windows_resource) 658 #undef DEFINE 659 }; 660 661 // Create some files filled with magic. 662 for (type *i = types, *e = types + (sizeof(types) / sizeof(type)); i != e; 663 ++i) { 664 SmallString<128> file_pathname(TestDirectory); 665 path::append(file_pathname, i->filename); 666 std::error_code EC; 667 raw_fd_ostream file(file_pathname, EC, sys::fs::F_None); 668 ASSERT_FALSE(file.has_error()); 669 StringRef magic(i->magic_str, i->magic_str_len); 670 file << magic; 671 file.close(); 672 EXPECT_EQ(i->magic, fs::identify_magic(magic)); 673 ASSERT_NO_ERROR(fs::remove(Twine(file_pathname))); 674 } 675 } 676 677 #ifdef LLVM_ON_WIN32 678 TEST_F(FileSystemTest, CarriageReturn) { 679 SmallString<128> FilePathname(TestDirectory); 680 std::error_code EC; 681 path::append(FilePathname, "test"); 682 683 { 684 raw_fd_ostream File(FilePathname, EC, sys::fs::F_Text); 685 ASSERT_NO_ERROR(EC); 686 File << '\n'; 687 } 688 { 689 auto Buf = MemoryBuffer::getFile(FilePathname.str()); 690 EXPECT_TRUE((bool)Buf); 691 EXPECT_EQ(Buf.get()->getBuffer(), "\r\n"); 692 } 693 694 { 695 raw_fd_ostream File(FilePathname, EC, sys::fs::F_None); 696 ASSERT_NO_ERROR(EC); 697 File << '\n'; 698 } 699 { 700 auto Buf = MemoryBuffer::getFile(FilePathname.str()); 701 EXPECT_TRUE((bool)Buf); 702 EXPECT_EQ(Buf.get()->getBuffer(), "\n"); 703 } 704 ASSERT_NO_ERROR(fs::remove(Twine(FilePathname))); 705 } 706 #endif 707 708 TEST_F(FileSystemTest, Resize) { 709 int FD; 710 SmallString<64> TempPath; 711 ASSERT_NO_ERROR(fs::createTemporaryFile("prefix", "temp", FD, TempPath)); 712 ASSERT_NO_ERROR(fs::resize_file(FD, 123)); 713 fs::file_status Status; 714 ASSERT_NO_ERROR(fs::status(FD, Status)); 715 ASSERT_EQ(Status.getSize(), 123U); 716 } 717 718 TEST_F(FileSystemTest, FileMapping) { 719 // Create a temp file. 720 int FileDescriptor; 721 SmallString<64> TempPath; 722 ASSERT_NO_ERROR( 723 fs::createTemporaryFile("prefix", "temp", FileDescriptor, TempPath)); 724 unsigned Size = 4096; 725 ASSERT_NO_ERROR(fs::resize_file(FileDescriptor, Size)); 726 727 // Map in temp file and add some content 728 std::error_code EC; 729 StringRef Val("hello there"); 730 { 731 fs::mapped_file_region mfr(FileDescriptor, 732 fs::mapped_file_region::readwrite, Size, 0, EC); 733 ASSERT_NO_ERROR(EC); 734 std::copy(Val.begin(), Val.end(), mfr.data()); 735 // Explicitly add a 0. 736 mfr.data()[Val.size()] = 0; 737 // Unmap temp file 738 } 739 740 // Map it back in read-only 741 int FD; 742 EC = fs::openFileForRead(Twine(TempPath), FD); 743 ASSERT_NO_ERROR(EC); 744 fs::mapped_file_region mfr(FD, fs::mapped_file_region::readonly, Size, 0, EC); 745 ASSERT_NO_ERROR(EC); 746 747 // Verify content 748 EXPECT_EQ(StringRef(mfr.const_data()), Val); 749 750 // Unmap temp file 751 fs::mapped_file_region m(FD, fs::mapped_file_region::readonly, Size, 0, EC); 752 ASSERT_NO_ERROR(EC); 753 ASSERT_EQ(close(FD), 0); 754 } 755 756 TEST(Support, NormalizePath) { 757 #if defined(LLVM_ON_WIN32) 758 #define EXPECT_PATH_IS(path__, windows__, not_windows__) \ 759 EXPECT_EQ(path__, windows__); 760 #else 761 #define EXPECT_PATH_IS(path__, windows__, not_windows__) \ 762 EXPECT_EQ(path__, not_windows__); 763 #endif 764 765 SmallString<64> Path1("a"); 766 SmallString<64> Path2("a/b"); 767 SmallString<64> Path3("a\\b"); 768 SmallString<64> Path4("a\\\\b"); 769 SmallString<64> Path5("\\a"); 770 SmallString<64> Path6("a\\"); 771 772 path::native(Path1); 773 EXPECT_PATH_IS(Path1, "a", "a"); 774 775 path::native(Path2); 776 EXPECT_PATH_IS(Path2, "a\\b", "a/b"); 777 778 path::native(Path3); 779 EXPECT_PATH_IS(Path3, "a\\b", "a/b"); 780 781 path::native(Path4); 782 EXPECT_PATH_IS(Path4, "a\\\\b", "a\\\\b"); 783 784 path::native(Path5); 785 EXPECT_PATH_IS(Path5, "\\a", "/a"); 786 787 path::native(Path6); 788 EXPECT_PATH_IS(Path6, "a\\", "a/"); 789 790 #undef EXPECT_PATH_IS 791 } 792 793 TEST(Support, RemoveLeadingDotSlash) { 794 StringRef Path1("././/foolz/wat"); 795 StringRef Path2("./////"); 796 797 Path1 = path::remove_leading_dotslash(Path1); 798 EXPECT_EQ(Path1, "foolz/wat"); 799 Path2 = path::remove_leading_dotslash(Path2); 800 EXPECT_EQ(Path2, ""); 801 } 802 } // anonymous namespace 803