blob: 466cd117a507fbabc52598622b38c7567e8b6c8b [file] [log] [blame]
Jonas Devliegherefc514902018-10-10 13:27:25 +00001//===- unittests/Support/VirtualFileSystem.cpp -------------- VFS tests ---===//
Ben Langmuirc8130a72014-02-20 21:59:23 +00002//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
Jonas Devliegherefc514902018-10-10 13:27:25 +000010#include "llvm/Support/VirtualFileSystem.h"
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +000011#include "llvm/ADT/Triple.h"
Nico Weberd637c052018-04-30 13:52:15 +000012#include "llvm/Config/llvm-config.h"
Rafael Espindola71de0b62014-06-13 17:20:50 +000013#include "llvm/Support/Errc.h"
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +000014#include "llvm/Support/Host.h"
Ben Langmuird51ba0b2014-02-21 23:39:37 +000015#include "llvm/Support/MemoryBuffer.h"
Simon Marchiddbabc62018-08-06 21:48:20 +000016#include "llvm/Support/Path.h"
Ben Langmuird51ba0b2014-02-21 23:39:37 +000017#include "llvm/Support/SourceMgr.h"
Ilya Biryukovd5554c512018-09-04 14:15:53 +000018#include "gmock/gmock.h"
Ben Langmuirc8130a72014-02-20 21:59:23 +000019#include "gtest/gtest.h"
20#include <map>
Ilya Biryukovd5554c512018-09-04 14:15:53 +000021#include <string>
Hans Wennborgdcfba332015-10-06 23:40:43 +000022
Ben Langmuirc8130a72014-02-20 21:59:23 +000023using namespace llvm;
24using llvm::sys::fs::UniqueID;
Sam McCall39223772018-10-01 16:07:03 +000025using testing::ElementsAre;
26using testing::Pair;
27using testing::UnorderedElementsAre;
Ben Langmuirc8130a72014-02-20 21:59:23 +000028
29namespace {
Ben Langmuirf13302e2015-12-10 23:41:39 +000030struct DummyFile : public vfs::File {
31 vfs::Status S;
32 explicit DummyFile(vfs::Status S) : S(S) {}
33 llvm::ErrorOr<vfs::Status> status() override { return S; }
34 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
35 getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
36 bool IsVolatile) override {
37 llvm_unreachable("unimplemented");
38 }
Eugene Zelenko1660a5d2016-01-26 19:01:06 +000039 std::error_code close() override { return std::error_code(); }
Ben Langmuirf13302e2015-12-10 23:41:39 +000040};
41
Ben Langmuirc8130a72014-02-20 21:59:23 +000042class DummyFileSystem : public vfs::FileSystem {
43 int FSID; // used to produce UniqueIDs
44 int FileID; // used to produce UniqueIDs
45 std::map<std::string, vfs::Status> FilesAndDirs;
46
47 static int getNextFSID() {
48 static int Count = 0;
49 return Count++;
50 }
51
52public:
53 DummyFileSystem() : FSID(getNextFSID()), FileID(0) {}
54
Fariborz Jahanian5afc8692014-10-01 16:56:40 +000055 ErrorOr<vfs::Status> status(const Twine &Path) override {
Ben Langmuirc8130a72014-02-20 21:59:23 +000056 std::map<std::string, vfs::Status>::iterator I =
Ben Langmuird51ba0b2014-02-21 23:39:37 +000057 FilesAndDirs.find(Path.str());
Ben Langmuirc8130a72014-02-20 21:59:23 +000058 if (I == FilesAndDirs.end())
Rafael Espindola71de0b62014-06-13 17:20:50 +000059 return make_error_code(llvm::errc::no_such_file_or_directory);
Ben Langmuirc8130a72014-02-20 21:59:23 +000060 return I->second;
61 }
Benjamin Kramera8857962014-10-26 22:44:13 +000062 ErrorOr<std::unique_ptr<vfs::File>>
63 openFileForRead(const Twine &Path) override {
Ben Langmuirf13302e2015-12-10 23:41:39 +000064 auto S = status(Path);
65 if (S)
66 return std::unique_ptr<vfs::File>(new DummyFile{*S});
67 return S.getError();
Ben Langmuirc8130a72014-02-20 21:59:23 +000068 }
Benjamin Kramer7708b2a2015-10-05 13:55:20 +000069 llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
70 return std::string();
71 }
72 std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
73 return std::error_code();
74 }
Eric Liua840a462018-05-18 13:22:49 +000075 // Map any symlink to "/symlink".
76 std::error_code getRealPath(const Twine &Path,
77 SmallVectorImpl<char> &Output) const override {
78 auto I = FilesAndDirs.find(Path.str());
79 if (I == FilesAndDirs.end())
80 return make_error_code(llvm::errc::no_such_file_or_directory);
81 if (I->second.isSymlink()) {
82 Output.clear();
83 Twine("/symlink").toVector(Output);
84 return std::error_code();
85 }
86 Output.clear();
87 Path.toVector(Output);
88 return std::error_code();
89 }
Ben Langmuirc8130a72014-02-20 21:59:23 +000090
Jonas Devliegherefc514902018-10-10 13:27:25 +000091 struct DirIterImpl : public llvm::vfs::detail::DirIterImpl {
Ben Langmuir740812b2014-06-24 19:37:16 +000092 std::map<std::string, vfs::Status> &FilesAndDirs;
93 std::map<std::string, vfs::Status>::iterator I;
94 std::string Path;
Ben Langmuir7c9f6c82014-06-25 20:25:40 +000095 bool isInPath(StringRef S) {
96 if (Path.size() < S.size() && S.find(Path) == 0) {
97 auto LastSep = S.find_last_of('/');
Jonas Devliegherefc514902018-10-10 13:27:25 +000098 if (LastSep == Path.size() || LastSep == Path.size() - 1)
Ben Langmuir7c9f6c82014-06-25 20:25:40 +000099 return true;
100 }
101 return false;
102 }
Ben Langmuir740812b2014-06-24 19:37:16 +0000103 DirIterImpl(std::map<std::string, vfs::Status> &FilesAndDirs,
104 const Twine &_Path)
105 : FilesAndDirs(FilesAndDirs), I(FilesAndDirs.begin()),
106 Path(_Path.str()) {
Jonas Devliegherefc514902018-10-10 13:27:25 +0000107 for (; I != FilesAndDirs.end(); ++I) {
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000108 if (isInPath(I->first)) {
Sam McCall0ae00562018-09-14 12:47:38 +0000109 CurrentEntry =
110 vfs::directory_entry(I->second.getName(), I->second.getType());
Ben Langmuir740812b2014-06-24 19:37:16 +0000111 break;
112 }
113 }
114 }
115 std::error_code increment() override {
116 ++I;
Jonas Devliegherefc514902018-10-10 13:27:25 +0000117 for (; I != FilesAndDirs.end(); ++I) {
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000118 if (isInPath(I->first)) {
Sam McCall0ae00562018-09-14 12:47:38 +0000119 CurrentEntry =
120 vfs::directory_entry(I->second.getName(), I->second.getType());
Ben Langmuir740812b2014-06-24 19:37:16 +0000121 break;
122 }
123 }
124 if (I == FilesAndDirs.end())
Sam McCall0ae00562018-09-14 12:47:38 +0000125 CurrentEntry = vfs::directory_entry();
Ben Langmuir740812b2014-06-24 19:37:16 +0000126 return std::error_code();
127 }
128 };
129
130 vfs::directory_iterator dir_begin(const Twine &Dir,
131 std::error_code &EC) override {
132 return vfs::directory_iterator(
133 std::make_shared<DirIterImpl>(FilesAndDirs, Dir));
134 }
135
Ben Langmuirc8130a72014-02-20 21:59:23 +0000136 void addEntry(StringRef Path, const vfs::Status &Status) {
137 FilesAndDirs[Path] = Status;
138 }
139
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000140 void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
Pavel Labathac71c8e2016-11-09 10:52:22 +0000141 vfs::Status S(Path, UniqueID(FSID, FileID++),
142 std::chrono::system_clock::now(), 0, 0, 1024,
143 sys::fs::file_type::regular_file, Perms);
Ben Langmuirc8130a72014-02-20 21:59:23 +0000144 addEntry(Path, S);
145 }
146
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000147 void addDirectory(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
Pavel Labathac71c8e2016-11-09 10:52:22 +0000148 vfs::Status S(Path, UniqueID(FSID, FileID++),
149 std::chrono::system_clock::now(), 0, 0, 0,
150 sys::fs::file_type::directory_file, Perms);
Ben Langmuirc8130a72014-02-20 21:59:23 +0000151 addEntry(Path, S);
152 }
153
154 void addSymlink(StringRef Path) {
Pavel Labathac71c8e2016-11-09 10:52:22 +0000155 vfs::Status S(Path, UniqueID(FSID, FileID++),
156 std::chrono::system_clock::now(), 0, 0, 0,
157 sys::fs::file_type::symlink_file, sys::fs::all_all);
Ben Langmuirc8130a72014-02-20 21:59:23 +0000158 addEntry(Path, S);
159 }
160};
Simon Marchiddbabc62018-08-06 21:48:20 +0000161
162/// Replace back-slashes by front-slashes.
163std::string getPosixPath(std::string S) {
164 SmallString<128> Result;
165 llvm::sys::path::native(S, Result, llvm::sys::path::Style::posix);
166 return Result.str();
Craig Topper576ac052018-08-08 22:31:14 +0000167}
Ben Langmuirc8130a72014-02-20 21:59:23 +0000168} // end anonymous namespace
169
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000170TEST(VirtualFileSystemTest, StatusQueries) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000171 IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
Rafael Espindola8e650d72014-06-12 20:37:59 +0000172 ErrorOr<vfs::Status> Status((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000173
174 D->addRegularFile("/foo");
175 Status = D->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000176 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000177 EXPECT_TRUE(Status->isStatusKnown());
178 EXPECT_FALSE(Status->isDirectory());
179 EXPECT_TRUE(Status->isRegularFile());
180 EXPECT_FALSE(Status->isSymlink());
181 EXPECT_FALSE(Status->isOther());
182 EXPECT_TRUE(Status->exists());
183
184 D->addDirectory("/bar");
185 Status = D->status("/bar");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000186 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000187 EXPECT_TRUE(Status->isStatusKnown());
188 EXPECT_TRUE(Status->isDirectory());
189 EXPECT_FALSE(Status->isRegularFile());
190 EXPECT_FALSE(Status->isSymlink());
191 EXPECT_FALSE(Status->isOther());
192 EXPECT_TRUE(Status->exists());
193
194 D->addSymlink("/baz");
195 Status = D->status("/baz");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000196 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000197 EXPECT_TRUE(Status->isStatusKnown());
198 EXPECT_FALSE(Status->isDirectory());
199 EXPECT_FALSE(Status->isRegularFile());
200 EXPECT_TRUE(Status->isSymlink());
201 EXPECT_FALSE(Status->isOther());
202 EXPECT_TRUE(Status->exists());
203
204 EXPECT_TRUE(Status->equivalent(*Status));
205 ErrorOr<vfs::Status> Status2 = D->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000206 ASSERT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000207 EXPECT_FALSE(Status->equivalent(*Status2));
208}
209
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000210TEST(VirtualFileSystemTest, BaseOnlyOverlay) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000211 IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
Rafael Espindola8e650d72014-06-12 20:37:59 +0000212 ErrorOr<vfs::Status> Status((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000213 EXPECT_FALSE(Status = D->status("/foo"));
214
215 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(new vfs::OverlayFileSystem(D));
216 EXPECT_FALSE(Status = O->status("/foo"));
217
218 D->addRegularFile("/foo");
219 Status = D->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000220 EXPECT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000221
Rafael Espindola8e650d72014-06-12 20:37:59 +0000222 ErrorOr<vfs::Status> Status2((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000223 Status2 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000224 EXPECT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000225 EXPECT_TRUE(Status->equivalent(*Status2));
226}
227
Eric Liua840a462018-05-18 13:22:49 +0000228TEST(VirtualFileSystemTest, GetRealPathInOverlay) {
229 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
230 Lower->addRegularFile("/foo");
231 Lower->addSymlink("/lower_link");
232 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
233
234 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
235 new vfs::OverlayFileSystem(Lower));
236 O->pushOverlay(Upper);
237
238 // Regular file.
239 SmallString<16> RealPath;
240 EXPECT_FALSE(O->getRealPath("/foo", RealPath));
241 EXPECT_EQ(RealPath.str(), "/foo");
242
243 // Expect no error getting real path for symlink in lower overlay.
244 EXPECT_FALSE(O->getRealPath("/lower_link", RealPath));
245 EXPECT_EQ(RealPath.str(), "/symlink");
246
247 // Try a non-existing link.
248 EXPECT_EQ(O->getRealPath("/upper_link", RealPath),
249 errc::no_such_file_or_directory);
250
251 // Add a new symlink in upper.
252 Upper->addSymlink("/upper_link");
253 EXPECT_FALSE(O->getRealPath("/upper_link", RealPath));
254 EXPECT_EQ(RealPath.str(), "/symlink");
255}
256
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000257TEST(VirtualFileSystemTest, OverlayFiles) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000258 IntrusiveRefCntPtr<DummyFileSystem> Base(new DummyFileSystem());
259 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
260 IntrusiveRefCntPtr<DummyFileSystem> Top(new DummyFileSystem());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000261 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
262 new vfs::OverlayFileSystem(Base));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000263 O->pushOverlay(Middle);
264 O->pushOverlay(Top);
265
Rafael Espindola8e650d72014-06-12 20:37:59 +0000266 ErrorOr<vfs::Status> Status1((std::error_code())),
267 Status2((std::error_code())), Status3((std::error_code())),
268 StatusB((std::error_code())), StatusM((std::error_code())),
269 StatusT((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000270
271 Base->addRegularFile("/foo");
272 StatusB = Base->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000273 ASSERT_FALSE(StatusB.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000274 Status1 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000275 ASSERT_FALSE(Status1.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000276 Middle->addRegularFile("/foo");
277 StatusM = Middle->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000278 ASSERT_FALSE(StatusM.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000279 Status2 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000280 ASSERT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000281 Top->addRegularFile("/foo");
282 StatusT = Top->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000283 ASSERT_FALSE(StatusT.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000284 Status3 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000285 ASSERT_FALSE(Status3.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000286
287 EXPECT_TRUE(Status1->equivalent(*StatusB));
288 EXPECT_TRUE(Status2->equivalent(*StatusM));
289 EXPECT_TRUE(Status3->equivalent(*StatusT));
290
291 EXPECT_FALSE(Status1->equivalent(*Status2));
292 EXPECT_FALSE(Status2->equivalent(*Status3));
293 EXPECT_FALSE(Status1->equivalent(*Status3));
294}
295
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000296TEST(VirtualFileSystemTest, OverlayDirsNonMerged) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000297 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
298 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000299 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
300 new vfs::OverlayFileSystem(Lower));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000301 O->pushOverlay(Upper);
302
303 Lower->addDirectory("/lower-only");
304 Upper->addDirectory("/upper-only");
305
306 // non-merged paths should be the same
307 ErrorOr<vfs::Status> Status1 = Lower->status("/lower-only");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000308 ASSERT_FALSE(Status1.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000309 ErrorOr<vfs::Status> Status2 = O->status("/lower-only");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000310 ASSERT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000311 EXPECT_TRUE(Status1->equivalent(*Status2));
312
313 Status1 = Upper->status("/upper-only");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000314 ASSERT_FALSE(Status1.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000315 Status2 = O->status("/upper-only");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000316 ASSERT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000317 EXPECT_TRUE(Status1->equivalent(*Status2));
318}
319
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000320TEST(VirtualFileSystemTest, MergedDirPermissions) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000321 // merged directories get the permissions of the upper dir
322 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
323 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000324 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
325 new vfs::OverlayFileSystem(Lower));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000326 O->pushOverlay(Upper);
327
Rafael Espindola8e650d72014-06-12 20:37:59 +0000328 ErrorOr<vfs::Status> Status((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000329 Lower->addDirectory("/both", sys::fs::owner_read);
330 Upper->addDirectory("/both", sys::fs::owner_all | sys::fs::group_read);
331 Status = O->status("/both");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000332 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000333 EXPECT_EQ(0740, Status->getPermissions());
334
335 // permissions (as usual) are not recursively applied
336 Lower->addRegularFile("/both/foo", sys::fs::owner_read);
337 Upper->addRegularFile("/both/bar", sys::fs::owner_write);
338 Status = O->status("/both/foo");
Jonas Devliegherefc514902018-10-10 13:27:25 +0000339 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000340 EXPECT_EQ(0400, Status->getPermissions());
341 Status = O->status("/both/bar");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000342 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000343 EXPECT_EQ(0200, Status->getPermissions());
344}
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000345
Ben Langmuir740812b2014-06-24 19:37:16 +0000346namespace {
347struct ScopedDir {
348 SmallString<128> Path;
Jonas Devliegherefc514902018-10-10 13:27:25 +0000349 ScopedDir(const Twine &Name, bool Unique = false) {
Ben Langmuir740812b2014-06-24 19:37:16 +0000350 std::error_code EC;
351 if (Unique) {
Jonas Devliegherefc514902018-10-10 13:27:25 +0000352 EC = llvm::sys::fs::createUniqueDirectory(Name, Path);
Ben Langmuir740812b2014-06-24 19:37:16 +0000353 } else {
354 Path = Name.str();
355 EC = llvm::sys::fs::create_directory(Twine(Path));
356 }
357 if (EC)
358 Path = "";
359 EXPECT_FALSE(EC);
360 }
361 ~ScopedDir() {
Galina Kistanova45fbb592017-06-15 21:01:24 +0000362 if (Path != "") {
Ben Langmuir740812b2014-06-24 19:37:16 +0000363 EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
Galina Kistanova45fbb592017-06-15 21:01:24 +0000364 }
Ben Langmuir740812b2014-06-24 19:37:16 +0000365 }
366 operator StringRef() { return Path.str(); }
367};
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000368
369struct ScopedLink {
370 SmallString<128> Path;
371 ScopedLink(const Twine &To, const Twine &From) {
372 Path = From.str();
373 std::error_code EC = sys::fs::create_link(To, From);
374 if (EC)
375 Path = "";
376 EXPECT_FALSE(EC);
377 }
378 ~ScopedLink() {
Galina Kistanova45fbb592017-06-15 21:01:24 +0000379 if (Path != "") {
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000380 EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
Galina Kistanova45fbb592017-06-15 21:01:24 +0000381 }
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000382 }
383 operator StringRef() { return Path.str(); }
384};
Hans Wennborgdcfba332015-10-06 23:40:43 +0000385} // end anonymous namespace
Ben Langmuir740812b2014-06-24 19:37:16 +0000386
387TEST(VirtualFileSystemTest, BasicRealFSIteration) {
Jonas Devliegherefc514902018-10-10 13:27:25 +0000388 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
Ben Langmuir740812b2014-06-24 19:37:16 +0000389 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
390
391 std::error_code EC;
392 vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC);
393 ASSERT_FALSE(EC);
394 EXPECT_EQ(vfs::directory_iterator(), I); // empty directory is empty
395
Jonas Devliegherefc514902018-10-10 13:27:25 +0000396 ScopedDir _a(TestDirectory + "/a");
397 ScopedDir _ab(TestDirectory + "/a/b");
398 ScopedDir _c(TestDirectory + "/c");
399 ScopedDir _cd(TestDirectory + "/c/d");
Ben Langmuir740812b2014-06-24 19:37:16 +0000400
401 I = FS->dir_begin(Twine(TestDirectory), EC);
402 ASSERT_FALSE(EC);
403 ASSERT_NE(vfs::directory_iterator(), I);
Ben Langmuirefb8b602014-06-24 21:08:13 +0000404 // Check either a or c, since we can't rely on the iteration order.
Sam McCall0ae00562018-09-14 12:47:38 +0000405 EXPECT_TRUE(I->path().endswith("a") || I->path().endswith("c"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000406 I.increment(EC);
407 ASSERT_FALSE(EC);
408 ASSERT_NE(vfs::directory_iterator(), I);
Sam McCall0ae00562018-09-14 12:47:38 +0000409 EXPECT_TRUE(I->path().endswith("a") || I->path().endswith("c"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000410 I.increment(EC);
411 EXPECT_EQ(vfs::directory_iterator(), I);
412}
413
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000414#ifdef LLVM_ON_UNIX
415TEST(VirtualFileSystemTest, BrokenSymlinkRealFSIteration) {
416 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
417 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
418
419 ScopedLink _a("no_such_file", TestDirectory + "/a");
420 ScopedDir _b(TestDirectory + "/b");
421 ScopedLink _c("no_such_file", TestDirectory + "/c");
422
Sam McCall39223772018-10-01 16:07:03 +0000423 // Should get no iteration error, but a stat error for the broken symlinks.
424 std::map<std::string, std::error_code> StatResults;
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000425 std::error_code EC;
426 for (vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC), E;
427 I != E; I.increment(EC)) {
Sam McCall39223772018-10-01 16:07:03 +0000428 EXPECT_FALSE(EC);
429 StatResults[sys::path::filename(I->path())] =
430 FS->status(I->path()).getError();
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000431 }
Sam McCall39223772018-10-01 16:07:03 +0000432 EXPECT_THAT(
433 StatResults,
434 ElementsAre(
435 Pair("a", std::make_error_code(std::errc::no_such_file_or_directory)),
436 Pair("b", std::error_code()),
437 Pair("c",
438 std::make_error_code(std::errc::no_such_file_or_directory))));
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000439}
440#endif
441
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000442TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
Jonas Devliegherefc514902018-10-10 13:27:25 +0000443 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000444 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
445
446 std::error_code EC;
447 auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
448 ASSERT_FALSE(EC);
449 EXPECT_EQ(vfs::recursive_directory_iterator(), I); // empty directory is empty
450
Jonas Devliegherefc514902018-10-10 13:27:25 +0000451 ScopedDir _a(TestDirectory + "/a");
452 ScopedDir _ab(TestDirectory + "/a/b");
453 ScopedDir _c(TestDirectory + "/c");
454 ScopedDir _cd(TestDirectory + "/c/d");
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000455
456 I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
457 ASSERT_FALSE(EC);
458 ASSERT_NE(vfs::recursive_directory_iterator(), I);
459
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000460 std::vector<std::string> Contents;
461 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
462 I.increment(EC)) {
Sam McCall0ae00562018-09-14 12:47:38 +0000463 Contents.push_back(I->path());
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000464 }
465
466 // Check contents, which may be in any order
467 EXPECT_EQ(4U, Contents.size());
Jonas Devliegherefc514902018-10-10 13:27:25 +0000468 int Counts[4] = {0, 0, 0, 0};
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000469 for (const std::string &Name : Contents) {
470 ASSERT_FALSE(Name.empty());
Jonas Devliegherefc514902018-10-10 13:27:25 +0000471 int Index = Name[Name.size() - 1] - 'a';
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000472 ASSERT_TRUE(Index >= 0 && Index < 4);
473 Counts[Index]++;
474 }
475 EXPECT_EQ(1, Counts[0]); // a
476 EXPECT_EQ(1, Counts[1]); // b
477 EXPECT_EQ(1, Counts[2]); // c
478 EXPECT_EQ(1, Counts[3]); // d
479}
480
Jonas Devlieghere41fb9512018-10-31 23:36:10 +0000481TEST(VirtualFileSystemTest, BasicRealFSRecursiveIterationNoPush) {
482 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
483
484 ScopedDir _a(TestDirectory + "/a");
485 ScopedDir _ab(TestDirectory + "/a/b");
486 ScopedDir _c(TestDirectory + "/c");
487 ScopedDir _cd(TestDirectory + "/c/d");
488 ScopedDir _e(TestDirectory + "/e");
489 ScopedDir _ef(TestDirectory + "/e/f");
490 ScopedDir _g(TestDirectory + "/g");
491
492 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
493
494 // Test that calling no_push on entries without subdirectories has no effect.
495 {
496 std::error_code EC;
497 auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
498 ASSERT_FALSE(EC);
499
500 std::vector<std::string> Contents;
501 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
502 I.increment(EC)) {
503 Contents.push_back(I->path());
504 char last = I->path().back();
505 switch (last) {
506 case 'b':
507 case 'd':
508 case 'f':
509 case 'g':
510 I.no_push();
511 break;
512 default:
513 break;
514 }
515 }
516 EXPECT_EQ(7U, Contents.size());
517 }
518
519 // Test that calling no_push skips subdirectories.
520 {
521 std::error_code EC;
522 auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
523 ASSERT_FALSE(EC);
524
525 std::vector<std::string> Contents;
526 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
527 I.increment(EC)) {
528 Contents.push_back(I->path());
529 char last = I->path().back();
530 switch (last) {
531 case 'a':
532 case 'c':
533 case 'e':
534 I.no_push();
535 break;
536 default:
537 break;
538 }
539 }
540
541 // Check contents, which may be in any order
542 EXPECT_EQ(4U, Contents.size());
543 int Counts[7] = {0, 0, 0, 0, 0, 0, 0};
544 for (const std::string &Name : Contents) {
545 ASSERT_FALSE(Name.empty());
546 int Index = Name[Name.size() - 1] - 'a';
547 ASSERT_TRUE(Index >= 0 && Index < 7);
548 Counts[Index]++;
549 }
550 EXPECT_EQ(1, Counts[0]); // a
551 EXPECT_EQ(0, Counts[1]); // b
552 EXPECT_EQ(1, Counts[2]); // c
553 EXPECT_EQ(0, Counts[3]); // d
554 EXPECT_EQ(1, Counts[4]); // e
555 EXPECT_EQ(0, Counts[5]); // f
556 EXPECT_EQ(1, Counts[6]); // g
557 }
558}
559
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000560#ifdef LLVM_ON_UNIX
561TEST(VirtualFileSystemTest, BrokenSymlinkRealFSRecursiveIteration) {
562 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
563 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
564
565 ScopedLink _a("no_such_file", TestDirectory + "/a");
566 ScopedDir _b(TestDirectory + "/b");
567 ScopedLink _ba("no_such_file", TestDirectory + "/b/a");
568 ScopedDir _bb(TestDirectory + "/b/b");
569 ScopedLink _bc("no_such_file", TestDirectory + "/b/c");
570 ScopedLink _c("no_such_file", TestDirectory + "/c");
571 ScopedDir _d(TestDirectory + "/d");
572 ScopedDir _dd(TestDirectory + "/d/d");
573 ScopedDir _ddd(TestDirectory + "/d/d/d");
574 ScopedLink _e("no_such_file", TestDirectory + "/e");
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000575
Max Moroze0975672018-04-04 19:47:25 +0000576 std::vector<std::string> VisitedBrokenSymlinks;
577 std::vector<std::string> VisitedNonBrokenSymlinks;
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000578 std::error_code EC;
579 for (vfs::recursive_directory_iterator I(*FS, Twine(TestDirectory), EC), E;
580 I != E; I.increment(EC)) {
Sam McCall39223772018-10-01 16:07:03 +0000581 EXPECT_FALSE(EC);
582 (FS->status(I->path()) ? VisitedNonBrokenSymlinks : VisitedBrokenSymlinks)
583 .push_back(I->path());
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000584 }
585
Max Moroze0975672018-04-04 19:47:25 +0000586 // Check visited file names.
Sam McCall39223772018-10-01 16:07:03 +0000587 EXPECT_THAT(VisitedBrokenSymlinks,
588 UnorderedElementsAre(StringRef(_a), StringRef(_ba),
589 StringRef(_bc), StringRef(_c),
590 StringRef(_e)));
591 EXPECT_THAT(VisitedNonBrokenSymlinks,
592 UnorderedElementsAre(StringRef(_b), StringRef(_bb), StringRef(_d),
593 StringRef(_dd), StringRef(_ddd)));
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000594}
595#endif
596
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000597template <typename DirIter>
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000598static void checkContents(DirIter I, ArrayRef<StringRef> ExpectedOut) {
Ben Langmuir740812b2014-06-24 19:37:16 +0000599 std::error_code EC;
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000600 SmallVector<StringRef, 4> Expected(ExpectedOut.begin(), ExpectedOut.end());
601 SmallVector<std::string, 4> InputToCheck;
Ben Langmuir740812b2014-06-24 19:37:16 +0000602
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000603 // Do not rely on iteration order to check for contents, sort both
604 // content vectors before comparison.
605 for (DirIter E; !EC && I != E; I.increment(EC))
Sam McCall0ae00562018-09-14 12:47:38 +0000606 InputToCheck.push_back(I->path());
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000607
Fangrui Song55fab262018-09-26 22:16:28 +0000608 llvm::sort(InputToCheck);
609 llvm::sort(Expected);
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000610 EXPECT_EQ(InputToCheck.size(), Expected.size());
611
612 unsigned LastElt = std::min(InputToCheck.size(), Expected.size());
613 for (unsigned Idx = 0; Idx != LastElt; ++Idx)
Bruno Cardoso Lopes2835c5c2016-05-12 19:13:04 +0000614 EXPECT_EQ(StringRef(InputToCheck[Idx]), Expected[Idx]);
Ben Langmuir740812b2014-06-24 19:37:16 +0000615}
616
617TEST(VirtualFileSystemTest, OverlayIteration) {
618 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
619 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
620 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
621 new vfs::OverlayFileSystem(Lower));
622 O->pushOverlay(Upper);
623
624 std::error_code EC;
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000625 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
Ben Langmuir740812b2014-06-24 19:37:16 +0000626
627 Lower->addRegularFile("/file1");
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000628 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file1"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000629
630 Upper->addRegularFile("/file2");
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000631 checkContents(O->dir_begin("/", EC), {"/file2", "/file1"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000632
633 Lower->addDirectory("/dir1");
634 Lower->addRegularFile("/dir1/foo");
635 Upper->addDirectory("/dir2");
636 Upper->addRegularFile("/dir2/foo");
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000637 checkContents(O->dir_begin("/dir2", EC), ArrayRef<StringRef>("/dir2/foo"));
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000638 checkContents(O->dir_begin("/", EC), {"/dir2", "/file2", "/dir1", "/file1"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000639}
640
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000641TEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
642 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
643 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
644 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
645 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
646 new vfs::OverlayFileSystem(Lower));
647 O->pushOverlay(Middle);
648 O->pushOverlay(Upper);
649
650 std::error_code EC;
651 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
652 ArrayRef<StringRef>());
653
654 Lower->addRegularFile("/file1");
655 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
656 ArrayRef<StringRef>("/file1"));
657
658 Upper->addDirectory("/dir");
659 Upper->addRegularFile("/dir/file2");
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000660 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
661 {"/dir", "/dir/file2", "/file1"});
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000662
663 Lower->addDirectory("/dir1");
664 Lower->addRegularFile("/dir1/foo");
665 Lower->addDirectory("/dir1/a");
666 Lower->addRegularFile("/dir1/a/b");
667 Middle->addDirectory("/a");
668 Middle->addDirectory("/a/b");
669 Middle->addDirectory("/a/b/c");
670 Middle->addRegularFile("/a/b/c/d");
671 Middle->addRegularFile("/hiddenByUp");
672 Upper->addDirectory("/dir2");
673 Upper->addRegularFile("/dir2/foo");
674 Upper->addRegularFile("/hiddenByUp");
675 checkContents(vfs::recursive_directory_iterator(*O, "/dir2", EC),
676 ArrayRef<StringRef>("/dir2/foo"));
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000677 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
678 {"/dir", "/dir/file2", "/dir2", "/dir2/foo", "/hiddenByUp",
679 "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
680 "/dir1/a/b", "/dir1/foo", "/file1"});
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000681}
682
Ben Langmuir740812b2014-06-24 19:37:16 +0000683TEST(VirtualFileSystemTest, ThreeLevelIteration) {
684 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
685 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
686 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
687 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
688 new vfs::OverlayFileSystem(Lower));
689 O->pushOverlay(Middle);
690 O->pushOverlay(Upper);
691
692 std::error_code EC;
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000693 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
Ben Langmuir740812b2014-06-24 19:37:16 +0000694
695 Middle->addRegularFile("/file2");
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000696 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file2"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000697
698 Lower->addRegularFile("/file1");
699 Upper->addRegularFile("/file3");
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000700 checkContents(O->dir_begin("/", EC), {"/file3", "/file2", "/file1"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000701}
702
703TEST(VirtualFileSystemTest, HiddenInIteration) {
704 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
705 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
706 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
707 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
708 new vfs::OverlayFileSystem(Lower));
709 O->pushOverlay(Middle);
710 O->pushOverlay(Upper);
711
712 std::error_code EC;
Sam McCall0ae00562018-09-14 12:47:38 +0000713 Lower->addRegularFile("/onlyInLow");
714 Lower->addDirectory("/hiddenByMid");
715 Lower->addDirectory("/hiddenByUp");
716 Middle->addRegularFile("/onlyInMid");
717 Middle->addRegularFile("/hiddenByMid");
718 Middle->addDirectory("/hiddenByUp");
719 Upper->addRegularFile("/onlyInUp");
720 Upper->addRegularFile("/hiddenByUp");
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000721 checkContents(
722 O->dir_begin("/", EC),
723 {"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000724
725 // Make sure we get the top-most entry
Ben Langmuirefb8b602014-06-24 21:08:13 +0000726 {
727 std::error_code EC;
728 vfs::directory_iterator I = O->dir_begin("/", EC), E;
Jonas Devliegherefc514902018-10-10 13:27:25 +0000729 for (; !EC && I != E; I.increment(EC))
Sam McCall0ae00562018-09-14 12:47:38 +0000730 if (I->path() == "/hiddenByUp")
Ben Langmuirefb8b602014-06-24 21:08:13 +0000731 break;
732 ASSERT_NE(E, I);
Sam McCall0ae00562018-09-14 12:47:38 +0000733 EXPECT_EQ(sys::fs::file_type::regular_file, I->type());
Ben Langmuirefb8b602014-06-24 21:08:13 +0000734 }
735 {
736 std::error_code EC;
737 vfs::directory_iterator I = O->dir_begin("/", EC), E;
Jonas Devliegherefc514902018-10-10 13:27:25 +0000738 for (; !EC && I != E; I.increment(EC))
Sam McCall0ae00562018-09-14 12:47:38 +0000739 if (I->path() == "/hiddenByMid")
Ben Langmuirefb8b602014-06-24 21:08:13 +0000740 break;
741 ASSERT_NE(E, I);
Sam McCall0ae00562018-09-14 12:47:38 +0000742 EXPECT_EQ(sys::fs::file_type::regular_file, I->type());
Ben Langmuirefb8b602014-06-24 21:08:13 +0000743 }
Ben Langmuir740812b2014-06-24 19:37:16 +0000744}
745
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000746class InMemoryFileSystemTest : public ::testing::Test {
747protected:
Jonas Devliegherefc514902018-10-10 13:27:25 +0000748 llvm::vfs::InMemoryFileSystem FS;
749 llvm::vfs::InMemoryFileSystem NormalizedFS;
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000750
751 InMemoryFileSystemTest()
752 : FS(/*UseNormalizedPaths=*/false),
753 NormalizedFS(/*UseNormalizedPaths=*/true) {}
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000754};
755
Ilya Biryukovd5554c512018-09-04 14:15:53 +0000756MATCHER_P2(IsHardLinkTo, FS, Target, "") {
757 StringRef From = arg;
758 StringRef To = Target;
759 auto OpenedFrom = FS->openFileForRead(From);
760 auto OpenedTo = FS->openFileForRead(To);
761 return !OpenedFrom.getError() && !OpenedTo.getError() &&
762 (*OpenedFrom)->status()->getUniqueID() ==
763 (*OpenedTo)->status()->getUniqueID();
764}
765
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000766TEST_F(InMemoryFileSystemTest, IsEmpty) {
767 auto Stat = FS.status("/a");
Jonas Devliegherefc514902018-10-10 13:27:25 +0000768 ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000769 Stat = FS.status("/");
Rafael Espindolab7ab1872015-10-05 20:20:50 +0000770 ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000771}
772
773TEST_F(InMemoryFileSystemTest, WindowsPath) {
774 FS.addFile("c:/windows/system128/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
775 auto Stat = FS.status("c:");
NAKAMURA Takumi4c33a1a2015-10-06 12:16:27 +0000776#if !defined(_WIN32)
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000777 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
NAKAMURA Takumi4c33a1a2015-10-06 12:16:27 +0000778#endif
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000779 Stat = FS.status("c:/windows/system128/foo.cpp");
780 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
781 FS.addFile("d:/windows/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
782 Stat = FS.status("d:/windows/foo.cpp");
783 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
784}
785
786TEST_F(InMemoryFileSystemTest, OverlayFile) {
787 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000788 NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000789 auto Stat = FS.status("/");
790 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000791 Stat = FS.status("/.");
792 ASSERT_FALSE(Stat);
793 Stat = NormalizedFS.status("/.");
794 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000795 Stat = FS.status("/a");
796 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
797 ASSERT_EQ("/a", Stat->getName());
798}
799
Benjamin Kramer2e2351a2015-10-06 10:04:08 +0000800TEST_F(InMemoryFileSystemTest, OverlayFileNoOwn) {
801 auto Buf = MemoryBuffer::getMemBuffer("a");
802 FS.addFileNoOwn("/a", 0, Buf.get());
803 auto Stat = FS.status("/a");
804 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
805 ASSERT_EQ("/a", Stat->getName());
806}
807
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000808TEST_F(InMemoryFileSystemTest, OpenFileForRead) {
809 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000810 FS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
811 FS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
812 NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
813 NormalizedFS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
814 NormalizedFS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000815 auto File = FS.openFileForRead("/a");
816 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
817 File = FS.openFileForRead("/a"); // Open again.
818 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000819 File = NormalizedFS.openFileForRead("/././a"); // Open again.
820 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000821 File = FS.openFileForRead("/");
Rafael Espindolab7ab1872015-10-05 20:20:50 +0000822 ASSERT_EQ(File.getError(), errc::invalid_argument) << FS.toString();
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000823 File = FS.openFileForRead("/b");
Rafael Espindolab7ab1872015-10-05 20:20:50 +0000824 ASSERT_EQ(File.getError(), errc::no_such_file_or_directory) << FS.toString();
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000825 File = FS.openFileForRead("./c");
826 ASSERT_FALSE(File);
827 File = FS.openFileForRead("e/../d");
828 ASSERT_FALSE(File);
829 File = NormalizedFS.openFileForRead("./c");
Benjamin Kramerd5e0b582015-10-07 08:32:50 +0000830 ASSERT_EQ("c", (*(*File)->getBuffer("ignored"))->getBuffer());
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000831 File = NormalizedFS.openFileForRead("e/../d");
832 ASSERT_EQ("d", (*(*File)->getBuffer("ignored"))->getBuffer());
833}
834
835TEST_F(InMemoryFileSystemTest, DuplicatedFile) {
836 ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
837 ASSERT_FALSE(FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("a")));
838 ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
839 ASSERT_FALSE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("b")));
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000840}
841
842TEST_F(InMemoryFileSystemTest, DirectoryIteration) {
843 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""));
844 FS.addFile("/b/c", 0, MemoryBuffer::getMemBuffer(""));
845
846 std::error_code EC;
847 vfs::directory_iterator I = FS.dir_begin("/", EC);
848 ASSERT_FALSE(EC);
Sam McCall0ae00562018-09-14 12:47:38 +0000849 ASSERT_EQ("/a", I->path());
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000850 I.increment(EC);
851 ASSERT_FALSE(EC);
Sam McCall0ae00562018-09-14 12:47:38 +0000852 ASSERT_EQ("/b", I->path());
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000853 I.increment(EC);
854 ASSERT_FALSE(EC);
855 ASSERT_EQ(vfs::directory_iterator(), I);
856
857 I = FS.dir_begin("/b", EC);
858 ASSERT_FALSE(EC);
Simon Marchiddbabc62018-08-06 21:48:20 +0000859 // When on Windows, we end up with "/b\\c" as the name. Convert to Posix
860 // path for the sake of the comparison.
Sam McCall0ae00562018-09-14 12:47:38 +0000861 ASSERT_EQ("/b/c", getPosixPath(I->path()));
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000862 I.increment(EC);
863 ASSERT_FALSE(EC);
864 ASSERT_EQ(vfs::directory_iterator(), I);
865}
866
Benjamin Kramer1b8dbe32015-10-06 14:45:16 +0000867TEST_F(InMemoryFileSystemTest, WorkingDirectory) {
868 FS.setCurrentWorkingDirectory("/b");
869 FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
870
871 auto Stat = FS.status("/b/c");
872 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
Simon Marchiddbabc62018-08-06 21:48:20 +0000873 ASSERT_EQ("/b/c", Stat->getName());
Benjamin Kramer1b8dbe32015-10-06 14:45:16 +0000874 ASSERT_EQ("/b", *FS.getCurrentWorkingDirectory());
875
876 Stat = FS.status("c");
877 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
Benjamin Kramere9e76072016-01-09 16:33:16 +0000878
879 NormalizedFS.setCurrentWorkingDirectory("/b/c");
880 NormalizedFS.setCurrentWorkingDirectory(".");
Simon Marchiddbabc62018-08-06 21:48:20 +0000881 ASSERT_EQ("/b/c",
882 getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get()));
Benjamin Kramere9e76072016-01-09 16:33:16 +0000883 NormalizedFS.setCurrentWorkingDirectory("..");
Simon Marchiddbabc62018-08-06 21:48:20 +0000884 ASSERT_EQ("/b",
885 getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get()));
Benjamin Kramer1b8dbe32015-10-06 14:45:16 +0000886}
887
Jonas Devliegherecbb5c862018-11-08 00:01:32 +0000888TEST_F(InMemoryFileSystemTest, IsLocal) {
889 FS.setCurrentWorkingDirectory("/b");
890 FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
891
892 std::error_code EC;
893 bool IsLocal = true;
894 EC = FS.isLocal("c", IsLocal);
895 ASSERT_FALSE(EC);
896 ASSERT_FALSE(IsLocal);
897}
898
Eric Liu43cb4512018-05-24 13:52:48 +0000899#if !defined(_WIN32)
Eric Liu33dd6192018-05-24 11:17:00 +0000900TEST_F(InMemoryFileSystemTest, GetRealPath) {
901 SmallString<16> Path;
902 EXPECT_EQ(FS.getRealPath("b", Path), errc::operation_not_permitted);
903
904 auto GetRealPath = [this](StringRef P) {
905 SmallString<16> Output;
906 auto EC = FS.getRealPath(P, Output);
907 EXPECT_FALSE(EC);
908 return Output.str().str();
909 };
910
911 FS.setCurrentWorkingDirectory("a");
912 EXPECT_EQ(GetRealPath("b"), "a/b");
913 EXPECT_EQ(GetRealPath("../b"), "b");
914 EXPECT_EQ(GetRealPath("b/./c"), "a/b/c");
915
916 FS.setCurrentWorkingDirectory("/a");
917 EXPECT_EQ(GetRealPath("b"), "/a/b");
918 EXPECT_EQ(GetRealPath("../b"), "/b");
919 EXPECT_EQ(GetRealPath("b/./c"), "/a/b/c");
920}
Eric Liu43cb4512018-05-24 13:52:48 +0000921#endif // _WIN32
Eric Liu33dd6192018-05-24 11:17:00 +0000922
Ben Hamiltone5af5bd2017-11-09 16:01:16 +0000923TEST_F(InMemoryFileSystemTest, AddFileWithUser) {
924 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), 0xFEEDFACE);
925 auto Stat = FS.status("/a");
926 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
927 ASSERT_TRUE(Stat->isDirectory());
928 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
929 Stat = FS.status("/a/b");
930 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
931 ASSERT_TRUE(Stat->isDirectory());
932 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
933 Stat = FS.status("/a/b/c");
934 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
935 ASSERT_TRUE(Stat->isRegularFile());
936 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
937 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
938}
939
940TEST_F(InMemoryFileSystemTest, AddFileWithGroup) {
941 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, 0xDABBAD00);
942 auto Stat = FS.status("/a");
943 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
944 ASSERT_TRUE(Stat->isDirectory());
945 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
946 Stat = FS.status("/a/b");
947 ASSERT_TRUE(Stat->isDirectory());
948 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
949 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
950 Stat = FS.status("/a/b/c");
951 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
952 ASSERT_TRUE(Stat->isRegularFile());
953 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
954 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
955}
956
957TEST_F(InMemoryFileSystemTest, AddFileWithFileType) {
958 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None,
959 sys::fs::file_type::socket_file);
960 auto Stat = FS.status("/a");
961 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
962 ASSERT_TRUE(Stat->isDirectory());
963 Stat = FS.status("/a/b");
964 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
965 ASSERT_TRUE(Stat->isDirectory());
966 Stat = FS.status("/a/b/c");
967 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
968 ASSERT_EQ(sys::fs::file_type::socket_file, Stat->getType());
969 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
970}
971
972TEST_F(InMemoryFileSystemTest, AddFileWithPerms) {
Jonas Devliegherefc514902018-10-10 13:27:25 +0000973 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None, None,
974 sys::fs::perms::owner_read | sys::fs::perms::owner_write);
Ben Hamiltone5af5bd2017-11-09 16:01:16 +0000975 auto Stat = FS.status("/a");
976 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
977 ASSERT_TRUE(Stat->isDirectory());
978 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
Jonas Devliegherefc514902018-10-10 13:27:25 +0000979 sys::fs::perms::owner_exe,
980 Stat->getPermissions());
Ben Hamiltone5af5bd2017-11-09 16:01:16 +0000981 Stat = FS.status("/a/b");
982 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
983 ASSERT_TRUE(Stat->isDirectory());
984 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
Jonas Devliegherefc514902018-10-10 13:27:25 +0000985 sys::fs::perms::owner_exe,
986 Stat->getPermissions());
Ben Hamiltone5af5bd2017-11-09 16:01:16 +0000987 Stat = FS.status("/a/b/c");
988 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
989 ASSERT_TRUE(Stat->isRegularFile());
990 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write,
991 Stat->getPermissions());
992}
993
Ben Hamilton78381012017-11-16 19:34:08 +0000994TEST_F(InMemoryFileSystemTest, AddDirectoryThenAddChild) {
995 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""), /*User=*/None,
996 /*Group=*/None, sys::fs::file_type::directory_file);
997 FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("abc"), /*User=*/None,
998 /*Group=*/None, sys::fs::file_type::regular_file);
999 auto Stat = FS.status("/a");
1000 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1001 ASSERT_TRUE(Stat->isDirectory());
1002 Stat = FS.status("/a/b");
1003 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1004 ASSERT_TRUE(Stat->isRegularFile());
1005}
1006
Simon Marchiddbabc62018-08-06 21:48:20 +00001007// Test that the name returned by status() is in the same form as the path that
1008// was requested (to match the behavior of RealFileSystem).
1009TEST_F(InMemoryFileSystemTest, StatusName) {
1010 NormalizedFS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"),
1011 /*User=*/None,
1012 /*Group=*/None, sys::fs::file_type::regular_file);
1013 NormalizedFS.setCurrentWorkingDirectory("/a/b");
1014
1015 // Access using InMemoryFileSystem::status.
1016 auto Stat = NormalizedFS.status("../b/c");
1017 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
1018 << NormalizedFS.toString();
1019 ASSERT_TRUE(Stat->isRegularFile());
1020 ASSERT_EQ("../b/c", Stat->getName());
1021
1022 // Access using InMemoryFileAdaptor::status.
1023 auto File = NormalizedFS.openFileForRead("../b/c");
1024 ASSERT_FALSE(File.getError()) << File.getError() << "\n"
1025 << NormalizedFS.toString();
1026 Stat = (*File)->status();
1027 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
1028 << NormalizedFS.toString();
1029 ASSERT_TRUE(Stat->isRegularFile());
1030 ASSERT_EQ("../b/c", Stat->getName());
1031
1032 // Access using a directory iterator.
1033 std::error_code EC;
Jonas Devliegherefc514902018-10-10 13:27:25 +00001034 llvm::vfs::directory_iterator It = NormalizedFS.dir_begin("../b", EC);
Simon Marchiddbabc62018-08-06 21:48:20 +00001035 // When on Windows, we end up with "../b\\c" as the name. Convert to Posix
1036 // path for the sake of the comparison.
Sam McCall0ae00562018-09-14 12:47:38 +00001037 ASSERT_EQ("../b/c", getPosixPath(It->path()));
Simon Marchiddbabc62018-08-06 21:48:20 +00001038}
1039
Ilya Biryukovd5554c512018-09-04 14:15:53 +00001040TEST_F(InMemoryFileSystemTest, AddHardLinkToFile) {
1041 StringRef FromLink = "/path/to/FROM/link";
1042 StringRef Target = "/path/to/TO/file";
1043 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1044 EXPECT_TRUE(FS.addHardLink(FromLink, Target));
1045 EXPECT_THAT(FromLink, IsHardLinkTo(&FS, Target));
1046 EXPECT_TRUE(FS.status(FromLink)->getSize() == FS.status(Target)->getSize());
1047 EXPECT_TRUE(FS.getBufferForFile(FromLink)->get()->getBuffer() ==
1048 FS.getBufferForFile(Target)->get()->getBuffer());
1049}
1050
1051TEST_F(InMemoryFileSystemTest, AddHardLinkInChainPattern) {
1052 StringRef Link0 = "/path/to/0/link";
1053 StringRef Link1 = "/path/to/1/link";
1054 StringRef Link2 = "/path/to/2/link";
1055 StringRef Target = "/path/to/target";
1056 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target file"));
1057 EXPECT_TRUE(FS.addHardLink(Link2, Target));
1058 EXPECT_TRUE(FS.addHardLink(Link1, Link2));
1059 EXPECT_TRUE(FS.addHardLink(Link0, Link1));
1060 EXPECT_THAT(Link0, IsHardLinkTo(&FS, Target));
1061 EXPECT_THAT(Link1, IsHardLinkTo(&FS, Target));
1062 EXPECT_THAT(Link2, IsHardLinkTo(&FS, Target));
1063}
1064
1065TEST_F(InMemoryFileSystemTest, AddHardLinkToAFileThatWasNotAddedBefore) {
1066 EXPECT_FALSE(FS.addHardLink("/path/to/link", "/path/to/target"));
1067}
1068
1069TEST_F(InMemoryFileSystemTest, AddHardLinkFromAFileThatWasAddedBefore) {
1070 StringRef Link = "/path/to/link";
1071 StringRef Target = "/path/to/target";
1072 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1073 FS.addFile(Link, 0, MemoryBuffer::getMemBuffer("content of link"));
1074 EXPECT_FALSE(FS.addHardLink(Link, Target));
1075}
1076
1077TEST_F(InMemoryFileSystemTest, AddSameHardLinkMoreThanOnce) {
1078 StringRef Link = "/path/to/link";
1079 StringRef Target = "/path/to/target";
1080 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1081 EXPECT_TRUE(FS.addHardLink(Link, Target));
1082 EXPECT_FALSE(FS.addHardLink(Link, Target));
1083}
1084
1085TEST_F(InMemoryFileSystemTest, AddFileInPlaceOfAHardLinkWithSameContent) {
1086 StringRef Link = "/path/to/link";
1087 StringRef Target = "/path/to/target";
1088 StringRef Content = "content of target";
1089 EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1090 EXPECT_TRUE(FS.addHardLink(Link, Target));
1091 EXPECT_TRUE(FS.addFile(Link, 0, MemoryBuffer::getMemBuffer(Content)));
1092}
1093
1094TEST_F(InMemoryFileSystemTest, AddFileInPlaceOfAHardLinkWithDifferentContent) {
1095 StringRef Link = "/path/to/link";
1096 StringRef Target = "/path/to/target";
1097 StringRef Content = "content of target";
1098 StringRef LinkContent = "different content of link";
1099 EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1100 EXPECT_TRUE(FS.addHardLink(Link, Target));
1101 EXPECT_FALSE(FS.addFile(Link, 0, MemoryBuffer::getMemBuffer(LinkContent)));
1102}
1103
1104TEST_F(InMemoryFileSystemTest, AddHardLinkToADirectory) {
1105 StringRef Dir = "path/to/dummy/dir";
1106 StringRef Link = "/path/to/link";
1107 StringRef File = "path/to/dummy/dir/target";
1108 StringRef Content = "content of target";
1109 EXPECT_TRUE(FS.addFile(File, 0, MemoryBuffer::getMemBuffer(Content)));
1110 EXPECT_FALSE(FS.addHardLink(Link, Dir));
1111}
1112
1113TEST_F(InMemoryFileSystemTest, AddHardLinkFromADirectory) {
1114 StringRef Dir = "path/to/dummy/dir";
1115 StringRef Target = "path/to/dummy/dir/target";
1116 StringRef Content = "content of target";
1117 EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1118 EXPECT_FALSE(FS.addHardLink(Dir, Target));
1119}
1120
1121TEST_F(InMemoryFileSystemTest, AddHardLinkUnderAFile) {
1122 StringRef CommonContent = "content string";
1123 FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer(CommonContent));
1124 FS.addFile("/c/d", 0, MemoryBuffer::getMemBuffer(CommonContent));
1125 EXPECT_FALSE(FS.addHardLink("/c/d/e", "/a/b"));
1126}
1127
1128TEST_F(InMemoryFileSystemTest, RecursiveIterationWithHardLink) {
1129 std::error_code EC;
1130 FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("content string"));
1131 EXPECT_TRUE(FS.addHardLink("/c/d", "/a/b"));
1132 auto I = vfs::recursive_directory_iterator(FS, "/", EC);
1133 ASSERT_FALSE(EC);
1134 std::vector<std::string> Nodes;
1135 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
1136 I.increment(EC)) {
Sam McCall0ae00562018-09-14 12:47:38 +00001137 Nodes.push_back(getPosixPath(I->path()));
Ilya Biryukovd5554c512018-09-04 14:15:53 +00001138 }
1139 EXPECT_THAT(Nodes, testing::UnorderedElementsAre("/a", "/a/b", "/c", "/c/d"));
1140}
1141
Ben Langmuir93853232014-03-05 21:32:20 +00001142// NOTE: in the tests below, we use '//root/' as our root directory, since it is
1143// a legal *absolute* path on Windows as well as *nix.
Ben Langmuir97882e72014-02-24 20:56:37 +00001144class VFSFromYAMLTest : public ::testing::Test {
1145public:
1146 int NumDiagnostics;
Ben Langmuir93853232014-03-05 21:32:20 +00001147
Alexander Kornienko34eb2072015-04-11 02:00:23 +00001148 void SetUp() override { NumDiagnostics = 0; }
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001149
Ben Langmuir97882e72014-02-24 20:56:37 +00001150 static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
1151 VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
1152 ++Test->NumDiagnostics;
1153 }
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001154
Ben Langmuir97882e72014-02-24 20:56:37 +00001155 IntrusiveRefCntPtr<vfs::FileSystem>
1156 getFromYAMLRawString(StringRef Content,
1157 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
Rafael Espindolad87f8d72014-08-27 20:03:29 +00001158 std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content);
Bruno Cardoso Lopesd878e282016-03-20 02:08:48 +00001159 return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, "", this,
Rafael Espindola91ac8df2014-08-17 23:27:13 +00001160 ExternalFS);
Ben Langmuir97882e72014-02-24 20:56:37 +00001161 }
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001162
Ben Langmuir97882e72014-02-24 20:56:37 +00001163 IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
1164 StringRef Content,
1165 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
1166 std::string VersionPlusContent("{\n 'version':0,\n");
1167 VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
1168 return getFromYAMLRawString(VersionPlusContent, ExternalFS);
1169 }
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +00001170
1171 // This is intended as a "XFAIL" for windows hosts.
1172 bool supportsSameDirMultipleYAMLEntries() {
1173 Triple Host(Triple::normalize(sys::getProcessTriple()));
1174 return !Host.isOSWindows();
1175 }
Ben Langmuir97882e72014-02-24 20:56:37 +00001176};
1177
1178TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001179 IntrusiveRefCntPtr<vfs::FileSystem> FS;
1180 FS = getFromYAMLString("");
Alp Tokerf994cef2014-07-05 03:08:06 +00001181 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001182 FS = getFromYAMLString("[]");
Alp Tokerf994cef2014-07-05 03:08:06 +00001183 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001184 FS = getFromYAMLString("'string'");
Alp Tokerf994cef2014-07-05 03:08:06 +00001185 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001186 EXPECT_EQ(3, NumDiagnostics);
1187}
1188
Ben Langmuir97882e72014-02-24 20:56:37 +00001189TEST_F(VFSFromYAMLTest, MappedFiles) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001190 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001191 Lower->addRegularFile("//root/foo/bar/a");
Jonas Devliegherefc514902018-10-10 13:27:25 +00001192 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1193 "{ 'roots': [\n"
1194 "{\n"
1195 " 'type': 'directory',\n"
1196 " 'name': '//root/',\n"
1197 " 'contents': [ {\n"
1198 " 'type': 'file',\n"
1199 " 'name': 'file1',\n"
1200 " 'external-contents': '//root/foo/bar/a'\n"
1201 " },\n"
1202 " {\n"
1203 " 'type': 'file',\n"
1204 " 'name': 'file2',\n"
1205 " 'external-contents': '//root/foo/b'\n"
1206 " }\n"
1207 " ]\n"
1208 "}\n"
1209 "]\n"
1210 "}",
1211 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001212 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001213
1214 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1215 new vfs::OverlayFileSystem(Lower));
1216 O->pushOverlay(FS);
1217
1218 // file
Ben Langmuir93853232014-03-05 21:32:20 +00001219 ErrorOr<vfs::Status> S = O->status("//root/file1");
Rafael Espindola3ae06202014-05-31 03:20:52 +00001220 ASSERT_FALSE(S.getError());
Ben Langmuir93853232014-03-05 21:32:20 +00001221 EXPECT_EQ("//root/foo/bar/a", S->getName());
Ben Langmuirf13302e2015-12-10 23:41:39 +00001222 EXPECT_TRUE(S->IsVFSMapped);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001223
Ben Langmuir93853232014-03-05 21:32:20 +00001224 ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
1225 EXPECT_EQ("//root/foo/bar/a", SLower->getName());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001226 EXPECT_TRUE(S->equivalent(*SLower));
Ben Langmuirf13302e2015-12-10 23:41:39 +00001227 EXPECT_FALSE(SLower->IsVFSMapped);
1228
1229 // file after opening
1230 auto OpenedF = O->openFileForRead("//root/file1");
1231 ASSERT_FALSE(OpenedF.getError());
1232 auto OpenedS = (*OpenedF)->status();
1233 ASSERT_FALSE(OpenedS.getError());
1234 EXPECT_EQ("//root/foo/bar/a", OpenedS->getName());
1235 EXPECT_TRUE(OpenedS->IsVFSMapped);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001236
1237 // directory
Ben Langmuir93853232014-03-05 21:32:20 +00001238 S = O->status("//root/");
Rafael Espindola3ae06202014-05-31 03:20:52 +00001239 ASSERT_FALSE(S.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001240 EXPECT_TRUE(S->isDirectory());
Ben Langmuir93853232014-03-05 21:32:20 +00001241 EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001242
1243 // broken mapping
Rafael Espindola71de0b62014-06-13 17:20:50 +00001244 EXPECT_EQ(O->status("//root/file2").getError(),
1245 llvm::errc::no_such_file_or_directory);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001246 EXPECT_EQ(0, NumDiagnostics);
1247}
1248
Ben Langmuir97882e72014-02-24 20:56:37 +00001249TEST_F(VFSFromYAMLTest, CaseInsensitive) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001250 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001251 Lower->addRegularFile("//root/foo/bar/a");
Jonas Devliegherefc514902018-10-10 13:27:25 +00001252 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1253 "{ 'case-sensitive': 'false',\n"
1254 " 'roots': [\n"
1255 "{\n"
1256 " 'type': 'directory',\n"
1257 " 'name': '//root/',\n"
1258 " 'contents': [ {\n"
1259 " 'type': 'file',\n"
1260 " 'name': 'XX',\n"
1261 " 'external-contents': '//root/foo/bar/a'\n"
1262 " }\n"
1263 " ]\n"
1264 "}]}",
1265 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001266 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001267
1268 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1269 new vfs::OverlayFileSystem(Lower));
1270 O->pushOverlay(FS);
1271
Ben Langmuir93853232014-03-05 21:32:20 +00001272 ErrorOr<vfs::Status> S = O->status("//root/XX");
Rafael Espindola3ae06202014-05-31 03:20:52 +00001273 ASSERT_FALSE(S.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001274
Ben Langmuir93853232014-03-05 21:32:20 +00001275 ErrorOr<vfs::Status> SS = O->status("//root/xx");
Rafael Espindola3ae06202014-05-31 03:20:52 +00001276 ASSERT_FALSE(SS.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001277 EXPECT_TRUE(S->equivalent(*SS));
Ben Langmuir93853232014-03-05 21:32:20 +00001278 SS = O->status("//root/xX");
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001279 EXPECT_TRUE(S->equivalent(*SS));
Ben Langmuir93853232014-03-05 21:32:20 +00001280 SS = O->status("//root/Xx");
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001281 EXPECT_TRUE(S->equivalent(*SS));
1282 EXPECT_EQ(0, NumDiagnostics);
1283}
1284
Ben Langmuir97882e72014-02-24 20:56:37 +00001285TEST_F(VFSFromYAMLTest, CaseSensitive) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001286 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001287 Lower->addRegularFile("//root/foo/bar/a");
Jonas Devliegherefc514902018-10-10 13:27:25 +00001288 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1289 "{ 'case-sensitive': 'true',\n"
1290 " 'roots': [\n"
1291 "{\n"
1292 " 'type': 'directory',\n"
1293 " 'name': '//root/',\n"
1294 " 'contents': [ {\n"
1295 " 'type': 'file',\n"
1296 " 'name': 'XX',\n"
1297 " 'external-contents': '//root/foo/bar/a'\n"
1298 " }\n"
1299 " ]\n"
1300 "}]}",
1301 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001302 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001303
1304 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1305 new vfs::OverlayFileSystem(Lower));
1306 O->pushOverlay(FS);
1307
Ben Langmuir93853232014-03-05 21:32:20 +00001308 ErrorOr<vfs::Status> SS = O->status("//root/xx");
Rafael Espindola71de0b62014-06-13 17:20:50 +00001309 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuir93853232014-03-05 21:32:20 +00001310 SS = O->status("//root/xX");
Rafael Espindola71de0b62014-06-13 17:20:50 +00001311 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuir93853232014-03-05 21:32:20 +00001312 SS = O->status("//root/Xx");
Rafael Espindola71de0b62014-06-13 17:20:50 +00001313 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001314 EXPECT_EQ(0, NumDiagnostics);
1315}
1316
Ben Langmuir97882e72014-02-24 20:56:37 +00001317TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001318 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1319
1320 // invalid YAML at top-level
1321 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001322 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001323 // invalid YAML in roots
1324 FS = getFromYAMLString("{ 'roots':[}", Lower);
1325 // invalid YAML in directory
1326 FS = getFromYAMLString(
1327 "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
1328 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001329 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001330
1331 // invalid configuration
1332 FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001333 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001334 FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001335 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001336
1337 // invalid roots
1338 FS = getFromYAMLString("{ 'roots':'' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001339 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001340 FS = getFromYAMLString("{ 'roots':{} }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001341 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001342
1343 // invalid entries
1344 FS = getFromYAMLString(
1345 "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001346 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001347 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
1348 "'external-contents': 'other' }",
1349 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001350 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001351 FS = getFromYAMLString(
1352 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
1353 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001354 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001355 FS = getFromYAMLString(
1356 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
1357 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001358 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001359 FS = getFromYAMLString(
1360 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
1361 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001362 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001363 FS = getFromYAMLString(
1364 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
1365 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001366 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001367 FS = getFromYAMLString(
1368 "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
1369 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001370 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001371
1372 // missing mandatory fields
1373 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001374 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001375 FS = getFromYAMLString(
1376 "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001377 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001378 FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001379 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001380
1381 // duplicate keys
1382 FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001383 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001384 FS = getFromYAMLString(
1385 "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
1386 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001387 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001388 FS =
1389 getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
1390 "'external-contents':'blah' } ] }",
1391 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001392 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001393
1394 // missing version
1395 FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001396 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001397
1398 // bad version number
1399 FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001400 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001401 FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001402 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001403 FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001404 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001405 EXPECT_EQ(24, NumDiagnostics);
1406}
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001407
Ben Langmuirb59cf672014-02-27 00:25:12 +00001408TEST_F(VFSFromYAMLTest, UseExternalName) {
1409 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001410 Lower->addRegularFile("//root/external/file");
Ben Langmuirb59cf672014-02-27 00:25:12 +00001411
Jonas Devliegherefc514902018-10-10 13:27:25 +00001412 IntrusiveRefCntPtr<vfs::FileSystem> FS =
1413 getFromYAMLString("{ 'roots': [\n"
1414 " { 'type': 'file', 'name': '//root/A',\n"
1415 " 'external-contents': '//root/external/file'\n"
1416 " },\n"
1417 " { 'type': 'file', 'name': '//root/B',\n"
1418 " 'use-external-name': true,\n"
1419 " 'external-contents': '//root/external/file'\n"
1420 " },\n"
1421 " { 'type': 'file', 'name': '//root/C',\n"
1422 " 'use-external-name': false,\n"
1423 " 'external-contents': '//root/external/file'\n"
1424 " }\n"
1425 "] }",
1426 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001427 ASSERT_TRUE(nullptr != FS.get());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001428
1429 // default true
Ben Langmuir93853232014-03-05 21:32:20 +00001430 EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001431 // explicit
Ben Langmuir93853232014-03-05 21:32:20 +00001432 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1433 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001434
1435 // global configuration
Jonas Devliegherefc514902018-10-10 13:27:25 +00001436 FS = getFromYAMLString("{ 'use-external-names': false,\n"
1437 " 'roots': [\n"
1438 " { 'type': 'file', 'name': '//root/A',\n"
1439 " 'external-contents': '//root/external/file'\n"
1440 " },\n"
1441 " { 'type': 'file', 'name': '//root/B',\n"
1442 " 'use-external-name': true,\n"
1443 " 'external-contents': '//root/external/file'\n"
1444 " },\n"
1445 " { 'type': 'file', 'name': '//root/C',\n"
1446 " 'use-external-name': false,\n"
1447 " 'external-contents': '//root/external/file'\n"
1448 " }\n"
1449 "] }",
1450 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001451 ASSERT_TRUE(nullptr != FS.get());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001452
1453 // default
Ben Langmuir93853232014-03-05 21:32:20 +00001454 EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001455 // explicit
Ben Langmuir93853232014-03-05 21:32:20 +00001456 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1457 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001458}
1459
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001460TEST_F(VFSFromYAMLTest, MultiComponentPath) {
1461 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001462 Lower->addRegularFile("//root/other");
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001463
1464 // file in roots
Jonas Devliegherefc514902018-10-10 13:27:25 +00001465 IntrusiveRefCntPtr<vfs::FileSystem> FS =
1466 getFromYAMLString("{ 'roots': [\n"
1467 " { 'type': 'file', 'name': '//root/path/to/file',\n"
1468 " 'external-contents': '//root/other' }]\n"
1469 "}",
1470 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001471 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001472 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1473 EXPECT_FALSE(FS->status("//root/path/to").getError());
1474 EXPECT_FALSE(FS->status("//root/path").getError());
1475 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001476
1477 // at the start
1478 FS = getFromYAMLString(
1479 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001480 " { 'type': 'directory', 'name': '//root/path/to',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001481 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001482 " 'external-contents': '//root/other' }]}]\n"
Jonas Devliegherefc514902018-10-10 13:27:25 +00001483 "}",
1484 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001485 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001486 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1487 EXPECT_FALSE(FS->status("//root/path/to").getError());
1488 EXPECT_FALSE(FS->status("//root/path").getError());
1489 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001490
1491 // at the end
1492 FS = getFromYAMLString(
1493 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001494 " { 'type': 'directory', 'name': '//root/',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001495 " 'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001496 " 'external-contents': '//root/other' }]}]\n"
Jonas Devliegherefc514902018-10-10 13:27:25 +00001497 "}",
1498 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001499 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001500 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1501 EXPECT_FALSE(FS->status("//root/path/to").getError());
1502 EXPECT_FALSE(FS->status("//root/path").getError());
1503 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001504}
1505
1506TEST_F(VFSFromYAMLTest, TrailingSlashes) {
1507 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001508 Lower->addRegularFile("//root/other");
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001509
1510 // file in roots
1511 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1512 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001513 " { 'type': 'directory', 'name': '//root/path/to////',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001514 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001515 " 'external-contents': '//root/other' }]}]\n"
Jonas Devliegherefc514902018-10-10 13:27:25 +00001516 "}",
1517 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001518 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001519 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1520 EXPECT_FALSE(FS->status("//root/path/to").getError());
1521 EXPECT_FALSE(FS->status("//root/path").getError());
1522 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001523}
Ben Langmuir740812b2014-06-24 19:37:16 +00001524
1525TEST_F(VFSFromYAMLTest, DirectoryIteration) {
1526 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1527 Lower->addDirectory("//root/");
1528 Lower->addDirectory("//root/foo");
1529 Lower->addDirectory("//root/foo/bar");
1530 Lower->addRegularFile("//root/foo/bar/a");
1531 Lower->addRegularFile("//root/foo/bar/b");
1532 Lower->addRegularFile("//root/file3");
Jonas Devliegherefc514902018-10-10 13:27:25 +00001533 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1534 "{ 'use-external-names': false,\n"
1535 " 'roots': [\n"
1536 "{\n"
1537 " 'type': 'directory',\n"
1538 " 'name': '//root/',\n"
1539 " 'contents': [ {\n"
1540 " 'type': 'file',\n"
1541 " 'name': 'file1',\n"
1542 " 'external-contents': '//root/foo/bar/a'\n"
1543 " },\n"
1544 " {\n"
1545 " 'type': 'file',\n"
1546 " 'name': 'file2',\n"
1547 " 'external-contents': '//root/foo/bar/b'\n"
1548 " }\n"
1549 " ]\n"
1550 "}\n"
1551 "]\n"
1552 "}",
1553 Lower);
Hans Wennborgdcfba332015-10-06 23:40:43 +00001554 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuir740812b2014-06-24 19:37:16 +00001555
1556 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1557 new vfs::OverlayFileSystem(Lower));
1558 O->pushOverlay(FS);
1559
1560 std::error_code EC;
Benjamin Kramer2a23e552016-01-10 10:45:19 +00001561 checkContents(O->dir_begin("//root/", EC),
Bruno Cardoso Lopes26092b22016-05-12 04:43:27 +00001562 {"//root/file1", "//root/file2", "//root/file3", "//root/foo"});
Ben Langmuir740812b2014-06-24 19:37:16 +00001563
Benjamin Kramer2a23e552016-01-10 10:45:19 +00001564 checkContents(O->dir_begin("//root/foo/bar", EC),
1565 {"//root/foo/bar/a", "//root/foo/bar/b"});
Ben Langmuir740812b2014-06-24 19:37:16 +00001566}
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +00001567
1568TEST_F(VFSFromYAMLTest, DirectoryIterationSameDirMultipleEntries) {
1569 // https://llvm.org/bugs/show_bug.cgi?id=27725
1570 if (!supportsSameDirMultipleYAMLEntries())
1571 return;
1572
1573 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1574 Lower->addDirectory("//root/zab");
1575 Lower->addDirectory("//root/baz");
1576 Lower->addRegularFile("//root/zab/a");
1577 Lower->addRegularFile("//root/zab/b");
1578 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1579 "{ 'use-external-names': false,\n"
1580 " 'roots': [\n"
1581 "{\n"
1582 " 'type': 'directory',\n"
1583 " 'name': '//root/baz/',\n"
1584 " 'contents': [ {\n"
1585 " 'type': 'file',\n"
1586 " 'name': 'x',\n"
1587 " 'external-contents': '//root/zab/a'\n"
1588 " }\n"
1589 " ]\n"
1590 "},\n"
1591 "{\n"
1592 " 'type': 'directory',\n"
1593 " 'name': '//root/baz/',\n"
1594 " 'contents': [ {\n"
1595 " 'type': 'file',\n"
1596 " 'name': 'y',\n"
1597 " 'external-contents': '//root/zab/b'\n"
1598 " }\n"
1599 " ]\n"
1600 "}\n"
1601 "]\n"
1602 "}",
1603 Lower);
1604 ASSERT_TRUE(FS.get() != nullptr);
1605
1606 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1607 new vfs::OverlayFileSystem(Lower));
1608 O->pushOverlay(FS);
1609
1610 std::error_code EC;
1611
1612 checkContents(O->dir_begin("//root/baz/", EC),
1613 {"//root/baz/x", "//root/baz/y"});
1614}
Bruno Cardoso Lopes32b28972016-05-14 00:00:18 +00001615
1616TEST_F(VFSFromYAMLTest, RecursiveDirectoryIterationLevel) {
1617
1618 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1619 Lower->addDirectory("//root/a");
1620 Lower->addDirectory("//root/a/b");
1621 Lower->addDirectory("//root/a/b/c");
1622 Lower->addRegularFile("//root/a/b/c/file");
1623 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1624 "{ 'use-external-names': false,\n"
1625 " 'roots': [\n"
1626 "{\n"
1627 " 'type': 'directory',\n"
1628 " 'name': '//root/a/b/c/',\n"
1629 " 'contents': [ {\n"
1630 " 'type': 'file',\n"
1631 " 'name': 'file',\n"
1632 " 'external-contents': '//root/a/b/c/file'\n"
1633 " }\n"
1634 " ]\n"
1635 "},\n"
1636 "]\n"
1637 "}",
1638 Lower);
1639 ASSERT_TRUE(FS.get() != nullptr);
1640
1641 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1642 new vfs::OverlayFileSystem(Lower));
1643 O->pushOverlay(FS);
1644
1645 std::error_code EC;
1646
1647 // Test recursive_directory_iterator level()
1648 vfs::recursive_directory_iterator I = vfs::recursive_directory_iterator(
Jonas Devliegherefc514902018-10-10 13:27:25 +00001649 *O, "//root", EC),
1650 E;
Bruno Cardoso Lopes32b28972016-05-14 00:00:18 +00001651 ASSERT_FALSE(EC);
1652 for (int l = 0; I != E; I.increment(EC), ++l) {
1653 ASSERT_FALSE(EC);
1654 EXPECT_EQ(I.level(), l);
1655 }
1656 EXPECT_EQ(I, E);
1657}
Volodymyr Sapsai3b2f6a42018-08-07 19:05:41 +00001658
1659TEST_F(VFSFromYAMLTest, RelativePaths) {
1660 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1661 // Filename at root level without a parent directory.
1662 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1663 "{ 'roots': [\n"
1664 " { 'type': 'file', 'name': 'file-not-in-directory.h',\n"
1665 " 'external-contents': '//root/external/file'\n"
1666 " }\n"
Jonas Devliegherefc514902018-10-10 13:27:25 +00001667 "] }",
1668 Lower);
Volodymyr Sapsai3b2f6a42018-08-07 19:05:41 +00001669 EXPECT_EQ(nullptr, FS.get());
1670
1671 // Relative file path.
Jonas Devliegherefc514902018-10-10 13:27:25 +00001672 FS = getFromYAMLString("{ 'roots': [\n"
1673 " { 'type': 'file', 'name': 'relative/file/path.h',\n"
1674 " 'external-contents': '//root/external/file'\n"
1675 " }\n"
1676 "] }",
1677 Lower);
Volodymyr Sapsai3b2f6a42018-08-07 19:05:41 +00001678 EXPECT_EQ(nullptr, FS.get());
1679
1680 // Relative directory path.
1681 FS = getFromYAMLString(
Jonas Devliegherefc514902018-10-10 13:27:25 +00001682 "{ 'roots': [\n"
1683 " { 'type': 'directory', 'name': 'relative/directory/path.h',\n"
1684 " 'contents': []\n"
1685 " }\n"
1686 "] }",
1687 Lower);
Volodymyr Sapsai3b2f6a42018-08-07 19:05:41 +00001688 EXPECT_EQ(nullptr, FS.get());
1689
1690 EXPECT_EQ(3, NumDiagnostics);
1691}
Volodymyr Sapsai91e13162018-10-26 22:14:33 +00001692
1693TEST_F(VFSFromYAMLTest, NonFallthroughDirectoryIteration) {
1694 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1695 Lower->addDirectory("//root/");
1696 Lower->addRegularFile("//root/a");
1697 Lower->addRegularFile("//root/b");
1698 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1699 "{ 'use-external-names': false,\n"
1700 " 'fallthrough': false,\n"
1701 " 'roots': [\n"
1702 "{\n"
1703 " 'type': 'directory',\n"
1704 " 'name': '//root/',\n"
1705 " 'contents': [ {\n"
1706 " 'type': 'file',\n"
1707 " 'name': 'c',\n"
1708 " 'external-contents': '//root/a'\n"
1709 " }\n"
1710 " ]\n"
1711 "}\n"
1712 "]\n"
1713 "}",
1714 Lower);
1715 ASSERT_TRUE(FS.get() != nullptr);
1716
1717 std::error_code EC;
1718 checkContents(FS->dir_begin("//root/", EC),
1719 {"//root/c"});
1720}
1721
1722TEST_F(VFSFromYAMLTest, DirectoryIterationWithDuplicates) {
1723 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1724 Lower->addDirectory("//root/");
1725 Lower->addRegularFile("//root/a");
1726 Lower->addRegularFile("//root/b");
1727 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1728 "{ 'use-external-names': false,\n"
1729 " 'roots': [\n"
1730 "{\n"
1731 " 'type': 'directory',\n"
1732 " 'name': '//root/',\n"
1733 " 'contents': [ {\n"
1734 " 'type': 'file',\n"
1735 " 'name': 'a',\n"
1736 " 'external-contents': '//root/a'\n"
1737 " }\n"
1738 " ]\n"
1739 "}\n"
1740 "]\n"
1741 "}",
1742 Lower);
1743 ASSERT_TRUE(FS.get() != nullptr);
1744
1745 std::error_code EC;
1746 checkContents(FS->dir_begin("//root/", EC),
1747 {"//root/a", "//root/b"});
1748}
1749
1750TEST_F(VFSFromYAMLTest, DirectoryIterationErrorInVFSLayer) {
1751 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1752 Lower->addDirectory("//root/");
1753 Lower->addDirectory("//root/foo");
1754 Lower->addRegularFile("//root/foo/a");
1755 Lower->addRegularFile("//root/foo/b");
1756 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1757 "{ 'use-external-names': false,\n"
1758 " 'roots': [\n"
1759 "{\n"
1760 " 'type': 'directory',\n"
1761 " 'name': '//root/',\n"
1762 " 'contents': [ {\n"
1763 " 'type': 'file',\n"
1764 " 'name': 'bar/a',\n"
1765 " 'external-contents': '//root/foo/a'\n"
1766 " }\n"
1767 " ]\n"
1768 "}\n"
1769 "]\n"
1770 "}",
1771 Lower);
1772 ASSERT_TRUE(FS.get() != nullptr);
1773
1774 std::error_code EC;
1775 checkContents(FS->dir_begin("//root/foo", EC),
1776 {"//root/foo/a", "//root/foo/b"});
1777}