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