blob: a2a6c6aebe4b04a5f9960991ace46073d199c26b [file] [log] [blame]
Zhanyong Wanbc402ab2011-02-15 21:30:27 +00001//===- unittests/Basic/FileMangerTest.cpp ------------ FileManger tests ---===//
Zhanyong Wane1dd3e22011-02-11 18:44:49 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Chandler Carruth320d9662012-12-04 09:45:34 +000010#include "clang/Basic/FileManager.h"
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000011#include "clang/Basic/FileSystemOptions.h"
12#include "clang/Basic/FileSystemStatCache.h"
Ilya Biryukov47035c02017-08-02 07:25:24 +000013#include "clang/Basic/VirtualFileSystem.h"
Benjamin Kramer33335df2015-03-01 21:36:40 +000014#include "llvm/ADT/STLExtras.h"
Alp Toker1d257e12014-06-04 03:28:55 +000015#include "llvm/Config/llvm-config.h"
Erik Verbruggendfffaf52017-03-28 09:18:05 +000016#include "llvm/Support/Path.h"
Chandler Carruth575bc3ba2015-01-14 11:23:58 +000017#include "gtest/gtest.h"
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000018
19using namespace llvm;
20using namespace clang;
21
22namespace {
23
24// Used to create a fake file system for running the tests with such
25// that the tests are not affected by the structure/contents of the
26// file system on the machine running the tests.
27class FakeStatCache : public FileSystemStatCache {
28private:
29 // Maps a file/directory path to its desired stat result. Anything
30 // not in this map is considered to not exist in the file system.
Rafael Espindolaf8f91b82013-08-01 21:42:11 +000031 llvm::StringMap<FileData, llvm::BumpPtrAllocator> StatCalls;
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000032
33 void InjectFileOrDirectory(const char *Path, ino_t INode, bool IsFile) {
Erik Verbruggendfffaf52017-03-28 09:18:05 +000034#ifndef LLVM_ON_WIN32
35 SmallString<128> NormalizedPath(Path);
36 llvm::sys::path::native(NormalizedPath);
37 Path = NormalizedPath.c_str();
38#endif
39
Rafael Espindolaf8f91b82013-08-01 21:42:11 +000040 FileData Data;
Ben Langmuird066d4c2014-02-28 21:16:07 +000041 Data.Name = Path;
42 Data.Size = 0;
43 Data.ModTime = 0;
44 Data.UniqueID = llvm::sys::fs::UniqueID(1, INode);
Rafael Espindolaf8f91b82013-08-01 21:42:11 +000045 Data.IsDirectory = !IsFile;
Ben Langmuird066d4c2014-02-28 21:16:07 +000046 Data.IsNamedPipe = false;
47 Data.InPCH = false;
Rafael Espindolaf8f91b82013-08-01 21:42:11 +000048 StatCalls[Path] = Data;
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000049 }
50
51public:
52 // Inject a file with the given inode value to the fake file system.
53 void InjectFile(const char *Path, ino_t INode) {
54 InjectFileOrDirectory(Path, INode, /*IsFile=*/true);
55 }
56
57 // Inject a directory with the given inode value to the fake file system.
58 void InjectDirectory(const char *Path, ino_t INode) {
59 InjectFileOrDirectory(Path, INode, /*IsFile=*/false);
60 }
61
62 // Implement FileSystemStatCache::getStat().
Mehdi Amini0df59d82016-10-11 07:31:29 +000063 LookupResult getStat(StringRef Path, FileData &Data, bool isFile,
Benjamin Kramer46741752014-07-08 16:07:39 +000064 std::unique_ptr<vfs::File> *F,
65 vfs::FileSystem &FS) override {
Erik Verbruggendfffaf52017-03-28 09:18:05 +000066#ifndef LLVM_ON_WIN32
67 SmallString<128> NormalizedPath(Path);
68 llvm::sys::path::native(NormalizedPath);
69 Path = NormalizedPath.c_str();
70#endif
71
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000072 if (StatCalls.count(Path) != 0) {
Rafael Espindolaf8f91b82013-08-01 21:42:11 +000073 Data = StatCalls[Path];
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000074 return CacheExists;
75 }
76
77 return CacheMissing; // This means the file/directory doesn't exist.
78 }
79};
80
81// The test fixture.
82class FileManagerTest : public ::testing::Test {
83 protected:
84 FileManagerTest() : manager(options) {
85 }
86
87 FileSystemOptions options;
88 FileManager manager;
89};
90
91// When a virtual file is added, its getDir() field is set correctly
92// (not NULL, correct name).
93TEST_F(FileManagerTest, getVirtualFileSetsTheDirFieldCorrectly) {
94 const FileEntry *file = manager.getVirtualFile("foo.cpp", 42, 0);
Craig Topper416fa342014-06-08 08:38:12 +000095 ASSERT_TRUE(file != nullptr);
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000096
97 const DirectoryEntry *dir = file->getDir();
Craig Topper416fa342014-06-08 08:38:12 +000098 ASSERT_TRUE(dir != nullptr);
Mehdi Amini0df59d82016-10-11 07:31:29 +000099 EXPECT_EQ(".", dir->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000100
101 file = manager.getVirtualFile("x/y/z.cpp", 42, 0);
Craig Topper416fa342014-06-08 08:38:12 +0000102 ASSERT_TRUE(file != nullptr);
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000103
104 dir = file->getDir();
Craig Topper416fa342014-06-08 08:38:12 +0000105 ASSERT_TRUE(dir != nullptr);
Mehdi Amini0df59d82016-10-11 07:31:29 +0000106 EXPECT_EQ("x/y", dir->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000107}
108
109// Before any virtual file is added, no virtual directory exists.
110TEST_F(FileManagerTest, NoVirtualDirectoryExistsBeforeAVirtualFileIsAdded) {
111 // An empty FakeStatCache causes all stat calls made by the
112 // FileManager to report "file/directory doesn't exist". This
113 // avoids the possibility of the result of this test being affected
114 // by what's in the real file system.
David Blaikie23430cc2014-08-11 21:29:24 +0000115 manager.addStatCache(llvm::make_unique<FakeStatCache>());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000116
Craig Topper416fa342014-06-08 08:38:12 +0000117 EXPECT_EQ(nullptr, manager.getDirectory("virtual/dir/foo"));
118 EXPECT_EQ(nullptr, manager.getDirectory("virtual/dir"));
119 EXPECT_EQ(nullptr, manager.getDirectory("virtual"));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000120}
121
122// When a virtual file is added, all of its ancestors should be created.
123TEST_F(FileManagerTest, getVirtualFileCreatesDirectoryEntriesForAncestors) {
124 // Fake an empty real file system.
David Blaikie23430cc2014-08-11 21:29:24 +0000125 manager.addStatCache(llvm::make_unique<FakeStatCache>());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000126
127 manager.getVirtualFile("virtual/dir/bar.h", 100, 0);
Craig Topper416fa342014-06-08 08:38:12 +0000128 EXPECT_EQ(nullptr, manager.getDirectory("virtual/dir/foo"));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000129
130 const DirectoryEntry *dir = manager.getDirectory("virtual/dir");
Craig Topper416fa342014-06-08 08:38:12 +0000131 ASSERT_TRUE(dir != nullptr);
Mehdi Amini0df59d82016-10-11 07:31:29 +0000132 EXPECT_EQ("virtual/dir", dir->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000133
134 dir = manager.getDirectory("virtual");
Craig Topper416fa342014-06-08 08:38:12 +0000135 ASSERT_TRUE(dir != nullptr);
Mehdi Amini0df59d82016-10-11 07:31:29 +0000136 EXPECT_EQ("virtual", dir->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000137}
138
139// getFile() returns non-NULL if a real file exists at the given path.
140TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingRealFile) {
141 // Inject fake files into the file system.
David Blaikie23430cc2014-08-11 21:29:24 +0000142 auto statCache = llvm::make_unique<FakeStatCache>();
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000143 statCache->InjectDirectory("/tmp", 42);
144 statCache->InjectFile("/tmp/test", 43);
Rafael Espindolaee305462013-07-29 15:47:24 +0000145
Hans Wennborg501eadb2014-03-12 16:07:46 +0000146#ifdef LLVM_ON_WIN32
Rafael Espindolaee305462013-07-29 15:47:24 +0000147 const char *DirName = "C:.";
148 const char *FileName = "C:test";
149 statCache->InjectDirectory(DirName, 44);
150 statCache->InjectFile(FileName, 45);
151#endif
152
David Blaikie23430cc2014-08-11 21:29:24 +0000153 manager.addStatCache(std::move(statCache));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000154
155 const FileEntry *file = manager.getFile("/tmp/test");
Craig Topper416fa342014-06-08 08:38:12 +0000156 ASSERT_TRUE(file != nullptr);
Erik Verbruggendfffaf52017-03-28 09:18:05 +0000157 ASSERT_TRUE(file->isValid());
Mehdi Amini004b9c72016-10-10 22:52:47 +0000158 EXPECT_EQ("/tmp/test", file->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000159
160 const DirectoryEntry *dir = file->getDir();
Craig Topper416fa342014-06-08 08:38:12 +0000161 ASSERT_TRUE(dir != nullptr);
Mehdi Amini0df59d82016-10-11 07:31:29 +0000162 EXPECT_EQ("/tmp", dir->getName());
Rafael Espindolaee305462013-07-29 15:47:24 +0000163
Hans Wennborg501eadb2014-03-12 16:07:46 +0000164#ifdef LLVM_ON_WIN32
Rafael Espindolaee305462013-07-29 15:47:24 +0000165 file = manager.getFile(FileName);
166 ASSERT_TRUE(file != NULL);
167
168 dir = file->getDir();
169 ASSERT_TRUE(dir != NULL);
Mehdi Amini0df59d82016-10-11 07:31:29 +0000170 EXPECT_EQ(DirName, dir->getName());
Rafael Espindolaee305462013-07-29 15:47:24 +0000171#endif
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000172}
173
174// getFile() returns non-NULL if a virtual file exists at the given path.
175TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingVirtualFile) {
176 // Fake an empty real file system.
David Blaikie23430cc2014-08-11 21:29:24 +0000177 manager.addStatCache(llvm::make_unique<FakeStatCache>());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000178
179 manager.getVirtualFile("virtual/dir/bar.h", 100, 0);
180 const FileEntry *file = manager.getFile("virtual/dir/bar.h");
Craig Topper416fa342014-06-08 08:38:12 +0000181 ASSERT_TRUE(file != nullptr);
Erik Verbruggendfffaf52017-03-28 09:18:05 +0000182 ASSERT_TRUE(file->isValid());
Mehdi Amini004b9c72016-10-10 22:52:47 +0000183 EXPECT_EQ("virtual/dir/bar.h", file->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000184
185 const DirectoryEntry *dir = file->getDir();
Craig Topper416fa342014-06-08 08:38:12 +0000186 ASSERT_TRUE(dir != nullptr);
Mehdi Amini0df59d82016-10-11 07:31:29 +0000187 EXPECT_EQ("virtual/dir", dir->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000188}
189
190// getFile() returns different FileEntries for different paths when
191// there's no aliasing.
192TEST_F(FileManagerTest, getFileReturnsDifferentFileEntriesForDifferentFiles) {
193 // Inject two fake files into the file system. Different inodes
194 // mean the files are not symlinked together.
David Blaikie23430cc2014-08-11 21:29:24 +0000195 auto statCache = llvm::make_unique<FakeStatCache>();
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000196 statCache->InjectDirectory(".", 41);
197 statCache->InjectFile("foo.cpp", 42);
198 statCache->InjectFile("bar.cpp", 43);
David Blaikie23430cc2014-08-11 21:29:24 +0000199 manager.addStatCache(std::move(statCache));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000200
201 const FileEntry *fileFoo = manager.getFile("foo.cpp");
202 const FileEntry *fileBar = manager.getFile("bar.cpp");
Craig Topper416fa342014-06-08 08:38:12 +0000203 ASSERT_TRUE(fileFoo != nullptr);
Erik Verbruggendfffaf52017-03-28 09:18:05 +0000204 ASSERT_TRUE(fileFoo->isValid());
Craig Topper416fa342014-06-08 08:38:12 +0000205 ASSERT_TRUE(fileBar != nullptr);
Erik Verbruggendfffaf52017-03-28 09:18:05 +0000206 ASSERT_TRUE(fileBar->isValid());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000207 EXPECT_NE(fileFoo, fileBar);
208}
209
210// getFile() returns NULL if neither a real file nor a virtual file
211// exists at the given path.
212TEST_F(FileManagerTest, getFileReturnsNULLForNonexistentFile) {
213 // Inject a fake foo.cpp into the file system.
David Blaikie23430cc2014-08-11 21:29:24 +0000214 auto statCache = llvm::make_unique<FakeStatCache>();
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000215 statCache->InjectDirectory(".", 41);
216 statCache->InjectFile("foo.cpp", 42);
David Blaikie23430cc2014-08-11 21:29:24 +0000217 manager.addStatCache(std::move(statCache));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000218
219 // Create a virtual bar.cpp file.
220 manager.getVirtualFile("bar.cpp", 200, 0);
221
222 const FileEntry *file = manager.getFile("xyz.txt");
Craig Topper416fa342014-06-08 08:38:12 +0000223 EXPECT_EQ(nullptr, file);
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000224}
225
226// The following tests apply to Unix-like system only.
227
Hans Wennborg501eadb2014-03-12 16:07:46 +0000228#ifndef LLVM_ON_WIN32
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000229
230// getFile() returns the same FileEntry for real files that are aliases.
231TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedRealFiles) {
232 // Inject two real files with the same inode.
David Blaikie23430cc2014-08-11 21:29:24 +0000233 auto statCache = llvm::make_unique<FakeStatCache>();
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000234 statCache->InjectDirectory("abc", 41);
235 statCache->InjectFile("abc/foo.cpp", 42);
236 statCache->InjectFile("abc/bar.cpp", 42);
David Blaikie23430cc2014-08-11 21:29:24 +0000237 manager.addStatCache(std::move(statCache));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000238
239 EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp"));
240}
241
242// getFile() returns the same FileEntry for virtual files that have
243// corresponding real files that are aliases.
244TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedVirtualFiles) {
245 // Inject two real files with the same inode.
David Blaikie23430cc2014-08-11 21:29:24 +0000246 auto statCache = llvm::make_unique<FakeStatCache>();
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000247 statCache->InjectDirectory("abc", 41);
248 statCache->InjectFile("abc/foo.cpp", 42);
249 statCache->InjectFile("abc/bar.cpp", 42);
David Blaikie23430cc2014-08-11 21:29:24 +0000250 manager.addStatCache(std::move(statCache));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000251
Erik Verbruggendfffaf52017-03-28 09:18:05 +0000252 ASSERT_TRUE(manager.getVirtualFile("abc/foo.cpp", 100, 0)->isValid());
253 ASSERT_TRUE(manager.getVirtualFile("abc/bar.cpp", 200, 0)->isValid());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000254
255 EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp"));
256}
257
David Blaikie23430cc2014-08-11 21:29:24 +0000258TEST_F(FileManagerTest, addRemoveStatCache) {
259 manager.addStatCache(llvm::make_unique<FakeStatCache>());
260 auto statCacheOwner = llvm::make_unique<FakeStatCache>();
261 auto *statCache = statCacheOwner.get();
262 manager.addStatCache(std::move(statCacheOwner));
263 manager.addStatCache(llvm::make_unique<FakeStatCache>());
264 manager.removeStatCache(statCache);
265}
266
Erik Verbruggendfffaf52017-03-28 09:18:05 +0000267// getFile() Should return the same entry as getVirtualFile if the file actually
268// is a virtual file, even if the name is not exactly the same (but is after
269// normalisation done by the file system, like on Windows). This can be checked
270// here by checkng the size.
271TEST_F(FileManagerTest, getVirtualFileWithDifferentName) {
272 // Inject fake files into the file system.
273 auto statCache = llvm::make_unique<FakeStatCache>();
274 statCache->InjectDirectory("c:\\tmp", 42);
275 statCache->InjectFile("c:\\tmp\\test", 43);
276
277 manager.addStatCache(std::move(statCache));
278
279 // Inject the virtual file:
280 const FileEntry *file1 = manager.getVirtualFile("c:\\tmp\\test", 123, 1);
281 ASSERT_TRUE(file1 != nullptr);
282 ASSERT_TRUE(file1->isValid());
283 EXPECT_EQ(43U, file1->getUniqueID().getFile());
284 EXPECT_EQ(123, file1->getSize());
285
286 // Lookup the virtual file with a different name:
287 const FileEntry *file2 = manager.getFile("c:/tmp/test", 100, 1);
288 ASSERT_TRUE(file2 != nullptr);
289 ASSERT_TRUE(file2->isValid());
290 // Check that it's the same UFE:
291 EXPECT_EQ(file1, file2);
292 EXPECT_EQ(43U, file2->getUniqueID().getFile());
293 // Check that the contents of the UFE are not overwritten by the entry in the
294 // filesystem:
295 EXPECT_EQ(123, file2->getSize());
296}
297
Hans Wennborg501eadb2014-03-12 16:07:46 +0000298#endif // !LLVM_ON_WIN32
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000299
Ilya Biryukov47035c02017-08-02 07:25:24 +0000300TEST_F(FileManagerTest, makeAbsoluteUsesVFS) {
301 SmallString<64> CustomWorkingDir;
302#ifdef LLVM_ON_WIN32
303 CustomWorkingDir = "C:";
304#else
305 CustomWorkingDir = "/";
306#endif
307 llvm::sys::path::append(CustomWorkingDir, "some", "weird", "path");
308
309 auto FS =
310 IntrusiveRefCntPtr<vfs::InMemoryFileSystem>(new vfs::InMemoryFileSystem);
311 // setCurrentworkingdirectory must finish without error.
312 ASSERT_TRUE(!FS->setCurrentWorkingDirectory(CustomWorkingDir));
313
314 FileSystemOptions Opts;
315 FileManager Manager(Opts, FS);
316
317 SmallString<64> Path("a/foo.cpp");
318
319 SmallString<64> ExpectedResult(CustomWorkingDir);
320 llvm::sys::path::append(ExpectedResult, Path);
321
322 ASSERT_TRUE(Manager.makeAbsolutePath(Path));
323 EXPECT_EQ(Path, ExpectedResult);
324}
325
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000326} // anonymous namespace