blob: 0856b17791fa99a78472ea9839484ffcf821de5d [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"
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +000011#include "llvm/ADT/Triple.h"
Rafael Espindola71de0b62014-06-13 17:20:50 +000012#include "llvm/Support/Errc.h"
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +000013#include "llvm/Support/Host.h"
Ben Langmuird51ba0b2014-02-21 23:39:37 +000014#include "llvm/Support/MemoryBuffer.h"
Ben Langmuird51ba0b2014-02-21 23:39:37 +000015#include "llvm/Support/SourceMgr.h"
Ben Langmuirc8130a72014-02-20 21:59:23 +000016#include "gtest/gtest.h"
17#include <map>
Hans Wennborgdcfba332015-10-06 23:40:43 +000018
Ben Langmuirc8130a72014-02-20 21:59:23 +000019using namespace clang;
20using namespace llvm;
21using llvm::sys::fs::UniqueID;
22
23namespace {
Ben Langmuirf13302e2015-12-10 23:41:39 +000024struct DummyFile : public vfs::File {
25 vfs::Status S;
26 explicit DummyFile(vfs::Status S) : S(S) {}
27 llvm::ErrorOr<vfs::Status> status() override { return S; }
28 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
29 getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
30 bool IsVolatile) override {
31 llvm_unreachable("unimplemented");
32 }
Eugene Zelenko1660a5d2016-01-26 19:01:06 +000033 std::error_code close() override { return std::error_code(); }
Ben Langmuirf13302e2015-12-10 23:41:39 +000034};
35
Ben Langmuirc8130a72014-02-20 21:59:23 +000036class DummyFileSystem : public vfs::FileSystem {
37 int FSID; // used to produce UniqueIDs
38 int FileID; // used to produce UniqueIDs
39 std::map<std::string, vfs::Status> FilesAndDirs;
40
41 static int getNextFSID() {
42 static int Count = 0;
43 return Count++;
44 }
45
46public:
47 DummyFileSystem() : FSID(getNextFSID()), FileID(0) {}
48
Fariborz Jahanian5afc8692014-10-01 16:56:40 +000049 ErrorOr<vfs::Status> status(const Twine &Path) override {
Ben Langmuirc8130a72014-02-20 21:59:23 +000050 std::map<std::string, vfs::Status>::iterator I =
Ben Langmuird51ba0b2014-02-21 23:39:37 +000051 FilesAndDirs.find(Path.str());
Ben Langmuirc8130a72014-02-20 21:59:23 +000052 if (I == FilesAndDirs.end())
Rafael Espindola71de0b62014-06-13 17:20:50 +000053 return make_error_code(llvm::errc::no_such_file_or_directory);
Ben Langmuirc8130a72014-02-20 21:59:23 +000054 return I->second;
55 }
Benjamin Kramera8857962014-10-26 22:44:13 +000056 ErrorOr<std::unique_ptr<vfs::File>>
57 openFileForRead(const Twine &Path) override {
Ben Langmuirf13302e2015-12-10 23:41:39 +000058 auto S = status(Path);
59 if (S)
60 return std::unique_ptr<vfs::File>(new DummyFile{*S});
61 return S.getError();
Ben Langmuirc8130a72014-02-20 21:59:23 +000062 }
Benjamin Kramer7708b2a2015-10-05 13:55:20 +000063 llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
64 return std::string();
65 }
66 std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
67 return std::error_code();
68 }
Ben Langmuirc8130a72014-02-20 21:59:23 +000069
Ben Langmuir740812b2014-06-24 19:37:16 +000070 struct DirIterImpl : public clang::vfs::detail::DirIterImpl {
71 std::map<std::string, vfs::Status> &FilesAndDirs;
72 std::map<std::string, vfs::Status>::iterator I;
73 std::string Path;
Ben Langmuir7c9f6c82014-06-25 20:25:40 +000074 bool isInPath(StringRef S) {
75 if (Path.size() < S.size() && S.find(Path) == 0) {
76 auto LastSep = S.find_last_of('/');
77 if (LastSep == Path.size() || LastSep == Path.size()-1)
78 return true;
79 }
80 return false;
81 }
Ben Langmuir740812b2014-06-24 19:37:16 +000082 DirIterImpl(std::map<std::string, vfs::Status> &FilesAndDirs,
83 const Twine &_Path)
84 : FilesAndDirs(FilesAndDirs), I(FilesAndDirs.begin()),
85 Path(_Path.str()) {
86 for ( ; I != FilesAndDirs.end(); ++I) {
Ben Langmuir7c9f6c82014-06-25 20:25:40 +000087 if (isInPath(I->first)) {
Ben Langmuir740812b2014-06-24 19:37:16 +000088 CurrentEntry = I->second;
89 break;
90 }
91 }
92 }
93 std::error_code increment() override {
94 ++I;
95 for ( ; I != FilesAndDirs.end(); ++I) {
Ben Langmuir7c9f6c82014-06-25 20:25:40 +000096 if (isInPath(I->first)) {
Ben Langmuir740812b2014-06-24 19:37:16 +000097 CurrentEntry = I->second;
98 break;
99 }
100 }
101 if (I == FilesAndDirs.end())
102 CurrentEntry = vfs::Status();
103 return std::error_code();
104 }
105 };
106
107 vfs::directory_iterator dir_begin(const Twine &Dir,
108 std::error_code &EC) override {
109 return vfs::directory_iterator(
110 std::make_shared<DirIterImpl>(FilesAndDirs, Dir));
111 }
112
Ben Langmuirc8130a72014-02-20 21:59:23 +0000113 void addEntry(StringRef Path, const vfs::Status &Status) {
114 FilesAndDirs[Path] = Status;
115 }
116
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000117 void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
Pavel Labathac71c8e2016-11-09 10:52:22 +0000118 vfs::Status S(Path, UniqueID(FSID, FileID++),
119 std::chrono::system_clock::now(), 0, 0, 1024,
120 sys::fs::file_type::regular_file, Perms);
Ben Langmuirc8130a72014-02-20 21:59:23 +0000121 addEntry(Path, S);
122 }
123
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000124 void addDirectory(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
Pavel Labathac71c8e2016-11-09 10:52:22 +0000125 vfs::Status S(Path, UniqueID(FSID, FileID++),
126 std::chrono::system_clock::now(), 0, 0, 0,
127 sys::fs::file_type::directory_file, Perms);
Ben Langmuirc8130a72014-02-20 21:59:23 +0000128 addEntry(Path, S);
129 }
130
131 void addSymlink(StringRef Path) {
Pavel Labathac71c8e2016-11-09 10:52:22 +0000132 vfs::Status S(Path, UniqueID(FSID, FileID++),
133 std::chrono::system_clock::now(), 0, 0, 0,
134 sys::fs::file_type::symlink_file, sys::fs::all_all);
Ben Langmuirc8130a72014-02-20 21:59:23 +0000135 addEntry(Path, S);
136 }
137};
138} // end anonymous namespace
139
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000140TEST(VirtualFileSystemTest, StatusQueries) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000141 IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
Rafael Espindola8e650d72014-06-12 20:37:59 +0000142 ErrorOr<vfs::Status> Status((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000143
144 D->addRegularFile("/foo");
145 Status = D->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000146 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000147 EXPECT_TRUE(Status->isStatusKnown());
148 EXPECT_FALSE(Status->isDirectory());
149 EXPECT_TRUE(Status->isRegularFile());
150 EXPECT_FALSE(Status->isSymlink());
151 EXPECT_FALSE(Status->isOther());
152 EXPECT_TRUE(Status->exists());
153
154 D->addDirectory("/bar");
155 Status = D->status("/bar");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000156 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000157 EXPECT_TRUE(Status->isStatusKnown());
158 EXPECT_TRUE(Status->isDirectory());
159 EXPECT_FALSE(Status->isRegularFile());
160 EXPECT_FALSE(Status->isSymlink());
161 EXPECT_FALSE(Status->isOther());
162 EXPECT_TRUE(Status->exists());
163
164 D->addSymlink("/baz");
165 Status = D->status("/baz");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000166 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000167 EXPECT_TRUE(Status->isStatusKnown());
168 EXPECT_FALSE(Status->isDirectory());
169 EXPECT_FALSE(Status->isRegularFile());
170 EXPECT_TRUE(Status->isSymlink());
171 EXPECT_FALSE(Status->isOther());
172 EXPECT_TRUE(Status->exists());
173
174 EXPECT_TRUE(Status->equivalent(*Status));
175 ErrorOr<vfs::Status> Status2 = D->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000176 ASSERT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000177 EXPECT_FALSE(Status->equivalent(*Status2));
178}
179
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000180TEST(VirtualFileSystemTest, BaseOnlyOverlay) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000181 IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
Rafael Espindola8e650d72014-06-12 20:37:59 +0000182 ErrorOr<vfs::Status> Status((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000183 EXPECT_FALSE(Status = D->status("/foo"));
184
185 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(new vfs::OverlayFileSystem(D));
186 EXPECT_FALSE(Status = O->status("/foo"));
187
188 D->addRegularFile("/foo");
189 Status = D->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000190 EXPECT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000191
Rafael Espindola8e650d72014-06-12 20:37:59 +0000192 ErrorOr<vfs::Status> Status2((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000193 Status2 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000194 EXPECT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000195 EXPECT_TRUE(Status->equivalent(*Status2));
196}
197
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000198TEST(VirtualFileSystemTest, OverlayFiles) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000199 IntrusiveRefCntPtr<DummyFileSystem> Base(new DummyFileSystem());
200 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
201 IntrusiveRefCntPtr<DummyFileSystem> Top(new DummyFileSystem());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000202 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
203 new vfs::OverlayFileSystem(Base));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000204 O->pushOverlay(Middle);
205 O->pushOverlay(Top);
206
Rafael Espindola8e650d72014-06-12 20:37:59 +0000207 ErrorOr<vfs::Status> Status1((std::error_code())),
208 Status2((std::error_code())), Status3((std::error_code())),
209 StatusB((std::error_code())), StatusM((std::error_code())),
210 StatusT((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000211
212 Base->addRegularFile("/foo");
213 StatusB = Base->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000214 ASSERT_FALSE(StatusB.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000215 Status1 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000216 ASSERT_FALSE(Status1.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000217 Middle->addRegularFile("/foo");
218 StatusM = Middle->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000219 ASSERT_FALSE(StatusM.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000220 Status2 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000221 ASSERT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000222 Top->addRegularFile("/foo");
223 StatusT = Top->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000224 ASSERT_FALSE(StatusT.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000225 Status3 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000226 ASSERT_FALSE(Status3.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000227
228 EXPECT_TRUE(Status1->equivalent(*StatusB));
229 EXPECT_TRUE(Status2->equivalent(*StatusM));
230 EXPECT_TRUE(Status3->equivalent(*StatusT));
231
232 EXPECT_FALSE(Status1->equivalent(*Status2));
233 EXPECT_FALSE(Status2->equivalent(*Status3));
234 EXPECT_FALSE(Status1->equivalent(*Status3));
235}
236
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000237TEST(VirtualFileSystemTest, OverlayDirsNonMerged) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000238 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
239 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000240 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
241 new vfs::OverlayFileSystem(Lower));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000242 O->pushOverlay(Upper);
243
244 Lower->addDirectory("/lower-only");
245 Upper->addDirectory("/upper-only");
246
247 // non-merged paths should be the same
248 ErrorOr<vfs::Status> Status1 = Lower->status("/lower-only");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000249 ASSERT_FALSE(Status1.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000250 ErrorOr<vfs::Status> Status2 = O->status("/lower-only");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000251 ASSERT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000252 EXPECT_TRUE(Status1->equivalent(*Status2));
253
254 Status1 = Upper->status("/upper-only");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000255 ASSERT_FALSE(Status1.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000256 Status2 = O->status("/upper-only");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000257 ASSERT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000258 EXPECT_TRUE(Status1->equivalent(*Status2));
259}
260
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000261TEST(VirtualFileSystemTest, MergedDirPermissions) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000262 // merged directories get the permissions of the upper dir
263 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
264 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000265 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
266 new vfs::OverlayFileSystem(Lower));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000267 O->pushOverlay(Upper);
268
Rafael Espindola8e650d72014-06-12 20:37:59 +0000269 ErrorOr<vfs::Status> Status((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000270 Lower->addDirectory("/both", sys::fs::owner_read);
271 Upper->addDirectory("/both", sys::fs::owner_all | sys::fs::group_read);
272 Status = O->status("/both");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000273 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000274 EXPECT_EQ(0740, Status->getPermissions());
275
276 // permissions (as usual) are not recursively applied
277 Lower->addRegularFile("/both/foo", sys::fs::owner_read);
278 Upper->addRegularFile("/both/bar", sys::fs::owner_write);
279 Status = O->status("/both/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000280 ASSERT_FALSE( Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000281 EXPECT_EQ(0400, Status->getPermissions());
282 Status = O->status("/both/bar");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000283 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000284 EXPECT_EQ(0200, Status->getPermissions());
285}
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000286
Ben Langmuir740812b2014-06-24 19:37:16 +0000287namespace {
288struct ScopedDir {
289 SmallString<128> Path;
290 ScopedDir(const Twine &Name, bool Unique=false) {
291 std::error_code EC;
292 if (Unique) {
293 EC = llvm::sys::fs::createUniqueDirectory(Name, Path);
294 } else {
295 Path = Name.str();
296 EC = llvm::sys::fs::create_directory(Twine(Path));
297 }
298 if (EC)
299 Path = "";
300 EXPECT_FALSE(EC);
301 }
302 ~ScopedDir() {
303 if (Path != "")
304 EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
305 }
306 operator StringRef() { return Path.str(); }
307};
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000308
309struct ScopedLink {
310 SmallString<128> Path;
311 ScopedLink(const Twine &To, const Twine &From) {
312 Path = From.str();
313 std::error_code EC = sys::fs::create_link(To, From);
314 if (EC)
315 Path = "";
316 EXPECT_FALSE(EC);
317 }
318 ~ScopedLink() {
319 if (Path != "")
320 EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
321 }
322 operator StringRef() { return Path.str(); }
323};
Hans Wennborgdcfba332015-10-06 23:40:43 +0000324} // end anonymous namespace
Ben Langmuir740812b2014-06-24 19:37:16 +0000325
326TEST(VirtualFileSystemTest, BasicRealFSIteration) {
327 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
328 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
329
330 std::error_code EC;
331 vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC);
332 ASSERT_FALSE(EC);
333 EXPECT_EQ(vfs::directory_iterator(), I); // empty directory is empty
334
335 ScopedDir _a(TestDirectory+"/a");
336 ScopedDir _ab(TestDirectory+"/a/b");
337 ScopedDir _c(TestDirectory+"/c");
338 ScopedDir _cd(TestDirectory+"/c/d");
339
340 I = FS->dir_begin(Twine(TestDirectory), EC);
341 ASSERT_FALSE(EC);
342 ASSERT_NE(vfs::directory_iterator(), I);
Ben Langmuirefb8b602014-06-24 21:08:13 +0000343 // Check either a or c, since we can't rely on the iteration order.
344 EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000345 I.increment(EC);
346 ASSERT_FALSE(EC);
347 ASSERT_NE(vfs::directory_iterator(), I);
Ben Langmuirefb8b602014-06-24 21:08:13 +0000348 EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000349 I.increment(EC);
350 EXPECT_EQ(vfs::directory_iterator(), I);
351}
352
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000353#ifdef LLVM_ON_UNIX
354TEST(VirtualFileSystemTest, BrokenSymlinkRealFSIteration) {
355 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
356 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
357
358 ScopedLink _a("no_such_file", TestDirectory + "/a");
359 ScopedDir _b(TestDirectory + "/b");
360 ScopedLink _c("no_such_file", TestDirectory + "/c");
361
362 std::error_code EC;
363 for (vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC), E;
364 I != E; I.increment(EC)) {
365 // Skip broken symlinks.
Juergen Ributzka53fda392017-03-14 17:46:26 +0000366 auto EC2 = std::make_error_code(std::errc::no_such_file_or_directory);
367 if (EC == EC2) {
368 EC.clear();
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000369 continue;
370 }
371 // For bot debugging.
372 if (EC) {
Juergen Ributzka53fda392017-03-14 17:46:26 +0000373 outs() << "Error code found:\n"
374 << "EC value: " << EC.value() << "\n"
375 << "EC category: " << EC.category().name()
376 << "EC message: " << EC.message() << "\n";
377
378 outs() << "Error code tested for:\n"
379 << "EC value: " << EC2.value() << "\n"
380 << "EC category: " << EC2.category().name()
381 << "EC message: " << EC2.message() << "\n";
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000382 }
383 ASSERT_FALSE(EC);
384 EXPECT_TRUE(I->getName() == _b);
385 }
386}
387#endif
388
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000389TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
390 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
391 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
392
393 std::error_code EC;
394 auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
395 ASSERT_FALSE(EC);
396 EXPECT_EQ(vfs::recursive_directory_iterator(), I); // empty directory is empty
397
398 ScopedDir _a(TestDirectory+"/a");
399 ScopedDir _ab(TestDirectory+"/a/b");
400 ScopedDir _c(TestDirectory+"/c");
401 ScopedDir _cd(TestDirectory+"/c/d");
402
403 I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
404 ASSERT_FALSE(EC);
405 ASSERT_NE(vfs::recursive_directory_iterator(), I);
406
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000407 std::vector<std::string> Contents;
408 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
409 I.increment(EC)) {
410 Contents.push_back(I->getName());
411 }
412
413 // Check contents, which may be in any order
414 EXPECT_EQ(4U, Contents.size());
415 int Counts[4] = { 0, 0, 0, 0 };
416 for (const std::string &Name : Contents) {
417 ASSERT_FALSE(Name.empty());
418 int Index = Name[Name.size()-1] - 'a';
419 ASSERT_TRUE(Index >= 0 && Index < 4);
420 Counts[Index]++;
421 }
422 EXPECT_EQ(1, Counts[0]); // a
423 EXPECT_EQ(1, Counts[1]); // b
424 EXPECT_EQ(1, Counts[2]); // c
425 EXPECT_EQ(1, Counts[3]); // d
426}
427
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000428#ifdef LLVM_ON_UNIX
429TEST(VirtualFileSystemTest, BrokenSymlinkRealFSRecursiveIteration) {
430 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
431 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
432
433 ScopedLink _a("no_such_file", TestDirectory + "/a");
434 ScopedDir _b(TestDirectory + "/b");
435 ScopedLink _ba("no_such_file", TestDirectory + "/b/a");
436 ScopedDir _bb(TestDirectory + "/b/b");
437 ScopedLink _bc("no_such_file", TestDirectory + "/b/c");
438 ScopedLink _c("no_such_file", TestDirectory + "/c");
439 ScopedDir _d(TestDirectory + "/d");
440 ScopedDir _dd(TestDirectory + "/d/d");
441 ScopedDir _ddd(TestDirectory + "/d/d/d");
442 ScopedLink _e("no_such_file", TestDirectory + "/e");
443 std::vector<StringRef> Expected = {_b, _bb, _d, _dd, _ddd};
444
445 std::vector<std::string> Contents;
446 std::error_code EC;
447 for (vfs::recursive_directory_iterator I(*FS, Twine(TestDirectory), EC), E;
448 I != E; I.increment(EC)) {
449 // Skip broken symlinks.
Juergen Ributzka53fda392017-03-14 17:46:26 +0000450 auto EC2 = std::make_error_code(std::errc::no_such_file_or_directory);
451 if (EC == EC2) {
452 EC.clear();
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000453 continue;
454 }
455 // For bot debugging.
456 if (EC) {
Juergen Ributzka53fda392017-03-14 17:46:26 +0000457 outs() << "Error code found:\n"
458 << "EC value: " << EC.value() << "\n"
459 << "EC category: " << EC.category().name()
460 << "EC message: " << EC.message() << "\n";
461
462 outs() << "Error code tested for:\n"
463 << "EC value: " << EC2.value() << "\n"
464 << "EC category: " << EC2.category().name()
465 << "EC message: " << EC2.message() << "\n";
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000466 }
467 ASSERT_FALSE(EC);
468 Contents.push_back(I->getName());
469 }
470
471 // Check sorted contents.
472 std::sort(Contents.begin(), Contents.end());
473 EXPECT_EQ(Expected.size(), Contents.size());
474 EXPECT_TRUE(std::equal(Contents.begin(), Contents.end(), Expected.begin()));
475}
476#endif
477
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000478template <typename DirIter>
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000479static void checkContents(DirIter I, ArrayRef<StringRef> ExpectedOut) {
Ben Langmuir740812b2014-06-24 19:37:16 +0000480 std::error_code EC;
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000481 SmallVector<StringRef, 4> Expected(ExpectedOut.begin(), ExpectedOut.end());
482 SmallVector<std::string, 4> InputToCheck;
Ben Langmuir740812b2014-06-24 19:37:16 +0000483
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000484 // Do not rely on iteration order to check for contents, sort both
485 // content vectors before comparison.
486 for (DirIter E; !EC && I != E; I.increment(EC))
487 InputToCheck.push_back(I->getName());
488
489 std::sort(InputToCheck.begin(), InputToCheck.end());
490 std::sort(Expected.begin(), Expected.end());
491 EXPECT_EQ(InputToCheck.size(), Expected.size());
492
493 unsigned LastElt = std::min(InputToCheck.size(), Expected.size());
494 for (unsigned Idx = 0; Idx != LastElt; ++Idx)
Bruno Cardoso Lopes2835c5c2016-05-12 19:13:04 +0000495 EXPECT_EQ(StringRef(InputToCheck[Idx]), Expected[Idx]);
Ben Langmuir740812b2014-06-24 19:37:16 +0000496}
497
498TEST(VirtualFileSystemTest, OverlayIteration) {
499 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
500 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
501 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
502 new vfs::OverlayFileSystem(Lower));
503 O->pushOverlay(Upper);
504
505 std::error_code EC;
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000506 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
Ben Langmuir740812b2014-06-24 19:37:16 +0000507
508 Lower->addRegularFile("/file1");
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000509 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file1"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000510
511 Upper->addRegularFile("/file2");
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000512 checkContents(O->dir_begin("/", EC), {"/file2", "/file1"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000513
514 Lower->addDirectory("/dir1");
515 Lower->addRegularFile("/dir1/foo");
516 Upper->addDirectory("/dir2");
517 Upper->addRegularFile("/dir2/foo");
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000518 checkContents(O->dir_begin("/dir2", EC), ArrayRef<StringRef>("/dir2/foo"));
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000519 checkContents(O->dir_begin("/", EC), {"/dir2", "/file2", "/dir1", "/file1"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000520}
521
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000522TEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
523 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
524 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
525 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
526 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
527 new vfs::OverlayFileSystem(Lower));
528 O->pushOverlay(Middle);
529 O->pushOverlay(Upper);
530
531 std::error_code EC;
532 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
533 ArrayRef<StringRef>());
534
535 Lower->addRegularFile("/file1");
536 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
537 ArrayRef<StringRef>("/file1"));
538
539 Upper->addDirectory("/dir");
540 Upper->addRegularFile("/dir/file2");
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000541 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
542 {"/dir", "/dir/file2", "/file1"});
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000543
544 Lower->addDirectory("/dir1");
545 Lower->addRegularFile("/dir1/foo");
546 Lower->addDirectory("/dir1/a");
547 Lower->addRegularFile("/dir1/a/b");
548 Middle->addDirectory("/a");
549 Middle->addDirectory("/a/b");
550 Middle->addDirectory("/a/b/c");
551 Middle->addRegularFile("/a/b/c/d");
552 Middle->addRegularFile("/hiddenByUp");
553 Upper->addDirectory("/dir2");
554 Upper->addRegularFile("/dir2/foo");
555 Upper->addRegularFile("/hiddenByUp");
556 checkContents(vfs::recursive_directory_iterator(*O, "/dir2", EC),
557 ArrayRef<StringRef>("/dir2/foo"));
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000558 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
559 {"/dir", "/dir/file2", "/dir2", "/dir2/foo", "/hiddenByUp",
560 "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
561 "/dir1/a/b", "/dir1/foo", "/file1"});
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000562}
563
Ben Langmuir740812b2014-06-24 19:37:16 +0000564TEST(VirtualFileSystemTest, ThreeLevelIteration) {
565 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
566 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
567 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
568 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
569 new vfs::OverlayFileSystem(Lower));
570 O->pushOverlay(Middle);
571 O->pushOverlay(Upper);
572
573 std::error_code EC;
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000574 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
Ben Langmuir740812b2014-06-24 19:37:16 +0000575
576 Middle->addRegularFile("/file2");
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000577 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file2"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000578
579 Lower->addRegularFile("/file1");
580 Upper->addRegularFile("/file3");
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000581 checkContents(O->dir_begin("/", EC), {"/file3", "/file2", "/file1"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000582}
583
584TEST(VirtualFileSystemTest, HiddenInIteration) {
585 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
586 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
587 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
588 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
589 new vfs::OverlayFileSystem(Lower));
590 O->pushOverlay(Middle);
591 O->pushOverlay(Upper);
592
593 std::error_code EC;
594 Lower->addRegularFile("/onlyInLow", sys::fs::owner_read);
595 Lower->addRegularFile("/hiddenByMid", sys::fs::owner_read);
596 Lower->addRegularFile("/hiddenByUp", sys::fs::owner_read);
597 Middle->addRegularFile("/onlyInMid", sys::fs::owner_write);
598 Middle->addRegularFile("/hiddenByMid", sys::fs::owner_write);
599 Middle->addRegularFile("/hiddenByUp", sys::fs::owner_write);
600 Upper->addRegularFile("/onlyInUp", sys::fs::owner_all);
601 Upper->addRegularFile("/hiddenByUp", sys::fs::owner_all);
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000602 checkContents(
603 O->dir_begin("/", EC),
604 {"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000605
606 // Make sure we get the top-most entry
Ben Langmuirefb8b602014-06-24 21:08:13 +0000607 {
608 std::error_code EC;
609 vfs::directory_iterator I = O->dir_begin("/", EC), E;
610 for ( ; !EC && I != E; I.increment(EC))
611 if (I->getName() == "/hiddenByUp")
612 break;
613 ASSERT_NE(E, I);
614 EXPECT_EQ(sys::fs::owner_all, I->getPermissions());
615 }
616 {
617 std::error_code EC;
618 vfs::directory_iterator I = O->dir_begin("/", EC), E;
619 for ( ; !EC && I != E; I.increment(EC))
620 if (I->getName() == "/hiddenByMid")
621 break;
622 ASSERT_NE(E, I);
623 EXPECT_EQ(sys::fs::owner_write, I->getPermissions());
624 }
Ben Langmuir740812b2014-06-24 19:37:16 +0000625}
626
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000627class InMemoryFileSystemTest : public ::testing::Test {
628protected:
629 clang::vfs::InMemoryFileSystem FS;
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000630 clang::vfs::InMemoryFileSystem NormalizedFS;
631
632 InMemoryFileSystemTest()
633 : FS(/*UseNormalizedPaths=*/false),
634 NormalizedFS(/*UseNormalizedPaths=*/true) {}
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000635};
636
637TEST_F(InMemoryFileSystemTest, IsEmpty) {
638 auto Stat = FS.status("/a");
Rafael Espindolab7ab1872015-10-05 20:20:50 +0000639 ASSERT_EQ(Stat.getError(),errc::no_such_file_or_directory) << FS.toString();
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000640 Stat = FS.status("/");
Rafael Espindolab7ab1872015-10-05 20:20:50 +0000641 ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000642}
643
644TEST_F(InMemoryFileSystemTest, WindowsPath) {
645 FS.addFile("c:/windows/system128/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
646 auto Stat = FS.status("c:");
NAKAMURA Takumi4c33a1a2015-10-06 12:16:27 +0000647#if !defined(_WIN32)
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000648 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
NAKAMURA Takumi4c33a1a2015-10-06 12:16:27 +0000649#endif
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000650 Stat = FS.status("c:/windows/system128/foo.cpp");
651 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
652 FS.addFile("d:/windows/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
653 Stat = FS.status("d:/windows/foo.cpp");
654 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
655}
656
657TEST_F(InMemoryFileSystemTest, OverlayFile) {
658 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000659 NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000660 auto Stat = FS.status("/");
661 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000662 Stat = FS.status("/.");
663 ASSERT_FALSE(Stat);
664 Stat = NormalizedFS.status("/.");
665 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000666 Stat = FS.status("/a");
667 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
668 ASSERT_EQ("/a", Stat->getName());
669}
670
Benjamin Kramer2e2351a2015-10-06 10:04:08 +0000671TEST_F(InMemoryFileSystemTest, OverlayFileNoOwn) {
672 auto Buf = MemoryBuffer::getMemBuffer("a");
673 FS.addFileNoOwn("/a", 0, Buf.get());
674 auto Stat = FS.status("/a");
675 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
676 ASSERT_EQ("/a", Stat->getName());
677}
678
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000679TEST_F(InMemoryFileSystemTest, OpenFileForRead) {
680 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000681 FS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
682 FS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
683 NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
684 NormalizedFS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
685 NormalizedFS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000686 auto File = FS.openFileForRead("/a");
687 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
688 File = FS.openFileForRead("/a"); // Open again.
689 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000690 File = NormalizedFS.openFileForRead("/././a"); // Open again.
691 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000692 File = FS.openFileForRead("/");
Rafael Espindolab7ab1872015-10-05 20:20:50 +0000693 ASSERT_EQ(File.getError(), errc::invalid_argument) << FS.toString();
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000694 File = FS.openFileForRead("/b");
Rafael Espindolab7ab1872015-10-05 20:20:50 +0000695 ASSERT_EQ(File.getError(), errc::no_such_file_or_directory) << FS.toString();
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000696 File = FS.openFileForRead("./c");
697 ASSERT_FALSE(File);
698 File = FS.openFileForRead("e/../d");
699 ASSERT_FALSE(File);
700 File = NormalizedFS.openFileForRead("./c");
Benjamin Kramerd5e0b582015-10-07 08:32:50 +0000701 ASSERT_EQ("c", (*(*File)->getBuffer("ignored"))->getBuffer());
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000702 File = NormalizedFS.openFileForRead("e/../d");
703 ASSERT_EQ("d", (*(*File)->getBuffer("ignored"))->getBuffer());
704}
705
706TEST_F(InMemoryFileSystemTest, DuplicatedFile) {
707 ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
708 ASSERT_FALSE(FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("a")));
709 ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
710 ASSERT_FALSE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("b")));
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000711}
712
713TEST_F(InMemoryFileSystemTest, DirectoryIteration) {
714 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""));
715 FS.addFile("/b/c", 0, MemoryBuffer::getMemBuffer(""));
716
717 std::error_code EC;
718 vfs::directory_iterator I = FS.dir_begin("/", EC);
719 ASSERT_FALSE(EC);
720 ASSERT_EQ("/a", I->getName());
721 I.increment(EC);
722 ASSERT_FALSE(EC);
723 ASSERT_EQ("/b", I->getName());
724 I.increment(EC);
725 ASSERT_FALSE(EC);
726 ASSERT_EQ(vfs::directory_iterator(), I);
727
728 I = FS.dir_begin("/b", EC);
729 ASSERT_FALSE(EC);
730 ASSERT_EQ("/b/c", I->getName());
731 I.increment(EC);
732 ASSERT_FALSE(EC);
733 ASSERT_EQ(vfs::directory_iterator(), I);
734}
735
Benjamin Kramer1b8dbe32015-10-06 14:45:16 +0000736TEST_F(InMemoryFileSystemTest, WorkingDirectory) {
737 FS.setCurrentWorkingDirectory("/b");
738 FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
739
740 auto Stat = FS.status("/b/c");
741 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
742 ASSERT_EQ("c", Stat->getName());
743 ASSERT_EQ("/b", *FS.getCurrentWorkingDirectory());
744
745 Stat = FS.status("c");
746 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
Benjamin Kramere9e76072016-01-09 16:33:16 +0000747
Benjamin Kramer730338b2016-01-10 10:36:59 +0000748 auto ReplaceBackslashes = [](std::string S) {
749 std::replace(S.begin(), S.end(), '\\', '/');
750 return S;
751 };
Benjamin Kramere9e76072016-01-09 16:33:16 +0000752 NormalizedFS.setCurrentWorkingDirectory("/b/c");
753 NormalizedFS.setCurrentWorkingDirectory(".");
Benjamin Kramer730338b2016-01-10 10:36:59 +0000754 ASSERT_EQ("/b/c", ReplaceBackslashes(
755 NormalizedFS.getCurrentWorkingDirectory().get()));
Benjamin Kramere9e76072016-01-09 16:33:16 +0000756 NormalizedFS.setCurrentWorkingDirectory("..");
Benjamin Kramer730338b2016-01-10 10:36:59 +0000757 ASSERT_EQ("/b", ReplaceBackslashes(
758 NormalizedFS.getCurrentWorkingDirectory().get()));
Benjamin Kramer1b8dbe32015-10-06 14:45:16 +0000759}
760
Ben Langmuir93853232014-03-05 21:32:20 +0000761// NOTE: in the tests below, we use '//root/' as our root directory, since it is
762// a legal *absolute* path on Windows as well as *nix.
Ben Langmuir97882e72014-02-24 20:56:37 +0000763class VFSFromYAMLTest : public ::testing::Test {
764public:
765 int NumDiagnostics;
Ben Langmuir93853232014-03-05 21:32:20 +0000766
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000767 void SetUp() override { NumDiagnostics = 0; }
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000768
Ben Langmuir97882e72014-02-24 20:56:37 +0000769 static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
770 VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
771 ++Test->NumDiagnostics;
772 }
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000773
Ben Langmuir97882e72014-02-24 20:56:37 +0000774 IntrusiveRefCntPtr<vfs::FileSystem>
775 getFromYAMLRawString(StringRef Content,
776 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
Rafael Espindolad87f8d72014-08-27 20:03:29 +0000777 std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content);
Bruno Cardoso Lopesd878e282016-03-20 02:08:48 +0000778 return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, "", this,
Rafael Espindola91ac8df2014-08-17 23:27:13 +0000779 ExternalFS);
Ben Langmuir97882e72014-02-24 20:56:37 +0000780 }
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000781
Ben Langmuir97882e72014-02-24 20:56:37 +0000782 IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
783 StringRef Content,
784 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
785 std::string VersionPlusContent("{\n 'version':0,\n");
786 VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
787 return getFromYAMLRawString(VersionPlusContent, ExternalFS);
788 }
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +0000789
790 // This is intended as a "XFAIL" for windows hosts.
791 bool supportsSameDirMultipleYAMLEntries() {
792 Triple Host(Triple::normalize(sys::getProcessTriple()));
793 return !Host.isOSWindows();
794 }
Ben Langmuir97882e72014-02-24 20:56:37 +0000795};
796
797TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000798 IntrusiveRefCntPtr<vfs::FileSystem> FS;
799 FS = getFromYAMLString("");
Alp Tokerf994cef2014-07-05 03:08:06 +0000800 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000801 FS = getFromYAMLString("[]");
Alp Tokerf994cef2014-07-05 03:08:06 +0000802 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000803 FS = getFromYAMLString("'string'");
Alp Tokerf994cef2014-07-05 03:08:06 +0000804 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000805 EXPECT_EQ(3, NumDiagnostics);
806}
807
Ben Langmuir97882e72014-02-24 20:56:37 +0000808TEST_F(VFSFromYAMLTest, MappedFiles) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000809 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +0000810 Lower->addRegularFile("//root/foo/bar/a");
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000811 IntrusiveRefCntPtr<vfs::FileSystem> FS =
812 getFromYAMLString("{ 'roots': [\n"
813 "{\n"
814 " 'type': 'directory',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000815 " 'name': '//root/',\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000816 " 'contents': [ {\n"
817 " 'type': 'file',\n"
818 " 'name': 'file1',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000819 " 'external-contents': '//root/foo/bar/a'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000820 " },\n"
821 " {\n"
822 " 'type': 'file',\n"
823 " 'name': 'file2',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000824 " 'external-contents': '//root/foo/b'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000825 " }\n"
826 " ]\n"
827 "}\n"
828 "]\n"
829 "}",
830 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000831 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000832
833 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
834 new vfs::OverlayFileSystem(Lower));
835 O->pushOverlay(FS);
836
837 // file
Ben Langmuir93853232014-03-05 21:32:20 +0000838 ErrorOr<vfs::Status> S = O->status("//root/file1");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000839 ASSERT_FALSE(S.getError());
Ben Langmuir93853232014-03-05 21:32:20 +0000840 EXPECT_EQ("//root/foo/bar/a", S->getName());
Ben Langmuirf13302e2015-12-10 23:41:39 +0000841 EXPECT_TRUE(S->IsVFSMapped);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000842
Ben Langmuir93853232014-03-05 21:32:20 +0000843 ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
844 EXPECT_EQ("//root/foo/bar/a", SLower->getName());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000845 EXPECT_TRUE(S->equivalent(*SLower));
Ben Langmuirf13302e2015-12-10 23:41:39 +0000846 EXPECT_FALSE(SLower->IsVFSMapped);
847
848 // file after opening
849 auto OpenedF = O->openFileForRead("//root/file1");
850 ASSERT_FALSE(OpenedF.getError());
851 auto OpenedS = (*OpenedF)->status();
852 ASSERT_FALSE(OpenedS.getError());
853 EXPECT_EQ("//root/foo/bar/a", OpenedS->getName());
854 EXPECT_TRUE(OpenedS->IsVFSMapped);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000855
856 // directory
Ben Langmuir93853232014-03-05 21:32:20 +0000857 S = O->status("//root/");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000858 ASSERT_FALSE(S.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000859 EXPECT_TRUE(S->isDirectory());
Ben Langmuir93853232014-03-05 21:32:20 +0000860 EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000861
862 // broken mapping
Rafael Espindola71de0b62014-06-13 17:20:50 +0000863 EXPECT_EQ(O->status("//root/file2").getError(),
864 llvm::errc::no_such_file_or_directory);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000865 EXPECT_EQ(0, NumDiagnostics);
866}
867
Ben Langmuir97882e72014-02-24 20:56:37 +0000868TEST_F(VFSFromYAMLTest, CaseInsensitive) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000869 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +0000870 Lower->addRegularFile("//root/foo/bar/a");
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000871 IntrusiveRefCntPtr<vfs::FileSystem> FS =
872 getFromYAMLString("{ 'case-sensitive': 'false',\n"
873 " 'roots': [\n"
874 "{\n"
875 " 'type': 'directory',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000876 " 'name': '//root/',\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000877 " 'contents': [ {\n"
878 " 'type': 'file',\n"
879 " 'name': 'XX',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000880 " 'external-contents': '//root/foo/bar/a'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000881 " }\n"
882 " ]\n"
883 "}]}",
884 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000885 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000886
887 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
888 new vfs::OverlayFileSystem(Lower));
889 O->pushOverlay(FS);
890
Ben Langmuir93853232014-03-05 21:32:20 +0000891 ErrorOr<vfs::Status> S = O->status("//root/XX");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000892 ASSERT_FALSE(S.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000893
Ben Langmuir93853232014-03-05 21:32:20 +0000894 ErrorOr<vfs::Status> SS = O->status("//root/xx");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000895 ASSERT_FALSE(SS.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000896 EXPECT_TRUE(S->equivalent(*SS));
Ben Langmuir93853232014-03-05 21:32:20 +0000897 SS = O->status("//root/xX");
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000898 EXPECT_TRUE(S->equivalent(*SS));
Ben Langmuir93853232014-03-05 21:32:20 +0000899 SS = O->status("//root/Xx");
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000900 EXPECT_TRUE(S->equivalent(*SS));
901 EXPECT_EQ(0, NumDiagnostics);
902}
903
Ben Langmuir97882e72014-02-24 20:56:37 +0000904TEST_F(VFSFromYAMLTest, CaseSensitive) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000905 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +0000906 Lower->addRegularFile("//root/foo/bar/a");
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000907 IntrusiveRefCntPtr<vfs::FileSystem> FS =
908 getFromYAMLString("{ 'case-sensitive': 'true',\n"
909 " 'roots': [\n"
910 "{\n"
911 " 'type': 'directory',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000912 " 'name': '//root/',\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000913 " 'contents': [ {\n"
914 " 'type': 'file',\n"
915 " 'name': 'XX',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000916 " 'external-contents': '//root/foo/bar/a'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000917 " }\n"
918 " ]\n"
919 "}]}",
920 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000921 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000922
923 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
924 new vfs::OverlayFileSystem(Lower));
925 O->pushOverlay(FS);
926
Ben Langmuir93853232014-03-05 21:32:20 +0000927 ErrorOr<vfs::Status> SS = O->status("//root/xx");
Rafael Espindola71de0b62014-06-13 17:20:50 +0000928 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuir93853232014-03-05 21:32:20 +0000929 SS = O->status("//root/xX");
Rafael Espindola71de0b62014-06-13 17:20:50 +0000930 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuir93853232014-03-05 21:32:20 +0000931 SS = O->status("//root/Xx");
Rafael Espindola71de0b62014-06-13 17:20:50 +0000932 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000933 EXPECT_EQ(0, NumDiagnostics);
934}
935
Ben Langmuir97882e72014-02-24 20:56:37 +0000936TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000937 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
938
939 // invalid YAML at top-level
940 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000941 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000942 // invalid YAML in roots
943 FS = getFromYAMLString("{ 'roots':[}", Lower);
944 // invalid YAML in directory
945 FS = getFromYAMLString(
946 "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
947 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000948 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000949
950 // invalid configuration
951 FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000952 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000953 FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000954 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000955
956 // invalid roots
957 FS = getFromYAMLString("{ 'roots':'' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000958 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000959 FS = getFromYAMLString("{ 'roots':{} }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000960 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000961
962 // invalid entries
963 FS = getFromYAMLString(
964 "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000965 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000966 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
967 "'external-contents': 'other' }",
968 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000969 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000970 FS = getFromYAMLString(
971 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
972 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000973 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000974 FS = getFromYAMLString(
975 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
976 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000977 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000978 FS = getFromYAMLString(
979 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
980 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000981 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000982 FS = getFromYAMLString(
983 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
984 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000985 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000986 FS = getFromYAMLString(
987 "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
988 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000989 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000990
991 // missing mandatory fields
992 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000993 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000994 FS = getFromYAMLString(
995 "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000996 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000997 FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000998 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000999
1000 // duplicate keys
1001 FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001002 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001003 FS = getFromYAMLString(
1004 "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
1005 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001006 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001007 FS =
1008 getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
1009 "'external-contents':'blah' } ] }",
1010 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001011 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001012
1013 // missing version
1014 FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001015 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001016
1017 // bad version number
1018 FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001019 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001020 FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001021 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001022 FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001023 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001024 EXPECT_EQ(24, NumDiagnostics);
1025}
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001026
Ben Langmuirb59cf672014-02-27 00:25:12 +00001027TEST_F(VFSFromYAMLTest, UseExternalName) {
1028 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001029 Lower->addRegularFile("//root/external/file");
Ben Langmuirb59cf672014-02-27 00:25:12 +00001030
1031 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1032 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001033 " { 'type': 'file', 'name': '//root/A',\n"
1034 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001035 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001036 " { 'type': 'file', 'name': '//root/B',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001037 " 'use-external-name': true,\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001038 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001039 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001040 " { 'type': 'file', 'name': '//root/C',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001041 " 'use-external-name': false,\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001042 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001043 " }\n"
1044 "] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001045 ASSERT_TRUE(nullptr != FS.get());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001046
1047 // default true
Ben Langmuir93853232014-03-05 21:32:20 +00001048 EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001049 // explicit
Ben Langmuir93853232014-03-05 21:32:20 +00001050 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1051 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001052
1053 // global configuration
1054 FS = getFromYAMLString(
1055 "{ 'use-external-names': false,\n"
1056 " 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001057 " { 'type': 'file', 'name': '//root/A',\n"
1058 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001059 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001060 " { 'type': 'file', 'name': '//root/B',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001061 " 'use-external-name': true,\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001062 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001063 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001064 " { 'type': 'file', 'name': '//root/C',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001065 " 'use-external-name': false,\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001066 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001067 " }\n"
1068 "] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001069 ASSERT_TRUE(nullptr != FS.get());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001070
1071 // default
Ben Langmuir93853232014-03-05 21:32:20 +00001072 EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001073 // explicit
Ben Langmuir93853232014-03-05 21:32:20 +00001074 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1075 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001076}
1077
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001078TEST_F(VFSFromYAMLTest, MultiComponentPath) {
1079 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001080 Lower->addRegularFile("//root/other");
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001081
1082 // file in roots
1083 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1084 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001085 " { 'type': 'file', 'name': '//root/path/to/file',\n"
1086 " 'external-contents': '//root/other' }]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001087 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001088 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001089 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1090 EXPECT_FALSE(FS->status("//root/path/to").getError());
1091 EXPECT_FALSE(FS->status("//root/path").getError());
1092 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001093
1094 // at the start
1095 FS = getFromYAMLString(
1096 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001097 " { 'type': 'directory', 'name': '//root/path/to',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001098 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001099 " 'external-contents': '//root/other' }]}]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001100 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001101 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001102 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1103 EXPECT_FALSE(FS->status("//root/path/to").getError());
1104 EXPECT_FALSE(FS->status("//root/path").getError());
1105 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001106
1107 // at the end
1108 FS = getFromYAMLString(
1109 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001110 " { 'type': 'directory', 'name': '//root/',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001111 " 'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001112 " 'external-contents': '//root/other' }]}]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001113 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001114 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001115 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1116 EXPECT_FALSE(FS->status("//root/path/to").getError());
1117 EXPECT_FALSE(FS->status("//root/path").getError());
1118 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001119}
1120
1121TEST_F(VFSFromYAMLTest, TrailingSlashes) {
1122 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001123 Lower->addRegularFile("//root/other");
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001124
1125 // file in roots
1126 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1127 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001128 " { 'type': 'directory', 'name': '//root/path/to////',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001129 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001130 " 'external-contents': '//root/other' }]}]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001131 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001132 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001133 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1134 EXPECT_FALSE(FS->status("//root/path/to").getError());
1135 EXPECT_FALSE(FS->status("//root/path").getError());
1136 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001137}
Ben Langmuir740812b2014-06-24 19:37:16 +00001138
1139TEST_F(VFSFromYAMLTest, DirectoryIteration) {
1140 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1141 Lower->addDirectory("//root/");
1142 Lower->addDirectory("//root/foo");
1143 Lower->addDirectory("//root/foo/bar");
1144 Lower->addRegularFile("//root/foo/bar/a");
1145 Lower->addRegularFile("//root/foo/bar/b");
1146 Lower->addRegularFile("//root/file3");
1147 IntrusiveRefCntPtr<vfs::FileSystem> FS =
1148 getFromYAMLString("{ 'use-external-names': false,\n"
1149 " 'roots': [\n"
1150 "{\n"
1151 " 'type': 'directory',\n"
1152 " 'name': '//root/',\n"
1153 " 'contents': [ {\n"
1154 " 'type': 'file',\n"
1155 " 'name': 'file1',\n"
1156 " 'external-contents': '//root/foo/bar/a'\n"
1157 " },\n"
1158 " {\n"
1159 " 'type': 'file',\n"
1160 " 'name': 'file2',\n"
1161 " 'external-contents': '//root/foo/bar/b'\n"
1162 " }\n"
1163 " ]\n"
1164 "}\n"
1165 "]\n"
1166 "}",
1167 Lower);
Hans Wennborgdcfba332015-10-06 23:40:43 +00001168 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuir740812b2014-06-24 19:37:16 +00001169
1170 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1171 new vfs::OverlayFileSystem(Lower));
1172 O->pushOverlay(FS);
1173
1174 std::error_code EC;
Benjamin Kramer2a23e552016-01-10 10:45:19 +00001175 checkContents(O->dir_begin("//root/", EC),
Bruno Cardoso Lopes26092b22016-05-12 04:43:27 +00001176 {"//root/file1", "//root/file2", "//root/file3", "//root/foo"});
Ben Langmuir740812b2014-06-24 19:37:16 +00001177
Benjamin Kramer2a23e552016-01-10 10:45:19 +00001178 checkContents(O->dir_begin("//root/foo/bar", EC),
1179 {"//root/foo/bar/a", "//root/foo/bar/b"});
Ben Langmuir740812b2014-06-24 19:37:16 +00001180}
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +00001181
1182TEST_F(VFSFromYAMLTest, DirectoryIterationSameDirMultipleEntries) {
1183 // https://llvm.org/bugs/show_bug.cgi?id=27725
1184 if (!supportsSameDirMultipleYAMLEntries())
1185 return;
1186
1187 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1188 Lower->addDirectory("//root/zab");
1189 Lower->addDirectory("//root/baz");
1190 Lower->addRegularFile("//root/zab/a");
1191 Lower->addRegularFile("//root/zab/b");
1192 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1193 "{ 'use-external-names': false,\n"
1194 " 'roots': [\n"
1195 "{\n"
1196 " 'type': 'directory',\n"
1197 " 'name': '//root/baz/',\n"
1198 " 'contents': [ {\n"
1199 " 'type': 'file',\n"
1200 " 'name': 'x',\n"
1201 " 'external-contents': '//root/zab/a'\n"
1202 " }\n"
1203 " ]\n"
1204 "},\n"
1205 "{\n"
1206 " 'type': 'directory',\n"
1207 " 'name': '//root/baz/',\n"
1208 " 'contents': [ {\n"
1209 " 'type': 'file',\n"
1210 " 'name': 'y',\n"
1211 " 'external-contents': '//root/zab/b'\n"
1212 " }\n"
1213 " ]\n"
1214 "}\n"
1215 "]\n"
1216 "}",
1217 Lower);
1218 ASSERT_TRUE(FS.get() != nullptr);
1219
1220 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1221 new vfs::OverlayFileSystem(Lower));
1222 O->pushOverlay(FS);
1223
1224 std::error_code EC;
1225
1226 checkContents(O->dir_begin("//root/baz/", EC),
1227 {"//root/baz/x", "//root/baz/y"});
1228}
Bruno Cardoso Lopes32b28972016-05-14 00:00:18 +00001229
1230TEST_F(VFSFromYAMLTest, RecursiveDirectoryIterationLevel) {
1231
1232 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1233 Lower->addDirectory("//root/a");
1234 Lower->addDirectory("//root/a/b");
1235 Lower->addDirectory("//root/a/b/c");
1236 Lower->addRegularFile("//root/a/b/c/file");
1237 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1238 "{ 'use-external-names': false,\n"
1239 " 'roots': [\n"
1240 "{\n"
1241 " 'type': 'directory',\n"
1242 " 'name': '//root/a/b/c/',\n"
1243 " 'contents': [ {\n"
1244 " 'type': 'file',\n"
1245 " 'name': 'file',\n"
1246 " 'external-contents': '//root/a/b/c/file'\n"
1247 " }\n"
1248 " ]\n"
1249 "},\n"
1250 "]\n"
1251 "}",
1252 Lower);
1253 ASSERT_TRUE(FS.get() != nullptr);
1254
1255 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1256 new vfs::OverlayFileSystem(Lower));
1257 O->pushOverlay(FS);
1258
1259 std::error_code EC;
1260
1261 // Test recursive_directory_iterator level()
1262 vfs::recursive_directory_iterator I = vfs::recursive_directory_iterator(
1263 *O, "//root", EC), E;
1264 ASSERT_FALSE(EC);
1265 for (int l = 0; I != E; I.increment(EC), ++l) {
1266 ASSERT_FALSE(EC);
1267 EXPECT_EQ(I.level(), l);
1268 }
1269 EXPECT_EQ(I, E);
1270}