1bc402abcSZhanyong Wan //===- unittests/Basic/FileMangerTest.cpp ------------ FileManger tests ---===//
2bc402abcSZhanyong Wan //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bc402abcSZhanyong Wan //
7bc402abcSZhanyong Wan //===----------------------------------------------------------------------===//
8bc402abcSZhanyong Wan
9320d9666SChandler Carruth #include "clang/Basic/FileManager.h"
10bc402abcSZhanyong Wan #include "clang/Basic/FileSystemOptions.h"
11bc402abcSZhanyong Wan #include "clang/Basic/FileSystemStatCache.h"
1233335df8SBenjamin Kramer #include "llvm/ADT/STLExtras.h"
13dfffaf57SErik Verbruggen #include "llvm/Support/Path.h"
14fc51490bSJonas Devlieghere #include "llvm/Support/VirtualFileSystem.h"
15da47ec3cSDuncan P. N. Exon Smith #include "llvm/Testing/Support/Error.h"
16575bc3baSChandler Carruth #include "gtest/gtest.h"
17bc402abcSZhanyong Wan
18bc402abcSZhanyong Wan using namespace llvm;
19bc402abcSZhanyong Wan using namespace clang;
20bc402abcSZhanyong Wan
21bc402abcSZhanyong Wan namespace {
22bc402abcSZhanyong Wan
23bc402abcSZhanyong Wan // Used to create a fake file system for running the tests with such
24bc402abcSZhanyong Wan // that the tests are not affected by the structure/contents of the
25bc402abcSZhanyong Wan // file system on the machine running the tests.
26bc402abcSZhanyong Wan class FakeStatCache : public FileSystemStatCache {
27bc402abcSZhanyong Wan private:
28bc402abcSZhanyong Wan // Maps a file/directory path to its desired stat result. Anything
29bc402abcSZhanyong Wan // not in this map is considered to not exist in the file system.
3006f64d53SHarlan Haskins llvm::StringMap<llvm::vfs::Status, llvm::BumpPtrAllocator> StatCalls;
31bc402abcSZhanyong Wan
InjectFileOrDirectory(const char * Path,ino_t INode,bool IsFile,const char * StatPath)32729d7d23SDuncan P. N. Exon Smith void InjectFileOrDirectory(const char *Path, ino_t INode, bool IsFile,
33729d7d23SDuncan P. N. Exon Smith const char *StatPath) {
34dfffaf57SErik Verbruggen SmallString<128> NormalizedPath(Path);
3599023627SDuncan P. N. Exon Smith SmallString<128> NormalizedStatPath;
3699023627SDuncan P. N. Exon Smith if (is_style_posix(llvm::sys::path::Style::native)) {
37dfffaf57SErik Verbruggen llvm::sys::path::native(NormalizedPath);
38dfffaf57SErik Verbruggen Path = NormalizedPath.c_str();
39729d7d23SDuncan P. N. Exon Smith
40729d7d23SDuncan P. N. Exon Smith if (StatPath) {
41729d7d23SDuncan P. N. Exon Smith NormalizedStatPath = StatPath;
42729d7d23SDuncan P. N. Exon Smith llvm::sys::path::native(NormalizedStatPath);
43729d7d23SDuncan P. N. Exon Smith StatPath = NormalizedStatPath.c_str();
44729d7d23SDuncan P. N. Exon Smith }
4599023627SDuncan P. N. Exon Smith }
46dfffaf57SErik Verbruggen
47729d7d23SDuncan P. N. Exon Smith if (!StatPath)
48729d7d23SDuncan P. N. Exon Smith StatPath = Path;
49729d7d23SDuncan P. N. Exon Smith
5006f64d53SHarlan Haskins auto fileType = IsFile ?
5106f64d53SHarlan Haskins llvm::sys::fs::file_type::regular_file :
5206f64d53SHarlan Haskins llvm::sys::fs::file_type::directory_file;
53729d7d23SDuncan P. N. Exon Smith llvm::vfs::Status Status(StatPath, llvm::sys::fs::UniqueID(1, INode),
5406f64d53SHarlan Haskins /*MTime*/{}, /*User*/0, /*Group*/0,
5506f64d53SHarlan Haskins /*Size*/0, fileType,
5606f64d53SHarlan Haskins llvm::sys::fs::perms::all_all);
5706f64d53SHarlan Haskins StatCalls[Path] = Status;
58bc402abcSZhanyong Wan }
59bc402abcSZhanyong Wan
60bc402abcSZhanyong Wan public:
61bc402abcSZhanyong Wan // Inject a file with the given inode value to the fake file system.
InjectFile(const char * Path,ino_t INode,const char * StatPath=nullptr)62729d7d23SDuncan P. N. Exon Smith void InjectFile(const char *Path, ino_t INode,
63729d7d23SDuncan P. N. Exon Smith const char *StatPath = nullptr) {
64729d7d23SDuncan P. N. Exon Smith InjectFileOrDirectory(Path, INode, /*IsFile=*/true, StatPath);
65bc402abcSZhanyong Wan }
66bc402abcSZhanyong Wan
67bc402abcSZhanyong Wan // Inject a directory with the given inode value to the fake file system.
InjectDirectory(const char * Path,ino_t INode)68bc402abcSZhanyong Wan void InjectDirectory(const char *Path, ino_t INode) {
69729d7d23SDuncan P. N. Exon Smith InjectFileOrDirectory(Path, INode, /*IsFile=*/false, nullptr);
70bc402abcSZhanyong Wan }
71bc402abcSZhanyong Wan
72bc402abcSZhanyong Wan // Implement FileSystemStatCache::getStat().
getStat(StringRef Path,llvm::vfs::Status & Status,bool isFile,std::unique_ptr<llvm::vfs::File> * F,llvm::vfs::FileSystem & FS)73d8f776afSHarlan Haskins std::error_code getStat(StringRef Path, llvm::vfs::Status &Status,
74d8f776afSHarlan Haskins bool isFile,
75fc51490bSJonas Devlieghere std::unique_ptr<llvm::vfs::File> *F,
76fc51490bSJonas Devlieghere llvm::vfs::FileSystem &FS) override {
77dfffaf57SErik Verbruggen SmallString<128> NormalizedPath(Path);
7899023627SDuncan P. N. Exon Smith if (is_style_posix(llvm::sys::path::Style::native)) {
79dfffaf57SErik Verbruggen llvm::sys::path::native(NormalizedPath);
80dfffaf57SErik Verbruggen Path = NormalizedPath.c_str();
8199023627SDuncan P. N. Exon Smith }
82dfffaf57SErik Verbruggen
83bc402abcSZhanyong Wan if (StatCalls.count(Path) != 0) {
8406f64d53SHarlan Haskins Status = StatCalls[Path];
85d8f776afSHarlan Haskins return std::error_code();
86bc402abcSZhanyong Wan }
87bc402abcSZhanyong Wan
88d8f776afSHarlan Haskins return std::make_error_code(std::errc::no_such_file_or_directory);
89bc402abcSZhanyong Wan }
90bc402abcSZhanyong Wan };
91bc402abcSZhanyong Wan
92bc402abcSZhanyong Wan // The test fixture.
93bc402abcSZhanyong Wan class FileManagerTest : public ::testing::Test {
94bc402abcSZhanyong Wan protected:
FileManagerTest()95bc402abcSZhanyong Wan FileManagerTest() : manager(options) {
96bc402abcSZhanyong Wan }
97bc402abcSZhanyong Wan
98bc402abcSZhanyong Wan FileSystemOptions options;
99bc402abcSZhanyong Wan FileManager manager;
100bc402abcSZhanyong Wan };
101bc402abcSZhanyong Wan
102713e716cSJan Svoboda // When a virtual file is added, its getDir() field has correct name.
TEST_F(FileManagerTest,getVirtualFileSetsTheDirFieldCorrectly)103bc402abcSZhanyong Wan TEST_F(FileManagerTest, getVirtualFileSetsTheDirFieldCorrectly) {
104713e716cSJan Svoboda FileEntryRef file = manager.getVirtualFileRef("foo.cpp", 42, 0);
105713e716cSJan Svoboda EXPECT_EQ(".", file.getDir().getName());
106bc402abcSZhanyong Wan
107713e716cSJan Svoboda file = manager.getVirtualFileRef("x/y/z.cpp", 42, 0);
108713e716cSJan Svoboda EXPECT_EQ("x/y", file.getDir().getName());
109bc402abcSZhanyong Wan }
110bc402abcSZhanyong Wan
111bc402abcSZhanyong Wan // Before any virtual file is added, no virtual directory exists.
TEST_F(FileManagerTest,NoVirtualDirectoryExistsBeforeAVirtualFileIsAdded)112bc402abcSZhanyong Wan TEST_F(FileManagerTest, NoVirtualDirectoryExistsBeforeAVirtualFileIsAdded) {
113bc402abcSZhanyong Wan // An empty FakeStatCache causes all stat calls made by the
114bc402abcSZhanyong Wan // FileManager to report "file/directory doesn't exist". This
115bc402abcSZhanyong Wan // avoids the possibility of the result of this test being affected
116bc402abcSZhanyong Wan // by what's in the real file system.
1172b3d49b6SJonas Devlieghere manager.setStatCache(std::make_unique<FakeStatCache>());
118bc402abcSZhanyong Wan
119461f0722SHarlan Haskins ASSERT_FALSE(manager.getDirectory("virtual/dir/foo"));
120461f0722SHarlan Haskins ASSERT_FALSE(manager.getDirectory("virtual/dir"));
121461f0722SHarlan Haskins ASSERT_FALSE(manager.getDirectory("virtual"));
122bc402abcSZhanyong Wan }
123bc402abcSZhanyong Wan
124bc402abcSZhanyong Wan // When a virtual file is added, all of its ancestors should be created.
TEST_F(FileManagerTest,getVirtualFileCreatesDirectoryEntriesForAncestors)125bc402abcSZhanyong Wan TEST_F(FileManagerTest, getVirtualFileCreatesDirectoryEntriesForAncestors) {
126bc402abcSZhanyong Wan // Fake an empty real file system.
1272b3d49b6SJonas Devlieghere manager.setStatCache(std::make_unique<FakeStatCache>());
128bc402abcSZhanyong Wan
129bc402abcSZhanyong Wan manager.getVirtualFile("virtual/dir/bar.h", 100, 0);
130461f0722SHarlan Haskins ASSERT_FALSE(manager.getDirectory("virtual/dir/foo"));
131bc402abcSZhanyong Wan
132713e716cSJan Svoboda auto dir = manager.getDirectoryRef("virtual/dir");
133713e716cSJan Svoboda ASSERT_THAT_EXPECTED(dir, llvm::Succeeded());
134713e716cSJan Svoboda EXPECT_EQ("virtual/dir", dir->getName());
135bc402abcSZhanyong Wan
136713e716cSJan Svoboda dir = manager.getDirectoryRef("virtual");
137713e716cSJan Svoboda ASSERT_THAT_EXPECTED(dir, llvm::Succeeded());
138713e716cSJan Svoboda EXPECT_EQ("virtual", dir->getName());
139bc402abcSZhanyong Wan }
140bc402abcSZhanyong Wan
141713e716cSJan Svoboda // getFileRef() succeeds if a real file exists at the given path.
TEST_F(FileManagerTest,getFileReturnsValidFileEntryForExistingRealFile)142bc402abcSZhanyong Wan TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingRealFile) {
143bc402abcSZhanyong Wan // Inject fake files into the file system.
1442b3d49b6SJonas Devlieghere auto statCache = std::make_unique<FakeStatCache>();
145bc402abcSZhanyong Wan statCache->InjectDirectory("/tmp", 42);
146bc402abcSZhanyong Wan statCache->InjectFile("/tmp/test", 43);
147ee30546cSRafael Espindola
1481865df49SNico Weber #ifdef _WIN32
149ee30546cSRafael Espindola const char *DirName = "C:.";
150ee30546cSRafael Espindola const char *FileName = "C:test";
151ee30546cSRafael Espindola statCache->InjectDirectory(DirName, 44);
152ee30546cSRafael Espindola statCache->InjectFile(FileName, 45);
153ee30546cSRafael Espindola #endif
154ee30546cSRafael Espindola
155d92b1ae1SAlex Lorenz manager.setStatCache(std::move(statCache));
156bc402abcSZhanyong Wan
157713e716cSJan Svoboda auto file = manager.getFileRef("/tmp/test");
158713e716cSJan Svoboda ASSERT_THAT_EXPECTED(file, llvm::Succeeded());
159713e716cSJan Svoboda EXPECT_EQ("/tmp/test", file->getName());
160bc402abcSZhanyong Wan
161713e716cSJan Svoboda EXPECT_EQ("/tmp", file->getDir().getName());
162ee30546cSRafael Espindola
1631865df49SNico Weber #ifdef _WIN32
164713e716cSJan Svoboda file = manager.getFileRef(FileName);
165713e716cSJan Svoboda ASSERT_THAT_EXPECTED(file, llvm::Succeeded());
166713e716cSJan Svoboda EXPECT_EQ(DirName, file->getDir().getName());
167ee30546cSRafael Espindola #endif
168bc402abcSZhanyong Wan }
169bc402abcSZhanyong Wan
170713e716cSJan Svoboda // getFileRef() succeeds if a virtual file exists at the given path.
TEST_F(FileManagerTest,getFileReturnsValidFileEntryForExistingVirtualFile)171bc402abcSZhanyong Wan TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingVirtualFile) {
172bc402abcSZhanyong Wan // Fake an empty real file system.
1732b3d49b6SJonas Devlieghere manager.setStatCache(std::make_unique<FakeStatCache>());
174bc402abcSZhanyong Wan
175bc402abcSZhanyong Wan manager.getVirtualFile("virtual/dir/bar.h", 100, 0);
176713e716cSJan Svoboda auto file = manager.getFileRef("virtual/dir/bar.h");
177713e716cSJan Svoboda ASSERT_THAT_EXPECTED(file, llvm::Succeeded());
178713e716cSJan Svoboda EXPECT_EQ("virtual/dir/bar.h", file->getName());
179713e716cSJan Svoboda EXPECT_EQ("virtual/dir", file->getDir().getName());
180bc402abcSZhanyong Wan }
181bc402abcSZhanyong Wan
182bc402abcSZhanyong Wan // getFile() returns different FileEntries for different paths when
183bc402abcSZhanyong Wan // there's no aliasing.
TEST_F(FileManagerTest,getFileReturnsDifferentFileEntriesForDifferentFiles)184bc402abcSZhanyong Wan TEST_F(FileManagerTest, getFileReturnsDifferentFileEntriesForDifferentFiles) {
185bc402abcSZhanyong Wan // Inject two fake files into the file system. Different inodes
186bc402abcSZhanyong Wan // mean the files are not symlinked together.
1872b3d49b6SJonas Devlieghere auto statCache = std::make_unique<FakeStatCache>();
188bc402abcSZhanyong Wan statCache->InjectDirectory(".", 41);
189bc402abcSZhanyong Wan statCache->InjectFile("foo.cpp", 42);
190bc402abcSZhanyong Wan statCache->InjectFile("bar.cpp", 43);
191d92b1ae1SAlex Lorenz manager.setStatCache(std::move(statCache));
192bc402abcSZhanyong Wan
193461f0722SHarlan Haskins auto fileFoo = manager.getFile("foo.cpp");
194461f0722SHarlan Haskins auto fileBar = manager.getFile("bar.cpp");
195461f0722SHarlan Haskins ASSERT_TRUE(fileFoo);
196461f0722SHarlan Haskins ASSERT_TRUE(fileBar);
197461f0722SHarlan Haskins EXPECT_NE(*fileFoo, *fileBar);
198bc402abcSZhanyong Wan }
199bc402abcSZhanyong Wan
2008d323d15SHarlan Haskins // getFile() returns an error if neither a real file nor a virtual file
201bc402abcSZhanyong Wan // exists at the given path.
TEST_F(FileManagerTest,getFileReturnsErrorForNonexistentFile)2028d323d15SHarlan Haskins TEST_F(FileManagerTest, getFileReturnsErrorForNonexistentFile) {
203bc402abcSZhanyong Wan // Inject a fake foo.cpp into the file system.
2042b3d49b6SJonas Devlieghere auto statCache = std::make_unique<FakeStatCache>();
205bc402abcSZhanyong Wan statCache->InjectDirectory(".", 41);
206bc402abcSZhanyong Wan statCache->InjectFile("foo.cpp", 42);
2075341f79aSHarlan Haskins statCache->InjectDirectory("MyDirectory", 49);
208d92b1ae1SAlex Lorenz manager.setStatCache(std::move(statCache));
209bc402abcSZhanyong Wan
210bc402abcSZhanyong Wan // Create a virtual bar.cpp file.
211bc402abcSZhanyong Wan manager.getVirtualFile("bar.cpp", 200, 0);
212bc402abcSZhanyong Wan
213461f0722SHarlan Haskins auto file = manager.getFile("xyz.txt");
214461f0722SHarlan Haskins ASSERT_FALSE(file);
2158d323d15SHarlan Haskins ASSERT_EQ(file.getError(), std::errc::no_such_file_or_directory);
2168d323d15SHarlan Haskins
2178d323d15SHarlan Haskins auto readingDirAsFile = manager.getFile("MyDirectory");
2188d323d15SHarlan Haskins ASSERT_FALSE(readingDirAsFile);
2198d323d15SHarlan Haskins ASSERT_EQ(readingDirAsFile.getError(), std::errc::is_a_directory);
2208d323d15SHarlan Haskins
2218d323d15SHarlan Haskins auto readingFileAsDir = manager.getDirectory("foo.cpp");
2228d323d15SHarlan Haskins ASSERT_FALSE(readingFileAsDir);
2238d323d15SHarlan Haskins ASSERT_EQ(readingFileAsDir.getError(), std::errc::not_a_directory);
224bc402abcSZhanyong Wan }
225bc402abcSZhanyong Wan
226bc402abcSZhanyong Wan // The following tests apply to Unix-like system only.
227bc402abcSZhanyong Wan
2281865df49SNico Weber #ifndef _WIN32
229bc402abcSZhanyong Wan
230bc402abcSZhanyong Wan // getFile() returns the same FileEntry for real files that are aliases.
TEST_F(FileManagerTest,getFileReturnsSameFileEntryForAliasedRealFiles)231bc402abcSZhanyong Wan TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedRealFiles) {
232bc402abcSZhanyong Wan // Inject two real files with the same inode.
2332b3d49b6SJonas Devlieghere auto statCache = std::make_unique<FakeStatCache>();
234bc402abcSZhanyong Wan statCache->InjectDirectory("abc", 41);
235bc402abcSZhanyong Wan statCache->InjectFile("abc/foo.cpp", 42);
236bc402abcSZhanyong Wan statCache->InjectFile("abc/bar.cpp", 42);
237d92b1ae1SAlex Lorenz manager.setStatCache(std::move(statCache));
238bc402abcSZhanyong Wan
239461f0722SHarlan Haskins auto f1 = manager.getFile("abc/foo.cpp");
240461f0722SHarlan Haskins auto f2 = manager.getFile("abc/bar.cpp");
241461f0722SHarlan Haskins
242461f0722SHarlan Haskins EXPECT_EQ(f1 ? *f1 : nullptr,
243461f0722SHarlan Haskins f2 ? *f2 : nullptr);
244729d7d23SDuncan P. N. Exon Smith
245729d7d23SDuncan P. N. Exon Smith // Check that getFileRef also does the right thing.
246729d7d23SDuncan P. N. Exon Smith auto r1 = manager.getFileRef("abc/foo.cpp");
247729d7d23SDuncan P. N. Exon Smith auto r2 = manager.getFileRef("abc/bar.cpp");
248729d7d23SDuncan P. N. Exon Smith ASSERT_FALSE(!r1);
249729d7d23SDuncan P. N. Exon Smith ASSERT_FALSE(!r2);
250729d7d23SDuncan P. N. Exon Smith
251729d7d23SDuncan P. N. Exon Smith EXPECT_EQ("abc/foo.cpp", r1->getName());
252729d7d23SDuncan P. N. Exon Smith EXPECT_EQ("abc/bar.cpp", r2->getName());
253729d7d23SDuncan P. N. Exon Smith EXPECT_EQ((f1 ? *f1 : nullptr), &r1->getFileEntry());
254729d7d23SDuncan P. N. Exon Smith EXPECT_EQ((f2 ? *f2 : nullptr), &r2->getFileEntry());
255729d7d23SDuncan P. N. Exon Smith }
256729d7d23SDuncan P. N. Exon Smith
TEST_F(FileManagerTest,getFileRefReturnsCorrectNameForDifferentStatPath)257729d7d23SDuncan P. N. Exon Smith TEST_F(FileManagerTest, getFileRefReturnsCorrectNameForDifferentStatPath) {
258729d7d23SDuncan P. N. Exon Smith // Inject files with the same inode, but where some files have a stat that
2598976a1e1SDuncan P. N. Exon Smith // gives a different name. This is adding coverage for stat behaviour
2608976a1e1SDuncan P. N. Exon Smith // triggered by the RedirectingFileSystem for 'use-external-name' that
2618976a1e1SDuncan P. N. Exon Smith // FileManager::getFileRef has special logic for.
262729d7d23SDuncan P. N. Exon Smith auto StatCache = std::make_unique<FakeStatCache>();
263729d7d23SDuncan P. N. Exon Smith StatCache->InjectDirectory("dir", 40);
264729d7d23SDuncan P. N. Exon Smith StatCache->InjectFile("dir/f1.cpp", 41);
265729d7d23SDuncan P. N. Exon Smith StatCache->InjectFile("dir/f1-alias.cpp", 41, "dir/f1.cpp");
266729d7d23SDuncan P. N. Exon Smith StatCache->InjectFile("dir/f2.cpp", 42);
267729d7d23SDuncan P. N. Exon Smith StatCache->InjectFile("dir/f2-alias.cpp", 42, "dir/f2.cpp");
268917acac9SDuncan P. N. Exon Smith
269917acac9SDuncan P. N. Exon Smith // This unintuitive rename-the-file-on-stat behaviour supports how the
270917acac9SDuncan P. N. Exon Smith // RedirectingFileSystem VFS layer responds to stats. However, even if you
271917acac9SDuncan P. N. Exon Smith // have two layers, you should only get a single filename back. As such the
272917acac9SDuncan P. N. Exon Smith // following stat cache behaviour is not supported (the correct stat entry
273917acac9SDuncan P. N. Exon Smith // for a double-redirection would be "dir/f1.cpp") and the getFileRef below
274917acac9SDuncan P. N. Exon Smith // should assert.
275917acac9SDuncan P. N. Exon Smith StatCache->InjectFile("dir/f1-alias-alias.cpp", 41, "dir/f1-alias.cpp");
276917acac9SDuncan P. N. Exon Smith
277729d7d23SDuncan P. N. Exon Smith manager.setStatCache(std::move(StatCache));
278729d7d23SDuncan P. N. Exon Smith
279917acac9SDuncan P. N. Exon Smith // With F1, test accessing the non-redirected name first.
280729d7d23SDuncan P. N. Exon Smith auto F1 = manager.getFileRef("dir/f1.cpp");
281729d7d23SDuncan P. N. Exon Smith auto F1Alias = manager.getFileRef("dir/f1-alias.cpp");
282729d7d23SDuncan P. N. Exon Smith auto F1Alias2 = manager.getFileRef("dir/f1-alias.cpp");
283729d7d23SDuncan P. N. Exon Smith ASSERT_FALSE(!F1);
284729d7d23SDuncan P. N. Exon Smith ASSERT_FALSE(!F1Alias);
285729d7d23SDuncan P. N. Exon Smith ASSERT_FALSE(!F1Alias2);
286729d7d23SDuncan P. N. Exon Smith EXPECT_EQ("dir/f1.cpp", F1->getName());
287729d7d23SDuncan P. N. Exon Smith EXPECT_EQ("dir/f1.cpp", F1->getFileEntry().getName());
288729d7d23SDuncan P. N. Exon Smith EXPECT_EQ("dir/f1.cpp", F1Alias->getName());
289729d7d23SDuncan P. N. Exon Smith EXPECT_EQ("dir/f1.cpp", F1Alias2->getName());
290729d7d23SDuncan P. N. Exon Smith EXPECT_EQ(&F1->getFileEntry(), &F1Alias->getFileEntry());
291729d7d23SDuncan P. N. Exon Smith EXPECT_EQ(&F1->getFileEntry(), &F1Alias2->getFileEntry());
292729d7d23SDuncan P. N. Exon Smith
293917acac9SDuncan P. N. Exon Smith #if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST
294917acac9SDuncan P. N. Exon Smith EXPECT_DEATH((void)manager.getFileRef("dir/f1-alias-alias.cpp"),
295917acac9SDuncan P. N. Exon Smith "filename redirected to a non-canonical filename?");
296917acac9SDuncan P. N. Exon Smith #endif
297917acac9SDuncan P. N. Exon Smith
298729d7d23SDuncan P. N. Exon Smith // With F2, test accessing the redirected name first.
299729d7d23SDuncan P. N. Exon Smith auto F2Alias = manager.getFileRef("dir/f2-alias.cpp");
300729d7d23SDuncan P. N. Exon Smith auto F2 = manager.getFileRef("dir/f2.cpp");
301729d7d23SDuncan P. N. Exon Smith auto F2Alias2 = manager.getFileRef("dir/f2-alias.cpp");
302729d7d23SDuncan P. N. Exon Smith ASSERT_FALSE(!F2);
303729d7d23SDuncan P. N. Exon Smith ASSERT_FALSE(!F2Alias);
304729d7d23SDuncan P. N. Exon Smith ASSERT_FALSE(!F2Alias2);
305729d7d23SDuncan P. N. Exon Smith EXPECT_EQ("dir/f2.cpp", F2->getName());
306729d7d23SDuncan P. N. Exon Smith EXPECT_EQ("dir/f2.cpp", F2->getFileEntry().getName());
307729d7d23SDuncan P. N. Exon Smith EXPECT_EQ("dir/f2.cpp", F2Alias->getName());
308729d7d23SDuncan P. N. Exon Smith EXPECT_EQ("dir/f2.cpp", F2Alias2->getName());
309729d7d23SDuncan P. N. Exon Smith EXPECT_EQ(&F2->getFileEntry(), &F2Alias->getFileEntry());
310729d7d23SDuncan P. N. Exon Smith EXPECT_EQ(&F2->getFileEntry(), &F2Alias2->getFileEntry());
311bc402abcSZhanyong Wan }
312bc402abcSZhanyong Wan
313bc402abcSZhanyong Wan // getFile() returns the same FileEntry for virtual files that have
314bc402abcSZhanyong Wan // corresponding real files that are aliases.
TEST_F(FileManagerTest,getFileReturnsSameFileEntryForAliasedVirtualFiles)315bc402abcSZhanyong Wan TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedVirtualFiles) {
316bc402abcSZhanyong Wan // Inject two real files with the same inode.
3172b3d49b6SJonas Devlieghere auto statCache = std::make_unique<FakeStatCache>();
318bc402abcSZhanyong Wan statCache->InjectDirectory("abc", 41);
319bc402abcSZhanyong Wan statCache->InjectFile("abc/foo.cpp", 42);
320bc402abcSZhanyong Wan statCache->InjectFile("abc/bar.cpp", 42);
321d92b1ae1SAlex Lorenz manager.setStatCache(std::move(statCache));
322bc402abcSZhanyong Wan
323461f0722SHarlan Haskins auto f1 = manager.getFile("abc/foo.cpp");
324461f0722SHarlan Haskins auto f2 = manager.getFile("abc/bar.cpp");
325461f0722SHarlan Haskins
326461f0722SHarlan Haskins EXPECT_EQ(f1 ? *f1 : nullptr,
327461f0722SHarlan Haskins f2 ? *f2 : nullptr);
328bc402abcSZhanyong Wan }
329bc402abcSZhanyong Wan
TEST_F(FileManagerTest,getFileRefEquality)330ac49500cSDuncan P. N. Exon Smith TEST_F(FileManagerTest, getFileRefEquality) {
331ac49500cSDuncan P. N. Exon Smith auto StatCache = std::make_unique<FakeStatCache>();
332ac49500cSDuncan P. N. Exon Smith StatCache->InjectDirectory("dir", 40);
333ac49500cSDuncan P. N. Exon Smith StatCache->InjectFile("dir/f1.cpp", 41);
334ac49500cSDuncan P. N. Exon Smith StatCache->InjectFile("dir/f1-also.cpp", 41);
335ac49500cSDuncan P. N. Exon Smith StatCache->InjectFile("dir/f1-redirect.cpp", 41, "dir/f1.cpp");
336ac49500cSDuncan P. N. Exon Smith StatCache->InjectFile("dir/f2.cpp", 42);
337ac49500cSDuncan P. N. Exon Smith manager.setStatCache(std::move(StatCache));
338ac49500cSDuncan P. N. Exon Smith
339ac49500cSDuncan P. N. Exon Smith auto F1 = manager.getFileRef("dir/f1.cpp");
340ac49500cSDuncan P. N. Exon Smith auto F1Again = manager.getFileRef("dir/f1.cpp");
341ac49500cSDuncan P. N. Exon Smith auto F1Also = manager.getFileRef("dir/f1-also.cpp");
342ac49500cSDuncan P. N. Exon Smith auto F1Redirect = manager.getFileRef("dir/f1-redirect.cpp");
343ac49500cSDuncan P. N. Exon Smith auto F2 = manager.getFileRef("dir/f2.cpp");
344ac49500cSDuncan P. N. Exon Smith
345ac49500cSDuncan P. N. Exon Smith // Check Expected<FileEntryRef> for error.
346ac49500cSDuncan P. N. Exon Smith ASSERT_FALSE(!F1);
347ac49500cSDuncan P. N. Exon Smith ASSERT_FALSE(!F1Also);
348ac49500cSDuncan P. N. Exon Smith ASSERT_FALSE(!F1Again);
349ac49500cSDuncan P. N. Exon Smith ASSERT_FALSE(!F1Redirect);
350ac49500cSDuncan P. N. Exon Smith ASSERT_FALSE(!F2);
351ac49500cSDuncan P. N. Exon Smith
352ac49500cSDuncan P. N. Exon Smith // Check names.
353ac49500cSDuncan P. N. Exon Smith EXPECT_EQ("dir/f1.cpp", F1->getName());
354ac49500cSDuncan P. N. Exon Smith EXPECT_EQ("dir/f1.cpp", F1Again->getName());
355ac49500cSDuncan P. N. Exon Smith EXPECT_EQ("dir/f1-also.cpp", F1Also->getName());
356ac49500cSDuncan P. N. Exon Smith EXPECT_EQ("dir/f1.cpp", F1Redirect->getName());
357ac49500cSDuncan P. N. Exon Smith EXPECT_EQ("dir/f2.cpp", F2->getName());
358ac49500cSDuncan P. N. Exon Smith
359ac49500cSDuncan P. N. Exon Smith // Compare against FileEntry*.
360ac49500cSDuncan P. N. Exon Smith EXPECT_EQ(&F1->getFileEntry(), *F1);
361ac49500cSDuncan P. N. Exon Smith EXPECT_EQ(*F1, &F1->getFileEntry());
362ac49500cSDuncan P. N. Exon Smith EXPECT_NE(&F2->getFileEntry(), *F1);
363ac49500cSDuncan P. N. Exon Smith EXPECT_NE(*F1, &F2->getFileEntry());
364ac49500cSDuncan P. N. Exon Smith
365ac49500cSDuncan P. N. Exon Smith // Compare using ==.
366ac49500cSDuncan P. N. Exon Smith EXPECT_EQ(*F1, *F1Also);
367ac49500cSDuncan P. N. Exon Smith EXPECT_EQ(*F1, *F1Again);
368ac49500cSDuncan P. N. Exon Smith EXPECT_EQ(*F1, *F1Redirect);
369ac49500cSDuncan P. N. Exon Smith EXPECT_EQ(*F1Also, *F1Redirect);
370ac49500cSDuncan P. N. Exon Smith EXPECT_NE(*F2, *F1);
371ac49500cSDuncan P. N. Exon Smith EXPECT_NE(*F2, *F1Also);
372ac49500cSDuncan P. N. Exon Smith EXPECT_NE(*F2, *F1Again);
373ac49500cSDuncan P. N. Exon Smith EXPECT_NE(*F2, *F1Redirect);
374ac49500cSDuncan P. N. Exon Smith
375ac49500cSDuncan P. N. Exon Smith // Compare using isSameRef.
376ac49500cSDuncan P. N. Exon Smith EXPECT_TRUE(F1->isSameRef(*F1Again));
377ac49500cSDuncan P. N. Exon Smith EXPECT_TRUE(F1->isSameRef(*F1Redirect));
378ac49500cSDuncan P. N. Exon Smith EXPECT_FALSE(F1->isSameRef(*F1Also));
379ac49500cSDuncan P. N. Exon Smith EXPECT_FALSE(F1->isSameRef(*F2));
380ac49500cSDuncan P. N. Exon Smith }
381ac49500cSDuncan P. N. Exon Smith
382dfffaf57SErik Verbruggen // getFile() Should return the same entry as getVirtualFile if the file actually
383dfffaf57SErik Verbruggen // is a virtual file, even if the name is not exactly the same (but is after
384dfffaf57SErik Verbruggen // normalisation done by the file system, like on Windows). This can be checked
3855ccdd923SJiading Gai // here by checking the size.
TEST_F(FileManagerTest,getVirtualFileWithDifferentName)386dfffaf57SErik Verbruggen TEST_F(FileManagerTest, getVirtualFileWithDifferentName) {
387dfffaf57SErik Verbruggen // Inject fake files into the file system.
3882b3d49b6SJonas Devlieghere auto statCache = std::make_unique<FakeStatCache>();
389dfffaf57SErik Verbruggen statCache->InjectDirectory("c:\\tmp", 42);
390dfffaf57SErik Verbruggen statCache->InjectFile("c:\\tmp\\test", 43);
391dfffaf57SErik Verbruggen
392d92b1ae1SAlex Lorenz manager.setStatCache(std::move(statCache));
393dfffaf57SErik Verbruggen
394dfffaf57SErik Verbruggen // Inject the virtual file:
395dfffaf57SErik Verbruggen const FileEntry *file1 = manager.getVirtualFile("c:\\tmp\\test", 123, 1);
396dfffaf57SErik Verbruggen ASSERT_TRUE(file1 != nullptr);
397dfffaf57SErik Verbruggen EXPECT_EQ(43U, file1->getUniqueID().getFile());
398dfffaf57SErik Verbruggen EXPECT_EQ(123, file1->getSize());
399dfffaf57SErik Verbruggen
400dfffaf57SErik Verbruggen // Lookup the virtual file with a different name:
401461f0722SHarlan Haskins auto file2 = manager.getFile("c:/tmp/test", 100, 1);
402461f0722SHarlan Haskins ASSERT_TRUE(file2);
403dfffaf57SErik Verbruggen // Check that it's the same UFE:
404461f0722SHarlan Haskins EXPECT_EQ(file1, *file2);
405461f0722SHarlan Haskins EXPECT_EQ(43U, (*file2)->getUniqueID().getFile());
406dfffaf57SErik Verbruggen // Check that the contents of the UFE are not overwritten by the entry in the
407dfffaf57SErik Verbruggen // filesystem:
408461f0722SHarlan Haskins EXPECT_EQ(123, (*file2)->getSize());
409dfffaf57SErik Verbruggen }
410dfffaf57SErik Verbruggen
4111865df49SNico Weber #endif // !_WIN32
412bc402abcSZhanyong Wan
getSystemRoot()41399023627SDuncan P. N. Exon Smith static StringRef getSystemRoot() {
414*35ab2a11SPaul Pluzhnikov return is_style_windows(llvm::sys::path::Style::native) ? "C:\\" : "/";
41599023627SDuncan P. N. Exon Smith }
41699023627SDuncan P. N. Exon Smith
TEST_F(FileManagerTest,makeAbsoluteUsesVFS)41747035c02SIlya Biryukov TEST_F(FileManagerTest, makeAbsoluteUsesVFS) {
41899023627SDuncan P. N. Exon Smith // FIXME: Should this be using a root path / call getSystemRoot()? For now,
41999023627SDuncan P. N. Exon Smith // avoiding that and leaving the test as-is.
42099023627SDuncan P. N. Exon Smith SmallString<64> CustomWorkingDir =
42199023627SDuncan P. N. Exon Smith is_style_windows(llvm::sys::path::Style::native) ? StringRef("C:")
42299023627SDuncan P. N. Exon Smith : StringRef("/");
42347035c02SIlya Biryukov llvm::sys::path::append(CustomWorkingDir, "some", "weird", "path");
42447035c02SIlya Biryukov
425fc51490bSJonas Devlieghere auto FS = IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem>(
426fc51490bSJonas Devlieghere new llvm::vfs::InMemoryFileSystem);
42747035c02SIlya Biryukov // setCurrentworkingdirectory must finish without error.
42847035c02SIlya Biryukov ASSERT_TRUE(!FS->setCurrentWorkingDirectory(CustomWorkingDir));
42947035c02SIlya Biryukov
43047035c02SIlya Biryukov FileSystemOptions Opts;
43147035c02SIlya Biryukov FileManager Manager(Opts, FS);
43247035c02SIlya Biryukov
43347035c02SIlya Biryukov SmallString<64> Path("a/foo.cpp");
43447035c02SIlya Biryukov
43547035c02SIlya Biryukov SmallString<64> ExpectedResult(CustomWorkingDir);
43647035c02SIlya Biryukov llvm::sys::path::append(ExpectedResult, Path);
43747035c02SIlya Biryukov
43847035c02SIlya Biryukov ASSERT_TRUE(Manager.makeAbsolutePath(Path));
43947035c02SIlya Biryukov EXPECT_EQ(Path, ExpectedResult);
44047035c02SIlya Biryukov }
44147035c02SIlya Biryukov
442e9870c0cSKadir Cetinkaya // getVirtualFile should always fill the real path.
TEST_F(FileManagerTest,getVirtualFileFillsRealPathName)443e9870c0cSKadir Cetinkaya TEST_F(FileManagerTest, getVirtualFileFillsRealPathName) {
44499023627SDuncan P. N. Exon Smith SmallString<64> CustomWorkingDir = getSystemRoot();
4450ef54dbdSStella Stamenova
4460ef54dbdSStella Stamenova auto FS = IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem>(
4470ef54dbdSStella Stamenova new llvm::vfs::InMemoryFileSystem);
4480ef54dbdSStella Stamenova // setCurrentworkingdirectory must finish without error.
4490ef54dbdSStella Stamenova ASSERT_TRUE(!FS->setCurrentWorkingDirectory(CustomWorkingDir));
4500ef54dbdSStella Stamenova
4510ef54dbdSStella Stamenova FileSystemOptions Opts;
4520ef54dbdSStella Stamenova FileManager Manager(Opts, FS);
4530ef54dbdSStella Stamenova
454e9870c0cSKadir Cetinkaya // Inject fake files into the file system.
4552b3d49b6SJonas Devlieghere auto statCache = std::make_unique<FakeStatCache>();
456e9870c0cSKadir Cetinkaya statCache->InjectDirectory("/tmp", 42);
457e9870c0cSKadir Cetinkaya statCache->InjectFile("/tmp/test", 43);
4580ef54dbdSStella Stamenova
459d92b1ae1SAlex Lorenz Manager.setStatCache(std::move(statCache));
460e9870c0cSKadir Cetinkaya
461e9870c0cSKadir Cetinkaya // Check for real path.
4620ef54dbdSStella Stamenova const FileEntry *file = Manager.getVirtualFile("/tmp/test", 123, 1);
463e9870c0cSKadir Cetinkaya ASSERT_TRUE(file != nullptr);
4640ef54dbdSStella Stamenova SmallString<64> ExpectedResult = CustomWorkingDir;
4650ef54dbdSStella Stamenova
466853ec892SKadir Cetinkaya llvm::sys::path::append(ExpectedResult, "tmp", "test");
467853ec892SKadir Cetinkaya EXPECT_EQ(file->tryGetRealPathName(), ExpectedResult);
468e9870c0cSKadir Cetinkaya }
469e9870c0cSKadir Cetinkaya
TEST_F(FileManagerTest,getFileDontOpenRealPath)470cd8607dbSJan Korous TEST_F(FileManagerTest, getFileDontOpenRealPath) {
47199023627SDuncan P. N. Exon Smith SmallString<64> CustomWorkingDir = getSystemRoot();
472cd8607dbSJan Korous
473cd8607dbSJan Korous auto FS = IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem>(
474cd8607dbSJan Korous new llvm::vfs::InMemoryFileSystem);
475cd8607dbSJan Korous // setCurrentworkingdirectory must finish without error.
476cd8607dbSJan Korous ASSERT_TRUE(!FS->setCurrentWorkingDirectory(CustomWorkingDir));
477cd8607dbSJan Korous
478cd8607dbSJan Korous FileSystemOptions Opts;
479cd8607dbSJan Korous FileManager Manager(Opts, FS);
480cd8607dbSJan Korous
4811dbc7218SJan Korous // Inject fake files into the file system.
4822b3d49b6SJonas Devlieghere auto statCache = std::make_unique<FakeStatCache>();
4831dbc7218SJan Korous statCache->InjectDirectory("/tmp", 42);
4841dbc7218SJan Korous statCache->InjectFile("/tmp/test", 43);
485cd8607dbSJan Korous
4861dbc7218SJan Korous Manager.setStatCache(std::move(statCache));
487cd8607dbSJan Korous
4881dbc7218SJan Korous // Check for real path.
4898d323d15SHarlan Haskins auto file = Manager.getFile("/tmp/test", /*OpenFile=*/false);
4908d323d15SHarlan Haskins ASSERT_TRUE(file);
4911dbc7218SJan Korous SmallString<64> ExpectedResult = CustomWorkingDir;
492cd8607dbSJan Korous
4931dbc7218SJan Korous llvm::sys::path::append(ExpectedResult, "tmp", "test");
4948d323d15SHarlan Haskins EXPECT_EQ((*file)->tryGetRealPathName(), ExpectedResult);
495cd8607dbSJan Korous }
496cd8607dbSJan Korous
TEST_F(FileManagerTest,getBypassFile)497e1b7f22bSDuncan P. N. Exon Smith TEST_F(FileManagerTest, getBypassFile) {
498e1b7f22bSDuncan P. N. Exon Smith SmallString<64> CustomWorkingDir;
499e1b7f22bSDuncan P. N. Exon Smith #ifdef _WIN32
500e1b7f22bSDuncan P. N. Exon Smith CustomWorkingDir = "C:/";
501e1b7f22bSDuncan P. N. Exon Smith #else
502e1b7f22bSDuncan P. N. Exon Smith CustomWorkingDir = "/";
503e1b7f22bSDuncan P. N. Exon Smith #endif
504e1b7f22bSDuncan P. N. Exon Smith
505e1b7f22bSDuncan P. N. Exon Smith auto FS = IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem>(
506e1b7f22bSDuncan P. N. Exon Smith new llvm::vfs::InMemoryFileSystem);
507e1b7f22bSDuncan P. N. Exon Smith // setCurrentworkingdirectory must finish without error.
508e1b7f22bSDuncan P. N. Exon Smith ASSERT_TRUE(!FS->setCurrentWorkingDirectory(CustomWorkingDir));
509e1b7f22bSDuncan P. N. Exon Smith
510e1b7f22bSDuncan P. N. Exon Smith FileSystemOptions Opts;
511e1b7f22bSDuncan P. N. Exon Smith FileManager Manager(Opts, FS);
512e1b7f22bSDuncan P. N. Exon Smith
513e1b7f22bSDuncan P. N. Exon Smith // Inject fake files into the file system.
514e1b7f22bSDuncan P. N. Exon Smith auto Cache = std::make_unique<FakeStatCache>();
515e1b7f22bSDuncan P. N. Exon Smith Cache->InjectDirectory("/tmp", 42);
516e1b7f22bSDuncan P. N. Exon Smith Cache->InjectFile("/tmp/test", 43);
517e1b7f22bSDuncan P. N. Exon Smith Manager.setStatCache(std::move(Cache));
518e1b7f22bSDuncan P. N. Exon Smith
519e1b7f22bSDuncan P. N. Exon Smith // Set up a virtual file with a different size than FakeStatCache uses.
520e1b7f22bSDuncan P. N. Exon Smith const FileEntry *File = Manager.getVirtualFile("/tmp/test", /*Size=*/10, 0);
521e1b7f22bSDuncan P. N. Exon Smith ASSERT_TRUE(File);
522917acac9SDuncan P. N. Exon Smith const FileEntry &FE = *File;
523917acac9SDuncan P. N. Exon Smith EXPECT_EQ(FE.getSize(), 10);
524e1b7f22bSDuncan P. N. Exon Smith
525e1b7f22bSDuncan P. N. Exon Smith // Calling a second time should not affect the UID or size.
526917acac9SDuncan P. N. Exon Smith unsigned VirtualUID = FE.getUID();
527da47ec3cSDuncan P. N. Exon Smith llvm::Optional<FileEntryRef> SearchRef;
528da47ec3cSDuncan P. N. Exon Smith ASSERT_THAT_ERROR(Manager.getFileRef("/tmp/test").moveInto(SearchRef),
529da47ec3cSDuncan P. N. Exon Smith Succeeded());
530da47ec3cSDuncan P. N. Exon Smith EXPECT_EQ(&FE, &SearchRef->getFileEntry());
531917acac9SDuncan P. N. Exon Smith EXPECT_EQ(FE.getUID(), VirtualUID);
532917acac9SDuncan P. N. Exon Smith EXPECT_EQ(FE.getSize(), 10);
533e1b7f22bSDuncan P. N. Exon Smith
534e1b7f22bSDuncan P. N. Exon Smith // Bypass the file.
535917acac9SDuncan P. N. Exon Smith llvm::Optional<FileEntryRef> BypassRef =
536917acac9SDuncan P. N. Exon Smith Manager.getBypassFile(File->getLastRef());
537e1b7f22bSDuncan P. N. Exon Smith ASSERT_TRUE(BypassRef);
538917acac9SDuncan P. N. Exon Smith EXPECT_EQ("/tmp/test", BypassRef->getName());
539e1b7f22bSDuncan P. N. Exon Smith
540e1b7f22bSDuncan P. N. Exon Smith // Check that it's different in the right ways.
541e1b7f22bSDuncan P. N. Exon Smith EXPECT_NE(&BypassRef->getFileEntry(), File);
542e1b7f22bSDuncan P. N. Exon Smith EXPECT_NE(BypassRef->getUID(), VirtualUID);
543917acac9SDuncan P. N. Exon Smith EXPECT_NE(BypassRef->getSize(), FE.getSize());
544e1b7f22bSDuncan P. N. Exon Smith
545e1b7f22bSDuncan P. N. Exon Smith // The virtual file should still be returned when searching.
546da47ec3cSDuncan P. N. Exon Smith ASSERT_THAT_ERROR(Manager.getFileRef("/tmp/test").moveInto(SearchRef),
547da47ec3cSDuncan P. N. Exon Smith Succeeded());
548da47ec3cSDuncan P. N. Exon Smith EXPECT_EQ(&FE, &SearchRef->getFileEntry());
549e1b7f22bSDuncan P. N. Exon Smith }
550e1b7f22bSDuncan P. N. Exon Smith
551bc402abcSZhanyong Wan } // anonymous namespace
552