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