blob: a9b39b5b13fdd2373acffb2f6df67ea2124d2a82 [file] [log] [blame]
Ben Langmuirc8130a72014-02-20 21:59:23 +00001//===- unittests/Basic/VirtualFileSystem.cpp ---------------- VFS tests ---===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include "clang/Basic/VirtualFileSystem.h"
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +000011#include "llvm/ADT/Triple.h"
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"
Ben Langmuirc8130a72014-02-20 21:59:23 +000018#include "gtest/gtest.h"
19#include <map>
Hans Wennborgdcfba332015-10-06 23:40:43 +000020
Ben Langmuirc8130a72014-02-20 21:59:23 +000021using namespace clang;
22using namespace llvm;
23using llvm::sys::fs::UniqueID;
24
25namespace {
Ben Langmuirf13302e2015-12-10 23:41:39 +000026struct DummyFile : public vfs::File {
27 vfs::Status S;
28 explicit DummyFile(vfs::Status S) : S(S) {}
29 llvm::ErrorOr<vfs::Status> status() override { return S; }
30 llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
31 getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
32 bool IsVolatile) override {
33 llvm_unreachable("unimplemented");
34 }
Eugene Zelenko1660a5d2016-01-26 19:01:06 +000035 std::error_code close() override { return std::error_code(); }
Ben Langmuirf13302e2015-12-10 23:41:39 +000036};
37
Ben Langmuirc8130a72014-02-20 21:59:23 +000038class DummyFileSystem : public vfs::FileSystem {
39 int FSID; // used to produce UniqueIDs
40 int FileID; // used to produce UniqueIDs
41 std::map<std::string, vfs::Status> FilesAndDirs;
42
43 static int getNextFSID() {
44 static int Count = 0;
45 return Count++;
46 }
47
48public:
49 DummyFileSystem() : FSID(getNextFSID()), FileID(0) {}
50
Fariborz Jahanian5afc8692014-10-01 16:56:40 +000051 ErrorOr<vfs::Status> status(const Twine &Path) override {
Ben Langmuirc8130a72014-02-20 21:59:23 +000052 std::map<std::string, vfs::Status>::iterator I =
Ben Langmuird51ba0b2014-02-21 23:39:37 +000053 FilesAndDirs.find(Path.str());
Ben Langmuirc8130a72014-02-20 21:59:23 +000054 if (I == FilesAndDirs.end())
Rafael Espindola71de0b62014-06-13 17:20:50 +000055 return make_error_code(llvm::errc::no_such_file_or_directory);
Ben Langmuirc8130a72014-02-20 21:59:23 +000056 return I->second;
57 }
Benjamin Kramera8857962014-10-26 22:44:13 +000058 ErrorOr<std::unique_ptr<vfs::File>>
59 openFileForRead(const Twine &Path) override {
Ben Langmuirf13302e2015-12-10 23:41:39 +000060 auto S = status(Path);
61 if (S)
62 return std::unique_ptr<vfs::File>(new DummyFile{*S});
63 return S.getError();
Ben Langmuirc8130a72014-02-20 21:59:23 +000064 }
Benjamin Kramer7708b2a2015-10-05 13:55:20 +000065 llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
66 return std::string();
67 }
68 std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
69 return std::error_code();
70 }
Eric Liua840a462018-05-18 13:22:49 +000071 // Map any symlink to "/symlink".
72 std::error_code getRealPath(const Twine &Path,
73 SmallVectorImpl<char> &Output) const override {
74 auto I = FilesAndDirs.find(Path.str());
75 if (I == FilesAndDirs.end())
76 return make_error_code(llvm::errc::no_such_file_or_directory);
77 if (I->second.isSymlink()) {
78 Output.clear();
79 Twine("/symlink").toVector(Output);
80 return std::error_code();
81 }
82 Output.clear();
83 Path.toVector(Output);
84 return std::error_code();
85 }
Ben Langmuirc8130a72014-02-20 21:59:23 +000086
Ben Langmuir740812b2014-06-24 19:37:16 +000087 struct DirIterImpl : public clang::vfs::detail::DirIterImpl {
88 std::map<std::string, vfs::Status> &FilesAndDirs;
89 std::map<std::string, vfs::Status>::iterator I;
90 std::string Path;
Ben Langmuir7c9f6c82014-06-25 20:25:40 +000091 bool isInPath(StringRef S) {
92 if (Path.size() < S.size() && S.find(Path) == 0) {
93 auto LastSep = S.find_last_of('/');
94 if (LastSep == Path.size() || LastSep == Path.size()-1)
95 return true;
96 }
97 return false;
98 }
Ben Langmuir740812b2014-06-24 19:37:16 +000099 DirIterImpl(std::map<std::string, vfs::Status> &FilesAndDirs,
100 const Twine &_Path)
101 : FilesAndDirs(FilesAndDirs), I(FilesAndDirs.begin()),
102 Path(_Path.str()) {
103 for ( ; I != FilesAndDirs.end(); ++I) {
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000104 if (isInPath(I->first)) {
Ben Langmuir740812b2014-06-24 19:37:16 +0000105 CurrentEntry = I->second;
106 break;
107 }
108 }
109 }
110 std::error_code increment() override {
111 ++I;
112 for ( ; I != FilesAndDirs.end(); ++I) {
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000113 if (isInPath(I->first)) {
Ben Langmuir740812b2014-06-24 19:37:16 +0000114 CurrentEntry = I->second;
115 break;
116 }
117 }
118 if (I == FilesAndDirs.end())
119 CurrentEntry = vfs::Status();
120 return std::error_code();
121 }
122 };
123
124 vfs::directory_iterator dir_begin(const Twine &Dir,
125 std::error_code &EC) override {
126 return vfs::directory_iterator(
127 std::make_shared<DirIterImpl>(FilesAndDirs, Dir));
128 }
129
Ben Langmuirc8130a72014-02-20 21:59:23 +0000130 void addEntry(StringRef Path, const vfs::Status &Status) {
131 FilesAndDirs[Path] = Status;
132 }
133
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000134 void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
Pavel Labathac71c8e2016-11-09 10:52:22 +0000135 vfs::Status S(Path, UniqueID(FSID, FileID++),
136 std::chrono::system_clock::now(), 0, 0, 1024,
137 sys::fs::file_type::regular_file, Perms);
Ben Langmuirc8130a72014-02-20 21:59:23 +0000138 addEntry(Path, S);
139 }
140
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000141 void addDirectory(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
Pavel Labathac71c8e2016-11-09 10:52:22 +0000142 vfs::Status S(Path, UniqueID(FSID, FileID++),
143 std::chrono::system_clock::now(), 0, 0, 0,
144 sys::fs::file_type::directory_file, Perms);
Ben Langmuirc8130a72014-02-20 21:59:23 +0000145 addEntry(Path, S);
146 }
147
148 void addSymlink(StringRef Path) {
Pavel Labathac71c8e2016-11-09 10:52:22 +0000149 vfs::Status S(Path, UniqueID(FSID, FileID++),
150 std::chrono::system_clock::now(), 0, 0, 0,
151 sys::fs::file_type::symlink_file, sys::fs::all_all);
Ben Langmuirc8130a72014-02-20 21:59:23 +0000152 addEntry(Path, S);
153 }
154};
Simon Marchiddbabc62018-08-06 21:48:20 +0000155
156/// Replace back-slashes by front-slashes.
157std::string getPosixPath(std::string S) {
158 SmallString<128> Result;
159 llvm::sys::path::native(S, Result, llvm::sys::path::Style::posix);
160 return Result.str();
161};
Ben Langmuirc8130a72014-02-20 21:59:23 +0000162} // end anonymous namespace
163
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000164TEST(VirtualFileSystemTest, StatusQueries) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000165 IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
Rafael Espindola8e650d72014-06-12 20:37:59 +0000166 ErrorOr<vfs::Status> Status((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000167
168 D->addRegularFile("/foo");
169 Status = D->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000170 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000171 EXPECT_TRUE(Status->isStatusKnown());
172 EXPECT_FALSE(Status->isDirectory());
173 EXPECT_TRUE(Status->isRegularFile());
174 EXPECT_FALSE(Status->isSymlink());
175 EXPECT_FALSE(Status->isOther());
176 EXPECT_TRUE(Status->exists());
177
178 D->addDirectory("/bar");
179 Status = D->status("/bar");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000180 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000181 EXPECT_TRUE(Status->isStatusKnown());
182 EXPECT_TRUE(Status->isDirectory());
183 EXPECT_FALSE(Status->isRegularFile());
184 EXPECT_FALSE(Status->isSymlink());
185 EXPECT_FALSE(Status->isOther());
186 EXPECT_TRUE(Status->exists());
187
188 D->addSymlink("/baz");
189 Status = D->status("/baz");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000190 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000191 EXPECT_TRUE(Status->isStatusKnown());
192 EXPECT_FALSE(Status->isDirectory());
193 EXPECT_FALSE(Status->isRegularFile());
194 EXPECT_TRUE(Status->isSymlink());
195 EXPECT_FALSE(Status->isOther());
196 EXPECT_TRUE(Status->exists());
197
198 EXPECT_TRUE(Status->equivalent(*Status));
199 ErrorOr<vfs::Status> Status2 = D->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000200 ASSERT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000201 EXPECT_FALSE(Status->equivalent(*Status2));
202}
203
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000204TEST(VirtualFileSystemTest, BaseOnlyOverlay) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000205 IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
Rafael Espindola8e650d72014-06-12 20:37:59 +0000206 ErrorOr<vfs::Status> Status((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000207 EXPECT_FALSE(Status = D->status("/foo"));
208
209 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(new vfs::OverlayFileSystem(D));
210 EXPECT_FALSE(Status = O->status("/foo"));
211
212 D->addRegularFile("/foo");
213 Status = D->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000214 EXPECT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000215
Rafael Espindola8e650d72014-06-12 20:37:59 +0000216 ErrorOr<vfs::Status> Status2((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000217 Status2 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000218 EXPECT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000219 EXPECT_TRUE(Status->equivalent(*Status2));
220}
221
Eric Liua840a462018-05-18 13:22:49 +0000222TEST(VirtualFileSystemTest, GetRealPathInOverlay) {
223 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
224 Lower->addRegularFile("/foo");
225 Lower->addSymlink("/lower_link");
226 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
227
228 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
229 new vfs::OverlayFileSystem(Lower));
230 O->pushOverlay(Upper);
231
232 // Regular file.
233 SmallString<16> RealPath;
234 EXPECT_FALSE(O->getRealPath("/foo", RealPath));
235 EXPECT_EQ(RealPath.str(), "/foo");
236
237 // Expect no error getting real path for symlink in lower overlay.
238 EXPECT_FALSE(O->getRealPath("/lower_link", RealPath));
239 EXPECT_EQ(RealPath.str(), "/symlink");
240
241 // Try a non-existing link.
242 EXPECT_EQ(O->getRealPath("/upper_link", RealPath),
243 errc::no_such_file_or_directory);
244
245 // Add a new symlink in upper.
246 Upper->addSymlink("/upper_link");
247 EXPECT_FALSE(O->getRealPath("/upper_link", RealPath));
248 EXPECT_EQ(RealPath.str(), "/symlink");
249}
250
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000251TEST(VirtualFileSystemTest, OverlayFiles) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000252 IntrusiveRefCntPtr<DummyFileSystem> Base(new DummyFileSystem());
253 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
254 IntrusiveRefCntPtr<DummyFileSystem> Top(new DummyFileSystem());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000255 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
256 new vfs::OverlayFileSystem(Base));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000257 O->pushOverlay(Middle);
258 O->pushOverlay(Top);
259
Rafael Espindola8e650d72014-06-12 20:37:59 +0000260 ErrorOr<vfs::Status> Status1((std::error_code())),
261 Status2((std::error_code())), Status3((std::error_code())),
262 StatusB((std::error_code())), StatusM((std::error_code())),
263 StatusT((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000264
265 Base->addRegularFile("/foo");
266 StatusB = Base->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000267 ASSERT_FALSE(StatusB.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000268 Status1 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000269 ASSERT_FALSE(Status1.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000270 Middle->addRegularFile("/foo");
271 StatusM = Middle->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000272 ASSERT_FALSE(StatusM.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000273 Status2 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000274 ASSERT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000275 Top->addRegularFile("/foo");
276 StatusT = Top->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000277 ASSERT_FALSE(StatusT.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000278 Status3 = O->status("/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000279 ASSERT_FALSE(Status3.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000280
281 EXPECT_TRUE(Status1->equivalent(*StatusB));
282 EXPECT_TRUE(Status2->equivalent(*StatusM));
283 EXPECT_TRUE(Status3->equivalent(*StatusT));
284
285 EXPECT_FALSE(Status1->equivalent(*Status2));
286 EXPECT_FALSE(Status2->equivalent(*Status3));
287 EXPECT_FALSE(Status1->equivalent(*Status3));
288}
289
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000290TEST(VirtualFileSystemTest, OverlayDirsNonMerged) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000291 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
292 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000293 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
294 new vfs::OverlayFileSystem(Lower));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000295 O->pushOverlay(Upper);
296
297 Lower->addDirectory("/lower-only");
298 Upper->addDirectory("/upper-only");
299
300 // non-merged paths should be the same
301 ErrorOr<vfs::Status> Status1 = Lower->status("/lower-only");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000302 ASSERT_FALSE(Status1.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000303 ErrorOr<vfs::Status> Status2 = O->status("/lower-only");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000304 ASSERT_FALSE(Status2.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000305 EXPECT_TRUE(Status1->equivalent(*Status2));
306
307 Status1 = Upper->status("/upper-only");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000308 ASSERT_FALSE(Status1.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000309 Status2 = O->status("/upper-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
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000314TEST(VirtualFileSystemTest, MergedDirPermissions) {
Ben Langmuirc8130a72014-02-20 21:59:23 +0000315 // merged directories get the permissions of the upper dir
316 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
317 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000318 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
319 new vfs::OverlayFileSystem(Lower));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000320 O->pushOverlay(Upper);
321
Rafael Espindola8e650d72014-06-12 20:37:59 +0000322 ErrorOr<vfs::Status> Status((std::error_code()));
Ben Langmuirc8130a72014-02-20 21:59:23 +0000323 Lower->addDirectory("/both", sys::fs::owner_read);
324 Upper->addDirectory("/both", sys::fs::owner_all | sys::fs::group_read);
325 Status = O->status("/both");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000326 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000327 EXPECT_EQ(0740, Status->getPermissions());
328
329 // permissions (as usual) are not recursively applied
330 Lower->addRegularFile("/both/foo", sys::fs::owner_read);
331 Upper->addRegularFile("/both/bar", sys::fs::owner_write);
332 Status = O->status("/both/foo");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000333 ASSERT_FALSE( Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000334 EXPECT_EQ(0400, Status->getPermissions());
335 Status = O->status("/both/bar");
Rafael Espindola3ae06202014-05-31 03:20:52 +0000336 ASSERT_FALSE(Status.getError());
Ben Langmuirc8130a72014-02-20 21:59:23 +0000337 EXPECT_EQ(0200, Status->getPermissions());
338}
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000339
Ben Langmuir740812b2014-06-24 19:37:16 +0000340namespace {
341struct ScopedDir {
342 SmallString<128> Path;
343 ScopedDir(const Twine &Name, bool Unique=false) {
344 std::error_code EC;
345 if (Unique) {
346 EC = llvm::sys::fs::createUniqueDirectory(Name, Path);
347 } else {
348 Path = Name.str();
349 EC = llvm::sys::fs::create_directory(Twine(Path));
350 }
351 if (EC)
352 Path = "";
353 EXPECT_FALSE(EC);
354 }
355 ~ScopedDir() {
Galina Kistanova45fbb592017-06-15 21:01:24 +0000356 if (Path != "") {
Ben Langmuir740812b2014-06-24 19:37:16 +0000357 EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
Galina Kistanova45fbb592017-06-15 21:01:24 +0000358 }
Ben Langmuir740812b2014-06-24 19:37:16 +0000359 }
360 operator StringRef() { return Path.str(); }
361};
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000362
363struct ScopedLink {
364 SmallString<128> Path;
365 ScopedLink(const Twine &To, const Twine &From) {
366 Path = From.str();
367 std::error_code EC = sys::fs::create_link(To, From);
368 if (EC)
369 Path = "";
370 EXPECT_FALSE(EC);
371 }
372 ~ScopedLink() {
Galina Kistanova45fbb592017-06-15 21:01:24 +0000373 if (Path != "") {
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000374 EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
Galina Kistanova45fbb592017-06-15 21:01:24 +0000375 }
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000376 }
377 operator StringRef() { return Path.str(); }
378};
Hans Wennborgdcfba332015-10-06 23:40:43 +0000379} // end anonymous namespace
Ben Langmuir740812b2014-06-24 19:37:16 +0000380
381TEST(VirtualFileSystemTest, BasicRealFSIteration) {
382 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
383 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
384
385 std::error_code EC;
386 vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC);
387 ASSERT_FALSE(EC);
388 EXPECT_EQ(vfs::directory_iterator(), I); // empty directory is empty
389
390 ScopedDir _a(TestDirectory+"/a");
391 ScopedDir _ab(TestDirectory+"/a/b");
392 ScopedDir _c(TestDirectory+"/c");
393 ScopedDir _cd(TestDirectory+"/c/d");
394
395 I = FS->dir_begin(Twine(TestDirectory), EC);
396 ASSERT_FALSE(EC);
397 ASSERT_NE(vfs::directory_iterator(), I);
Ben Langmuirefb8b602014-06-24 21:08:13 +0000398 // Check either a or c, since we can't rely on the iteration order.
399 EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000400 I.increment(EC);
401 ASSERT_FALSE(EC);
402 ASSERT_NE(vfs::directory_iterator(), I);
Ben Langmuirefb8b602014-06-24 21:08:13 +0000403 EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000404 I.increment(EC);
405 EXPECT_EQ(vfs::directory_iterator(), I);
406}
407
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000408#ifdef LLVM_ON_UNIX
409TEST(VirtualFileSystemTest, BrokenSymlinkRealFSIteration) {
410 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
411 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
412
413 ScopedLink _a("no_such_file", TestDirectory + "/a");
414 ScopedDir _b(TestDirectory + "/b");
415 ScopedLink _c("no_such_file", TestDirectory + "/c");
416
417 std::error_code EC;
418 for (vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC), E;
419 I != E; I.increment(EC)) {
420 // Skip broken symlinks.
Juergen Ributzka53fda392017-03-14 17:46:26 +0000421 auto EC2 = std::make_error_code(std::errc::no_such_file_or_directory);
422 if (EC == EC2) {
423 EC.clear();
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000424 continue;
425 }
426 // For bot debugging.
427 if (EC) {
Juergen Ributzka53fda392017-03-14 17:46:26 +0000428 outs() << "Error code found:\n"
429 << "EC value: " << EC.value() << "\n"
430 << "EC category: " << EC.category().name()
431 << "EC message: " << EC.message() << "\n";
432
433 outs() << "Error code tested for:\n"
434 << "EC value: " << EC2.value() << "\n"
435 << "EC category: " << EC2.category().name()
436 << "EC message: " << EC2.message() << "\n";
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000437 }
438 ASSERT_FALSE(EC);
439 EXPECT_TRUE(I->getName() == _b);
440 }
441}
442#endif
443
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000444TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
445 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
446 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
447
448 std::error_code EC;
449 auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
450 ASSERT_FALSE(EC);
451 EXPECT_EQ(vfs::recursive_directory_iterator(), I); // empty directory is empty
452
453 ScopedDir _a(TestDirectory+"/a");
454 ScopedDir _ab(TestDirectory+"/a/b");
455 ScopedDir _c(TestDirectory+"/c");
456 ScopedDir _cd(TestDirectory+"/c/d");
457
458 I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
459 ASSERT_FALSE(EC);
460 ASSERT_NE(vfs::recursive_directory_iterator(), I);
461
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000462 std::vector<std::string> Contents;
463 for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
464 I.increment(EC)) {
465 Contents.push_back(I->getName());
466 }
467
468 // Check contents, which may be in any order
469 EXPECT_EQ(4U, Contents.size());
470 int Counts[4] = { 0, 0, 0, 0 };
471 for (const std::string &Name : Contents) {
472 ASSERT_FALSE(Name.empty());
473 int Index = Name[Name.size()-1] - 'a';
474 ASSERT_TRUE(Index >= 0 && Index < 4);
475 Counts[Index]++;
476 }
477 EXPECT_EQ(1, Counts[0]); // a
478 EXPECT_EQ(1, Counts[1]); // b
479 EXPECT_EQ(1, Counts[2]); // c
480 EXPECT_EQ(1, Counts[3]); // d
481}
482
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000483#ifdef LLVM_ON_UNIX
484TEST(VirtualFileSystemTest, BrokenSymlinkRealFSRecursiveIteration) {
485 ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
486 IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
487
488 ScopedLink _a("no_such_file", TestDirectory + "/a");
489 ScopedDir _b(TestDirectory + "/b");
490 ScopedLink _ba("no_such_file", TestDirectory + "/b/a");
491 ScopedDir _bb(TestDirectory + "/b/b");
492 ScopedLink _bc("no_such_file", TestDirectory + "/b/c");
493 ScopedLink _c("no_such_file", TestDirectory + "/c");
494 ScopedDir _d(TestDirectory + "/d");
495 ScopedDir _dd(TestDirectory + "/d/d");
496 ScopedDir _ddd(TestDirectory + "/d/d/d");
497 ScopedLink _e("no_such_file", TestDirectory + "/e");
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000498
Max Moroze0975672018-04-04 19:47:25 +0000499 std::vector<StringRef> ExpectedBrokenSymlinks = {_a, _ba, _bc, _c, _e};
500 std::vector<StringRef> ExpectedNonBrokenSymlinks = {_b, _bb, _d, _dd, _ddd};
501 std::vector<std::string> VisitedBrokenSymlinks;
502 std::vector<std::string> VisitedNonBrokenSymlinks;
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000503 std::error_code EC;
504 for (vfs::recursive_directory_iterator I(*FS, Twine(TestDirectory), EC), E;
505 I != E; I.increment(EC)) {
Juergen Ributzka53fda392017-03-14 17:46:26 +0000506 auto EC2 = std::make_error_code(std::errc::no_such_file_or_directory);
507 if (EC == EC2) {
Max Moroze0975672018-04-04 19:47:25 +0000508 VisitedBrokenSymlinks.push_back(I->getName());
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000509 continue;
510 }
511 // For bot debugging.
512 if (EC) {
Juergen Ributzka53fda392017-03-14 17:46:26 +0000513 outs() << "Error code found:\n"
514 << "EC value: " << EC.value() << "\n"
515 << "EC category: " << EC.category().name()
516 << "EC message: " << EC.message() << "\n";
517
518 outs() << "Error code tested for:\n"
519 << "EC value: " << EC2.value() << "\n"
520 << "EC category: " << EC2.category().name()
521 << "EC message: " << EC2.message() << "\n";
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000522 }
523 ASSERT_FALSE(EC);
Max Moroze0975672018-04-04 19:47:25 +0000524 VisitedNonBrokenSymlinks.push_back(I->getName());
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000525 }
526
Max Moroze0975672018-04-04 19:47:25 +0000527 // Check visited file names.
528 std::sort(VisitedBrokenSymlinks.begin(), VisitedBrokenSymlinks.end());
529 std::sort(VisitedNonBrokenSymlinks.begin(), VisitedNonBrokenSymlinks.end());
530 EXPECT_EQ(ExpectedBrokenSymlinks.size(), VisitedBrokenSymlinks.size());
531 EXPECT_TRUE(std::equal(VisitedBrokenSymlinks.begin(),
532 VisitedBrokenSymlinks.end(),
533 ExpectedBrokenSymlinks.begin()));
534 EXPECT_EQ(ExpectedNonBrokenSymlinks.size(), VisitedNonBrokenSymlinks.size());
535 EXPECT_TRUE(std::equal(VisitedNonBrokenSymlinks.begin(),
536 VisitedNonBrokenSymlinks.end(),
537 ExpectedNonBrokenSymlinks.begin()));
Juergen Ributzkaf9787432017-03-14 00:14:40 +0000538}
539#endif
540
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000541template <typename DirIter>
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000542static void checkContents(DirIter I, ArrayRef<StringRef> ExpectedOut) {
Ben Langmuir740812b2014-06-24 19:37:16 +0000543 std::error_code EC;
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000544 SmallVector<StringRef, 4> Expected(ExpectedOut.begin(), ExpectedOut.end());
545 SmallVector<std::string, 4> InputToCheck;
Ben Langmuir740812b2014-06-24 19:37:16 +0000546
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000547 // Do not rely on iteration order to check for contents, sort both
548 // content vectors before comparison.
549 for (DirIter E; !EC && I != E; I.increment(EC))
550 InputToCheck.push_back(I->getName());
551
Mandeep Singh Grangc205d8c2018-03-27 16:50:00 +0000552 llvm::sort(InputToCheck.begin(), InputToCheck.end());
553 llvm::sort(Expected.begin(), Expected.end());
Bruno Cardoso Lopes29ebd492016-05-11 20:58:47 +0000554 EXPECT_EQ(InputToCheck.size(), Expected.size());
555
556 unsigned LastElt = std::min(InputToCheck.size(), Expected.size());
557 for (unsigned Idx = 0; Idx != LastElt; ++Idx)
Bruno Cardoso Lopes2835c5c2016-05-12 19:13:04 +0000558 EXPECT_EQ(StringRef(InputToCheck[Idx]), Expected[Idx]);
Ben Langmuir740812b2014-06-24 19:37:16 +0000559}
560
561TEST(VirtualFileSystemTest, OverlayIteration) {
562 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
563 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
564 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
565 new vfs::OverlayFileSystem(Lower));
566 O->pushOverlay(Upper);
567
568 std::error_code EC;
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000569 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
Ben Langmuir740812b2014-06-24 19:37:16 +0000570
571 Lower->addRegularFile("/file1");
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000572 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file1"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000573
574 Upper->addRegularFile("/file2");
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000575 checkContents(O->dir_begin("/", EC), {"/file2", "/file1"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000576
577 Lower->addDirectory("/dir1");
578 Lower->addRegularFile("/dir1/foo");
579 Upper->addDirectory("/dir2");
580 Upper->addRegularFile("/dir2/foo");
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000581 checkContents(O->dir_begin("/dir2", EC), ArrayRef<StringRef>("/dir2/foo"));
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000582 checkContents(O->dir_begin("/", EC), {"/dir2", "/file2", "/dir1", "/file1"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000583}
584
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000585TEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
586 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
587 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
588 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
589 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
590 new vfs::OverlayFileSystem(Lower));
591 O->pushOverlay(Middle);
592 O->pushOverlay(Upper);
593
594 std::error_code EC;
595 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
596 ArrayRef<StringRef>());
597
598 Lower->addRegularFile("/file1");
599 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
600 ArrayRef<StringRef>("/file1"));
601
602 Upper->addDirectory("/dir");
603 Upper->addRegularFile("/dir/file2");
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000604 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
605 {"/dir", "/dir/file2", "/file1"});
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000606
607 Lower->addDirectory("/dir1");
608 Lower->addRegularFile("/dir1/foo");
609 Lower->addDirectory("/dir1/a");
610 Lower->addRegularFile("/dir1/a/b");
611 Middle->addDirectory("/a");
612 Middle->addDirectory("/a/b");
613 Middle->addDirectory("/a/b/c");
614 Middle->addRegularFile("/a/b/c/d");
615 Middle->addRegularFile("/hiddenByUp");
616 Upper->addDirectory("/dir2");
617 Upper->addRegularFile("/dir2/foo");
618 Upper->addRegularFile("/hiddenByUp");
619 checkContents(vfs::recursive_directory_iterator(*O, "/dir2", EC),
620 ArrayRef<StringRef>("/dir2/foo"));
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000621 checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
622 {"/dir", "/dir/file2", "/dir2", "/dir2/foo", "/hiddenByUp",
623 "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
624 "/dir1/a/b", "/dir1/foo", "/file1"});
Ben Langmuir7c9f6c82014-06-25 20:25:40 +0000625}
626
Ben Langmuir740812b2014-06-24 19:37:16 +0000627TEST(VirtualFileSystemTest, ThreeLevelIteration) {
628 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
629 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
630 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
631 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
632 new vfs::OverlayFileSystem(Lower));
633 O->pushOverlay(Middle);
634 O->pushOverlay(Upper);
635
636 std::error_code EC;
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000637 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
Ben Langmuir740812b2014-06-24 19:37:16 +0000638
639 Middle->addRegularFile("/file2");
NAKAMURA Takumi4669bd42014-06-25 04:34:10 +0000640 checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file2"));
Ben Langmuir740812b2014-06-24 19:37:16 +0000641
642 Lower->addRegularFile("/file1");
643 Upper->addRegularFile("/file3");
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000644 checkContents(O->dir_begin("/", EC), {"/file3", "/file2", "/file1"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000645}
646
647TEST(VirtualFileSystemTest, HiddenInIteration) {
648 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
649 IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
650 IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
651 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
652 new vfs::OverlayFileSystem(Lower));
653 O->pushOverlay(Middle);
654 O->pushOverlay(Upper);
655
656 std::error_code EC;
657 Lower->addRegularFile("/onlyInLow", sys::fs::owner_read);
658 Lower->addRegularFile("/hiddenByMid", sys::fs::owner_read);
659 Lower->addRegularFile("/hiddenByUp", sys::fs::owner_read);
660 Middle->addRegularFile("/onlyInMid", sys::fs::owner_write);
661 Middle->addRegularFile("/hiddenByMid", sys::fs::owner_write);
662 Middle->addRegularFile("/hiddenByUp", sys::fs::owner_write);
663 Upper->addRegularFile("/onlyInUp", sys::fs::owner_all);
664 Upper->addRegularFile("/hiddenByUp", sys::fs::owner_all);
Benjamin Kramer2a23e552016-01-10 10:45:19 +0000665 checkContents(
666 O->dir_begin("/", EC),
667 {"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"});
Ben Langmuir740812b2014-06-24 19:37:16 +0000668
669 // Make sure we get the top-most entry
Ben Langmuirefb8b602014-06-24 21:08:13 +0000670 {
671 std::error_code EC;
672 vfs::directory_iterator I = O->dir_begin("/", EC), E;
673 for ( ; !EC && I != E; I.increment(EC))
674 if (I->getName() == "/hiddenByUp")
675 break;
676 ASSERT_NE(E, I);
677 EXPECT_EQ(sys::fs::owner_all, I->getPermissions());
678 }
679 {
680 std::error_code EC;
681 vfs::directory_iterator I = O->dir_begin("/", EC), E;
682 for ( ; !EC && I != E; I.increment(EC))
683 if (I->getName() == "/hiddenByMid")
684 break;
685 ASSERT_NE(E, I);
686 EXPECT_EQ(sys::fs::owner_write, I->getPermissions());
687 }
Ben Langmuir740812b2014-06-24 19:37:16 +0000688}
689
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000690class InMemoryFileSystemTest : public ::testing::Test {
691protected:
692 clang::vfs::InMemoryFileSystem FS;
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000693 clang::vfs::InMemoryFileSystem NormalizedFS;
694
695 InMemoryFileSystemTest()
696 : FS(/*UseNormalizedPaths=*/false),
697 NormalizedFS(/*UseNormalizedPaths=*/true) {}
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000698};
699
700TEST_F(InMemoryFileSystemTest, IsEmpty) {
701 auto Stat = FS.status("/a");
Rafael Espindolab7ab1872015-10-05 20:20:50 +0000702 ASSERT_EQ(Stat.getError(),errc::no_such_file_or_directory) << FS.toString();
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000703 Stat = FS.status("/");
Rafael Espindolab7ab1872015-10-05 20:20:50 +0000704 ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000705}
706
707TEST_F(InMemoryFileSystemTest, WindowsPath) {
708 FS.addFile("c:/windows/system128/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
709 auto Stat = FS.status("c:");
NAKAMURA Takumi4c33a1a2015-10-06 12:16:27 +0000710#if !defined(_WIN32)
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000711 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
NAKAMURA Takumi4c33a1a2015-10-06 12:16:27 +0000712#endif
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000713 Stat = FS.status("c:/windows/system128/foo.cpp");
714 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
715 FS.addFile("d:/windows/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
716 Stat = FS.status("d:/windows/foo.cpp");
717 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
718}
719
720TEST_F(InMemoryFileSystemTest, OverlayFile) {
721 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000722 NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000723 auto Stat = FS.status("/");
724 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000725 Stat = FS.status("/.");
726 ASSERT_FALSE(Stat);
727 Stat = NormalizedFS.status("/.");
728 ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000729 Stat = FS.status("/a");
730 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
731 ASSERT_EQ("/a", Stat->getName());
732}
733
Benjamin Kramer2e2351a2015-10-06 10:04:08 +0000734TEST_F(InMemoryFileSystemTest, OverlayFileNoOwn) {
735 auto Buf = MemoryBuffer::getMemBuffer("a");
736 FS.addFileNoOwn("/a", 0, Buf.get());
737 auto Stat = FS.status("/a");
738 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
739 ASSERT_EQ("/a", Stat->getName());
740}
741
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000742TEST_F(InMemoryFileSystemTest, OpenFileForRead) {
743 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000744 FS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
745 FS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
746 NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
747 NormalizedFS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
748 NormalizedFS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000749 auto File = FS.openFileForRead("/a");
750 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
751 File = FS.openFileForRead("/a"); // Open again.
752 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000753 File = NormalizedFS.openFileForRead("/././a"); // Open again.
754 ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000755 File = FS.openFileForRead("/");
Rafael Espindolab7ab1872015-10-05 20:20:50 +0000756 ASSERT_EQ(File.getError(), errc::invalid_argument) << FS.toString();
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000757 File = FS.openFileForRead("/b");
Rafael Espindolab7ab1872015-10-05 20:20:50 +0000758 ASSERT_EQ(File.getError(), errc::no_such_file_or_directory) << FS.toString();
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000759 File = FS.openFileForRead("./c");
760 ASSERT_FALSE(File);
761 File = FS.openFileForRead("e/../d");
762 ASSERT_FALSE(File);
763 File = NormalizedFS.openFileForRead("./c");
Benjamin Kramerd5e0b582015-10-07 08:32:50 +0000764 ASSERT_EQ("c", (*(*File)->getBuffer("ignored"))->getBuffer());
Benjamin Kramer71ce3762015-10-12 16:16:39 +0000765 File = NormalizedFS.openFileForRead("e/../d");
766 ASSERT_EQ("d", (*(*File)->getBuffer("ignored"))->getBuffer());
767}
768
769TEST_F(InMemoryFileSystemTest, DuplicatedFile) {
770 ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
771 ASSERT_FALSE(FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("a")));
772 ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
773 ASSERT_FALSE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("b")));
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000774}
775
776TEST_F(InMemoryFileSystemTest, DirectoryIteration) {
777 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""));
778 FS.addFile("/b/c", 0, MemoryBuffer::getMemBuffer(""));
779
780 std::error_code EC;
781 vfs::directory_iterator I = FS.dir_begin("/", EC);
782 ASSERT_FALSE(EC);
783 ASSERT_EQ("/a", I->getName());
784 I.increment(EC);
785 ASSERT_FALSE(EC);
786 ASSERT_EQ("/b", I->getName());
787 I.increment(EC);
788 ASSERT_FALSE(EC);
789 ASSERT_EQ(vfs::directory_iterator(), I);
790
791 I = FS.dir_begin("/b", EC);
792 ASSERT_FALSE(EC);
Simon Marchiddbabc62018-08-06 21:48:20 +0000793 // When on Windows, we end up with "/b\\c" as the name. Convert to Posix
794 // path for the sake of the comparison.
795 ASSERT_EQ("/b/c", getPosixPath(I->getName()));
Benjamin Kramera25dcfd2015-10-05 13:55:14 +0000796 I.increment(EC);
797 ASSERT_FALSE(EC);
798 ASSERT_EQ(vfs::directory_iterator(), I);
799}
800
Benjamin Kramer1b8dbe32015-10-06 14:45:16 +0000801TEST_F(InMemoryFileSystemTest, WorkingDirectory) {
802 FS.setCurrentWorkingDirectory("/b");
803 FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
804
805 auto Stat = FS.status("/b/c");
806 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
Simon Marchiddbabc62018-08-06 21:48:20 +0000807 ASSERT_EQ("/b/c", Stat->getName());
Benjamin Kramer1b8dbe32015-10-06 14:45:16 +0000808 ASSERT_EQ("/b", *FS.getCurrentWorkingDirectory());
809
810 Stat = FS.status("c");
811 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
Benjamin Kramere9e76072016-01-09 16:33:16 +0000812
813 NormalizedFS.setCurrentWorkingDirectory("/b/c");
814 NormalizedFS.setCurrentWorkingDirectory(".");
Simon Marchiddbabc62018-08-06 21:48:20 +0000815 ASSERT_EQ("/b/c",
816 getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get()));
Benjamin Kramere9e76072016-01-09 16:33:16 +0000817 NormalizedFS.setCurrentWorkingDirectory("..");
Simon Marchiddbabc62018-08-06 21:48:20 +0000818 ASSERT_EQ("/b",
819 getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get()));
Benjamin Kramer1b8dbe32015-10-06 14:45:16 +0000820}
821
Eric Liu43cb4512018-05-24 13:52:48 +0000822#if !defined(_WIN32)
Eric Liu33dd6192018-05-24 11:17:00 +0000823TEST_F(InMemoryFileSystemTest, GetRealPath) {
824 SmallString<16> Path;
825 EXPECT_EQ(FS.getRealPath("b", Path), errc::operation_not_permitted);
826
827 auto GetRealPath = [this](StringRef P) {
828 SmallString<16> Output;
829 auto EC = FS.getRealPath(P, Output);
830 EXPECT_FALSE(EC);
831 return Output.str().str();
832 };
833
834 FS.setCurrentWorkingDirectory("a");
835 EXPECT_EQ(GetRealPath("b"), "a/b");
836 EXPECT_EQ(GetRealPath("../b"), "b");
837 EXPECT_EQ(GetRealPath("b/./c"), "a/b/c");
838
839 FS.setCurrentWorkingDirectory("/a");
840 EXPECT_EQ(GetRealPath("b"), "/a/b");
841 EXPECT_EQ(GetRealPath("../b"), "/b");
842 EXPECT_EQ(GetRealPath("b/./c"), "/a/b/c");
843}
Eric Liu43cb4512018-05-24 13:52:48 +0000844#endif // _WIN32
Eric Liu33dd6192018-05-24 11:17:00 +0000845
Ben Hamiltone5af5bd2017-11-09 16:01:16 +0000846TEST_F(InMemoryFileSystemTest, AddFileWithUser) {
847 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), 0xFEEDFACE);
848 auto Stat = FS.status("/a");
849 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
850 ASSERT_TRUE(Stat->isDirectory());
851 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
852 Stat = FS.status("/a/b");
853 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
854 ASSERT_TRUE(Stat->isDirectory());
855 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
856 Stat = FS.status("/a/b/c");
857 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
858 ASSERT_TRUE(Stat->isRegularFile());
859 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
860 ASSERT_EQ(0xFEEDFACE, Stat->getUser());
861}
862
863TEST_F(InMemoryFileSystemTest, AddFileWithGroup) {
864 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, 0xDABBAD00);
865 auto Stat = FS.status("/a");
866 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
867 ASSERT_TRUE(Stat->isDirectory());
868 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
869 Stat = FS.status("/a/b");
870 ASSERT_TRUE(Stat->isDirectory());
871 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
872 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
873 Stat = FS.status("/a/b/c");
874 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
875 ASSERT_TRUE(Stat->isRegularFile());
876 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
877 ASSERT_EQ(0xDABBAD00, Stat->getGroup());
878}
879
880TEST_F(InMemoryFileSystemTest, AddFileWithFileType) {
881 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None,
882 sys::fs::file_type::socket_file);
883 auto Stat = FS.status("/a");
884 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
885 ASSERT_TRUE(Stat->isDirectory());
886 Stat = FS.status("/a/b");
887 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
888 ASSERT_TRUE(Stat->isDirectory());
889 Stat = FS.status("/a/b/c");
890 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
891 ASSERT_EQ(sys::fs::file_type::socket_file, Stat->getType());
892 ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
893}
894
895TEST_F(InMemoryFileSystemTest, AddFileWithPerms) {
896 FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None,
897 None, sys::fs::perms::owner_read | sys::fs::perms::owner_write);
898 auto Stat = FS.status("/a");
899 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
900 ASSERT_TRUE(Stat->isDirectory());
901 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
902 sys::fs::perms::owner_exe, Stat->getPermissions());
903 Stat = FS.status("/a/b");
904 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
905 ASSERT_TRUE(Stat->isDirectory());
906 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
907 sys::fs::perms::owner_exe, Stat->getPermissions());
908 Stat = FS.status("/a/b/c");
909 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
910 ASSERT_TRUE(Stat->isRegularFile());
911 ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write,
912 Stat->getPermissions());
913}
914
Ben Hamilton78381012017-11-16 19:34:08 +0000915TEST_F(InMemoryFileSystemTest, AddDirectoryThenAddChild) {
916 FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""), /*User=*/None,
917 /*Group=*/None, sys::fs::file_type::directory_file);
918 FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("abc"), /*User=*/None,
919 /*Group=*/None, sys::fs::file_type::regular_file);
920 auto Stat = FS.status("/a");
921 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
922 ASSERT_TRUE(Stat->isDirectory());
923 Stat = FS.status("/a/b");
924 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
925 ASSERT_TRUE(Stat->isRegularFile());
926}
927
Simon Marchiddbabc62018-08-06 21:48:20 +0000928// Test that the name returned by status() is in the same form as the path that
929// was requested (to match the behavior of RealFileSystem).
930TEST_F(InMemoryFileSystemTest, StatusName) {
931 NormalizedFS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"),
932 /*User=*/None,
933 /*Group=*/None, sys::fs::file_type::regular_file);
934 NormalizedFS.setCurrentWorkingDirectory("/a/b");
935
936 // Access using InMemoryFileSystem::status.
937 auto Stat = NormalizedFS.status("../b/c");
938 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
939 << NormalizedFS.toString();
940 ASSERT_TRUE(Stat->isRegularFile());
941 ASSERT_EQ("../b/c", Stat->getName());
942
943 // Access using InMemoryFileAdaptor::status.
944 auto File = NormalizedFS.openFileForRead("../b/c");
945 ASSERT_FALSE(File.getError()) << File.getError() << "\n"
946 << NormalizedFS.toString();
947 Stat = (*File)->status();
948 ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
949 << NormalizedFS.toString();
950 ASSERT_TRUE(Stat->isRegularFile());
951 ASSERT_EQ("../b/c", Stat->getName());
952
953 // Access using a directory iterator.
954 std::error_code EC;
955 clang::vfs::directory_iterator It = NormalizedFS.dir_begin("../b", EC);
956 // When on Windows, we end up with "../b\\c" as the name. Convert to Posix
957 // path for the sake of the comparison.
958 ASSERT_EQ("../b/c", getPosixPath(It->getName()));
959}
960
Ben Langmuir93853232014-03-05 21:32:20 +0000961// NOTE: in the tests below, we use '//root/' as our root directory, since it is
962// a legal *absolute* path on Windows as well as *nix.
Ben Langmuir97882e72014-02-24 20:56:37 +0000963class VFSFromYAMLTest : public ::testing::Test {
964public:
965 int NumDiagnostics;
Ben Langmuir93853232014-03-05 21:32:20 +0000966
Alexander Kornienko34eb2072015-04-11 02:00:23 +0000967 void SetUp() override { NumDiagnostics = 0; }
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000968
Ben Langmuir97882e72014-02-24 20:56:37 +0000969 static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
970 VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
971 ++Test->NumDiagnostics;
972 }
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000973
Ben Langmuir97882e72014-02-24 20:56:37 +0000974 IntrusiveRefCntPtr<vfs::FileSystem>
975 getFromYAMLRawString(StringRef Content,
976 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
Rafael Espindolad87f8d72014-08-27 20:03:29 +0000977 std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content);
Bruno Cardoso Lopesd878e282016-03-20 02:08:48 +0000978 return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, "", this,
Rafael Espindola91ac8df2014-08-17 23:27:13 +0000979 ExternalFS);
Ben Langmuir97882e72014-02-24 20:56:37 +0000980 }
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000981
Ben Langmuir97882e72014-02-24 20:56:37 +0000982 IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
983 StringRef Content,
984 IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
985 std::string VersionPlusContent("{\n 'version':0,\n");
986 VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
987 return getFromYAMLRawString(VersionPlusContent, ExternalFS);
988 }
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +0000989
990 // This is intended as a "XFAIL" for windows hosts.
991 bool supportsSameDirMultipleYAMLEntries() {
992 Triple Host(Triple::normalize(sys::getProcessTriple()));
993 return !Host.isOSWindows();
994 }
Ben Langmuir97882e72014-02-24 20:56:37 +0000995};
996
997TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +0000998 IntrusiveRefCntPtr<vfs::FileSystem> FS;
999 FS = getFromYAMLString("");
Alp Tokerf994cef2014-07-05 03:08:06 +00001000 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001001 FS = getFromYAMLString("[]");
Alp Tokerf994cef2014-07-05 03:08:06 +00001002 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001003 FS = getFromYAMLString("'string'");
Alp Tokerf994cef2014-07-05 03:08:06 +00001004 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001005 EXPECT_EQ(3, NumDiagnostics);
1006}
1007
Ben Langmuir97882e72014-02-24 20:56:37 +00001008TEST_F(VFSFromYAMLTest, MappedFiles) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001009 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001010 Lower->addRegularFile("//root/foo/bar/a");
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001011 IntrusiveRefCntPtr<vfs::FileSystem> FS =
1012 getFromYAMLString("{ 'roots': [\n"
1013 "{\n"
1014 " 'type': 'directory',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001015 " 'name': '//root/',\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001016 " 'contents': [ {\n"
1017 " 'type': 'file',\n"
1018 " 'name': 'file1',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001019 " 'external-contents': '//root/foo/bar/a'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001020 " },\n"
1021 " {\n"
1022 " 'type': 'file',\n"
1023 " 'name': 'file2',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001024 " 'external-contents': '//root/foo/b'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001025 " }\n"
1026 " ]\n"
1027 "}\n"
1028 "]\n"
1029 "}",
1030 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001031 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001032
1033 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1034 new vfs::OverlayFileSystem(Lower));
1035 O->pushOverlay(FS);
1036
1037 // file
Ben Langmuir93853232014-03-05 21:32:20 +00001038 ErrorOr<vfs::Status> S = O->status("//root/file1");
Rafael Espindola3ae06202014-05-31 03:20:52 +00001039 ASSERT_FALSE(S.getError());
Ben Langmuir93853232014-03-05 21:32:20 +00001040 EXPECT_EQ("//root/foo/bar/a", S->getName());
Ben Langmuirf13302e2015-12-10 23:41:39 +00001041 EXPECT_TRUE(S->IsVFSMapped);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001042
Ben Langmuir93853232014-03-05 21:32:20 +00001043 ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
1044 EXPECT_EQ("//root/foo/bar/a", SLower->getName());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001045 EXPECT_TRUE(S->equivalent(*SLower));
Ben Langmuirf13302e2015-12-10 23:41:39 +00001046 EXPECT_FALSE(SLower->IsVFSMapped);
1047
1048 // file after opening
1049 auto OpenedF = O->openFileForRead("//root/file1");
1050 ASSERT_FALSE(OpenedF.getError());
1051 auto OpenedS = (*OpenedF)->status();
1052 ASSERT_FALSE(OpenedS.getError());
1053 EXPECT_EQ("//root/foo/bar/a", OpenedS->getName());
1054 EXPECT_TRUE(OpenedS->IsVFSMapped);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001055
1056 // directory
Ben Langmuir93853232014-03-05 21:32:20 +00001057 S = O->status("//root/");
Rafael Espindola3ae06202014-05-31 03:20:52 +00001058 ASSERT_FALSE(S.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001059 EXPECT_TRUE(S->isDirectory());
Ben Langmuir93853232014-03-05 21:32:20 +00001060 EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001061
1062 // broken mapping
Rafael Espindola71de0b62014-06-13 17:20:50 +00001063 EXPECT_EQ(O->status("//root/file2").getError(),
1064 llvm::errc::no_such_file_or_directory);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001065 EXPECT_EQ(0, NumDiagnostics);
1066}
1067
Ben Langmuir97882e72014-02-24 20:56:37 +00001068TEST_F(VFSFromYAMLTest, CaseInsensitive) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001069 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001070 Lower->addRegularFile("//root/foo/bar/a");
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001071 IntrusiveRefCntPtr<vfs::FileSystem> FS =
1072 getFromYAMLString("{ 'case-sensitive': 'false',\n"
1073 " 'roots': [\n"
1074 "{\n"
1075 " 'type': 'directory',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001076 " 'name': '//root/',\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001077 " 'contents': [ {\n"
1078 " 'type': 'file',\n"
1079 " 'name': 'XX',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001080 " 'external-contents': '//root/foo/bar/a'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001081 " }\n"
1082 " ]\n"
1083 "}]}",
1084 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001085 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001086
1087 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1088 new vfs::OverlayFileSystem(Lower));
1089 O->pushOverlay(FS);
1090
Ben Langmuir93853232014-03-05 21:32:20 +00001091 ErrorOr<vfs::Status> S = O->status("//root/XX");
Rafael Espindola3ae06202014-05-31 03:20:52 +00001092 ASSERT_FALSE(S.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001093
Ben Langmuir93853232014-03-05 21:32:20 +00001094 ErrorOr<vfs::Status> SS = O->status("//root/xx");
Rafael Espindola3ae06202014-05-31 03:20:52 +00001095 ASSERT_FALSE(SS.getError());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001096 EXPECT_TRUE(S->equivalent(*SS));
Ben Langmuir93853232014-03-05 21:32:20 +00001097 SS = O->status("//root/xX");
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001098 EXPECT_TRUE(S->equivalent(*SS));
Ben Langmuir93853232014-03-05 21:32:20 +00001099 SS = O->status("//root/Xx");
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001100 EXPECT_TRUE(S->equivalent(*SS));
1101 EXPECT_EQ(0, NumDiagnostics);
1102}
1103
Ben Langmuir97882e72014-02-24 20:56:37 +00001104TEST_F(VFSFromYAMLTest, CaseSensitive) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001105 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001106 Lower->addRegularFile("//root/foo/bar/a");
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001107 IntrusiveRefCntPtr<vfs::FileSystem> FS =
1108 getFromYAMLString("{ 'case-sensitive': 'true',\n"
1109 " 'roots': [\n"
1110 "{\n"
1111 " 'type': 'directory',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001112 " 'name': '//root/',\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001113 " 'contents': [ {\n"
1114 " 'type': 'file',\n"
1115 " 'name': 'XX',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001116 " 'external-contents': '//root/foo/bar/a'\n"
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001117 " }\n"
1118 " ]\n"
1119 "}]}",
1120 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001121 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001122
1123 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1124 new vfs::OverlayFileSystem(Lower));
1125 O->pushOverlay(FS);
1126
Ben Langmuir93853232014-03-05 21:32:20 +00001127 ErrorOr<vfs::Status> SS = O->status("//root/xx");
Rafael Espindola71de0b62014-06-13 17:20:50 +00001128 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuir93853232014-03-05 21:32:20 +00001129 SS = O->status("//root/xX");
Rafael Espindola71de0b62014-06-13 17:20:50 +00001130 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuir93853232014-03-05 21:32:20 +00001131 SS = O->status("//root/Xx");
Rafael Espindola71de0b62014-06-13 17:20:50 +00001132 EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001133 EXPECT_EQ(0, NumDiagnostics);
1134}
1135
Ben Langmuir97882e72014-02-24 20:56:37 +00001136TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001137 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1138
1139 // invalid YAML at top-level
1140 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001141 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001142 // invalid YAML in roots
1143 FS = getFromYAMLString("{ 'roots':[}", Lower);
1144 // invalid YAML in directory
1145 FS = getFromYAMLString(
1146 "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
1147 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001148 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001149
1150 // invalid configuration
1151 FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001152 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001153 FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001154 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001155
1156 // invalid roots
1157 FS = getFromYAMLString("{ 'roots':'' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001158 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001159 FS = getFromYAMLString("{ 'roots':{} }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001160 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001161
1162 // invalid entries
1163 FS = getFromYAMLString(
1164 "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001165 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001166 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
1167 "'external-contents': 'other' }",
1168 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001169 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001170 FS = getFromYAMLString(
1171 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
1172 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001173 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001174 FS = getFromYAMLString(
1175 "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
1176 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001177 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001178 FS = getFromYAMLString(
1179 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
1180 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001181 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001182 FS = getFromYAMLString(
1183 "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
1184 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001185 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001186 FS = getFromYAMLString(
1187 "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
1188 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001189 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001190
1191 // missing mandatory fields
1192 FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001193 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001194 FS = getFromYAMLString(
1195 "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001196 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001197 FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001198 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001199
1200 // duplicate keys
1201 FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001202 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001203 FS = getFromYAMLString(
1204 "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
1205 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001206 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001207 FS =
1208 getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
1209 "'external-contents':'blah' } ] }",
1210 Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001211 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001212
1213 // missing version
1214 FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001215 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001216
1217 // bad version number
1218 FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001219 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001220 FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001221 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001222 FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001223 EXPECT_EQ(nullptr, FS.get());
Ben Langmuird51ba0b2014-02-21 23:39:37 +00001224 EXPECT_EQ(24, NumDiagnostics);
1225}
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001226
Ben Langmuirb59cf672014-02-27 00:25:12 +00001227TEST_F(VFSFromYAMLTest, UseExternalName) {
1228 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001229 Lower->addRegularFile("//root/external/file");
Ben Langmuirb59cf672014-02-27 00:25:12 +00001230
1231 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1232 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001233 " { 'type': 'file', 'name': '//root/A',\n"
1234 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001235 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001236 " { 'type': 'file', 'name': '//root/B',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001237 " 'use-external-name': true,\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001238 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001239 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001240 " { 'type': 'file', 'name': '//root/C',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001241 " 'use-external-name': false,\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001242 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001243 " }\n"
1244 "] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001245 ASSERT_TRUE(nullptr != FS.get());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001246
1247 // default true
Ben Langmuir93853232014-03-05 21:32:20 +00001248 EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001249 // explicit
Ben Langmuir93853232014-03-05 21:32:20 +00001250 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1251 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001252
1253 // global configuration
1254 FS = getFromYAMLString(
1255 "{ 'use-external-names': false,\n"
1256 " 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001257 " { 'type': 'file', 'name': '//root/A',\n"
1258 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001259 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001260 " { 'type': 'file', 'name': '//root/B',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001261 " 'use-external-name': true,\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001262 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001263 " },\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001264 " { 'type': 'file', 'name': '//root/C',\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001265 " 'use-external-name': false,\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001266 " 'external-contents': '//root/external/file'\n"
Ben Langmuirb59cf672014-02-27 00:25:12 +00001267 " }\n"
1268 "] }", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001269 ASSERT_TRUE(nullptr != FS.get());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001270
1271 // default
Ben Langmuir93853232014-03-05 21:32:20 +00001272 EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001273 // explicit
Ben Langmuir93853232014-03-05 21:32:20 +00001274 EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1275 EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
Ben Langmuirb59cf672014-02-27 00:25:12 +00001276}
1277
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001278TEST_F(VFSFromYAMLTest, MultiComponentPath) {
1279 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001280 Lower->addRegularFile("//root/other");
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001281
1282 // file in roots
1283 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1284 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001285 " { 'type': 'file', 'name': '//root/path/to/file',\n"
1286 " 'external-contents': '//root/other' }]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001287 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001288 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001289 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1290 EXPECT_FALSE(FS->status("//root/path/to").getError());
1291 EXPECT_FALSE(FS->status("//root/path").getError());
1292 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001293
1294 // at the start
1295 FS = getFromYAMLString(
1296 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001297 " { 'type': 'directory', 'name': '//root/path/to',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001298 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001299 " 'external-contents': '//root/other' }]}]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001300 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001301 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001302 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1303 EXPECT_FALSE(FS->status("//root/path/to").getError());
1304 EXPECT_FALSE(FS->status("//root/path").getError());
1305 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001306
1307 // at the end
1308 FS = getFromYAMLString(
1309 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001310 " { 'type': 'directory', 'name': '//root/',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001311 " 'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001312 " 'external-contents': '//root/other' }]}]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001313 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001314 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001315 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1316 EXPECT_FALSE(FS->status("//root/path/to").getError());
1317 EXPECT_FALSE(FS->status("//root/path").getError());
1318 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001319}
1320
1321TEST_F(VFSFromYAMLTest, TrailingSlashes) {
1322 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
Ben Langmuir93853232014-03-05 21:32:20 +00001323 Lower->addRegularFile("//root/other");
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001324
1325 // file in roots
1326 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1327 "{ 'roots': [\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001328 " { 'type': 'directory', 'name': '//root/path/to////',\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001329 " 'contents': [ { 'type': 'file', 'name': 'file',\n"
Ben Langmuir93853232014-03-05 21:32:20 +00001330 " 'external-contents': '//root/other' }]}]\n"
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001331 "}", Lower);
Alp Tokerf994cef2014-07-05 03:08:06 +00001332 ASSERT_TRUE(nullptr != FS.get());
Rafael Espindola3ae06202014-05-31 03:20:52 +00001333 EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1334 EXPECT_FALSE(FS->status("//root/path/to").getError());
1335 EXPECT_FALSE(FS->status("//root/path").getError());
1336 EXPECT_FALSE(FS->status("//root/").getError());
Ben Langmuir47ff9ab2014-02-25 04:34:14 +00001337}
Ben Langmuir740812b2014-06-24 19:37:16 +00001338
1339TEST_F(VFSFromYAMLTest, DirectoryIteration) {
1340 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1341 Lower->addDirectory("//root/");
1342 Lower->addDirectory("//root/foo");
1343 Lower->addDirectory("//root/foo/bar");
1344 Lower->addRegularFile("//root/foo/bar/a");
1345 Lower->addRegularFile("//root/foo/bar/b");
1346 Lower->addRegularFile("//root/file3");
1347 IntrusiveRefCntPtr<vfs::FileSystem> FS =
1348 getFromYAMLString("{ 'use-external-names': false,\n"
1349 " 'roots': [\n"
1350 "{\n"
1351 " 'type': 'directory',\n"
1352 " 'name': '//root/',\n"
1353 " 'contents': [ {\n"
1354 " 'type': 'file',\n"
1355 " 'name': 'file1',\n"
1356 " 'external-contents': '//root/foo/bar/a'\n"
1357 " },\n"
1358 " {\n"
1359 " 'type': 'file',\n"
1360 " 'name': 'file2',\n"
1361 " 'external-contents': '//root/foo/bar/b'\n"
1362 " }\n"
1363 " ]\n"
1364 "}\n"
1365 "]\n"
1366 "}",
1367 Lower);
Hans Wennborgdcfba332015-10-06 23:40:43 +00001368 ASSERT_TRUE(FS.get() != nullptr);
Ben Langmuir740812b2014-06-24 19:37:16 +00001369
1370 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1371 new vfs::OverlayFileSystem(Lower));
1372 O->pushOverlay(FS);
1373
1374 std::error_code EC;
Benjamin Kramer2a23e552016-01-10 10:45:19 +00001375 checkContents(O->dir_begin("//root/", EC),
Bruno Cardoso Lopes26092b22016-05-12 04:43:27 +00001376 {"//root/file1", "//root/file2", "//root/file3", "//root/foo"});
Ben Langmuir740812b2014-06-24 19:37:16 +00001377
Benjamin Kramer2a23e552016-01-10 10:45:19 +00001378 checkContents(O->dir_begin("//root/foo/bar", EC),
1379 {"//root/foo/bar/a", "//root/foo/bar/b"});
Ben Langmuir740812b2014-06-24 19:37:16 +00001380}
Bruno Cardoso Lopesf6a0a722016-05-12 19:13:07 +00001381
1382TEST_F(VFSFromYAMLTest, DirectoryIterationSameDirMultipleEntries) {
1383 // https://llvm.org/bugs/show_bug.cgi?id=27725
1384 if (!supportsSameDirMultipleYAMLEntries())
1385 return;
1386
1387 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1388 Lower->addDirectory("//root/zab");
1389 Lower->addDirectory("//root/baz");
1390 Lower->addRegularFile("//root/zab/a");
1391 Lower->addRegularFile("//root/zab/b");
1392 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1393 "{ 'use-external-names': false,\n"
1394 " 'roots': [\n"
1395 "{\n"
1396 " 'type': 'directory',\n"
1397 " 'name': '//root/baz/',\n"
1398 " 'contents': [ {\n"
1399 " 'type': 'file',\n"
1400 " 'name': 'x',\n"
1401 " 'external-contents': '//root/zab/a'\n"
1402 " }\n"
1403 " ]\n"
1404 "},\n"
1405 "{\n"
1406 " 'type': 'directory',\n"
1407 " 'name': '//root/baz/',\n"
1408 " 'contents': [ {\n"
1409 " 'type': 'file',\n"
1410 " 'name': 'y',\n"
1411 " 'external-contents': '//root/zab/b'\n"
1412 " }\n"
1413 " ]\n"
1414 "}\n"
1415 "]\n"
1416 "}",
1417 Lower);
1418 ASSERT_TRUE(FS.get() != nullptr);
1419
1420 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1421 new vfs::OverlayFileSystem(Lower));
1422 O->pushOverlay(FS);
1423
1424 std::error_code EC;
1425
1426 checkContents(O->dir_begin("//root/baz/", EC),
1427 {"//root/baz/x", "//root/baz/y"});
1428}
Bruno Cardoso Lopes32b28972016-05-14 00:00:18 +00001429
1430TEST_F(VFSFromYAMLTest, RecursiveDirectoryIterationLevel) {
1431
1432 IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1433 Lower->addDirectory("//root/a");
1434 Lower->addDirectory("//root/a/b");
1435 Lower->addDirectory("//root/a/b/c");
1436 Lower->addRegularFile("//root/a/b/c/file");
1437 IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1438 "{ 'use-external-names': false,\n"
1439 " 'roots': [\n"
1440 "{\n"
1441 " 'type': 'directory',\n"
1442 " 'name': '//root/a/b/c/',\n"
1443 " 'contents': [ {\n"
1444 " 'type': 'file',\n"
1445 " 'name': 'file',\n"
1446 " 'external-contents': '//root/a/b/c/file'\n"
1447 " }\n"
1448 " ]\n"
1449 "},\n"
1450 "]\n"
1451 "}",
1452 Lower);
1453 ASSERT_TRUE(FS.get() != nullptr);
1454
1455 IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1456 new vfs::OverlayFileSystem(Lower));
1457 O->pushOverlay(FS);
1458
1459 std::error_code EC;
1460
1461 // Test recursive_directory_iterator level()
1462 vfs::recursive_directory_iterator I = vfs::recursive_directory_iterator(
1463 *O, "//root", EC), E;
1464 ASSERT_FALSE(EC);
1465 for (int l = 0; I != E; I.increment(EC), ++l) {
1466 ASSERT_FALSE(EC);
1467 EXPECT_EQ(I.level(), l);
1468 }
1469 EXPECT_EQ(I, E);
1470}