blob: 71d2d2b60c04ce9ea4e4baa1e28bb4883d59ea60 [file] [log] [blame]
Ben Langmuirc8130a72014-02-20 21:59:23 +00001//===- unittests/Basic/VirtualFileSystem.cpp ---------------- VFS tests ---===//
2//
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
10#include "clang/Basic/VirtualFileSystem.h"
Rafael Espindola71de0b62014-06-13 17:20:50 +000011#include "llvm/Support/Errc.h"
Ben Langmuird51ba0b2014-02-21 23:39:37 +000012#include "llvm/Support/MemoryBuffer.h"
Ben Langmuirc8130a72014-02-20 21:59:23 +000013#include "llvm/Support/Path.h"
Ben Langmuird51ba0b2014-02-21 23:39:37 +000014#include "llvm/Support/SourceMgr.h"
Ben Langmuirc8130a72014-02-20 21:59:23 +000015#include "gtest/gtest.h"
16#include <map>
17using namespace clang;
18using namespace llvm;
19using llvm::sys::fs::UniqueID;
20
21namespace {
22class DummyFileSystem : public vfs::FileSystem {
23 int FSID; // used to produce UniqueIDs
24 int FileID; // used to produce UniqueIDs
25 std::map<std::string, vfs::Status> FilesAndDirs;
26
27 static int getNextFSID() {
28 static int Count = 0;
29 return Count++;
30 }
31
32public:
33 DummyFileSystem() : FSID(getNextFSID()), FileID(0) {}
34
Fariborz Jahanian5afc8692014-10-01 16:56:40 +000035 ErrorOr<vfs::Status> status(const Twine &Path) override {
Ben Langmuirc8130a72014-02-20 21:59:23 +000036 std::map<std::string, vfs::Status>::iterator I =
Ben Langmuird51ba0b2014-02-21 23:39:37 +000037 FilesAndDirs.find(Path.str());
Ben Langmuirc8130a72014-02-20 21:59:23 +000038 if (I == FilesAndDirs.end())
Rafael Espindola71de0b62014-06-13 17:20:50 +000039 return make_error_code(llvm::errc::no_such_file_or_directory);
Ben Langmuirc8130a72014-02-20 21:59:23 +000040 return I->second;
41 }
Benjamin Kramera8857962014-10-26 22:44:13 +000042 ErrorOr<std::unique_ptr<vfs::File>>
43 openFileForRead(const Twine &Path) override {
Ben Langmuirc8130a72014-02-20 21:59:23 +000044 llvm_unreachable("unimplemented");
45 }
46
Ben Langmuir740812b2014-06-24 19:37:16 +000047 struct DirIterImpl : public clang::vfs::detail::DirIterImpl {
48 std::map<std::string, vfs::Status> &FilesAndDirs;
49 std::map<std::string, vfs::Status>::iterator I;
50 std::string Path;
Ben Langmuir7c9f6c82014-06-25 20:25:40 +000051 bool isInPath(StringRef S) {
52 if (Path.size() < S.size() && S.find(Path) == 0) {
53 auto LastSep = S.find_last_of('/');
54 if (LastSep == Path.size() || LastSep == Path.size()-1)
55 return true;
56 }
57 return false;
58 }
Ben Langmuir740812b2014-06-24 19:37:16 +000059 DirIterImpl(std::map<std::string, vfs::Status> &FilesAndDirs,
60 const Twine &_Path)
61 : FilesAndDirs(FilesAndDirs), I(FilesAndDirs.begin()),
62 Path(_Path.str()) {
63 for ( ; I != FilesAndDirs.end(); ++I) {
Ben Langmuir7c9f6c82014-06-25 20:25:40 +000064 if (isInPath(I->first)) {
Ben Langmuir740812b2014-06-24 19:37:16 +000065 CurrentEntry = I->second;
66 break;
67 }
68 }
69 }
70 std::error_code increment() override {
71 ++I;
72 for ( ; I != FilesAndDirs.end(); ++I) {
Ben Langmuir7c9f6c82014-06-25 20:25:40 +000073 if (isInPath(I->first)) {
Ben Langmuir740812b2014-06-24 19:37:16 +000074 CurrentEntry = I->second;
75 break;
76 }
77 }
78 if (I == FilesAndDirs.end())
79 CurrentEntry = vfs::Status();
80 return std::error_code();
81 }
82 };
83
84 vfs::directory_iterator dir_begin(const Twine &Dir,
85 std::error_code &EC) override {
86 return vfs::directory_iterator(
87 std::make_shared<DirIterImpl>(FilesAndDirs, Dir));
88 }
89
Ben Langmuirc8130a72014-02-20 21:59:23 +000090 void addEntry(StringRef Path, const vfs::Status &Status) {
91 FilesAndDirs[Path] = Status;
92 }
93
Ben Langmuird51ba0b2014-02-21 23:39:37 +000094 void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
Ben Langmuirc8130a72014-02-20 21:59:23 +000095 vfs::Status S(Path, Path, UniqueID(FSID, FileID++), sys::TimeValue::now(),
96 0, 0, 1024, sys::fs::file_type::regular_file, Perms);
97 addEntry(Path, S);
98 }
99
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000100 void addDirectory(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000101 vfs::Status S(Path, Path, UniqueID(FSID, FileID++), sys::TimeValue::now(),
102 0, 0, 0, sys::fs::file_type::directory_file, Perms);
103 addEntry(Path, S);
104 }
105
106 void addSymlink(StringRef Path) {
107 vfs::Status S(Path, Path, UniqueID(FSID, FileID++), sys::TimeValue::now(),
108 0, 0, 0, sys::fs::file_type::symlink_file, sys::fs::all_all);
109 addEntry(Path, S);
110 }
111};
112} // end anonymous namespace
113
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000114TEST(VirtualFileSystemTest, StatusQueries) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000115 IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
Rafael Espindola8e650d72014-06-12 20:37:59 +0000116 ErrorOr<vfs::Status> Status((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000117
118 D->addRegularFile("/foo");
119 Status = D->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000120 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000121 EXPECT_TRUE(Status->isStatusKnown());
122 EXPECT_FALSE(Status->isDirectory());
123 EXPECT_TRUE(Status->isRegularFile());
124 EXPECT_FALSE(Status->isSymlink());
125 EXPECT_FALSE(Status->isOther());
126 EXPECT_TRUE(Status->exists());
127
128 D->addDirectory("/bar");
129 Status = D->status("/bar");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000130 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000131 EXPECT_TRUE(Status->isStatusKnown());
132 EXPECT_TRUE(Status->isDirectory());
133 EXPECT_FALSE(Status->isRegularFile());
134 EXPECT_FALSE(Status->isSymlink());
135 EXPECT_FALSE(Status->isOther());
136 EXPECT_TRUE(Status->exists());
137
138 D->addSymlink("/baz");
139 Status = D->status("/baz");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000140 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000141 EXPECT_TRUE(Status->isStatusKnown());
142 EXPECT_FALSE(Status->isDirectory());
143 EXPECT_FALSE(Status->isRegularFile());
144 EXPECT_TRUE(Status->isSymlink());
145 EXPECT_FALSE(Status->isOther());
146 EXPECT_TRUE(Status->exists());
147
148 EXPECT_TRUE(Status->equivalent(*Status));
149 ErrorOr<vfs::Status> Status2 = D->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000150 ASSERT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000151 EXPECT_FALSE(Status->equivalent(*Status2));
152}
153
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000154TEST(VirtualFileSystemTest, BaseOnlyOverlay) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000155 IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
Rafael Espindola8e650d72014-06-12 20:37:59 +0000156 ErrorOr<vfs::Status> Status((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000157 EXPECT_FALSE(Status = D->status("/foo"));
158
159 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(new vfs::OverlayFileSystem(D));
160 EXPECT_FALSE(Status = O->status("/foo"));
161
162 D->addRegularFile("/foo");
163 Status = D->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000164 EXPECT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000165
Rafael Espindola8e650d72014-06-12 20:37:59 +0000166 ErrorOr<vfs::Status> Status2((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000167 Status2 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000168 EXPECT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000169 EXPECT_TRUE(Status->equivalent(*Status2));
170}
171
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000172TEST(VirtualFileSystemTest, OverlayFiles) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000173 IntrusiveRefCntPtr<DummyFileSystem> Base(new DummyFileSystem());
174 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
175 IntrusiveRefCntPtr<DummyFileSystem> Top(new DummyFileSystem());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000176 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
177 new vfs::OverlayFileSystem(Base));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000178 O->pushOverlay(Middle);
179 O->pushOverlay(Top);
180
Rafael Espindola8e650d72014-06-12 20:37:59 +0000181 ErrorOr<vfs::Status> Status1((std::error_code())),
182 Status2((std::error_code())), Status3((std::error_code())),
183 StatusB((std::error_code())), StatusM((std::error_code())),
184 StatusT((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000185
186 Base->addRegularFile("/foo");
187 StatusB = Base->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000188 ASSERT_FALSE(StatusB.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000189 Status1 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000190 ASSERT_FALSE(Status1.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000191 Middle->addRegularFile("/foo");
192 StatusM = Middle->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000193 ASSERT_FALSE(StatusM.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000194 Status2 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000195 ASSERT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000196 Top->addRegularFile("/foo");
197 StatusT = Top->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000198 ASSERT_FALSE(StatusT.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000199 Status3 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000200 ASSERT_FALSE(Status3.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000201
202 EXPECT_TRUE(Status1->equivalent(*StatusB));
203 EXPECT_TRUE(Status2->equivalent(*StatusM));
204 EXPECT_TRUE(Status3->equivalent(*StatusT));
205
206 EXPECT_FALSE(Status1->equivalent(*Status2));
207 EXPECT_FALSE(Status2->equivalent(*Status3));
208 EXPECT_FALSE(Status1->equivalent(*Status3));
209}
210
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000211TEST(VirtualFileSystemTest, OverlayDirsNonMerged) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000212 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
213 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000214 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
215 new vfs::OverlayFileSystem(Lower));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000216 O->pushOverlay(Upper);
217
218 Lower->addDirectory("/lower-only");
219 Upper->addDirectory("/upper-only");
220
221 // non-merged paths should be the same
222 ErrorOr<vfs::Status> Status1 = Lower->status("/lower-only");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000223 ASSERT_FALSE(Status1.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000224 ErrorOr<vfs::Status> Status2 = O->status("/lower-only");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000225 ASSERT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000226 EXPECT_TRUE(Status1->equivalent(*Status2));
227
228 Status1 = Upper->status("/upper-only");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000229 ASSERT_FALSE(Status1.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000230 Status2 = O->status("/upper-only");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000231 ASSERT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000232 EXPECT_TRUE(Status1->equivalent(*Status2));
233}
234
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000235TEST(VirtualFileSystemTest, MergedDirPermissions) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000236 // merged directories get the permissions of the upper dir
237 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
238 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000239 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
240 new vfs::OverlayFileSystem(Lower));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000241 O->pushOverlay(Upper);
242
Rafael Espindola8e650d72014-06-12 20:37:59 +0000243 ErrorOr<vfs::Status> Status((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000244 Lower->addDirectory("/both", sys::fs::owner_read);
245 Upper->addDirectory("/both", sys::fs::owner_all | sys::fs::group_read);
246 Status = O->status("/both");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000247 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000248 EXPECT_EQ(0740, Status->getPermissions());
249
250 // permissions (as usual) are not recursively applied
251 Lower->addRegularFile("/both/foo", sys::fs::owner_read);
252 Upper->addRegularFile("/both/bar", sys::fs::owner_write);
253 Status = O->status("/both/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000254 ASSERT_FALSE( Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000255 EXPECT_EQ(0400, Status->getPermissions());
256 Status = O->status("/both/bar");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000257 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000258 EXPECT_EQ(0200, Status->getPermissions());
259}
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000260
Ben Langmuir740812b2014-06-24 19:37:16 +0000261namespace {
262struct ScopedDir {
263 SmallString<128> Path;
264 ScopedDir(const Twine &Name, bool Unique=false) {
265 std::error_code EC;
266 if (Unique) {
267 EC = llvm::sys::fs::createUniqueDirectory(Name, Path);
268 } else {
269 Path = Name.str();
270 EC = llvm::sys::fs::create_directory(Twine(Path));
271 }
272 if (EC)
273 Path = "";
274 EXPECT_FALSE(EC);
275 }
276 ~ScopedDir() {
277 if (Path != "")
278 EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
279 }
280 operator StringRef() { return Path.str(); }
281};
Alexander Kornienkoab9db512015-06-22 23:07:51 +0000282}
Ben Langmuir740812b2014-06-24 19:37:16 +0000283
284TEST(VirtualFileSystemTest, BasicRealFSIteration) {
285 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
286 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
287
288 std::error_code EC;
289 vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC);
290 ASSERT_FALSE(EC);
291 EXPECT_EQ(vfs::directory_iterator(), I); // empty directory is empty
292
293 ScopedDir _a(TestDirectory+"/a");
294 ScopedDir _ab(TestDirectory+"/a/b");
295 ScopedDir _c(TestDirectory+"/c");
296 ScopedDir _cd(TestDirectory+"/c/d");
297
298 I = FS->dir_begin(Twine(TestDirectory), EC);
299 ASSERT_FALSE(EC);
300 ASSERT_NE(vfs::directory_iterator(), I);
Ben Langmuirefb8b602014-06-24 21:08:13 +0000301 // Check either a or c, since we can't rely on the iteration order.
302 EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000303 I.increment(EC);
304 ASSERT_FALSE(EC);
305 ASSERT_NE(vfs::directory_iterator(), I);
Ben Langmuirefb8b602014-06-24 21:08:13 +0000306 EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000307 I.increment(EC);
308 EXPECT_EQ(vfs::directory_iterator(), I);
309}
310
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000311TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
312 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
313 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
314
315 std::error_code EC;
316 auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
317 ASSERT_FALSE(EC);
318 EXPECT_EQ(vfs::recursive_directory_iterator(), I); // empty directory is empty
319
320 ScopedDir _a(TestDirectory+"/a");
321 ScopedDir _ab(TestDirectory+"/a/b");
322 ScopedDir _c(TestDirectory+"/c");
323 ScopedDir _cd(TestDirectory+"/c/d");
324
325 I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
326 ASSERT_FALSE(EC);
327 ASSERT_NE(vfs::recursive_directory_iterator(), I);
328
329
330 std::vector<std::string> Contents;
331 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
332 I.increment(EC)) {
333 Contents.push_back(I->getName());
334 }
335
336 // Check contents, which may be in any order
337 EXPECT_EQ(4U, Contents.size());
338 int Counts[4] = { 0, 0, 0, 0 };
339 for (const std::string &Name : Contents) {
340 ASSERT_FALSE(Name.empty());
341 int Index = Name[Name.size()-1] - 'a';
342 ASSERT_TRUE(Index >= 0 && Index < 4);
343 Counts[Index]++;
344 }
345 EXPECT_EQ(1, Counts[0]); // a
346 EXPECT_EQ(1, Counts[1]); // b
347 EXPECT_EQ(1, Counts[2]); // c
348 EXPECT_EQ(1, Counts[3]); // d
349}
350
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000351template <typename T, size_t N>
352std::vector<StringRef> makeStringRefVector(const T (&Arr)[N]) {
353 std::vector<StringRef> Vec;
354 for (size_t i = 0; i != N; ++i)
355 Vec.push_back(Arr[i]);
356 return Vec;
357}
358
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000359template <typename DirIter>
360static void checkContents(DirIter I, ArrayRef<StringRef> Expected) {
Ben Langmuir740812b2014-06-24 19:37:16 +0000361 std::error_code EC;
362 auto ExpectedIter = Expected.begin(), ExpectedEnd = Expected.end();
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000363 for (DirIter E;
Ben Langmuir740812b2014-06-24 19:37:16 +0000364 !EC && I != E && ExpectedIter != ExpectedEnd;
365 I.increment(EC), ++ExpectedIter)
366 EXPECT_EQ(*ExpectedIter, I->getName());
367
368 EXPECT_EQ(ExpectedEnd, ExpectedIter);
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000369 EXPECT_EQ(DirIter(), I);
Ben Langmuir740812b2014-06-24 19:37:16 +0000370}
371
372TEST(VirtualFileSystemTest, OverlayIteration) {
373 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
374 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
375 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
376 new vfs::OverlayFileSystem(Lower));
377 O->pushOverlay(Upper);
378
379 std::error_code EC;
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000380 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
Ben Langmuir740812b2014-06-24 19:37:16 +0000381
382 Lower->addRegularFile("/file1");
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000383 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file1"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000384
385 Upper->addRegularFile("/file2");
386 {
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000387 const char *Contents[] = {"/file2", "/file1"};
388 checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
Ben Langmuir740812b2014-06-24 19:37:16 +0000389 }
390
391 Lower->addDirectory("/dir1");
392 Lower->addRegularFile("/dir1/foo");
393 Upper->addDirectory("/dir2");
394 Upper->addRegularFile("/dir2/foo");
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000395 checkContents(O->dir_begin("/dir2", EC), ArrayRef<StringRef>("/dir2/foo"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000396 {
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000397 const char *Contents[] = {"/dir2", "/file2", "/dir1", "/file1"};
398 checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
Ben Langmuir740812b2014-06-24 19:37:16 +0000399 }
400}
401
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000402TEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
403 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
404 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
405 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
406 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
407 new vfs::OverlayFileSystem(Lower));
408 O->pushOverlay(Middle);
409 O->pushOverlay(Upper);
410
411 std::error_code EC;
412 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
413 ArrayRef<StringRef>());
414
415 Lower->addRegularFile("/file1");
416 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
417 ArrayRef<StringRef>("/file1"));
418
419 Upper->addDirectory("/dir");
420 Upper->addRegularFile("/dir/file2");
421 {
422 const char *Contents[] = {"/dir", "/dir/file2", "/file1"};
423 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
424 makeStringRefVector(Contents));
425 }
426
427 Lower->addDirectory("/dir1");
428 Lower->addRegularFile("/dir1/foo");
429 Lower->addDirectory("/dir1/a");
430 Lower->addRegularFile("/dir1/a/b");
431 Middle->addDirectory("/a");
432 Middle->addDirectory("/a/b");
433 Middle->addDirectory("/a/b/c");
434 Middle->addRegularFile("/a/b/c/d");
435 Middle->addRegularFile("/hiddenByUp");
436 Upper->addDirectory("/dir2");
437 Upper->addRegularFile("/dir2/foo");
438 Upper->addRegularFile("/hiddenByUp");
439 checkContents(vfs::recursive_directory_iterator(*O, "/dir2", EC),
440 ArrayRef<StringRef>("/dir2/foo"));
441 {
442 const char *Contents[] = { "/dir", "/dir/file2", "/dir2", "/dir2/foo",
443 "/hiddenByUp", "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
444 "/dir1/a/b", "/dir1/foo", "/file1" };
445 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
446 makeStringRefVector(Contents));
447 }
448}
449
Ben Langmuir740812b2014-06-24 19:37:16 +0000450TEST(VirtualFileSystemTest, ThreeLevelIteration) {
451 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
452 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
453 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
454 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
455 new vfs::OverlayFileSystem(Lower));
456 O->pushOverlay(Middle);
457 O->pushOverlay(Upper);
458
459 std::error_code EC;
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000460 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
Ben Langmuir740812b2014-06-24 19:37:16 +0000461
462 Middle->addRegularFile("/file2");
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000463 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file2"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000464
465 Lower->addRegularFile("/file1");
466 Upper->addRegularFile("/file3");
467 {
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000468 const char *Contents[] = {"/file3", "/file2", "/file1"};
469 checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
Ben Langmuir740812b2014-06-24 19:37:16 +0000470 }
471}
472
473TEST(VirtualFileSystemTest, HiddenInIteration) {
474 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
475 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
476 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
477 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
478 new vfs::OverlayFileSystem(Lower));
479 O->pushOverlay(Middle);
480 O->pushOverlay(Upper);
481
482 std::error_code EC;
483 Lower->addRegularFile("/onlyInLow", sys::fs::owner_read);
484 Lower->addRegularFile("/hiddenByMid", sys::fs::owner_read);
485 Lower->addRegularFile("/hiddenByUp", sys::fs::owner_read);
486 Middle->addRegularFile("/onlyInMid", sys::fs::owner_write);
487 Middle->addRegularFile("/hiddenByMid", sys::fs::owner_write);
488 Middle->addRegularFile("/hiddenByUp", sys::fs::owner_write);
489 Upper->addRegularFile("/onlyInUp", sys::fs::owner_all);
490 Upper->addRegularFile("/hiddenByUp", sys::fs::owner_all);
491 {
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000492 const char *Contents[] = {"/hiddenByUp", "/onlyInUp", "/hiddenByMid",
493 "/onlyInMid", "/onlyInLow"};
494 checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
Ben Langmuir740812b2014-06-24 19:37:16 +0000495 }
496
497 // Make sure we get the top-most entry
Ben Langmuirefb8b602014-06-24 21:08:13 +0000498 {
499 std::error_code EC;
500 vfs::directory_iterator I = O->dir_begin("/", EC), E;
501 for ( ; !EC && I != E; I.increment(EC))
502 if (I->getName() == "/hiddenByUp")
503 break;
504 ASSERT_NE(E, I);
505 EXPECT_EQ(sys::fs::owner_all, I->getPermissions());
506 }
507 {
508 std::error_code EC;
509 vfs::directory_iterator I = O->dir_begin("/", EC), E;
510 for ( ; !EC && I != E; I.increment(EC))
511 if (I->getName() == "/hiddenByMid")
512 break;
513 ASSERT_NE(E, I);
514 EXPECT_EQ(sys::fs::owner_write, I->getPermissions());
515 }
Ben Langmuir740812b2014-06-24 19:37:16 +0000516}
517
Ben Langmuir93853232014-03-05 21:32:20 +0000518// NOTE: in the tests below, we use '//root/' as our root directory, since it is
519// a legal *absolute* path on Windows as well as *nix.
Ben Langmuir97882e72014-02-24 20:56:37 +0000520class VFSFromYAMLTest : public ::testing::Test {
521public:
522 int NumDiagnostics;
Ben Langmuir93853232014-03-05 21:32:20 +0000523
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000524 void SetUp() override { NumDiagnostics = 0; }
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000525
Ben Langmuir97882e72014-02-24 20:56:37 +0000526 static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
527 VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
528 ++Test->NumDiagnostics;
529 }
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000530
Ben Langmuir97882e72014-02-24 20:56:37 +0000531 IntrusiveRefCntPtr<vfs::FileSystem>
532 getFromYAMLRawString(StringRef Content,
533 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
Rafael Espindolad87f8d72014-08-27 20:03:29 +0000534 std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content);
Rafael Espindola91ac8df2014-08-17 23:27:13 +0000535 return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, this,
536 ExternalFS);
Ben Langmuir97882e72014-02-24 20:56:37 +0000537 }
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000538
Ben Langmuir97882e72014-02-24 20:56:37 +0000539 IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
540 StringRef Content,
541 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
542 std::string VersionPlusContent("{\n 'version':0,\n");
543 VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
544 return getFromYAMLRawString(VersionPlusContent, ExternalFS);
545 }
Ben Langmuir97882e72014-02-24 20:56:37 +0000546};
547
548TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000549 IntrusiveRefCntPtr<vfs::FileSystem> FS;
550 FS = getFromYAMLString("");
Alp Tokerf994cef2014-07-05 03:08:06 +0000551 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000552 FS = getFromYAMLString("[]");
Alp Tokerf994cef2014-07-05 03:08:06 +0000553 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000554 FS = getFromYAMLString("'string'");
Alp Tokerf994cef2014-07-05 03:08:06 +0000555 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000556 EXPECT_EQ(3, NumDiagnostics);
557}
558
Ben Langmuir97882e72014-02-24 20:56:37 +0000559TEST_F(VFSFromYAMLTest, MappedFiles) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000560 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +0000561 Lower->addRegularFile("//root/foo/bar/a");
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000562 IntrusiveRefCntPtr<vfs::FileSystem> FS =
563 getFromYAMLString("{ 'roots': [\n"
564 "{\n"
565 " 'type': 'directory',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000566 " 'name': '//root/',\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000567 " 'contents': [ {\n"
568 " 'type': 'file',\n"
569 " 'name': 'file1',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000570 " 'external-contents': '//root/foo/bar/a'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000571 " },\n"
572 " {\n"
573 " 'type': 'file',\n"
574 " 'name': 'file2',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000575 " 'external-contents': '//root/foo/b'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000576 " }\n"
577 " ]\n"
578 "}\n"
579 "]\n"
580 "}",
581 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000582 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000583
584 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
585 new vfs::OverlayFileSystem(Lower));
586 O->pushOverlay(FS);
587
588 // file
Ben Langmuir93853232014-03-05 21:32:20 +0000589 ErrorOr<vfs::Status> S = O->status("//root/file1");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000590 ASSERT_FALSE(S.getError());
Ben Langmuir93853232014-03-05 21:32:20 +0000591 EXPECT_EQ("//root/foo/bar/a", S->getName());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000592
Ben Langmuir93853232014-03-05 21:32:20 +0000593 ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
594 EXPECT_EQ("//root/foo/bar/a", SLower->getName());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000595 EXPECT_TRUE(S->equivalent(*SLower));
596
597 // directory
Ben Langmuir93853232014-03-05 21:32:20 +0000598 S = O->status("//root/");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000599 ASSERT_FALSE(S.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000600 EXPECT_TRUE(S->isDirectory());
Ben Langmuir93853232014-03-05 21:32:20 +0000601 EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000602
603 // broken mapping
Rafael Espindola71de0b62014-06-13 17:20:50 +0000604 EXPECT_EQ(O->status("//root/file2").getError(),
605 llvm::errc::no_such_file_or_directory);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000606 EXPECT_EQ(0, NumDiagnostics);
607}
608
Ben Langmuir97882e72014-02-24 20:56:37 +0000609TEST_F(VFSFromYAMLTest, CaseInsensitive) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000610 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +0000611 Lower->addRegularFile("//root/foo/bar/a");
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000612 IntrusiveRefCntPtr<vfs::FileSystem> FS =
613 getFromYAMLString("{ 'case-sensitive': 'false',\n"
614 " 'roots': [\n"
615 "{\n"
616 " 'type': 'directory',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000617 " 'name': '//root/',\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000618 " 'contents': [ {\n"
619 " 'type': 'file',\n"
620 " 'name': 'XX',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000621 " 'external-contents': '//root/foo/bar/a'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000622 " }\n"
623 " ]\n"
624 "}]}",
625 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000626 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000627
628 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
629 new vfs::OverlayFileSystem(Lower));
630 O->pushOverlay(FS);
631
Ben Langmuir93853232014-03-05 21:32:20 +0000632 ErrorOr<vfs::Status> S = O->status("//root/XX");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000633 ASSERT_FALSE(S.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000634
Ben Langmuir93853232014-03-05 21:32:20 +0000635 ErrorOr<vfs::Status> SS = O->status("//root/xx");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000636 ASSERT_FALSE(SS.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000637 EXPECT_TRUE(S->equivalent(*SS));
Ben Langmuir93853232014-03-05 21:32:20 +0000638 SS = O->status("//root/xX");
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000639 EXPECT_TRUE(S->equivalent(*SS));
Ben Langmuir93853232014-03-05 21:32:20 +0000640 SS = O->status("//root/Xx");
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000641 EXPECT_TRUE(S->equivalent(*SS));
642 EXPECT_EQ(0, NumDiagnostics);
643}
644
Ben Langmuir97882e72014-02-24 20:56:37 +0000645TEST_F(VFSFromYAMLTest, CaseSensitive) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000646 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +0000647 Lower->addRegularFile("//root/foo/bar/a");
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000648 IntrusiveRefCntPtr<vfs::FileSystem> FS =
649 getFromYAMLString("{ 'case-sensitive': 'true',\n"
650 " 'roots': [\n"
651 "{\n"
652 " 'type': 'directory',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000653 " 'name': '//root/',\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000654 " 'contents': [ {\n"
655 " 'type': 'file',\n"
656 " 'name': 'XX',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000657 " 'external-contents': '//root/foo/bar/a'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000658 " }\n"
659 " ]\n"
660 "}]}",
661 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000662 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000663
664 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
665 new vfs::OverlayFileSystem(Lower));
666 O->pushOverlay(FS);
667
Ben Langmuir93853232014-03-05 21:32:20 +0000668 ErrorOr<vfs::Status> SS = O->status("//root/xx");
Rafael Espindola71de0b62014-06-13 17:20:50 +0000669 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuir93853232014-03-05 21:32:20 +0000670 SS = O->status("//root/xX");
Rafael Espindola71de0b62014-06-13 17:20:50 +0000671 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuir93853232014-03-05 21:32:20 +0000672 SS = O->status("//root/Xx");
Rafael Espindola71de0b62014-06-13 17:20:50 +0000673 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000674 EXPECT_EQ(0, NumDiagnostics);
675}
676
Ben Langmuir97882e72014-02-24 20:56:37 +0000677TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000678 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
679
680 // invalid YAML at top-level
681 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000682 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000683 // invalid YAML in roots
684 FS = getFromYAMLString("{ 'roots':[}", Lower);
685 // invalid YAML in directory
686 FS = getFromYAMLString(
687 "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
688 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000689 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000690
691 // invalid configuration
692 FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000693 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000694 FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000695 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000696
697 // invalid roots
698 FS = getFromYAMLString("{ 'roots':'' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000699 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000700 FS = getFromYAMLString("{ 'roots':{} }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000701 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000702
703 // invalid entries
704 FS = getFromYAMLString(
705 "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000706 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000707 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
708 "'external-contents': 'other' }",
709 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000710 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000711 FS = getFromYAMLString(
712 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
713 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000714 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000715 FS = getFromYAMLString(
716 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
717 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000718 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000719 FS = getFromYAMLString(
720 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
721 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000722 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000723 FS = getFromYAMLString(
724 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
725 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000726 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000727 FS = getFromYAMLString(
728 "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
729 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000730 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000731
732 // missing mandatory fields
733 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000734 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000735 FS = getFromYAMLString(
736 "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000737 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000738 FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000739 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000740
741 // duplicate keys
742 FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000743 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000744 FS = getFromYAMLString(
745 "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
746 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000747 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000748 FS =
749 getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
750 "'external-contents':'blah' } ] }",
751 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000752 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000753
754 // missing version
755 FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000756 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000757
758 // bad version number
759 FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000760 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000761 FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000762 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000763 FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000764 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000765 EXPECT_EQ(24, NumDiagnostics);
766}
Ben Langmuir47ff9ab2014-02-25 04:34:14 +0000767
Ben Langmuirb59cf672014-02-27 00:25:12 +0000768TEST_F(VFSFromYAMLTest, UseExternalName) {
769 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +0000770 Lower->addRegularFile("//root/external/file");
Ben Langmuirb59cf672014-02-27 00:25:12 +0000771
772 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
773 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000774 " { 'type': 'file', 'name': '//root/A',\n"
775 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +0000776 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000777 " { 'type': 'file', 'name': '//root/B',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +0000778 " 'use-external-name': true,\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000779 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +0000780 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000781 " { 'type': 'file', 'name': '//root/C',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +0000782 " 'use-external-name': false,\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000783 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +0000784 " }\n"
785 "] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000786 ASSERT_TRUE(nullptr != FS.get());
Ben Langmuirb59cf672014-02-27 00:25:12 +0000787
788 // default true
Ben Langmuir93853232014-03-05 21:32:20 +0000789 EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +0000790 // explicit
Ben Langmuir93853232014-03-05 21:32:20 +0000791 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
792 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +0000793
794 // global configuration
795 FS = getFromYAMLString(
796 "{ 'use-external-names': false,\n"
797 " 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000798 " { 'type': 'file', 'name': '//root/A',\n"
799 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +0000800 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000801 " { 'type': 'file', 'name': '//root/B',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +0000802 " 'use-external-name': true,\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000803 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +0000804 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000805 " { 'type': 'file', 'name': '//root/C',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +0000806 " 'use-external-name': false,\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000807 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +0000808 " }\n"
809 "] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000810 ASSERT_TRUE(nullptr != FS.get());
Ben Langmuirb59cf672014-02-27 00:25:12 +0000811
812 // default
Ben Langmuir93853232014-03-05 21:32:20 +0000813 EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +0000814 // explicit
Ben Langmuir93853232014-03-05 21:32:20 +0000815 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
816 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +0000817}
818
Ben Langmuir47ff9ab2014-02-25 04:34:14 +0000819TEST_F(VFSFromYAMLTest, MultiComponentPath) {
820 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +0000821 Lower->addRegularFile("//root/other");
Ben Langmuir47ff9ab2014-02-25 04:34:14 +0000822
823 // file in roots
824 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
825 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000826 " { 'type': 'file', 'name': '//root/path/to/file',\n"
827 " 'external-contents': '//root/other' }]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +0000828 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000829 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +0000830 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
831 EXPECT_FALSE(FS->status("//root/path/to").getError());
832 EXPECT_FALSE(FS->status("//root/path").getError());
833 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +0000834
835 // at the start
836 FS = getFromYAMLString(
837 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000838 " { 'type': 'directory', 'name': '//root/path/to',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +0000839 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000840 " 'external-contents': '//root/other' }]}]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +0000841 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000842 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +0000843 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
844 EXPECT_FALSE(FS->status("//root/path/to").getError());
845 EXPECT_FALSE(FS->status("//root/path").getError());
846 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +0000847
848 // at the end
849 FS = getFromYAMLString(
850 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000851 " { 'type': 'directory', 'name': '//root/',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +0000852 " 'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000853 " 'external-contents': '//root/other' }]}]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +0000854 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000855 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +0000856 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
857 EXPECT_FALSE(FS->status("//root/path/to").getError());
858 EXPECT_FALSE(FS->status("//root/path").getError());
859 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +0000860}
861
862TEST_F(VFSFromYAMLTest, TrailingSlashes) {
863 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +0000864 Lower->addRegularFile("//root/other");
Ben Langmuir47ff9ab2014-02-25 04:34:14 +0000865
866 // file in roots
867 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
868 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000869 " { 'type': 'directory', 'name': '//root/path/to////',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +0000870 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000871 " 'external-contents': '//root/other' }]}]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +0000872 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000873 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +0000874 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
875 EXPECT_FALSE(FS->status("//root/path/to").getError());
876 EXPECT_FALSE(FS->status("//root/path").getError());
877 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +0000878}
Ben Langmuir740812b2014-06-24 19:37:16 +0000879
880TEST_F(VFSFromYAMLTest, DirectoryIteration) {
881 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
882 Lower->addDirectory("//root/");
883 Lower->addDirectory("//root/foo");
884 Lower->addDirectory("//root/foo/bar");
885 Lower->addRegularFile("//root/foo/bar/a");
886 Lower->addRegularFile("//root/foo/bar/b");
887 Lower->addRegularFile("//root/file3");
888 IntrusiveRefCntPtr<vfs::FileSystem> FS =
889 getFromYAMLString("{ 'use-external-names': false,\n"
890 " 'roots': [\n"
891 "{\n"
892 " 'type': 'directory',\n"
893 " 'name': '//root/',\n"
894 " 'contents': [ {\n"
895 " 'type': 'file',\n"
896 " 'name': 'file1',\n"
897 " 'external-contents': '//root/foo/bar/a'\n"
898 " },\n"
899 " {\n"
900 " 'type': 'file',\n"
901 " 'name': 'file2',\n"
902 " 'external-contents': '//root/foo/bar/b'\n"
903 " }\n"
904 " ]\n"
905 "}\n"
906 "]\n"
907 "}",
908 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000909 ASSERT_TRUE(FS.get() != NULL);
Ben Langmuir740812b2014-06-24 19:37:16 +0000910
911 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
912 new vfs::OverlayFileSystem(Lower));
913 O->pushOverlay(FS);
914
915 std::error_code EC;
916 {
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000917 const char *Contents[] = {"//root/file1", "//root/file2", "//root/file3",
918 "//root/foo"};
919 checkContents(O->dir_begin("//root/", EC), makeStringRefVector(Contents));
Ben Langmuir740812b2014-06-24 19:37:16 +0000920 }
921
922 {
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000923 const char *Contents[] = {"//root/foo/bar/a", "//root/foo/bar/b"};
924 checkContents(O->dir_begin("//root/foo/bar", EC),
925 makeStringRefVector(Contents));
Ben Langmuir740812b2014-06-24 19:37:16 +0000926 }
927}