xref: /aosp_15_r20/external/clang/unittests/Basic/FileManagerTest.cpp (revision 67e74705e28f6214e480b399dd47ea732279e315)
1*67e74705SXin Li //===- unittests/Basic/FileMangerTest.cpp ------------ FileManger tests ---===//
2*67e74705SXin Li //
3*67e74705SXin Li //                     The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li 
10*67e74705SXin Li #include "clang/Basic/FileManager.h"
11*67e74705SXin Li #include "clang/Basic/FileSystemOptions.h"
12*67e74705SXin Li #include "clang/Basic/FileSystemStatCache.h"
13*67e74705SXin Li #include "llvm/ADT/STLExtras.h"
14*67e74705SXin Li #include "llvm/Config/llvm-config.h"
15*67e74705SXin Li #include "gtest/gtest.h"
16*67e74705SXin Li 
17*67e74705SXin Li using namespace llvm;
18*67e74705SXin Li using namespace clang;
19*67e74705SXin Li 
20*67e74705SXin Li namespace {
21*67e74705SXin Li 
22*67e74705SXin Li // Used to create a fake file system for running the tests with such
23*67e74705SXin Li // that the tests are not affected by the structure/contents of the
24*67e74705SXin Li // file system on the machine running the tests.
25*67e74705SXin Li class FakeStatCache : public FileSystemStatCache {
26*67e74705SXin Li private:
27*67e74705SXin Li   // Maps a file/directory path to its desired stat result.  Anything
28*67e74705SXin Li   // not in this map is considered to not exist in the file system.
29*67e74705SXin Li   llvm::StringMap<FileData, llvm::BumpPtrAllocator> StatCalls;
30*67e74705SXin Li 
InjectFileOrDirectory(const char * Path,ino_t INode,bool IsFile)31*67e74705SXin Li   void InjectFileOrDirectory(const char *Path, ino_t INode, bool IsFile) {
32*67e74705SXin Li     FileData Data;
33*67e74705SXin Li     Data.Name = Path;
34*67e74705SXin Li     Data.Size = 0;
35*67e74705SXin Li     Data.ModTime = 0;
36*67e74705SXin Li     Data.UniqueID = llvm::sys::fs::UniqueID(1, INode);
37*67e74705SXin Li     Data.IsDirectory = !IsFile;
38*67e74705SXin Li     Data.IsNamedPipe = false;
39*67e74705SXin Li     Data.InPCH = false;
40*67e74705SXin Li     StatCalls[Path] = Data;
41*67e74705SXin Li   }
42*67e74705SXin Li 
43*67e74705SXin Li public:
44*67e74705SXin Li   // Inject a file with the given inode value to the fake file system.
InjectFile(const char * Path,ino_t INode)45*67e74705SXin Li   void InjectFile(const char *Path, ino_t INode) {
46*67e74705SXin Li     InjectFileOrDirectory(Path, INode, /*IsFile=*/true);
47*67e74705SXin Li   }
48*67e74705SXin Li 
49*67e74705SXin Li   // Inject a directory with the given inode value to the fake file system.
InjectDirectory(const char * Path,ino_t INode)50*67e74705SXin Li   void InjectDirectory(const char *Path, ino_t INode) {
51*67e74705SXin Li     InjectFileOrDirectory(Path, INode, /*IsFile=*/false);
52*67e74705SXin Li   }
53*67e74705SXin Li 
54*67e74705SXin Li   // Implement FileSystemStatCache::getStat().
getStat(const char * Path,FileData & Data,bool isFile,std::unique_ptr<vfs::File> * F,vfs::FileSystem & FS)55*67e74705SXin Li   LookupResult getStat(const char *Path, FileData &Data, bool isFile,
56*67e74705SXin Li                        std::unique_ptr<vfs::File> *F,
57*67e74705SXin Li                        vfs::FileSystem &FS) override {
58*67e74705SXin Li     if (StatCalls.count(Path) != 0) {
59*67e74705SXin Li       Data = StatCalls[Path];
60*67e74705SXin Li       return CacheExists;
61*67e74705SXin Li     }
62*67e74705SXin Li 
63*67e74705SXin Li     return CacheMissing;  // This means the file/directory doesn't exist.
64*67e74705SXin Li   }
65*67e74705SXin Li };
66*67e74705SXin Li 
67*67e74705SXin Li // The test fixture.
68*67e74705SXin Li class FileManagerTest : public ::testing::Test {
69*67e74705SXin Li  protected:
FileManagerTest()70*67e74705SXin Li   FileManagerTest() : manager(options) {
71*67e74705SXin Li   }
72*67e74705SXin Li 
73*67e74705SXin Li   FileSystemOptions options;
74*67e74705SXin Li   FileManager manager;
75*67e74705SXin Li };
76*67e74705SXin Li 
77*67e74705SXin Li // When a virtual file is added, its getDir() field is set correctly
78*67e74705SXin Li // (not NULL, correct name).
TEST_F(FileManagerTest,getVirtualFileSetsTheDirFieldCorrectly)79*67e74705SXin Li TEST_F(FileManagerTest, getVirtualFileSetsTheDirFieldCorrectly) {
80*67e74705SXin Li   const FileEntry *file = manager.getVirtualFile("foo.cpp", 42, 0);
81*67e74705SXin Li   ASSERT_TRUE(file != nullptr);
82*67e74705SXin Li 
83*67e74705SXin Li   const DirectoryEntry *dir = file->getDir();
84*67e74705SXin Li   ASSERT_TRUE(dir != nullptr);
85*67e74705SXin Li   EXPECT_STREQ(".", dir->getName());
86*67e74705SXin Li 
87*67e74705SXin Li   file = manager.getVirtualFile("x/y/z.cpp", 42, 0);
88*67e74705SXin Li   ASSERT_TRUE(file != nullptr);
89*67e74705SXin Li 
90*67e74705SXin Li   dir = file->getDir();
91*67e74705SXin Li   ASSERT_TRUE(dir != nullptr);
92*67e74705SXin Li   EXPECT_STREQ("x/y", dir->getName());
93*67e74705SXin Li }
94*67e74705SXin Li 
95*67e74705SXin Li // Before any virtual file is added, no virtual directory exists.
TEST_F(FileManagerTest,NoVirtualDirectoryExistsBeforeAVirtualFileIsAdded)96*67e74705SXin Li TEST_F(FileManagerTest, NoVirtualDirectoryExistsBeforeAVirtualFileIsAdded) {
97*67e74705SXin Li   // An empty FakeStatCache causes all stat calls made by the
98*67e74705SXin Li   // FileManager to report "file/directory doesn't exist".  This
99*67e74705SXin Li   // avoids the possibility of the result of this test being affected
100*67e74705SXin Li   // by what's in the real file system.
101*67e74705SXin Li   manager.addStatCache(llvm::make_unique<FakeStatCache>());
102*67e74705SXin Li 
103*67e74705SXin Li   EXPECT_EQ(nullptr, manager.getDirectory("virtual/dir/foo"));
104*67e74705SXin Li   EXPECT_EQ(nullptr, manager.getDirectory("virtual/dir"));
105*67e74705SXin Li   EXPECT_EQ(nullptr, manager.getDirectory("virtual"));
106*67e74705SXin Li }
107*67e74705SXin Li 
108*67e74705SXin Li // When a virtual file is added, all of its ancestors should be created.
TEST_F(FileManagerTest,getVirtualFileCreatesDirectoryEntriesForAncestors)109*67e74705SXin Li TEST_F(FileManagerTest, getVirtualFileCreatesDirectoryEntriesForAncestors) {
110*67e74705SXin Li   // Fake an empty real file system.
111*67e74705SXin Li   manager.addStatCache(llvm::make_unique<FakeStatCache>());
112*67e74705SXin Li 
113*67e74705SXin Li   manager.getVirtualFile("virtual/dir/bar.h", 100, 0);
114*67e74705SXin Li   EXPECT_EQ(nullptr, manager.getDirectory("virtual/dir/foo"));
115*67e74705SXin Li 
116*67e74705SXin Li   const DirectoryEntry *dir = manager.getDirectory("virtual/dir");
117*67e74705SXin Li   ASSERT_TRUE(dir != nullptr);
118*67e74705SXin Li   EXPECT_STREQ("virtual/dir", dir->getName());
119*67e74705SXin Li 
120*67e74705SXin Li   dir = manager.getDirectory("virtual");
121*67e74705SXin Li   ASSERT_TRUE(dir != nullptr);
122*67e74705SXin Li   EXPECT_STREQ("virtual", dir->getName());
123*67e74705SXin Li }
124*67e74705SXin Li 
125*67e74705SXin Li // getFile() returns non-NULL if a real file exists at the given path.
TEST_F(FileManagerTest,getFileReturnsValidFileEntryForExistingRealFile)126*67e74705SXin Li TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingRealFile) {
127*67e74705SXin Li   // Inject fake files into the file system.
128*67e74705SXin Li   auto statCache = llvm::make_unique<FakeStatCache>();
129*67e74705SXin Li   statCache->InjectDirectory("/tmp", 42);
130*67e74705SXin Li   statCache->InjectFile("/tmp/test", 43);
131*67e74705SXin Li 
132*67e74705SXin Li #ifdef LLVM_ON_WIN32
133*67e74705SXin Li   const char *DirName = "C:.";
134*67e74705SXin Li   const char *FileName = "C:test";
135*67e74705SXin Li   statCache->InjectDirectory(DirName, 44);
136*67e74705SXin Li   statCache->InjectFile(FileName, 45);
137*67e74705SXin Li #endif
138*67e74705SXin Li 
139*67e74705SXin Li   manager.addStatCache(std::move(statCache));
140*67e74705SXin Li 
141*67e74705SXin Li   const FileEntry *file = manager.getFile("/tmp/test");
142*67e74705SXin Li   ASSERT_TRUE(file != nullptr);
143*67e74705SXin Li   EXPECT_STREQ("/tmp/test", file->getName());
144*67e74705SXin Li 
145*67e74705SXin Li   const DirectoryEntry *dir = file->getDir();
146*67e74705SXin Li   ASSERT_TRUE(dir != nullptr);
147*67e74705SXin Li   EXPECT_STREQ("/tmp", dir->getName());
148*67e74705SXin Li 
149*67e74705SXin Li #ifdef LLVM_ON_WIN32
150*67e74705SXin Li   file = manager.getFile(FileName);
151*67e74705SXin Li   ASSERT_TRUE(file != NULL);
152*67e74705SXin Li 
153*67e74705SXin Li   dir = file->getDir();
154*67e74705SXin Li   ASSERT_TRUE(dir != NULL);
155*67e74705SXin Li   EXPECT_STREQ(DirName, dir->getName());
156*67e74705SXin Li #endif
157*67e74705SXin Li }
158*67e74705SXin Li 
159*67e74705SXin Li // getFile() returns non-NULL if a virtual file exists at the given path.
TEST_F(FileManagerTest,getFileReturnsValidFileEntryForExistingVirtualFile)160*67e74705SXin Li TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingVirtualFile) {
161*67e74705SXin Li   // Fake an empty real file system.
162*67e74705SXin Li   manager.addStatCache(llvm::make_unique<FakeStatCache>());
163*67e74705SXin Li 
164*67e74705SXin Li   manager.getVirtualFile("virtual/dir/bar.h", 100, 0);
165*67e74705SXin Li   const FileEntry *file = manager.getFile("virtual/dir/bar.h");
166*67e74705SXin Li   ASSERT_TRUE(file != nullptr);
167*67e74705SXin Li   EXPECT_STREQ("virtual/dir/bar.h", file->getName());
168*67e74705SXin Li 
169*67e74705SXin Li   const DirectoryEntry *dir = file->getDir();
170*67e74705SXin Li   ASSERT_TRUE(dir != nullptr);
171*67e74705SXin Li   EXPECT_STREQ("virtual/dir", dir->getName());
172*67e74705SXin Li }
173*67e74705SXin Li 
174*67e74705SXin Li // getFile() returns different FileEntries for different paths when
175*67e74705SXin Li // there's no aliasing.
TEST_F(FileManagerTest,getFileReturnsDifferentFileEntriesForDifferentFiles)176*67e74705SXin Li TEST_F(FileManagerTest, getFileReturnsDifferentFileEntriesForDifferentFiles) {
177*67e74705SXin Li   // Inject two fake files into the file system.  Different inodes
178*67e74705SXin Li   // mean the files are not symlinked together.
179*67e74705SXin Li   auto statCache = llvm::make_unique<FakeStatCache>();
180*67e74705SXin Li   statCache->InjectDirectory(".", 41);
181*67e74705SXin Li   statCache->InjectFile("foo.cpp", 42);
182*67e74705SXin Li   statCache->InjectFile("bar.cpp", 43);
183*67e74705SXin Li   manager.addStatCache(std::move(statCache));
184*67e74705SXin Li 
185*67e74705SXin Li   const FileEntry *fileFoo = manager.getFile("foo.cpp");
186*67e74705SXin Li   const FileEntry *fileBar = manager.getFile("bar.cpp");
187*67e74705SXin Li   ASSERT_TRUE(fileFoo != nullptr);
188*67e74705SXin Li   ASSERT_TRUE(fileBar != nullptr);
189*67e74705SXin Li   EXPECT_NE(fileFoo, fileBar);
190*67e74705SXin Li }
191*67e74705SXin Li 
192*67e74705SXin Li // getFile() returns NULL if neither a real file nor a virtual file
193*67e74705SXin Li // exists at the given path.
TEST_F(FileManagerTest,getFileReturnsNULLForNonexistentFile)194*67e74705SXin Li TEST_F(FileManagerTest, getFileReturnsNULLForNonexistentFile) {
195*67e74705SXin Li   // Inject a fake foo.cpp into the file system.
196*67e74705SXin Li   auto statCache = llvm::make_unique<FakeStatCache>();
197*67e74705SXin Li   statCache->InjectDirectory(".", 41);
198*67e74705SXin Li   statCache->InjectFile("foo.cpp", 42);
199*67e74705SXin Li   manager.addStatCache(std::move(statCache));
200*67e74705SXin Li 
201*67e74705SXin Li   // Create a virtual bar.cpp file.
202*67e74705SXin Li   manager.getVirtualFile("bar.cpp", 200, 0);
203*67e74705SXin Li 
204*67e74705SXin Li   const FileEntry *file = manager.getFile("xyz.txt");
205*67e74705SXin Li   EXPECT_EQ(nullptr, file);
206*67e74705SXin Li }
207*67e74705SXin Li 
208*67e74705SXin Li // The following tests apply to Unix-like system only.
209*67e74705SXin Li 
210*67e74705SXin Li #ifndef LLVM_ON_WIN32
211*67e74705SXin Li 
212*67e74705SXin Li // getFile() returns the same FileEntry for real files that are aliases.
TEST_F(FileManagerTest,getFileReturnsSameFileEntryForAliasedRealFiles)213*67e74705SXin Li TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedRealFiles) {
214*67e74705SXin Li   // Inject two real files with the same inode.
215*67e74705SXin Li   auto statCache = llvm::make_unique<FakeStatCache>();
216*67e74705SXin Li   statCache->InjectDirectory("abc", 41);
217*67e74705SXin Li   statCache->InjectFile("abc/foo.cpp", 42);
218*67e74705SXin Li   statCache->InjectFile("abc/bar.cpp", 42);
219*67e74705SXin Li   manager.addStatCache(std::move(statCache));
220*67e74705SXin Li 
221*67e74705SXin Li   EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp"));
222*67e74705SXin Li }
223*67e74705SXin Li 
224*67e74705SXin Li // getFile() returns the same FileEntry for virtual files that have
225*67e74705SXin Li // corresponding real files that are aliases.
TEST_F(FileManagerTest,getFileReturnsSameFileEntryForAliasedVirtualFiles)226*67e74705SXin Li TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedVirtualFiles) {
227*67e74705SXin Li   // Inject two real files with the same inode.
228*67e74705SXin Li   auto statCache = llvm::make_unique<FakeStatCache>();
229*67e74705SXin Li   statCache->InjectDirectory("abc", 41);
230*67e74705SXin Li   statCache->InjectFile("abc/foo.cpp", 42);
231*67e74705SXin Li   statCache->InjectFile("abc/bar.cpp", 42);
232*67e74705SXin Li   manager.addStatCache(std::move(statCache));
233*67e74705SXin Li 
234*67e74705SXin Li   manager.getVirtualFile("abc/foo.cpp", 100, 0);
235*67e74705SXin Li   manager.getVirtualFile("abc/bar.cpp", 200, 0);
236*67e74705SXin Li 
237*67e74705SXin Li   EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp"));
238*67e74705SXin Li }
239*67e74705SXin Li 
TEST_F(FileManagerTest,addRemoveStatCache)240*67e74705SXin Li TEST_F(FileManagerTest, addRemoveStatCache) {
241*67e74705SXin Li   manager.addStatCache(llvm::make_unique<FakeStatCache>());
242*67e74705SXin Li   auto statCacheOwner = llvm::make_unique<FakeStatCache>();
243*67e74705SXin Li   auto *statCache = statCacheOwner.get();
244*67e74705SXin Li   manager.addStatCache(std::move(statCacheOwner));
245*67e74705SXin Li   manager.addStatCache(llvm::make_unique<FakeStatCache>());
246*67e74705SXin Li   manager.removeStatCache(statCache);
247*67e74705SXin Li }
248*67e74705SXin Li 
249*67e74705SXin Li #endif  // !LLVM_ON_WIN32
250*67e74705SXin Li 
251*67e74705SXin Li } // anonymous namespace
252