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