blob: d86c96f5a2ce02bfd630677ab4cc6064d834048a [file] [log] [blame]
Zhanyong Wan483651c2011-02-15 21:30:27 +00001//===- unittests/Basic/FileMangerTest.cpp ------------ FileManger tests ---===//
Zhanyong Wan9b555ea2011-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 Carruth1050e8b2012-12-04 09:45:34 +000010#include "clang/Basic/FileManager.h"
Zhanyong Wan9b555ea2011-02-11 18:44:49 +000011#include "clang/Basic/FileSystemOptions.h"
12#include "clang/Basic/FileSystemStatCache.h"
Zhanyong Wan9b555ea2011-02-11 18:44:49 +000013#include "gtest/gtest.h"
14
15using namespace llvm;
16using namespace clang;
17
18namespace {
19
20// Used to create a fake file system for running the tests with such
21// that the tests are not affected by the structure/contents of the
22// file system on the machine running the tests.
23class FakeStatCache : public FileSystemStatCache {
24private:
25 // Maps a file/directory path to its desired stat result. Anything
26 // not in this map is considered to not exist in the file system.
27 llvm::StringMap<struct stat, llvm::BumpPtrAllocator> StatCalls;
28
29 void InjectFileOrDirectory(const char *Path, ino_t INode, bool IsFile) {
NAKAMURA Takumid01fb362011-09-23 01:53:05 +000030 struct stat statBuf;
31 memset(&statBuf, 0, sizeof(statBuf));
Zhanyong Wan9b555ea2011-02-11 18:44:49 +000032 statBuf.st_dev = 1;
NAKAMURA Takumi8e27eb72011-06-24 14:10:29 +000033#ifndef _WIN32 // struct stat has no st_ino field on Windows.
Zhanyong Wan9b555ea2011-02-11 18:44:49 +000034 statBuf.st_ino = INode;
35#endif
36 statBuf.st_mode = IsFile ? (0777 | S_IFREG) // a regular file
37 : (0777 | S_IFDIR); // a directory
38 StatCalls[Path] = statBuf;
39 }
40
41public:
42 // Inject a file with the given inode value to the fake file system.
43 void InjectFile(const char *Path, ino_t INode) {
44 InjectFileOrDirectory(Path, INode, /*IsFile=*/true);
45 }
46
47 // Inject a directory with the given inode value to the fake file system.
48 void InjectDirectory(const char *Path, ino_t INode) {
49 InjectFileOrDirectory(Path, INode, /*IsFile=*/false);
50 }
51
52 // Implement FileSystemStatCache::getStat().
53 virtual LookupResult getStat(const char *Path, struct stat &StatBuf,
Argyrios Kyrtzidise5d30e32012-12-11 07:48:23 +000054 bool isFile, int *FileDescriptor) {
Zhanyong Wan9b555ea2011-02-11 18:44:49 +000055 if (StatCalls.count(Path) != 0) {
56 StatBuf = StatCalls[Path];
57 return CacheExists;
58 }
59
60 return CacheMissing; // This means the file/directory doesn't exist.
61 }
62};
63
64// The test fixture.
65class FileManagerTest : public ::testing::Test {
66 protected:
67 FileManagerTest() : manager(options) {
68 }
69
70 FileSystemOptions options;
71 FileManager manager;
72};
73
74// When a virtual file is added, its getDir() field is set correctly
75// (not NULL, correct name).
76TEST_F(FileManagerTest, getVirtualFileSetsTheDirFieldCorrectly) {
77 const FileEntry *file = manager.getVirtualFile("foo.cpp", 42, 0);
78 ASSERT_TRUE(file != NULL);
79
80 const DirectoryEntry *dir = file->getDir();
81 ASSERT_TRUE(dir != NULL);
82 EXPECT_STREQ(".", dir->getName());
83
84 file = manager.getVirtualFile("x/y/z.cpp", 42, 0);
85 ASSERT_TRUE(file != NULL);
86
87 dir = file->getDir();
88 ASSERT_TRUE(dir != NULL);
89 EXPECT_STREQ("x/y", dir->getName());
90}
91
92// Before any virtual file is added, no virtual directory exists.
93TEST_F(FileManagerTest, NoVirtualDirectoryExistsBeforeAVirtualFileIsAdded) {
94 // An empty FakeStatCache causes all stat calls made by the
95 // FileManager to report "file/directory doesn't exist". This
96 // avoids the possibility of the result of this test being affected
97 // by what's in the real file system.
98 manager.addStatCache(new FakeStatCache);
99
100 EXPECT_EQ(NULL, manager.getDirectory("virtual/dir/foo"));
101 EXPECT_EQ(NULL, manager.getDirectory("virtual/dir"));
102 EXPECT_EQ(NULL, manager.getDirectory("virtual"));
103}
104
105// When a virtual file is added, all of its ancestors should be created.
106TEST_F(FileManagerTest, getVirtualFileCreatesDirectoryEntriesForAncestors) {
107 // Fake an empty real file system.
108 manager.addStatCache(new FakeStatCache);
109
110 manager.getVirtualFile("virtual/dir/bar.h", 100, 0);
111 EXPECT_EQ(NULL, manager.getDirectory("virtual/dir/foo"));
112
113 const DirectoryEntry *dir = manager.getDirectory("virtual/dir");
114 ASSERT_TRUE(dir != NULL);
115 EXPECT_STREQ("virtual/dir", dir->getName());
116
117 dir = manager.getDirectory("virtual");
118 ASSERT_TRUE(dir != NULL);
119 EXPECT_STREQ("virtual", dir->getName());
120}
121
122// getFile() returns non-NULL if a real file exists at the given path.
123TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingRealFile) {
124 // Inject fake files into the file system.
125 FakeStatCache *statCache = new FakeStatCache;
126 statCache->InjectDirectory("/tmp", 42);
127 statCache->InjectFile("/tmp/test", 43);
Rafael Espindola146d57f2013-07-29 15:47:24 +0000128
129#ifdef _WIN32
130 const char *DirName = "C:.";
131 const char *FileName = "C:test";
132 statCache->InjectDirectory(DirName, 44);
133 statCache->InjectFile(FileName, 45);
134#endif
135
Zhanyong Wan9b555ea2011-02-11 18:44:49 +0000136 manager.addStatCache(statCache);
137
138 const FileEntry *file = manager.getFile("/tmp/test");
139 ASSERT_TRUE(file != NULL);
140 EXPECT_STREQ("/tmp/test", file->getName());
141
142 const DirectoryEntry *dir = file->getDir();
143 ASSERT_TRUE(dir != NULL);
144 EXPECT_STREQ("/tmp", dir->getName());
Rafael Espindola146d57f2013-07-29 15:47:24 +0000145
146#ifdef _WIN32
147 file = manager.getFile(FileName);
148 ASSERT_TRUE(file != NULL);
149
150 dir = file->getDir();
151 ASSERT_TRUE(dir != NULL);
152 EXPECT_STREQ(DirName, dir->getName());
153#endif
Zhanyong Wan9b555ea2011-02-11 18:44:49 +0000154}
155
156// getFile() returns non-NULL if a virtual file exists at the given path.
157TEST_F(FileManagerTest, getFileReturnsValidFileEntryForExistingVirtualFile) {
158 // Fake an empty real file system.
159 manager.addStatCache(new FakeStatCache);
160
161 manager.getVirtualFile("virtual/dir/bar.h", 100, 0);
162 const FileEntry *file = manager.getFile("virtual/dir/bar.h");
163 ASSERT_TRUE(file != NULL);
164 EXPECT_STREQ("virtual/dir/bar.h", file->getName());
165
166 const DirectoryEntry *dir = file->getDir();
167 ASSERT_TRUE(dir != NULL);
168 EXPECT_STREQ("virtual/dir", dir->getName());
169}
170
171// getFile() returns different FileEntries for different paths when
172// there's no aliasing.
173TEST_F(FileManagerTest, getFileReturnsDifferentFileEntriesForDifferentFiles) {
174 // Inject two fake files into the file system. Different inodes
175 // mean the files are not symlinked together.
176 FakeStatCache *statCache = new FakeStatCache;
177 statCache->InjectDirectory(".", 41);
178 statCache->InjectFile("foo.cpp", 42);
179 statCache->InjectFile("bar.cpp", 43);
180 manager.addStatCache(statCache);
181
182 const FileEntry *fileFoo = manager.getFile("foo.cpp");
183 const FileEntry *fileBar = manager.getFile("bar.cpp");
184 ASSERT_TRUE(fileFoo != NULL);
185 ASSERT_TRUE(fileBar != NULL);
186 EXPECT_NE(fileFoo, fileBar);
187}
188
189// getFile() returns NULL if neither a real file nor a virtual file
190// exists at the given path.
191TEST_F(FileManagerTest, getFileReturnsNULLForNonexistentFile) {
192 // Inject a fake foo.cpp into the file system.
193 FakeStatCache *statCache = new FakeStatCache;
194 statCache->InjectDirectory(".", 41);
195 statCache->InjectFile("foo.cpp", 42);
196 manager.addStatCache(statCache);
197
198 // Create a virtual bar.cpp file.
199 manager.getVirtualFile("bar.cpp", 200, 0);
200
201 const FileEntry *file = manager.getFile("xyz.txt");
202 EXPECT_EQ(NULL, file);
203}
204
205// The following tests apply to Unix-like system only.
206
NAKAMURA Takumi8e27eb72011-06-24 14:10:29 +0000207#ifndef _WIN32
Zhanyong Wan9b555ea2011-02-11 18:44:49 +0000208
209// getFile() returns the same FileEntry for real files that are aliases.
210TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedRealFiles) {
211 // Inject two real files with the same inode.
212 FakeStatCache *statCache = new FakeStatCache;
213 statCache->InjectDirectory("abc", 41);
214 statCache->InjectFile("abc/foo.cpp", 42);
215 statCache->InjectFile("abc/bar.cpp", 42);
216 manager.addStatCache(statCache);
217
218 EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp"));
219}
220
221// getFile() returns the same FileEntry for virtual files that have
222// corresponding real files that are aliases.
223TEST_F(FileManagerTest, getFileReturnsSameFileEntryForAliasedVirtualFiles) {
224 // Inject two real files with the same inode.
225 FakeStatCache *statCache = new FakeStatCache;
226 statCache->InjectDirectory("abc", 41);
227 statCache->InjectFile("abc/foo.cpp", 42);
228 statCache->InjectFile("abc/bar.cpp", 42);
229 manager.addStatCache(statCache);
230
231 manager.getVirtualFile("abc/foo.cpp", 100, 0);
232 manager.getVirtualFile("abc/bar.cpp", 200, 0);
233
234 EXPECT_EQ(manager.getFile("abc/foo.cpp"), manager.getFile("abc/bar.cpp"));
235}
236
NAKAMURA Takumi8e27eb72011-06-24 14:10:29 +0000237#endif // !_WIN32
Zhanyong Wan9b555ea2011-02-11 18:44:49 +0000238
239} // anonymous namespace