blob: f6cbd5bbae3f061a7d1c166e169ffb33f9d02d59 [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//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Ben Langmuirc8130a72014-02-20 21:59:23 +00006//
7//===----------------------------------------------------------------------===//
8
Jonas Devliegherefc514902018-10-10 13:27:25 +00009#include "llvm/Support/VirtualFileSystem.h"
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +000010#include "llvm/ADT/Triple.h"
Nico Weberd637c052018-04-30 13:52:15 +000011#include "llvm/Config/llvm-config.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"
Simon Marchiddbabc62018-08-06 21:48:20 +000015#include "llvm/Support/Path.h"
Ben Langmuird51ba0b2014-02-21 23:39:37 +000016#include "llvm/Support/SourceMgr.h"
Ilya Biryukovd5554c512018-09-04 14:15:53 +000017#include "gmock/gmock.h"
Ben Langmuirc8130a72014-02-20 21:59:23 +000018#include "gtest/gtest.h"
19#include <map>
Ilya Biryukovd5554c512018-09-04 14:15:53 +000020#include <string>
Hans Wennborgdcfba332015-10-06 23:40:43 +000021
Ben Langmuirc8130a72014-02-20 21:59:23 +000022using namespace llvm;
23using llvm::sys::fs::UniqueID;
Sam McCall39223772018-10-01 16:07:03 +000024using testing::ElementsAre;
25using testing::Pair;
26using testing::UnorderedElementsAre;
Ben Langmuirc8130a72014-02-20 21:59:23 +000027
28namespace {
Ben Langmuirf13302e2015-12-10 23:41:39 +000029struct DummyFile : public vfs::File {
30 vfs::Status S;
31 explicit DummyFile(vfs::Status S) : S(S) {}
32 llvm::ErrorOr<vfs::Status> status() override { return S; }
33 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
34 getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
35 bool IsVolatile) override {
36 llvm_unreachable("unimplemented");
37 }
Eugene Zelenko1660a5d2016-01-26 19:01:06 +000038 std::error_code close() override { return std::error_code(); }
Ben Langmuirf13302e2015-12-10 23:41:39 +000039};
40
Ben Langmuirc8130a72014-02-20 21:59:23 +000041class DummyFileSystem : public vfs::FileSystem {
42 int FSID; // used to produce UniqueIDs
43 int FileID; // used to produce UniqueIDs
44 std::map<std::string, vfs::Status> FilesAndDirs;
45
46 static int getNextFSID() {
47 static int Count = 0;
48 return Count++;
49 }
50
51public:
52 DummyFileSystem() : FSID(getNextFSID()), FileID(0) {}
53
Fariborz Jahanian5afc8692014-10-01 16:56:40 +000054 ErrorOr<vfs::Status> status(const Twine &Path) override {
Ben Langmuirc8130a72014-02-20 21:59:23 +000055 std::map<std::string, vfs::Status>::iterator I =
Ben Langmuird51ba0b2014-02-21 23:39:37 +000056 FilesAndDirs.find(Path.str());
Ben Langmuirc8130a72014-02-20 21:59:23 +000057 if (I == FilesAndDirs.end())
Rafael Espindola71de0b62014-06-13 17:20:50 +000058 return make_error_code(llvm::errc::no_such_file_or_directory);
Ben Langmuirc8130a72014-02-20 21:59:23 +000059 return I->second;
60 }
Benjamin Kramera8857962014-10-26 22:44:13 +000061 ErrorOr<std::unique_ptr<vfs::File>>
62 openFileForRead(const Twine &Path) override {
Ben Langmuirf13302e2015-12-10 23:41:39 +000063 auto S = status(Path);
64 if (S)
65 return std::unique_ptr<vfs::File>(new DummyFile{*S});
66 return S.getError();
Ben Langmuirc8130a72014-02-20 21:59:23 +000067 }
Benjamin Kramer7708b2a2015-10-05 13:55:20 +000068 llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
69 return std::string();
70 }
71 std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
72 return std::error_code();
73 }
Eric Liua840a462018-05-18 13:22:49 +000074 // Map any symlink to "/symlink".
Sam McCall99538e82018-11-09 15:11:34 +000075 std::error_code getRealPath(const Twine &Path,
76 SmallVectorImpl<char> &Output) const override {
Eric Liua840a462018-05-18 13:22:49 +000077 auto I = FilesAndDirs.find(Path.str());
78 if (I == FilesAndDirs.end())
79 return make_error_code(llvm::errc::no_such_file_or_directory);
80 if (I->second.isSymlink()) {
81 Output.clear();
82 Twine("/symlink").toVector(Output);
83 return std::error_code();
84 }
85 Output.clear();
86 Path.toVector(Output);
87 return std::error_code();
88 }
Ben Langmuirc8130a72014-02-20 21:59:23 +000089
Jonas Devliegherefc514902018-10-10 13:27:25 +000090 struct DirIterImpl : public llvm::vfs::detail::DirIterImpl {
Ben Langmuir740812b2014-06-24 19:37:16 +000091 std::map<std::string, vfs::Status> &FilesAndDirs;
92 std::map<std::string, vfs::Status>::iterator I;
93 std::string Path;
Ben Langmuir7c9f6c82014-06-25 20:25:40 +000094 bool isInPath(StringRef S) {
95 if (Path.size() < S.size() && S.find(Path) == 0) {
96 auto LastSep = S.find_last_of('/');
Jonas Devliegherefc514902018-10-10 13:27:25 +000097 if (LastSep == Path.size() || LastSep == Path.size() - 1)
Ben Langmuir7c9f6c82014-06-25 20:25:40 +000098 return true;
99 }
100 return false;
101 }
Ben Langmuir740812b2014-06-24 19:37:16 +0000102 DirIterImpl(std::map<std::string, vfs::Status> &FilesAndDirs,
103 const Twine &_Path)
104 : FilesAndDirs(FilesAndDirs), I(FilesAndDirs.begin()),
105 Path(_Path.str()) {
Jonas Devliegherefc514902018-10-10 13:27:25 +0000106 for (; I != FilesAndDirs.end(); ++I) {
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000107 if (isInPath(I->first)) {
Sam McCall0ae00562018-09-14 12:47:38 +0000108 CurrentEntry =
109 vfs::directory_entry(I->second.getName(), I->second.getType());
Ben Langmuir740812b2014-06-24 19:37:16 +0000110 break;
111 }
112 }
113 }
114 std::error_code increment() override {
115 ++I;
Jonas Devliegherefc514902018-10-10 13:27:25 +0000116 for (; I != FilesAndDirs.end(); ++I) {
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000117 if (isInPath(I->first)) {
Sam McCall0ae00562018-09-14 12:47:38 +0000118 CurrentEntry =
119 vfs::directory_entry(I->second.getName(), I->second.getType());
Ben Langmuir740812b2014-06-24 19:37:16 +0000120 break;
121 }
122 }
123 if (I == FilesAndDirs.end())
Sam McCall0ae00562018-09-14 12:47:38 +0000124 CurrentEntry = vfs::directory_entry();
Ben Langmuir740812b2014-06-24 19:37:16 +0000125 return std::error_code();
126 }
127 };
128
129 vfs::directory_iterator dir_begin(const Twine &Dir,
130 std::error_code &EC) override {
131 return vfs::directory_iterator(
132 std::make_shared<DirIterImpl>(FilesAndDirs, Dir));
133 }
134
Ben Langmuirc8130a72014-02-20 21:59:23 +0000135 void addEntry(StringRef Path, const vfs::Status &Status) {
136 FilesAndDirs[Path] = Status;
137 }
138
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000139 void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
Pavel Labathac71c8e2016-11-09 10:52:22 +0000140 vfs::Status S(Path, UniqueID(FSID, FileID++),
141 std::chrono::system_clock::now(), 0, 0, 1024,
142 sys::fs::file_type::regular_file, Perms);
Ben Langmuirc8130a72014-02-20 21:59:23 +0000143 addEntry(Path, S);
144 }
145
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000146 void addDirectory(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
Pavel Labathac71c8e2016-11-09 10:52:22 +0000147 vfs::Status S(Path, UniqueID(FSID, FileID++),
148 std::chrono::system_clock::now(), 0, 0, 0,
149 sys::fs::file_type::directory_file, Perms);
Ben Langmuirc8130a72014-02-20 21:59:23 +0000150 addEntry(Path, S);
151 }
152
153 void addSymlink(StringRef Path) {
Pavel Labathac71c8e2016-11-09 10:52:22 +0000154 vfs::Status S(Path, UniqueID(FSID, FileID++),
155 std::chrono::system_clock::now(), 0, 0, 0,
156 sys::fs::file_type::symlink_file, sys::fs::all_all);
Ben Langmuirc8130a72014-02-20 21:59:23 +0000157 addEntry(Path, S);
158 }
159};
Simon Marchiddbabc62018-08-06 21:48:20 +0000160
161/// Replace back-slashes by front-slashes.
162std::string getPosixPath(std::string S) {
163 SmallString<128> Result;
164 llvm::sys::path::native(S, Result, llvm::sys::path::Style::posix);
165 return Result.str();
Craig Topper576ac052018-08-08 22:31:14 +0000166}
Ben Langmuirc8130a72014-02-20 21:59:23 +0000167} // end anonymous namespace
168
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000169TEST(VirtualFileSystemTest, StatusQueries) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000170 IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
Rafael Espindola8e650d72014-06-12 20:37:59 +0000171 ErrorOr<vfs::Status> Status((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000172
173 D->addRegularFile("/foo");
174 Status = D->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000175 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000176 EXPECT_TRUE(Status->isStatusKnown());
177 EXPECT_FALSE(Status->isDirectory());
178 EXPECT_TRUE(Status->isRegularFile());
179 EXPECT_FALSE(Status->isSymlink());
180 EXPECT_FALSE(Status->isOther());
181 EXPECT_TRUE(Status->exists());
182
183 D->addDirectory("/bar");
184 Status = D->status("/bar");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000185 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000186 EXPECT_TRUE(Status->isStatusKnown());
187 EXPECT_TRUE(Status->isDirectory());
188 EXPECT_FALSE(Status->isRegularFile());
189 EXPECT_FALSE(Status->isSymlink());
190 EXPECT_FALSE(Status->isOther());
191 EXPECT_TRUE(Status->exists());
192
193 D->addSymlink("/baz");
194 Status = D->status("/baz");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000195 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000196 EXPECT_TRUE(Status->isStatusKnown());
197 EXPECT_FALSE(Status->isDirectory());
198 EXPECT_FALSE(Status->isRegularFile());
199 EXPECT_TRUE(Status->isSymlink());
200 EXPECT_FALSE(Status->isOther());
201 EXPECT_TRUE(Status->exists());
202
203 EXPECT_TRUE(Status->equivalent(*Status));
204 ErrorOr<vfs::Status> Status2 = D->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000205 ASSERT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000206 EXPECT_FALSE(Status->equivalent(*Status2));
207}
208
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000209TEST(VirtualFileSystemTest, BaseOnlyOverlay) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000210 IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
Rafael Espindola8e650d72014-06-12 20:37:59 +0000211 ErrorOr<vfs::Status> Status((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000212 EXPECT_FALSE(Status = D->status("/foo"));
213
214 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(new vfs::OverlayFileSystem(D));
215 EXPECT_FALSE(Status = O->status("/foo"));
216
217 D->addRegularFile("/foo");
218 Status = D->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000219 EXPECT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000220
Rafael Espindola8e650d72014-06-12 20:37:59 +0000221 ErrorOr<vfs::Status> Status2((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000222 Status2 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000223 EXPECT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000224 EXPECT_TRUE(Status->equivalent(*Status2));
225}
226
Eric Liua840a462018-05-18 13:22:49 +0000227TEST(VirtualFileSystemTest, GetRealPathInOverlay) {
228 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
229 Lower->addRegularFile("/foo");
230 Lower->addSymlink("/lower_link");
231 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
232
233 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
234 new vfs::OverlayFileSystem(Lower));
235 O->pushOverlay(Upper);
236
237 // Regular file.
238 SmallString<16> RealPath;
239 EXPECT_FALSE(O->getRealPath("/foo", RealPath));
240 EXPECT_EQ(RealPath.str(), "/foo");
241
242 // Expect no error getting real path for symlink in lower overlay.
243 EXPECT_FALSE(O->getRealPath("/lower_link", RealPath));
244 EXPECT_EQ(RealPath.str(), "/symlink");
245
246 // Try a non-existing link.
247 EXPECT_EQ(O->getRealPath("/upper_link", RealPath),
248 errc::no_such_file_or_directory);
249
250 // Add a new symlink in upper.
251 Upper->addSymlink("/upper_link");
252 EXPECT_FALSE(O->getRealPath("/upper_link", RealPath));
253 EXPECT_EQ(RealPath.str(), "/symlink");
254}
255
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000256TEST(VirtualFileSystemTest, OverlayFiles) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000257 IntrusiveRefCntPtr<DummyFileSystem> Base(new DummyFileSystem());
258 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
259 IntrusiveRefCntPtr<DummyFileSystem> Top(new DummyFileSystem());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000260 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
261 new vfs::OverlayFileSystem(Base));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000262 O->pushOverlay(Middle);
263 O->pushOverlay(Top);
264
Rafael Espindola8e650d72014-06-12 20:37:59 +0000265 ErrorOr<vfs::Status> Status1((std::error_code())),
266 Status2((std::error_code())), Status3((std::error_code())),
267 StatusB((std::error_code())), StatusM((std::error_code())),
268 StatusT((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000269
270 Base->addRegularFile("/foo");
271 StatusB = Base->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000272 ASSERT_FALSE(StatusB.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000273 Status1 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000274 ASSERT_FALSE(Status1.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000275 Middle->addRegularFile("/foo");
276 StatusM = Middle->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000277 ASSERT_FALSE(StatusM.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000278 Status2 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000279 ASSERT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000280 Top->addRegularFile("/foo");
281 StatusT = Top->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000282 ASSERT_FALSE(StatusT.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000283 Status3 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000284 ASSERT_FALSE(Status3.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000285
286 EXPECT_TRUE(Status1->equivalent(*StatusB));
287 EXPECT_TRUE(Status2->equivalent(*StatusM));
288 EXPECT_TRUE(Status3->equivalent(*StatusT));
289
290 EXPECT_FALSE(Status1->equivalent(*Status2));
291 EXPECT_FALSE(Status2->equivalent(*Status3));
292 EXPECT_FALSE(Status1->equivalent(*Status3));
293}
294
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000295TEST(VirtualFileSystemTest, OverlayDirsNonMerged) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000296 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
297 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000298 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
299 new vfs::OverlayFileSystem(Lower));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000300 O->pushOverlay(Upper);
301
302 Lower->addDirectory("/lower-only");
303 Upper->addDirectory("/upper-only");
304
305 // non-merged paths should be the same
306 ErrorOr<vfs::Status> Status1 = Lower->status("/lower-only");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000307 ASSERT_FALSE(Status1.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000308 ErrorOr<vfs::Status> Status2 = O->status("/lower-only");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000309 ASSERT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000310 EXPECT_TRUE(Status1->equivalent(*Status2));
311
312 Status1 = Upper->status("/upper-only");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000313 ASSERT_FALSE(Status1.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000314 Status2 = O->status("/upper-only");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000315 ASSERT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000316 EXPECT_TRUE(Status1->equivalent(*Status2));
317}
318
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000319TEST(VirtualFileSystemTest, MergedDirPermissions) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000320 // merged directories get the permissions of the upper dir
321 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
322 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000323 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
324 new vfs::OverlayFileSystem(Lower));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000325 O->pushOverlay(Upper);
326
Rafael Espindola8e650d72014-06-12 20:37:59 +0000327 ErrorOr<vfs::Status> Status((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000328 Lower->addDirectory("/both", sys::fs::owner_read);
329 Upper->addDirectory("/both", sys::fs::owner_all | sys::fs::group_read);
330 Status = O->status("/both");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000331 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000332 EXPECT_EQ(0740, Status->getPermissions());
333
334 // permissions (as usual) are not recursively applied
335 Lower->addRegularFile("/both/foo", sys::fs::owner_read);
336 Upper->addRegularFile("/both/bar", sys::fs::owner_write);
337 Status = O->status("/both/foo");
Jonas Devliegherefc514902018-10-10 13:27:25 +0000338 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000339 EXPECT_EQ(0400, Status->getPermissions());
340 Status = O->status("/both/bar");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000341 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000342 EXPECT_EQ(0200, Status->getPermissions());
343}
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000344
Ben Langmuir740812b2014-06-24 19:37:16 +0000345namespace {
346struct ScopedDir {
347 SmallString<128> Path;
Jonas Devliegherefc514902018-10-10 13:27:25 +0000348 ScopedDir(const Twine &Name, bool Unique = false) {
Ben Langmuir740812b2014-06-24 19:37:16 +0000349 std::error_code EC;
350 if (Unique) {
Jonas Devliegherefc514902018-10-10 13:27:25 +0000351 EC = llvm::sys::fs::createUniqueDirectory(Name, Path);
Ben Langmuir740812b2014-06-24 19:37:16 +0000352 } else {
353 Path = Name.str();
354 EC = llvm::sys::fs::create_directory(Twine(Path));
355 }
356 if (EC)
357 Path = "";
358 EXPECT_FALSE(EC);
359 }
360 ~ScopedDir() {
Galina Kistanova45fbb592017-06-15 21:01:24 +0000361 if (Path != "") {
Ben Langmuir740812b2014-06-24 19:37:16 +0000362 EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
Galina Kistanova45fbb592017-06-15 21:01:24 +0000363 }
Ben Langmuir740812b2014-06-24 19:37:16 +0000364 }
365 operator StringRef() { return Path.str(); }
366};
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000367
368struct ScopedLink {
369 SmallString<128> Path;
370 ScopedLink(const Twine &To, const Twine &From) {
371 Path = From.str();
372 std::error_code EC = sys::fs::create_link(To, From);
373 if (EC)
374 Path = "";
375 EXPECT_FALSE(EC);
376 }
377 ~ScopedLink() {
Galina Kistanova45fbb592017-06-15 21:01:24 +0000378 if (Path != "") {
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000379 EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
Galina Kistanova45fbb592017-06-15 21:01:24 +0000380 }
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000381 }
382 operator StringRef() { return Path.str(); }
383};
Hans Wennborgdcfba332015-10-06 23:40:43 +0000384} // end anonymous namespace
Ben Langmuir740812b2014-06-24 19:37:16 +0000385
386TEST(VirtualFileSystemTest, BasicRealFSIteration) {
Jonas Devliegherefc514902018-10-10 13:27:25 +0000387 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
Ben Langmuir740812b2014-06-24 19:37:16 +0000388 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
389
390 std::error_code EC;
391 vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC);
392 ASSERT_FALSE(EC);
393 EXPECT_EQ(vfs::directory_iterator(), I); // empty directory is empty
394
Jonas Devliegherefc514902018-10-10 13:27:25 +0000395 ScopedDir _a(TestDirectory + "/a");
396 ScopedDir _ab(TestDirectory + "/a/b");
397 ScopedDir _c(TestDirectory + "/c");
398 ScopedDir _cd(TestDirectory + "/c/d");
Ben Langmuir740812b2014-06-24 19:37:16 +0000399
400 I = FS->dir_begin(Twine(TestDirectory), EC);
401 ASSERT_FALSE(EC);
402 ASSERT_NE(vfs::directory_iterator(), I);
Ben Langmuirefb8b602014-06-24 21:08:13 +0000403 // Check either a or c, since we can't rely on the iteration order.
Sam McCall0ae00562018-09-14 12:47:38 +0000404 EXPECT_TRUE(I->path().endswith("a") || I->path().endswith("c"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000405 I.increment(EC);
406 ASSERT_FALSE(EC);
407 ASSERT_NE(vfs::directory_iterator(), I);
Sam McCall0ae00562018-09-14 12:47:38 +0000408 EXPECT_TRUE(I->path().endswith("a") || I->path().endswith("c"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000409 I.increment(EC);
410 EXPECT_EQ(vfs::directory_iterator(), I);
411}
412
Sam McCall62ab1a12019-01-14 17:51:10 +0000413#ifdef LLVM_ON_UNIX
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000414TEST(VirtualFileSystemTest, BrokenSymlinkRealFSIteration) {
415 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
416 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
417
418 ScopedLink _a("no_such_file", TestDirectory + "/a");
419 ScopedDir _b(TestDirectory + "/b");
420 ScopedLink _c("no_such_file", TestDirectory + "/c");
421
Sam McCall39223772018-10-01 16:07:03 +0000422 // Should get no iteration error, but a stat error for the broken symlinks.
423 std::map<std::string, std::error_code> StatResults;
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000424 std::error_code EC;
425 for (vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC), E;
426 I != E; I.increment(EC)) {
Sam McCall39223772018-10-01 16:07:03 +0000427 EXPECT_FALSE(EC);
428 StatResults[sys::path::filename(I->path())] =
429 FS->status(I->path()).getError();
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000430 }
Sam McCall39223772018-10-01 16:07:03 +0000431 EXPECT_THAT(
432 StatResults,
433 ElementsAre(
434 Pair("a", std::make_error_code(std::errc::no_such_file_or_directory)),
435 Pair("b", std::error_code()),
436 Pair("c",
437 std::make_error_code(std::errc::no_such_file_or_directory))));
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000438}
439#endif
440
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000441TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
Jonas Devliegherefc514902018-10-10 13:27:25 +0000442 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000443 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
444
445 std::error_code EC;
446 auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
447 ASSERT_FALSE(EC);
448 EXPECT_EQ(vfs::recursive_directory_iterator(), I); // empty directory is empty
449
Jonas Devliegherefc514902018-10-10 13:27:25 +0000450 ScopedDir _a(TestDirectory + "/a");
451 ScopedDir _ab(TestDirectory + "/a/b");
452 ScopedDir _c(TestDirectory + "/c");
453 ScopedDir _cd(TestDirectory + "/c/d");
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000454
455 I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
456 ASSERT_FALSE(EC);
457 ASSERT_NE(vfs::recursive_directory_iterator(), I);
458
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000459 std::vector<std::string> Contents;
460 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
461 I.increment(EC)) {
Sam McCall0ae00562018-09-14 12:47:38 +0000462 Contents.push_back(I->path());
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000463 }
464
465 // Check contents, which may be in any order
466 EXPECT_EQ(4U, Contents.size());
Jonas Devliegherefc514902018-10-10 13:27:25 +0000467 int Counts[4] = {0, 0, 0, 0};
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000468 for (const std::string &Name : Contents) {
469 ASSERT_FALSE(Name.empty());
Jonas Devliegherefc514902018-10-10 13:27:25 +0000470 int Index = Name[Name.size() - 1] - 'a';
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000471 ASSERT_TRUE(Index >= 0 && Index < 4);
472 Counts[Index]++;
473 }
474 EXPECT_EQ(1, Counts[0]); // a
475 EXPECT_EQ(1, Counts[1]); // b
476 EXPECT_EQ(1, Counts[2]); // c
477 EXPECT_EQ(1, Counts[3]); // d
478}
479
Jonas Devlieghere41fb9512018-10-31 23:36:10 +0000480TEST(VirtualFileSystemTest, BasicRealFSRecursiveIterationNoPush) {
481 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
482
483 ScopedDir _a(TestDirectory + "/a");
484 ScopedDir _ab(TestDirectory + "/a/b");
485 ScopedDir _c(TestDirectory + "/c");
486 ScopedDir _cd(TestDirectory + "/c/d");
487 ScopedDir _e(TestDirectory + "/e");
488 ScopedDir _ef(TestDirectory + "/e/f");
489 ScopedDir _g(TestDirectory + "/g");
490
491 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
492
493 // Test that calling no_push on entries without subdirectories has no effect.
494 {
495 std::error_code EC;
496 auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
497 ASSERT_FALSE(EC);
498
499 std::vector<std::string> Contents;
500 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
501 I.increment(EC)) {
502 Contents.push_back(I->path());
503 char last = I->path().back();
504 switch (last) {
505 case 'b':
506 case 'd':
507 case 'f':
508 case 'g':
509 I.no_push();
510 break;
511 default:
512 break;
513 }
514 }
515 EXPECT_EQ(7U, Contents.size());
516 }
517
518 // Test that calling no_push skips subdirectories.
519 {
520 std::error_code EC;
521 auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
522 ASSERT_FALSE(EC);
523
524 std::vector<std::string> Contents;
525 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
526 I.increment(EC)) {
527 Contents.push_back(I->path());
528 char last = I->path().back();
529 switch (last) {
530 case 'a':
531 case 'c':
532 case 'e':
533 I.no_push();
534 break;
535 default:
536 break;
537 }
538 }
539
540 // Check contents, which may be in any order
541 EXPECT_EQ(4U, Contents.size());
542 int Counts[7] = {0, 0, 0, 0, 0, 0, 0};
543 for (const std::string &Name : Contents) {
544 ASSERT_FALSE(Name.empty());
545 int Index = Name[Name.size() - 1] - 'a';
546 ASSERT_TRUE(Index >= 0 && Index < 7);
547 Counts[Index]++;
548 }
549 EXPECT_EQ(1, Counts[0]); // a
550 EXPECT_EQ(0, Counts[1]); // b
551 EXPECT_EQ(1, Counts[2]); // c
552 EXPECT_EQ(0, Counts[3]); // d
553 EXPECT_EQ(1, Counts[4]); // e
554 EXPECT_EQ(0, Counts[5]); // f
555 EXPECT_EQ(1, Counts[6]); // g
556 }
557}
558
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000559#ifdef LLVM_ON_UNIX
560TEST(VirtualFileSystemTest, BrokenSymlinkRealFSRecursiveIteration) {
561 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
562 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
563
564 ScopedLink _a("no_such_file", TestDirectory + "/a");
565 ScopedDir _b(TestDirectory + "/b");
566 ScopedLink _ba("no_such_file", TestDirectory + "/b/a");
567 ScopedDir _bb(TestDirectory + "/b/b");
568 ScopedLink _bc("no_such_file", TestDirectory + "/b/c");
569 ScopedLink _c("no_such_file", TestDirectory + "/c");
570 ScopedDir _d(TestDirectory + "/d");
571 ScopedDir _dd(TestDirectory + "/d/d");
572 ScopedDir _ddd(TestDirectory + "/d/d/d");
573 ScopedLink _e("no_such_file", TestDirectory + "/e");
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000574
Max Moroze0975672018-04-04 19:47:25 +0000575 std::vector<std::string> VisitedBrokenSymlinks;
576 std::vector<std::string> VisitedNonBrokenSymlinks;
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000577 std::error_code EC;
578 for (vfs::recursive_directory_iterator I(*FS, Twine(TestDirectory), EC), E;
579 I != E; I.increment(EC)) {
Sam McCall39223772018-10-01 16:07:03 +0000580 EXPECT_FALSE(EC);
581 (FS->status(I->path()) ? VisitedNonBrokenSymlinks : VisitedBrokenSymlinks)
582 .push_back(I->path());
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000583 }
584
Max Moroze0975672018-04-04 19:47:25 +0000585 // Check visited file names.
Sam McCall39223772018-10-01 16:07:03 +0000586 EXPECT_THAT(VisitedBrokenSymlinks,
587 UnorderedElementsAre(StringRef(_a), StringRef(_ba),
588 StringRef(_bc), StringRef(_c),
589 StringRef(_e)));
590 EXPECT_THAT(VisitedNonBrokenSymlinks,
591 UnorderedElementsAre(StringRef(_b), StringRef(_bb), StringRef(_d),
592 StringRef(_dd), StringRef(_ddd)));
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000593}
594#endif
595
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000596template <typename DirIter>
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000597static void checkContents(DirIter I, ArrayRef<StringRef> ExpectedOut) {
Ben Langmuir740812b2014-06-24 19:37:16 +0000598 std::error_code EC;
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000599 SmallVector<StringRef, 4> Expected(ExpectedOut.begin(), ExpectedOut.end());
600 SmallVector<std::string, 4> InputToCheck;
Ben Langmuir740812b2014-06-24 19:37:16 +0000601
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000602 // Do not rely on iteration order to check for contents, sort both
603 // content vectors before comparison.
604 for (DirIter E; !EC && I != E; I.increment(EC))
Sam McCall0ae00562018-09-14 12:47:38 +0000605 InputToCheck.push_back(I->path());
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000606
Fangrui Song55fab262018-09-26 22:16:28 +0000607 llvm::sort(InputToCheck);
608 llvm::sort(Expected);
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000609 EXPECT_EQ(InputToCheck.size(), Expected.size());
610
611 unsigned LastElt = std::min(InputToCheck.size(), Expected.size());
612 for (unsigned Idx = 0; Idx != LastElt; ++Idx)
Bruno Cardoso Lopes2835c5c2016-05-12 19:13:04 +0000613 EXPECT_EQ(StringRef(InputToCheck[Idx]), Expected[Idx]);
Ben Langmuir740812b2014-06-24 19:37:16 +0000614}
615
616TEST(VirtualFileSystemTest, OverlayIteration) {
617 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
618 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
619 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
620 new vfs::OverlayFileSystem(Lower));
621 O->pushOverlay(Upper);
622
623 std::error_code EC;
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000624 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
Ben Langmuir740812b2014-06-24 19:37:16 +0000625
626 Lower->addRegularFile("/file1");
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000627 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file1"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000628
629 Upper->addRegularFile("/file2");
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000630 checkContents(O->dir_begin("/", EC), {"/file2", "/file1"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000631
632 Lower->addDirectory("/dir1");
633 Lower->addRegularFile("/dir1/foo");
634 Upper->addDirectory("/dir2");
635 Upper->addRegularFile("/dir2/foo");
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000636 checkContents(O->dir_begin("/dir2", EC), ArrayRef<StringRef>("/dir2/foo"));
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000637 checkContents(O->dir_begin("/", EC), {"/dir2", "/file2", "/dir1", "/file1"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000638}
639
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000640TEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
641 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
642 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
643 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
644 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
645 new vfs::OverlayFileSystem(Lower));
646 O->pushOverlay(Middle);
647 O->pushOverlay(Upper);
648
649 std::error_code EC;
650 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
651 ArrayRef<StringRef>());
652
653 Lower->addRegularFile("/file1");
654 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
655 ArrayRef<StringRef>("/file1"));
656
657 Upper->addDirectory("/dir");
658 Upper->addRegularFile("/dir/file2");
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000659 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
660 {"/dir", "/dir/file2", "/file1"});
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000661
662 Lower->addDirectory("/dir1");
663 Lower->addRegularFile("/dir1/foo");
664 Lower->addDirectory("/dir1/a");
665 Lower->addRegularFile("/dir1/a/b");
666 Middle->addDirectory("/a");
667 Middle->addDirectory("/a/b");
668 Middle->addDirectory("/a/b/c");
669 Middle->addRegularFile("/a/b/c/d");
670 Middle->addRegularFile("/hiddenByUp");
671 Upper->addDirectory("/dir2");
672 Upper->addRegularFile("/dir2/foo");
673 Upper->addRegularFile("/hiddenByUp");
674 checkContents(vfs::recursive_directory_iterator(*O, "/dir2", EC),
675 ArrayRef<StringRef>("/dir2/foo"));
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000676 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
677 {"/dir", "/dir/file2", "/dir2", "/dir2/foo", "/hiddenByUp",
678 "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
679 "/dir1/a/b", "/dir1/foo", "/file1"});
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000680}
681
Ben Langmuir740812b2014-06-24 19:37:16 +0000682TEST(VirtualFileSystemTest, ThreeLevelIteration) {
683 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
684 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
685 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
686 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
687 new vfs::OverlayFileSystem(Lower));
688 O->pushOverlay(Middle);
689 O->pushOverlay(Upper);
690
691 std::error_code EC;
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000692 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
Ben Langmuir740812b2014-06-24 19:37:16 +0000693
694 Middle->addRegularFile("/file2");
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000695 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file2"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000696
697 Lower->addRegularFile("/file1");
698 Upper->addRegularFile("/file3");
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000699 checkContents(O->dir_begin("/", EC), {"/file3", "/file2", "/file1"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000700}
701
702TEST(VirtualFileSystemTest, HiddenInIteration) {
703 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
704 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
705 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
706 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
707 new vfs::OverlayFileSystem(Lower));
708 O->pushOverlay(Middle);
709 O->pushOverlay(Upper);
710
711 std::error_code EC;
Sam McCall0ae00562018-09-14 12:47:38 +0000712 Lower->addRegularFile("/onlyInLow");
713 Lower->addDirectory("/hiddenByMid");
714 Lower->addDirectory("/hiddenByUp");
715 Middle->addRegularFile("/onlyInMid");
716 Middle->addRegularFile("/hiddenByMid");
717 Middle->addDirectory("/hiddenByUp");
718 Upper->addRegularFile("/onlyInUp");
719 Upper->addRegularFile("/hiddenByUp");
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000720 checkContents(
721 O->dir_begin("/", EC),
722 {"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000723
724 // Make sure we get the top-most entry
Ben Langmuirefb8b602014-06-24 21:08:13 +0000725 {
726 std::error_code EC;
727 vfs::directory_iterator I = O->dir_begin("/", EC), E;
Jonas Devliegherefc514902018-10-10 13:27:25 +0000728 for (; !EC && I != E; I.increment(EC))
Sam McCall0ae00562018-09-14 12:47:38 +0000729 if (I->path() == "/hiddenByUp")
Ben Langmuirefb8b602014-06-24 21:08:13 +0000730 break;
731 ASSERT_NE(E, I);
Sam McCall0ae00562018-09-14 12:47:38 +0000732 EXPECT_EQ(sys::fs::file_type::regular_file, I->type());
Ben Langmuirefb8b602014-06-24 21:08:13 +0000733 }
734 {
735 std::error_code EC;
736 vfs::directory_iterator I = O->dir_begin("/", EC), E;
Jonas Devliegherefc514902018-10-10 13:27:25 +0000737 for (; !EC && I != E; I.increment(EC))
Sam McCall0ae00562018-09-14 12:47:38 +0000738 if (I->path() == "/hiddenByMid")
Ben Langmuirefb8b602014-06-24 21:08:13 +0000739 break;
740 ASSERT_NE(E, I);
Sam McCall0ae00562018-09-14 12:47:38 +0000741 EXPECT_EQ(sys::fs::file_type::regular_file, I->type());
Ben Langmuirefb8b602014-06-24 21:08:13 +0000742 }
Ben Langmuir740812b2014-06-24 19:37:16 +0000743}
744
Michael J. Spencer937a1042018-12-17 22:30:05 +0000745TEST(ProxyFileSystemTest, Basic) {
746 IntrusiveRefCntPtr<vfs::InMemoryFileSystem> Base(
747 new vfs::InMemoryFileSystem());
748 vfs::ProxyFileSystem PFS(Base);
749
750 Base->addFile("/a", 0, MemoryBuffer::getMemBuffer("test"));
751
752 auto Stat = PFS.status("/a");
753 ASSERT_FALSE(Stat.getError());
754
755 auto File = PFS.openFileForRead("/a");
756 ASSERT_FALSE(File.getError());
757 EXPECT_EQ("test", (*(*File)->getBuffer("ignored"))->getBuffer());
758
759 std::error_code EC;
760 vfs::directory_iterator I = PFS.dir_begin("/", EC);
761 ASSERT_FALSE(EC);
762 ASSERT_EQ("/a", I->path());
763 I.increment(EC);
764 ASSERT_FALSE(EC);
765 ASSERT_EQ(vfs::directory_iterator(), I);
766
767 ASSERT_FALSE(PFS.setCurrentWorkingDirectory("/"));
768
769 auto PWD = PFS.getCurrentWorkingDirectory();
770 ASSERT_FALSE(PWD.getError());
771 ASSERT_EQ("/", *PWD);
772
773 SmallString<16> Path;
774 ASSERT_FALSE(PFS.getRealPath("a", Path));
775 ASSERT_EQ("/a", Path);
776
777 bool Local = true;
778 ASSERT_FALSE(PFS.isLocal("/a", Local));
779 ASSERT_EQ(false, Local);
780}
781
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000782class InMemoryFileSystemTest : public ::testing::Test {
783protected:
Jonas Devliegherefc514902018-10-10 13:27:25 +0000784 llvm::vfs::InMemoryFileSystem FS;
785 llvm::vfs::InMemoryFileSystem NormalizedFS;
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000786
787 InMemoryFileSystemTest()
788 : FS(/*UseNormalizedPaths=*/false),
789 NormalizedFS(/*UseNormalizedPaths=*/true) {}
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000790};
791
Ilya Biryukovd5554c512018-09-04 14:15:53 +0000792MATCHER_P2(IsHardLinkTo, FS, Target, "") {
793 StringRef From = arg;
794 StringRef To = Target;
795 auto OpenedFrom = FS->openFileForRead(From);
796 auto OpenedTo = FS->openFileForRead(To);
797 return !OpenedFrom.getError() && !OpenedTo.getError() &&
798 (*OpenedFrom)->status()->getUniqueID() ==
799 (*OpenedTo)->status()->getUniqueID();
800}
801
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000802TEST_F(InMemoryFileSystemTest, IsEmpty) {
803 auto Stat = FS.status("/a");
Jonas Devliegherefc514902018-10-10 13:27:25 +0000804 ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000805 Stat = FS.status("/");
Rafael Espindolab7ab1872015-10-05 20:20:50 +0000806 ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000807}
808
809TEST_F(InMemoryFileSystemTest, WindowsPath) {
810 FS.addFile("c:/windows/system128/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
811 auto Stat = FS.status("c:");
NAKAMURA Takumi4c33a1a2015-10-06 12:16:27 +0000812#if !defined(_WIN32)
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000813 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
NAKAMURA Takumi4c33a1a2015-10-06 12:16:27 +0000814#endif
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000815 Stat = FS.status("c:/windows/system128/foo.cpp");
816 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
817 FS.addFile("d:/windows/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
818 Stat = FS.status("d:/windows/foo.cpp");
819 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
820}
821
822TEST_F(InMemoryFileSystemTest, OverlayFile) {
823 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000824 NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000825 auto Stat = FS.status("/");
826 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000827 Stat = FS.status("/.");
828 ASSERT_FALSE(Stat);
829 Stat = NormalizedFS.status("/.");
830 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000831 Stat = FS.status("/a");
832 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
833 ASSERT_EQ("/a", Stat->getName());
834}
835
Benjamin Kramer2e2351a2015-10-06 10:04:08 +0000836TEST_F(InMemoryFileSystemTest, OverlayFileNoOwn) {
837 auto Buf = MemoryBuffer::getMemBuffer("a");
838 FS.addFileNoOwn("/a", 0, Buf.get());
839 auto Stat = FS.status("/a");
840 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
841 ASSERT_EQ("/a", Stat->getName());
842}
843
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000844TEST_F(InMemoryFileSystemTest, OpenFileForRead) {
845 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000846 FS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
847 FS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
848 NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
849 NormalizedFS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
850 NormalizedFS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000851 auto File = FS.openFileForRead("/a");
852 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
853 File = FS.openFileForRead("/a"); // Open again.
854 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000855 File = NormalizedFS.openFileForRead("/././a"); // Open again.
856 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000857 File = FS.openFileForRead("/");
Rafael Espindolab7ab1872015-10-05 20:20:50 +0000858 ASSERT_EQ(File.getError(), errc::invalid_argument) << FS.toString();
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000859 File = FS.openFileForRead("/b");
Rafael Espindolab7ab1872015-10-05 20:20:50 +0000860 ASSERT_EQ(File.getError(), errc::no_such_file_or_directory) << FS.toString();
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000861 File = FS.openFileForRead("./c");
862 ASSERT_FALSE(File);
863 File = FS.openFileForRead("e/../d");
864 ASSERT_FALSE(File);
865 File = NormalizedFS.openFileForRead("./c");
Benjamin Kramerd5e0b582015-10-07 08:32:50 +0000866 ASSERT_EQ("c", (*(*File)->getBuffer("ignored"))->getBuffer());
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000867 File = NormalizedFS.openFileForRead("e/../d");
868 ASSERT_EQ("d", (*(*File)->getBuffer("ignored"))->getBuffer());
869}
870
871TEST_F(InMemoryFileSystemTest, DuplicatedFile) {
872 ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
873 ASSERT_FALSE(FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("a")));
874 ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
875 ASSERT_FALSE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("b")));
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000876}
877
878TEST_F(InMemoryFileSystemTest, DirectoryIteration) {
879 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""));
880 FS.addFile("/b/c", 0, MemoryBuffer::getMemBuffer(""));
881
882 std::error_code EC;
883 vfs::directory_iterator I = FS.dir_begin("/", EC);
884 ASSERT_FALSE(EC);
Sam McCall0ae00562018-09-14 12:47:38 +0000885 ASSERT_EQ("/a", I->path());
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000886 I.increment(EC);
887 ASSERT_FALSE(EC);
Sam McCall0ae00562018-09-14 12:47:38 +0000888 ASSERT_EQ("/b", I->path());
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000889 I.increment(EC);
890 ASSERT_FALSE(EC);
891 ASSERT_EQ(vfs::directory_iterator(), I);
892
893 I = FS.dir_begin("/b", EC);
894 ASSERT_FALSE(EC);
Simon Marchiddbabc62018-08-06 21:48:20 +0000895 // When on Windows, we end up with "/b\\c" as the name. Convert to Posix
896 // path for the sake of the comparison.
Sam McCall0ae00562018-09-14 12:47:38 +0000897 ASSERT_EQ("/b/c", getPosixPath(I->path()));
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000898 I.increment(EC);
899 ASSERT_FALSE(EC);
900 ASSERT_EQ(vfs::directory_iterator(), I);
901}
902
Benjamin Kramer1b8dbe32015-10-06 14:45:16 +0000903TEST_F(InMemoryFileSystemTest, WorkingDirectory) {
904 FS.setCurrentWorkingDirectory("/b");
905 FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
906
907 auto Stat = FS.status("/b/c");
908 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
Simon Marchiddbabc62018-08-06 21:48:20 +0000909 ASSERT_EQ("/b/c", Stat->getName());
Benjamin Kramer1b8dbe32015-10-06 14:45:16 +0000910 ASSERT_EQ("/b", *FS.getCurrentWorkingDirectory());
911
912 Stat = FS.status("c");
913 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
Benjamin Kramere9e76072016-01-09 16:33:16 +0000914
915 NormalizedFS.setCurrentWorkingDirectory("/b/c");
916 NormalizedFS.setCurrentWorkingDirectory(".");
Simon Marchiddbabc62018-08-06 21:48:20 +0000917 ASSERT_EQ("/b/c",
918 getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get()));
Benjamin Kramere9e76072016-01-09 16:33:16 +0000919 NormalizedFS.setCurrentWorkingDirectory("..");
Simon Marchiddbabc62018-08-06 21:48:20 +0000920 ASSERT_EQ("/b",
921 getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get()));
Benjamin Kramer1b8dbe32015-10-06 14:45:16 +0000922}
923
Jonas Devliegherecbb5c862018-11-08 00:01:32 +0000924TEST_F(InMemoryFileSystemTest, IsLocal) {
925 FS.setCurrentWorkingDirectory("/b");
926 FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
927
928 std::error_code EC;
929 bool IsLocal = true;
930 EC = FS.isLocal("c", IsLocal);
931 ASSERT_FALSE(EC);
932 ASSERT_FALSE(IsLocal);
933}
934
Eric Liu43cb4512018-05-24 13:52:48 +0000935#if !defined(_WIN32)
Eric Liu33dd6192018-05-24 11:17:00 +0000936TEST_F(InMemoryFileSystemTest, GetRealPath) {
937 SmallString<16> Path;
938 EXPECT_EQ(FS.getRealPath("b", Path), errc::operation_not_permitted);
939
940 auto GetRealPath = [this](StringRef P) {
941 SmallString<16> Output;
942 auto EC = FS.getRealPath(P, Output);
943 EXPECT_FALSE(EC);
944 return Output.str().str();
945 };
946
947 FS.setCurrentWorkingDirectory("a");
948 EXPECT_EQ(GetRealPath("b"), "a/b");
949 EXPECT_EQ(GetRealPath("../b"), "b");
950 EXPECT_EQ(GetRealPath("b/./c"), "a/b/c");
951
952 FS.setCurrentWorkingDirectory("/a");
953 EXPECT_EQ(GetRealPath("b"), "/a/b");
954 EXPECT_EQ(GetRealPath("../b"), "/b");
955 EXPECT_EQ(GetRealPath("b/./c"), "/a/b/c");
956}
Eric Liu43cb4512018-05-24 13:52:48 +0000957#endif // _WIN32
Eric Liu33dd6192018-05-24 11:17:00 +0000958
Ben Hamiltone5af5bd2017-11-09 16:01:16 +0000959TEST_F(InMemoryFileSystemTest, AddFileWithUser) {
960 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), 0xFEEDFACE);
961 auto Stat = FS.status("/a");
962 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
963 ASSERT_TRUE(Stat->isDirectory());
964 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
965 Stat = FS.status("/a/b");
966 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
967 ASSERT_TRUE(Stat->isDirectory());
968 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
969 Stat = FS.status("/a/b/c");
970 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
971 ASSERT_TRUE(Stat->isRegularFile());
972 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
973 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
974}
975
976TEST_F(InMemoryFileSystemTest, AddFileWithGroup) {
977 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, 0xDABBAD00);
978 auto Stat = FS.status("/a");
979 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
980 ASSERT_TRUE(Stat->isDirectory());
981 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
982 Stat = FS.status("/a/b");
983 ASSERT_TRUE(Stat->isDirectory());
984 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
985 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
986 Stat = FS.status("/a/b/c");
987 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
988 ASSERT_TRUE(Stat->isRegularFile());
989 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
990 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
991}
992
993TEST_F(InMemoryFileSystemTest, AddFileWithFileType) {
994 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None,
995 sys::fs::file_type::socket_file);
996 auto Stat = FS.status("/a");
997 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
998 ASSERT_TRUE(Stat->isDirectory());
999 Stat = FS.status("/a/b");
1000 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1001 ASSERT_TRUE(Stat->isDirectory());
1002 Stat = FS.status("/a/b/c");
1003 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1004 ASSERT_EQ(sys::fs::file_type::socket_file, Stat->getType());
1005 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
1006}
1007
1008TEST_F(InMemoryFileSystemTest, AddFileWithPerms) {
Jonas Devliegherefc514902018-10-10 13:27:25 +00001009 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None, None,
1010 sys::fs::perms::owner_read | sys::fs::perms::owner_write);
Ben Hamiltone5af5bd2017-11-09 16:01:16 +00001011 auto Stat = FS.status("/a");
1012 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1013 ASSERT_TRUE(Stat->isDirectory());
1014 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
Jonas Devliegherefc514902018-10-10 13:27:25 +00001015 sys::fs::perms::owner_exe,
1016 Stat->getPermissions());
Ben Hamiltone5af5bd2017-11-09 16:01:16 +00001017 Stat = FS.status("/a/b");
1018 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1019 ASSERT_TRUE(Stat->isDirectory());
1020 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
Jonas Devliegherefc514902018-10-10 13:27:25 +00001021 sys::fs::perms::owner_exe,
1022 Stat->getPermissions());
Ben Hamiltone5af5bd2017-11-09 16:01:16 +00001023 Stat = FS.status("/a/b/c");
1024 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1025 ASSERT_TRUE(Stat->isRegularFile());
1026 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write,
1027 Stat->getPermissions());
1028}
1029
Ben Hamilton78381012017-11-16 19:34:08 +00001030TEST_F(InMemoryFileSystemTest, AddDirectoryThenAddChild) {
1031 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""), /*User=*/None,
1032 /*Group=*/None, sys::fs::file_type::directory_file);
1033 FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("abc"), /*User=*/None,
1034 /*Group=*/None, sys::fs::file_type::regular_file);
1035 auto Stat = FS.status("/a");
1036 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1037 ASSERT_TRUE(Stat->isDirectory());
1038 Stat = FS.status("/a/b");
1039 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1040 ASSERT_TRUE(Stat->isRegularFile());
1041}
1042
Simon Marchiddbabc62018-08-06 21:48:20 +00001043// Test that the name returned by status() is in the same form as the path that
1044// was requested (to match the behavior of RealFileSystem).
1045TEST_F(InMemoryFileSystemTest, StatusName) {
1046 NormalizedFS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"),
1047 /*User=*/None,
1048 /*Group=*/None, sys::fs::file_type::regular_file);
1049 NormalizedFS.setCurrentWorkingDirectory("/a/b");
1050
1051 // Access using InMemoryFileSystem::status.
1052 auto Stat = NormalizedFS.status("../b/c");
1053 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
1054 << NormalizedFS.toString();
1055 ASSERT_TRUE(Stat->isRegularFile());
1056 ASSERT_EQ("../b/c", Stat->getName());
1057
1058 // Access using InMemoryFileAdaptor::status.
1059 auto File = NormalizedFS.openFileForRead("../b/c");
1060 ASSERT_FALSE(File.getError()) << File.getError() << "\n"
1061 << NormalizedFS.toString();
1062 Stat = (*File)->status();
1063 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
1064 << NormalizedFS.toString();
1065 ASSERT_TRUE(Stat->isRegularFile());
1066 ASSERT_EQ("../b/c", Stat->getName());
1067
1068 // Access using a directory iterator.
1069 std::error_code EC;
Jonas Devliegherefc514902018-10-10 13:27:25 +00001070 llvm::vfs::directory_iterator It = NormalizedFS.dir_begin("../b", EC);
Simon Marchiddbabc62018-08-06 21:48:20 +00001071 // When on Windows, we end up with "../b\\c" as the name. Convert to Posix
1072 // path for the sake of the comparison.
Sam McCall0ae00562018-09-14 12:47:38 +00001073 ASSERT_EQ("../b/c", getPosixPath(It->path()));
Simon Marchiddbabc62018-08-06 21:48:20 +00001074}
1075
Ilya Biryukovd5554c512018-09-04 14:15:53 +00001076TEST_F(InMemoryFileSystemTest, AddHardLinkToFile) {
1077 StringRef FromLink = "/path/to/FROM/link";
1078 StringRef Target = "/path/to/TO/file";
1079 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1080 EXPECT_TRUE(FS.addHardLink(FromLink, Target));
1081 EXPECT_THAT(FromLink, IsHardLinkTo(&FS, Target));
1082 EXPECT_TRUE(FS.status(FromLink)->getSize() == FS.status(Target)->getSize());
1083 EXPECT_TRUE(FS.getBufferForFile(FromLink)->get()->getBuffer() ==
1084 FS.getBufferForFile(Target)->get()->getBuffer());
1085}
1086
1087TEST_F(InMemoryFileSystemTest, AddHardLinkInChainPattern) {
1088 StringRef Link0 = "/path/to/0/link";
1089 StringRef Link1 = "/path/to/1/link";
1090 StringRef Link2 = "/path/to/2/link";
1091 StringRef Target = "/path/to/target";
1092 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target file"));
1093 EXPECT_TRUE(FS.addHardLink(Link2, Target));
1094 EXPECT_TRUE(FS.addHardLink(Link1, Link2));
1095 EXPECT_TRUE(FS.addHardLink(Link0, Link1));
1096 EXPECT_THAT(Link0, IsHardLinkTo(&FS, Target));
1097 EXPECT_THAT(Link1, IsHardLinkTo(&FS, Target));
1098 EXPECT_THAT(Link2, IsHardLinkTo(&FS, Target));
1099}
1100
1101TEST_F(InMemoryFileSystemTest, AddHardLinkToAFileThatWasNotAddedBefore) {
1102 EXPECT_FALSE(FS.addHardLink("/path/to/link", "/path/to/target"));
1103}
1104
1105TEST_F(InMemoryFileSystemTest, AddHardLinkFromAFileThatWasAddedBefore) {
1106 StringRef Link = "/path/to/link";
1107 StringRef Target = "/path/to/target";
1108 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1109 FS.addFile(Link, 0, MemoryBuffer::getMemBuffer("content of link"));
1110 EXPECT_FALSE(FS.addHardLink(Link, Target));
1111}
1112
1113TEST_F(InMemoryFileSystemTest, AddSameHardLinkMoreThanOnce) {
1114 StringRef Link = "/path/to/link";
1115 StringRef Target = "/path/to/target";
1116 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1117 EXPECT_TRUE(FS.addHardLink(Link, Target));
1118 EXPECT_FALSE(FS.addHardLink(Link, Target));
1119}
1120
1121TEST_F(InMemoryFileSystemTest, AddFileInPlaceOfAHardLinkWithSameContent) {
1122 StringRef Link = "/path/to/link";
1123 StringRef Target = "/path/to/target";
1124 StringRef Content = "content of target";
1125 EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1126 EXPECT_TRUE(FS.addHardLink(Link, Target));
1127 EXPECT_TRUE(FS.addFile(Link, 0, MemoryBuffer::getMemBuffer(Content)));
1128}
1129
1130TEST_F(InMemoryFileSystemTest, AddFileInPlaceOfAHardLinkWithDifferentContent) {
1131 StringRef Link = "/path/to/link";
1132 StringRef Target = "/path/to/target";
1133 StringRef Content = "content of target";
1134 StringRef LinkContent = "different content of link";
1135 EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1136 EXPECT_TRUE(FS.addHardLink(Link, Target));
1137 EXPECT_FALSE(FS.addFile(Link, 0, MemoryBuffer::getMemBuffer(LinkContent)));
1138}
1139
1140TEST_F(InMemoryFileSystemTest, AddHardLinkToADirectory) {
1141 StringRef Dir = "path/to/dummy/dir";
1142 StringRef Link = "/path/to/link";
1143 StringRef File = "path/to/dummy/dir/target";
1144 StringRef Content = "content of target";
1145 EXPECT_TRUE(FS.addFile(File, 0, MemoryBuffer::getMemBuffer(Content)));
1146 EXPECT_FALSE(FS.addHardLink(Link, Dir));
1147}
1148
1149TEST_F(InMemoryFileSystemTest, AddHardLinkFromADirectory) {
1150 StringRef Dir = "path/to/dummy/dir";
1151 StringRef Target = "path/to/dummy/dir/target";
1152 StringRef Content = "content of target";
1153 EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1154 EXPECT_FALSE(FS.addHardLink(Dir, Target));
1155}
1156
1157TEST_F(InMemoryFileSystemTest, AddHardLinkUnderAFile) {
1158 StringRef CommonContent = "content string";
1159 FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer(CommonContent));
1160 FS.addFile("/c/d", 0, MemoryBuffer::getMemBuffer(CommonContent));
1161 EXPECT_FALSE(FS.addHardLink("/c/d/e", "/a/b"));
1162}
1163
1164TEST_F(InMemoryFileSystemTest, RecursiveIterationWithHardLink) {
1165 std::error_code EC;
1166 FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("content string"));
1167 EXPECT_TRUE(FS.addHardLink("/c/d", "/a/b"));
1168 auto I = vfs::recursive_directory_iterator(FS, "/", EC);
1169 ASSERT_FALSE(EC);
1170 std::vector<std::string> Nodes;
1171 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
1172 I.increment(EC)) {
Sam McCall0ae00562018-09-14 12:47:38 +00001173 Nodes.push_back(getPosixPath(I->path()));
Ilya Biryukovd5554c512018-09-04 14:15:53 +00001174 }
1175 EXPECT_THAT(Nodes, testing::UnorderedElementsAre("/a", "/a/b", "/c", "/c/d"));
1176}
1177
Ben Langmuir93853232014-03-05 21:32:20 +00001178// NOTE: in the tests below, we use '//root/' as our root directory, since it is
1179// a legal *absolute* path on Windows as well as *nix.
Ben Langmuir97882e72014-02-24 20:56:37 +00001180class VFSFromYAMLTest : public ::testing::Test {
1181public:
1182 int NumDiagnostics;
Ben Langmuir93853232014-03-05 21:32:20 +00001183
Alexander Kornienko34eb2072015-04-11 02:00:23 +00001184 void SetUp() override { NumDiagnostics = 0; }
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001185
Ben Langmuir97882e72014-02-24 20:56:37 +00001186 static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
1187 VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
1188 ++Test->NumDiagnostics;
1189 }
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001190
Ben Langmuir97882e72014-02-24 20:56:37 +00001191 IntrusiveRefCntPtr<vfs::FileSystem>
1192 getFromYAMLRawString(StringRef Content,
1193 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
Rafael Espindolad87f8d72014-08-27 20:03:29 +00001194 std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content);
Bruno Cardoso Lopesd878e282016-03-20 02:08:48 +00001195 return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, "", this,
Rafael Espindola91ac8df2014-08-17 23:27:13 +00001196 ExternalFS);
Ben Langmuir97882e72014-02-24 20:56:37 +00001197 }
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001198
Ben Langmuir97882e72014-02-24 20:56:37 +00001199 IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
1200 StringRef Content,
1201 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
1202 std::string VersionPlusContent("{\n 'version':0,\n");
1203 VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
1204 return getFromYAMLRawString(VersionPlusContent, ExternalFS);
1205 }
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +00001206
1207 // This is intended as a "XFAIL" for windows hosts.
1208 bool supportsSameDirMultipleYAMLEntries() {
1209 Triple Host(Triple::normalize(sys::getProcessTriple()));
1210 return !Host.isOSWindows();
1211 }
Ben Langmuir97882e72014-02-24 20:56:37 +00001212};
1213
1214TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001215 IntrusiveRefCntPtr<vfs::FileSystem> FS;
1216 FS = getFromYAMLString("");
Alp Tokerf994cef2014-07-05 03:08:06 +00001217 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001218 FS = getFromYAMLString("[]");
Alp Tokerf994cef2014-07-05 03:08:06 +00001219 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001220 FS = getFromYAMLString("'string'");
Alp Tokerf994cef2014-07-05 03:08:06 +00001221 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001222 EXPECT_EQ(3, NumDiagnostics);
1223}
1224
Ben Langmuir97882e72014-02-24 20:56:37 +00001225TEST_F(VFSFromYAMLTest, MappedFiles) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001226 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001227 Lower->addRegularFile("//root/foo/bar/a");
Jonas Devliegherefc514902018-10-10 13:27:25 +00001228 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1229 "{ 'roots': [\n"
1230 "{\n"
1231 " 'type': 'directory',\n"
1232 " 'name': '//root/',\n"
1233 " 'contents': [ {\n"
1234 " 'type': 'file',\n"
1235 " 'name': 'file1',\n"
1236 " 'external-contents': '//root/foo/bar/a'\n"
1237 " },\n"
1238 " {\n"
1239 " 'type': 'file',\n"
1240 " 'name': 'file2',\n"
1241 " 'external-contents': '//root/foo/b'\n"
1242 " }\n"
1243 " ]\n"
1244 "}\n"
1245 "]\n"
1246 "}",
1247 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001248 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001249
1250 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1251 new vfs::OverlayFileSystem(Lower));
1252 O->pushOverlay(FS);
1253
1254 // file
Ben Langmuir93853232014-03-05 21:32:20 +00001255 ErrorOr<vfs::Status> S = O->status("//root/file1");
Rafael Espindola3ae06202014-05-31 03:20:52 +00001256 ASSERT_FALSE(S.getError());
Ben Langmuir93853232014-03-05 21:32:20 +00001257 EXPECT_EQ("//root/foo/bar/a", S->getName());
Ben Langmuirf13302e2015-12-10 23:41:39 +00001258 EXPECT_TRUE(S->IsVFSMapped);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001259
Ben Langmuir93853232014-03-05 21:32:20 +00001260 ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
1261 EXPECT_EQ("//root/foo/bar/a", SLower->getName());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001262 EXPECT_TRUE(S->equivalent(*SLower));
Ben Langmuirf13302e2015-12-10 23:41:39 +00001263 EXPECT_FALSE(SLower->IsVFSMapped);
1264
1265 // file after opening
1266 auto OpenedF = O->openFileForRead("//root/file1");
1267 ASSERT_FALSE(OpenedF.getError());
1268 auto OpenedS = (*OpenedF)->status();
1269 ASSERT_FALSE(OpenedS.getError());
1270 EXPECT_EQ("//root/foo/bar/a", OpenedS->getName());
1271 EXPECT_TRUE(OpenedS->IsVFSMapped);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001272
1273 // directory
Ben Langmuir93853232014-03-05 21:32:20 +00001274 S = O->status("//root/");
Rafael Espindola3ae06202014-05-31 03:20:52 +00001275 ASSERT_FALSE(S.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001276 EXPECT_TRUE(S->isDirectory());
Ben Langmuir93853232014-03-05 21:32:20 +00001277 EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001278
1279 // broken mapping
Rafael Espindola71de0b62014-06-13 17:20:50 +00001280 EXPECT_EQ(O->status("//root/file2").getError(),
1281 llvm::errc::no_such_file_or_directory);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001282 EXPECT_EQ(0, NumDiagnostics);
1283}
1284
Ben Langmuir97882e72014-02-24 20:56:37 +00001285TEST_F(VFSFromYAMLTest, CaseInsensitive) {
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': 'false',\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> S = O->status("//root/XX");
Rafael Espindola3ae06202014-05-31 03:20:52 +00001309 ASSERT_FALSE(S.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001310
Ben Langmuir93853232014-03-05 21:32:20 +00001311 ErrorOr<vfs::Status> SS = O->status("//root/xx");
Rafael Espindola3ae06202014-05-31 03:20:52 +00001312 ASSERT_FALSE(SS.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001313 EXPECT_TRUE(S->equivalent(*SS));
Ben Langmuir93853232014-03-05 21:32:20 +00001314 SS = O->status("//root/xX");
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001315 EXPECT_TRUE(S->equivalent(*SS));
Ben Langmuir93853232014-03-05 21:32:20 +00001316 SS = O->status("//root/Xx");
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001317 EXPECT_TRUE(S->equivalent(*SS));
1318 EXPECT_EQ(0, NumDiagnostics);
1319}
1320
Ben Langmuir97882e72014-02-24 20:56:37 +00001321TEST_F(VFSFromYAMLTest, CaseSensitive) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001322 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001323 Lower->addRegularFile("//root/foo/bar/a");
Jonas Devliegherefc514902018-10-10 13:27:25 +00001324 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1325 "{ 'case-sensitive': 'true',\n"
1326 " 'roots': [\n"
1327 "{\n"
1328 " 'type': 'directory',\n"
1329 " 'name': '//root/',\n"
1330 " 'contents': [ {\n"
1331 " 'type': 'file',\n"
1332 " 'name': 'XX',\n"
1333 " 'external-contents': '//root/foo/bar/a'\n"
1334 " }\n"
1335 " ]\n"
1336 "}]}",
1337 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001338 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001339
1340 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1341 new vfs::OverlayFileSystem(Lower));
1342 O->pushOverlay(FS);
1343
Ben Langmuir93853232014-03-05 21:32:20 +00001344 ErrorOr<vfs::Status> SS = O->status("//root/xx");
Rafael Espindola71de0b62014-06-13 17:20:50 +00001345 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuir93853232014-03-05 21:32:20 +00001346 SS = O->status("//root/xX");
Rafael Espindola71de0b62014-06-13 17:20:50 +00001347 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuir93853232014-03-05 21:32:20 +00001348 SS = O->status("//root/Xx");
Rafael Espindola71de0b62014-06-13 17:20:50 +00001349 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001350 EXPECT_EQ(0, NumDiagnostics);
1351}
1352
Ben Langmuir97882e72014-02-24 20:56:37 +00001353TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001354 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1355
1356 // invalid YAML at top-level
1357 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001358 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001359 // invalid YAML in roots
1360 FS = getFromYAMLString("{ 'roots':[}", Lower);
1361 // invalid YAML in directory
1362 FS = getFromYAMLString(
1363 "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
1364 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001365 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001366
1367 // invalid configuration
1368 FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001369 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001370 FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001371 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001372
1373 // invalid roots
1374 FS = getFromYAMLString("{ 'roots':'' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001375 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001376 FS = getFromYAMLString("{ 'roots':{} }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001377 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001378
1379 // invalid entries
1380 FS = getFromYAMLString(
1381 "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001382 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001383 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
1384 "'external-contents': 'other' }",
1385 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001386 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001387 FS = getFromYAMLString(
1388 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
1389 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001390 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001391 FS = getFromYAMLString(
1392 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
1393 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001394 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001395 FS = getFromYAMLString(
1396 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
1397 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001398 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001399 FS = getFromYAMLString(
1400 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
1401 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001402 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001403 FS = getFromYAMLString(
1404 "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
1405 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001406 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001407
1408 // missing mandatory fields
1409 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001410 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001411 FS = getFromYAMLString(
1412 "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001413 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001414 FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001415 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001416
1417 // duplicate keys
1418 FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001419 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001420 FS = getFromYAMLString(
1421 "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
1422 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001423 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001424 FS =
1425 getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
1426 "'external-contents':'blah' } ] }",
1427 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001428 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001429
1430 // missing version
1431 FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001432 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001433
1434 // bad version number
1435 FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001436 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001437 FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001438 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001439 FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001440 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001441 EXPECT_EQ(24, NumDiagnostics);
1442}
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001443
Ben Langmuirb59cf672014-02-27 00:25:12 +00001444TEST_F(VFSFromYAMLTest, UseExternalName) {
1445 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001446 Lower->addRegularFile("//root/external/file");
Ben Langmuirb59cf672014-02-27 00:25:12 +00001447
Jonas Devliegherefc514902018-10-10 13:27:25 +00001448 IntrusiveRefCntPtr<vfs::FileSystem> FS =
1449 getFromYAMLString("{ 'roots': [\n"
1450 " { 'type': 'file', 'name': '//root/A',\n"
1451 " 'external-contents': '//root/external/file'\n"
1452 " },\n"
1453 " { 'type': 'file', 'name': '//root/B',\n"
1454 " 'use-external-name': true,\n"
1455 " 'external-contents': '//root/external/file'\n"
1456 " },\n"
1457 " { 'type': 'file', 'name': '//root/C',\n"
1458 " 'use-external-name': false,\n"
1459 " 'external-contents': '//root/external/file'\n"
1460 " }\n"
1461 "] }",
1462 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001463 ASSERT_TRUE(nullptr != FS.get());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001464
1465 // default true
Ben Langmuir93853232014-03-05 21:32:20 +00001466 EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001467 // explicit
Ben Langmuir93853232014-03-05 21:32:20 +00001468 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1469 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001470
1471 // global configuration
Jonas Devliegherefc514902018-10-10 13:27:25 +00001472 FS = getFromYAMLString("{ 'use-external-names': false,\n"
1473 " 'roots': [\n"
1474 " { 'type': 'file', 'name': '//root/A',\n"
1475 " 'external-contents': '//root/external/file'\n"
1476 " },\n"
1477 " { 'type': 'file', 'name': '//root/B',\n"
1478 " 'use-external-name': true,\n"
1479 " 'external-contents': '//root/external/file'\n"
1480 " },\n"
1481 " { 'type': 'file', 'name': '//root/C',\n"
1482 " 'use-external-name': false,\n"
1483 " 'external-contents': '//root/external/file'\n"
1484 " }\n"
1485 "] }",
1486 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001487 ASSERT_TRUE(nullptr != FS.get());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001488
1489 // default
Ben Langmuir93853232014-03-05 21:32:20 +00001490 EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001491 // explicit
Ben Langmuir93853232014-03-05 21:32:20 +00001492 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1493 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001494}
1495
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001496TEST_F(VFSFromYAMLTest, MultiComponentPath) {
1497 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001498 Lower->addRegularFile("//root/other");
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001499
1500 // file in roots
Jonas Devliegherefc514902018-10-10 13:27:25 +00001501 IntrusiveRefCntPtr<vfs::FileSystem> FS =
1502 getFromYAMLString("{ 'roots': [\n"
1503 " { 'type': 'file', 'name': '//root/path/to/file',\n"
1504 " 'external-contents': '//root/other' }]\n"
1505 "}",
1506 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001507 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001508 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1509 EXPECT_FALSE(FS->status("//root/path/to").getError());
1510 EXPECT_FALSE(FS->status("//root/path").getError());
1511 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001512
1513 // at the start
1514 FS = getFromYAMLString(
1515 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001516 " { 'type': 'directory', 'name': '//root/path/to',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001517 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001518 " 'external-contents': '//root/other' }]}]\n"
Jonas Devliegherefc514902018-10-10 13:27:25 +00001519 "}",
1520 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001521 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001522 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1523 EXPECT_FALSE(FS->status("//root/path/to").getError());
1524 EXPECT_FALSE(FS->status("//root/path").getError());
1525 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001526
1527 // at the end
1528 FS = getFromYAMLString(
1529 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001530 " { 'type': 'directory', 'name': '//root/',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001531 " 'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001532 " 'external-contents': '//root/other' }]}]\n"
Jonas Devliegherefc514902018-10-10 13:27:25 +00001533 "}",
1534 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001535 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001536 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1537 EXPECT_FALSE(FS->status("//root/path/to").getError());
1538 EXPECT_FALSE(FS->status("//root/path").getError());
1539 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001540}
1541
1542TEST_F(VFSFromYAMLTest, TrailingSlashes) {
1543 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001544 Lower->addRegularFile("//root/other");
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001545
1546 // file in roots
1547 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1548 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001549 " { 'type': 'directory', 'name': '//root/path/to////',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001550 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001551 " 'external-contents': '//root/other' }]}]\n"
Jonas Devliegherefc514902018-10-10 13:27:25 +00001552 "}",
1553 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001554 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001555 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1556 EXPECT_FALSE(FS->status("//root/path/to").getError());
1557 EXPECT_FALSE(FS->status("//root/path").getError());
1558 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001559}
Ben Langmuir740812b2014-06-24 19:37:16 +00001560
1561TEST_F(VFSFromYAMLTest, DirectoryIteration) {
1562 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1563 Lower->addDirectory("//root/");
1564 Lower->addDirectory("//root/foo");
1565 Lower->addDirectory("//root/foo/bar");
1566 Lower->addRegularFile("//root/foo/bar/a");
1567 Lower->addRegularFile("//root/foo/bar/b");
1568 Lower->addRegularFile("//root/file3");
Jonas Devliegherefc514902018-10-10 13:27:25 +00001569 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1570 "{ 'use-external-names': false,\n"
1571 " 'roots': [\n"
1572 "{\n"
1573 " 'type': 'directory',\n"
1574 " 'name': '//root/',\n"
1575 " 'contents': [ {\n"
1576 " 'type': 'file',\n"
1577 " 'name': 'file1',\n"
1578 " 'external-contents': '//root/foo/bar/a'\n"
1579 " },\n"
1580 " {\n"
1581 " 'type': 'file',\n"
1582 " 'name': 'file2',\n"
1583 " 'external-contents': '//root/foo/bar/b'\n"
1584 " }\n"
1585 " ]\n"
1586 "}\n"
1587 "]\n"
1588 "}",
1589 Lower);
Hans Wennborgdcfba332015-10-06 23:40:43 +00001590 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuir740812b2014-06-24 19:37:16 +00001591
1592 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1593 new vfs::OverlayFileSystem(Lower));
1594 O->pushOverlay(FS);
1595
1596 std::error_code EC;
Benjamin Kramer2a23e552016-01-10 10:45:19 +00001597 checkContents(O->dir_begin("//root/", EC),
Bruno Cardoso Lopes26092b22016-05-12 04:43:27 +00001598 {"//root/file1", "//root/file2", "//root/file3", "//root/foo"});
Ben Langmuir740812b2014-06-24 19:37:16 +00001599
Benjamin Kramer2a23e552016-01-10 10:45:19 +00001600 checkContents(O->dir_begin("//root/foo/bar", EC),
1601 {"//root/foo/bar/a", "//root/foo/bar/b"});
Ben Langmuir740812b2014-06-24 19:37:16 +00001602}
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +00001603
1604TEST_F(VFSFromYAMLTest, DirectoryIterationSameDirMultipleEntries) {
1605 // https://llvm.org/bugs/show_bug.cgi?id=27725
1606 if (!supportsSameDirMultipleYAMLEntries())
1607 return;
1608
1609 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1610 Lower->addDirectory("//root/zab");
1611 Lower->addDirectory("//root/baz");
1612 Lower->addRegularFile("//root/zab/a");
1613 Lower->addRegularFile("//root/zab/b");
1614 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1615 "{ 'use-external-names': false,\n"
1616 " 'roots': [\n"
1617 "{\n"
1618 " 'type': 'directory',\n"
1619 " 'name': '//root/baz/',\n"
1620 " 'contents': [ {\n"
1621 " 'type': 'file',\n"
1622 " 'name': 'x',\n"
1623 " 'external-contents': '//root/zab/a'\n"
1624 " }\n"
1625 " ]\n"
1626 "},\n"
1627 "{\n"
1628 " 'type': 'directory',\n"
1629 " 'name': '//root/baz/',\n"
1630 " 'contents': [ {\n"
1631 " 'type': 'file',\n"
1632 " 'name': 'y',\n"
1633 " 'external-contents': '//root/zab/b'\n"
1634 " }\n"
1635 " ]\n"
1636 "}\n"
1637 "]\n"
1638 "}",
1639 Lower);
1640 ASSERT_TRUE(FS.get() != nullptr);
1641
1642 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1643 new vfs::OverlayFileSystem(Lower));
1644 O->pushOverlay(FS);
1645
1646 std::error_code EC;
1647
1648 checkContents(O->dir_begin("//root/baz/", EC),
1649 {"//root/baz/x", "//root/baz/y"});
1650}
Bruno Cardoso Lopes32b28972016-05-14 00:00:18 +00001651
1652TEST_F(VFSFromYAMLTest, RecursiveDirectoryIterationLevel) {
1653
1654 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1655 Lower->addDirectory("//root/a");
1656 Lower->addDirectory("//root/a/b");
1657 Lower->addDirectory("//root/a/b/c");
1658 Lower->addRegularFile("//root/a/b/c/file");
1659 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1660 "{ 'use-external-names': false,\n"
1661 " 'roots': [\n"
1662 "{\n"
1663 " 'type': 'directory',\n"
1664 " 'name': '//root/a/b/c/',\n"
1665 " 'contents': [ {\n"
1666 " 'type': 'file',\n"
1667 " 'name': 'file',\n"
1668 " 'external-contents': '//root/a/b/c/file'\n"
1669 " }\n"
1670 " ]\n"
1671 "},\n"
1672 "]\n"
1673 "}",
1674 Lower);
1675 ASSERT_TRUE(FS.get() != nullptr);
1676
1677 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1678 new vfs::OverlayFileSystem(Lower));
1679 O->pushOverlay(FS);
1680
1681 std::error_code EC;
1682
1683 // Test recursive_directory_iterator level()
1684 vfs::recursive_directory_iterator I = vfs::recursive_directory_iterator(
Jonas Devliegherefc514902018-10-10 13:27:25 +00001685 *O, "//root", EC),
1686 E;
Bruno Cardoso Lopes32b28972016-05-14 00:00:18 +00001687 ASSERT_FALSE(EC);
1688 for (int l = 0; I != E; I.increment(EC), ++l) {
1689 ASSERT_FALSE(EC);
1690 EXPECT_EQ(I.level(), l);
1691 }
1692 EXPECT_EQ(I, E);
1693}
Volodymyr Sapsai3b2f6a42018-08-07 19:05:41 +00001694
1695TEST_F(VFSFromYAMLTest, RelativePaths) {
1696 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1697 // Filename at root level without a parent directory.
1698 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1699 "{ 'roots': [\n"
1700 " { 'type': 'file', 'name': 'file-not-in-directory.h',\n"
1701 " 'external-contents': '//root/external/file'\n"
1702 " }\n"
Jonas Devliegherefc514902018-10-10 13:27:25 +00001703 "] }",
1704 Lower);
Volodymyr Sapsai3b2f6a42018-08-07 19:05:41 +00001705 EXPECT_EQ(nullptr, FS.get());
1706
1707 // Relative file path.
Jonas Devliegherefc514902018-10-10 13:27:25 +00001708 FS = getFromYAMLString("{ 'roots': [\n"
1709 " { 'type': 'file', 'name': 'relative/file/path.h',\n"
1710 " 'external-contents': '//root/external/file'\n"
1711 " }\n"
1712 "] }",
1713 Lower);
Volodymyr Sapsai3b2f6a42018-08-07 19:05:41 +00001714 EXPECT_EQ(nullptr, FS.get());
1715
1716 // Relative directory path.
1717 FS = getFromYAMLString(
Jonas Devliegherefc514902018-10-10 13:27:25 +00001718 "{ 'roots': [\n"
1719 " { 'type': 'directory', 'name': 'relative/directory/path.h',\n"
1720 " 'contents': []\n"
1721 " }\n"
1722 "] }",
1723 Lower);
Volodymyr Sapsai3b2f6a42018-08-07 19:05:41 +00001724 EXPECT_EQ(nullptr, FS.get());
1725
1726 EXPECT_EQ(3, NumDiagnostics);
1727}
Volodymyr Sapsai91e13162018-10-26 22:14:33 +00001728
1729TEST_F(VFSFromYAMLTest, NonFallthroughDirectoryIteration) {
1730 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1731 Lower->addDirectory("//root/");
1732 Lower->addRegularFile("//root/a");
1733 Lower->addRegularFile("//root/b");
1734 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1735 "{ 'use-external-names': false,\n"
1736 " 'fallthrough': false,\n"
1737 " 'roots': [\n"
1738 "{\n"
1739 " 'type': 'directory',\n"
1740 " 'name': '//root/',\n"
1741 " 'contents': [ {\n"
1742 " 'type': 'file',\n"
1743 " 'name': 'c',\n"
1744 " 'external-contents': '//root/a'\n"
1745 " }\n"
1746 " ]\n"
1747 "}\n"
1748 "]\n"
1749 "}",
1750 Lower);
1751 ASSERT_TRUE(FS.get() != nullptr);
1752
1753 std::error_code EC;
1754 checkContents(FS->dir_begin("//root/", EC),
1755 {"//root/c"});
1756}
1757
1758TEST_F(VFSFromYAMLTest, DirectoryIterationWithDuplicates) {
1759 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1760 Lower->addDirectory("//root/");
1761 Lower->addRegularFile("//root/a");
1762 Lower->addRegularFile("//root/b");
1763 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1764 "{ 'use-external-names': false,\n"
1765 " 'roots': [\n"
1766 "{\n"
1767 " 'type': 'directory',\n"
1768 " 'name': '//root/',\n"
1769 " 'contents': [ {\n"
1770 " 'type': 'file',\n"
1771 " 'name': 'a',\n"
1772 " 'external-contents': '//root/a'\n"
1773 " }\n"
1774 " ]\n"
1775 "}\n"
1776 "]\n"
1777 "}",
1778 Lower);
1779 ASSERT_TRUE(FS.get() != nullptr);
1780
1781 std::error_code EC;
1782 checkContents(FS->dir_begin("//root/", EC),
1783 {"//root/a", "//root/b"});
1784}
1785
1786TEST_F(VFSFromYAMLTest, DirectoryIterationErrorInVFSLayer) {
1787 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1788 Lower->addDirectory("//root/");
1789 Lower->addDirectory("//root/foo");
1790 Lower->addRegularFile("//root/foo/a");
1791 Lower->addRegularFile("//root/foo/b");
1792 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1793 "{ 'use-external-names': false,\n"
1794 " 'roots': [\n"
1795 "{\n"
1796 " 'type': 'directory',\n"
1797 " 'name': '//root/',\n"
1798 " 'contents': [ {\n"
1799 " 'type': 'file',\n"
1800 " 'name': 'bar/a',\n"
1801 " 'external-contents': '//root/foo/a'\n"
1802 " }\n"
1803 " ]\n"
1804 "}\n"
1805 "]\n"
1806 "}",
1807 Lower);
1808 ASSERT_TRUE(FS.get() != nullptr);
1809
1810 std::error_code EC;
1811 checkContents(FS->dir_begin("//root/foo", EC),
1812 {"//root/foo/a", "//root/foo/b"});
1813}
Volodymyr Sapsai76100332018-11-16 01:15:54 +00001814
1815TEST_F(VFSFromYAMLTest, GetRealPath) {
1816 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Volodymyr Sapsaiab734262018-11-16 02:20:33 +00001817 Lower->addDirectory("//dir/");
Volodymyr Sapsai76100332018-11-16 01:15:54 +00001818 Lower->addRegularFile("/foo");
1819 Lower->addSymlink("/link");
1820 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1821 "{ 'use-external-names': false,\n"
1822 " 'roots': [\n"
1823 "{\n"
1824 " 'type': 'directory',\n"
Volodymyr Sapsaiab734262018-11-16 02:20:33 +00001825 " 'name': '//root/',\n"
Volodymyr Sapsai76100332018-11-16 01:15:54 +00001826 " 'contents': [ {\n"
1827 " 'type': 'file',\n"
1828 " 'name': 'bar',\n"
1829 " 'external-contents': '/link'\n"
1830 " }\n"
1831 " ]\n"
1832 "},\n"
1833 "{\n"
1834 " 'type': 'directory',\n"
Volodymyr Sapsaiab734262018-11-16 02:20:33 +00001835 " 'name': '//dir/',\n"
Volodymyr Sapsai76100332018-11-16 01:15:54 +00001836 " 'contents': []\n"
1837 "}\n"
1838 "]\n"
1839 "}",
1840 Lower);
1841 ASSERT_TRUE(FS.get() != nullptr);
1842
1843 // Regular file present in underlying file system.
1844 SmallString<16> RealPath;
1845 EXPECT_FALSE(FS->getRealPath("/foo", RealPath));
1846 EXPECT_EQ(RealPath.str(), "/foo");
1847
1848 // File present in YAML pointing to symlink in underlying file system.
Volodymyr Sapsaiab734262018-11-16 02:20:33 +00001849 EXPECT_FALSE(FS->getRealPath("//root/bar", RealPath));
Volodymyr Sapsai76100332018-11-16 01:15:54 +00001850 EXPECT_EQ(RealPath.str(), "/symlink");
1851
1852 // Directories should fall back to the underlying file system is possible.
Volodymyr Sapsaiab734262018-11-16 02:20:33 +00001853 EXPECT_FALSE(FS->getRealPath("//dir/", RealPath));
1854 EXPECT_EQ(RealPath.str(), "//dir/");
Volodymyr Sapsai76100332018-11-16 01:15:54 +00001855
1856 // Try a non-existing file.
1857 EXPECT_EQ(FS->getRealPath("/non_existing", RealPath),
1858 errc::no_such_file_or_directory);
1859}