1 //===-- FileCollectorTest.cpp -----------------------------------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #include "gmock/gmock.h"
10 #include "gtest/gtest.h"
12 #include "llvm/Support/FileCollector.h"
13 #include "llvm/Support/FileSystem.h"
19 inline bool operator==(const llvm::vfs::YAMLVFSEntry
&LHS
,
20 const llvm::vfs::YAMLVFSEntry
&RHS
) {
21 return LHS
.VPath
== RHS
.VPath
&& LHS
.RPath
== RHS
.RPath
;
27 class TestingFileCollector
: public FileCollector
{
29 using FileCollector::FileCollector
;
30 using FileCollector::Root
;
31 using FileCollector::Seen
;
32 using FileCollector::SymlinkMap
;
33 using FileCollector::VFSWriter
;
35 bool hasSeen(StringRef fs
) {
36 return Seen
.find(fs
) != Seen
.end();
41 SmallString
<128> Path
;
42 ScopedDir(const Twine
&Name
, bool Unique
= false) {
45 EC
= llvm::sys::fs::createUniqueDirectory(Name
, Path
);
48 EC
= llvm::sys::fs::create_directory(Twine(Path
));
53 // Ensure the path is the real path so tests can use it to compare against
55 SmallString
<128> RealPath
;
56 if (!llvm::sys::fs::real_path(Path
, RealPath
))
61 EXPECT_FALSE(llvm::sys::fs::remove_directories(Path
.str()));
64 operator StringRef() { return Path
.str(); }
68 SmallString
<128> Path
;
69 ScopedLink(const Twine
&To
, const Twine
&From
) {
71 std::error_code EC
= sys::fs::create_link(To
, From
);
78 EXPECT_FALSE(llvm::sys::fs::remove(Path
.str()));
81 operator StringRef() { return Path
.str(); }
85 SmallString
<128> Path
;
86 ScopedFile(const Twine
&Name
) {
88 EC
= llvm::sys::fs::createUniqueFile(Name
, Path
);
95 EXPECT_FALSE(llvm::sys::fs::remove(Path
.str()));
98 operator StringRef() { return Path
.str(); }
100 } // end anonymous namespace
102 TEST(FileCollectorTest
, addFile
) {
103 ScopedDir
root("add_file_root", true);
104 std::string root_fs
= root
.Path
.str();
105 TestingFileCollector
FileCollector(root_fs
, root_fs
);
107 FileCollector
.addFile("/path/to/a");
108 FileCollector
.addFile("/path/to/b");
109 FileCollector
.addFile("/path/to/c");
111 // Make sure the root is correct.
112 EXPECT_EQ(FileCollector
.Root
, root_fs
);
114 // Make sure we've seen all the added files.
115 EXPECT_TRUE(FileCollector
.hasSeen("/path/to/a"));
116 EXPECT_TRUE(FileCollector
.hasSeen("/path/to/b"));
117 EXPECT_TRUE(FileCollector
.hasSeen("/path/to/c"));
119 // Make sure we've only seen the added files.
120 EXPECT_FALSE(FileCollector
.hasSeen("/path/to/d"));
123 TEST(FileCollectorTest
, copyFiles
) {
124 ScopedDir
file_root("file_root", true);
125 ScopedFile
a(file_root
+ "/aaa");
126 ScopedFile
b(file_root
+ "/bbb");
127 ScopedFile
c(file_root
+ "/ccc");
129 // Create file collector and add files.
130 ScopedDir
root("copy_files_root", true);
131 std::string root_fs
= root
.Path
.str();
132 TestingFileCollector
FileCollector(root_fs
, root_fs
);
133 FileCollector
.addFile(a
.Path
);
134 FileCollector
.addFile(b
.Path
);
135 FileCollector
.addFile(c
.Path
);
137 // Make sure we can copy the files.
138 std::error_code ec
= FileCollector
.copyFiles(true);
141 // Now add a bogus file and make sure we error out.
142 FileCollector
.addFile("/some/bogus/file");
143 ec
= FileCollector
.copyFiles(true);
146 // However, if stop_on_error is true the copy should still succeed.
147 ec
= FileCollector
.copyFiles(false);
151 TEST(FileCollectorTest
, recordAndConstructDirectory
) {
152 ScopedDir
file_root("dir_root", true);
153 ScopedDir
subdir(file_root
+ "/subdir");
154 ScopedDir
subdir2(file_root
+ "/subdir2");
155 ScopedFile
a(subdir2
+ "/a");
157 // Create file collector and add files.
158 ScopedDir
root("copy_files_root", true);
159 std::string root_fs
= root
.Path
.str();
160 TestingFileCollector
FileCollector(root_fs
, root_fs
);
161 FileCollector
.addFile(a
.Path
);
163 // The empty directory isn't seen until we add it.
164 EXPECT_TRUE(FileCollector
.hasSeen(a
.Path
));
165 EXPECT_FALSE(FileCollector
.hasSeen(subdir
.Path
));
167 FileCollector
.addFile(subdir
.Path
);
168 EXPECT_TRUE(FileCollector
.hasSeen(subdir
.Path
));
170 // Make sure we can construct the directory.
171 std::error_code ec
= FileCollector
.copyFiles(true);
173 bool IsDirectory
= false;
174 llvm::SmallString
<128> SubdirInRoot
= root
.Path
;
175 llvm::sys::path::append(SubdirInRoot
,
176 llvm::sys::path::relative_path(subdir
.Path
));
177 ec
= sys::fs::is_directory(SubdirInRoot
, IsDirectory
);
179 ASSERT_TRUE(IsDirectory
);
182 TEST(FileCollectorTest
, recordVFSAccesses
) {
183 ScopedDir
file_root("dir_root", true);
184 ScopedDir
subdir(file_root
+ "/subdir");
185 ScopedDir
subdir2(file_root
+ "/subdir2");
186 ScopedFile
a(subdir2
+ "/a");
187 ScopedFile
b(file_root
+ "/b");
188 ScopedDir
subdir3(file_root
+ "/subdir3");
189 ScopedFile
subdir3a(subdir3
+ "/aa");
190 ScopedDir
subdir3b(subdir3
+ "/subdirb");
192 ScopedFile
subdir3fileremoved(subdir3
+ "/removed");
195 // Create file collector and add files.
196 ScopedDir
root("copy_files_root", true);
197 std::string root_fs
= root
.Path
.str();
198 auto Collector
= std::make_shared
<TestingFileCollector
>(root_fs
, root_fs
);
200 FileCollector::createCollectorVFS(vfs::getRealFileSystem(), Collector
);
202 EXPECT_TRUE(Collector
->hasSeen(a
.Path
));
204 VFS
->openFileForRead(b
.Path
);
205 EXPECT_TRUE(Collector
->hasSeen(b
.Path
));
207 VFS
->status(subdir
.Path
);
208 EXPECT_TRUE(Collector
->hasSeen(subdir
.Path
));
212 auto It
= VFS
->dir_begin(subdir3
.Path
, EC
);
214 EXPECT_TRUE(Collector
->hasSeen(subdir3
.Path
));
215 EXPECT_TRUE(Collector
->hasSeen(subdir3a
.Path
));
216 EXPECT_TRUE(Collector
->hasSeen(subdir3b
.Path
));
217 std::string RemovedFileName
= (Twine(subdir3
.Path
) + "/removed").str();
218 EXPECT_FALSE(Collector
->hasSeen(RemovedFileName
));
223 TEST(FileCollectorTest
, Symlinks
) {
224 // Root where the original files live.
225 ScopedDir
file_root("file_root", true);
227 // Create some files in the file root.
228 ScopedFile
a(file_root
+ "/aaa");
229 ScopedFile
b(file_root
+ "/bbb");
230 ScopedFile
c(file_root
+ "/ccc");
232 // Create a directory foo with file ddd.
233 ScopedDir
foo(file_root
+ "/foo");
234 ScopedFile
d(foo
+ "/ddd");
236 // Create a file eee in the foo's parent directory.
237 ScopedFile
e(foo
+ "/../eee");
239 // Create a symlink bar pointing to foo.
240 ScopedLink
symlink(file_root
+ "/foo", file_root
+ "/bar");
242 // Root where files are copied to.
243 ScopedDir
reproducer_root("reproducer_root", true);
244 std::string root_fs
= reproducer_root
.Path
.str();
245 TestingFileCollector
FileCollector(root_fs
, root_fs
);
247 // Add all the files to the collector.
248 FileCollector
.addFile(a
.Path
);
249 FileCollector
.addFile(b
.Path
);
250 FileCollector
.addFile(c
.Path
);
251 FileCollector
.addFile(d
.Path
);
252 FileCollector
.addFile(e
.Path
);
253 FileCollector
.addFile(file_root
+ "/bar/ddd");
255 auto mapping
= FileCollector
.VFSWriter
.getMappings();
258 // Make sure the common case works.
259 std::string vpath
= (file_root
+ "/aaa").str();
260 std::string rpath
= (reproducer_root
.Path
+ file_root
.Path
+ "/aaa").str();
261 printf("%s -> %s\n", vpath
.c_str(), rpath
.c_str());
262 EXPECT_THAT(mapping
, testing::Contains(vfs::YAMLVFSEntry(vpath
, rpath
)));
266 // Make sure the virtual path points to the real source path.
267 std::string vpath
= (file_root
+ "/bar/ddd").str();
269 (reproducer_root
.Path
+ file_root
.Path
+ "/foo/ddd").str();
270 printf("%s -> %s\n", vpath
.c_str(), rpath
.c_str());
271 EXPECT_THAT(mapping
, testing::Contains(vfs::YAMLVFSEntry(vpath
, rpath
)));
275 // Make sure that .. is removed from the source path.
276 std::string vpath
= (file_root
+ "/eee").str();
277 std::string rpath
= (reproducer_root
.Path
+ file_root
.Path
+ "/eee").str();
278 printf("%s -> %s\n", vpath
.c_str(), rpath
.c_str());
279 EXPECT_THAT(mapping
, testing::Contains(vfs::YAMLVFSEntry(vpath
, rpath
)));
283 TEST(FileCollectorTest
, recordVFSSymlinkAccesses
) {
284 ScopedDir
file_root("dir_root", true);
285 ScopedFile
a(file_root
+ "/a");
286 ScopedLink
symlink(file_root
+ "/a", file_root
+ "/b");
288 // Create file collector and add files.
289 ScopedDir
root("copy_files_root", true);
290 std::string root_fs
= root
.Path
.str();
291 auto Collector
= std::make_shared
<TestingFileCollector
>(root_fs
, root_fs
);
293 FileCollector::createCollectorVFS(vfs::getRealFileSystem(), Collector
);
294 SmallString
<256> Output
;
295 VFS
->getRealPath(symlink
.Path
, Output
);
296 EXPECT_TRUE(Collector
->hasSeen(a
.Path
));
297 EXPECT_TRUE(Collector
->hasSeen(symlink
.Path
));