blob: 5aa1c0241a7436c83673c2f5368247e8a7f37448 [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"
Erik Verbruggendfffaf52017-03-28 09:18:05 +000015#include "llvm/Support/Path.h"
Chandler Carruth575bc3ba2015-01-14 11:23:58 +000016#include "gtest/gtest.h"
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000017
18using namespace llvm;
19using namespace clang;
20
21namespace {
22
23// Used to create a fake file system for running the tests with such
24// that the tests are not affected by the structure/contents of the
25// file system on the machine running the tests.
26class FakeStatCache : public FileSystemStatCache {
27private:
28 // Maps a file/directory path to its desired stat result. Anything
29 // not in this map is considered to not exist in the file system.
Rafael Espindolaf8f91b82013-08-01 21:42:11 +000030 llvm::StringMap<FileData, llvm::BumpPtrAllocator> StatCalls;
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000031
32 void InjectFileOrDirectory(const char *Path, ino_t INode, bool IsFile) {
Nico Weber1865df42018-04-27 19:11:14 +000033#ifndef _WIN32
Erik Verbruggendfffaf52017-03-28 09:18:05 +000034 SmallString<128> NormalizedPath(Path);
35 llvm::sys::path::native(NormalizedPath);
36 Path = NormalizedPath.c_str();
37#endif
38
Rafael Espindolaf8f91b82013-08-01 21:42:11 +000039 FileData Data;
Ben Langmuird066d4c2014-02-28 21:16:07 +000040 Data.Name = Path;
41 Data.Size = 0;
42 Data.ModTime = 0;
43 Data.UniqueID = llvm::sys::fs::UniqueID(1, INode);
Rafael Espindolaf8f91b82013-08-01 21:42:11 +000044 Data.IsDirectory = !IsFile;
Ben Langmuird066d4c2014-02-28 21:16:07 +000045 Data.IsNamedPipe = false;
46 Data.InPCH = false;
Rafael Espindolaf8f91b82013-08-01 21:42:11 +000047 StatCalls[Path] = Data;
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000048 }
49
50public:
51 // Inject a file with the given inode value to the fake file system.
52 void InjectFile(const char *Path, ino_t INode) {
53 InjectFileOrDirectory(Path, INode, /*IsFile=*/true);
54 }
55
56 // Inject a directory with the given inode value to the fake file system.
57 void InjectDirectory(const char *Path, ino_t INode) {
58 InjectFileOrDirectory(Path, INode, /*IsFile=*/false);
59 }
60
61 // Implement FileSystemStatCache::getStat().
Mehdi Amini0df59d82016-10-11 07:31:29 +000062 LookupResult getStat(StringRef Path, FileData &Data, bool isFile,
Benjamin Kramer46741752014-07-08 16:07:39 +000063 std::unique_ptr<vfs::File> *F,
64 vfs::FileSystem &FS) override {
Nico Weber1865df42018-04-27 19:11:14 +000065#ifndef _WIN32
Erik Verbruggendfffaf52017-03-28 09:18:05 +000066 SmallString<128> NormalizedPath(Path);
67 llvm::sys::path::native(NormalizedPath);
68 Path = NormalizedPath.c_str();
69#endif
70
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000071 if (StatCalls.count(Path) != 0) {
Rafael Espindolaf8f91b82013-08-01 21:42:11 +000072 Data = StatCalls[Path];
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000073 return CacheExists;
74 }
75
76 return CacheMissing; // This means the file/directory doesn't exist.
77 }
78};
79
80// The test fixture.
81class FileManagerTest : public ::testing::Test {
82 protected:
83 FileManagerTest() : manager(options) {
84 }
85
86 FileSystemOptions options;
87 FileManager manager;
88};
89
90// When a virtual file is added, its getDir() field is set correctly
91// (not NULL, correct name).
92TEST_F(FileManagerTest, getVirtualFileSetsTheDirFieldCorrectly) {
93 const FileEntry *file = manager.getVirtualFile("foo.cpp", 42, 0);
Craig Topper416fa342014-06-08 08:38:12 +000094 ASSERT_TRUE(file != nullptr);
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000095
96 const DirectoryEntry *dir = file->getDir();
Craig Topper416fa342014-06-08 08:38:12 +000097 ASSERT_TRUE(dir != nullptr);
Mehdi Amini0df59d82016-10-11 07:31:29 +000098 EXPECT_EQ(".", dir->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000099
100 file = manager.getVirtualFile("x/y/z.cpp", 42, 0);
Craig Topper416fa342014-06-08 08:38:12 +0000101 ASSERT_TRUE(file != nullptr);
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000102
103 dir = file->getDir();
Craig Topper416fa342014-06-08 08:38:12 +0000104 ASSERT_TRUE(dir != nullptr);
Mehdi Amini0df59d82016-10-11 07:31:29 +0000105 EXPECT_EQ("x/y", dir->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000106}
107
108// Before any virtual file is added, no virtual directory exists.
109TEST_F(FileManagerTest, NoVirtualDirectoryExistsBeforeAVirtualFileIsAdded) {
110 // An empty FakeStatCache causes all stat calls made by the
111 // FileManager to report "file/directory doesn't exist". This
112 // avoids the possibility of the result of this test being affected
113 // by what's in the real file system.
David Blaikie23430cc2014-08-11 21:29:24 +0000114 manager.addStatCache(llvm::make_unique<FakeStatCache>());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000115
Craig Topper416fa342014-06-08 08:38:12 +0000116 EXPECT_EQ(nullptr, manager.getDirectory("virtual/dir/foo"));
117 EXPECT_EQ(nullptr, manager.getDirectory("virtual/dir"));
118 EXPECT_EQ(nullptr, manager.getDirectory("virtual"));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000119}
120
121// When a virtual file is added, all of its ancestors should be created.
122TEST_F(FileManagerTest, getVirtualFileCreatesDirectoryEntriesForAncestors) {
123 // Fake an empty real file system.
David Blaikie23430cc2014-08-11 21:29:24 +0000124 manager.addStatCache(llvm::make_unique<FakeStatCache>());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000125
126 manager.getVirtualFile("virtual/dir/bar.h", 100, 0);
Craig Topper416fa342014-06-08 08:38:12 +0000127 EXPECT_EQ(nullptr, manager.getDirectory("virtual/dir/foo"));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000128
129 const DirectoryEntry *dir = manager.getDirectory("virtual/dir");
Craig Topper416fa342014-06-08 08:38:12 +0000130 ASSERT_TRUE(dir != nullptr);
Mehdi Amini0df59d82016-10-11 07:31:29 +0000131 EXPECT_EQ("virtual/dir", dir->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000132
133 dir = manager.getDirectory("virtual");
Craig Topper416fa342014-06-08 08:38:12 +0000134 ASSERT_TRUE(dir != nullptr);
Mehdi Amini0df59d82016-10-11 07:31:29 +0000135 EXPECT_EQ("virtual", dir->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000136}
137
138// getFile() returns non-NULL if a real file exists at the given path.
139TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingRealFile) {
140 // Inject fake files into the file system.
David Blaikie23430cc2014-08-11 21:29:24 +0000141 auto statCache = llvm::make_unique<FakeStatCache>();
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000142 statCache->InjectDirectory("/tmp", 42);
143 statCache->InjectFile("/tmp/test", 43);
Rafael Espindolaee305462013-07-29 15:47:24 +0000144
Nico Weber1865df42018-04-27 19:11:14 +0000145#ifdef _WIN32
Rafael Espindolaee305462013-07-29 15:47:24 +0000146 const char *DirName = "C:.";
147 const char *FileName = "C:test";
148 statCache->InjectDirectory(DirName, 44);
149 statCache->InjectFile(FileName, 45);
150#endif
151
David Blaikie23430cc2014-08-11 21:29:24 +0000152 manager.addStatCache(std::move(statCache));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000153
154 const FileEntry *file = manager.getFile("/tmp/test");
Craig Topper416fa342014-06-08 08:38:12 +0000155 ASSERT_TRUE(file != nullptr);
Erik Verbruggendfffaf52017-03-28 09:18:05 +0000156 ASSERT_TRUE(file->isValid());
Mehdi Amini004b9c72016-10-10 22:52:47 +0000157 EXPECT_EQ("/tmp/test", file->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000158
159 const DirectoryEntry *dir = file->getDir();
Craig Topper416fa342014-06-08 08:38:12 +0000160 ASSERT_TRUE(dir != nullptr);
Mehdi Amini0df59d82016-10-11 07:31:29 +0000161 EXPECT_EQ("/tmp", dir->getName());
Rafael Espindolaee305462013-07-29 15:47:24 +0000162
Nico Weber1865df42018-04-27 19:11:14 +0000163#ifdef _WIN32
Rafael Espindolaee305462013-07-29 15:47:24 +0000164 file = manager.getFile(FileName);
165 ASSERT_TRUE(file != NULL);
166
167 dir = file->getDir();
168 ASSERT_TRUE(dir != NULL);
Mehdi Amini0df59d82016-10-11 07:31:29 +0000169 EXPECT_EQ(DirName, dir->getName());
Rafael Espindolaee305462013-07-29 15:47:24 +0000170#endif
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000171}
172
173// getFile() returns non-NULL if a virtual file exists at the given path.
174TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingVirtualFile) {
175 // Fake an empty real file system.
David Blaikie23430cc2014-08-11 21:29:24 +0000176 manager.addStatCache(llvm::make_unique<FakeStatCache>());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000177
178 manager.getVirtualFile("virtual/dir/bar.h", 100, 0);
179 const FileEntry *file = manager.getFile("virtual/dir/bar.h");
Craig Topper416fa342014-06-08 08:38:12 +0000180 ASSERT_TRUE(file != nullptr);
Erik Verbruggendfffaf52017-03-28 09:18:05 +0000181 ASSERT_TRUE(file->isValid());
Mehdi Amini004b9c72016-10-10 22:52:47 +0000182 EXPECT_EQ("virtual/dir/bar.h", file->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000183
184 const DirectoryEntry *dir = file->getDir();
Craig Topper416fa342014-06-08 08:38:12 +0000185 ASSERT_TRUE(dir != nullptr);
Mehdi Amini0df59d82016-10-11 07:31:29 +0000186 EXPECT_EQ("virtual/dir", dir->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000187}
188
189// getFile() returns different FileEntries for different paths when
190// there's no aliasing.
191TEST_F(FileManagerTest, getFileReturnsDifferentFileEntriesForDifferentFiles) {
192 // Inject two fake files into the file system. Different inodes
193 // mean the files are not symlinked together.
David Blaikie23430cc2014-08-11 21:29:24 +0000194 auto statCache = llvm::make_unique<FakeStatCache>();
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000195 statCache->InjectDirectory(".", 41);
196 statCache->InjectFile("foo.cpp", 42);
197 statCache->InjectFile("bar.cpp", 43);
David Blaikie23430cc2014-08-11 21:29:24 +0000198 manager.addStatCache(std::move(statCache));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000199
200 const FileEntry *fileFoo = manager.getFile("foo.cpp");
201 const FileEntry *fileBar = manager.getFile("bar.cpp");
Craig Topper416fa342014-06-08 08:38:12 +0000202 ASSERT_TRUE(fileFoo != nullptr);
Erik Verbruggendfffaf52017-03-28 09:18:05 +0000203 ASSERT_TRUE(fileFoo->isValid());
Craig Topper416fa342014-06-08 08:38:12 +0000204 ASSERT_TRUE(fileBar != nullptr);
Erik Verbruggendfffaf52017-03-28 09:18:05 +0000205 ASSERT_TRUE(fileBar->isValid());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000206 EXPECT_NE(fileFoo, fileBar);
207}
208
209// getFile() returns NULL if neither a real file nor a virtual file
210// exists at the given path.
211TEST_F(FileManagerTest, getFileReturnsNULLForNonexistentFile) {
212 // Inject a fake foo.cpp into the file system.
David Blaikie23430cc2014-08-11 21:29:24 +0000213 auto statCache = llvm::make_unique<FakeStatCache>();
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000214 statCache->InjectDirectory(".", 41);
215 statCache->InjectFile("foo.cpp", 42);
David Blaikie23430cc2014-08-11 21:29:24 +0000216 manager.addStatCache(std::move(statCache));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000217
218 // Create a virtual bar.cpp file.
219 manager.getVirtualFile("bar.cpp", 200, 0);
220
221 const FileEntry *file = manager.getFile("xyz.txt");
Craig Topper416fa342014-06-08 08:38:12 +0000222 EXPECT_EQ(nullptr, file);
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000223}
224
225// The following tests apply to Unix-like system only.
226
Nico Weber1865df42018-04-27 19:11:14 +0000227#ifndef _WIN32
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000228
229// getFile() returns the same FileEntry for real files that are aliases.
230TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedRealFiles) {
231 // Inject two real files with the same inode.
David Blaikie23430cc2014-08-11 21:29:24 +0000232 auto statCache = llvm::make_unique<FakeStatCache>();
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000233 statCache->InjectDirectory("abc", 41);
234 statCache->InjectFile("abc/foo.cpp", 42);
235 statCache->InjectFile("abc/bar.cpp", 42);
David Blaikie23430cc2014-08-11 21:29:24 +0000236 manager.addStatCache(std::move(statCache));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000237
238 EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp"));
239}
240
241// getFile() returns the same FileEntry for virtual files that have
242// corresponding real files that are aliases.
243TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedVirtualFiles) {
244 // Inject two real files with the same inode.
David Blaikie23430cc2014-08-11 21:29:24 +0000245 auto statCache = llvm::make_unique<FakeStatCache>();
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000246 statCache->InjectDirectory("abc", 41);
247 statCache->InjectFile("abc/foo.cpp", 42);
248 statCache->InjectFile("abc/bar.cpp", 42);
David Blaikie23430cc2014-08-11 21:29:24 +0000249 manager.addStatCache(std::move(statCache));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000250
Erik Verbruggendfffaf52017-03-28 09:18:05 +0000251 ASSERT_TRUE(manager.getVirtualFile("abc/foo.cpp", 100, 0)->isValid());
252 ASSERT_TRUE(manager.getVirtualFile("abc/bar.cpp", 200, 0)->isValid());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000253
254 EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp"));
255}
256
David Blaikie23430cc2014-08-11 21:29:24 +0000257TEST_F(FileManagerTest, addRemoveStatCache) {
258 manager.addStatCache(llvm::make_unique<FakeStatCache>());
259 auto statCacheOwner = llvm::make_unique<FakeStatCache>();
260 auto *statCache = statCacheOwner.get();
261 manager.addStatCache(std::move(statCacheOwner));
262 manager.addStatCache(llvm::make_unique<FakeStatCache>());
263 manager.removeStatCache(statCache);
264}
265
Erik Verbruggendfffaf52017-03-28 09:18:05 +0000266// getFile() Should return the same entry as getVirtualFile if the file actually
267// is a virtual file, even if the name is not exactly the same (but is after
268// normalisation done by the file system, like on Windows). This can be checked
269// here by checkng the size.
270TEST_F(FileManagerTest, getVirtualFileWithDifferentName) {
271 // Inject fake files into the file system.
272 auto statCache = llvm::make_unique<FakeStatCache>();
273 statCache->InjectDirectory("c:\\tmp", 42);
274 statCache->InjectFile("c:\\tmp\\test", 43);
275
276 manager.addStatCache(std::move(statCache));
277
278 // Inject the virtual file:
279 const FileEntry *file1 = manager.getVirtualFile("c:\\tmp\\test", 123, 1);
280 ASSERT_TRUE(file1 != nullptr);
281 ASSERT_TRUE(file1->isValid());
282 EXPECT_EQ(43U, file1->getUniqueID().getFile());
283 EXPECT_EQ(123, file1->getSize());
284
285 // Lookup the virtual file with a different name:
286 const FileEntry *file2 = manager.getFile("c:/tmp/test", 100, 1);
287 ASSERT_TRUE(file2 != nullptr);
288 ASSERT_TRUE(file2->isValid());
289 // Check that it's the same UFE:
290 EXPECT_EQ(file1, file2);
291 EXPECT_EQ(43U, file2->getUniqueID().getFile());
292 // Check that the contents of the UFE are not overwritten by the entry in the
293 // filesystem:
294 EXPECT_EQ(123, file2->getSize());
295}
296
Nico Weber1865df42018-04-27 19:11:14 +0000297#endif // !_WIN32
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000298
Ilya Biryukov47035c02017-08-02 07:25:24 +0000299TEST_F(FileManagerTest, makeAbsoluteUsesVFS) {
300 SmallString<64> CustomWorkingDir;
Nico Weber1865df42018-04-27 19:11:14 +0000301#ifdef _WIN32
Ilya Biryukov47035c02017-08-02 07:25:24 +0000302 CustomWorkingDir = "C:";
303#else
304 CustomWorkingDir = "/";
305#endif
306 llvm::sys::path::append(CustomWorkingDir, "some", "weird", "path");
307
308 auto FS =
309 IntrusiveRefCntPtr<vfs::InMemoryFileSystem>(new vfs::InMemoryFileSystem);
310 // setCurrentworkingdirectory must finish without error.
311 ASSERT_TRUE(!FS->setCurrentWorkingDirectory(CustomWorkingDir));
312
313 FileSystemOptions Opts;
314 FileManager Manager(Opts, FS);
315
316 SmallString<64> Path("a/foo.cpp");
317
318 SmallString<64> ExpectedResult(CustomWorkingDir);
319 llvm::sys::path::append(ExpectedResult, Path);
320
321 ASSERT_TRUE(Manager.makeAbsolutePath(Path));
322 EXPECT_EQ(Path, ExpectedResult);
323}
324
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000325} // anonymous namespace