xref: /minix3/external/bsd/llvm/dist/clang/unittests/Basic/VirtualFileSystemTest.cpp (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc //===- unittests/Basic/VirtualFileSystem.cpp ---------------- VFS tests ---===//
2*0a6a1f1dSLionel Sambuc //
3*0a6a1f1dSLionel Sambuc //                     The LLVM Compiler Infrastructure
4*0a6a1f1dSLionel Sambuc //
5*0a6a1f1dSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6*0a6a1f1dSLionel Sambuc // License. See LICENSE.TXT for details.
7*0a6a1f1dSLionel Sambuc //
8*0a6a1f1dSLionel Sambuc //===----------------------------------------------------------------------===//
9*0a6a1f1dSLionel Sambuc 
10*0a6a1f1dSLionel Sambuc #include "clang/Basic/VirtualFileSystem.h"
11*0a6a1f1dSLionel Sambuc #include "llvm/Support/Errc.h"
12*0a6a1f1dSLionel Sambuc #include "llvm/Support/MemoryBuffer.h"
13*0a6a1f1dSLionel Sambuc #include "llvm/Support/Path.h"
14*0a6a1f1dSLionel Sambuc #include "llvm/Support/SourceMgr.h"
15*0a6a1f1dSLionel Sambuc #include "gtest/gtest.h"
16*0a6a1f1dSLionel Sambuc #include <map>
17*0a6a1f1dSLionel Sambuc using namespace clang;
18*0a6a1f1dSLionel Sambuc using namespace llvm;
19*0a6a1f1dSLionel Sambuc using llvm::sys::fs::UniqueID;
20*0a6a1f1dSLionel Sambuc 
21*0a6a1f1dSLionel Sambuc namespace {
22*0a6a1f1dSLionel Sambuc class DummyFileSystem : public vfs::FileSystem {
23*0a6a1f1dSLionel Sambuc   int FSID;   // used to produce UniqueIDs
24*0a6a1f1dSLionel Sambuc   int FileID; // used to produce UniqueIDs
25*0a6a1f1dSLionel Sambuc   std::map<std::string, vfs::Status> FilesAndDirs;
26*0a6a1f1dSLionel Sambuc 
getNextFSID()27*0a6a1f1dSLionel Sambuc   static int getNextFSID() {
28*0a6a1f1dSLionel Sambuc     static int Count = 0;
29*0a6a1f1dSLionel Sambuc     return Count++;
30*0a6a1f1dSLionel Sambuc   }
31*0a6a1f1dSLionel Sambuc 
32*0a6a1f1dSLionel Sambuc public:
DummyFileSystem()33*0a6a1f1dSLionel Sambuc   DummyFileSystem() : FSID(getNextFSID()), FileID(0) {}
34*0a6a1f1dSLionel Sambuc 
status(const Twine & Path)35*0a6a1f1dSLionel Sambuc   ErrorOr<vfs::Status> status(const Twine &Path) override {
36*0a6a1f1dSLionel Sambuc     std::map<std::string, vfs::Status>::iterator I =
37*0a6a1f1dSLionel Sambuc         FilesAndDirs.find(Path.str());
38*0a6a1f1dSLionel Sambuc     if (I == FilesAndDirs.end())
39*0a6a1f1dSLionel Sambuc       return make_error_code(llvm::errc::no_such_file_or_directory);
40*0a6a1f1dSLionel Sambuc     return I->second;
41*0a6a1f1dSLionel Sambuc   }
42*0a6a1f1dSLionel Sambuc   ErrorOr<std::unique_ptr<vfs::File>>
openFileForRead(const Twine & Path)43*0a6a1f1dSLionel Sambuc   openFileForRead(const Twine &Path) override {
44*0a6a1f1dSLionel Sambuc     llvm_unreachable("unimplemented");
45*0a6a1f1dSLionel Sambuc   }
46*0a6a1f1dSLionel Sambuc 
47*0a6a1f1dSLionel Sambuc   struct DirIterImpl : public clang::vfs::detail::DirIterImpl {
48*0a6a1f1dSLionel Sambuc     std::map<std::string, vfs::Status> &FilesAndDirs;
49*0a6a1f1dSLionel Sambuc     std::map<std::string, vfs::Status>::iterator I;
50*0a6a1f1dSLionel Sambuc     std::string Path;
isInPath__anon3b3f4fa60111::DummyFileSystem::DirIterImpl51*0a6a1f1dSLionel Sambuc     bool isInPath(StringRef S) {
52*0a6a1f1dSLionel Sambuc       if (Path.size() < S.size() && S.find(Path) == 0) {
53*0a6a1f1dSLionel Sambuc         auto LastSep = S.find_last_of('/');
54*0a6a1f1dSLionel Sambuc         if (LastSep == Path.size() || LastSep == Path.size()-1)
55*0a6a1f1dSLionel Sambuc           return true;
56*0a6a1f1dSLionel Sambuc       }
57*0a6a1f1dSLionel Sambuc       return false;
58*0a6a1f1dSLionel Sambuc     }
DirIterImpl__anon3b3f4fa60111::DummyFileSystem::DirIterImpl59*0a6a1f1dSLionel Sambuc     DirIterImpl(std::map<std::string, vfs::Status> &FilesAndDirs,
60*0a6a1f1dSLionel Sambuc                 const Twine &_Path)
61*0a6a1f1dSLionel Sambuc         : FilesAndDirs(FilesAndDirs), I(FilesAndDirs.begin()),
62*0a6a1f1dSLionel Sambuc           Path(_Path.str()) {
63*0a6a1f1dSLionel Sambuc       for ( ; I != FilesAndDirs.end(); ++I) {
64*0a6a1f1dSLionel Sambuc         if (isInPath(I->first)) {
65*0a6a1f1dSLionel Sambuc           CurrentEntry = I->second;
66*0a6a1f1dSLionel Sambuc           break;
67*0a6a1f1dSLionel Sambuc         }
68*0a6a1f1dSLionel Sambuc       }
69*0a6a1f1dSLionel Sambuc     }
increment__anon3b3f4fa60111::DummyFileSystem::DirIterImpl70*0a6a1f1dSLionel Sambuc     std::error_code increment() override {
71*0a6a1f1dSLionel Sambuc       ++I;
72*0a6a1f1dSLionel Sambuc       for ( ; I != FilesAndDirs.end(); ++I) {
73*0a6a1f1dSLionel Sambuc         if (isInPath(I->first)) {
74*0a6a1f1dSLionel Sambuc           CurrentEntry = I->second;
75*0a6a1f1dSLionel Sambuc           break;
76*0a6a1f1dSLionel Sambuc         }
77*0a6a1f1dSLionel Sambuc       }
78*0a6a1f1dSLionel Sambuc       if (I == FilesAndDirs.end())
79*0a6a1f1dSLionel Sambuc         CurrentEntry = vfs::Status();
80*0a6a1f1dSLionel Sambuc       return std::error_code();
81*0a6a1f1dSLionel Sambuc     }
82*0a6a1f1dSLionel Sambuc   };
83*0a6a1f1dSLionel Sambuc 
dir_begin(const Twine & Dir,std::error_code & EC)84*0a6a1f1dSLionel Sambuc   vfs::directory_iterator dir_begin(const Twine &Dir,
85*0a6a1f1dSLionel Sambuc                                     std::error_code &EC) override {
86*0a6a1f1dSLionel Sambuc     return vfs::directory_iterator(
87*0a6a1f1dSLionel Sambuc         std::make_shared<DirIterImpl>(FilesAndDirs, Dir));
88*0a6a1f1dSLionel Sambuc   }
89*0a6a1f1dSLionel Sambuc 
addEntry(StringRef Path,const vfs::Status & Status)90*0a6a1f1dSLionel Sambuc   void addEntry(StringRef Path, const vfs::Status &Status) {
91*0a6a1f1dSLionel Sambuc     FilesAndDirs[Path] = Status;
92*0a6a1f1dSLionel Sambuc   }
93*0a6a1f1dSLionel Sambuc 
addRegularFile(StringRef Path,sys::fs::perms Perms=sys::fs::all_all)94*0a6a1f1dSLionel Sambuc   void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
95*0a6a1f1dSLionel Sambuc     vfs::Status S(Path, Path, UniqueID(FSID, FileID++), sys::TimeValue::now(),
96*0a6a1f1dSLionel Sambuc                   0, 0, 1024, sys::fs::file_type::regular_file, Perms);
97*0a6a1f1dSLionel Sambuc     addEntry(Path, S);
98*0a6a1f1dSLionel Sambuc   }
99*0a6a1f1dSLionel Sambuc 
addDirectory(StringRef Path,sys::fs::perms Perms=sys::fs::all_all)100*0a6a1f1dSLionel Sambuc   void addDirectory(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
101*0a6a1f1dSLionel Sambuc     vfs::Status S(Path, Path, UniqueID(FSID, FileID++), sys::TimeValue::now(),
102*0a6a1f1dSLionel Sambuc                   0, 0, 0, sys::fs::file_type::directory_file, Perms);
103*0a6a1f1dSLionel Sambuc     addEntry(Path, S);
104*0a6a1f1dSLionel Sambuc   }
105*0a6a1f1dSLionel Sambuc 
addSymlink(StringRef Path)106*0a6a1f1dSLionel Sambuc   void addSymlink(StringRef Path) {
107*0a6a1f1dSLionel Sambuc     vfs::Status S(Path, Path, UniqueID(FSID, FileID++), sys::TimeValue::now(),
108*0a6a1f1dSLionel Sambuc                   0, 0, 0, sys::fs::file_type::symlink_file, sys::fs::all_all);
109*0a6a1f1dSLionel Sambuc     addEntry(Path, S);
110*0a6a1f1dSLionel Sambuc   }
111*0a6a1f1dSLionel Sambuc };
112*0a6a1f1dSLionel Sambuc } // end anonymous namespace
113*0a6a1f1dSLionel Sambuc 
TEST(VirtualFileSystemTest,StatusQueries)114*0a6a1f1dSLionel Sambuc TEST(VirtualFileSystemTest, StatusQueries) {
115*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
116*0a6a1f1dSLionel Sambuc   ErrorOr<vfs::Status> Status((std::error_code()));
117*0a6a1f1dSLionel Sambuc 
118*0a6a1f1dSLionel Sambuc   D->addRegularFile("/foo");
119*0a6a1f1dSLionel Sambuc   Status = D->status("/foo");
120*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(Status.getError());
121*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(Status->isStatusKnown());
122*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(Status->isDirectory());
123*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(Status->isRegularFile());
124*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(Status->isSymlink());
125*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(Status->isOther());
126*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(Status->exists());
127*0a6a1f1dSLionel Sambuc 
128*0a6a1f1dSLionel Sambuc   D->addDirectory("/bar");
129*0a6a1f1dSLionel Sambuc   Status = D->status("/bar");
130*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(Status.getError());
131*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(Status->isStatusKnown());
132*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(Status->isDirectory());
133*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(Status->isRegularFile());
134*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(Status->isSymlink());
135*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(Status->isOther());
136*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(Status->exists());
137*0a6a1f1dSLionel Sambuc 
138*0a6a1f1dSLionel Sambuc   D->addSymlink("/baz");
139*0a6a1f1dSLionel Sambuc   Status = D->status("/baz");
140*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(Status.getError());
141*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(Status->isStatusKnown());
142*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(Status->isDirectory());
143*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(Status->isRegularFile());
144*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(Status->isSymlink());
145*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(Status->isOther());
146*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(Status->exists());
147*0a6a1f1dSLionel Sambuc 
148*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(Status->equivalent(*Status));
149*0a6a1f1dSLionel Sambuc   ErrorOr<vfs::Status> Status2 = D->status("/foo");
150*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(Status2.getError());
151*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(Status->equivalent(*Status2));
152*0a6a1f1dSLionel Sambuc }
153*0a6a1f1dSLionel Sambuc 
TEST(VirtualFileSystemTest,BaseOnlyOverlay)154*0a6a1f1dSLionel Sambuc TEST(VirtualFileSystemTest, BaseOnlyOverlay) {
155*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
156*0a6a1f1dSLionel Sambuc   ErrorOr<vfs::Status> Status((std::error_code()));
157*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(Status = D->status("/foo"));
158*0a6a1f1dSLionel Sambuc 
159*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(new vfs::OverlayFileSystem(D));
160*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(Status = O->status("/foo"));
161*0a6a1f1dSLionel Sambuc 
162*0a6a1f1dSLionel Sambuc   D->addRegularFile("/foo");
163*0a6a1f1dSLionel Sambuc   Status = D->status("/foo");
164*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(Status.getError());
165*0a6a1f1dSLionel Sambuc 
166*0a6a1f1dSLionel Sambuc   ErrorOr<vfs::Status> Status2((std::error_code()));
167*0a6a1f1dSLionel Sambuc   Status2 = O->status("/foo");
168*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(Status2.getError());
169*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(Status->equivalent(*Status2));
170*0a6a1f1dSLionel Sambuc }
171*0a6a1f1dSLionel Sambuc 
TEST(VirtualFileSystemTest,OverlayFiles)172*0a6a1f1dSLionel Sambuc TEST(VirtualFileSystemTest, OverlayFiles) {
173*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Base(new DummyFileSystem());
174*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
175*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Top(new DummyFileSystem());
176*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
177*0a6a1f1dSLionel Sambuc       new vfs::OverlayFileSystem(Base));
178*0a6a1f1dSLionel Sambuc   O->pushOverlay(Middle);
179*0a6a1f1dSLionel Sambuc   O->pushOverlay(Top);
180*0a6a1f1dSLionel Sambuc 
181*0a6a1f1dSLionel Sambuc   ErrorOr<vfs::Status> Status1((std::error_code())),
182*0a6a1f1dSLionel Sambuc       Status2((std::error_code())), Status3((std::error_code())),
183*0a6a1f1dSLionel Sambuc       StatusB((std::error_code())), StatusM((std::error_code())),
184*0a6a1f1dSLionel Sambuc       StatusT((std::error_code()));
185*0a6a1f1dSLionel Sambuc 
186*0a6a1f1dSLionel Sambuc   Base->addRegularFile("/foo");
187*0a6a1f1dSLionel Sambuc   StatusB = Base->status("/foo");
188*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(StatusB.getError());
189*0a6a1f1dSLionel Sambuc   Status1 = O->status("/foo");
190*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(Status1.getError());
191*0a6a1f1dSLionel Sambuc   Middle->addRegularFile("/foo");
192*0a6a1f1dSLionel Sambuc   StatusM = Middle->status("/foo");
193*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(StatusM.getError());
194*0a6a1f1dSLionel Sambuc   Status2 = O->status("/foo");
195*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(Status2.getError());
196*0a6a1f1dSLionel Sambuc   Top->addRegularFile("/foo");
197*0a6a1f1dSLionel Sambuc   StatusT = Top->status("/foo");
198*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(StatusT.getError());
199*0a6a1f1dSLionel Sambuc   Status3 = O->status("/foo");
200*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(Status3.getError());
201*0a6a1f1dSLionel Sambuc 
202*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(Status1->equivalent(*StatusB));
203*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(Status2->equivalent(*StatusM));
204*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(Status3->equivalent(*StatusT));
205*0a6a1f1dSLionel Sambuc 
206*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(Status1->equivalent(*Status2));
207*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(Status2->equivalent(*Status3));
208*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(Status1->equivalent(*Status3));
209*0a6a1f1dSLionel Sambuc }
210*0a6a1f1dSLionel Sambuc 
TEST(VirtualFileSystemTest,OverlayDirsNonMerged)211*0a6a1f1dSLionel Sambuc TEST(VirtualFileSystemTest, OverlayDirsNonMerged) {
212*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
213*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
214*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
215*0a6a1f1dSLionel Sambuc       new vfs::OverlayFileSystem(Lower));
216*0a6a1f1dSLionel Sambuc   O->pushOverlay(Upper);
217*0a6a1f1dSLionel Sambuc 
218*0a6a1f1dSLionel Sambuc   Lower->addDirectory("/lower-only");
219*0a6a1f1dSLionel Sambuc   Upper->addDirectory("/upper-only");
220*0a6a1f1dSLionel Sambuc 
221*0a6a1f1dSLionel Sambuc   // non-merged paths should be the same
222*0a6a1f1dSLionel Sambuc   ErrorOr<vfs::Status> Status1 = Lower->status("/lower-only");
223*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(Status1.getError());
224*0a6a1f1dSLionel Sambuc   ErrorOr<vfs::Status> Status2 = O->status("/lower-only");
225*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(Status2.getError());
226*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(Status1->equivalent(*Status2));
227*0a6a1f1dSLionel Sambuc 
228*0a6a1f1dSLionel Sambuc   Status1 = Upper->status("/upper-only");
229*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(Status1.getError());
230*0a6a1f1dSLionel Sambuc   Status2 = O->status("/upper-only");
231*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(Status2.getError());
232*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(Status1->equivalent(*Status2));
233*0a6a1f1dSLionel Sambuc }
234*0a6a1f1dSLionel Sambuc 
TEST(VirtualFileSystemTest,MergedDirPermissions)235*0a6a1f1dSLionel Sambuc TEST(VirtualFileSystemTest, MergedDirPermissions) {
236*0a6a1f1dSLionel Sambuc   // merged directories get the permissions of the upper dir
237*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
238*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
239*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
240*0a6a1f1dSLionel Sambuc       new vfs::OverlayFileSystem(Lower));
241*0a6a1f1dSLionel Sambuc   O->pushOverlay(Upper);
242*0a6a1f1dSLionel Sambuc 
243*0a6a1f1dSLionel Sambuc   ErrorOr<vfs::Status> Status((std::error_code()));
244*0a6a1f1dSLionel Sambuc   Lower->addDirectory("/both", sys::fs::owner_read);
245*0a6a1f1dSLionel Sambuc   Upper->addDirectory("/both", sys::fs::owner_all | sys::fs::group_read);
246*0a6a1f1dSLionel Sambuc   Status = O->status("/both");
247*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(Status.getError());
248*0a6a1f1dSLionel Sambuc   EXPECT_EQ(0740, Status->getPermissions());
249*0a6a1f1dSLionel Sambuc 
250*0a6a1f1dSLionel Sambuc   // permissions (as usual) are not recursively applied
251*0a6a1f1dSLionel Sambuc   Lower->addRegularFile("/both/foo", sys::fs::owner_read);
252*0a6a1f1dSLionel Sambuc   Upper->addRegularFile("/both/bar", sys::fs::owner_write);
253*0a6a1f1dSLionel Sambuc   Status = O->status("/both/foo");
254*0a6a1f1dSLionel Sambuc   ASSERT_FALSE( Status.getError());
255*0a6a1f1dSLionel Sambuc   EXPECT_EQ(0400, Status->getPermissions());
256*0a6a1f1dSLionel Sambuc   Status = O->status("/both/bar");
257*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(Status.getError());
258*0a6a1f1dSLionel Sambuc   EXPECT_EQ(0200, Status->getPermissions());
259*0a6a1f1dSLionel Sambuc }
260*0a6a1f1dSLionel Sambuc 
261*0a6a1f1dSLionel Sambuc namespace {
262*0a6a1f1dSLionel Sambuc struct ScopedDir {
263*0a6a1f1dSLionel Sambuc   SmallString<128> Path;
ScopedDir__anon3b3f4fa60211::ScopedDir264*0a6a1f1dSLionel Sambuc   ScopedDir(const Twine &Name, bool Unique=false) {
265*0a6a1f1dSLionel Sambuc     std::error_code EC;
266*0a6a1f1dSLionel Sambuc     if (Unique) {
267*0a6a1f1dSLionel Sambuc       EC =  llvm::sys::fs::createUniqueDirectory(Name, Path);
268*0a6a1f1dSLionel Sambuc     } else {
269*0a6a1f1dSLionel Sambuc       Path = Name.str();
270*0a6a1f1dSLionel Sambuc       EC = llvm::sys::fs::create_directory(Twine(Path));
271*0a6a1f1dSLionel Sambuc     }
272*0a6a1f1dSLionel Sambuc     if (EC)
273*0a6a1f1dSLionel Sambuc       Path = "";
274*0a6a1f1dSLionel Sambuc     EXPECT_FALSE(EC);
275*0a6a1f1dSLionel Sambuc   }
~ScopedDir__anon3b3f4fa60211::ScopedDir276*0a6a1f1dSLionel Sambuc   ~ScopedDir() {
277*0a6a1f1dSLionel Sambuc     if (Path != "")
278*0a6a1f1dSLionel Sambuc       EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
279*0a6a1f1dSLionel Sambuc   }
operator StringRef__anon3b3f4fa60211::ScopedDir280*0a6a1f1dSLionel Sambuc   operator StringRef() { return Path.str(); }
281*0a6a1f1dSLionel Sambuc };
282*0a6a1f1dSLionel Sambuc }
283*0a6a1f1dSLionel Sambuc 
TEST(VirtualFileSystemTest,BasicRealFSIteration)284*0a6a1f1dSLionel Sambuc TEST(VirtualFileSystemTest, BasicRealFSIteration) {
285*0a6a1f1dSLionel Sambuc   ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
286*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
287*0a6a1f1dSLionel Sambuc 
288*0a6a1f1dSLionel Sambuc   std::error_code EC;
289*0a6a1f1dSLionel Sambuc   vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC);
290*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(EC);
291*0a6a1f1dSLionel Sambuc   EXPECT_EQ(vfs::directory_iterator(), I); // empty directory is empty
292*0a6a1f1dSLionel Sambuc 
293*0a6a1f1dSLionel Sambuc   ScopedDir _a(TestDirectory+"/a");
294*0a6a1f1dSLionel Sambuc   ScopedDir _ab(TestDirectory+"/a/b");
295*0a6a1f1dSLionel Sambuc   ScopedDir _c(TestDirectory+"/c");
296*0a6a1f1dSLionel Sambuc   ScopedDir _cd(TestDirectory+"/c/d");
297*0a6a1f1dSLionel Sambuc 
298*0a6a1f1dSLionel Sambuc   I = FS->dir_begin(Twine(TestDirectory), EC);
299*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(EC);
300*0a6a1f1dSLionel Sambuc   ASSERT_NE(vfs::directory_iterator(), I);
301*0a6a1f1dSLionel Sambuc   // Check either a or c, since we can't rely on the iteration order.
302*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
303*0a6a1f1dSLionel Sambuc   I.increment(EC);
304*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(EC);
305*0a6a1f1dSLionel Sambuc   ASSERT_NE(vfs::directory_iterator(), I);
306*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
307*0a6a1f1dSLionel Sambuc   I.increment(EC);
308*0a6a1f1dSLionel Sambuc   EXPECT_EQ(vfs::directory_iterator(), I);
309*0a6a1f1dSLionel Sambuc }
310*0a6a1f1dSLionel Sambuc 
TEST(VirtualFileSystemTest,BasicRealFSRecursiveIteration)311*0a6a1f1dSLionel Sambuc TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
312*0a6a1f1dSLionel Sambuc   ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
313*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
314*0a6a1f1dSLionel Sambuc 
315*0a6a1f1dSLionel Sambuc   std::error_code EC;
316*0a6a1f1dSLionel Sambuc   auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
317*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(EC);
318*0a6a1f1dSLionel Sambuc   EXPECT_EQ(vfs::recursive_directory_iterator(), I); // empty directory is empty
319*0a6a1f1dSLionel Sambuc 
320*0a6a1f1dSLionel Sambuc   ScopedDir _a(TestDirectory+"/a");
321*0a6a1f1dSLionel Sambuc   ScopedDir _ab(TestDirectory+"/a/b");
322*0a6a1f1dSLionel Sambuc   ScopedDir _c(TestDirectory+"/c");
323*0a6a1f1dSLionel Sambuc   ScopedDir _cd(TestDirectory+"/c/d");
324*0a6a1f1dSLionel Sambuc 
325*0a6a1f1dSLionel Sambuc   I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
326*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(EC);
327*0a6a1f1dSLionel Sambuc   ASSERT_NE(vfs::recursive_directory_iterator(), I);
328*0a6a1f1dSLionel Sambuc 
329*0a6a1f1dSLionel Sambuc 
330*0a6a1f1dSLionel Sambuc   std::vector<std::string> Contents;
331*0a6a1f1dSLionel Sambuc   for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
332*0a6a1f1dSLionel Sambuc        I.increment(EC)) {
333*0a6a1f1dSLionel Sambuc     Contents.push_back(I->getName());
334*0a6a1f1dSLionel Sambuc   }
335*0a6a1f1dSLionel Sambuc 
336*0a6a1f1dSLionel Sambuc   // Check contents, which may be in any order
337*0a6a1f1dSLionel Sambuc   EXPECT_EQ(4U, Contents.size());
338*0a6a1f1dSLionel Sambuc   int Counts[4] = { 0, 0, 0, 0 };
339*0a6a1f1dSLionel Sambuc   for (const std::string &Name : Contents) {
340*0a6a1f1dSLionel Sambuc     ASSERT_FALSE(Name.empty());
341*0a6a1f1dSLionel Sambuc     int Index = Name[Name.size()-1] - 'a';
342*0a6a1f1dSLionel Sambuc     ASSERT_TRUE(Index >= 0 && Index < 4);
343*0a6a1f1dSLionel Sambuc     Counts[Index]++;
344*0a6a1f1dSLionel Sambuc   }
345*0a6a1f1dSLionel Sambuc   EXPECT_EQ(1, Counts[0]); // a
346*0a6a1f1dSLionel Sambuc   EXPECT_EQ(1, Counts[1]); // b
347*0a6a1f1dSLionel Sambuc   EXPECT_EQ(1, Counts[2]); // c
348*0a6a1f1dSLionel Sambuc   EXPECT_EQ(1, Counts[3]); // d
349*0a6a1f1dSLionel Sambuc }
350*0a6a1f1dSLionel Sambuc 
351*0a6a1f1dSLionel Sambuc template <typename T, size_t N>
makeStringRefVector(const T (& Arr)[N])352*0a6a1f1dSLionel Sambuc std::vector<StringRef> makeStringRefVector(const T (&Arr)[N]) {
353*0a6a1f1dSLionel Sambuc   std::vector<StringRef> Vec;
354*0a6a1f1dSLionel Sambuc   for (size_t i = 0; i != N; ++i)
355*0a6a1f1dSLionel Sambuc     Vec.push_back(Arr[i]);
356*0a6a1f1dSLionel Sambuc   return Vec;
357*0a6a1f1dSLionel Sambuc }
358*0a6a1f1dSLionel Sambuc 
359*0a6a1f1dSLionel Sambuc template <typename DirIter>
checkContents(DirIter I,ArrayRef<StringRef> Expected)360*0a6a1f1dSLionel Sambuc static void checkContents(DirIter I, ArrayRef<StringRef> Expected) {
361*0a6a1f1dSLionel Sambuc   std::error_code EC;
362*0a6a1f1dSLionel Sambuc   auto ExpectedIter = Expected.begin(), ExpectedEnd = Expected.end();
363*0a6a1f1dSLionel Sambuc   for (DirIter E;
364*0a6a1f1dSLionel Sambuc        !EC && I != E && ExpectedIter != ExpectedEnd;
365*0a6a1f1dSLionel Sambuc        I.increment(EC), ++ExpectedIter)
366*0a6a1f1dSLionel Sambuc     EXPECT_EQ(*ExpectedIter, I->getName());
367*0a6a1f1dSLionel Sambuc 
368*0a6a1f1dSLionel Sambuc   EXPECT_EQ(ExpectedEnd, ExpectedIter);
369*0a6a1f1dSLionel Sambuc   EXPECT_EQ(DirIter(), I);
370*0a6a1f1dSLionel Sambuc }
371*0a6a1f1dSLionel Sambuc 
TEST(VirtualFileSystemTest,OverlayIteration)372*0a6a1f1dSLionel Sambuc TEST(VirtualFileSystemTest, OverlayIteration) {
373*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
374*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
375*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
376*0a6a1f1dSLionel Sambuc       new vfs::OverlayFileSystem(Lower));
377*0a6a1f1dSLionel Sambuc   O->pushOverlay(Upper);
378*0a6a1f1dSLionel Sambuc 
379*0a6a1f1dSLionel Sambuc   std::error_code EC;
380*0a6a1f1dSLionel Sambuc   checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
381*0a6a1f1dSLionel Sambuc 
382*0a6a1f1dSLionel Sambuc   Lower->addRegularFile("/file1");
383*0a6a1f1dSLionel Sambuc   checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file1"));
384*0a6a1f1dSLionel Sambuc 
385*0a6a1f1dSLionel Sambuc   Upper->addRegularFile("/file2");
386*0a6a1f1dSLionel Sambuc   {
387*0a6a1f1dSLionel Sambuc     const char *Contents[] = {"/file2", "/file1"};
388*0a6a1f1dSLionel Sambuc     checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
389*0a6a1f1dSLionel Sambuc   }
390*0a6a1f1dSLionel Sambuc 
391*0a6a1f1dSLionel Sambuc   Lower->addDirectory("/dir1");
392*0a6a1f1dSLionel Sambuc   Lower->addRegularFile("/dir1/foo");
393*0a6a1f1dSLionel Sambuc   Upper->addDirectory("/dir2");
394*0a6a1f1dSLionel Sambuc   Upper->addRegularFile("/dir2/foo");
395*0a6a1f1dSLionel Sambuc   checkContents(O->dir_begin("/dir2", EC), ArrayRef<StringRef>("/dir2/foo"));
396*0a6a1f1dSLionel Sambuc   {
397*0a6a1f1dSLionel Sambuc     const char *Contents[] = {"/dir2", "/file2", "/dir1", "/file1"};
398*0a6a1f1dSLionel Sambuc     checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
399*0a6a1f1dSLionel Sambuc   }
400*0a6a1f1dSLionel Sambuc }
401*0a6a1f1dSLionel Sambuc 
TEST(VirtualFileSystemTest,OverlayRecursiveIteration)402*0a6a1f1dSLionel Sambuc TEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
403*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
404*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
405*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
406*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
407*0a6a1f1dSLionel Sambuc       new vfs::OverlayFileSystem(Lower));
408*0a6a1f1dSLionel Sambuc   O->pushOverlay(Middle);
409*0a6a1f1dSLionel Sambuc   O->pushOverlay(Upper);
410*0a6a1f1dSLionel Sambuc 
411*0a6a1f1dSLionel Sambuc   std::error_code EC;
412*0a6a1f1dSLionel Sambuc   checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
413*0a6a1f1dSLionel Sambuc                 ArrayRef<StringRef>());
414*0a6a1f1dSLionel Sambuc 
415*0a6a1f1dSLionel Sambuc   Lower->addRegularFile("/file1");
416*0a6a1f1dSLionel Sambuc   checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
417*0a6a1f1dSLionel Sambuc                 ArrayRef<StringRef>("/file1"));
418*0a6a1f1dSLionel Sambuc 
419*0a6a1f1dSLionel Sambuc   Upper->addDirectory("/dir");
420*0a6a1f1dSLionel Sambuc   Upper->addRegularFile("/dir/file2");
421*0a6a1f1dSLionel Sambuc   {
422*0a6a1f1dSLionel Sambuc     const char *Contents[] = {"/dir", "/dir/file2", "/file1"};
423*0a6a1f1dSLionel Sambuc     checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
424*0a6a1f1dSLionel Sambuc                   makeStringRefVector(Contents));
425*0a6a1f1dSLionel Sambuc   }
426*0a6a1f1dSLionel Sambuc 
427*0a6a1f1dSLionel Sambuc   Lower->addDirectory("/dir1");
428*0a6a1f1dSLionel Sambuc   Lower->addRegularFile("/dir1/foo");
429*0a6a1f1dSLionel Sambuc   Lower->addDirectory("/dir1/a");
430*0a6a1f1dSLionel Sambuc   Lower->addRegularFile("/dir1/a/b");
431*0a6a1f1dSLionel Sambuc   Middle->addDirectory("/a");
432*0a6a1f1dSLionel Sambuc   Middle->addDirectory("/a/b");
433*0a6a1f1dSLionel Sambuc   Middle->addDirectory("/a/b/c");
434*0a6a1f1dSLionel Sambuc   Middle->addRegularFile("/a/b/c/d");
435*0a6a1f1dSLionel Sambuc   Middle->addRegularFile("/hiddenByUp");
436*0a6a1f1dSLionel Sambuc   Upper->addDirectory("/dir2");
437*0a6a1f1dSLionel Sambuc   Upper->addRegularFile("/dir2/foo");
438*0a6a1f1dSLionel Sambuc   Upper->addRegularFile("/hiddenByUp");
439*0a6a1f1dSLionel Sambuc   checkContents(vfs::recursive_directory_iterator(*O, "/dir2", EC),
440*0a6a1f1dSLionel Sambuc                 ArrayRef<StringRef>("/dir2/foo"));
441*0a6a1f1dSLionel Sambuc   {
442*0a6a1f1dSLionel Sambuc     const char *Contents[] = { "/dir", "/dir/file2", "/dir2", "/dir2/foo",
443*0a6a1f1dSLionel Sambuc         "/hiddenByUp", "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
444*0a6a1f1dSLionel Sambuc         "/dir1/a/b", "/dir1/foo", "/file1" };
445*0a6a1f1dSLionel Sambuc     checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
446*0a6a1f1dSLionel Sambuc                   makeStringRefVector(Contents));
447*0a6a1f1dSLionel Sambuc   }
448*0a6a1f1dSLionel Sambuc }
449*0a6a1f1dSLionel Sambuc 
TEST(VirtualFileSystemTest,ThreeLevelIteration)450*0a6a1f1dSLionel Sambuc TEST(VirtualFileSystemTest, ThreeLevelIteration) {
451*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
452*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
453*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
454*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
455*0a6a1f1dSLionel Sambuc       new vfs::OverlayFileSystem(Lower));
456*0a6a1f1dSLionel Sambuc   O->pushOverlay(Middle);
457*0a6a1f1dSLionel Sambuc   O->pushOverlay(Upper);
458*0a6a1f1dSLionel Sambuc 
459*0a6a1f1dSLionel Sambuc   std::error_code EC;
460*0a6a1f1dSLionel Sambuc   checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
461*0a6a1f1dSLionel Sambuc 
462*0a6a1f1dSLionel Sambuc   Middle->addRegularFile("/file2");
463*0a6a1f1dSLionel Sambuc   checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file2"));
464*0a6a1f1dSLionel Sambuc 
465*0a6a1f1dSLionel Sambuc   Lower->addRegularFile("/file1");
466*0a6a1f1dSLionel Sambuc   Upper->addRegularFile("/file3");
467*0a6a1f1dSLionel Sambuc   {
468*0a6a1f1dSLionel Sambuc     const char *Contents[] = {"/file3", "/file2", "/file1"};
469*0a6a1f1dSLionel Sambuc     checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
470*0a6a1f1dSLionel Sambuc   }
471*0a6a1f1dSLionel Sambuc }
472*0a6a1f1dSLionel Sambuc 
TEST(VirtualFileSystemTest,HiddenInIteration)473*0a6a1f1dSLionel Sambuc TEST(VirtualFileSystemTest, HiddenInIteration) {
474*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
475*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
476*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
477*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
478*0a6a1f1dSLionel Sambuc       new vfs::OverlayFileSystem(Lower));
479*0a6a1f1dSLionel Sambuc   O->pushOverlay(Middle);
480*0a6a1f1dSLionel Sambuc   O->pushOverlay(Upper);
481*0a6a1f1dSLionel Sambuc 
482*0a6a1f1dSLionel Sambuc   std::error_code EC;
483*0a6a1f1dSLionel Sambuc   Lower->addRegularFile("/onlyInLow", sys::fs::owner_read);
484*0a6a1f1dSLionel Sambuc   Lower->addRegularFile("/hiddenByMid", sys::fs::owner_read);
485*0a6a1f1dSLionel Sambuc   Lower->addRegularFile("/hiddenByUp", sys::fs::owner_read);
486*0a6a1f1dSLionel Sambuc   Middle->addRegularFile("/onlyInMid", sys::fs::owner_write);
487*0a6a1f1dSLionel Sambuc   Middle->addRegularFile("/hiddenByMid", sys::fs::owner_write);
488*0a6a1f1dSLionel Sambuc   Middle->addRegularFile("/hiddenByUp", sys::fs::owner_write);
489*0a6a1f1dSLionel Sambuc   Upper->addRegularFile("/onlyInUp", sys::fs::owner_all);
490*0a6a1f1dSLionel Sambuc   Upper->addRegularFile("/hiddenByUp", sys::fs::owner_all);
491*0a6a1f1dSLionel Sambuc   {
492*0a6a1f1dSLionel Sambuc     const char *Contents[] = {"/hiddenByUp", "/onlyInUp", "/hiddenByMid",
493*0a6a1f1dSLionel Sambuc                               "/onlyInMid", "/onlyInLow"};
494*0a6a1f1dSLionel Sambuc     checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
495*0a6a1f1dSLionel Sambuc   }
496*0a6a1f1dSLionel Sambuc 
497*0a6a1f1dSLionel Sambuc   // Make sure we get the top-most entry
498*0a6a1f1dSLionel Sambuc   {
499*0a6a1f1dSLionel Sambuc     std::error_code EC;
500*0a6a1f1dSLionel Sambuc     vfs::directory_iterator I = O->dir_begin("/", EC), E;
501*0a6a1f1dSLionel Sambuc     for ( ; !EC && I != E; I.increment(EC))
502*0a6a1f1dSLionel Sambuc       if (I->getName() == "/hiddenByUp")
503*0a6a1f1dSLionel Sambuc         break;
504*0a6a1f1dSLionel Sambuc     ASSERT_NE(E, I);
505*0a6a1f1dSLionel Sambuc     EXPECT_EQ(sys::fs::owner_all, I->getPermissions());
506*0a6a1f1dSLionel Sambuc   }
507*0a6a1f1dSLionel Sambuc   {
508*0a6a1f1dSLionel Sambuc     std::error_code EC;
509*0a6a1f1dSLionel Sambuc     vfs::directory_iterator I = O->dir_begin("/", EC), E;
510*0a6a1f1dSLionel Sambuc     for ( ; !EC && I != E; I.increment(EC))
511*0a6a1f1dSLionel Sambuc       if (I->getName() == "/hiddenByMid")
512*0a6a1f1dSLionel Sambuc         break;
513*0a6a1f1dSLionel Sambuc     ASSERT_NE(E, I);
514*0a6a1f1dSLionel Sambuc     EXPECT_EQ(sys::fs::owner_write, I->getPermissions());
515*0a6a1f1dSLionel Sambuc   }
516*0a6a1f1dSLionel Sambuc }
517*0a6a1f1dSLionel Sambuc 
518*0a6a1f1dSLionel Sambuc // NOTE: in the tests below, we use '//root/' as our root directory, since it is
519*0a6a1f1dSLionel Sambuc // a legal *absolute* path on Windows as well as *nix.
520*0a6a1f1dSLionel Sambuc class VFSFromYAMLTest : public ::testing::Test {
521*0a6a1f1dSLionel Sambuc public:
522*0a6a1f1dSLionel Sambuc   int NumDiagnostics;
523*0a6a1f1dSLionel Sambuc 
SetUp()524*0a6a1f1dSLionel Sambuc   void SetUp() {
525*0a6a1f1dSLionel Sambuc     NumDiagnostics = 0;
526*0a6a1f1dSLionel Sambuc   }
527*0a6a1f1dSLionel Sambuc 
CountingDiagHandler(const SMDiagnostic &,void * Context)528*0a6a1f1dSLionel Sambuc   static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
529*0a6a1f1dSLionel Sambuc     VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
530*0a6a1f1dSLionel Sambuc     ++Test->NumDiagnostics;
531*0a6a1f1dSLionel Sambuc   }
532*0a6a1f1dSLionel Sambuc 
533*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::FileSystem>
getFromYAMLRawString(StringRef Content,IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS)534*0a6a1f1dSLionel Sambuc   getFromYAMLRawString(StringRef Content,
535*0a6a1f1dSLionel Sambuc                        IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
536*0a6a1f1dSLionel Sambuc     std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content);
537*0a6a1f1dSLionel Sambuc     return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, this,
538*0a6a1f1dSLionel Sambuc                           ExternalFS);
539*0a6a1f1dSLionel Sambuc   }
540*0a6a1f1dSLionel Sambuc 
getFromYAMLString(StringRef Content,IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS=new DummyFileSystem ())541*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
542*0a6a1f1dSLionel Sambuc       StringRef Content,
543*0a6a1f1dSLionel Sambuc       IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
544*0a6a1f1dSLionel Sambuc     std::string VersionPlusContent("{\n  'version':0,\n");
545*0a6a1f1dSLionel Sambuc     VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
546*0a6a1f1dSLionel Sambuc     return getFromYAMLRawString(VersionPlusContent, ExternalFS);
547*0a6a1f1dSLionel Sambuc   }
548*0a6a1f1dSLionel Sambuc };
549*0a6a1f1dSLionel Sambuc 
TEST_F(VFSFromYAMLTest,BasicVFSFromYAML)550*0a6a1f1dSLionel Sambuc TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
551*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::FileSystem> FS;
552*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString("");
553*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
554*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString("[]");
555*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
556*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString("'string'");
557*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
558*0a6a1f1dSLionel Sambuc   EXPECT_EQ(3, NumDiagnostics);
559*0a6a1f1dSLionel Sambuc }
560*0a6a1f1dSLionel Sambuc 
TEST_F(VFSFromYAMLTest,MappedFiles)561*0a6a1f1dSLionel Sambuc TEST_F(VFSFromYAMLTest, MappedFiles) {
562*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
563*0a6a1f1dSLionel Sambuc   Lower->addRegularFile("//root/foo/bar/a");
564*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::FileSystem> FS =
565*0a6a1f1dSLionel Sambuc       getFromYAMLString("{ 'roots': [\n"
566*0a6a1f1dSLionel Sambuc                         "{\n"
567*0a6a1f1dSLionel Sambuc                         "  'type': 'directory',\n"
568*0a6a1f1dSLionel Sambuc                         "  'name': '//root/',\n"
569*0a6a1f1dSLionel Sambuc                         "  'contents': [ {\n"
570*0a6a1f1dSLionel Sambuc                         "                  'type': 'file',\n"
571*0a6a1f1dSLionel Sambuc                         "                  'name': 'file1',\n"
572*0a6a1f1dSLionel Sambuc                         "                  'external-contents': '//root/foo/bar/a'\n"
573*0a6a1f1dSLionel Sambuc                         "                },\n"
574*0a6a1f1dSLionel Sambuc                         "                {\n"
575*0a6a1f1dSLionel Sambuc                         "                  'type': 'file',\n"
576*0a6a1f1dSLionel Sambuc                         "                  'name': 'file2',\n"
577*0a6a1f1dSLionel Sambuc                         "                  'external-contents': '//root/foo/b'\n"
578*0a6a1f1dSLionel Sambuc                         "                }\n"
579*0a6a1f1dSLionel Sambuc                         "              ]\n"
580*0a6a1f1dSLionel Sambuc                         "}\n"
581*0a6a1f1dSLionel Sambuc                         "]\n"
582*0a6a1f1dSLionel Sambuc                         "}",
583*0a6a1f1dSLionel Sambuc                         Lower);
584*0a6a1f1dSLionel Sambuc   ASSERT_TRUE(FS.get() != nullptr);
585*0a6a1f1dSLionel Sambuc 
586*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
587*0a6a1f1dSLionel Sambuc       new vfs::OverlayFileSystem(Lower));
588*0a6a1f1dSLionel Sambuc   O->pushOverlay(FS);
589*0a6a1f1dSLionel Sambuc 
590*0a6a1f1dSLionel Sambuc   // file
591*0a6a1f1dSLionel Sambuc   ErrorOr<vfs::Status> S = O->status("//root/file1");
592*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(S.getError());
593*0a6a1f1dSLionel Sambuc   EXPECT_EQ("//root/foo/bar/a", S->getName());
594*0a6a1f1dSLionel Sambuc 
595*0a6a1f1dSLionel Sambuc   ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
596*0a6a1f1dSLionel Sambuc   EXPECT_EQ("//root/foo/bar/a", SLower->getName());
597*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(S->equivalent(*SLower));
598*0a6a1f1dSLionel Sambuc 
599*0a6a1f1dSLionel Sambuc   // directory
600*0a6a1f1dSLionel Sambuc   S = O->status("//root/");
601*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(S.getError());
602*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(S->isDirectory());
603*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
604*0a6a1f1dSLionel Sambuc 
605*0a6a1f1dSLionel Sambuc   // broken mapping
606*0a6a1f1dSLionel Sambuc   EXPECT_EQ(O->status("//root/file2").getError(),
607*0a6a1f1dSLionel Sambuc             llvm::errc::no_such_file_or_directory);
608*0a6a1f1dSLionel Sambuc   EXPECT_EQ(0, NumDiagnostics);
609*0a6a1f1dSLionel Sambuc }
610*0a6a1f1dSLionel Sambuc 
TEST_F(VFSFromYAMLTest,CaseInsensitive)611*0a6a1f1dSLionel Sambuc TEST_F(VFSFromYAMLTest, CaseInsensitive) {
612*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
613*0a6a1f1dSLionel Sambuc   Lower->addRegularFile("//root/foo/bar/a");
614*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::FileSystem> FS =
615*0a6a1f1dSLionel Sambuc       getFromYAMLString("{ 'case-sensitive': 'false',\n"
616*0a6a1f1dSLionel Sambuc                         "  'roots': [\n"
617*0a6a1f1dSLionel Sambuc                         "{\n"
618*0a6a1f1dSLionel Sambuc                         "  'type': 'directory',\n"
619*0a6a1f1dSLionel Sambuc                         "  'name': '//root/',\n"
620*0a6a1f1dSLionel Sambuc                         "  'contents': [ {\n"
621*0a6a1f1dSLionel Sambuc                         "                  'type': 'file',\n"
622*0a6a1f1dSLionel Sambuc                         "                  'name': 'XX',\n"
623*0a6a1f1dSLionel Sambuc                         "                  'external-contents': '//root/foo/bar/a'\n"
624*0a6a1f1dSLionel Sambuc                         "                }\n"
625*0a6a1f1dSLionel Sambuc                         "              ]\n"
626*0a6a1f1dSLionel Sambuc                         "}]}",
627*0a6a1f1dSLionel Sambuc                         Lower);
628*0a6a1f1dSLionel Sambuc   ASSERT_TRUE(FS.get() != nullptr);
629*0a6a1f1dSLionel Sambuc 
630*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
631*0a6a1f1dSLionel Sambuc       new vfs::OverlayFileSystem(Lower));
632*0a6a1f1dSLionel Sambuc   O->pushOverlay(FS);
633*0a6a1f1dSLionel Sambuc 
634*0a6a1f1dSLionel Sambuc   ErrorOr<vfs::Status> S = O->status("//root/XX");
635*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(S.getError());
636*0a6a1f1dSLionel Sambuc 
637*0a6a1f1dSLionel Sambuc   ErrorOr<vfs::Status> SS = O->status("//root/xx");
638*0a6a1f1dSLionel Sambuc   ASSERT_FALSE(SS.getError());
639*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(S->equivalent(*SS));
640*0a6a1f1dSLionel Sambuc   SS = O->status("//root/xX");
641*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(S->equivalent(*SS));
642*0a6a1f1dSLionel Sambuc   SS = O->status("//root/Xx");
643*0a6a1f1dSLionel Sambuc   EXPECT_TRUE(S->equivalent(*SS));
644*0a6a1f1dSLionel Sambuc   EXPECT_EQ(0, NumDiagnostics);
645*0a6a1f1dSLionel Sambuc }
646*0a6a1f1dSLionel Sambuc 
TEST_F(VFSFromYAMLTest,CaseSensitive)647*0a6a1f1dSLionel Sambuc TEST_F(VFSFromYAMLTest, CaseSensitive) {
648*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
649*0a6a1f1dSLionel Sambuc   Lower->addRegularFile("//root/foo/bar/a");
650*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::FileSystem> FS =
651*0a6a1f1dSLionel Sambuc       getFromYAMLString("{ 'case-sensitive': 'true',\n"
652*0a6a1f1dSLionel Sambuc                         "  'roots': [\n"
653*0a6a1f1dSLionel Sambuc                         "{\n"
654*0a6a1f1dSLionel Sambuc                         "  'type': 'directory',\n"
655*0a6a1f1dSLionel Sambuc                         "  'name': '//root/',\n"
656*0a6a1f1dSLionel Sambuc                         "  'contents': [ {\n"
657*0a6a1f1dSLionel Sambuc                         "                  'type': 'file',\n"
658*0a6a1f1dSLionel Sambuc                         "                  'name': 'XX',\n"
659*0a6a1f1dSLionel Sambuc                         "                  'external-contents': '//root/foo/bar/a'\n"
660*0a6a1f1dSLionel Sambuc                         "                }\n"
661*0a6a1f1dSLionel Sambuc                         "              ]\n"
662*0a6a1f1dSLionel Sambuc                         "}]}",
663*0a6a1f1dSLionel Sambuc                         Lower);
664*0a6a1f1dSLionel Sambuc   ASSERT_TRUE(FS.get() != nullptr);
665*0a6a1f1dSLionel Sambuc 
666*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
667*0a6a1f1dSLionel Sambuc       new vfs::OverlayFileSystem(Lower));
668*0a6a1f1dSLionel Sambuc   O->pushOverlay(FS);
669*0a6a1f1dSLionel Sambuc 
670*0a6a1f1dSLionel Sambuc   ErrorOr<vfs::Status> SS = O->status("//root/xx");
671*0a6a1f1dSLionel Sambuc   EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
672*0a6a1f1dSLionel Sambuc   SS = O->status("//root/xX");
673*0a6a1f1dSLionel Sambuc   EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
674*0a6a1f1dSLionel Sambuc   SS = O->status("//root/Xx");
675*0a6a1f1dSLionel Sambuc   EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
676*0a6a1f1dSLionel Sambuc   EXPECT_EQ(0, NumDiagnostics);
677*0a6a1f1dSLionel Sambuc }
678*0a6a1f1dSLionel Sambuc 
TEST_F(VFSFromYAMLTest,IllegalVFSFile)679*0a6a1f1dSLionel Sambuc TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
680*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
681*0a6a1f1dSLionel Sambuc 
682*0a6a1f1dSLionel Sambuc   // invalid YAML at top-level
683*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
684*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
685*0a6a1f1dSLionel Sambuc   // invalid YAML in roots
686*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString("{ 'roots':[}", Lower);
687*0a6a1f1dSLionel Sambuc   // invalid YAML in directory
688*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString(
689*0a6a1f1dSLionel Sambuc       "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
690*0a6a1f1dSLionel Sambuc       Lower);
691*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
692*0a6a1f1dSLionel Sambuc 
693*0a6a1f1dSLionel Sambuc   // invalid configuration
694*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
695*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
696*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
697*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
698*0a6a1f1dSLionel Sambuc 
699*0a6a1f1dSLionel Sambuc   // invalid roots
700*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString("{ 'roots':'' }", Lower);
701*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
702*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString("{ 'roots':{} }", Lower);
703*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
704*0a6a1f1dSLionel Sambuc 
705*0a6a1f1dSLionel Sambuc   // invalid entries
706*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString(
707*0a6a1f1dSLionel Sambuc       "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
708*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
709*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
710*0a6a1f1dSLionel Sambuc                          "'external-contents': 'other' }",
711*0a6a1f1dSLionel Sambuc                          Lower);
712*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
713*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString(
714*0a6a1f1dSLionel Sambuc       "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
715*0a6a1f1dSLionel Sambuc       Lower);
716*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
717*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString(
718*0a6a1f1dSLionel Sambuc       "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
719*0a6a1f1dSLionel Sambuc       Lower);
720*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
721*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString(
722*0a6a1f1dSLionel Sambuc       "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
723*0a6a1f1dSLionel Sambuc       Lower);
724*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
725*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString(
726*0a6a1f1dSLionel Sambuc       "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
727*0a6a1f1dSLionel Sambuc       Lower);
728*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
729*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString(
730*0a6a1f1dSLionel Sambuc       "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
731*0a6a1f1dSLionel Sambuc       Lower);
732*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
733*0a6a1f1dSLionel Sambuc 
734*0a6a1f1dSLionel Sambuc   // missing mandatory fields
735*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
736*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
737*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString(
738*0a6a1f1dSLionel Sambuc       "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
739*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
740*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
741*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
742*0a6a1f1dSLionel Sambuc 
743*0a6a1f1dSLionel Sambuc   // duplicate keys
744*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
745*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
746*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString(
747*0a6a1f1dSLionel Sambuc       "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
748*0a6a1f1dSLionel Sambuc       Lower);
749*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
750*0a6a1f1dSLionel Sambuc   FS =
751*0a6a1f1dSLionel Sambuc       getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
752*0a6a1f1dSLionel Sambuc                         "'external-contents':'blah' } ] }",
753*0a6a1f1dSLionel Sambuc                         Lower);
754*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
755*0a6a1f1dSLionel Sambuc 
756*0a6a1f1dSLionel Sambuc   // missing version
757*0a6a1f1dSLionel Sambuc   FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
758*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
759*0a6a1f1dSLionel Sambuc 
760*0a6a1f1dSLionel Sambuc   // bad version number
761*0a6a1f1dSLionel Sambuc   FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
762*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
763*0a6a1f1dSLionel Sambuc   FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
764*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
765*0a6a1f1dSLionel Sambuc   FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
766*0a6a1f1dSLionel Sambuc   EXPECT_EQ(nullptr, FS.get());
767*0a6a1f1dSLionel Sambuc   EXPECT_EQ(24, NumDiagnostics);
768*0a6a1f1dSLionel Sambuc }
769*0a6a1f1dSLionel Sambuc 
TEST_F(VFSFromYAMLTest,UseExternalName)770*0a6a1f1dSLionel Sambuc TEST_F(VFSFromYAMLTest, UseExternalName) {
771*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
772*0a6a1f1dSLionel Sambuc   Lower->addRegularFile("//root/external/file");
773*0a6a1f1dSLionel Sambuc 
774*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
775*0a6a1f1dSLionel Sambuc       "{ 'roots': [\n"
776*0a6a1f1dSLionel Sambuc       "  { 'type': 'file', 'name': '//root/A',\n"
777*0a6a1f1dSLionel Sambuc       "    'external-contents': '//root/external/file'\n"
778*0a6a1f1dSLionel Sambuc       "  },\n"
779*0a6a1f1dSLionel Sambuc       "  { 'type': 'file', 'name': '//root/B',\n"
780*0a6a1f1dSLionel Sambuc       "    'use-external-name': true,\n"
781*0a6a1f1dSLionel Sambuc       "    'external-contents': '//root/external/file'\n"
782*0a6a1f1dSLionel Sambuc       "  },\n"
783*0a6a1f1dSLionel Sambuc       "  { 'type': 'file', 'name': '//root/C',\n"
784*0a6a1f1dSLionel Sambuc       "    'use-external-name': false,\n"
785*0a6a1f1dSLionel Sambuc       "    'external-contents': '//root/external/file'\n"
786*0a6a1f1dSLionel Sambuc       "  }\n"
787*0a6a1f1dSLionel Sambuc       "] }", Lower);
788*0a6a1f1dSLionel Sambuc   ASSERT_TRUE(nullptr != FS.get());
789*0a6a1f1dSLionel Sambuc 
790*0a6a1f1dSLionel Sambuc   // default true
791*0a6a1f1dSLionel Sambuc   EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
792*0a6a1f1dSLionel Sambuc   // explicit
793*0a6a1f1dSLionel Sambuc   EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
794*0a6a1f1dSLionel Sambuc   EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
795*0a6a1f1dSLionel Sambuc 
796*0a6a1f1dSLionel Sambuc   // global configuration
797*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString(
798*0a6a1f1dSLionel Sambuc       "{ 'use-external-names': false,\n"
799*0a6a1f1dSLionel Sambuc       "  'roots': [\n"
800*0a6a1f1dSLionel Sambuc       "  { 'type': 'file', 'name': '//root/A',\n"
801*0a6a1f1dSLionel Sambuc       "    'external-contents': '//root/external/file'\n"
802*0a6a1f1dSLionel Sambuc       "  },\n"
803*0a6a1f1dSLionel Sambuc       "  { 'type': 'file', 'name': '//root/B',\n"
804*0a6a1f1dSLionel Sambuc       "    'use-external-name': true,\n"
805*0a6a1f1dSLionel Sambuc       "    'external-contents': '//root/external/file'\n"
806*0a6a1f1dSLionel Sambuc       "  },\n"
807*0a6a1f1dSLionel Sambuc       "  { 'type': 'file', 'name': '//root/C',\n"
808*0a6a1f1dSLionel Sambuc       "    'use-external-name': false,\n"
809*0a6a1f1dSLionel Sambuc       "    'external-contents': '//root/external/file'\n"
810*0a6a1f1dSLionel Sambuc       "  }\n"
811*0a6a1f1dSLionel Sambuc       "] }", Lower);
812*0a6a1f1dSLionel Sambuc   ASSERT_TRUE(nullptr != FS.get());
813*0a6a1f1dSLionel Sambuc 
814*0a6a1f1dSLionel Sambuc   // default
815*0a6a1f1dSLionel Sambuc   EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
816*0a6a1f1dSLionel Sambuc   // explicit
817*0a6a1f1dSLionel Sambuc   EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
818*0a6a1f1dSLionel Sambuc   EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
819*0a6a1f1dSLionel Sambuc }
820*0a6a1f1dSLionel Sambuc 
TEST_F(VFSFromYAMLTest,MultiComponentPath)821*0a6a1f1dSLionel Sambuc TEST_F(VFSFromYAMLTest, MultiComponentPath) {
822*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
823*0a6a1f1dSLionel Sambuc   Lower->addRegularFile("//root/other");
824*0a6a1f1dSLionel Sambuc 
825*0a6a1f1dSLionel Sambuc   // file in roots
826*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
827*0a6a1f1dSLionel Sambuc       "{ 'roots': [\n"
828*0a6a1f1dSLionel Sambuc       "  { 'type': 'file', 'name': '//root/path/to/file',\n"
829*0a6a1f1dSLionel Sambuc       "    'external-contents': '//root/other' }]\n"
830*0a6a1f1dSLionel Sambuc       "}", Lower);
831*0a6a1f1dSLionel Sambuc   ASSERT_TRUE(nullptr != FS.get());
832*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(FS->status("//root/path/to/file").getError());
833*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(FS->status("//root/path/to").getError());
834*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(FS->status("//root/path").getError());
835*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(FS->status("//root/").getError());
836*0a6a1f1dSLionel Sambuc 
837*0a6a1f1dSLionel Sambuc   // at the start
838*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString(
839*0a6a1f1dSLionel Sambuc       "{ 'roots': [\n"
840*0a6a1f1dSLionel Sambuc       "  { 'type': 'directory', 'name': '//root/path/to',\n"
841*0a6a1f1dSLionel Sambuc       "    'contents': [ { 'type': 'file', 'name': 'file',\n"
842*0a6a1f1dSLionel Sambuc       "                    'external-contents': '//root/other' }]}]\n"
843*0a6a1f1dSLionel Sambuc       "}", Lower);
844*0a6a1f1dSLionel Sambuc   ASSERT_TRUE(nullptr != FS.get());
845*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(FS->status("//root/path/to/file").getError());
846*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(FS->status("//root/path/to").getError());
847*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(FS->status("//root/path").getError());
848*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(FS->status("//root/").getError());
849*0a6a1f1dSLionel Sambuc 
850*0a6a1f1dSLionel Sambuc   // at the end
851*0a6a1f1dSLionel Sambuc   FS = getFromYAMLString(
852*0a6a1f1dSLionel Sambuc       "{ 'roots': [\n"
853*0a6a1f1dSLionel Sambuc       "  { 'type': 'directory', 'name': '//root/',\n"
854*0a6a1f1dSLionel Sambuc       "    'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
855*0a6a1f1dSLionel Sambuc       "                    'external-contents': '//root/other' }]}]\n"
856*0a6a1f1dSLionel Sambuc       "}", Lower);
857*0a6a1f1dSLionel Sambuc   ASSERT_TRUE(nullptr != FS.get());
858*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(FS->status("//root/path/to/file").getError());
859*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(FS->status("//root/path/to").getError());
860*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(FS->status("//root/path").getError());
861*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(FS->status("//root/").getError());
862*0a6a1f1dSLionel Sambuc }
863*0a6a1f1dSLionel Sambuc 
TEST_F(VFSFromYAMLTest,TrailingSlashes)864*0a6a1f1dSLionel Sambuc TEST_F(VFSFromYAMLTest, TrailingSlashes) {
865*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
866*0a6a1f1dSLionel Sambuc   Lower->addRegularFile("//root/other");
867*0a6a1f1dSLionel Sambuc 
868*0a6a1f1dSLionel Sambuc   // file in roots
869*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
870*0a6a1f1dSLionel Sambuc       "{ 'roots': [\n"
871*0a6a1f1dSLionel Sambuc       "  { 'type': 'directory', 'name': '//root/path/to////',\n"
872*0a6a1f1dSLionel Sambuc       "    'contents': [ { 'type': 'file', 'name': 'file',\n"
873*0a6a1f1dSLionel Sambuc       "                    'external-contents': '//root/other' }]}]\n"
874*0a6a1f1dSLionel Sambuc       "}", Lower);
875*0a6a1f1dSLionel Sambuc   ASSERT_TRUE(nullptr != FS.get());
876*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(FS->status("//root/path/to/file").getError());
877*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(FS->status("//root/path/to").getError());
878*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(FS->status("//root/path").getError());
879*0a6a1f1dSLionel Sambuc   EXPECT_FALSE(FS->status("//root/").getError());
880*0a6a1f1dSLionel Sambuc }
881*0a6a1f1dSLionel Sambuc 
TEST_F(VFSFromYAMLTest,DirectoryIteration)882*0a6a1f1dSLionel Sambuc TEST_F(VFSFromYAMLTest, DirectoryIteration) {
883*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
884*0a6a1f1dSLionel Sambuc   Lower->addDirectory("//root/");
885*0a6a1f1dSLionel Sambuc   Lower->addDirectory("//root/foo");
886*0a6a1f1dSLionel Sambuc   Lower->addDirectory("//root/foo/bar");
887*0a6a1f1dSLionel Sambuc   Lower->addRegularFile("//root/foo/bar/a");
888*0a6a1f1dSLionel Sambuc   Lower->addRegularFile("//root/foo/bar/b");
889*0a6a1f1dSLionel Sambuc   Lower->addRegularFile("//root/file3");
890*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::FileSystem> FS =
891*0a6a1f1dSLionel Sambuc   getFromYAMLString("{ 'use-external-names': false,\n"
892*0a6a1f1dSLionel Sambuc                     "  'roots': [\n"
893*0a6a1f1dSLionel Sambuc                     "{\n"
894*0a6a1f1dSLionel Sambuc                     "  'type': 'directory',\n"
895*0a6a1f1dSLionel Sambuc                     "  'name': '//root/',\n"
896*0a6a1f1dSLionel Sambuc                     "  'contents': [ {\n"
897*0a6a1f1dSLionel Sambuc                     "                  'type': 'file',\n"
898*0a6a1f1dSLionel Sambuc                     "                  'name': 'file1',\n"
899*0a6a1f1dSLionel Sambuc                     "                  'external-contents': '//root/foo/bar/a'\n"
900*0a6a1f1dSLionel Sambuc                     "                },\n"
901*0a6a1f1dSLionel Sambuc                     "                {\n"
902*0a6a1f1dSLionel Sambuc                     "                  'type': 'file',\n"
903*0a6a1f1dSLionel Sambuc                     "                  'name': 'file2',\n"
904*0a6a1f1dSLionel Sambuc                     "                  'external-contents': '//root/foo/bar/b'\n"
905*0a6a1f1dSLionel Sambuc                     "                }\n"
906*0a6a1f1dSLionel Sambuc                     "              ]\n"
907*0a6a1f1dSLionel Sambuc                     "}\n"
908*0a6a1f1dSLionel Sambuc                     "]\n"
909*0a6a1f1dSLionel Sambuc                     "}",
910*0a6a1f1dSLionel Sambuc                     Lower);
911*0a6a1f1dSLionel Sambuc   ASSERT_TRUE(FS.get() != NULL);
912*0a6a1f1dSLionel Sambuc 
913*0a6a1f1dSLionel Sambuc   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
914*0a6a1f1dSLionel Sambuc       new vfs::OverlayFileSystem(Lower));
915*0a6a1f1dSLionel Sambuc   O->pushOverlay(FS);
916*0a6a1f1dSLionel Sambuc 
917*0a6a1f1dSLionel Sambuc   std::error_code EC;
918*0a6a1f1dSLionel Sambuc   {
919*0a6a1f1dSLionel Sambuc     const char *Contents[] = {"//root/file1", "//root/file2", "//root/file3",
920*0a6a1f1dSLionel Sambuc                               "//root/foo"};
921*0a6a1f1dSLionel Sambuc     checkContents(O->dir_begin("//root/", EC), makeStringRefVector(Contents));
922*0a6a1f1dSLionel Sambuc   }
923*0a6a1f1dSLionel Sambuc 
924*0a6a1f1dSLionel Sambuc   {
925*0a6a1f1dSLionel Sambuc     const char *Contents[] = {"//root/foo/bar/a", "//root/foo/bar/b"};
926*0a6a1f1dSLionel Sambuc     checkContents(O->dir_begin("//root/foo/bar", EC),
927*0a6a1f1dSLionel Sambuc                   makeStringRefVector(Contents));
928*0a6a1f1dSLionel Sambuc   }
929*0a6a1f1dSLionel Sambuc }
930