1651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//===- unittests/Basic/VirtualFileSystem.cpp ---------------- VFS tests ---===//
2651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//
3651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//                     The LLVM Compiler Infrastructure
4651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//
5651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// This file is distributed under the University of Illinois Open Source
6651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// License. See LICENSE.TXT for details.
7651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//
8651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines//===----------------------------------------------------------------------===//
9651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
10651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "clang/Basic/VirtualFileSystem.h"
11ef8225444452a1486bd721f3285301fe84643b00Stephen Hines#include "llvm/Support/Errc.h"
12651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "llvm/Support/MemoryBuffer.h"
13651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "llvm/Support/Path.h"
14651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "llvm/Support/SourceMgr.h"
15651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include "gtest/gtest.h"
16651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines#include <map>
17651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesusing namespace clang;
18651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesusing namespace llvm;
19651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesusing llvm::sys::fs::UniqueID;
20651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
21651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesnamespace {
22651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesclass DummyFileSystem : public vfs::FileSystem {
23651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  int FSID;   // used to produce UniqueIDs
24651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  int FileID; // used to produce UniqueIDs
25651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  std::map<std::string, vfs::Status> FilesAndDirs;
26651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
27651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  static int getNextFSID() {
28651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    static int Count = 0;
29651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return Count++;
30651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
31651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
32651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinespublic:
33651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  DummyFileSystem() : FSID(getNextFSID()), FileID(0) {}
34651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
35651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<vfs::Status> status(const Twine &Path) {
36651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    std::map<std::string, vfs::Status>::iterator I =
37651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines        FilesAndDirs.find(Path.str());
38651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    if (I == FilesAndDirs.end())
39ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      return make_error_code(llvm::errc::no_such_file_or_directory);
40651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return I->second;
41651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
42ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code openFileForRead(const Twine &Path,
43ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                  std::unique_ptr<vfs::File> &Result) {
44651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    llvm_unreachable("unimplemented");
45651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
46ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code getBufferForFile(const Twine &Name,
47ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                   std::unique_ptr<MemoryBuffer> &Result,
48ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                   int64_t FileSize = -1,
49ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                   bool RequiresNullTerminator = true) {
50651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    llvm_unreachable("unimplemented");
51651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
52651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
53ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  struct DirIterImpl : public clang::vfs::detail::DirIterImpl {
54ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    std::map<std::string, vfs::Status> &FilesAndDirs;
55ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    std::map<std::string, vfs::Status>::iterator I;
56ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    std::string Path;
57ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    bool isInPath(StringRef S) {
58ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      if (Path.size() < S.size() && S.find(Path) == 0) {
59ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        auto LastSep = S.find_last_of('/');
60ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        if (LastSep == Path.size() || LastSep == Path.size()-1)
61ef8225444452a1486bd721f3285301fe84643b00Stephen Hines          return true;
62ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      }
63ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      return false;
64ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    }
65ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    DirIterImpl(std::map<std::string, vfs::Status> &FilesAndDirs,
66ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                const Twine &_Path)
67ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        : FilesAndDirs(FilesAndDirs), I(FilesAndDirs.begin()),
68ef8225444452a1486bd721f3285301fe84643b00Stephen Hines          Path(_Path.str()) {
69ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      for ( ; I != FilesAndDirs.end(); ++I) {
70ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        if (isInPath(I->first)) {
71ef8225444452a1486bd721f3285301fe84643b00Stephen Hines          CurrentEntry = I->second;
72ef8225444452a1486bd721f3285301fe84643b00Stephen Hines          break;
73ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        }
74ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      }
75ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    }
76ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    std::error_code increment() override {
77ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      ++I;
78ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      for ( ; I != FilesAndDirs.end(); ++I) {
79ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        if (isInPath(I->first)) {
80ef8225444452a1486bd721f3285301fe84643b00Stephen Hines          CurrentEntry = I->second;
81ef8225444452a1486bd721f3285301fe84643b00Stephen Hines          break;
82ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        }
83ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      }
84ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      if (I == FilesAndDirs.end())
85ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        CurrentEntry = vfs::Status();
86ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      return std::error_code();
87ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    }
88ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  };
89ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
90ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  vfs::directory_iterator dir_begin(const Twine &Dir,
91ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                                    std::error_code &EC) override {
92ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    return vfs::directory_iterator(
93ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        std::make_shared<DirIterImpl>(FilesAndDirs, Dir));
94ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
95ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
96651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  void addEntry(StringRef Path, const vfs::Status &Status) {
97651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    FilesAndDirs[Path] = Status;
98651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
99651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
100651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
101651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    vfs::Status S(Path, Path, UniqueID(FSID, FileID++), sys::TimeValue::now(),
102651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                  0, 0, 1024, sys::fs::file_type::regular_file, Perms);
103651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    addEntry(Path, S);
104651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
105651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
106651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  void addDirectory(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
107651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    vfs::Status S(Path, Path, UniqueID(FSID, FileID++), sys::TimeValue::now(),
108651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                  0, 0, 0, sys::fs::file_type::directory_file, Perms);
109651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    addEntry(Path, S);
110651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
111651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
112651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  void addSymlink(StringRef Path) {
113651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    vfs::Status S(Path, Path, UniqueID(FSID, FileID++), sys::TimeValue::now(),
114651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                  0, 0, 0, sys::fs::file_type::symlink_file, sys::fs::all_all);
115651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    addEntry(Path, S);
116651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
117651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
118651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines} // end anonymous namespace
119651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
120651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesTEST(VirtualFileSystemTest, StatusQueries) {
121651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
122ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ErrorOr<vfs::Status> Status((std::error_code()));
123651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
124651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  D->addRegularFile("/foo");
125651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status = D->status("/foo");
126ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(Status.getError());
127651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(Status->isStatusKnown());
128651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_FALSE(Status->isDirectory());
129651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(Status->isRegularFile());
130651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_FALSE(Status->isSymlink());
131651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_FALSE(Status->isOther());
132651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(Status->exists());
133651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
134651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  D->addDirectory("/bar");
135651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status = D->status("/bar");
136ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(Status.getError());
137651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(Status->isStatusKnown());
138651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(Status->isDirectory());
139651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_FALSE(Status->isRegularFile());
140651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_FALSE(Status->isSymlink());
141651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_FALSE(Status->isOther());
142651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(Status->exists());
143651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
144651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  D->addSymlink("/baz");
145651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status = D->status("/baz");
146ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(Status.getError());
147651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(Status->isStatusKnown());
148651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_FALSE(Status->isDirectory());
149651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_FALSE(Status->isRegularFile());
150651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(Status->isSymlink());
151651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_FALSE(Status->isOther());
152651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(Status->exists());
153651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
154651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(Status->equivalent(*Status));
155651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<vfs::Status> Status2 = D->status("/foo");
156ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(Status2.getError());
157651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_FALSE(Status->equivalent(*Status2));
158651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
159651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
160651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesTEST(VirtualFileSystemTest, BaseOnlyOverlay) {
161651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
162ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ErrorOr<vfs::Status> Status((std::error_code()));
163651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_FALSE(Status = D->status("/foo"));
164651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
165651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(new vfs::OverlayFileSystem(D));
166651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_FALSE(Status = O->status("/foo"));
167651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
168651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  D->addRegularFile("/foo");
169651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status = D->status("/foo");
170ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_FALSE(Status.getError());
171651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
172ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ErrorOr<vfs::Status> Status2((std::error_code()));
173651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status2 = O->status("/foo");
174ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_FALSE(Status2.getError());
175651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(Status->equivalent(*Status2));
176651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
177651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
178651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesTEST(VirtualFileSystemTest, OverlayFiles) {
179651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Base(new DummyFileSystem());
180651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
181651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Top(new DummyFileSystem());
182651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
183651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      new vfs::OverlayFileSystem(Base));
184651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  O->pushOverlay(Middle);
185651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  O->pushOverlay(Top);
186651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
187ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ErrorOr<vfs::Status> Status1((std::error_code())),
188ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      Status2((std::error_code())), Status3((std::error_code())),
189ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      StatusB((std::error_code())), StatusM((std::error_code())),
190ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      StatusT((std::error_code()));
191651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
192651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Base->addRegularFile("/foo");
193651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  StatusB = Base->status("/foo");
194ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(StatusB.getError());
195651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status1 = O->status("/foo");
196ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(Status1.getError());
197651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Middle->addRegularFile("/foo");
198651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  StatusM = Middle->status("/foo");
199ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(StatusM.getError());
200651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status2 = O->status("/foo");
201ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(Status2.getError());
202651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Top->addRegularFile("/foo");
203651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  StatusT = Top->status("/foo");
204ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(StatusT.getError());
205651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status3 = O->status("/foo");
206ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(Status3.getError());
207651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
208651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(Status1->equivalent(*StatusB));
209651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(Status2->equivalent(*StatusM));
210651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(Status3->equivalent(*StatusT));
211651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
212651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_FALSE(Status1->equivalent(*Status2));
213651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_FALSE(Status2->equivalent(*Status3));
214651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_FALSE(Status1->equivalent(*Status3));
215651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
216651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
217651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesTEST(VirtualFileSystemTest, OverlayDirsNonMerged) {
218651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
219651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
220651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
221651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      new vfs::OverlayFileSystem(Lower));
222651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  O->pushOverlay(Upper);
223651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
224651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Lower->addDirectory("/lower-only");
225651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Upper->addDirectory("/upper-only");
226651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
227651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // non-merged paths should be the same
228651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<vfs::Status> Status1 = Lower->status("/lower-only");
229ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(Status1.getError());
230651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<vfs::Status> Status2 = O->status("/lower-only");
231ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(Status2.getError());
232651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(Status1->equivalent(*Status2));
233651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
234651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status1 = Upper->status("/upper-only");
235ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(Status1.getError());
236651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status2 = O->status("/upper-only");
237ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(Status2.getError());
238651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(Status1->equivalent(*Status2));
239651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
240651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
241651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesTEST(VirtualFileSystemTest, MergedDirPermissions) {
242651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // merged directories get the permissions of the upper dir
243651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
244651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
245651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
246651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      new vfs::OverlayFileSystem(Lower));
247651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  O->pushOverlay(Upper);
248651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
249ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ErrorOr<vfs::Status> Status((std::error_code()));
250651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Lower->addDirectory("/both", sys::fs::owner_read);
251651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Upper->addDirectory("/both", sys::fs::owner_all | sys::fs::group_read);
252651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status = O->status("/both");
253ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(Status.getError());
254651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_EQ(0740, Status->getPermissions());
255651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
256651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // permissions (as usual) are not recursively applied
257651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Lower->addRegularFile("/both/foo", sys::fs::owner_read);
258651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Upper->addRegularFile("/both/bar", sys::fs::owner_write);
259651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status = O->status("/both/foo");
260ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE( Status.getError());
261651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_EQ(0400, Status->getPermissions());
262651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Status = O->status("/both/bar");
263ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(Status.getError());
264651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_EQ(0200, Status->getPermissions());
265651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
266651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
267ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesnamespace {
268ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesstruct ScopedDir {
269ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  SmallString<128> Path;
270ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ScopedDir(const Twine &Name, bool Unique=false) {
271ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    std::error_code EC;
272ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    if (Unique) {
273ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      EC =  llvm::sys::fs::createUniqueDirectory(Name, Path);
274ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    } else {
275ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      Path = Name.str();
276ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      EC = llvm::sys::fs::create_directory(Twine(Path));
277ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    }
278ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    if (EC)
279ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      Path = "";
280ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    EXPECT_FALSE(EC);
281ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
282ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ~ScopedDir() {
283ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    if (Path != "")
284ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      EXPECT_FALSE(llvm::sys::fs::remove(Path.str()));
285ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
286ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  operator StringRef() { return Path.str(); }
287ef8225444452a1486bd721f3285301fe84643b00Stephen Hines};
288ef8225444452a1486bd721f3285301fe84643b00Stephen Hines}
289ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
290ef8225444452a1486bd721f3285301fe84643b00Stephen HinesTEST(VirtualFileSystemTest, BasicRealFSIteration) {
291ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
292ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
293ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
294ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code EC;
295ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory), EC);
296ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(EC);
297ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(vfs::directory_iterator(), I); // empty directory is empty
298ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
299ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ScopedDir _a(TestDirectory+"/a");
300ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ScopedDir _ab(TestDirectory+"/a/b");
301ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ScopedDir _c(TestDirectory+"/c");
302ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ScopedDir _cd(TestDirectory+"/c/d");
303ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
304ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  I = FS->dir_begin(Twine(TestDirectory), EC);
305ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(EC);
306ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_NE(vfs::directory_iterator(), I);
307ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  // Check either a or c, since we can't rely on the iteration order.
308ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
309ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  I.increment(EC);
310ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(EC);
311ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_NE(vfs::directory_iterator(), I);
312ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_TRUE(I->getName().endswith("a") || I->getName().endswith("c"));
313ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  I.increment(EC);
314ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(vfs::directory_iterator(), I);
315ef8225444452a1486bd721f3285301fe84643b00Stephen Hines}
316ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
317ef8225444452a1486bd721f3285301fe84643b00Stephen HinesTEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
318ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ScopedDir TestDirectory("virtual-file-system-test", /*Unique*/true);
319ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
320ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
321ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code EC;
322ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  auto I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
323ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(EC);
324ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(vfs::recursive_directory_iterator(), I); // empty directory is empty
325ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
326ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ScopedDir _a(TestDirectory+"/a");
327ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ScopedDir _ab(TestDirectory+"/a/b");
328ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ScopedDir _c(TestDirectory+"/c");
329ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ScopedDir _cd(TestDirectory+"/c/d");
330ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
331ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory), EC);
332ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(EC);
333ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_NE(vfs::recursive_directory_iterator(), I);
334ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
335ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
336ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::vector<std::string> Contents;
337ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
338ef8225444452a1486bd721f3285301fe84643b00Stephen Hines       I.increment(EC)) {
339ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    Contents.push_back(I->getName());
340ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
341ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
342ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  // Check contents, which may be in any order
343ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(4U, Contents.size());
344ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  int Counts[4] = { 0, 0, 0, 0 };
345ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  for (const std::string &Name : Contents) {
346ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    ASSERT_FALSE(Name.empty());
347ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    int Index = Name[Name.size()-1] - 'a';
348ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    ASSERT_TRUE(Index >= 0 && Index < 4);
349ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    Counts[Index]++;
350ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
351ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(1, Counts[0]); // a
352ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(1, Counts[1]); // b
353ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(1, Counts[2]); // c
354ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(1, Counts[3]); // d
355ef8225444452a1486bd721f3285301fe84643b00Stephen Hines}
356ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
357ef8225444452a1486bd721f3285301fe84643b00Stephen Hinestemplate <typename T, size_t N>
358ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesstd::vector<StringRef> makeStringRefVector(const T (&Arr)[N]) {
359ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::vector<StringRef> Vec;
360ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  for (size_t i = 0; i != N; ++i)
361ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    Vec.push_back(Arr[i]);
362ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  return Vec;
363ef8225444452a1486bd721f3285301fe84643b00Stephen Hines}
364ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
365ef8225444452a1486bd721f3285301fe84643b00Stephen Hinestemplate <typename DirIter>
366ef8225444452a1486bd721f3285301fe84643b00Stephen Hinesstatic void checkContents(DirIter I, ArrayRef<StringRef> Expected) {
367ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code EC;
368ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  auto ExpectedIter = Expected.begin(), ExpectedEnd = Expected.end();
369ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  for (DirIter E;
370ef8225444452a1486bd721f3285301fe84643b00Stephen Hines       !EC && I != E && ExpectedIter != ExpectedEnd;
371ef8225444452a1486bd721f3285301fe84643b00Stephen Hines       I.increment(EC), ++ExpectedIter)
372ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    EXPECT_EQ(*ExpectedIter, I->getName());
373ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
374ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(ExpectedEnd, ExpectedIter);
375ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(DirIter(), I);
376ef8225444452a1486bd721f3285301fe84643b00Stephen Hines}
377ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
378ef8225444452a1486bd721f3285301fe84643b00Stephen HinesTEST(VirtualFileSystemTest, OverlayIteration) {
379ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
380ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
381ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
382ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      new vfs::OverlayFileSystem(Lower));
383ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  O->pushOverlay(Upper);
384ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
385ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code EC;
386ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
387ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
388ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Lower->addRegularFile("/file1");
389ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file1"));
390ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
391ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Upper->addRegularFile("/file2");
392ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  {
393ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    const char *Contents[] = {"/file2", "/file1"};
394ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
395ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
396ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
397ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Lower->addDirectory("/dir1");
398ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Lower->addRegularFile("/dir1/foo");
399ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Upper->addDirectory("/dir2");
400ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Upper->addRegularFile("/dir2/foo");
401ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  checkContents(O->dir_begin("/dir2", EC), ArrayRef<StringRef>("/dir2/foo"));
402ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  {
403ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    const char *Contents[] = {"/dir2", "/file2", "/dir1", "/file1"};
404ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
405ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
406ef8225444452a1486bd721f3285301fe84643b00Stephen Hines}
407ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
408ef8225444452a1486bd721f3285301fe84643b00Stephen HinesTEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
409ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
410ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
411ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
412ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
413ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      new vfs::OverlayFileSystem(Lower));
414ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  O->pushOverlay(Middle);
415ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  O->pushOverlay(Upper);
416ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
417ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code EC;
418ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
419ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                ArrayRef<StringRef>());
420ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
421ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Lower->addRegularFile("/file1");
422ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
423ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                ArrayRef<StringRef>("/file1"));
424ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
425ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Upper->addDirectory("/dir");
426ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Upper->addRegularFile("/dir/file2");
427ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  {
428ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    const char *Contents[] = {"/dir", "/dir/file2", "/file1"};
429ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
430ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                  makeStringRefVector(Contents));
431ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
432ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
433ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Lower->addDirectory("/dir1");
434ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Lower->addRegularFile("/dir1/foo");
435ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Lower->addDirectory("/dir1/a");
436ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Lower->addRegularFile("/dir1/a/b");
437ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Middle->addDirectory("/a");
438ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Middle->addDirectory("/a/b");
439ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Middle->addDirectory("/a/b/c");
440ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Middle->addRegularFile("/a/b/c/d");
441ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Middle->addRegularFile("/hiddenByUp");
442ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Upper->addDirectory("/dir2");
443ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Upper->addRegularFile("/dir2/foo");
444ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Upper->addRegularFile("/hiddenByUp");
445ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  checkContents(vfs::recursive_directory_iterator(*O, "/dir2", EC),
446ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                ArrayRef<StringRef>("/dir2/foo"));
447ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  {
448ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    const char *Contents[] = { "/dir", "/dir/file2", "/dir2", "/dir2/foo",
449ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        "/hiddenByUp", "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
450ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        "/dir1/a/b", "/dir1/foo", "/file1" };
451ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
452ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                  makeStringRefVector(Contents));
453ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
454ef8225444452a1486bd721f3285301fe84643b00Stephen Hines}
455ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
456ef8225444452a1486bd721f3285301fe84643b00Stephen HinesTEST(VirtualFileSystemTest, ThreeLevelIteration) {
457ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
458ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
459ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
460ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
461ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      new vfs::OverlayFileSystem(Lower));
462ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  O->pushOverlay(Middle);
463ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  O->pushOverlay(Upper);
464ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
465ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code EC;
466ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
467ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
468ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Middle->addRegularFile("/file2");
469ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file2"));
470ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
471ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Lower->addRegularFile("/file1");
472ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Upper->addRegularFile("/file3");
473ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  {
474ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    const char *Contents[] = {"/file3", "/file2", "/file1"};
475ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
476ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
477ef8225444452a1486bd721f3285301fe84643b00Stephen Hines}
478ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
479ef8225444452a1486bd721f3285301fe84643b00Stephen HinesTEST(VirtualFileSystemTest, HiddenInIteration) {
480ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
481ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
482ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
483ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
484ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      new vfs::OverlayFileSystem(Lower));
485ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  O->pushOverlay(Middle);
486ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  O->pushOverlay(Upper);
487ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
488ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code EC;
489ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Lower->addRegularFile("/onlyInLow", sys::fs::owner_read);
490ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Lower->addRegularFile("/hiddenByMid", sys::fs::owner_read);
491ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Lower->addRegularFile("/hiddenByUp", sys::fs::owner_read);
492ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Middle->addRegularFile("/onlyInMid", sys::fs::owner_write);
493ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Middle->addRegularFile("/hiddenByMid", sys::fs::owner_write);
494ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Middle->addRegularFile("/hiddenByUp", sys::fs::owner_write);
495ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Upper->addRegularFile("/onlyInUp", sys::fs::owner_all);
496ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Upper->addRegularFile("/hiddenByUp", sys::fs::owner_all);
497ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  {
498ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    const char *Contents[] = {"/hiddenByUp", "/onlyInUp", "/hiddenByMid",
499ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                              "/onlyInMid", "/onlyInLow"};
500ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    checkContents(O->dir_begin("/", EC), makeStringRefVector(Contents));
501ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
502ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
503ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  // Make sure we get the top-most entry
504ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  {
505ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    std::error_code EC;
506ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    vfs::directory_iterator I = O->dir_begin("/", EC), E;
507ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    for ( ; !EC && I != E; I.increment(EC))
508ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      if (I->getName() == "/hiddenByUp")
509ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        break;
510ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    ASSERT_NE(E, I);
511ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    EXPECT_EQ(sys::fs::owner_all, I->getPermissions());
512ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
513ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  {
514ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    std::error_code EC;
515ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    vfs::directory_iterator I = O->dir_begin("/", EC), E;
516ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    for ( ; !EC && I != E; I.increment(EC))
517ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      if (I->getName() == "/hiddenByMid")
518ef8225444452a1486bd721f3285301fe84643b00Stephen Hines        break;
519ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    ASSERT_NE(E, I);
520ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    EXPECT_EQ(sys::fs::owner_write, I->getPermissions());
521ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
522ef8225444452a1486bd721f3285301fe84643b00Stephen Hines}
523ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
524651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// NOTE: in the tests below, we use '//root/' as our root directory, since it is
525651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines// a legal *absolute* path on Windows as well as *nix.
526651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinesclass VFSFromYAMLTest : public ::testing::Test {
527651f13cea278ec967336033dd032faef0e9fc2ecStephen Hinespublic:
528651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  int NumDiagnostics;
529651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
530651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  void SetUp() {
531651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    NumDiagnostics = 0;
532651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
533651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
534651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
535651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
536651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    ++Test->NumDiagnostics;
537651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
538651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
539651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<vfs::FileSystem>
540651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  getFromYAMLRawString(StringRef Content,
541651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                       IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
542651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    MemoryBuffer *Buffer = MemoryBuffer::getMemBuffer(Content);
543651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return getVFSFromYAML(Buffer, CountingDiagHandler, this, ExternalFS);
544651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
545651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
546651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
547651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      StringRef Content,
548651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
549651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    std::string VersionPlusContent("{\n  'version':0,\n");
550651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
551651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines    return getFromYAMLRawString(VersionPlusContent, ExternalFS);
552651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  }
553651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines};
554651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
555651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesTEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
556651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<vfs::FileSystem> FS;
557651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString("");
558ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
559651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString("[]");
560ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
561651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString("'string'");
562ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
563651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_EQ(3, NumDiagnostics);
564651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
565651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
566651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesTEST_F(VFSFromYAMLTest, MappedFiles) {
567651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
568651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Lower->addRegularFile("//root/foo/bar/a");
569651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<vfs::FileSystem> FS =
570651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      getFromYAMLString("{ 'roots': [\n"
571651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "{\n"
572651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "  'type': 'directory',\n"
573651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "  'name': '//root/',\n"
574651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "  'contents': [ {\n"
575651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "                  'type': 'file',\n"
576651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "                  'name': 'file1',\n"
577651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "                  'external-contents': '//root/foo/bar/a'\n"
578651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "                },\n"
579651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "                {\n"
580651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "                  'type': 'file',\n"
581651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "                  'name': 'file2',\n"
582651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "                  'external-contents': '//root/foo/b'\n"
583651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "                }\n"
584651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "              ]\n"
585651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "}\n"
586651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "]\n"
587651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "}",
588651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        Lower);
589ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_TRUE(FS.get() != nullptr);
590651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
591651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
592651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      new vfs::OverlayFileSystem(Lower));
593651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  O->pushOverlay(FS);
594651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
595651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // file
596651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<vfs::Status> S = O->status("//root/file1");
597ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(S.getError());
598651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_EQ("//root/foo/bar/a", S->getName());
599651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
600651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
601651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_EQ("//root/foo/bar/a", SLower->getName());
602651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(S->equivalent(*SLower));
603651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
604651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // directory
605651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  S = O->status("//root/");
606ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(S.getError());
607651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(S->isDirectory());
608651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
609651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
610651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // broken mapping
611ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(O->status("//root/file2").getError(),
612ef8225444452a1486bd721f3285301fe84643b00Stephen Hines            llvm::errc::no_such_file_or_directory);
613651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_EQ(0, NumDiagnostics);
614651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
615651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
616651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesTEST_F(VFSFromYAMLTest, CaseInsensitive) {
617651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
618651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Lower->addRegularFile("//root/foo/bar/a");
619651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<vfs::FileSystem> FS =
620651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      getFromYAMLString("{ 'case-sensitive': 'false',\n"
621651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "  'roots': [\n"
622651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "{\n"
623651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "  'type': 'directory',\n"
624651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "  'name': '//root/',\n"
625651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "  'contents': [ {\n"
626651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "                  'type': 'file',\n"
627651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "                  'name': 'XX',\n"
628651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "                  'external-contents': '//root/foo/bar/a'\n"
629651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "                }\n"
630651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "              ]\n"
631651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "}]}",
632651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        Lower);
633ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_TRUE(FS.get() != nullptr);
634651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
635651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
636651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      new vfs::OverlayFileSystem(Lower));
637651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  O->pushOverlay(FS);
638651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
639651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<vfs::Status> S = O->status("//root/XX");
640ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(S.getError());
641651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
642651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<vfs::Status> SS = O->status("//root/xx");
643ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_FALSE(SS.getError());
644651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(S->equivalent(*SS));
645651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  SS = O->status("//root/xX");
646651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(S->equivalent(*SS));
647651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  SS = O->status("//root/Xx");
648651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_TRUE(S->equivalent(*SS));
649651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_EQ(0, NumDiagnostics);
650651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
651651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
652651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesTEST_F(VFSFromYAMLTest, CaseSensitive) {
653651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
654651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Lower->addRegularFile("//root/foo/bar/a");
655651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<vfs::FileSystem> FS =
656651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      getFromYAMLString("{ 'case-sensitive': 'true',\n"
657651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "  'roots': [\n"
658651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "{\n"
659651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "  'type': 'directory',\n"
660651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "  'name': '//root/',\n"
661651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "  'contents': [ {\n"
662651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "                  'type': 'file',\n"
663651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "                  'name': 'XX',\n"
664651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "                  'external-contents': '//root/foo/bar/a'\n"
665651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "                }\n"
666651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "              ]\n"
667651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "}]}",
668651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        Lower);
669ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_TRUE(FS.get() != nullptr);
670651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
671651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
672651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      new vfs::OverlayFileSystem(Lower));
673651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  O->pushOverlay(FS);
674651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
675651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  ErrorOr<vfs::Status> SS = O->status("//root/xx");
676ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
677651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  SS = O->status("//root/xX");
678ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
679651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  SS = O->status("//root/Xx");
680ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
681651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_EQ(0, NumDiagnostics);
682651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
683651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
684651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesTEST_F(VFSFromYAMLTest, IllegalVFSFile) {
685651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
686651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
687651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // invalid YAML at top-level
688651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
689ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
690651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // invalid YAML in roots
691651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString("{ 'roots':[}", Lower);
692651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // invalid YAML in directory
693651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString(
694651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
695651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Lower);
696ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
697651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
698651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // invalid configuration
699651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
700ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
701651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
702ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
703651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
704651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // invalid roots
705651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString("{ 'roots':'' }", Lower);
706ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
707651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString("{ 'roots':{} }", Lower);
708ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
709651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
710651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // invalid entries
711651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString(
712651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
713ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
714651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
715651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                         "'external-contents': 'other' }",
716651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                         Lower);
717ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
718651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString(
719651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
720651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Lower);
721ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
722651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString(
723651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
724651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Lower);
725ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
726651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString(
727651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
728651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Lower);
729ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
730651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString(
731651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
732651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Lower);
733ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
734651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString(
735651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
736651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Lower);
737ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
738651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
739651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // missing mandatory fields
740651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
741ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
742651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString(
743651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
744ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
745651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
746ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
747651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
748651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // duplicate keys
749651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
750ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
751651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString(
752651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
753651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      Lower);
754ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
755651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS =
756651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
757651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        "'external-contents':'blah' } ] }",
758651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines                        Lower);
759ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
760651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
761651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // missing version
762651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
763ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
764651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
765651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // bad version number
766651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
767ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
768651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
769ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
770651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
771ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_EQ(nullptr, FS.get());
772651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_EQ(24, NumDiagnostics);
773651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
774651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
775651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesTEST_F(VFSFromYAMLTest, UseExternalName) {
776651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
777651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Lower->addRegularFile("//root/external/file");
778651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
779651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
780651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "{ 'roots': [\n"
781651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  { 'type': 'file', 'name': '//root/A',\n"
782651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "    'external-contents': '//root/external/file'\n"
783651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  },\n"
784651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  { 'type': 'file', 'name': '//root/B',\n"
785651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "    'use-external-name': true,\n"
786651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "    'external-contents': '//root/external/file'\n"
787651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  },\n"
788651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  { 'type': 'file', 'name': '//root/C',\n"
789651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "    'use-external-name': false,\n"
790651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "    'external-contents': '//root/external/file'\n"
791651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  }\n"
792651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "] }", Lower);
793ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_TRUE(nullptr != FS.get());
794651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
795651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // default true
796651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
797651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // explicit
798651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
799651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
800651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
801651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // global configuration
802651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString(
803651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "{ 'use-external-names': false,\n"
804651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  'roots': [\n"
805651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  { 'type': 'file', 'name': '//root/A',\n"
806651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "    'external-contents': '//root/external/file'\n"
807651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  },\n"
808651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  { 'type': 'file', 'name': '//root/B',\n"
809651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "    'use-external-name': true,\n"
810651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "    'external-contents': '//root/external/file'\n"
811651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  },\n"
812651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  { 'type': 'file', 'name': '//root/C',\n"
813651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "    'use-external-name': false,\n"
814651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "    'external-contents': '//root/external/file'\n"
815651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  }\n"
816651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "] }", Lower);
817ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_TRUE(nullptr != FS.get());
818651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
819651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // default
820651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
821651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // explicit
822651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
823651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
824651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
825651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
826651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesTEST_F(VFSFromYAMLTest, MultiComponentPath) {
827651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
828651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Lower->addRegularFile("//root/other");
829651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
830651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // file in roots
831651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
832651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "{ 'roots': [\n"
833651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  { 'type': 'file', 'name': '//root/path/to/file',\n"
834651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "    'external-contents': '//root/other' }]\n"
835651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "}", Lower);
836ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_TRUE(nullptr != FS.get());
837ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_FALSE(FS->status("//root/path/to/file").getError());
838ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_FALSE(FS->status("//root/path/to").getError());
839ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_FALSE(FS->status("//root/path").getError());
840ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_FALSE(FS->status("//root/").getError());
841651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
842651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // at the start
843651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString(
844651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "{ 'roots': [\n"
845651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  { 'type': 'directory', 'name': '//root/path/to',\n"
846651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "    'contents': [ { 'type': 'file', 'name': 'file',\n"
847651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "                    'external-contents': '//root/other' }]}]\n"
848651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "}", Lower);
849ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_TRUE(nullptr != FS.get());
850ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_FALSE(FS->status("//root/path/to/file").getError());
851ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_FALSE(FS->status("//root/path/to").getError());
852ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_FALSE(FS->status("//root/path").getError());
853ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_FALSE(FS->status("//root/").getError());
854651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
855651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // at the end
856651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  FS = getFromYAMLString(
857651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "{ 'roots': [\n"
858651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  { 'type': 'directory', 'name': '//root/',\n"
859651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "    'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
860651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "                    'external-contents': '//root/other' }]}]\n"
861651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "}", Lower);
862ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_TRUE(nullptr != FS.get());
863ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_FALSE(FS->status("//root/path/to/file").getError());
864ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_FALSE(FS->status("//root/path/to").getError());
865ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_FALSE(FS->status("//root/path").getError());
866ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_FALSE(FS->status("//root/").getError());
867651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
868651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
869651f13cea278ec967336033dd032faef0e9fc2ecStephen HinesTEST_F(VFSFromYAMLTest, TrailingSlashes) {
870651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
871651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  Lower->addRegularFile("//root/other");
872651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines
873651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  // file in roots
874651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines  IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
875651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "{ 'roots': [\n"
876651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "  { 'type': 'directory', 'name': '//root/path/to////',\n"
877651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "    'contents': [ { 'type': 'file', 'name': 'file',\n"
878651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "                    'external-contents': '//root/other' }]}]\n"
879651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines      "}", Lower);
880ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_TRUE(nullptr != FS.get());
881ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_FALSE(FS->status("//root/path/to/file").getError());
882ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_FALSE(FS->status("//root/path/to").getError());
883ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_FALSE(FS->status("//root/path").getError());
884ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  EXPECT_FALSE(FS->status("//root/").getError());
885ef8225444452a1486bd721f3285301fe84643b00Stephen Hines}
886ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
887ef8225444452a1486bd721f3285301fe84643b00Stephen HinesTEST_F(VFSFromYAMLTest, DirectoryIteration) {
888ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
889ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Lower->addDirectory("//root/");
890ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Lower->addDirectory("//root/foo");
891ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Lower->addDirectory("//root/foo/bar");
892ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Lower->addRegularFile("//root/foo/bar/a");
893ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Lower->addRegularFile("//root/foo/bar/b");
894ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  Lower->addRegularFile("//root/file3");
895ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<vfs::FileSystem> FS =
896ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  getFromYAMLString("{ 'use-external-names': false,\n"
897ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                    "  'roots': [\n"
898ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                    "{\n"
899ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                    "  'type': 'directory',\n"
900ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                    "  'name': '//root/',\n"
901ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                    "  'contents': [ {\n"
902ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                    "                  'type': 'file',\n"
903ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                    "                  'name': 'file1',\n"
904ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                    "                  'external-contents': '//root/foo/bar/a'\n"
905ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                    "                },\n"
906ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                    "                {\n"
907ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                    "                  'type': 'file',\n"
908ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                    "                  'name': 'file2',\n"
909ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                    "                  'external-contents': '//root/foo/bar/b'\n"
910ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                    "                }\n"
911ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                    "              ]\n"
912ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                    "}\n"
913ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                    "]\n"
914ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                    "}",
915ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                    Lower);
916ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  ASSERT_TRUE(FS.get() != NULL);
917ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
918ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
919ef8225444452a1486bd721f3285301fe84643b00Stephen Hines      new vfs::OverlayFileSystem(Lower));
920ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  O->pushOverlay(FS);
921ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
922ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  std::error_code EC;
923ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  {
924ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    const char *Contents[] = {"//root/file1", "//root/file2", "//root/file3",
925ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                              "//root/foo"};
926ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    checkContents(O->dir_begin("//root/", EC), makeStringRefVector(Contents));
927ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
928ef8225444452a1486bd721f3285301fe84643b00Stephen Hines
929ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  {
930ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    const char *Contents[] = {"//root/foo/bar/a", "//root/foo/bar/b"};
931ef8225444452a1486bd721f3285301fe84643b00Stephen Hines    checkContents(O->dir_begin("//root/foo/bar", EC),
932ef8225444452a1486bd721f3285301fe84643b00Stephen Hines                  makeStringRefVector(Contents));
933ef8225444452a1486bd721f3285301fe84643b00Stephen Hines  }
934651f13cea278ec967336033dd032faef0e9fc2ecStephen Hines}
935