blob: d5c01141bba821661ff312c09c6bda297993fcf1 [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
Eric Liu43cb4512018-05-24 13:52:48 +0000888#if !defined(_WIN32)
Eric Liu33dd6192018-05-24 11:17:00 +0000889TEST_F(InMemoryFileSystemTest, GetRealPath) {
890 SmallString<16> Path;
891 EXPECT_EQ(FS.getRealPath("b", Path), errc::operation_not_permitted);
892
893 auto GetRealPath = [this](StringRef P) {
894 SmallString<16> Output;
895 auto EC = FS.getRealPath(P, Output);
896 EXPECT_FALSE(EC);
897 return Output.str().str();
898 };
899
900 FS.setCurrentWorkingDirectory("a");
901 EXPECT_EQ(GetRealPath("b"), "a/b");
902 EXPECT_EQ(GetRealPath("../b"), "b");
903 EXPECT_EQ(GetRealPath("b/./c"), "a/b/c");
904
905 FS.setCurrentWorkingDirectory("/a");
906 EXPECT_EQ(GetRealPath("b"), "/a/b");
907 EXPECT_EQ(GetRealPath("../b"), "/b");
908 EXPECT_EQ(GetRealPath("b/./c"), "/a/b/c");
909}
Eric Liu43cb4512018-05-24 13:52:48 +0000910#endif // _WIN32
Eric Liu33dd6192018-05-24 11:17:00 +0000911
Ben Hamiltone5af5bd2017-11-09 16:01:16 +0000912TEST_F(InMemoryFileSystemTest, AddFileWithUser) {
913 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), 0xFEEDFACE);
914 auto Stat = FS.status("/a");
915 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
916 ASSERT_TRUE(Stat->isDirectory());
917 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
918 Stat = FS.status("/a/b");
919 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
920 ASSERT_TRUE(Stat->isDirectory());
921 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
922 Stat = FS.status("/a/b/c");
923 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
924 ASSERT_TRUE(Stat->isRegularFile());
925 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
926 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
927}
928
929TEST_F(InMemoryFileSystemTest, AddFileWithGroup) {
930 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, 0xDABBAD00);
931 auto Stat = FS.status("/a");
932 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
933 ASSERT_TRUE(Stat->isDirectory());
934 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
935 Stat = FS.status("/a/b");
936 ASSERT_TRUE(Stat->isDirectory());
937 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
938 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
939 Stat = FS.status("/a/b/c");
940 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
941 ASSERT_TRUE(Stat->isRegularFile());
942 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
943 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
944}
945
946TEST_F(InMemoryFileSystemTest, AddFileWithFileType) {
947 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None,
948 sys::fs::file_type::socket_file);
949 auto Stat = FS.status("/a");
950 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
951 ASSERT_TRUE(Stat->isDirectory());
952 Stat = FS.status("/a/b");
953 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
954 ASSERT_TRUE(Stat->isDirectory());
955 Stat = FS.status("/a/b/c");
956 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
957 ASSERT_EQ(sys::fs::file_type::socket_file, Stat->getType());
958 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
959}
960
961TEST_F(InMemoryFileSystemTest, AddFileWithPerms) {
Jonas Devliegherefc514902018-10-10 13:27:25 +0000962 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None, None,
963 sys::fs::perms::owner_read | sys::fs::perms::owner_write);
Ben Hamiltone5af5bd2017-11-09 16:01:16 +0000964 auto Stat = FS.status("/a");
965 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
966 ASSERT_TRUE(Stat->isDirectory());
967 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
Jonas Devliegherefc514902018-10-10 13:27:25 +0000968 sys::fs::perms::owner_exe,
969 Stat->getPermissions());
Ben Hamiltone5af5bd2017-11-09 16:01:16 +0000970 Stat = FS.status("/a/b");
971 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
972 ASSERT_TRUE(Stat->isDirectory());
973 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
Jonas Devliegherefc514902018-10-10 13:27:25 +0000974 sys::fs::perms::owner_exe,
975 Stat->getPermissions());
Ben Hamiltone5af5bd2017-11-09 16:01:16 +0000976 Stat = FS.status("/a/b/c");
977 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
978 ASSERT_TRUE(Stat->isRegularFile());
979 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write,
980 Stat->getPermissions());
981}
982
Ben Hamilton78381012017-11-16 19:34:08 +0000983TEST_F(InMemoryFileSystemTest, AddDirectoryThenAddChild) {
984 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""), /*User=*/None,
985 /*Group=*/None, sys::fs::file_type::directory_file);
986 FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("abc"), /*User=*/None,
987 /*Group=*/None, sys::fs::file_type::regular_file);
988 auto Stat = FS.status("/a");
989 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
990 ASSERT_TRUE(Stat->isDirectory());
991 Stat = FS.status("/a/b");
992 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
993 ASSERT_TRUE(Stat->isRegularFile());
994}
995
Simon Marchiddbabc62018-08-06 21:48:20 +0000996// Test that the name returned by status() is in the same form as the path that
997// was requested (to match the behavior of RealFileSystem).
998TEST_F(InMemoryFileSystemTest, StatusName) {
999 NormalizedFS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"),
1000 /*User=*/None,
1001 /*Group=*/None, sys::fs::file_type::regular_file);
1002 NormalizedFS.setCurrentWorkingDirectory("/a/b");
1003
1004 // Access using InMemoryFileSystem::status.
1005 auto Stat = NormalizedFS.status("../b/c");
1006 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
1007 << NormalizedFS.toString();
1008 ASSERT_TRUE(Stat->isRegularFile());
1009 ASSERT_EQ("../b/c", Stat->getName());
1010
1011 // Access using InMemoryFileAdaptor::status.
1012 auto File = NormalizedFS.openFileForRead("../b/c");
1013 ASSERT_FALSE(File.getError()) << File.getError() << "\n"
1014 << NormalizedFS.toString();
1015 Stat = (*File)->status();
1016 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
1017 << NormalizedFS.toString();
1018 ASSERT_TRUE(Stat->isRegularFile());
1019 ASSERT_EQ("../b/c", Stat->getName());
1020
1021 // Access using a directory iterator.
1022 std::error_code EC;
Jonas Devliegherefc514902018-10-10 13:27:25 +00001023 llvm::vfs::directory_iterator It = NormalizedFS.dir_begin("../b", EC);
Simon Marchiddbabc62018-08-06 21:48:20 +00001024 // When on Windows, we end up with "../b\\c" as the name. Convert to Posix
1025 // path for the sake of the comparison.
Sam McCall0ae00562018-09-14 12:47:38 +00001026 ASSERT_EQ("../b/c", getPosixPath(It->path()));
Simon Marchiddbabc62018-08-06 21:48:20 +00001027}
1028
Ilya Biryukovd5554c512018-09-04 14:15:53 +00001029TEST_F(InMemoryFileSystemTest, AddHardLinkToFile) {
1030 StringRef FromLink = "/path/to/FROM/link";
1031 StringRef Target = "/path/to/TO/file";
1032 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1033 EXPECT_TRUE(FS.addHardLink(FromLink, Target));
1034 EXPECT_THAT(FromLink, IsHardLinkTo(&FS, Target));
1035 EXPECT_TRUE(FS.status(FromLink)->getSize() == FS.status(Target)->getSize());
1036 EXPECT_TRUE(FS.getBufferForFile(FromLink)->get()->getBuffer() ==
1037 FS.getBufferForFile(Target)->get()->getBuffer());
1038}
1039
1040TEST_F(InMemoryFileSystemTest, AddHardLinkInChainPattern) {
1041 StringRef Link0 = "/path/to/0/link";
1042 StringRef Link1 = "/path/to/1/link";
1043 StringRef Link2 = "/path/to/2/link";
1044 StringRef Target = "/path/to/target";
1045 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target file"));
1046 EXPECT_TRUE(FS.addHardLink(Link2, Target));
1047 EXPECT_TRUE(FS.addHardLink(Link1, Link2));
1048 EXPECT_TRUE(FS.addHardLink(Link0, Link1));
1049 EXPECT_THAT(Link0, IsHardLinkTo(&FS, Target));
1050 EXPECT_THAT(Link1, IsHardLinkTo(&FS, Target));
1051 EXPECT_THAT(Link2, IsHardLinkTo(&FS, Target));
1052}
1053
1054TEST_F(InMemoryFileSystemTest, AddHardLinkToAFileThatWasNotAddedBefore) {
1055 EXPECT_FALSE(FS.addHardLink("/path/to/link", "/path/to/target"));
1056}
1057
1058TEST_F(InMemoryFileSystemTest, AddHardLinkFromAFileThatWasAddedBefore) {
1059 StringRef Link = "/path/to/link";
1060 StringRef Target = "/path/to/target";
1061 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1062 FS.addFile(Link, 0, MemoryBuffer::getMemBuffer("content of link"));
1063 EXPECT_FALSE(FS.addHardLink(Link, Target));
1064}
1065
1066TEST_F(InMemoryFileSystemTest, AddSameHardLinkMoreThanOnce) {
1067 StringRef Link = "/path/to/link";
1068 StringRef Target = "/path/to/target";
1069 FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1070 EXPECT_TRUE(FS.addHardLink(Link, Target));
1071 EXPECT_FALSE(FS.addHardLink(Link, Target));
1072}
1073
1074TEST_F(InMemoryFileSystemTest, AddFileInPlaceOfAHardLinkWithSameContent) {
1075 StringRef Link = "/path/to/link";
1076 StringRef Target = "/path/to/target";
1077 StringRef Content = "content of target";
1078 EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1079 EXPECT_TRUE(FS.addHardLink(Link, Target));
1080 EXPECT_TRUE(FS.addFile(Link, 0, MemoryBuffer::getMemBuffer(Content)));
1081}
1082
1083TEST_F(InMemoryFileSystemTest, AddFileInPlaceOfAHardLinkWithDifferentContent) {
1084 StringRef Link = "/path/to/link";
1085 StringRef Target = "/path/to/target";
1086 StringRef Content = "content of target";
1087 StringRef LinkContent = "different content of link";
1088 EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1089 EXPECT_TRUE(FS.addHardLink(Link, Target));
1090 EXPECT_FALSE(FS.addFile(Link, 0, MemoryBuffer::getMemBuffer(LinkContent)));
1091}
1092
1093TEST_F(InMemoryFileSystemTest, AddHardLinkToADirectory) {
1094 StringRef Dir = "path/to/dummy/dir";
1095 StringRef Link = "/path/to/link";
1096 StringRef File = "path/to/dummy/dir/target";
1097 StringRef Content = "content of target";
1098 EXPECT_TRUE(FS.addFile(File, 0, MemoryBuffer::getMemBuffer(Content)));
1099 EXPECT_FALSE(FS.addHardLink(Link, Dir));
1100}
1101
1102TEST_F(InMemoryFileSystemTest, AddHardLinkFromADirectory) {
1103 StringRef Dir = "path/to/dummy/dir";
1104 StringRef Target = "path/to/dummy/dir/target";
1105 StringRef Content = "content of target";
1106 EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1107 EXPECT_FALSE(FS.addHardLink(Dir, Target));
1108}
1109
1110TEST_F(InMemoryFileSystemTest, AddHardLinkUnderAFile) {
1111 StringRef CommonContent = "content string";
1112 FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer(CommonContent));
1113 FS.addFile("/c/d", 0, MemoryBuffer::getMemBuffer(CommonContent));
1114 EXPECT_FALSE(FS.addHardLink("/c/d/e", "/a/b"));
1115}
1116
1117TEST_F(InMemoryFileSystemTest, RecursiveIterationWithHardLink) {
1118 std::error_code EC;
1119 FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("content string"));
1120 EXPECT_TRUE(FS.addHardLink("/c/d", "/a/b"));
1121 auto I = vfs::recursive_directory_iterator(FS, "/", EC);
1122 ASSERT_FALSE(EC);
1123 std::vector<std::string> Nodes;
1124 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
1125 I.increment(EC)) {
Sam McCall0ae00562018-09-14 12:47:38 +00001126 Nodes.push_back(getPosixPath(I->path()));
Ilya Biryukovd5554c512018-09-04 14:15:53 +00001127 }
1128 EXPECT_THAT(Nodes, testing::UnorderedElementsAre("/a", "/a/b", "/c", "/c/d"));
1129}
1130
Ben Langmuir93853232014-03-05 21:32:20 +00001131// NOTE: in the tests below, we use '//root/' as our root directory, since it is
1132// a legal *absolute* path on Windows as well as *nix.
Ben Langmuir97882e72014-02-24 20:56:37 +00001133class VFSFromYAMLTest : public ::testing::Test {
1134public:
1135 int NumDiagnostics;
Ben Langmuir93853232014-03-05 21:32:20 +00001136
Alexander Kornienko34eb2072015-04-11 02:00:23 +00001137 void SetUp() override { NumDiagnostics = 0; }
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001138
Ben Langmuir97882e72014-02-24 20:56:37 +00001139 static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
1140 VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
1141 ++Test->NumDiagnostics;
1142 }
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001143
Ben Langmuir97882e72014-02-24 20:56:37 +00001144 IntrusiveRefCntPtr<vfs::FileSystem>
1145 getFromYAMLRawString(StringRef Content,
1146 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
Rafael Espindolad87f8d72014-08-27 20:03:29 +00001147 std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content);
Bruno Cardoso Lopesd878e282016-03-20 02:08:48 +00001148 return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, "", this,
Rafael Espindola91ac8df2014-08-17 23:27:13 +00001149 ExternalFS);
Ben Langmuir97882e72014-02-24 20:56:37 +00001150 }
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001151
Ben Langmuir97882e72014-02-24 20:56:37 +00001152 IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
1153 StringRef Content,
1154 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
1155 std::string VersionPlusContent("{\n 'version':0,\n");
1156 VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
1157 return getFromYAMLRawString(VersionPlusContent, ExternalFS);
1158 }
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +00001159
1160 // This is intended as a "XFAIL" for windows hosts.
1161 bool supportsSameDirMultipleYAMLEntries() {
1162 Triple Host(Triple::normalize(sys::getProcessTriple()));
1163 return !Host.isOSWindows();
1164 }
Ben Langmuir97882e72014-02-24 20:56:37 +00001165};
1166
1167TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001168 IntrusiveRefCntPtr<vfs::FileSystem> FS;
1169 FS = getFromYAMLString("");
Alp Tokerf994cef2014-07-05 03:08:06 +00001170 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001171 FS = getFromYAMLString("[]");
Alp Tokerf994cef2014-07-05 03:08:06 +00001172 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001173 FS = getFromYAMLString("'string'");
Alp Tokerf994cef2014-07-05 03:08:06 +00001174 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001175 EXPECT_EQ(3, NumDiagnostics);
1176}
1177
Ben Langmuir97882e72014-02-24 20:56:37 +00001178TEST_F(VFSFromYAMLTest, MappedFiles) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001179 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001180 Lower->addRegularFile("//root/foo/bar/a");
Jonas Devliegherefc514902018-10-10 13:27:25 +00001181 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1182 "{ 'roots': [\n"
1183 "{\n"
1184 " 'type': 'directory',\n"
1185 " 'name': '//root/',\n"
1186 " 'contents': [ {\n"
1187 " 'type': 'file',\n"
1188 " 'name': 'file1',\n"
1189 " 'external-contents': '//root/foo/bar/a'\n"
1190 " },\n"
1191 " {\n"
1192 " 'type': 'file',\n"
1193 " 'name': 'file2',\n"
1194 " 'external-contents': '//root/foo/b'\n"
1195 " }\n"
1196 " ]\n"
1197 "}\n"
1198 "]\n"
1199 "}",
1200 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001201 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001202
1203 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1204 new vfs::OverlayFileSystem(Lower));
1205 O->pushOverlay(FS);
1206
1207 // file
Ben Langmuir93853232014-03-05 21:32:20 +00001208 ErrorOr<vfs::Status> S = O->status("//root/file1");
Rafael Espindola3ae06202014-05-31 03:20:52 +00001209 ASSERT_FALSE(S.getError());
Ben Langmuir93853232014-03-05 21:32:20 +00001210 EXPECT_EQ("//root/foo/bar/a", S->getName());
Ben Langmuirf13302e2015-12-10 23:41:39 +00001211 EXPECT_TRUE(S->IsVFSMapped);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001212
Ben Langmuir93853232014-03-05 21:32:20 +00001213 ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
1214 EXPECT_EQ("//root/foo/bar/a", SLower->getName());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001215 EXPECT_TRUE(S->equivalent(*SLower));
Ben Langmuirf13302e2015-12-10 23:41:39 +00001216 EXPECT_FALSE(SLower->IsVFSMapped);
1217
1218 // file after opening
1219 auto OpenedF = O->openFileForRead("//root/file1");
1220 ASSERT_FALSE(OpenedF.getError());
1221 auto OpenedS = (*OpenedF)->status();
1222 ASSERT_FALSE(OpenedS.getError());
1223 EXPECT_EQ("//root/foo/bar/a", OpenedS->getName());
1224 EXPECT_TRUE(OpenedS->IsVFSMapped);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001225
1226 // directory
Ben Langmuir93853232014-03-05 21:32:20 +00001227 S = O->status("//root/");
Rafael Espindola3ae06202014-05-31 03:20:52 +00001228 ASSERT_FALSE(S.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001229 EXPECT_TRUE(S->isDirectory());
Ben Langmuir93853232014-03-05 21:32:20 +00001230 EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001231
1232 // broken mapping
Rafael Espindola71de0b62014-06-13 17:20:50 +00001233 EXPECT_EQ(O->status("//root/file2").getError(),
1234 llvm::errc::no_such_file_or_directory);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001235 EXPECT_EQ(0, NumDiagnostics);
1236}
1237
Ben Langmuir97882e72014-02-24 20:56:37 +00001238TEST_F(VFSFromYAMLTest, CaseInsensitive) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001239 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001240 Lower->addRegularFile("//root/foo/bar/a");
Jonas Devliegherefc514902018-10-10 13:27:25 +00001241 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1242 "{ 'case-sensitive': 'false',\n"
1243 " 'roots': [\n"
1244 "{\n"
1245 " 'type': 'directory',\n"
1246 " 'name': '//root/',\n"
1247 " 'contents': [ {\n"
1248 " 'type': 'file',\n"
1249 " 'name': 'XX',\n"
1250 " 'external-contents': '//root/foo/bar/a'\n"
1251 " }\n"
1252 " ]\n"
1253 "}]}",
1254 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001255 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001256
1257 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1258 new vfs::OverlayFileSystem(Lower));
1259 O->pushOverlay(FS);
1260
Ben Langmuir93853232014-03-05 21:32:20 +00001261 ErrorOr<vfs::Status> S = O->status("//root/XX");
Rafael Espindola3ae06202014-05-31 03:20:52 +00001262 ASSERT_FALSE(S.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001263
Ben Langmuir93853232014-03-05 21:32:20 +00001264 ErrorOr<vfs::Status> SS = O->status("//root/xx");
Rafael Espindola3ae06202014-05-31 03:20:52 +00001265 ASSERT_FALSE(SS.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001266 EXPECT_TRUE(S->equivalent(*SS));
Ben Langmuir93853232014-03-05 21:32:20 +00001267 SS = O->status("//root/xX");
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001268 EXPECT_TRUE(S->equivalent(*SS));
Ben Langmuir93853232014-03-05 21:32:20 +00001269 SS = O->status("//root/Xx");
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001270 EXPECT_TRUE(S->equivalent(*SS));
1271 EXPECT_EQ(0, NumDiagnostics);
1272}
1273
Ben Langmuir97882e72014-02-24 20:56:37 +00001274TEST_F(VFSFromYAMLTest, CaseSensitive) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001275 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001276 Lower->addRegularFile("//root/foo/bar/a");
Jonas Devliegherefc514902018-10-10 13:27:25 +00001277 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1278 "{ 'case-sensitive': 'true',\n"
1279 " 'roots': [\n"
1280 "{\n"
1281 " 'type': 'directory',\n"
1282 " 'name': '//root/',\n"
1283 " 'contents': [ {\n"
1284 " 'type': 'file',\n"
1285 " 'name': 'XX',\n"
1286 " 'external-contents': '//root/foo/bar/a'\n"
1287 " }\n"
1288 " ]\n"
1289 "}]}",
1290 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001291 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001292
1293 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1294 new vfs::OverlayFileSystem(Lower));
1295 O->pushOverlay(FS);
1296
Ben Langmuir93853232014-03-05 21:32:20 +00001297 ErrorOr<vfs::Status> SS = O->status("//root/xx");
Rafael Espindola71de0b62014-06-13 17:20:50 +00001298 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuir93853232014-03-05 21:32:20 +00001299 SS = O->status("//root/xX");
Rafael Espindola71de0b62014-06-13 17:20:50 +00001300 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuir93853232014-03-05 21:32:20 +00001301 SS = O->status("//root/Xx");
Rafael Espindola71de0b62014-06-13 17:20:50 +00001302 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001303 EXPECT_EQ(0, NumDiagnostics);
1304}
1305
Ben Langmuir97882e72014-02-24 20:56:37 +00001306TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001307 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1308
1309 // invalid YAML at top-level
1310 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001311 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001312 // invalid YAML in roots
1313 FS = getFromYAMLString("{ 'roots':[}", Lower);
1314 // invalid YAML in directory
1315 FS = getFromYAMLString(
1316 "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
1317 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001318 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001319
1320 // invalid configuration
1321 FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001322 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001323 FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001324 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001325
1326 // invalid roots
1327 FS = getFromYAMLString("{ 'roots':'' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001328 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001329 FS = getFromYAMLString("{ 'roots':{} }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001330 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001331
1332 // invalid entries
1333 FS = getFromYAMLString(
1334 "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001335 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001336 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
1337 "'external-contents': 'other' }",
1338 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001339 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001340 FS = getFromYAMLString(
1341 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
1342 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001343 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001344 FS = getFromYAMLString(
1345 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
1346 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001347 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001348 FS = getFromYAMLString(
1349 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
1350 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001351 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001352 FS = getFromYAMLString(
1353 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
1354 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001355 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001356 FS = getFromYAMLString(
1357 "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
1358 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001359 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001360
1361 // missing mandatory fields
1362 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001363 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001364 FS = getFromYAMLString(
1365 "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001366 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001367 FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001368 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001369
1370 // duplicate keys
1371 FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001372 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001373 FS = getFromYAMLString(
1374 "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
1375 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001376 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001377 FS =
1378 getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
1379 "'external-contents':'blah' } ] }",
1380 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001381 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001382
1383 // missing version
1384 FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001385 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001386
1387 // bad version number
1388 FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001389 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001390 FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001391 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001392 FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001393 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001394 EXPECT_EQ(24, NumDiagnostics);
1395}
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001396
Ben Langmuirb59cf672014-02-27 00:25:12 +00001397TEST_F(VFSFromYAMLTest, UseExternalName) {
1398 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001399 Lower->addRegularFile("//root/external/file");
Ben Langmuirb59cf672014-02-27 00:25:12 +00001400
Jonas Devliegherefc514902018-10-10 13:27:25 +00001401 IntrusiveRefCntPtr<vfs::FileSystem> FS =
1402 getFromYAMLString("{ 'roots': [\n"
1403 " { 'type': 'file', 'name': '//root/A',\n"
1404 " 'external-contents': '//root/external/file'\n"
1405 " },\n"
1406 " { 'type': 'file', 'name': '//root/B',\n"
1407 " 'use-external-name': true,\n"
1408 " 'external-contents': '//root/external/file'\n"
1409 " },\n"
1410 " { 'type': 'file', 'name': '//root/C',\n"
1411 " 'use-external-name': false,\n"
1412 " 'external-contents': '//root/external/file'\n"
1413 " }\n"
1414 "] }",
1415 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001416 ASSERT_TRUE(nullptr != FS.get());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001417
1418 // default true
Ben Langmuir93853232014-03-05 21:32:20 +00001419 EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001420 // explicit
Ben Langmuir93853232014-03-05 21:32:20 +00001421 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1422 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001423
1424 // global configuration
Jonas Devliegherefc514902018-10-10 13:27:25 +00001425 FS = getFromYAMLString("{ 'use-external-names': false,\n"
1426 " 'roots': [\n"
1427 " { 'type': 'file', 'name': '//root/A',\n"
1428 " 'external-contents': '//root/external/file'\n"
1429 " },\n"
1430 " { 'type': 'file', 'name': '//root/B',\n"
1431 " 'use-external-name': true,\n"
1432 " 'external-contents': '//root/external/file'\n"
1433 " },\n"
1434 " { 'type': 'file', 'name': '//root/C',\n"
1435 " 'use-external-name': false,\n"
1436 " 'external-contents': '//root/external/file'\n"
1437 " }\n"
1438 "] }",
1439 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001440 ASSERT_TRUE(nullptr != FS.get());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001441
1442 // default
Ben Langmuir93853232014-03-05 21:32:20 +00001443 EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001444 // explicit
Ben Langmuir93853232014-03-05 21:32:20 +00001445 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1446 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001447}
1448
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001449TEST_F(VFSFromYAMLTest, MultiComponentPath) {
1450 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001451 Lower->addRegularFile("//root/other");
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001452
1453 // file in roots
Jonas Devliegherefc514902018-10-10 13:27:25 +00001454 IntrusiveRefCntPtr<vfs::FileSystem> FS =
1455 getFromYAMLString("{ 'roots': [\n"
1456 " { 'type': 'file', 'name': '//root/path/to/file',\n"
1457 " 'external-contents': '//root/other' }]\n"
1458 "}",
1459 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001460 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001461 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1462 EXPECT_FALSE(FS->status("//root/path/to").getError());
1463 EXPECT_FALSE(FS->status("//root/path").getError());
1464 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001465
1466 // at the start
1467 FS = getFromYAMLString(
1468 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001469 " { 'type': 'directory', 'name': '//root/path/to',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001470 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001471 " 'external-contents': '//root/other' }]}]\n"
Jonas Devliegherefc514902018-10-10 13:27:25 +00001472 "}",
1473 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001474 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001475 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1476 EXPECT_FALSE(FS->status("//root/path/to").getError());
1477 EXPECT_FALSE(FS->status("//root/path").getError());
1478 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001479
1480 // at the end
1481 FS = getFromYAMLString(
1482 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001483 " { 'type': 'directory', 'name': '//root/',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001484 " 'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001485 " 'external-contents': '//root/other' }]}]\n"
Jonas Devliegherefc514902018-10-10 13:27:25 +00001486 "}",
1487 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001488 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001489 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1490 EXPECT_FALSE(FS->status("//root/path/to").getError());
1491 EXPECT_FALSE(FS->status("//root/path").getError());
1492 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001493}
1494
1495TEST_F(VFSFromYAMLTest, TrailingSlashes) {
1496 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001497 Lower->addRegularFile("//root/other");
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001498
1499 // file in roots
1500 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1501 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001502 " { 'type': 'directory', 'name': '//root/path/to////',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001503 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001504 " 'external-contents': '//root/other' }]}]\n"
Jonas Devliegherefc514902018-10-10 13:27:25 +00001505 "}",
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}
Ben Langmuir740812b2014-06-24 19:37:16 +00001513
1514TEST_F(VFSFromYAMLTest, DirectoryIteration) {
1515 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1516 Lower->addDirectory("//root/");
1517 Lower->addDirectory("//root/foo");
1518 Lower->addDirectory("//root/foo/bar");
1519 Lower->addRegularFile("//root/foo/bar/a");
1520 Lower->addRegularFile("//root/foo/bar/b");
1521 Lower->addRegularFile("//root/file3");
Jonas Devliegherefc514902018-10-10 13:27:25 +00001522 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1523 "{ 'use-external-names': false,\n"
1524 " 'roots': [\n"
1525 "{\n"
1526 " 'type': 'directory',\n"
1527 " 'name': '//root/',\n"
1528 " 'contents': [ {\n"
1529 " 'type': 'file',\n"
1530 " 'name': 'file1',\n"
1531 " 'external-contents': '//root/foo/bar/a'\n"
1532 " },\n"
1533 " {\n"
1534 " 'type': 'file',\n"
1535 " 'name': 'file2',\n"
1536 " 'external-contents': '//root/foo/bar/b'\n"
1537 " }\n"
1538 " ]\n"
1539 "}\n"
1540 "]\n"
1541 "}",
1542 Lower);
Hans Wennborgdcfba332015-10-06 23:40:43 +00001543 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuir740812b2014-06-24 19:37:16 +00001544
1545 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1546 new vfs::OverlayFileSystem(Lower));
1547 O->pushOverlay(FS);
1548
1549 std::error_code EC;
Benjamin Kramer2a23e552016-01-10 10:45:19 +00001550 checkContents(O->dir_begin("//root/", EC),
Bruno Cardoso Lopes26092b22016-05-12 04:43:27 +00001551 {"//root/file1", "//root/file2", "//root/file3", "//root/foo"});
Ben Langmuir740812b2014-06-24 19:37:16 +00001552
Benjamin Kramer2a23e552016-01-10 10:45:19 +00001553 checkContents(O->dir_begin("//root/foo/bar", EC),
1554 {"//root/foo/bar/a", "//root/foo/bar/b"});
Ben Langmuir740812b2014-06-24 19:37:16 +00001555}
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +00001556
1557TEST_F(VFSFromYAMLTest, DirectoryIterationSameDirMultipleEntries) {
1558 // https://llvm.org/bugs/show_bug.cgi?id=27725
1559 if (!supportsSameDirMultipleYAMLEntries())
1560 return;
1561
1562 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1563 Lower->addDirectory("//root/zab");
1564 Lower->addDirectory("//root/baz");
1565 Lower->addRegularFile("//root/zab/a");
1566 Lower->addRegularFile("//root/zab/b");
1567 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1568 "{ 'use-external-names': false,\n"
1569 " 'roots': [\n"
1570 "{\n"
1571 " 'type': 'directory',\n"
1572 " 'name': '//root/baz/',\n"
1573 " 'contents': [ {\n"
1574 " 'type': 'file',\n"
1575 " 'name': 'x',\n"
1576 " 'external-contents': '//root/zab/a'\n"
1577 " }\n"
1578 " ]\n"
1579 "},\n"
1580 "{\n"
1581 " 'type': 'directory',\n"
1582 " 'name': '//root/baz/',\n"
1583 " 'contents': [ {\n"
1584 " 'type': 'file',\n"
1585 " 'name': 'y',\n"
1586 " 'external-contents': '//root/zab/b'\n"
1587 " }\n"
1588 " ]\n"
1589 "}\n"
1590 "]\n"
1591 "}",
1592 Lower);
1593 ASSERT_TRUE(FS.get() != nullptr);
1594
1595 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1596 new vfs::OverlayFileSystem(Lower));
1597 O->pushOverlay(FS);
1598
1599 std::error_code EC;
1600
1601 checkContents(O->dir_begin("//root/baz/", EC),
1602 {"//root/baz/x", "//root/baz/y"});
1603}
Bruno Cardoso Lopes32b28972016-05-14 00:00:18 +00001604
1605TEST_F(VFSFromYAMLTest, RecursiveDirectoryIterationLevel) {
1606
1607 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1608 Lower->addDirectory("//root/a");
1609 Lower->addDirectory("//root/a/b");
1610 Lower->addDirectory("//root/a/b/c");
1611 Lower->addRegularFile("//root/a/b/c/file");
1612 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1613 "{ 'use-external-names': false,\n"
1614 " 'roots': [\n"
1615 "{\n"
1616 " 'type': 'directory',\n"
1617 " 'name': '//root/a/b/c/',\n"
1618 " 'contents': [ {\n"
1619 " 'type': 'file',\n"
1620 " 'name': 'file',\n"
1621 " 'external-contents': '//root/a/b/c/file'\n"
1622 " }\n"
1623 " ]\n"
1624 "},\n"
1625 "]\n"
1626 "}",
1627 Lower);
1628 ASSERT_TRUE(FS.get() != nullptr);
1629
1630 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1631 new vfs::OverlayFileSystem(Lower));
1632 O->pushOverlay(FS);
1633
1634 std::error_code EC;
1635
1636 // Test recursive_directory_iterator level()
1637 vfs::recursive_directory_iterator I = vfs::recursive_directory_iterator(
Jonas Devliegherefc514902018-10-10 13:27:25 +00001638 *O, "//root", EC),
1639 E;
Bruno Cardoso Lopes32b28972016-05-14 00:00:18 +00001640 ASSERT_FALSE(EC);
1641 for (int l = 0; I != E; I.increment(EC), ++l) {
1642 ASSERT_FALSE(EC);
1643 EXPECT_EQ(I.level(), l);
1644 }
1645 EXPECT_EQ(I, E);
1646}
Volodymyr Sapsai3b2f6a42018-08-07 19:05:41 +00001647
1648TEST_F(VFSFromYAMLTest, RelativePaths) {
1649 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1650 // Filename at root level without a parent directory.
1651 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1652 "{ 'roots': [\n"
1653 " { 'type': 'file', 'name': 'file-not-in-directory.h',\n"
1654 " 'external-contents': '//root/external/file'\n"
1655 " }\n"
Jonas Devliegherefc514902018-10-10 13:27:25 +00001656 "] }",
1657 Lower);
Volodymyr Sapsai3b2f6a42018-08-07 19:05:41 +00001658 EXPECT_EQ(nullptr, FS.get());
1659
1660 // Relative file path.
Jonas Devliegherefc514902018-10-10 13:27:25 +00001661 FS = getFromYAMLString("{ 'roots': [\n"
1662 " { 'type': 'file', 'name': 'relative/file/path.h',\n"
1663 " 'external-contents': '//root/external/file'\n"
1664 " }\n"
1665 "] }",
1666 Lower);
Volodymyr Sapsai3b2f6a42018-08-07 19:05:41 +00001667 EXPECT_EQ(nullptr, FS.get());
1668
1669 // Relative directory path.
1670 FS = getFromYAMLString(
Jonas Devliegherefc514902018-10-10 13:27:25 +00001671 "{ 'roots': [\n"
1672 " { 'type': 'directory', 'name': 'relative/directory/path.h',\n"
1673 " 'contents': []\n"
1674 " }\n"
1675 "] }",
1676 Lower);
Volodymyr Sapsai3b2f6a42018-08-07 19:05:41 +00001677 EXPECT_EQ(nullptr, FS.get());
1678
1679 EXPECT_EQ(3, NumDiagnostics);
1680}
Volodymyr Sapsai91e13162018-10-26 22:14:33 +00001681
1682TEST_F(VFSFromYAMLTest, NonFallthroughDirectoryIteration) {
1683 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1684 Lower->addDirectory("//root/");
1685 Lower->addRegularFile("//root/a");
1686 Lower->addRegularFile("//root/b");
1687 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1688 "{ 'use-external-names': false,\n"
1689 " 'fallthrough': false,\n"
1690 " 'roots': [\n"
1691 "{\n"
1692 " 'type': 'directory',\n"
1693 " 'name': '//root/',\n"
1694 " 'contents': [ {\n"
1695 " 'type': 'file',\n"
1696 " 'name': 'c',\n"
1697 " 'external-contents': '//root/a'\n"
1698 " }\n"
1699 " ]\n"
1700 "}\n"
1701 "]\n"
1702 "}",
1703 Lower);
1704 ASSERT_TRUE(FS.get() != nullptr);
1705
1706 std::error_code EC;
1707 checkContents(FS->dir_begin("//root/", EC),
1708 {"//root/c"});
1709}
1710
1711TEST_F(VFSFromYAMLTest, DirectoryIterationWithDuplicates) {
1712 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1713 Lower->addDirectory("//root/");
1714 Lower->addRegularFile("//root/a");
1715 Lower->addRegularFile("//root/b");
1716 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1717 "{ 'use-external-names': false,\n"
1718 " 'roots': [\n"
1719 "{\n"
1720 " 'type': 'directory',\n"
1721 " 'name': '//root/',\n"
1722 " 'contents': [ {\n"
1723 " 'type': 'file',\n"
1724 " 'name': 'a',\n"
1725 " 'external-contents': '//root/a'\n"
1726 " }\n"
1727 " ]\n"
1728 "}\n"
1729 "]\n"
1730 "}",
1731 Lower);
1732 ASSERT_TRUE(FS.get() != nullptr);
1733
1734 std::error_code EC;
1735 checkContents(FS->dir_begin("//root/", EC),
1736 {"//root/a", "//root/b"});
1737}
1738
1739TEST_F(VFSFromYAMLTest, DirectoryIterationErrorInVFSLayer) {
1740 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1741 Lower->addDirectory("//root/");
1742 Lower->addDirectory("//root/foo");
1743 Lower->addRegularFile("//root/foo/a");
1744 Lower->addRegularFile("//root/foo/b");
1745 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1746 "{ 'use-external-names': false,\n"
1747 " 'roots': [\n"
1748 "{\n"
1749 " 'type': 'directory',\n"
1750 " 'name': '//root/',\n"
1751 " 'contents': [ {\n"
1752 " 'type': 'file',\n"
1753 " 'name': 'bar/a',\n"
1754 " 'external-contents': '//root/foo/a'\n"
1755 " }\n"
1756 " ]\n"
1757 "}\n"
1758 "]\n"
1759 "}",
1760 Lower);
1761 ASSERT_TRUE(FS.get() != nullptr);
1762
1763 std::error_code EC;
1764 checkContents(FS->dir_begin("//root/foo", EC),
1765 {"//root/foo/a", "//root/foo/b"});
1766}