blob: 4cf21cd8459abc2f255d2d5e5bcec79850ad8953 [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"
Benjamin Kramer33335df2015-03-01 21:36:40 +000013#include "llvm/ADT/STLExtras.h"
Alp Toker1d257e12014-06-04 03:28:55 +000014#include "llvm/Config/llvm-config.h"
Chandler Carruth575bc3ba2015-01-14 11:23:58 +000015#include "gtest/gtest.h"
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000016
17using namespace llvm;
18using namespace clang;
19
20namespace {
21
22// Used to create a fake file system for running the tests with such
23// that the tests are not affected by the structure/contents of the
24// file system on the machine running the tests.
25class FakeStatCache : public FileSystemStatCache {
26private:
27 // Maps a file/directory path to its desired stat result. Anything
28 // not in this map is considered to not exist in the file system.
Rafael Espindolaf8f91b82013-08-01 21:42:11 +000029 llvm::StringMap<FileData, llvm::BumpPtrAllocator> StatCalls;
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000030
31 void InjectFileOrDirectory(const char *Path, ino_t INode, bool IsFile) {
Rafael Espindolaf8f91b82013-08-01 21:42:11 +000032 FileData Data;
Ben Langmuird066d4c2014-02-28 21:16:07 +000033 Data.Name = Path;
34 Data.Size = 0;
35 Data.ModTime = 0;
36 Data.UniqueID = llvm::sys::fs::UniqueID(1, INode);
Rafael Espindolaf8f91b82013-08-01 21:42:11 +000037 Data.IsDirectory = !IsFile;
Ben Langmuird066d4c2014-02-28 21:16:07 +000038 Data.IsNamedPipe = false;
39 Data.InPCH = false;
Rafael Espindolaf8f91b82013-08-01 21:42:11 +000040 StatCalls[Path] = Data;
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000041 }
42
43public:
44 // Inject a file with the given inode value to the fake file system.
45 void InjectFile(const char *Path, ino_t INode) {
46 InjectFileOrDirectory(Path, INode, /*IsFile=*/true);
47 }
48
49 // Inject a directory with the given inode value to the fake file system.
50 void InjectDirectory(const char *Path, ino_t INode) {
51 InjectFileOrDirectory(Path, INode, /*IsFile=*/false);
52 }
53
54 // Implement FileSystemStatCache::getStat().
Mehdi Amini0df59d82016-10-11 07:31:29 +000055 LookupResult getStat(StringRef Path, FileData &Data, bool isFile,
Benjamin Kramer46741752014-07-08 16:07:39 +000056 std::unique_ptr<vfs::File> *F,
57 vfs::FileSystem &FS) override {
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000058 if (StatCalls.count(Path) != 0) {
Rafael Espindolaf8f91b82013-08-01 21:42:11 +000059 Data = StatCalls[Path];
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000060 return CacheExists;
61 }
62
63 return CacheMissing; // This means the file/directory doesn't exist.
64 }
65};
66
67// The test fixture.
68class FileManagerTest : public ::testing::Test {
69 protected:
70 FileManagerTest() : manager(options) {
71 }
72
73 FileSystemOptions options;
74 FileManager manager;
75};
76
77// When a virtual file is added, its getDir() field is set correctly
78// (not NULL, correct name).
79TEST_F(FileManagerTest, getVirtualFileSetsTheDirFieldCorrectly) {
80 const FileEntry *file = manager.getVirtualFile("foo.cpp", 42, 0);
Craig Topper416fa342014-06-08 08:38:12 +000081 ASSERT_TRUE(file != nullptr);
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000082
83 const DirectoryEntry *dir = file->getDir();
Craig Topper416fa342014-06-08 08:38:12 +000084 ASSERT_TRUE(dir != nullptr);
Mehdi Amini0df59d82016-10-11 07:31:29 +000085 EXPECT_EQ(".", dir->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000086
87 file = manager.getVirtualFile("x/y/z.cpp", 42, 0);
Craig Topper416fa342014-06-08 08:38:12 +000088 ASSERT_TRUE(file != nullptr);
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000089
90 dir = file->getDir();
Craig Topper416fa342014-06-08 08:38:12 +000091 ASSERT_TRUE(dir != nullptr);
Mehdi Amini0df59d82016-10-11 07:31:29 +000092 EXPECT_EQ("x/y", dir->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +000093}
94
95// Before any virtual file is added, no virtual directory exists.
96TEST_F(FileManagerTest, NoVirtualDirectoryExistsBeforeAVirtualFileIsAdded) {
97 // An empty FakeStatCache causes all stat calls made by the
98 // FileManager to report "file/directory doesn't exist". This
99 // avoids the possibility of the result of this test being affected
100 // by what's in the real file system.
David Blaikie23430cc2014-08-11 21:29:24 +0000101 manager.addStatCache(llvm::make_unique<FakeStatCache>());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000102
Craig Topper416fa342014-06-08 08:38:12 +0000103 EXPECT_EQ(nullptr, manager.getDirectory("virtual/dir/foo"));
104 EXPECT_EQ(nullptr, manager.getDirectory("virtual/dir"));
105 EXPECT_EQ(nullptr, manager.getDirectory("virtual"));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000106}
107
108// When a virtual file is added, all of its ancestors should be created.
109TEST_F(FileManagerTest, getVirtualFileCreatesDirectoryEntriesForAncestors) {
110 // Fake an empty real file system.
David Blaikie23430cc2014-08-11 21:29:24 +0000111 manager.addStatCache(llvm::make_unique<FakeStatCache>());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000112
113 manager.getVirtualFile("virtual/dir/bar.h", 100, 0);
Craig Topper416fa342014-06-08 08:38:12 +0000114 EXPECT_EQ(nullptr, manager.getDirectory("virtual/dir/foo"));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000115
116 const DirectoryEntry *dir = manager.getDirectory("virtual/dir");
Craig Topper416fa342014-06-08 08:38:12 +0000117 ASSERT_TRUE(dir != nullptr);
Mehdi Amini0df59d82016-10-11 07:31:29 +0000118 EXPECT_EQ("virtual/dir", dir->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000119
120 dir = manager.getDirectory("virtual");
Craig Topper416fa342014-06-08 08:38:12 +0000121 ASSERT_TRUE(dir != nullptr);
Mehdi Amini0df59d82016-10-11 07:31:29 +0000122 EXPECT_EQ("virtual", dir->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000123}
124
125// getFile() returns non-NULL if a real file exists at the given path.
126TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingRealFile) {
127 // Inject fake files into the file system.
David Blaikie23430cc2014-08-11 21:29:24 +0000128 auto statCache = llvm::make_unique<FakeStatCache>();
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000129 statCache->InjectDirectory("/tmp", 42);
130 statCache->InjectFile("/tmp/test", 43);
Rafael Espindolaee305462013-07-29 15:47:24 +0000131
Hans Wennborg501eadb2014-03-12 16:07:46 +0000132#ifdef LLVM_ON_WIN32
Rafael Espindolaee305462013-07-29 15:47:24 +0000133 const char *DirName = "C:.";
134 const char *FileName = "C:test";
135 statCache->InjectDirectory(DirName, 44);
136 statCache->InjectFile(FileName, 45);
137#endif
138
David Blaikie23430cc2014-08-11 21:29:24 +0000139 manager.addStatCache(std::move(statCache));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000140
141 const FileEntry *file = manager.getFile("/tmp/test");
Craig Topper416fa342014-06-08 08:38:12 +0000142 ASSERT_TRUE(file != nullptr);
Mehdi Amini004b9c72016-10-10 22:52:47 +0000143 EXPECT_EQ("/tmp/test", file->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000144
145 const DirectoryEntry *dir = file->getDir();
Craig Topper416fa342014-06-08 08:38:12 +0000146 ASSERT_TRUE(dir != nullptr);
Mehdi Amini0df59d82016-10-11 07:31:29 +0000147 EXPECT_EQ("/tmp", dir->getName());
Rafael Espindolaee305462013-07-29 15:47:24 +0000148
Hans Wennborg501eadb2014-03-12 16:07:46 +0000149#ifdef LLVM_ON_WIN32
Rafael Espindolaee305462013-07-29 15:47:24 +0000150 file = manager.getFile(FileName);
151 ASSERT_TRUE(file != NULL);
152
153 dir = file->getDir();
154 ASSERT_TRUE(dir != NULL);
Mehdi Amini0df59d82016-10-11 07:31:29 +0000155 EXPECT_EQ(DirName, dir->getName());
Rafael Espindolaee305462013-07-29 15:47:24 +0000156#endif
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000157}
158
159// getFile() returns non-NULL if a virtual file exists at the given path.
160TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingVirtualFile) {
161 // Fake an empty real file system.
David Blaikie23430cc2014-08-11 21:29:24 +0000162 manager.addStatCache(llvm::make_unique<FakeStatCache>());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000163
164 manager.getVirtualFile("virtual/dir/bar.h", 100, 0);
165 const FileEntry *file = manager.getFile("virtual/dir/bar.h");
Craig Topper416fa342014-06-08 08:38:12 +0000166 ASSERT_TRUE(file != nullptr);
Mehdi Amini004b9c72016-10-10 22:52:47 +0000167 EXPECT_EQ("virtual/dir/bar.h", file->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000168
169 const DirectoryEntry *dir = file->getDir();
Craig Topper416fa342014-06-08 08:38:12 +0000170 ASSERT_TRUE(dir != nullptr);
Mehdi Amini0df59d82016-10-11 07:31:29 +0000171 EXPECT_EQ("virtual/dir", dir->getName());
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000172}
173
174// getFile() returns different FileEntries for different paths when
175// there's no aliasing.
176TEST_F(FileManagerTest, getFileReturnsDifferentFileEntriesForDifferentFiles) {
177 // Inject two fake files into the file system. Different inodes
178 // mean the files are not symlinked together.
David Blaikie23430cc2014-08-11 21:29:24 +0000179 auto statCache = llvm::make_unique<FakeStatCache>();
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000180 statCache->InjectDirectory(".", 41);
181 statCache->InjectFile("foo.cpp", 42);
182 statCache->InjectFile("bar.cpp", 43);
David Blaikie23430cc2014-08-11 21:29:24 +0000183 manager.addStatCache(std::move(statCache));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000184
185 const FileEntry *fileFoo = manager.getFile("foo.cpp");
186 const FileEntry *fileBar = manager.getFile("bar.cpp");
Craig Topper416fa342014-06-08 08:38:12 +0000187 ASSERT_TRUE(fileFoo != nullptr);
188 ASSERT_TRUE(fileBar != nullptr);
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000189 EXPECT_NE(fileFoo, fileBar);
190}
191
192// getFile() returns NULL if neither a real file nor a virtual file
193// exists at the given path.
194TEST_F(FileManagerTest, getFileReturnsNULLForNonexistentFile) {
195 // Inject a fake foo.cpp into the file system.
David Blaikie23430cc2014-08-11 21:29:24 +0000196 auto statCache = llvm::make_unique<FakeStatCache>();
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000197 statCache->InjectDirectory(".", 41);
198 statCache->InjectFile("foo.cpp", 42);
David Blaikie23430cc2014-08-11 21:29:24 +0000199 manager.addStatCache(std::move(statCache));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000200
201 // Create a virtual bar.cpp file.
202 manager.getVirtualFile("bar.cpp", 200, 0);
203
204 const FileEntry *file = manager.getFile("xyz.txt");
Craig Topper416fa342014-06-08 08:38:12 +0000205 EXPECT_EQ(nullptr, file);
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000206}
207
208// The following tests apply to Unix-like system only.
209
Hans Wennborg501eadb2014-03-12 16:07:46 +0000210#ifndef LLVM_ON_WIN32
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000211
212// getFile() returns the same FileEntry for real files that are aliases.
213TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedRealFiles) {
214 // Inject two real files with the same inode.
David Blaikie23430cc2014-08-11 21:29:24 +0000215 auto statCache = llvm::make_unique<FakeStatCache>();
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000216 statCache->InjectDirectory("abc", 41);
217 statCache->InjectFile("abc/foo.cpp", 42);
218 statCache->InjectFile("abc/bar.cpp", 42);
David Blaikie23430cc2014-08-11 21:29:24 +0000219 manager.addStatCache(std::move(statCache));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000220
221 EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp"));
222}
223
224// getFile() returns the same FileEntry for virtual files that have
225// corresponding real files that are aliases.
226TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedVirtualFiles) {
227 // Inject two real files with the same inode.
David Blaikie23430cc2014-08-11 21:29:24 +0000228 auto statCache = llvm::make_unique<FakeStatCache>();
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000229 statCache->InjectDirectory("abc", 41);
230 statCache->InjectFile("abc/foo.cpp", 42);
231 statCache->InjectFile("abc/bar.cpp", 42);
David Blaikie23430cc2014-08-11 21:29:24 +0000232 manager.addStatCache(std::move(statCache));
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000233
234 manager.getVirtualFile("abc/foo.cpp", 100, 0);
235 manager.getVirtualFile("abc/bar.cpp", 200, 0);
236
237 EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp"));
238}
239
David Blaikie23430cc2014-08-11 21:29:24 +0000240TEST_F(FileManagerTest, addRemoveStatCache) {
241 manager.addStatCache(llvm::make_unique<FakeStatCache>());
242 auto statCacheOwner = llvm::make_unique<FakeStatCache>();
243 auto *statCache = statCacheOwner.get();
244 manager.addStatCache(std::move(statCacheOwner));
245 manager.addStatCache(llvm::make_unique<FakeStatCache>());
246 manager.removeStatCache(statCache);
247}
248
Hans Wennborg501eadb2014-03-12 16:07:46 +0000249#endif // !LLVM_ON_WIN32
Zhanyong Wane1dd3e22011-02-11 18:44:49 +0000250
251} // anonymous namespace