1 //===-- FileCollectorTest.cpp -----------------------------------*- C++ -*-===// 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 #include "gmock/gmock.h" 10 #include "gtest/gtest.h" 11 12 #include "llvm/Support/FileCollector.h" 13 #include "llvm/Support/FileSystem.h" 14 #include "llvm/Testing/Support/SupportHelpers.h" 15 16 using namespace llvm; 17 using llvm::unittest::TempDir; 18 using llvm::unittest::TempFile; 19 using llvm::unittest::TempLink; 20 21 namespace llvm { 22 namespace vfs { 23 inline bool operator==(const llvm::vfs::YAMLVFSEntry &LHS, 24 const llvm::vfs::YAMLVFSEntry &RHS) { 25 return LHS.VPath == RHS.VPath && LHS.RPath == RHS.RPath; 26 } 27 } // namespace vfs 28 } // namespace llvm 29 30 namespace { 31 class TestingFileCollector : public FileCollector { 32 public: 33 using FileCollector::FileCollector; 34 using FileCollector::Root; 35 using FileCollector::Seen; 36 using FileCollector::SymlinkMap; 37 using FileCollector::VFSWriter; 38 39 bool hasSeen(StringRef fs) { 40 return Seen.find(fs) != Seen.end(); 41 } 42 }; 43 44 } // end anonymous namespace 45 46 TEST(FileCollectorTest, addFile) { 47 TempDir root("add_file_root", /*Unique*/ true); 48 std::string root_fs(root.path()); 49 TestingFileCollector FileCollector(root_fs, root_fs); 50 51 FileCollector.addFile("/path/to/a"); 52 FileCollector.addFile("/path/to/b"); 53 FileCollector.addFile("/path/to/c"); 54 55 // Make sure the root is correct. 56 EXPECT_EQ(FileCollector.Root, root_fs); 57 58 // Make sure we've seen all the added files. 59 EXPECT_TRUE(FileCollector.hasSeen("/path/to/a")); 60 EXPECT_TRUE(FileCollector.hasSeen("/path/to/b")); 61 EXPECT_TRUE(FileCollector.hasSeen("/path/to/c")); 62 63 // Make sure we've only seen the added files. 64 EXPECT_FALSE(FileCollector.hasSeen("/path/to/d")); 65 } 66 67 TEST(FileCollectorTest, addDirectory) { 68 TempDir file_root("file_root", /*Unique*/ true); 69 70 llvm::SmallString<128> aaa(file_root.path()); 71 llvm::sys::path::append(aaa, "aaa"); 72 TempFile a(aaa.str()); 73 74 llvm::SmallString<128> bbb(file_root.path()); 75 llvm::sys::path::append(bbb, "bbb"); 76 TempFile b(bbb.str()); 77 78 llvm::SmallString<128> ccc(file_root.path()); 79 llvm::sys::path::append(ccc, "ccc"); 80 TempFile c(ccc.str()); 81 82 std::string root_fs(file_root.path()); 83 TestingFileCollector FileCollector(root_fs, root_fs); 84 85 FileCollector.addDirectory(file_root.path()); 86 87 // Make sure the root is correct. 88 EXPECT_EQ(FileCollector.Root, root_fs); 89 90 // Make sure we've seen all the added files. 91 EXPECT_TRUE(FileCollector.hasSeen(a.path())); 92 EXPECT_TRUE(FileCollector.hasSeen(b.path())); 93 EXPECT_TRUE(FileCollector.hasSeen(c.path())); 94 95 // Make sure we've only seen the added files. 96 llvm::SmallString<128> ddd(file_root.path()); 97 llvm::sys::path::append(ddd, "ddd"); 98 TempFile d(ddd); 99 EXPECT_FALSE(FileCollector.hasSeen(d.path())); 100 } 101 102 TEST(FileCollectorTest, copyFiles) { 103 TempDir file_root("file_root", /*Unique*/ true); 104 TempFile a(file_root.path("aaa")); 105 TempFile b(file_root.path("bbb")); 106 TempFile c(file_root.path("ccc")); 107 108 // Create file collector and add files. 109 TempDir root("copy_files_root", /*Unique*/ true); 110 std::string root_fs(root.path()); 111 TestingFileCollector FileCollector(root_fs, root_fs); 112 FileCollector.addFile(a.path()); 113 FileCollector.addFile(b.path()); 114 FileCollector.addFile(c.path()); 115 116 // Make sure we can copy the files. 117 std::error_code ec = FileCollector.copyFiles(true); 118 EXPECT_FALSE(ec); 119 120 // Now add a bogus file and make sure we error out. 121 FileCollector.addFile("/some/bogus/file"); 122 ec = FileCollector.copyFiles(true); 123 EXPECT_TRUE(ec); 124 125 // However, if stop_on_error is true the copy should still succeed. 126 ec = FileCollector.copyFiles(false); 127 EXPECT_FALSE(ec); 128 } 129 130 TEST(FileCollectorTest, recordAndConstructDirectory) { 131 TempDir file_root("dir_root", /*Unique*/ true); 132 TempDir subdir(file_root.path("subdir")); 133 TempDir subdir2(file_root.path("subdir2")); 134 TempFile a(subdir2.path("a")); 135 136 // Create file collector and add files. 137 TempDir root("copy_files_root", /*Unique*/ true); 138 std::string root_fs(root.path()); 139 TestingFileCollector FileCollector(root_fs, root_fs); 140 FileCollector.addFile(a.path()); 141 142 // The empty directory isn't seen until we add it. 143 EXPECT_TRUE(FileCollector.hasSeen(a.path())); 144 EXPECT_FALSE(FileCollector.hasSeen(subdir.path())); 145 146 FileCollector.addFile(subdir.path()); 147 EXPECT_TRUE(FileCollector.hasSeen(subdir.path())); 148 149 // Make sure we can construct the directory. 150 std::error_code ec = FileCollector.copyFiles(true); 151 EXPECT_FALSE(ec); 152 bool IsDirectory = false; 153 llvm::SmallString<128> SubdirInRoot = root.path(); 154 llvm::sys::path::append(SubdirInRoot, 155 llvm::sys::path::relative_path(subdir.path())); 156 ec = sys::fs::is_directory(SubdirInRoot, IsDirectory); 157 EXPECT_FALSE(ec); 158 ASSERT_TRUE(IsDirectory); 159 } 160 161 TEST(FileCollectorTest, recordVFSAccesses) { 162 TempDir file_root("dir_root", /*Unique*/ true); 163 TempDir subdir(file_root.path("subdir")); 164 TempDir subdir2(file_root.path("subdir2")); 165 TempFile a(subdir2.path("a")); 166 TempFile b(file_root.path("b")); 167 TempDir subdir3(file_root.path("subdir3")); 168 TempFile subdir3a(subdir3.path("aa")); 169 TempDir subdir3b(subdir3.path("subdirb")); 170 { TempFile subdir3fileremoved(subdir3.path("removed")); } 171 172 // Create file collector and add files. 173 TempDir root("copy_files_root", /*Unique*/ true); 174 std::string root_fs(root.path()); 175 auto Collector = std::make_shared<TestingFileCollector>(root_fs, root_fs); 176 auto VFS = 177 FileCollector::createCollectorVFS(vfs::getRealFileSystem(), Collector); 178 VFS->status(a.path()); 179 EXPECT_TRUE(Collector->hasSeen(a.path())); 180 181 VFS->openFileForRead(b.path()); 182 EXPECT_TRUE(Collector->hasSeen(b.path())); 183 184 VFS->status(subdir.path()); 185 EXPECT_TRUE(Collector->hasSeen(subdir.path())); 186 187 #ifndef _WIN32 188 std::error_code EC; 189 auto It = VFS->dir_begin(subdir3.path(), EC); 190 EXPECT_FALSE(EC); 191 EXPECT_TRUE(Collector->hasSeen(subdir3.path())); 192 EXPECT_TRUE(Collector->hasSeen(subdir3a.path())); 193 EXPECT_TRUE(Collector->hasSeen(subdir3b.path())); 194 std::string RemovedFileName((Twine(subdir3.path("removed"))).str()); 195 EXPECT_FALSE(Collector->hasSeen(RemovedFileName)); 196 #endif 197 } 198 199 #ifndef _WIN32 200 TEST(FileCollectorTest, Symlinks) { 201 // Root where the original files live. 202 TempDir file_root("file_root", /*Unique*/ true); 203 204 // Create some files in the file root. 205 TempFile a(file_root.path("aaa")); 206 TempFile b(file_root.path("bbb")); 207 TempFile c(file_root.path("ccc")); 208 209 // Create a directory foo with file ddd. 210 TempDir foo(file_root.path("foo")); 211 TempFile d(foo.path("ddd")); 212 213 // Create a file eee in the foo's parent directory. 214 TempFile e(foo.path("../eee")); 215 216 // Create a symlink bar pointing to foo. 217 TempLink symlink(file_root.path("foo"), file_root.path("bar")); 218 219 // Root where files are copied to. 220 TempDir reproducer_root("reproducer_root", /*Unique*/ true); 221 std::string root_fs(reproducer_root.path()); 222 TestingFileCollector FileCollector(root_fs, root_fs); 223 224 // Add all the files to the collector. 225 FileCollector.addFile(a.path()); 226 FileCollector.addFile(b.path()); 227 FileCollector.addFile(c.path()); 228 FileCollector.addFile(d.path()); 229 FileCollector.addFile(e.path()); 230 FileCollector.addFile(file_root.path() + "/bar/ddd"); 231 232 auto mapping = FileCollector.VFSWriter.getMappings(); 233 234 { 235 // Make sure the common case works. 236 std::string vpath = (file_root.path() + "/aaa").str(); 237 std::string rpath = 238 (reproducer_root.path() + file_root.path() + "/aaa").str(); 239 printf("%s -> %s\n", vpath.c_str(), rpath.c_str()); 240 EXPECT_THAT(mapping, testing::Contains(vfs::YAMLVFSEntry(vpath, rpath))); 241 } 242 243 { 244 // Make sure the virtual path points to the real source path. 245 std::string vpath = (file_root.path() + "/bar/ddd").str(); 246 std::string rpath = 247 (reproducer_root.path() + file_root.path() + "/foo/ddd").str(); 248 printf("%s -> %s\n", vpath.c_str(), rpath.c_str()); 249 EXPECT_THAT(mapping, testing::Contains(vfs::YAMLVFSEntry(vpath, rpath))); 250 } 251 252 { 253 // Make sure that .. is removed from the source path. 254 std::string vpath = (file_root.path() + "/eee").str(); 255 std::string rpath = 256 (reproducer_root.path() + file_root.path() + "/eee").str(); 257 printf("%s -> %s\n", vpath.c_str(), rpath.c_str()); 258 EXPECT_THAT(mapping, testing::Contains(vfs::YAMLVFSEntry(vpath, rpath))); 259 } 260 } 261 262 TEST(FileCollectorTest, recordVFSSymlinkAccesses) { 263 TempDir file_root("dir_root", /*Unique*/ true); 264 TempFile a(file_root.path("a")); 265 TempLink symlink(file_root.path("a"), file_root.path("b")); 266 267 // Create file collector and add files. 268 TempDir root("copy_files_root", true); 269 std::string root_fs(root.path()); 270 auto Collector = std::make_shared<TestingFileCollector>(root_fs, root_fs); 271 auto VFS = 272 FileCollector::createCollectorVFS(vfs::getRealFileSystem(), Collector); 273 SmallString<256> Output; 274 VFS->getRealPath(symlink.path(), Output); 275 EXPECT_TRUE(Collector->hasSeen(a.path())); 276 EXPECT_TRUE(Collector->hasSeen(symlink.path())); 277 } 278 #endif 279