1*67e74705SXin Li //===- unittests/Basic/VirtualFileSystem.cpp ---------------- VFS tests ---===//
2*67e74705SXin Li //
3*67e74705SXin Li // The LLVM Compiler Infrastructure
4*67e74705SXin Li //
5*67e74705SXin Li // This file is distributed under the University of Illinois Open Source
6*67e74705SXin Li // License. See LICENSE.TXT for details.
7*67e74705SXin Li //
8*67e74705SXin Li //===----------------------------------------------------------------------===//
9*67e74705SXin Li
10*67e74705SXin Li #include "clang/Basic/VirtualFileSystem.h"
11*67e74705SXin Li #include "llvm/ADT/Triple.h"
12*67e74705SXin Li #include "llvm/Support/Errc.h"
13*67e74705SXin Li #include "llvm/Support/Host.h"
14*67e74705SXin Li #include "llvm/Support/MemoryBuffer.h"
15*67e74705SXin Li #include "llvm/Support/Path.h"
16*67e74705SXin Li #include "llvm/Support/SourceMgr.h"
17*67e74705SXin Li #include "gtest/gtest.h"
18*67e74705SXin Li #include <map>
19*67e74705SXin Li
20*67e74705SXin Li using namespace clang;
21*67e74705SXin Li using namespace llvm;
22*67e74705SXin Li using llvm::sys::fs::UniqueID;
23*67e74705SXin Li
24*67e74705SXin Li namespace {
25*67e74705SXin Li struct DummyFile : public vfs::File {
26*67e74705SXin Li vfs::Status S;
DummyFile__anon429988cb0111::DummyFile27*67e74705SXin Li explicit DummyFile(vfs::Status S) : S(S) {}
status__anon429988cb0111::DummyFile28*67e74705SXin Li llvm::ErrorOr<vfs::Status> status() override { return S; }
29*67e74705SXin Li llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
getBuffer__anon429988cb0111::DummyFile30*67e74705SXin Li getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
31*67e74705SXin Li bool IsVolatile) override {
32*67e74705SXin Li llvm_unreachable("unimplemented");
33*67e74705SXin Li }
close__anon429988cb0111::DummyFile34*67e74705SXin Li std::error_code close() override { return std::error_code(); }
35*67e74705SXin Li };
36*67e74705SXin Li
37*67e74705SXin Li class DummyFileSystem : public vfs::FileSystem {
38*67e74705SXin Li int FSID; // used to produce UniqueIDs
39*67e74705SXin Li int FileID; // used to produce UniqueIDs
40*67e74705SXin Li std::map<std::string, vfs::Status> FilesAndDirs;
41*67e74705SXin Li
getNextFSID()42*67e74705SXin Li static int getNextFSID() {
43*67e74705SXin Li static int Count = 0;
44*67e74705SXin Li return Count++;
45*67e74705SXin Li }
46*67e74705SXin Li
47*67e74705SXin Li public:
DummyFileSystem()48*67e74705SXin Li DummyFileSystem() : FSID(getNextFSID()), FileID(0) {}
49*67e74705SXin Li
status(const Twine & Path)50*67e74705SXin Li ErrorOr<vfs::Status> status(const Twine &Path) override {
51*67e74705SXin Li std::map<std::string, vfs::Status>::iterator I =
52*67e74705SXin Li FilesAndDirs.find(Path.str());
53*67e74705SXin Li if (I == FilesAndDirs.end())
54*67e74705SXin Li return make_error_code(llvm::errc::no_such_file_or_directory);
55*67e74705SXin Li return I->second;
56*67e74705SXin Li }
57*67e74705SXin Li ErrorOr<std::unique_ptr<vfs::File>>
openFileForRead(const Twine & Path)58*67e74705SXin Li openFileForRead(const Twine &Path) override {
59*67e74705SXin Li auto S = status(Path);
60*67e74705SXin Li if (S)
61*67e74705SXin Li return std::unique_ptr<vfs::File>(new DummyFile{*S});
62*67e74705SXin Li return S.getError();
63*67e74705SXin Li }
getCurrentWorkingDirectory() const64*67e74705SXin Li llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
65*67e74705SXin Li return std::string();
66*67e74705SXin Li }
setCurrentWorkingDirectory(const Twine & Path)67*67e74705SXin Li std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
68*67e74705SXin Li return std::error_code();
69*67e74705SXin Li }
70*67e74705SXin Li
71*67e74705SXin Li struct DirIterImpl : public clang::vfs::detail::DirIterImpl {
72*67e74705SXin Li std::map<std::string, vfs::Status> &FilesAndDirs;
73*67e74705SXin Li std::map<std::string, vfs::Status>::iterator I;
74*67e74705SXin Li std::string Path;
isInPath__anon429988cb0111::DummyFileSystem::DirIterImpl75*67e74705SXin Li bool isInPath(StringRef S) {
76*67e74705SXin Li if (Path.size() < S.size() && S.find(Path) == 0) {
77*67e74705SXin Li auto LastSep = S.find_last_of('/');
78*67e74705SXin Li if (LastSep == Path.size() || LastSep == Path.size()-1)
79*67e74705SXin Li return true;
80*67e74705SXin Li }
81*67e74705SXin Li return false;
82*67e74705SXin Li }
DirIterImpl__anon429988cb0111::DummyFileSystem::DirIterImpl83*67e74705SXin Li DirIterImpl(std::map<std::string, vfs::Status> &FilesAndDirs,
84*67e74705SXin Li const Twine &_Path)
85*67e74705SXin Li : FilesAndDirs(FilesAndDirs), I(FilesAndDirs.begin()),
86*67e74705SXin Li Path(_Path.str()) {
87*67e74705SXin Li for ( ; I != FilesAndDirs.end(); ++I) {
88*67e74705SXin Li if (isInPath(I->first)) {
89*67e74705SXin Li CurrentEntry = I->second;
90*67e74705SXin Li break;
91*67e74705SXin Li }
92*67e74705SXin Li }
93*67e74705SXin Li }
increment__anon429988cb0111::DummyFileSystem::DirIterImpl94*67e74705SXin Li std::error_code increment() override {
95*67e74705SXin Li ++I;
96*67e74705SXin Li for ( ; I != FilesAndDirs.end(); ++I) {
97*67e74705SXin Li if (isInPath(I->first)) {
98*67e74705SXin Li CurrentEntry = I->second;
99*67e74705SXin Li break;
100*67e74705SXin Li }
101*67e74705SXin Li }
102*67e74705SXin Li if (I == FilesAndDirs.end())
103*67e74705SXin Li CurrentEntry = vfs::Status();
104*67e74705SXin Li return std::error_code();
105*67e74705SXin Li }
106*67e74705SXin Li };
107*67e74705SXin Li
dir_begin(const Twine & Dir,std::error_code & EC)108*67e74705SXin Li vfs::directory_iterator dir_begin(const Twine &Dir,
109*67e74705SXin Li std::error_code &EC) override {
110*67e74705SXin Li return vfs::directory_iterator(
111*67e74705SXin Li std::make_shared<DirIterImpl>(FilesAndDirs, Dir));
112*67e74705SXin Li }
113*67e74705SXin Li
addEntry(StringRef Path,const vfs::Status & Status)114*67e74705SXin Li void addEntry(StringRef Path, const vfs::Status &Status) {
115*67e74705SXin Li FilesAndDirs[Path] = Status;
116*67e74705SXin Li }
117*67e74705SXin Li
addRegularFile(StringRef Path,sys::fs::perms Perms=sys::fs::all_all)118*67e74705SXin Li void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
119*67e74705SXin Li vfs::Status S(Path, UniqueID(FSID, FileID++), sys::TimeValue::now(), 0, 0,
120*67e74705SXin Li 1024, sys::fs::file_type::regular_file, Perms);
121*67e74705SXin Li addEntry(Path, S);
122*67e74705SXin Li }
123*67e74705SXin Li
addDirectory(StringRef Path,sys::fs::perms Perms=sys::fs::all_all)124*67e74705SXin Li void addDirectory(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
125*67e74705SXin Li vfs::Status S(Path, UniqueID(FSID, FileID++), sys::TimeValue::now(), 0, 0,
126*67e74705SXin Li 0, sys::fs::file_type::directory_file, Perms);
127*67e74705SXin Li addEntry(Path, S);
128*67e74705SXin Li }
129*67e74705SXin Li
addSymlink(StringRef Path)130*67e74705SXin Li void addSymlink(StringRef Path) {
131*67e74705SXin Li vfs::Status S(Path, UniqueID(FSID, FileID++), sys::TimeValue::now(), 0, 0,
132*67e74705SXin Li 0, sys::fs::file_type::symlink_file, sys::fs::all_all);
133*67e74705SXin Li addEntry(Path, S);
134*67e74705SXin Li }
135*67e74705SXin Li };
136*67e74705SXin Li } // end anonymous namespace
137*67e74705SXin Li
TEST(VirtualFileSystemTest,StatusQueries)138*67e74705SXin Li TEST(VirtualFileSystemTest, StatusQueries) {
139*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
140*67e74705SXin Li ErrorOr<vfs::Status> Status((std::error_code()));
141*67e74705SXin Li
142*67e74705SXin Li D->addRegularFile("/foo");
143*67e74705SXin Li Status = D->status("/foo");
144*67e74705SXin Li ASSERT_FALSE(Status.getError());
145*67e74705SXin Li EXPECT_TRUE(Status->isStatusKnown());
146*67e74705SXin Li EXPECT_FALSE(Status->isDirectory());
147*67e74705SXin Li EXPECT_TRUE(Status->isRegularFile());
148*67e74705SXin Li EXPECT_FALSE(Status->isSymlink());
149*67e74705SXin Li EXPECT_FALSE(Status->isOther());
150*67e74705SXin Li EXPECT_TRUE(Status->exists());
151*67e74705SXin Li
152*67e74705SXin Li D->addDirectory("/bar");
153*67e74705SXin Li Status = D->status("/bar");
154*67e74705SXin Li ASSERT_FALSE(Status.getError());
155*67e74705SXin Li EXPECT_TRUE(Status->isStatusKnown());
156*67e74705SXin Li EXPECT_TRUE(Status->isDirectory());
157*67e74705SXin Li EXPECT_FALSE(Status->isRegularFile());
158*67e74705SXin Li EXPECT_FALSE(Status->isSymlink());
159*67e74705SXin Li EXPECT_FALSE(Status->isOther());
160*67e74705SXin Li EXPECT_TRUE(Status->exists());
161*67e74705SXin Li
162*67e74705SXin Li D->addSymlink("/baz");
163*67e74705SXin Li Status = D->status("/baz");
164*67e74705SXin Li ASSERT_FALSE(Status.getError());
165*67e74705SXin Li EXPECT_TRUE(Status->isStatusKnown());
166*67e74705SXin Li EXPECT_FALSE(Status->isDirectory());
167*67e74705SXin Li EXPECT_FALSE(Status->isRegularFile());
168*67e74705SXin Li EXPECT_TRUE(Status->isSymlink());
169*67e74705SXin Li EXPECT_FALSE(Status->isOther());
170*67e74705SXin Li EXPECT_TRUE(Status->exists());
171*67e74705SXin Li
172*67e74705SXin Li EXPECT_TRUE(Status->equivalent(*Status));
173*67e74705SXin Li ErrorOr<vfs::Status> Status2 = D->status("/foo");
174*67e74705SXin Li ASSERT_FALSE(Status2.getError());
175*67e74705SXin Li EXPECT_FALSE(Status->equivalent(*Status2));
176*67e74705SXin Li }
177*67e74705SXin Li
TEST(VirtualFileSystemTest,BaseOnlyOverlay)178*67e74705SXin Li TEST(VirtualFileSystemTest, BaseOnlyOverlay) {
179*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
180*67e74705SXin Li ErrorOr<vfs::Status> Status((std::error_code()));
181*67e74705SXin Li EXPECT_FALSE(Status = D->status("/foo"));
182*67e74705SXin Li
183*67e74705SXin Li IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(new vfs::OverlayFileSystem(D));
184*67e74705SXin Li EXPECT_FALSE(Status = O->status("/foo"));
185*67e74705SXin Li
186*67e74705SXin Li D->addRegularFile("/foo");
187*67e74705SXin Li Status = D->status("/foo");
188*67e74705SXin Li EXPECT_FALSE(Status.getError());
189*67e74705SXin Li
190*67e74705SXin Li ErrorOr<vfs::Status> Status2((std::error_code()));
191*67e74705SXin Li Status2 = O->status("/foo");
192*67e74705SXin Li EXPECT_FALSE(Status2.getError());
193*67e74705SXin Li EXPECT_TRUE(Status->equivalent(*Status2));
194*67e74705SXin Li }
195*67e74705SXin Li
TEST(VirtualFileSystemTest,OverlayFiles)196*67e74705SXin Li TEST(VirtualFileSystemTest, OverlayFiles) {
197*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Base(new DummyFileSystem());
198*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
199*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Top(new DummyFileSystem());
200*67e74705SXin Li IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
201*67e74705SXin Li new vfs::OverlayFileSystem(Base));
202*67e74705SXin Li O->pushOverlay(Middle);
203*67e74705SXin Li O->pushOverlay(Top);
204*67e74705SXin Li
205*67e74705SXin Li ErrorOr<vfs::Status> Status1((std::error_code())),
206*67e74705SXin Li Status2((std::error_code())), Status3((std::error_code())),
207*67e74705SXin Li StatusB((std::error_code())), StatusM((std::error_code())),
208*67e74705SXin Li StatusT((std::error_code()));
209*67e74705SXin Li
210*67e74705SXin Li Base->addRegularFile("/foo");
211*67e74705SXin Li StatusB = Base->status("/foo");
212*67e74705SXin Li ASSERT_FALSE(StatusB.getError());
213*67e74705SXin Li Status1 = O->status("/foo");
214*67e74705SXin Li ASSERT_FALSE(Status1.getError());
215*67e74705SXin Li Middle->addRegularFile("/foo");
216*67e74705SXin Li StatusM = Middle->status("/foo");
217*67e74705SXin Li ASSERT_FALSE(StatusM.getError());
218*67e74705SXin Li Status2 = O->status("/foo");
219*67e74705SXin Li ASSERT_FALSE(Status2.getError());
220*67e74705SXin Li Top->addRegularFile("/foo");
221*67e74705SXin Li StatusT = Top->status("/foo");
222*67e74705SXin Li ASSERT_FALSE(StatusT.getError());
223*67e74705SXin Li Status3 = O->status("/foo");
224*67e74705SXin Li ASSERT_FALSE(Status3.getError());
225*67e74705SXin Li
226*67e74705SXin Li EXPECT_TRUE(Status1->equivalent(*StatusB));
227*67e74705SXin Li EXPECT_TRUE(Status2->equivalent(*StatusM));
228*67e74705SXin Li EXPECT_TRUE(Status3->equivalent(*StatusT));
229*67e74705SXin Li
230*67e74705SXin Li EXPECT_FALSE(Status1->equivalent(*Status2));
231*67e74705SXin Li EXPECT_FALSE(Status2->equivalent(*Status3));
232*67e74705SXin Li EXPECT_FALSE(Status1->equivalent(*Status3));
233*67e74705SXin Li }
234*67e74705SXin Li
TEST(VirtualFileSystemTest,OverlayDirsNonMerged)235*67e74705SXin Li TEST(VirtualFileSystemTest, OverlayDirsNonMerged) {
236*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
237*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
238*67e74705SXin Li IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
239*67e74705SXin Li new vfs::OverlayFileSystem(Lower));
240*67e74705SXin Li O->pushOverlay(Upper);
241*67e74705SXin Li
242*67e74705SXin Li Lower->addDirectory("/lower-only");
243*67e74705SXin Li Upper->addDirectory("/upper-only");
244*67e74705SXin Li
245*67e74705SXin Li // non-merged paths should be the same
246*67e74705SXin Li ErrorOr<vfs::Status> Status1 = Lower->status("/lower-only");
247*67e74705SXin Li ASSERT_FALSE(Status1.getError());
248*67e74705SXin Li ErrorOr<vfs::Status> Status2 = O->status("/lower-only");
249*67e74705SXin Li ASSERT_FALSE(Status2.getError());
250*67e74705SXin Li EXPECT_TRUE(Status1->equivalent(*Status2));
251*67e74705SXin Li
252*67e74705SXin Li Status1 = Upper->status("/upper-only");
253*67e74705SXin Li ASSERT_FALSE(Status1.getError());
254*67e74705SXin Li Status2 = O->status("/upper-only");
255*67e74705SXin Li ASSERT_FALSE(Status2.getError());
256*67e74705SXin Li EXPECT_TRUE(Status1->equivalent(*Status2));
257*67e74705SXin Li }
258*67e74705SXin Li
TEST(VirtualFileSystemTest,MergedDirPermissions)259*67e74705SXin Li TEST(VirtualFileSystemTest, MergedDirPermissions) {
260*67e74705SXin Li // merged directories get the permissions of the upper dir
261*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
262*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
263*67e74705SXin Li IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
264*67e74705SXin Li new vfs::OverlayFileSystem(Lower));
265*67e74705SXin Li O->pushOverlay(Upper);
266*67e74705SXin Li
267*67e74705SXin Li ErrorOr<vfs::Status> Status((std::error_code()));
268*67e74705SXin Li Lower->addDirectory("/both", sys::fs::owner_read);
269*67e74705SXin Li Upper->addDirectory("/both", sys::fs::owner_all | sys::fs::group_read);
270*67e74705SXin Li Status = O->status("/both");
271*67e74705SXin Li ASSERT_FALSE(Status.getError());
272*67e74705SXin Li EXPECT_EQ(0740, Status->getPermissions());
273*67e74705SXin Li
274*67e74705SXin Li // permissions (as usual) are not recursively applied
275*67e74705SXin Li Lower->addRegularFile("/both/foo", sys::fs::owner_read);
276*67e74705SXin Li Upper->addRegularFile("/both/bar", sys::fs::owner_write);
277*67e74705SXin Li Status = O->status("/both/foo");
278*67e74705SXin Li ASSERT_FALSE( Status.getError());
279*67e74705SXin Li EXPECT_EQ(0400, Status->getPermissions());
280*67e74705SXin Li Status = O->status("/both/bar");
281*67e74705SXin Li ASSERT_FALSE(Status.getError());
282*67e74705SXin Li EXPECT_EQ(0200, Status->getPermissions());
283*67e74705SXin Li }
284*67e74705SXin Li
285*67e74705SXin Li namespace {
286*67e74705SXin Li struct ScopedDir {
287*67e74705SXin Li SmallString<128> Path;
ScopedDir__anon429988cb0211::ScopedDir288*67e74705SXin Li ScopedDir(const Twine &Name, bool Unique=false) {
289*67e74705SXin Li std::error_code EC;
290*67e74705SXin Li if (Unique) {
291*67e74705SXin Li EC = llvm::sys::fs::createUniqueDirectory(Name, Path);
292*67e74705SXin Li } else {
293*67e74705SXin Li Path = Name.str();
294*67e74705SXin Li EC = llvm::sys::fs::create_directory(Twine(Path));
295*67e74705SXin Li }
296*67e74705SXin Li if (EC)
297*67e74705SXin Li Path = "";
298*67e74705SXin Li EXPECT_FALSE(EC);
299*67e74705SXin Li }
~ScopedDir__anon429988cb0211::ScopedDir300*67e74705SXin Li ~ScopedDir() {
301*67e74705SXin Li if (Path != "")
302*67e74705SXin Li EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
303*67e74705SXin Li }
operator StringRef__anon429988cb0211::ScopedDir304*67e74705SXin Li operator StringRef() { return Path.str(); }
305*67e74705SXin Li };
306*67e74705SXin Li } // end anonymous namespace
307*67e74705SXin Li
TEST(VirtualFileSystemTest,BasicRealFSIteration)308*67e74705SXin Li TEST(VirtualFileSystemTest, BasicRealFSIteration) {
309*67e74705SXin Li ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
310*67e74705SXin Li IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
311*67e74705SXin Li
312*67e74705SXin Li std::error_code EC;
313*67e74705SXin Li vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC);
314*67e74705SXin Li ASSERT_FALSE(EC);
315*67e74705SXin Li EXPECT_EQ(vfs::directory_iterator(), I); // empty directory is empty
316*67e74705SXin Li
317*67e74705SXin Li ScopedDir _a(TestDirectory+"/a");
318*67e74705SXin Li ScopedDir _ab(TestDirectory+"/a/b");
319*67e74705SXin Li ScopedDir _c(TestDirectory+"/c");
320*67e74705SXin Li ScopedDir _cd(TestDirectory+"/c/d");
321*67e74705SXin Li
322*67e74705SXin Li I = FS->dir_begin(Twine(TestDirectory), EC);
323*67e74705SXin Li ASSERT_FALSE(EC);
324*67e74705SXin Li ASSERT_NE(vfs::directory_iterator(), I);
325*67e74705SXin Li // Check either a or c, since we can't rely on the iteration order.
326*67e74705SXin Li EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
327*67e74705SXin Li I.increment(EC);
328*67e74705SXin Li ASSERT_FALSE(EC);
329*67e74705SXin Li ASSERT_NE(vfs::directory_iterator(), I);
330*67e74705SXin Li EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
331*67e74705SXin Li I.increment(EC);
332*67e74705SXin Li EXPECT_EQ(vfs::directory_iterator(), I);
333*67e74705SXin Li }
334*67e74705SXin Li
TEST(VirtualFileSystemTest,BasicRealFSRecursiveIteration)335*67e74705SXin Li TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
336*67e74705SXin Li ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
337*67e74705SXin Li IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
338*67e74705SXin Li
339*67e74705SXin Li std::error_code EC;
340*67e74705SXin Li auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
341*67e74705SXin Li ASSERT_FALSE(EC);
342*67e74705SXin Li EXPECT_EQ(vfs::recursive_directory_iterator(), I); // empty directory is empty
343*67e74705SXin Li
344*67e74705SXin Li ScopedDir _a(TestDirectory+"/a");
345*67e74705SXin Li ScopedDir _ab(TestDirectory+"/a/b");
346*67e74705SXin Li ScopedDir _c(TestDirectory+"/c");
347*67e74705SXin Li ScopedDir _cd(TestDirectory+"/c/d");
348*67e74705SXin Li
349*67e74705SXin Li I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
350*67e74705SXin Li ASSERT_FALSE(EC);
351*67e74705SXin Li ASSERT_NE(vfs::recursive_directory_iterator(), I);
352*67e74705SXin Li
353*67e74705SXin Li std::vector<std::string> Contents;
354*67e74705SXin Li for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
355*67e74705SXin Li I.increment(EC)) {
356*67e74705SXin Li Contents.push_back(I->getName());
357*67e74705SXin Li }
358*67e74705SXin Li
359*67e74705SXin Li // Check contents, which may be in any order
360*67e74705SXin Li EXPECT_EQ(4U, Contents.size());
361*67e74705SXin Li int Counts[4] = { 0, 0, 0, 0 };
362*67e74705SXin Li for (const std::string &Name : Contents) {
363*67e74705SXin Li ASSERT_FALSE(Name.empty());
364*67e74705SXin Li int Index = Name[Name.size()-1] - 'a';
365*67e74705SXin Li ASSERT_TRUE(Index >= 0 && Index < 4);
366*67e74705SXin Li Counts[Index]++;
367*67e74705SXin Li }
368*67e74705SXin Li EXPECT_EQ(1, Counts[0]); // a
369*67e74705SXin Li EXPECT_EQ(1, Counts[1]); // b
370*67e74705SXin Li EXPECT_EQ(1, Counts[2]); // c
371*67e74705SXin Li EXPECT_EQ(1, Counts[3]); // d
372*67e74705SXin Li }
373*67e74705SXin Li
374*67e74705SXin Li template <typename DirIter>
checkContents(DirIter I,ArrayRef<StringRef> ExpectedOut)375*67e74705SXin Li static void checkContents(DirIter I, ArrayRef<StringRef> ExpectedOut) {
376*67e74705SXin Li std::error_code EC;
377*67e74705SXin Li SmallVector<StringRef, 4> Expected(ExpectedOut.begin(), ExpectedOut.end());
378*67e74705SXin Li SmallVector<std::string, 4> InputToCheck;
379*67e74705SXin Li
380*67e74705SXin Li // Do not rely on iteration order to check for contents, sort both
381*67e74705SXin Li // content vectors before comparison.
382*67e74705SXin Li for (DirIter E; !EC && I != E; I.increment(EC))
383*67e74705SXin Li InputToCheck.push_back(I->getName());
384*67e74705SXin Li
385*67e74705SXin Li std::sort(InputToCheck.begin(), InputToCheck.end());
386*67e74705SXin Li std::sort(Expected.begin(), Expected.end());
387*67e74705SXin Li EXPECT_EQ(InputToCheck.size(), Expected.size());
388*67e74705SXin Li
389*67e74705SXin Li unsigned LastElt = std::min(InputToCheck.size(), Expected.size());
390*67e74705SXin Li for (unsigned Idx = 0; Idx != LastElt; ++Idx)
391*67e74705SXin Li EXPECT_EQ(StringRef(InputToCheck[Idx]), Expected[Idx]);
392*67e74705SXin Li }
393*67e74705SXin Li
TEST(VirtualFileSystemTest,OverlayIteration)394*67e74705SXin Li TEST(VirtualFileSystemTest, OverlayIteration) {
395*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
396*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
397*67e74705SXin Li IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
398*67e74705SXin Li new vfs::OverlayFileSystem(Lower));
399*67e74705SXin Li O->pushOverlay(Upper);
400*67e74705SXin Li
401*67e74705SXin Li std::error_code EC;
402*67e74705SXin Li checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
403*67e74705SXin Li
404*67e74705SXin Li Lower->addRegularFile("/file1");
405*67e74705SXin Li checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file1"));
406*67e74705SXin Li
407*67e74705SXin Li Upper->addRegularFile("/file2");
408*67e74705SXin Li checkContents(O->dir_begin("/", EC), {"/file2", "/file1"});
409*67e74705SXin Li
410*67e74705SXin Li Lower->addDirectory("/dir1");
411*67e74705SXin Li Lower->addRegularFile("/dir1/foo");
412*67e74705SXin Li Upper->addDirectory("/dir2");
413*67e74705SXin Li Upper->addRegularFile("/dir2/foo");
414*67e74705SXin Li checkContents(O->dir_begin("/dir2", EC), ArrayRef<StringRef>("/dir2/foo"));
415*67e74705SXin Li checkContents(O->dir_begin("/", EC), {"/dir2", "/file2", "/dir1", "/file1"});
416*67e74705SXin Li }
417*67e74705SXin Li
TEST(VirtualFileSystemTest,OverlayRecursiveIteration)418*67e74705SXin Li TEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
419*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
420*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
421*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
422*67e74705SXin Li IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
423*67e74705SXin Li new vfs::OverlayFileSystem(Lower));
424*67e74705SXin Li O->pushOverlay(Middle);
425*67e74705SXin Li O->pushOverlay(Upper);
426*67e74705SXin Li
427*67e74705SXin Li std::error_code EC;
428*67e74705SXin Li checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
429*67e74705SXin Li ArrayRef<StringRef>());
430*67e74705SXin Li
431*67e74705SXin Li Lower->addRegularFile("/file1");
432*67e74705SXin Li checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
433*67e74705SXin Li ArrayRef<StringRef>("/file1"));
434*67e74705SXin Li
435*67e74705SXin Li Upper->addDirectory("/dir");
436*67e74705SXin Li Upper->addRegularFile("/dir/file2");
437*67e74705SXin Li checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
438*67e74705SXin Li {"/dir", "/dir/file2", "/file1"});
439*67e74705SXin Li
440*67e74705SXin Li Lower->addDirectory("/dir1");
441*67e74705SXin Li Lower->addRegularFile("/dir1/foo");
442*67e74705SXin Li Lower->addDirectory("/dir1/a");
443*67e74705SXin Li Lower->addRegularFile("/dir1/a/b");
444*67e74705SXin Li Middle->addDirectory("/a");
445*67e74705SXin Li Middle->addDirectory("/a/b");
446*67e74705SXin Li Middle->addDirectory("/a/b/c");
447*67e74705SXin Li Middle->addRegularFile("/a/b/c/d");
448*67e74705SXin Li Middle->addRegularFile("/hiddenByUp");
449*67e74705SXin Li Upper->addDirectory("/dir2");
450*67e74705SXin Li Upper->addRegularFile("/dir2/foo");
451*67e74705SXin Li Upper->addRegularFile("/hiddenByUp");
452*67e74705SXin Li checkContents(vfs::recursive_directory_iterator(*O, "/dir2", EC),
453*67e74705SXin Li ArrayRef<StringRef>("/dir2/foo"));
454*67e74705SXin Li checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
455*67e74705SXin Li {"/dir", "/dir/file2", "/dir2", "/dir2/foo", "/hiddenByUp",
456*67e74705SXin Li "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
457*67e74705SXin Li "/dir1/a/b", "/dir1/foo", "/file1"});
458*67e74705SXin Li }
459*67e74705SXin Li
TEST(VirtualFileSystemTest,ThreeLevelIteration)460*67e74705SXin Li TEST(VirtualFileSystemTest, ThreeLevelIteration) {
461*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
462*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
463*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
464*67e74705SXin Li IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
465*67e74705SXin Li new vfs::OverlayFileSystem(Lower));
466*67e74705SXin Li O->pushOverlay(Middle);
467*67e74705SXin Li O->pushOverlay(Upper);
468*67e74705SXin Li
469*67e74705SXin Li std::error_code EC;
470*67e74705SXin Li checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
471*67e74705SXin Li
472*67e74705SXin Li Middle->addRegularFile("/file2");
473*67e74705SXin Li checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file2"));
474*67e74705SXin Li
475*67e74705SXin Li Lower->addRegularFile("/file1");
476*67e74705SXin Li Upper->addRegularFile("/file3");
477*67e74705SXin Li checkContents(O->dir_begin("/", EC), {"/file3", "/file2", "/file1"});
478*67e74705SXin Li }
479*67e74705SXin Li
TEST(VirtualFileSystemTest,HiddenInIteration)480*67e74705SXin Li TEST(VirtualFileSystemTest, HiddenInIteration) {
481*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
482*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
483*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
484*67e74705SXin Li IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
485*67e74705SXin Li new vfs::OverlayFileSystem(Lower));
486*67e74705SXin Li O->pushOverlay(Middle);
487*67e74705SXin Li O->pushOverlay(Upper);
488*67e74705SXin Li
489*67e74705SXin Li std::error_code EC;
490*67e74705SXin Li Lower->addRegularFile("/onlyInLow", sys::fs::owner_read);
491*67e74705SXin Li Lower->addRegularFile("/hiddenByMid", sys::fs::owner_read);
492*67e74705SXin Li Lower->addRegularFile("/hiddenByUp", sys::fs::owner_read);
493*67e74705SXin Li Middle->addRegularFile("/onlyInMid", sys::fs::owner_write);
494*67e74705SXin Li Middle->addRegularFile("/hiddenByMid", sys::fs::owner_write);
495*67e74705SXin Li Middle->addRegularFile("/hiddenByUp", sys::fs::owner_write);
496*67e74705SXin Li Upper->addRegularFile("/onlyInUp", sys::fs::owner_all);
497*67e74705SXin Li Upper->addRegularFile("/hiddenByUp", sys::fs::owner_all);
498*67e74705SXin Li checkContents(
499*67e74705SXin Li O->dir_begin("/", EC),
500*67e74705SXin Li {"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"});
501*67e74705SXin Li
502*67e74705SXin Li // Make sure we get the top-most entry
503*67e74705SXin Li {
504*67e74705SXin Li std::error_code EC;
505*67e74705SXin Li vfs::directory_iterator I = O->dir_begin("/", EC), E;
506*67e74705SXin Li for ( ; !EC && I != E; I.increment(EC))
507*67e74705SXin Li if (I->getName() == "/hiddenByUp")
508*67e74705SXin Li break;
509*67e74705SXin Li ASSERT_NE(E, I);
510*67e74705SXin Li EXPECT_EQ(sys::fs::owner_all, I->getPermissions());
511*67e74705SXin Li }
512*67e74705SXin Li {
513*67e74705SXin Li std::error_code EC;
514*67e74705SXin Li vfs::directory_iterator I = O->dir_begin("/", EC), E;
515*67e74705SXin Li for ( ; !EC && I != E; I.increment(EC))
516*67e74705SXin Li if (I->getName() == "/hiddenByMid")
517*67e74705SXin Li break;
518*67e74705SXin Li ASSERT_NE(E, I);
519*67e74705SXin Li EXPECT_EQ(sys::fs::owner_write, I->getPermissions());
520*67e74705SXin Li }
521*67e74705SXin Li }
522*67e74705SXin Li
523*67e74705SXin Li class InMemoryFileSystemTest : public ::testing::Test {
524*67e74705SXin Li protected:
525*67e74705SXin Li clang::vfs::InMemoryFileSystem FS;
526*67e74705SXin Li clang::vfs::InMemoryFileSystem NormalizedFS;
527*67e74705SXin Li
InMemoryFileSystemTest()528*67e74705SXin Li InMemoryFileSystemTest()
529*67e74705SXin Li : FS(/*UseNormalizedPaths=*/false),
530*67e74705SXin Li NormalizedFS(/*UseNormalizedPaths=*/true) {}
531*67e74705SXin Li };
532*67e74705SXin Li
TEST_F(InMemoryFileSystemTest,IsEmpty)533*67e74705SXin Li TEST_F(InMemoryFileSystemTest, IsEmpty) {
534*67e74705SXin Li auto Stat = FS.status("/a");
535*67e74705SXin Li ASSERT_EQ(Stat.getError(),errc::no_such_file_or_directory) << FS.toString();
536*67e74705SXin Li Stat = FS.status("/");
537*67e74705SXin Li ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
538*67e74705SXin Li }
539*67e74705SXin Li
TEST_F(InMemoryFileSystemTest,WindowsPath)540*67e74705SXin Li TEST_F(InMemoryFileSystemTest, WindowsPath) {
541*67e74705SXin Li FS.addFile("c:/windows/system128/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
542*67e74705SXin Li auto Stat = FS.status("c:");
543*67e74705SXin Li #if !defined(_WIN32)
544*67e74705SXin Li ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
545*67e74705SXin Li #endif
546*67e74705SXin Li Stat = FS.status("c:/windows/system128/foo.cpp");
547*67e74705SXin Li ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
548*67e74705SXin Li FS.addFile("d:/windows/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
549*67e74705SXin Li Stat = FS.status("d:/windows/foo.cpp");
550*67e74705SXin Li ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
551*67e74705SXin Li }
552*67e74705SXin Li
TEST_F(InMemoryFileSystemTest,OverlayFile)553*67e74705SXin Li TEST_F(InMemoryFileSystemTest, OverlayFile) {
554*67e74705SXin Li FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
555*67e74705SXin Li NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
556*67e74705SXin Li auto Stat = FS.status("/");
557*67e74705SXin Li ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
558*67e74705SXin Li Stat = FS.status("/.");
559*67e74705SXin Li ASSERT_FALSE(Stat);
560*67e74705SXin Li Stat = NormalizedFS.status("/.");
561*67e74705SXin Li ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
562*67e74705SXin Li Stat = FS.status("/a");
563*67e74705SXin Li ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
564*67e74705SXin Li ASSERT_EQ("/a", Stat->getName());
565*67e74705SXin Li }
566*67e74705SXin Li
TEST_F(InMemoryFileSystemTest,OverlayFileNoOwn)567*67e74705SXin Li TEST_F(InMemoryFileSystemTest, OverlayFileNoOwn) {
568*67e74705SXin Li auto Buf = MemoryBuffer::getMemBuffer("a");
569*67e74705SXin Li FS.addFileNoOwn("/a", 0, Buf.get());
570*67e74705SXin Li auto Stat = FS.status("/a");
571*67e74705SXin Li ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
572*67e74705SXin Li ASSERT_EQ("/a", Stat->getName());
573*67e74705SXin Li }
574*67e74705SXin Li
TEST_F(InMemoryFileSystemTest,OpenFileForRead)575*67e74705SXin Li TEST_F(InMemoryFileSystemTest, OpenFileForRead) {
576*67e74705SXin Li FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
577*67e74705SXin Li FS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
578*67e74705SXin Li FS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
579*67e74705SXin Li NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
580*67e74705SXin Li NormalizedFS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
581*67e74705SXin Li NormalizedFS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
582*67e74705SXin Li auto File = FS.openFileForRead("/a");
583*67e74705SXin Li ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
584*67e74705SXin Li File = FS.openFileForRead("/a"); // Open again.
585*67e74705SXin Li ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
586*67e74705SXin Li File = NormalizedFS.openFileForRead("/././a"); // Open again.
587*67e74705SXin Li ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
588*67e74705SXin Li File = FS.openFileForRead("/");
589*67e74705SXin Li ASSERT_EQ(File.getError(), errc::invalid_argument) << FS.toString();
590*67e74705SXin Li File = FS.openFileForRead("/b");
591*67e74705SXin Li ASSERT_EQ(File.getError(), errc::no_such_file_or_directory) << FS.toString();
592*67e74705SXin Li File = FS.openFileForRead("./c");
593*67e74705SXin Li ASSERT_FALSE(File);
594*67e74705SXin Li File = FS.openFileForRead("e/../d");
595*67e74705SXin Li ASSERT_FALSE(File);
596*67e74705SXin Li File = NormalizedFS.openFileForRead("./c");
597*67e74705SXin Li ASSERT_EQ("c", (*(*File)->getBuffer("ignored"))->getBuffer());
598*67e74705SXin Li File = NormalizedFS.openFileForRead("e/../d");
599*67e74705SXin Li ASSERT_EQ("d", (*(*File)->getBuffer("ignored"))->getBuffer());
600*67e74705SXin Li }
601*67e74705SXin Li
TEST_F(InMemoryFileSystemTest,DuplicatedFile)602*67e74705SXin Li TEST_F(InMemoryFileSystemTest, DuplicatedFile) {
603*67e74705SXin Li ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
604*67e74705SXin Li ASSERT_FALSE(FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("a")));
605*67e74705SXin Li ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
606*67e74705SXin Li ASSERT_FALSE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("b")));
607*67e74705SXin Li }
608*67e74705SXin Li
TEST_F(InMemoryFileSystemTest,DirectoryIteration)609*67e74705SXin Li TEST_F(InMemoryFileSystemTest, DirectoryIteration) {
610*67e74705SXin Li FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""));
611*67e74705SXin Li FS.addFile("/b/c", 0, MemoryBuffer::getMemBuffer(""));
612*67e74705SXin Li
613*67e74705SXin Li std::error_code EC;
614*67e74705SXin Li vfs::directory_iterator I = FS.dir_begin("/", EC);
615*67e74705SXin Li ASSERT_FALSE(EC);
616*67e74705SXin Li ASSERT_EQ("/a", I->getName());
617*67e74705SXin Li I.increment(EC);
618*67e74705SXin Li ASSERT_FALSE(EC);
619*67e74705SXin Li ASSERT_EQ("/b", I->getName());
620*67e74705SXin Li I.increment(EC);
621*67e74705SXin Li ASSERT_FALSE(EC);
622*67e74705SXin Li ASSERT_EQ(vfs::directory_iterator(), I);
623*67e74705SXin Li
624*67e74705SXin Li I = FS.dir_begin("/b", EC);
625*67e74705SXin Li ASSERT_FALSE(EC);
626*67e74705SXin Li ASSERT_EQ("/b/c", I->getName());
627*67e74705SXin Li I.increment(EC);
628*67e74705SXin Li ASSERT_FALSE(EC);
629*67e74705SXin Li ASSERT_EQ(vfs::directory_iterator(), I);
630*67e74705SXin Li }
631*67e74705SXin Li
TEST_F(InMemoryFileSystemTest,WorkingDirectory)632*67e74705SXin Li TEST_F(InMemoryFileSystemTest, WorkingDirectory) {
633*67e74705SXin Li FS.setCurrentWorkingDirectory("/b");
634*67e74705SXin Li FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
635*67e74705SXin Li
636*67e74705SXin Li auto Stat = FS.status("/b/c");
637*67e74705SXin Li ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
638*67e74705SXin Li ASSERT_EQ("c", Stat->getName());
639*67e74705SXin Li ASSERT_EQ("/b", *FS.getCurrentWorkingDirectory());
640*67e74705SXin Li
641*67e74705SXin Li Stat = FS.status("c");
642*67e74705SXin Li ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
643*67e74705SXin Li
644*67e74705SXin Li auto ReplaceBackslashes = [](std::string S) {
645*67e74705SXin Li std::replace(S.begin(), S.end(), '\\', '/');
646*67e74705SXin Li return S;
647*67e74705SXin Li };
648*67e74705SXin Li NormalizedFS.setCurrentWorkingDirectory("/b/c");
649*67e74705SXin Li NormalizedFS.setCurrentWorkingDirectory(".");
650*67e74705SXin Li ASSERT_EQ("/b/c", ReplaceBackslashes(
651*67e74705SXin Li NormalizedFS.getCurrentWorkingDirectory().get()));
652*67e74705SXin Li NormalizedFS.setCurrentWorkingDirectory("..");
653*67e74705SXin Li ASSERT_EQ("/b", ReplaceBackslashes(
654*67e74705SXin Li NormalizedFS.getCurrentWorkingDirectory().get()));
655*67e74705SXin Li }
656*67e74705SXin Li
657*67e74705SXin Li // NOTE: in the tests below, we use '//root/' as our root directory, since it is
658*67e74705SXin Li // a legal *absolute* path on Windows as well as *nix.
659*67e74705SXin Li class VFSFromYAMLTest : public ::testing::Test {
660*67e74705SXin Li public:
661*67e74705SXin Li int NumDiagnostics;
662*67e74705SXin Li
SetUp()663*67e74705SXin Li void SetUp() override { NumDiagnostics = 0; }
664*67e74705SXin Li
CountingDiagHandler(const SMDiagnostic &,void * Context)665*67e74705SXin Li static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
666*67e74705SXin Li VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
667*67e74705SXin Li ++Test->NumDiagnostics;
668*67e74705SXin Li }
669*67e74705SXin Li
670*67e74705SXin Li IntrusiveRefCntPtr<vfs::FileSystem>
getFromYAMLRawString(StringRef Content,IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS)671*67e74705SXin Li getFromYAMLRawString(StringRef Content,
672*67e74705SXin Li IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
673*67e74705SXin Li std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content);
674*67e74705SXin Li return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, "", this,
675*67e74705SXin Li ExternalFS);
676*67e74705SXin Li }
677*67e74705SXin Li
getFromYAMLString(StringRef Content,IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS=new DummyFileSystem ())678*67e74705SXin Li IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
679*67e74705SXin Li StringRef Content,
680*67e74705SXin Li IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
681*67e74705SXin Li std::string VersionPlusContent("{\n 'version':0,\n");
682*67e74705SXin Li VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
683*67e74705SXin Li return getFromYAMLRawString(VersionPlusContent, ExternalFS);
684*67e74705SXin Li }
685*67e74705SXin Li
686*67e74705SXin Li // This is intended as a "XFAIL" for windows hosts.
supportsSameDirMultipleYAMLEntries()687*67e74705SXin Li bool supportsSameDirMultipleYAMLEntries() {
688*67e74705SXin Li Triple Host(Triple::normalize(sys::getProcessTriple()));
689*67e74705SXin Li return !Host.isOSWindows();
690*67e74705SXin Li }
691*67e74705SXin Li };
692*67e74705SXin Li
TEST_F(VFSFromYAMLTest,BasicVFSFromYAML)693*67e74705SXin Li TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
694*67e74705SXin Li IntrusiveRefCntPtr<vfs::FileSystem> FS;
695*67e74705SXin Li FS = getFromYAMLString("");
696*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
697*67e74705SXin Li FS = getFromYAMLString("[]");
698*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
699*67e74705SXin Li FS = getFromYAMLString("'string'");
700*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
701*67e74705SXin Li EXPECT_EQ(3, NumDiagnostics);
702*67e74705SXin Li }
703*67e74705SXin Li
TEST_F(VFSFromYAMLTest,MappedFiles)704*67e74705SXin Li TEST_F(VFSFromYAMLTest, MappedFiles) {
705*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
706*67e74705SXin Li Lower->addRegularFile("//root/foo/bar/a");
707*67e74705SXin Li IntrusiveRefCntPtr<vfs::FileSystem> FS =
708*67e74705SXin Li getFromYAMLString("{ 'roots': [\n"
709*67e74705SXin Li "{\n"
710*67e74705SXin Li " 'type': 'directory',\n"
711*67e74705SXin Li " 'name': '//root/',\n"
712*67e74705SXin Li " 'contents': [ {\n"
713*67e74705SXin Li " 'type': 'file',\n"
714*67e74705SXin Li " 'name': 'file1',\n"
715*67e74705SXin Li " 'external-contents': '//root/foo/bar/a'\n"
716*67e74705SXin Li " },\n"
717*67e74705SXin Li " {\n"
718*67e74705SXin Li " 'type': 'file',\n"
719*67e74705SXin Li " 'name': 'file2',\n"
720*67e74705SXin Li " 'external-contents': '//root/foo/b'\n"
721*67e74705SXin Li " }\n"
722*67e74705SXin Li " ]\n"
723*67e74705SXin Li "}\n"
724*67e74705SXin Li "]\n"
725*67e74705SXin Li "}",
726*67e74705SXin Li Lower);
727*67e74705SXin Li ASSERT_TRUE(FS.get() != nullptr);
728*67e74705SXin Li
729*67e74705SXin Li IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
730*67e74705SXin Li new vfs::OverlayFileSystem(Lower));
731*67e74705SXin Li O->pushOverlay(FS);
732*67e74705SXin Li
733*67e74705SXin Li // file
734*67e74705SXin Li ErrorOr<vfs::Status> S = O->status("//root/file1");
735*67e74705SXin Li ASSERT_FALSE(S.getError());
736*67e74705SXin Li EXPECT_EQ("//root/foo/bar/a", S->getName());
737*67e74705SXin Li EXPECT_TRUE(S->IsVFSMapped);
738*67e74705SXin Li
739*67e74705SXin Li ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
740*67e74705SXin Li EXPECT_EQ("//root/foo/bar/a", SLower->getName());
741*67e74705SXin Li EXPECT_TRUE(S->equivalent(*SLower));
742*67e74705SXin Li EXPECT_FALSE(SLower->IsVFSMapped);
743*67e74705SXin Li
744*67e74705SXin Li // file after opening
745*67e74705SXin Li auto OpenedF = O->openFileForRead("//root/file1");
746*67e74705SXin Li ASSERT_FALSE(OpenedF.getError());
747*67e74705SXin Li auto OpenedS = (*OpenedF)->status();
748*67e74705SXin Li ASSERT_FALSE(OpenedS.getError());
749*67e74705SXin Li EXPECT_EQ("//root/foo/bar/a", OpenedS->getName());
750*67e74705SXin Li EXPECT_TRUE(OpenedS->IsVFSMapped);
751*67e74705SXin Li
752*67e74705SXin Li // directory
753*67e74705SXin Li S = O->status("//root/");
754*67e74705SXin Li ASSERT_FALSE(S.getError());
755*67e74705SXin Li EXPECT_TRUE(S->isDirectory());
756*67e74705SXin Li EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
757*67e74705SXin Li
758*67e74705SXin Li // broken mapping
759*67e74705SXin Li EXPECT_EQ(O->status("//root/file2").getError(),
760*67e74705SXin Li llvm::errc::no_such_file_or_directory);
761*67e74705SXin Li EXPECT_EQ(0, NumDiagnostics);
762*67e74705SXin Li }
763*67e74705SXin Li
TEST_F(VFSFromYAMLTest,CaseInsensitive)764*67e74705SXin Li TEST_F(VFSFromYAMLTest, CaseInsensitive) {
765*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
766*67e74705SXin Li Lower->addRegularFile("//root/foo/bar/a");
767*67e74705SXin Li IntrusiveRefCntPtr<vfs::FileSystem> FS =
768*67e74705SXin Li getFromYAMLString("{ 'case-sensitive': 'false',\n"
769*67e74705SXin Li " 'roots': [\n"
770*67e74705SXin Li "{\n"
771*67e74705SXin Li " 'type': 'directory',\n"
772*67e74705SXin Li " 'name': '//root/',\n"
773*67e74705SXin Li " 'contents': [ {\n"
774*67e74705SXin Li " 'type': 'file',\n"
775*67e74705SXin Li " 'name': 'XX',\n"
776*67e74705SXin Li " 'external-contents': '//root/foo/bar/a'\n"
777*67e74705SXin Li " }\n"
778*67e74705SXin Li " ]\n"
779*67e74705SXin Li "}]}",
780*67e74705SXin Li Lower);
781*67e74705SXin Li ASSERT_TRUE(FS.get() != nullptr);
782*67e74705SXin Li
783*67e74705SXin Li IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
784*67e74705SXin Li new vfs::OverlayFileSystem(Lower));
785*67e74705SXin Li O->pushOverlay(FS);
786*67e74705SXin Li
787*67e74705SXin Li ErrorOr<vfs::Status> S = O->status("//root/XX");
788*67e74705SXin Li ASSERT_FALSE(S.getError());
789*67e74705SXin Li
790*67e74705SXin Li ErrorOr<vfs::Status> SS = O->status("//root/xx");
791*67e74705SXin Li ASSERT_FALSE(SS.getError());
792*67e74705SXin Li EXPECT_TRUE(S->equivalent(*SS));
793*67e74705SXin Li SS = O->status("//root/xX");
794*67e74705SXin Li EXPECT_TRUE(S->equivalent(*SS));
795*67e74705SXin Li SS = O->status("//root/Xx");
796*67e74705SXin Li EXPECT_TRUE(S->equivalent(*SS));
797*67e74705SXin Li EXPECT_EQ(0, NumDiagnostics);
798*67e74705SXin Li }
799*67e74705SXin Li
TEST_F(VFSFromYAMLTest,CaseSensitive)800*67e74705SXin Li TEST_F(VFSFromYAMLTest, CaseSensitive) {
801*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
802*67e74705SXin Li Lower->addRegularFile("//root/foo/bar/a");
803*67e74705SXin Li IntrusiveRefCntPtr<vfs::FileSystem> FS =
804*67e74705SXin Li getFromYAMLString("{ 'case-sensitive': 'true',\n"
805*67e74705SXin Li " 'roots': [\n"
806*67e74705SXin Li "{\n"
807*67e74705SXin Li " 'type': 'directory',\n"
808*67e74705SXin Li " 'name': '//root/',\n"
809*67e74705SXin Li " 'contents': [ {\n"
810*67e74705SXin Li " 'type': 'file',\n"
811*67e74705SXin Li " 'name': 'XX',\n"
812*67e74705SXin Li " 'external-contents': '//root/foo/bar/a'\n"
813*67e74705SXin Li " }\n"
814*67e74705SXin Li " ]\n"
815*67e74705SXin Li "}]}",
816*67e74705SXin Li Lower);
817*67e74705SXin Li ASSERT_TRUE(FS.get() != nullptr);
818*67e74705SXin Li
819*67e74705SXin Li IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
820*67e74705SXin Li new vfs::OverlayFileSystem(Lower));
821*67e74705SXin Li O->pushOverlay(FS);
822*67e74705SXin Li
823*67e74705SXin Li ErrorOr<vfs::Status> SS = O->status("//root/xx");
824*67e74705SXin Li EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
825*67e74705SXin Li SS = O->status("//root/xX");
826*67e74705SXin Li EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
827*67e74705SXin Li SS = O->status("//root/Xx");
828*67e74705SXin Li EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
829*67e74705SXin Li EXPECT_EQ(0, NumDiagnostics);
830*67e74705SXin Li }
831*67e74705SXin Li
TEST_F(VFSFromYAMLTest,IllegalVFSFile)832*67e74705SXin Li TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
833*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
834*67e74705SXin Li
835*67e74705SXin Li // invalid YAML at top-level
836*67e74705SXin Li IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
837*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
838*67e74705SXin Li // invalid YAML in roots
839*67e74705SXin Li FS = getFromYAMLString("{ 'roots':[}", Lower);
840*67e74705SXin Li // invalid YAML in directory
841*67e74705SXin Li FS = getFromYAMLString(
842*67e74705SXin Li "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
843*67e74705SXin Li Lower);
844*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
845*67e74705SXin Li
846*67e74705SXin Li // invalid configuration
847*67e74705SXin Li FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
848*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
849*67e74705SXin Li FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
850*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
851*67e74705SXin Li
852*67e74705SXin Li // invalid roots
853*67e74705SXin Li FS = getFromYAMLString("{ 'roots':'' }", Lower);
854*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
855*67e74705SXin Li FS = getFromYAMLString("{ 'roots':{} }", Lower);
856*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
857*67e74705SXin Li
858*67e74705SXin Li // invalid entries
859*67e74705SXin Li FS = getFromYAMLString(
860*67e74705SXin Li "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
861*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
862*67e74705SXin Li FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
863*67e74705SXin Li "'external-contents': 'other' }",
864*67e74705SXin Li Lower);
865*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
866*67e74705SXin Li FS = getFromYAMLString(
867*67e74705SXin Li "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
868*67e74705SXin Li Lower);
869*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
870*67e74705SXin Li FS = getFromYAMLString(
871*67e74705SXin Li "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
872*67e74705SXin Li Lower);
873*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
874*67e74705SXin Li FS = getFromYAMLString(
875*67e74705SXin Li "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
876*67e74705SXin Li Lower);
877*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
878*67e74705SXin Li FS = getFromYAMLString(
879*67e74705SXin Li "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
880*67e74705SXin Li Lower);
881*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
882*67e74705SXin Li FS = getFromYAMLString(
883*67e74705SXin Li "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
884*67e74705SXin Li Lower);
885*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
886*67e74705SXin Li
887*67e74705SXin Li // missing mandatory fields
888*67e74705SXin Li FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
889*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
890*67e74705SXin Li FS = getFromYAMLString(
891*67e74705SXin Li "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
892*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
893*67e74705SXin Li FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
894*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
895*67e74705SXin Li
896*67e74705SXin Li // duplicate keys
897*67e74705SXin Li FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
898*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
899*67e74705SXin Li FS = getFromYAMLString(
900*67e74705SXin Li "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
901*67e74705SXin Li Lower);
902*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
903*67e74705SXin Li FS =
904*67e74705SXin Li getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
905*67e74705SXin Li "'external-contents':'blah' } ] }",
906*67e74705SXin Li Lower);
907*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
908*67e74705SXin Li
909*67e74705SXin Li // missing version
910*67e74705SXin Li FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
911*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
912*67e74705SXin Li
913*67e74705SXin Li // bad version number
914*67e74705SXin Li FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
915*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
916*67e74705SXin Li FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
917*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
918*67e74705SXin Li FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
919*67e74705SXin Li EXPECT_EQ(nullptr, FS.get());
920*67e74705SXin Li EXPECT_EQ(24, NumDiagnostics);
921*67e74705SXin Li }
922*67e74705SXin Li
TEST_F(VFSFromYAMLTest,UseExternalName)923*67e74705SXin Li TEST_F(VFSFromYAMLTest, UseExternalName) {
924*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
925*67e74705SXin Li Lower->addRegularFile("//root/external/file");
926*67e74705SXin Li
927*67e74705SXin Li IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
928*67e74705SXin Li "{ 'roots': [\n"
929*67e74705SXin Li " { 'type': 'file', 'name': '//root/A',\n"
930*67e74705SXin Li " 'external-contents': '//root/external/file'\n"
931*67e74705SXin Li " },\n"
932*67e74705SXin Li " { 'type': 'file', 'name': '//root/B',\n"
933*67e74705SXin Li " 'use-external-name': true,\n"
934*67e74705SXin Li " 'external-contents': '//root/external/file'\n"
935*67e74705SXin Li " },\n"
936*67e74705SXin Li " { 'type': 'file', 'name': '//root/C',\n"
937*67e74705SXin Li " 'use-external-name': false,\n"
938*67e74705SXin Li " 'external-contents': '//root/external/file'\n"
939*67e74705SXin Li " }\n"
940*67e74705SXin Li "] }", Lower);
941*67e74705SXin Li ASSERT_TRUE(nullptr != FS.get());
942*67e74705SXin Li
943*67e74705SXin Li // default true
944*67e74705SXin Li EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
945*67e74705SXin Li // explicit
946*67e74705SXin Li EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
947*67e74705SXin Li EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
948*67e74705SXin Li
949*67e74705SXin Li // global configuration
950*67e74705SXin Li FS = getFromYAMLString(
951*67e74705SXin Li "{ 'use-external-names': false,\n"
952*67e74705SXin Li " 'roots': [\n"
953*67e74705SXin Li " { 'type': 'file', 'name': '//root/A',\n"
954*67e74705SXin Li " 'external-contents': '//root/external/file'\n"
955*67e74705SXin Li " },\n"
956*67e74705SXin Li " { 'type': 'file', 'name': '//root/B',\n"
957*67e74705SXin Li " 'use-external-name': true,\n"
958*67e74705SXin Li " 'external-contents': '//root/external/file'\n"
959*67e74705SXin Li " },\n"
960*67e74705SXin Li " { 'type': 'file', 'name': '//root/C',\n"
961*67e74705SXin Li " 'use-external-name': false,\n"
962*67e74705SXin Li " 'external-contents': '//root/external/file'\n"
963*67e74705SXin Li " }\n"
964*67e74705SXin Li "] }", Lower);
965*67e74705SXin Li ASSERT_TRUE(nullptr != FS.get());
966*67e74705SXin Li
967*67e74705SXin Li // default
968*67e74705SXin Li EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
969*67e74705SXin Li // explicit
970*67e74705SXin Li EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
971*67e74705SXin Li EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
972*67e74705SXin Li }
973*67e74705SXin Li
TEST_F(VFSFromYAMLTest,MultiComponentPath)974*67e74705SXin Li TEST_F(VFSFromYAMLTest, MultiComponentPath) {
975*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
976*67e74705SXin Li Lower->addRegularFile("//root/other");
977*67e74705SXin Li
978*67e74705SXin Li // file in roots
979*67e74705SXin Li IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
980*67e74705SXin Li "{ 'roots': [\n"
981*67e74705SXin Li " { 'type': 'file', 'name': '//root/path/to/file',\n"
982*67e74705SXin Li " 'external-contents': '//root/other' }]\n"
983*67e74705SXin Li "}", Lower);
984*67e74705SXin Li ASSERT_TRUE(nullptr != FS.get());
985*67e74705SXin Li EXPECT_FALSE(FS->status("//root/path/to/file").getError());
986*67e74705SXin Li EXPECT_FALSE(FS->status("//root/path/to").getError());
987*67e74705SXin Li EXPECT_FALSE(FS->status("//root/path").getError());
988*67e74705SXin Li EXPECT_FALSE(FS->status("//root/").getError());
989*67e74705SXin Li
990*67e74705SXin Li // at the start
991*67e74705SXin Li FS = getFromYAMLString(
992*67e74705SXin Li "{ 'roots': [\n"
993*67e74705SXin Li " { 'type': 'directory', 'name': '//root/path/to',\n"
994*67e74705SXin Li " 'contents': [ { 'type': 'file', 'name': 'file',\n"
995*67e74705SXin Li " 'external-contents': '//root/other' }]}]\n"
996*67e74705SXin Li "}", Lower);
997*67e74705SXin Li ASSERT_TRUE(nullptr != FS.get());
998*67e74705SXin Li EXPECT_FALSE(FS->status("//root/path/to/file").getError());
999*67e74705SXin Li EXPECT_FALSE(FS->status("//root/path/to").getError());
1000*67e74705SXin Li EXPECT_FALSE(FS->status("//root/path").getError());
1001*67e74705SXin Li EXPECT_FALSE(FS->status("//root/").getError());
1002*67e74705SXin Li
1003*67e74705SXin Li // at the end
1004*67e74705SXin Li FS = getFromYAMLString(
1005*67e74705SXin Li "{ 'roots': [\n"
1006*67e74705SXin Li " { 'type': 'directory', 'name': '//root/',\n"
1007*67e74705SXin Li " 'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
1008*67e74705SXin Li " 'external-contents': '//root/other' }]}]\n"
1009*67e74705SXin Li "}", Lower);
1010*67e74705SXin Li ASSERT_TRUE(nullptr != FS.get());
1011*67e74705SXin Li EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1012*67e74705SXin Li EXPECT_FALSE(FS->status("//root/path/to").getError());
1013*67e74705SXin Li EXPECT_FALSE(FS->status("//root/path").getError());
1014*67e74705SXin Li EXPECT_FALSE(FS->status("//root/").getError());
1015*67e74705SXin Li }
1016*67e74705SXin Li
TEST_F(VFSFromYAMLTest,TrailingSlashes)1017*67e74705SXin Li TEST_F(VFSFromYAMLTest, TrailingSlashes) {
1018*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1019*67e74705SXin Li Lower->addRegularFile("//root/other");
1020*67e74705SXin Li
1021*67e74705SXin Li // file in roots
1022*67e74705SXin Li IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1023*67e74705SXin Li "{ 'roots': [\n"
1024*67e74705SXin Li " { 'type': 'directory', 'name': '//root/path/to////',\n"
1025*67e74705SXin Li " 'contents': [ { 'type': 'file', 'name': 'file',\n"
1026*67e74705SXin Li " 'external-contents': '//root/other' }]}]\n"
1027*67e74705SXin Li "}", Lower);
1028*67e74705SXin Li ASSERT_TRUE(nullptr != FS.get());
1029*67e74705SXin Li EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1030*67e74705SXin Li EXPECT_FALSE(FS->status("//root/path/to").getError());
1031*67e74705SXin Li EXPECT_FALSE(FS->status("//root/path").getError());
1032*67e74705SXin Li EXPECT_FALSE(FS->status("//root/").getError());
1033*67e74705SXin Li }
1034*67e74705SXin Li
TEST_F(VFSFromYAMLTest,DirectoryIteration)1035*67e74705SXin Li TEST_F(VFSFromYAMLTest, DirectoryIteration) {
1036*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1037*67e74705SXin Li Lower->addDirectory("//root/");
1038*67e74705SXin Li Lower->addDirectory("//root/foo");
1039*67e74705SXin Li Lower->addDirectory("//root/foo/bar");
1040*67e74705SXin Li Lower->addRegularFile("//root/foo/bar/a");
1041*67e74705SXin Li Lower->addRegularFile("//root/foo/bar/b");
1042*67e74705SXin Li Lower->addRegularFile("//root/file3");
1043*67e74705SXin Li IntrusiveRefCntPtr<vfs::FileSystem> FS =
1044*67e74705SXin Li getFromYAMLString("{ 'use-external-names': false,\n"
1045*67e74705SXin Li " 'roots': [\n"
1046*67e74705SXin Li "{\n"
1047*67e74705SXin Li " 'type': 'directory',\n"
1048*67e74705SXin Li " 'name': '//root/',\n"
1049*67e74705SXin Li " 'contents': [ {\n"
1050*67e74705SXin Li " 'type': 'file',\n"
1051*67e74705SXin Li " 'name': 'file1',\n"
1052*67e74705SXin Li " 'external-contents': '//root/foo/bar/a'\n"
1053*67e74705SXin Li " },\n"
1054*67e74705SXin Li " {\n"
1055*67e74705SXin Li " 'type': 'file',\n"
1056*67e74705SXin Li " 'name': 'file2',\n"
1057*67e74705SXin Li " 'external-contents': '//root/foo/bar/b'\n"
1058*67e74705SXin Li " }\n"
1059*67e74705SXin Li " ]\n"
1060*67e74705SXin Li "}\n"
1061*67e74705SXin Li "]\n"
1062*67e74705SXin Li "}",
1063*67e74705SXin Li Lower);
1064*67e74705SXin Li ASSERT_TRUE(FS.get() != nullptr);
1065*67e74705SXin Li
1066*67e74705SXin Li IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1067*67e74705SXin Li new vfs::OverlayFileSystem(Lower));
1068*67e74705SXin Li O->pushOverlay(FS);
1069*67e74705SXin Li
1070*67e74705SXin Li std::error_code EC;
1071*67e74705SXin Li checkContents(O->dir_begin("//root/", EC),
1072*67e74705SXin Li {"//root/file1", "//root/file2", "//root/file3", "//root/foo"});
1073*67e74705SXin Li
1074*67e74705SXin Li checkContents(O->dir_begin("//root/foo/bar", EC),
1075*67e74705SXin Li {"//root/foo/bar/a", "//root/foo/bar/b"});
1076*67e74705SXin Li }
1077*67e74705SXin Li
TEST_F(VFSFromYAMLTest,DirectoryIterationSameDirMultipleEntries)1078*67e74705SXin Li TEST_F(VFSFromYAMLTest, DirectoryIterationSameDirMultipleEntries) {
1079*67e74705SXin Li // https://llvm.org/bugs/show_bug.cgi?id=27725
1080*67e74705SXin Li if (!supportsSameDirMultipleYAMLEntries())
1081*67e74705SXin Li return;
1082*67e74705SXin Li
1083*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1084*67e74705SXin Li Lower->addDirectory("//root/zab");
1085*67e74705SXin Li Lower->addDirectory("//root/baz");
1086*67e74705SXin Li Lower->addRegularFile("//root/zab/a");
1087*67e74705SXin Li Lower->addRegularFile("//root/zab/b");
1088*67e74705SXin Li IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1089*67e74705SXin Li "{ 'use-external-names': false,\n"
1090*67e74705SXin Li " 'roots': [\n"
1091*67e74705SXin Li "{\n"
1092*67e74705SXin Li " 'type': 'directory',\n"
1093*67e74705SXin Li " 'name': '//root/baz/',\n"
1094*67e74705SXin Li " 'contents': [ {\n"
1095*67e74705SXin Li " 'type': 'file',\n"
1096*67e74705SXin Li " 'name': 'x',\n"
1097*67e74705SXin Li " 'external-contents': '//root/zab/a'\n"
1098*67e74705SXin Li " }\n"
1099*67e74705SXin Li " ]\n"
1100*67e74705SXin Li "},\n"
1101*67e74705SXin Li "{\n"
1102*67e74705SXin Li " 'type': 'directory',\n"
1103*67e74705SXin Li " 'name': '//root/baz/',\n"
1104*67e74705SXin Li " 'contents': [ {\n"
1105*67e74705SXin Li " 'type': 'file',\n"
1106*67e74705SXin Li " 'name': 'y',\n"
1107*67e74705SXin Li " 'external-contents': '//root/zab/b'\n"
1108*67e74705SXin Li " }\n"
1109*67e74705SXin Li " ]\n"
1110*67e74705SXin Li "}\n"
1111*67e74705SXin Li "]\n"
1112*67e74705SXin Li "}",
1113*67e74705SXin Li Lower);
1114*67e74705SXin Li ASSERT_TRUE(FS.get() != nullptr);
1115*67e74705SXin Li
1116*67e74705SXin Li IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1117*67e74705SXin Li new vfs::OverlayFileSystem(Lower));
1118*67e74705SXin Li O->pushOverlay(FS);
1119*67e74705SXin Li
1120*67e74705SXin Li std::error_code EC;
1121*67e74705SXin Li
1122*67e74705SXin Li checkContents(O->dir_begin("//root/baz/", EC),
1123*67e74705SXin Li {"//root/baz/x", "//root/baz/y"});
1124*67e74705SXin Li }
1125*67e74705SXin Li
TEST_F(VFSFromYAMLTest,RecursiveDirectoryIterationLevel)1126*67e74705SXin Li TEST_F(VFSFromYAMLTest, RecursiveDirectoryIterationLevel) {
1127*67e74705SXin Li
1128*67e74705SXin Li IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1129*67e74705SXin Li Lower->addDirectory("//root/a");
1130*67e74705SXin Li Lower->addDirectory("//root/a/b");
1131*67e74705SXin Li Lower->addDirectory("//root/a/b/c");
1132*67e74705SXin Li Lower->addRegularFile("//root/a/b/c/file");
1133*67e74705SXin Li IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1134*67e74705SXin Li "{ 'use-external-names': false,\n"
1135*67e74705SXin Li " 'roots': [\n"
1136*67e74705SXin Li "{\n"
1137*67e74705SXin Li " 'type': 'directory',\n"
1138*67e74705SXin Li " 'name': '//root/a/b/c/',\n"
1139*67e74705SXin Li " 'contents': [ {\n"
1140*67e74705SXin Li " 'type': 'file',\n"
1141*67e74705SXin Li " 'name': 'file',\n"
1142*67e74705SXin Li " 'external-contents': '//root/a/b/c/file'\n"
1143*67e74705SXin Li " }\n"
1144*67e74705SXin Li " ]\n"
1145*67e74705SXin Li "},\n"
1146*67e74705SXin Li "]\n"
1147*67e74705SXin Li "}",
1148*67e74705SXin Li Lower);
1149*67e74705SXin Li ASSERT_TRUE(FS.get() != nullptr);
1150*67e74705SXin Li
1151*67e74705SXin Li IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1152*67e74705SXin Li new vfs::OverlayFileSystem(Lower));
1153*67e74705SXin Li O->pushOverlay(FS);
1154*67e74705SXin Li
1155*67e74705SXin Li std::error_code EC;
1156*67e74705SXin Li
1157*67e74705SXin Li // Test recursive_directory_iterator level()
1158*67e74705SXin Li vfs::recursive_directory_iterator I = vfs::recursive_directory_iterator(
1159*67e74705SXin Li *O, "//root", EC), E;
1160*67e74705SXin Li ASSERT_FALSE(EC);
1161*67e74705SXin Li for (int l = 0; I != E; I.increment(EC), ++l) {
1162*67e74705SXin Li ASSERT_FALSE(EC);
1163*67e74705SXin Li EXPECT_EQ(I.level(), l);
1164*67e74705SXin Li }
1165*67e74705SXin Li EXPECT_EQ(I, E);
1166*67e74705SXin Li }
1167