blob: 40add2195b586a0749eaa7a87cd65ef3a3fa0208 [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() {
Galina Kistanova45fbb592017-06-15 21:01:24 +0000303 if (Path != "") {
Ben Langmuir740812b2014-06-24 19:37:16 +0000304 EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
Galina Kistanova45fbb592017-06-15 21:01:24 +0000305 }
Ben Langmuir740812b2014-06-24 19:37:16 +0000306 }
307 operator StringRef() { return Path.str(); }
308};
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000309
310struct ScopedLink {
311 SmallString<128> Path;
312 ScopedLink(const Twine &To, const Twine &From) {
313 Path = From.str();
314 std::error_code EC = sys::fs::create_link(To, From);
315 if (EC)
316 Path = "";
317 EXPECT_FALSE(EC);
318 }
319 ~ScopedLink() {
Galina Kistanova45fbb592017-06-15 21:01:24 +0000320 if (Path != "") {
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000321 EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
Galina Kistanova45fbb592017-06-15 21:01:24 +0000322 }
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000323 }
324 operator StringRef() { return Path.str(); }
325};
Hans Wennborgdcfba332015-10-06 23:40:43 +0000326} // end anonymous namespace
Ben Langmuir740812b2014-06-24 19:37:16 +0000327
328TEST(VirtualFileSystemTest, BasicRealFSIteration) {
329 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
330 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
331
332 std::error_code EC;
333 vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC);
334 ASSERT_FALSE(EC);
335 EXPECT_EQ(vfs::directory_iterator(), I); // empty directory is empty
336
337 ScopedDir _a(TestDirectory+"/a");
338 ScopedDir _ab(TestDirectory+"/a/b");
339 ScopedDir _c(TestDirectory+"/c");
340 ScopedDir _cd(TestDirectory+"/c/d");
341
342 I = FS->dir_begin(Twine(TestDirectory), EC);
343 ASSERT_FALSE(EC);
344 ASSERT_NE(vfs::directory_iterator(), I);
Ben Langmuirefb8b602014-06-24 21:08:13 +0000345 // Check either a or c, since we can't rely on the iteration order.
346 EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000347 I.increment(EC);
348 ASSERT_FALSE(EC);
349 ASSERT_NE(vfs::directory_iterator(), I);
Ben Langmuirefb8b602014-06-24 21:08:13 +0000350 EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000351 I.increment(EC);
352 EXPECT_EQ(vfs::directory_iterator(), I);
353}
354
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000355#ifdef LLVM_ON_UNIX
356TEST(VirtualFileSystemTest, BrokenSymlinkRealFSIteration) {
357 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
358 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
359
360 ScopedLink _a("no_such_file", TestDirectory + "/a");
361 ScopedDir _b(TestDirectory + "/b");
362 ScopedLink _c("no_such_file", TestDirectory + "/c");
363
364 std::error_code EC;
365 for (vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC), E;
366 I != E; I.increment(EC)) {
367 // Skip broken symlinks.
Juergen Ributzka53fda392017-03-14 17:46:26 +0000368 auto EC2 = std::make_error_code(std::errc::no_such_file_or_directory);
369 if (EC == EC2) {
370 EC.clear();
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000371 continue;
372 }
373 // For bot debugging.
374 if (EC) {
Juergen Ributzka53fda392017-03-14 17:46:26 +0000375 outs() << "Error code found:\n"
376 << "EC value: " << EC.value() << "\n"
377 << "EC category: " << EC.category().name()
378 << "EC message: " << EC.message() << "\n";
379
380 outs() << "Error code tested for:\n"
381 << "EC value: " << EC2.value() << "\n"
382 << "EC category: " << EC2.category().name()
383 << "EC message: " << EC2.message() << "\n";
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000384 }
385 ASSERT_FALSE(EC);
386 EXPECT_TRUE(I->getName() == _b);
387 }
388}
389#endif
390
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000391TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
392 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
393 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
394
395 std::error_code EC;
396 auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
397 ASSERT_FALSE(EC);
398 EXPECT_EQ(vfs::recursive_directory_iterator(), I); // empty directory is empty
399
400 ScopedDir _a(TestDirectory+"/a");
401 ScopedDir _ab(TestDirectory+"/a/b");
402 ScopedDir _c(TestDirectory+"/c");
403 ScopedDir _cd(TestDirectory+"/c/d");
404
405 I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
406 ASSERT_FALSE(EC);
407 ASSERT_NE(vfs::recursive_directory_iterator(), I);
408
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000409 std::vector<std::string> Contents;
410 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
411 I.increment(EC)) {
412 Contents.push_back(I->getName());
413 }
414
415 // Check contents, which may be in any order
416 EXPECT_EQ(4U, Contents.size());
417 int Counts[4] = { 0, 0, 0, 0 };
418 for (const std::string &Name : Contents) {
419 ASSERT_FALSE(Name.empty());
420 int Index = Name[Name.size()-1] - 'a';
421 ASSERT_TRUE(Index >= 0 && Index < 4);
422 Counts[Index]++;
423 }
424 EXPECT_EQ(1, Counts[0]); // a
425 EXPECT_EQ(1, Counts[1]); // b
426 EXPECT_EQ(1, Counts[2]); // c
427 EXPECT_EQ(1, Counts[3]); // d
428}
429
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000430#ifdef LLVM_ON_UNIX
431TEST(VirtualFileSystemTest, BrokenSymlinkRealFSRecursiveIteration) {
432 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
433 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
434
435 ScopedLink _a("no_such_file", TestDirectory + "/a");
436 ScopedDir _b(TestDirectory + "/b");
437 ScopedLink _ba("no_such_file", TestDirectory + "/b/a");
438 ScopedDir _bb(TestDirectory + "/b/b");
439 ScopedLink _bc("no_such_file", TestDirectory + "/b/c");
440 ScopedLink _c("no_such_file", TestDirectory + "/c");
441 ScopedDir _d(TestDirectory + "/d");
442 ScopedDir _dd(TestDirectory + "/d/d");
443 ScopedDir _ddd(TestDirectory + "/d/d/d");
444 ScopedLink _e("no_such_file", TestDirectory + "/e");
445 std::vector<StringRef> Expected = {_b, _bb, _d, _dd, _ddd};
446
447 std::vector<std::string> Contents;
448 std::error_code EC;
449 for (vfs::recursive_directory_iterator I(*FS, Twine(TestDirectory), EC), E;
450 I != E; I.increment(EC)) {
451 // Skip broken symlinks.
Juergen Ributzka53fda392017-03-14 17:46:26 +0000452 auto EC2 = std::make_error_code(std::errc::no_such_file_or_directory);
453 if (EC == EC2) {
454 EC.clear();
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000455 continue;
456 }
457 // For bot debugging.
458 if (EC) {
Juergen Ributzka53fda392017-03-14 17:46:26 +0000459 outs() << "Error code found:\n"
460 << "EC value: " << EC.value() << "\n"
461 << "EC category: " << EC.category().name()
462 << "EC message: " << EC.message() << "\n";
463
464 outs() << "Error code tested for:\n"
465 << "EC value: " << EC2.value() << "\n"
466 << "EC category: " << EC2.category().name()
467 << "EC message: " << EC2.message() << "\n";
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000468 }
469 ASSERT_FALSE(EC);
470 Contents.push_back(I->getName());
471 }
472
473 // Check sorted contents.
474 std::sort(Contents.begin(), Contents.end());
475 EXPECT_EQ(Expected.size(), Contents.size());
476 EXPECT_TRUE(std::equal(Contents.begin(), Contents.end(), Expected.begin()));
477}
478#endif
479
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000480template <typename DirIter>
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000481static void checkContents(DirIter I, ArrayRef<StringRef> ExpectedOut) {
Ben Langmuir740812b2014-06-24 19:37:16 +0000482 std::error_code EC;
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000483 SmallVector<StringRef, 4> Expected(ExpectedOut.begin(), ExpectedOut.end());
484 SmallVector<std::string, 4> InputToCheck;
Ben Langmuir740812b2014-06-24 19:37:16 +0000485
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000486 // Do not rely on iteration order to check for contents, sort both
487 // content vectors before comparison.
488 for (DirIter E; !EC && I != E; I.increment(EC))
489 InputToCheck.push_back(I->getName());
490
491 std::sort(InputToCheck.begin(), InputToCheck.end());
492 std::sort(Expected.begin(), Expected.end());
493 EXPECT_EQ(InputToCheck.size(), Expected.size());
494
495 unsigned LastElt = std::min(InputToCheck.size(), Expected.size());
496 for (unsigned Idx = 0; Idx != LastElt; ++Idx)
Bruno Cardoso Lopes2835c5c2016-05-12 19:13:04 +0000497 EXPECT_EQ(StringRef(InputToCheck[Idx]), Expected[Idx]);
Ben Langmuir740812b2014-06-24 19:37:16 +0000498}
499
500TEST(VirtualFileSystemTest, OverlayIteration) {
501 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
502 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
503 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
504 new vfs::OverlayFileSystem(Lower));
505 O->pushOverlay(Upper);
506
507 std::error_code EC;
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000508 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
Ben Langmuir740812b2014-06-24 19:37:16 +0000509
510 Lower->addRegularFile("/file1");
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000511 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file1"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000512
513 Upper->addRegularFile("/file2");
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000514 checkContents(O->dir_begin("/", EC), {"/file2", "/file1"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000515
516 Lower->addDirectory("/dir1");
517 Lower->addRegularFile("/dir1/foo");
518 Upper->addDirectory("/dir2");
519 Upper->addRegularFile("/dir2/foo");
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000520 checkContents(O->dir_begin("/dir2", EC), ArrayRef<StringRef>("/dir2/foo"));
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000521 checkContents(O->dir_begin("/", EC), {"/dir2", "/file2", "/dir1", "/file1"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000522}
523
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000524TEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
525 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
526 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
527 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
528 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
529 new vfs::OverlayFileSystem(Lower));
530 O->pushOverlay(Middle);
531 O->pushOverlay(Upper);
532
533 std::error_code EC;
534 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
535 ArrayRef<StringRef>());
536
537 Lower->addRegularFile("/file1");
538 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
539 ArrayRef<StringRef>("/file1"));
540
541 Upper->addDirectory("/dir");
542 Upper->addRegularFile("/dir/file2");
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000543 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
544 {"/dir", "/dir/file2", "/file1"});
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000545
546 Lower->addDirectory("/dir1");
547 Lower->addRegularFile("/dir1/foo");
548 Lower->addDirectory("/dir1/a");
549 Lower->addRegularFile("/dir1/a/b");
550 Middle->addDirectory("/a");
551 Middle->addDirectory("/a/b");
552 Middle->addDirectory("/a/b/c");
553 Middle->addRegularFile("/a/b/c/d");
554 Middle->addRegularFile("/hiddenByUp");
555 Upper->addDirectory("/dir2");
556 Upper->addRegularFile("/dir2/foo");
557 Upper->addRegularFile("/hiddenByUp");
558 checkContents(vfs::recursive_directory_iterator(*O, "/dir2", EC),
559 ArrayRef<StringRef>("/dir2/foo"));
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000560 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
561 {"/dir", "/dir/file2", "/dir2", "/dir2/foo", "/hiddenByUp",
562 "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
563 "/dir1/a/b", "/dir1/foo", "/file1"});
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000564}
565
Ben Langmuir740812b2014-06-24 19:37:16 +0000566TEST(VirtualFileSystemTest, ThreeLevelIteration) {
567 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
568 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
569 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
570 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
571 new vfs::OverlayFileSystem(Lower));
572 O->pushOverlay(Middle);
573 O->pushOverlay(Upper);
574
575 std::error_code EC;
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000576 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
Ben Langmuir740812b2014-06-24 19:37:16 +0000577
578 Middle->addRegularFile("/file2");
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000579 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file2"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000580
581 Lower->addRegularFile("/file1");
582 Upper->addRegularFile("/file3");
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000583 checkContents(O->dir_begin("/", EC), {"/file3", "/file2", "/file1"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000584}
585
586TEST(VirtualFileSystemTest, HiddenInIteration) {
587 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
588 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
589 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
590 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
591 new vfs::OverlayFileSystem(Lower));
592 O->pushOverlay(Middle);
593 O->pushOverlay(Upper);
594
595 std::error_code EC;
596 Lower->addRegularFile("/onlyInLow", sys::fs::owner_read);
597 Lower->addRegularFile("/hiddenByMid", sys::fs::owner_read);
598 Lower->addRegularFile("/hiddenByUp", sys::fs::owner_read);
599 Middle->addRegularFile("/onlyInMid", sys::fs::owner_write);
600 Middle->addRegularFile("/hiddenByMid", sys::fs::owner_write);
601 Middle->addRegularFile("/hiddenByUp", sys::fs::owner_write);
602 Upper->addRegularFile("/onlyInUp", sys::fs::owner_all);
603 Upper->addRegularFile("/hiddenByUp", sys::fs::owner_all);
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000604 checkContents(
605 O->dir_begin("/", EC),
606 {"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000607
608 // Make sure we get the top-most entry
Ben Langmuirefb8b602014-06-24 21:08:13 +0000609 {
610 std::error_code EC;
611 vfs::directory_iterator I = O->dir_begin("/", EC), E;
612 for ( ; !EC && I != E; I.increment(EC))
613 if (I->getName() == "/hiddenByUp")
614 break;
615 ASSERT_NE(E, I);
616 EXPECT_EQ(sys::fs::owner_all, I->getPermissions());
617 }
618 {
619 std::error_code EC;
620 vfs::directory_iterator I = O->dir_begin("/", EC), E;
621 for ( ; !EC && I != E; I.increment(EC))
622 if (I->getName() == "/hiddenByMid")
623 break;
624 ASSERT_NE(E, I);
625 EXPECT_EQ(sys::fs::owner_write, I->getPermissions());
626 }
Ben Langmuir740812b2014-06-24 19:37:16 +0000627}
628
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000629class InMemoryFileSystemTest : public ::testing::Test {
630protected:
631 clang::vfs::InMemoryFileSystem FS;
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000632 clang::vfs::InMemoryFileSystem NormalizedFS;
633
634 InMemoryFileSystemTest()
635 : FS(/*UseNormalizedPaths=*/false),
636 NormalizedFS(/*UseNormalizedPaths=*/true) {}
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000637};
638
639TEST_F(InMemoryFileSystemTest, IsEmpty) {
640 auto Stat = FS.status("/a");
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 Stat = FS.status("/");
Rafael Espindolab7ab1872015-10-05 20:20:50 +0000643 ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000644}
645
646TEST_F(InMemoryFileSystemTest, WindowsPath) {
647 FS.addFile("c:/windows/system128/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
648 auto Stat = FS.status("c:");
NAKAMURA Takumi4c33a1a2015-10-06 12:16:27 +0000649#if !defined(_WIN32)
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000650 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
NAKAMURA Takumi4c33a1a2015-10-06 12:16:27 +0000651#endif
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000652 Stat = FS.status("c:/windows/system128/foo.cpp");
653 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
654 FS.addFile("d:/windows/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
655 Stat = FS.status("d:/windows/foo.cpp");
656 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
657}
658
659TEST_F(InMemoryFileSystemTest, OverlayFile) {
660 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000661 NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000662 auto Stat = FS.status("/");
663 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000664 Stat = FS.status("/.");
665 ASSERT_FALSE(Stat);
666 Stat = NormalizedFS.status("/.");
667 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000668 Stat = FS.status("/a");
669 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
670 ASSERT_EQ("/a", Stat->getName());
671}
672
Benjamin Kramer2e2351a2015-10-06 10:04:08 +0000673TEST_F(InMemoryFileSystemTest, OverlayFileNoOwn) {
674 auto Buf = MemoryBuffer::getMemBuffer("a");
675 FS.addFileNoOwn("/a", 0, Buf.get());
676 auto Stat = FS.status("/a");
677 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
678 ASSERT_EQ("/a", Stat->getName());
679}
680
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000681TEST_F(InMemoryFileSystemTest, OpenFileForRead) {
682 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000683 FS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
684 FS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
685 NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
686 NormalizedFS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
687 NormalizedFS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000688 auto File = FS.openFileForRead("/a");
689 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
690 File = FS.openFileForRead("/a"); // Open again.
691 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000692 File = NormalizedFS.openFileForRead("/././a"); // Open again.
693 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000694 File = FS.openFileForRead("/");
Rafael Espindolab7ab1872015-10-05 20:20:50 +0000695 ASSERT_EQ(File.getError(), errc::invalid_argument) << FS.toString();
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000696 File = FS.openFileForRead("/b");
Rafael Espindolab7ab1872015-10-05 20:20:50 +0000697 ASSERT_EQ(File.getError(), errc::no_such_file_or_directory) << FS.toString();
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000698 File = FS.openFileForRead("./c");
699 ASSERT_FALSE(File);
700 File = FS.openFileForRead("e/../d");
701 ASSERT_FALSE(File);
702 File = NormalizedFS.openFileForRead("./c");
Benjamin Kramerd5e0b582015-10-07 08:32:50 +0000703 ASSERT_EQ("c", (*(*File)->getBuffer("ignored"))->getBuffer());
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000704 File = NormalizedFS.openFileForRead("e/../d");
705 ASSERT_EQ("d", (*(*File)->getBuffer("ignored"))->getBuffer());
706}
707
708TEST_F(InMemoryFileSystemTest, DuplicatedFile) {
709 ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
710 ASSERT_FALSE(FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("a")));
711 ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
712 ASSERT_FALSE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("b")));
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000713}
714
715TEST_F(InMemoryFileSystemTest, DirectoryIteration) {
716 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""));
717 FS.addFile("/b/c", 0, MemoryBuffer::getMemBuffer(""));
718
719 std::error_code EC;
720 vfs::directory_iterator I = FS.dir_begin("/", EC);
721 ASSERT_FALSE(EC);
722 ASSERT_EQ("/a", I->getName());
723 I.increment(EC);
724 ASSERT_FALSE(EC);
725 ASSERT_EQ("/b", I->getName());
726 I.increment(EC);
727 ASSERT_FALSE(EC);
728 ASSERT_EQ(vfs::directory_iterator(), I);
729
730 I = FS.dir_begin("/b", EC);
731 ASSERT_FALSE(EC);
732 ASSERT_EQ("/b/c", I->getName());
733 I.increment(EC);
734 ASSERT_FALSE(EC);
735 ASSERT_EQ(vfs::directory_iterator(), I);
736}
737
Benjamin Kramer1b8dbe32015-10-06 14:45:16 +0000738TEST_F(InMemoryFileSystemTest, WorkingDirectory) {
739 FS.setCurrentWorkingDirectory("/b");
740 FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
741
742 auto Stat = FS.status("/b/c");
743 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
744 ASSERT_EQ("c", Stat->getName());
745 ASSERT_EQ("/b", *FS.getCurrentWorkingDirectory());
746
747 Stat = FS.status("c");
748 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
Benjamin Kramere9e76072016-01-09 16:33:16 +0000749
Benjamin Kramer730338b2016-01-10 10:36:59 +0000750 auto ReplaceBackslashes = [](std::string S) {
751 std::replace(S.begin(), S.end(), '\\', '/');
752 return S;
753 };
Benjamin Kramere9e76072016-01-09 16:33:16 +0000754 NormalizedFS.setCurrentWorkingDirectory("/b/c");
755 NormalizedFS.setCurrentWorkingDirectory(".");
Benjamin Kramer730338b2016-01-10 10:36:59 +0000756 ASSERT_EQ("/b/c", ReplaceBackslashes(
757 NormalizedFS.getCurrentWorkingDirectory().get()));
Benjamin Kramere9e76072016-01-09 16:33:16 +0000758 NormalizedFS.setCurrentWorkingDirectory("..");
Benjamin Kramer730338b2016-01-10 10:36:59 +0000759 ASSERT_EQ("/b", ReplaceBackslashes(
760 NormalizedFS.getCurrentWorkingDirectory().get()));
Benjamin Kramer1b8dbe32015-10-06 14:45:16 +0000761}
762
Ben Langmuir93853232014-03-05 21:32:20 +0000763// NOTE: in the tests below, we use '//root/' as our root directory, since it is
764// a legal *absolute* path on Windows as well as *nix.
Ben Langmuir97882e72014-02-24 20:56:37 +0000765class VFSFromYAMLTest : public ::testing::Test {
766public:
767 int NumDiagnostics;
Ben Langmuir93853232014-03-05 21:32:20 +0000768
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000769 void SetUp() override { NumDiagnostics = 0; }
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000770
Ben Langmuir97882e72014-02-24 20:56:37 +0000771 static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
772 VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
773 ++Test->NumDiagnostics;
774 }
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000775
Ben Langmuir97882e72014-02-24 20:56:37 +0000776 IntrusiveRefCntPtr<vfs::FileSystem>
777 getFromYAMLRawString(StringRef Content,
778 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
Rafael Espindolad87f8d72014-08-27 20:03:29 +0000779 std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content);
Bruno Cardoso Lopesd878e282016-03-20 02:08:48 +0000780 return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, "", this,
Rafael Espindola91ac8df2014-08-17 23:27:13 +0000781 ExternalFS);
Ben Langmuir97882e72014-02-24 20:56:37 +0000782 }
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000783
Ben Langmuir97882e72014-02-24 20:56:37 +0000784 IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
785 StringRef Content,
786 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
787 std::string VersionPlusContent("{\n 'version':0,\n");
788 VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
789 return getFromYAMLRawString(VersionPlusContent, ExternalFS);
790 }
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +0000791
792 // This is intended as a "XFAIL" for windows hosts.
793 bool supportsSameDirMultipleYAMLEntries() {
794 Triple Host(Triple::normalize(sys::getProcessTriple()));
795 return !Host.isOSWindows();
796 }
Ben Langmuir97882e72014-02-24 20:56:37 +0000797};
798
799TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000800 IntrusiveRefCntPtr<vfs::FileSystem> FS;
801 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("[]");
Alp Tokerf994cef2014-07-05 03:08:06 +0000804 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000805 FS = getFromYAMLString("'string'");
Alp Tokerf994cef2014-07-05 03:08:06 +0000806 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000807 EXPECT_EQ(3, NumDiagnostics);
808}
809
Ben Langmuir97882e72014-02-24 20:56:37 +0000810TEST_F(VFSFromYAMLTest, MappedFiles) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000811 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +0000812 Lower->addRegularFile("//root/foo/bar/a");
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000813 IntrusiveRefCntPtr<vfs::FileSystem> FS =
814 getFromYAMLString("{ 'roots': [\n"
815 "{\n"
816 " 'type': 'directory',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000817 " 'name': '//root/',\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000818 " 'contents': [ {\n"
819 " 'type': 'file',\n"
820 " 'name': 'file1',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000821 " 'external-contents': '//root/foo/bar/a'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000822 " },\n"
823 " {\n"
824 " 'type': 'file',\n"
825 " 'name': 'file2',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000826 " 'external-contents': '//root/foo/b'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000827 " }\n"
828 " ]\n"
829 "}\n"
830 "]\n"
831 "}",
832 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000833 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000834
835 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
836 new vfs::OverlayFileSystem(Lower));
837 O->pushOverlay(FS);
838
839 // file
Ben Langmuir93853232014-03-05 21:32:20 +0000840 ErrorOr<vfs::Status> S = O->status("//root/file1");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000841 ASSERT_FALSE(S.getError());
Ben Langmuir93853232014-03-05 21:32:20 +0000842 EXPECT_EQ("//root/foo/bar/a", S->getName());
Ben Langmuirf13302e2015-12-10 23:41:39 +0000843 EXPECT_TRUE(S->IsVFSMapped);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000844
Ben Langmuir93853232014-03-05 21:32:20 +0000845 ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
846 EXPECT_EQ("//root/foo/bar/a", SLower->getName());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000847 EXPECT_TRUE(S->equivalent(*SLower));
Ben Langmuirf13302e2015-12-10 23:41:39 +0000848 EXPECT_FALSE(SLower->IsVFSMapped);
849
850 // file after opening
851 auto OpenedF = O->openFileForRead("//root/file1");
852 ASSERT_FALSE(OpenedF.getError());
853 auto OpenedS = (*OpenedF)->status();
854 ASSERT_FALSE(OpenedS.getError());
855 EXPECT_EQ("//root/foo/bar/a", OpenedS->getName());
856 EXPECT_TRUE(OpenedS->IsVFSMapped);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000857
858 // directory
Ben Langmuir93853232014-03-05 21:32:20 +0000859 S = O->status("//root/");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000860 ASSERT_FALSE(S.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000861 EXPECT_TRUE(S->isDirectory());
Ben Langmuir93853232014-03-05 21:32:20 +0000862 EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000863
864 // broken mapping
Rafael Espindola71de0b62014-06-13 17:20:50 +0000865 EXPECT_EQ(O->status("//root/file2").getError(),
866 llvm::errc::no_such_file_or_directory);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000867 EXPECT_EQ(0, NumDiagnostics);
868}
869
Ben Langmuir97882e72014-02-24 20:56:37 +0000870TEST_F(VFSFromYAMLTest, CaseInsensitive) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000871 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +0000872 Lower->addRegularFile("//root/foo/bar/a");
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000873 IntrusiveRefCntPtr<vfs::FileSystem> FS =
874 getFromYAMLString("{ 'case-sensitive': 'false',\n"
875 " 'roots': [\n"
876 "{\n"
877 " 'type': 'directory',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000878 " 'name': '//root/',\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000879 " 'contents': [ {\n"
880 " 'type': 'file',\n"
881 " 'name': 'XX',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000882 " 'external-contents': '//root/foo/bar/a'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000883 " }\n"
884 " ]\n"
885 "}]}",
886 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000887 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000888
889 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
890 new vfs::OverlayFileSystem(Lower));
891 O->pushOverlay(FS);
892
Ben Langmuir93853232014-03-05 21:32:20 +0000893 ErrorOr<vfs::Status> S = O->status("//root/XX");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000894 ASSERT_FALSE(S.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000895
Ben Langmuir93853232014-03-05 21:32:20 +0000896 ErrorOr<vfs::Status> SS = O->status("//root/xx");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000897 ASSERT_FALSE(SS.getError());
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));
Ben Langmuir93853232014-03-05 21:32:20 +0000901 SS = O->status("//root/Xx");
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000902 EXPECT_TRUE(S->equivalent(*SS));
903 EXPECT_EQ(0, NumDiagnostics);
904}
905
Ben Langmuir97882e72014-02-24 20:56:37 +0000906TEST_F(VFSFromYAMLTest, CaseSensitive) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000907 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +0000908 Lower->addRegularFile("//root/foo/bar/a");
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000909 IntrusiveRefCntPtr<vfs::FileSystem> FS =
910 getFromYAMLString("{ 'case-sensitive': 'true',\n"
911 " 'roots': [\n"
912 "{\n"
913 " 'type': 'directory',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000914 " 'name': '//root/',\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000915 " 'contents': [ {\n"
916 " 'type': 'file',\n"
917 " 'name': 'XX',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000918 " 'external-contents': '//root/foo/bar/a'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000919 " }\n"
920 " ]\n"
921 "}]}",
922 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000923 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000924
925 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
926 new vfs::OverlayFileSystem(Lower));
927 O->pushOverlay(FS);
928
Ben Langmuir93853232014-03-05 21:32:20 +0000929 ErrorOr<vfs::Status> 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 Langmuir93853232014-03-05 21:32:20 +0000933 SS = O->status("//root/Xx");
Rafael Espindola71de0b62014-06-13 17:20:50 +0000934 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000935 EXPECT_EQ(0, NumDiagnostics);
936}
937
Ben Langmuir97882e72014-02-24 20:56:37 +0000938TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000939 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
940
941 // invalid YAML at top-level
942 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000943 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000944 // invalid YAML in roots
945 FS = getFromYAMLString("{ 'roots':[}", Lower);
946 // invalid YAML in directory
947 FS = getFromYAMLString(
948 "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
949 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000950 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000951
952 // invalid configuration
953 FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000954 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000955 FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000956 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000957
958 // invalid roots
959 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 FS = getFromYAMLString("{ 'roots':{} }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000962 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000963
964 // invalid entries
965 FS = getFromYAMLString(
966 "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000967 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000968 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
969 "'external-contents': 'other' }",
970 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000971 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000972 FS = getFromYAMLString(
973 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
974 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000975 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000976 FS = getFromYAMLString(
977 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
978 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000979 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000980 FS = getFromYAMLString(
981 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
982 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000983 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000984 FS = getFromYAMLString(
985 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
986 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000987 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000988 FS = getFromYAMLString(
989 "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
990 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000991 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000992
993 // missing mandatory fields
994 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000995 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000996 FS = getFromYAMLString(
997 "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000998 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000999 FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001000 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001001
1002 // duplicate keys
1003 FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001004 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001005 FS = getFromYAMLString(
1006 "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
1007 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001008 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001009 FS =
1010 getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
1011 "'external-contents':'blah' } ] }",
1012 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001013 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001014
1015 // missing version
1016 FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001017 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001018
1019 // bad version number
1020 FS = getFromYAMLRawString("{ 'version':'foo', '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':-1, 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001023 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001024 FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001025 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001026 EXPECT_EQ(24, NumDiagnostics);
1027}
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001028
Ben Langmuirb59cf672014-02-27 00:25:12 +00001029TEST_F(VFSFromYAMLTest, UseExternalName) {
1030 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001031 Lower->addRegularFile("//root/external/file");
Ben Langmuirb59cf672014-02-27 00:25:12 +00001032
1033 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1034 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001035 " { 'type': 'file', 'name': '//root/A',\n"
1036 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001037 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001038 " { 'type': 'file', 'name': '//root/B',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001039 " 'use-external-name': true,\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001040 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001041 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001042 " { 'type': 'file', 'name': '//root/C',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001043 " 'use-external-name': false,\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001044 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001045 " }\n"
1046 "] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001047 ASSERT_TRUE(nullptr != FS.get());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001048
1049 // default true
Ben Langmuir93853232014-03-05 21:32:20 +00001050 EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001051 // explicit
Ben Langmuir93853232014-03-05 21:32:20 +00001052 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1053 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001054
1055 // global configuration
1056 FS = getFromYAMLString(
1057 "{ 'use-external-names': false,\n"
1058 " 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001059 " { 'type': 'file', 'name': '//root/A',\n"
1060 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001061 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001062 " { 'type': 'file', 'name': '//root/B',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001063 " 'use-external-name': true,\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001064 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001065 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001066 " { 'type': 'file', 'name': '//root/C',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001067 " 'use-external-name': false,\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001068 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001069 " }\n"
1070 "] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001071 ASSERT_TRUE(nullptr != FS.get());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001072
1073 // default
Ben Langmuir93853232014-03-05 21:32:20 +00001074 EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001075 // explicit
Ben Langmuir93853232014-03-05 21:32:20 +00001076 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1077 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001078}
1079
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001080TEST_F(VFSFromYAMLTest, MultiComponentPath) {
1081 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001082 Lower->addRegularFile("//root/other");
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001083
1084 // file in roots
1085 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1086 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001087 " { 'type': 'file', 'name': '//root/path/to/file',\n"
1088 " 'external-contents': '//root/other' }]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001089 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001090 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001091 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1092 EXPECT_FALSE(FS->status("//root/path/to").getError());
1093 EXPECT_FALSE(FS->status("//root/path").getError());
1094 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001095
1096 // at the start
1097 FS = getFromYAMLString(
1098 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001099 " { 'type': 'directory', 'name': '//root/path/to',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001100 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001101 " 'external-contents': '//root/other' }]}]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001102 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001103 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001104 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1105 EXPECT_FALSE(FS->status("//root/path/to").getError());
1106 EXPECT_FALSE(FS->status("//root/path").getError());
1107 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001108
1109 // at the end
1110 FS = getFromYAMLString(
1111 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001112 " { 'type': 'directory', 'name': '//root/',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001113 " 'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001114 " 'external-contents': '//root/other' }]}]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001115 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001116 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001117 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1118 EXPECT_FALSE(FS->status("//root/path/to").getError());
1119 EXPECT_FALSE(FS->status("//root/path").getError());
1120 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001121}
1122
1123TEST_F(VFSFromYAMLTest, TrailingSlashes) {
1124 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001125 Lower->addRegularFile("//root/other");
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001126
1127 // file in roots
1128 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1129 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001130 " { 'type': 'directory', 'name': '//root/path/to////',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001131 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001132 " 'external-contents': '//root/other' }]}]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001133 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001134 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001135 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1136 EXPECT_FALSE(FS->status("//root/path/to").getError());
1137 EXPECT_FALSE(FS->status("//root/path").getError());
1138 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001139}
Ben Langmuir740812b2014-06-24 19:37:16 +00001140
1141TEST_F(VFSFromYAMLTest, DirectoryIteration) {
1142 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1143 Lower->addDirectory("//root/");
1144 Lower->addDirectory("//root/foo");
1145 Lower->addDirectory("//root/foo/bar");
1146 Lower->addRegularFile("//root/foo/bar/a");
1147 Lower->addRegularFile("//root/foo/bar/b");
1148 Lower->addRegularFile("//root/file3");
1149 IntrusiveRefCntPtr<vfs::FileSystem> FS =
1150 getFromYAMLString("{ 'use-external-names': false,\n"
1151 " 'roots': [\n"
1152 "{\n"
1153 " 'type': 'directory',\n"
1154 " 'name': '//root/',\n"
1155 " 'contents': [ {\n"
1156 " 'type': 'file',\n"
1157 " 'name': 'file1',\n"
1158 " 'external-contents': '//root/foo/bar/a'\n"
1159 " },\n"
1160 " {\n"
1161 " 'type': 'file',\n"
1162 " 'name': 'file2',\n"
1163 " 'external-contents': '//root/foo/bar/b'\n"
1164 " }\n"
1165 " ]\n"
1166 "}\n"
1167 "]\n"
1168 "}",
1169 Lower);
Hans Wennborgdcfba332015-10-06 23:40:43 +00001170 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuir740812b2014-06-24 19:37:16 +00001171
1172 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1173 new vfs::OverlayFileSystem(Lower));
1174 O->pushOverlay(FS);
1175
1176 std::error_code EC;
Benjamin Kramer2a23e552016-01-10 10:45:19 +00001177 checkContents(O->dir_begin("//root/", EC),
Bruno Cardoso Lopes26092b22016-05-12 04:43:27 +00001178 {"//root/file1", "//root/file2", "//root/file3", "//root/foo"});
Ben Langmuir740812b2014-06-24 19:37:16 +00001179
Benjamin Kramer2a23e552016-01-10 10:45:19 +00001180 checkContents(O->dir_begin("//root/foo/bar", EC),
1181 {"//root/foo/bar/a", "//root/foo/bar/b"});
Ben Langmuir740812b2014-06-24 19:37:16 +00001182}
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +00001183
1184TEST_F(VFSFromYAMLTest, DirectoryIterationSameDirMultipleEntries) {
1185 // https://llvm.org/bugs/show_bug.cgi?id=27725
1186 if (!supportsSameDirMultipleYAMLEntries())
1187 return;
1188
1189 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1190 Lower->addDirectory("//root/zab");
1191 Lower->addDirectory("//root/baz");
1192 Lower->addRegularFile("//root/zab/a");
1193 Lower->addRegularFile("//root/zab/b");
1194 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1195 "{ 'use-external-names': false,\n"
1196 " 'roots': [\n"
1197 "{\n"
1198 " 'type': 'directory',\n"
1199 " 'name': '//root/baz/',\n"
1200 " 'contents': [ {\n"
1201 " 'type': 'file',\n"
1202 " 'name': 'x',\n"
1203 " 'external-contents': '//root/zab/a'\n"
1204 " }\n"
1205 " ]\n"
1206 "},\n"
1207 "{\n"
1208 " 'type': 'directory',\n"
1209 " 'name': '//root/baz/',\n"
1210 " 'contents': [ {\n"
1211 " 'type': 'file',\n"
1212 " 'name': 'y',\n"
1213 " 'external-contents': '//root/zab/b'\n"
1214 " }\n"
1215 " ]\n"
1216 "}\n"
1217 "]\n"
1218 "}",
1219 Lower);
1220 ASSERT_TRUE(FS.get() != nullptr);
1221
1222 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1223 new vfs::OverlayFileSystem(Lower));
1224 O->pushOverlay(FS);
1225
1226 std::error_code EC;
1227
1228 checkContents(O->dir_begin("//root/baz/", EC),
1229 {"//root/baz/x", "//root/baz/y"});
1230}
Bruno Cardoso Lopes32b28972016-05-14 00:00:18 +00001231
1232TEST_F(VFSFromYAMLTest, RecursiveDirectoryIterationLevel) {
1233
1234 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1235 Lower->addDirectory("//root/a");
1236 Lower->addDirectory("//root/a/b");
1237 Lower->addDirectory("//root/a/b/c");
1238 Lower->addRegularFile("//root/a/b/c/file");
1239 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1240 "{ 'use-external-names': false,\n"
1241 " 'roots': [\n"
1242 "{\n"
1243 " 'type': 'directory',\n"
1244 " 'name': '//root/a/b/c/',\n"
1245 " 'contents': [ {\n"
1246 " 'type': 'file',\n"
1247 " 'name': 'file',\n"
1248 " 'external-contents': '//root/a/b/c/file'\n"
1249 " }\n"
1250 " ]\n"
1251 "},\n"
1252 "]\n"
1253 "}",
1254 Lower);
1255 ASSERT_TRUE(FS.get() != nullptr);
1256
1257 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1258 new vfs::OverlayFileSystem(Lower));
1259 O->pushOverlay(FS);
1260
1261 std::error_code EC;
1262
1263 // Test recursive_directory_iterator level()
1264 vfs::recursive_directory_iterator I = vfs::recursive_directory_iterator(
1265 *O, "//root", EC), E;
1266 ASSERT_FALSE(EC);
1267 for (int l = 0; I != E; I.increment(EC), ++l) {
1268 ASSERT_FALSE(EC);
1269 EXPECT_EQ(I.level(), l);
1270 }
1271 EXPECT_EQ(I, E);
1272}