blob: 13c246ecc53e82e257e550338ff4f2e43d7dd380 [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.
Mandeep Singh Grangc205d8c2018-03-27 16:50:00 +0000474 llvm::sort(Contents.begin(), Contents.end());
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000475 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
Mandeep Singh Grangc205d8c2018-03-27 16:50:00 +0000491 llvm::sort(InputToCheck.begin(), InputToCheck.end());
492 llvm::sort(Expected.begin(), Expected.end());
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000493 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 Hamiltone5af5bd2017-11-09 16:01:16 +0000763TEST_F(InMemoryFileSystemTest, AddFileWithUser) {
764 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), 0xFEEDFACE);
765 auto Stat = FS.status("/a");
766 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
767 ASSERT_TRUE(Stat->isDirectory());
768 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
769 Stat = FS.status("/a/b");
770 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
771 ASSERT_TRUE(Stat->isDirectory());
772 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
773 Stat = FS.status("/a/b/c");
774 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
775 ASSERT_TRUE(Stat->isRegularFile());
776 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
777 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
778}
779
780TEST_F(InMemoryFileSystemTest, AddFileWithGroup) {
781 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, 0xDABBAD00);
782 auto Stat = FS.status("/a");
783 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
784 ASSERT_TRUE(Stat->isDirectory());
785 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
786 Stat = FS.status("/a/b");
787 ASSERT_TRUE(Stat->isDirectory());
788 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
789 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
790 Stat = FS.status("/a/b/c");
791 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
792 ASSERT_TRUE(Stat->isRegularFile());
793 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
794 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
795}
796
797TEST_F(InMemoryFileSystemTest, AddFileWithFileType) {
798 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None,
799 sys::fs::file_type::socket_file);
800 auto Stat = FS.status("/a");
801 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
802 ASSERT_TRUE(Stat->isDirectory());
803 Stat = FS.status("/a/b");
804 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
805 ASSERT_TRUE(Stat->isDirectory());
806 Stat = FS.status("/a/b/c");
807 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
808 ASSERT_EQ(sys::fs::file_type::socket_file, Stat->getType());
809 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
810}
811
812TEST_F(InMemoryFileSystemTest, AddFileWithPerms) {
813 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None,
814 None, sys::fs::perms::owner_read | sys::fs::perms::owner_write);
815 auto Stat = FS.status("/a");
816 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
817 ASSERT_TRUE(Stat->isDirectory());
818 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
819 sys::fs::perms::owner_exe, Stat->getPermissions());
820 Stat = FS.status("/a/b");
821 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
822 ASSERT_TRUE(Stat->isDirectory());
823 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
824 sys::fs::perms::owner_exe, Stat->getPermissions());
825 Stat = FS.status("/a/b/c");
826 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
827 ASSERT_TRUE(Stat->isRegularFile());
828 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write,
829 Stat->getPermissions());
830}
831
Ben Hamilton78381012017-11-16 19:34:08 +0000832TEST_F(InMemoryFileSystemTest, AddDirectoryThenAddChild) {
833 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""), /*User=*/None,
834 /*Group=*/None, sys::fs::file_type::directory_file);
835 FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("abc"), /*User=*/None,
836 /*Group=*/None, sys::fs::file_type::regular_file);
837 auto Stat = FS.status("/a");
838 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
839 ASSERT_TRUE(Stat->isDirectory());
840 Stat = FS.status("/a/b");
841 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
842 ASSERT_TRUE(Stat->isRegularFile());
843}
844
Ben Langmuir93853232014-03-05 21:32:20 +0000845// NOTE: in the tests below, we use '//root/' as our root directory, since it is
846// a legal *absolute* path on Windows as well as *nix.
Ben Langmuir97882e72014-02-24 20:56:37 +0000847class VFSFromYAMLTest : public ::testing::Test {
848public:
849 int NumDiagnostics;
Ben Langmuir93853232014-03-05 21:32:20 +0000850
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000851 void SetUp() override { NumDiagnostics = 0; }
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000852
Ben Langmuir97882e72014-02-24 20:56:37 +0000853 static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
854 VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
855 ++Test->NumDiagnostics;
856 }
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000857
Ben Langmuir97882e72014-02-24 20:56:37 +0000858 IntrusiveRefCntPtr<vfs::FileSystem>
859 getFromYAMLRawString(StringRef Content,
860 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
Rafael Espindolad87f8d72014-08-27 20:03:29 +0000861 std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content);
Bruno Cardoso Lopesd878e282016-03-20 02:08:48 +0000862 return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, "", this,
Rafael Espindola91ac8df2014-08-17 23:27:13 +0000863 ExternalFS);
Ben Langmuir97882e72014-02-24 20:56:37 +0000864 }
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000865
Ben Langmuir97882e72014-02-24 20:56:37 +0000866 IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
867 StringRef Content,
868 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
869 std::string VersionPlusContent("{\n 'version':0,\n");
870 VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
871 return getFromYAMLRawString(VersionPlusContent, ExternalFS);
872 }
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +0000873
874 // This is intended as a "XFAIL" for windows hosts.
875 bool supportsSameDirMultipleYAMLEntries() {
876 Triple Host(Triple::normalize(sys::getProcessTriple()));
877 return !Host.isOSWindows();
878 }
Ben Langmuir97882e72014-02-24 20:56:37 +0000879};
880
881TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000882 IntrusiveRefCntPtr<vfs::FileSystem> FS;
883 FS = getFromYAMLString("");
Alp Tokerf994cef2014-07-05 03:08:06 +0000884 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000885 FS = getFromYAMLString("[]");
Alp Tokerf994cef2014-07-05 03:08:06 +0000886 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000887 FS = getFromYAMLString("'string'");
Alp Tokerf994cef2014-07-05 03:08:06 +0000888 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000889 EXPECT_EQ(3, NumDiagnostics);
890}
891
Ben Langmuir97882e72014-02-24 20:56:37 +0000892TEST_F(VFSFromYAMLTest, MappedFiles) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000893 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +0000894 Lower->addRegularFile("//root/foo/bar/a");
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000895 IntrusiveRefCntPtr<vfs::FileSystem> FS =
896 getFromYAMLString("{ 'roots': [\n"
897 "{\n"
898 " 'type': 'directory',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000899 " 'name': '//root/',\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000900 " 'contents': [ {\n"
901 " 'type': 'file',\n"
902 " 'name': 'file1',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000903 " 'external-contents': '//root/foo/bar/a'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000904 " },\n"
905 " {\n"
906 " 'type': 'file',\n"
907 " 'name': 'file2',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000908 " 'external-contents': '//root/foo/b'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000909 " }\n"
910 " ]\n"
911 "}\n"
912 "]\n"
913 "}",
914 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000915 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000916
917 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
918 new vfs::OverlayFileSystem(Lower));
919 O->pushOverlay(FS);
920
921 // file
Ben Langmuir93853232014-03-05 21:32:20 +0000922 ErrorOr<vfs::Status> S = O->status("//root/file1");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000923 ASSERT_FALSE(S.getError());
Ben Langmuir93853232014-03-05 21:32:20 +0000924 EXPECT_EQ("//root/foo/bar/a", S->getName());
Ben Langmuirf13302e2015-12-10 23:41:39 +0000925 EXPECT_TRUE(S->IsVFSMapped);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000926
Ben Langmuir93853232014-03-05 21:32:20 +0000927 ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
928 EXPECT_EQ("//root/foo/bar/a", SLower->getName());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000929 EXPECT_TRUE(S->equivalent(*SLower));
Ben Langmuirf13302e2015-12-10 23:41:39 +0000930 EXPECT_FALSE(SLower->IsVFSMapped);
931
932 // file after opening
933 auto OpenedF = O->openFileForRead("//root/file1");
934 ASSERT_FALSE(OpenedF.getError());
935 auto OpenedS = (*OpenedF)->status();
936 ASSERT_FALSE(OpenedS.getError());
937 EXPECT_EQ("//root/foo/bar/a", OpenedS->getName());
938 EXPECT_TRUE(OpenedS->IsVFSMapped);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000939
940 // directory
Ben Langmuir93853232014-03-05 21:32:20 +0000941 S = O->status("//root/");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000942 ASSERT_FALSE(S.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000943 EXPECT_TRUE(S->isDirectory());
Ben Langmuir93853232014-03-05 21:32:20 +0000944 EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000945
946 // broken mapping
Rafael Espindola71de0b62014-06-13 17:20:50 +0000947 EXPECT_EQ(O->status("//root/file2").getError(),
948 llvm::errc::no_such_file_or_directory);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000949 EXPECT_EQ(0, NumDiagnostics);
950}
951
Ben Langmuir97882e72014-02-24 20:56:37 +0000952TEST_F(VFSFromYAMLTest, CaseInsensitive) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000953 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +0000954 Lower->addRegularFile("//root/foo/bar/a");
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000955 IntrusiveRefCntPtr<vfs::FileSystem> FS =
956 getFromYAMLString("{ 'case-sensitive': 'false',\n"
957 " 'roots': [\n"
958 "{\n"
959 " 'type': 'directory',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000960 " 'name': '//root/',\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000961 " 'contents': [ {\n"
962 " 'type': 'file',\n"
963 " 'name': 'XX',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000964 " 'external-contents': '//root/foo/bar/a'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000965 " }\n"
966 " ]\n"
967 "}]}",
968 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +0000969 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000970
971 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
972 new vfs::OverlayFileSystem(Lower));
973 O->pushOverlay(FS);
974
Ben Langmuir93853232014-03-05 21:32:20 +0000975 ErrorOr<vfs::Status> S = O->status("//root/XX");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000976 ASSERT_FALSE(S.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000977
Ben Langmuir93853232014-03-05 21:32:20 +0000978 ErrorOr<vfs::Status> SS = O->status("//root/xx");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000979 ASSERT_FALSE(SS.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000980 EXPECT_TRUE(S->equivalent(*SS));
Ben Langmuir93853232014-03-05 21:32:20 +0000981 SS = O->status("//root/xX");
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000982 EXPECT_TRUE(S->equivalent(*SS));
Ben Langmuir93853232014-03-05 21:32:20 +0000983 SS = O->status("//root/Xx");
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000984 EXPECT_TRUE(S->equivalent(*SS));
985 EXPECT_EQ(0, NumDiagnostics);
986}
987
Ben Langmuir97882e72014-02-24 20:56:37 +0000988TEST_F(VFSFromYAMLTest, CaseSensitive) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000989 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +0000990 Lower->addRegularFile("//root/foo/bar/a");
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000991 IntrusiveRefCntPtr<vfs::FileSystem> FS =
992 getFromYAMLString("{ 'case-sensitive': 'true',\n"
993 " 'roots': [\n"
994 "{\n"
995 " 'type': 'directory',\n"
Ben Langmuir93853232014-03-05 21:32:20 +0000996 " 'name': '//root/',\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000997 " 'contents': [ {\n"
998 " 'type': 'file',\n"
999 " 'name': 'XX',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001000 " 'external-contents': '//root/foo/bar/a'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001001 " }\n"
1002 " ]\n"
1003 "}]}",
1004 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001005 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001006
1007 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1008 new vfs::OverlayFileSystem(Lower));
1009 O->pushOverlay(FS);
1010
Ben Langmuir93853232014-03-05 21:32:20 +00001011 ErrorOr<vfs::Status> SS = O->status("//root/xx");
Rafael Espindola71de0b62014-06-13 17:20:50 +00001012 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuir93853232014-03-05 21:32:20 +00001013 SS = O->status("//root/xX");
Rafael Espindola71de0b62014-06-13 17:20:50 +00001014 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuir93853232014-03-05 21:32:20 +00001015 SS = O->status("//root/Xx");
Rafael Espindola71de0b62014-06-13 17:20:50 +00001016 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001017 EXPECT_EQ(0, NumDiagnostics);
1018}
1019
Ben Langmuir97882e72014-02-24 20:56:37 +00001020TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001021 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1022
1023 // invalid YAML at top-level
1024 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001025 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001026 // invalid YAML in roots
1027 FS = getFromYAMLString("{ 'roots':[}", Lower);
1028 // invalid YAML in directory
1029 FS = getFromYAMLString(
1030 "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
1031 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001032 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001033
1034 // invalid configuration
1035 FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001036 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001037 FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001038 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001039
1040 // invalid roots
1041 FS = getFromYAMLString("{ 'roots':'' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001042 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001043 FS = getFromYAMLString("{ 'roots':{} }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001044 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001045
1046 // invalid entries
1047 FS = getFromYAMLString(
1048 "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001049 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001050 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
1051 "'external-contents': 'other' }",
1052 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001053 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001054 FS = getFromYAMLString(
1055 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
1056 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001057 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001058 FS = getFromYAMLString(
1059 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
1060 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001061 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001062 FS = getFromYAMLString(
1063 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
1064 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001065 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001066 FS = getFromYAMLString(
1067 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
1068 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001069 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001070 FS = getFromYAMLString(
1071 "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
1072 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001073 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001074
1075 // missing mandatory fields
1076 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001077 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001078 FS = getFromYAMLString(
1079 "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001080 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001081 FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001082 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001083
1084 // duplicate keys
1085 FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001086 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001087 FS = getFromYAMLString(
1088 "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
1089 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001090 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001091 FS =
1092 getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
1093 "'external-contents':'blah' } ] }",
1094 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001095 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001096
1097 // missing version
1098 FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001099 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001100
1101 // bad version number
1102 FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001103 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001104 FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001105 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001106 FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001107 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001108 EXPECT_EQ(24, NumDiagnostics);
1109}
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001110
Ben Langmuirb59cf672014-02-27 00:25:12 +00001111TEST_F(VFSFromYAMLTest, UseExternalName) {
1112 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001113 Lower->addRegularFile("//root/external/file");
Ben Langmuirb59cf672014-02-27 00:25:12 +00001114
1115 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1116 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001117 " { 'type': 'file', 'name': '//root/A',\n"
1118 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001119 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001120 " { 'type': 'file', 'name': '//root/B',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001121 " 'use-external-name': true,\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001122 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001123 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001124 " { 'type': 'file', 'name': '//root/C',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001125 " 'use-external-name': false,\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001126 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001127 " }\n"
1128 "] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001129 ASSERT_TRUE(nullptr != FS.get());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001130
1131 // default true
Ben Langmuir93853232014-03-05 21:32:20 +00001132 EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001133 // explicit
Ben Langmuir93853232014-03-05 21:32:20 +00001134 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1135 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001136
1137 // global configuration
1138 FS = getFromYAMLString(
1139 "{ 'use-external-names': false,\n"
1140 " 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001141 " { 'type': 'file', 'name': '//root/A',\n"
1142 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001143 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001144 " { 'type': 'file', 'name': '//root/B',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001145 " 'use-external-name': true,\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001146 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001147 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001148 " { 'type': 'file', 'name': '//root/C',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001149 " 'use-external-name': false,\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001150 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001151 " }\n"
1152 "] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001153 ASSERT_TRUE(nullptr != FS.get());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001154
1155 // default
Ben Langmuir93853232014-03-05 21:32:20 +00001156 EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001157 // explicit
Ben Langmuir93853232014-03-05 21:32:20 +00001158 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1159 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001160}
1161
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001162TEST_F(VFSFromYAMLTest, MultiComponentPath) {
1163 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001164 Lower->addRegularFile("//root/other");
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001165
1166 // file in roots
1167 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1168 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001169 " { 'type': 'file', 'name': '//root/path/to/file',\n"
1170 " 'external-contents': '//root/other' }]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001171 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001172 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001173 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1174 EXPECT_FALSE(FS->status("//root/path/to").getError());
1175 EXPECT_FALSE(FS->status("//root/path").getError());
1176 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001177
1178 // at the start
1179 FS = getFromYAMLString(
1180 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001181 " { 'type': 'directory', 'name': '//root/path/to',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001182 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001183 " 'external-contents': '//root/other' }]}]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001184 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001185 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001186 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1187 EXPECT_FALSE(FS->status("//root/path/to").getError());
1188 EXPECT_FALSE(FS->status("//root/path").getError());
1189 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001190
1191 // at the end
1192 FS = getFromYAMLString(
1193 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001194 " { 'type': 'directory', 'name': '//root/',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001195 " 'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001196 " 'external-contents': '//root/other' }]}]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001197 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001198 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001199 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1200 EXPECT_FALSE(FS->status("//root/path/to").getError());
1201 EXPECT_FALSE(FS->status("//root/path").getError());
1202 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001203}
1204
1205TEST_F(VFSFromYAMLTest, TrailingSlashes) {
1206 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001207 Lower->addRegularFile("//root/other");
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001208
1209 // file in roots
1210 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1211 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001212 " { 'type': 'directory', 'name': '//root/path/to////',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001213 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001214 " 'external-contents': '//root/other' }]}]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001215 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001216 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001217 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1218 EXPECT_FALSE(FS->status("//root/path/to").getError());
1219 EXPECT_FALSE(FS->status("//root/path").getError());
1220 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001221}
Ben Langmuir740812b2014-06-24 19:37:16 +00001222
1223TEST_F(VFSFromYAMLTest, DirectoryIteration) {
1224 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1225 Lower->addDirectory("//root/");
1226 Lower->addDirectory("//root/foo");
1227 Lower->addDirectory("//root/foo/bar");
1228 Lower->addRegularFile("//root/foo/bar/a");
1229 Lower->addRegularFile("//root/foo/bar/b");
1230 Lower->addRegularFile("//root/file3");
1231 IntrusiveRefCntPtr<vfs::FileSystem> FS =
1232 getFromYAMLString("{ 'use-external-names': false,\n"
1233 " 'roots': [\n"
1234 "{\n"
1235 " 'type': 'directory',\n"
1236 " 'name': '//root/',\n"
1237 " 'contents': [ {\n"
1238 " 'type': 'file',\n"
1239 " 'name': 'file1',\n"
1240 " 'external-contents': '//root/foo/bar/a'\n"
1241 " },\n"
1242 " {\n"
1243 " 'type': 'file',\n"
1244 " 'name': 'file2',\n"
1245 " 'external-contents': '//root/foo/bar/b'\n"
1246 " }\n"
1247 " ]\n"
1248 "}\n"
1249 "]\n"
1250 "}",
1251 Lower);
Hans Wennborgdcfba332015-10-06 23:40:43 +00001252 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuir740812b2014-06-24 19:37:16 +00001253
1254 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1255 new vfs::OverlayFileSystem(Lower));
1256 O->pushOverlay(FS);
1257
1258 std::error_code EC;
Benjamin Kramer2a23e552016-01-10 10:45:19 +00001259 checkContents(O->dir_begin("//root/", EC),
Bruno Cardoso Lopes26092b22016-05-12 04:43:27 +00001260 {"//root/file1", "//root/file2", "//root/file3", "//root/foo"});
Ben Langmuir740812b2014-06-24 19:37:16 +00001261
Benjamin Kramer2a23e552016-01-10 10:45:19 +00001262 checkContents(O->dir_begin("//root/foo/bar", EC),
1263 {"//root/foo/bar/a", "//root/foo/bar/b"});
Ben Langmuir740812b2014-06-24 19:37:16 +00001264}
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +00001265
1266TEST_F(VFSFromYAMLTest, DirectoryIterationSameDirMultipleEntries) {
1267 // https://llvm.org/bugs/show_bug.cgi?id=27725
1268 if (!supportsSameDirMultipleYAMLEntries())
1269 return;
1270
1271 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1272 Lower->addDirectory("//root/zab");
1273 Lower->addDirectory("//root/baz");
1274 Lower->addRegularFile("//root/zab/a");
1275 Lower->addRegularFile("//root/zab/b");
1276 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1277 "{ 'use-external-names': false,\n"
1278 " 'roots': [\n"
1279 "{\n"
1280 " 'type': 'directory',\n"
1281 " 'name': '//root/baz/',\n"
1282 " 'contents': [ {\n"
1283 " 'type': 'file',\n"
1284 " 'name': 'x',\n"
1285 " 'external-contents': '//root/zab/a'\n"
1286 " }\n"
1287 " ]\n"
1288 "},\n"
1289 "{\n"
1290 " 'type': 'directory',\n"
1291 " 'name': '//root/baz/',\n"
1292 " 'contents': [ {\n"
1293 " 'type': 'file',\n"
1294 " 'name': 'y',\n"
1295 " 'external-contents': '//root/zab/b'\n"
1296 " }\n"
1297 " ]\n"
1298 "}\n"
1299 "]\n"
1300 "}",
1301 Lower);
1302 ASSERT_TRUE(FS.get() != nullptr);
1303
1304 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1305 new vfs::OverlayFileSystem(Lower));
1306 O->pushOverlay(FS);
1307
1308 std::error_code EC;
1309
1310 checkContents(O->dir_begin("//root/baz/", EC),
1311 {"//root/baz/x", "//root/baz/y"});
1312}
Bruno Cardoso Lopes32b28972016-05-14 00:00:18 +00001313
1314TEST_F(VFSFromYAMLTest, RecursiveDirectoryIterationLevel) {
1315
1316 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1317 Lower->addDirectory("//root/a");
1318 Lower->addDirectory("//root/a/b");
1319 Lower->addDirectory("//root/a/b/c");
1320 Lower->addRegularFile("//root/a/b/c/file");
1321 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1322 "{ 'use-external-names': false,\n"
1323 " 'roots': [\n"
1324 "{\n"
1325 " 'type': 'directory',\n"
1326 " 'name': '//root/a/b/c/',\n"
1327 " 'contents': [ {\n"
1328 " 'type': 'file',\n"
1329 " 'name': 'file',\n"
1330 " 'external-contents': '//root/a/b/c/file'\n"
1331 " }\n"
1332 " ]\n"
1333 "},\n"
1334 "]\n"
1335 "}",
1336 Lower);
1337 ASSERT_TRUE(FS.get() != nullptr);
1338
1339 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1340 new vfs::OverlayFileSystem(Lower));
1341 O->pushOverlay(FS);
1342
1343 std::error_code EC;
1344
1345 // Test recursive_directory_iterator level()
1346 vfs::recursive_directory_iterator I = vfs::recursive_directory_iterator(
1347 *O, "//root", EC), E;
1348 ASSERT_FALSE(EC);
1349 for (int l = 0; I != E; I.increment(EC), ++l) {
1350 ASSERT_FALSE(EC);
1351 EXPECT_EQ(I.level(), l);
1352 }
1353 EXPECT_EQ(I, E);
1354}