1fc51490bSJonas Devlieghere //===- unittests/Support/VirtualFileSystem.cpp -------------- VFS tests ---===//
2fc51490bSJonas Devlieghere //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fc51490bSJonas Devlieghere //
7fc51490bSJonas Devlieghere //===----------------------------------------------------------------------===//
8fc51490bSJonas Devlieghere 
9fc51490bSJonas Devlieghere #include "llvm/Support/VirtualFileSystem.h"
10fc51490bSJonas Devlieghere #include "llvm/ADT/Triple.h"
11fc51490bSJonas Devlieghere #include "llvm/Config/llvm-config.h"
12fc51490bSJonas Devlieghere #include "llvm/Support/Errc.h"
13fc51490bSJonas Devlieghere #include "llvm/Support/Host.h"
14fc51490bSJonas Devlieghere #include "llvm/Support/MemoryBuffer.h"
15fc51490bSJonas Devlieghere #include "llvm/Support/Path.h"
16fc51490bSJonas Devlieghere #include "llvm/Support/SourceMgr.h"
17fad75598SSergej Jaskiewicz #include "llvm/Testing/Support/SupportHelpers.h"
18fc51490bSJonas Devlieghere #include "gmock/gmock.h"
19fc51490bSJonas Devlieghere #include "gtest/gtest.h"
20fc51490bSJonas Devlieghere #include <map>
21fc51490bSJonas Devlieghere #include <string>
22fc51490bSJonas Devlieghere 
23fc51490bSJonas Devlieghere using namespace llvm;
24fc51490bSJonas Devlieghere using llvm::sys::fs::UniqueID;
25fad75598SSergej Jaskiewicz using llvm::unittest::TempDir;
26fad75598SSergej Jaskiewicz using llvm::unittest::TempFile;
27fad75598SSergej Jaskiewicz using llvm::unittest::TempLink;
28fc51490bSJonas Devlieghere using testing::ElementsAre;
29fc51490bSJonas Devlieghere using testing::Pair;
30fc51490bSJonas Devlieghere using testing::UnorderedElementsAre;
31fc51490bSJonas Devlieghere 
32fc51490bSJonas Devlieghere namespace {
33fc51490bSJonas Devlieghere struct DummyFile : public vfs::File {
34fc51490bSJonas Devlieghere   vfs::Status S;
35fc51490bSJonas Devlieghere   explicit DummyFile(vfs::Status S) : S(S) {}
36fc51490bSJonas Devlieghere   llvm::ErrorOr<vfs::Status> status() override { return S; }
37fc51490bSJonas Devlieghere   llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
38fc51490bSJonas Devlieghere   getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,
39fc51490bSJonas Devlieghere             bool IsVolatile) override {
40fc51490bSJonas Devlieghere     llvm_unreachable("unimplemented");
41fc51490bSJonas Devlieghere   }
42fc51490bSJonas Devlieghere   std::error_code close() override { return std::error_code(); }
43fc51490bSJonas Devlieghere };
44fc51490bSJonas Devlieghere 
45fc51490bSJonas Devlieghere class DummyFileSystem : public vfs::FileSystem {
46fc51490bSJonas Devlieghere   int FSID;   // used to produce UniqueIDs
47fc51490bSJonas Devlieghere   int FileID; // used to produce UniqueIDs
4821703543SJonas Devlieghere   std::string WorkingDirectory;
49fc51490bSJonas Devlieghere   std::map<std::string, vfs::Status> FilesAndDirs;
5021703543SJonas Devlieghere   typedef std::map<std::string, vfs::Status>::const_iterator const_iterator;
51fc51490bSJonas Devlieghere 
52fc51490bSJonas Devlieghere   static int getNextFSID() {
53fc51490bSJonas Devlieghere     static int Count = 0;
54fc51490bSJonas Devlieghere     return Count++;
55fc51490bSJonas Devlieghere   }
56fc51490bSJonas Devlieghere 
57fc51490bSJonas Devlieghere public:
58fc51490bSJonas Devlieghere   DummyFileSystem() : FSID(getNextFSID()), FileID(0) {}
59fc51490bSJonas Devlieghere 
60fc51490bSJonas Devlieghere   ErrorOr<vfs::Status> status(const Twine &Path) override {
6121703543SJonas Devlieghere     auto I = findEntry(Path);
62fc51490bSJonas Devlieghere     if (I == FilesAndDirs.end())
63fc51490bSJonas Devlieghere       return make_error_code(llvm::errc::no_such_file_or_directory);
64fc51490bSJonas Devlieghere     return I->second;
65fc51490bSJonas Devlieghere   }
66fc51490bSJonas Devlieghere   ErrorOr<std::unique_ptr<vfs::File>>
67fc51490bSJonas Devlieghere   openFileForRead(const Twine &Path) override {
68fc51490bSJonas Devlieghere     auto S = status(Path);
69fc51490bSJonas Devlieghere     if (S)
70fc51490bSJonas Devlieghere       return std::unique_ptr<vfs::File>(new DummyFile{*S});
71fc51490bSJonas Devlieghere     return S.getError();
72fc51490bSJonas Devlieghere   }
73fc51490bSJonas Devlieghere   llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {
7421703543SJonas Devlieghere     return WorkingDirectory;
75fc51490bSJonas Devlieghere   }
76fc51490bSJonas Devlieghere   std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
7721703543SJonas Devlieghere     WorkingDirectory = Path.str();
78fc51490bSJonas Devlieghere     return std::error_code();
79fc51490bSJonas Devlieghere   }
80fc51490bSJonas Devlieghere   // Map any symlink to "/symlink".
8199538e89SSam McCall   std::error_code getRealPath(const Twine &Path,
8299538e89SSam McCall                               SmallVectorImpl<char> &Output) const override {
8321703543SJonas Devlieghere     auto I = findEntry(Path);
84fc51490bSJonas Devlieghere     if (I == FilesAndDirs.end())
85fc51490bSJonas Devlieghere       return make_error_code(llvm::errc::no_such_file_or_directory);
86fc51490bSJonas Devlieghere     if (I->second.isSymlink()) {
87fc51490bSJonas Devlieghere       Output.clear();
88fc51490bSJonas Devlieghere       Twine("/symlink").toVector(Output);
89fc51490bSJonas Devlieghere       return std::error_code();
90fc51490bSJonas Devlieghere     }
91fc51490bSJonas Devlieghere     Output.clear();
92fc51490bSJonas Devlieghere     Path.toVector(Output);
93fc51490bSJonas Devlieghere     return std::error_code();
94fc51490bSJonas Devlieghere   }
95fc51490bSJonas Devlieghere 
96fc51490bSJonas Devlieghere   struct DirIterImpl : public llvm::vfs::detail::DirIterImpl {
97fc51490bSJonas Devlieghere     std::map<std::string, vfs::Status> &FilesAndDirs;
98fc51490bSJonas Devlieghere     std::map<std::string, vfs::Status>::iterator I;
99fc51490bSJonas Devlieghere     std::string Path;
100fc51490bSJonas Devlieghere     bool isInPath(StringRef S) {
101fc51490bSJonas Devlieghere       if (Path.size() < S.size() && S.find(Path) == 0) {
102fc51490bSJonas Devlieghere         auto LastSep = S.find_last_of('/');
103fc51490bSJonas Devlieghere         if (LastSep == Path.size() || LastSep == Path.size() - 1)
104fc51490bSJonas Devlieghere           return true;
105fc51490bSJonas Devlieghere       }
106fc51490bSJonas Devlieghere       return false;
107fc51490bSJonas Devlieghere     }
108fc51490bSJonas Devlieghere     DirIterImpl(std::map<std::string, vfs::Status> &FilesAndDirs,
109fc51490bSJonas Devlieghere                 const Twine &_Path)
110fc51490bSJonas Devlieghere         : FilesAndDirs(FilesAndDirs), I(FilesAndDirs.begin()),
111fc51490bSJonas Devlieghere           Path(_Path.str()) {
112fc51490bSJonas Devlieghere       for (; I != FilesAndDirs.end(); ++I) {
113fc51490bSJonas Devlieghere         if (isInPath(I->first)) {
114adcd0268SBenjamin Kramer           CurrentEntry = vfs::directory_entry(std::string(I->second.getName()),
115adcd0268SBenjamin Kramer                                               I->second.getType());
116fc51490bSJonas Devlieghere           break;
117fc51490bSJonas Devlieghere         }
118fc51490bSJonas Devlieghere       }
119fc51490bSJonas Devlieghere     }
120fc51490bSJonas Devlieghere     std::error_code increment() override {
121fc51490bSJonas Devlieghere       ++I;
122fc51490bSJonas Devlieghere       for (; I != FilesAndDirs.end(); ++I) {
123fc51490bSJonas Devlieghere         if (isInPath(I->first)) {
124adcd0268SBenjamin Kramer           CurrentEntry = vfs::directory_entry(std::string(I->second.getName()),
125adcd0268SBenjamin Kramer                                               I->second.getType());
126fc51490bSJonas Devlieghere           break;
127fc51490bSJonas Devlieghere         }
128fc51490bSJonas Devlieghere       }
129fc51490bSJonas Devlieghere       if (I == FilesAndDirs.end())
130fc51490bSJonas Devlieghere         CurrentEntry = vfs::directory_entry();
131fc51490bSJonas Devlieghere       return std::error_code();
132fc51490bSJonas Devlieghere     }
133fc51490bSJonas Devlieghere   };
134fc51490bSJonas Devlieghere 
135fc51490bSJonas Devlieghere   vfs::directory_iterator dir_begin(const Twine &Dir,
136fc51490bSJonas Devlieghere                                     std::error_code &EC) override {
137fc51490bSJonas Devlieghere     return vfs::directory_iterator(
138fc51490bSJonas Devlieghere         std::make_shared<DirIterImpl>(FilesAndDirs, Dir));
139fc51490bSJonas Devlieghere   }
140fc51490bSJonas Devlieghere 
141fc51490bSJonas Devlieghere   void addEntry(StringRef Path, const vfs::Status &Status) {
142adcd0268SBenjamin Kramer     FilesAndDirs[std::string(Path)] = Status;
143fc51490bSJonas Devlieghere   }
144fc51490bSJonas Devlieghere 
14521703543SJonas Devlieghere   const_iterator findEntry(const Twine &Path) const {
14621703543SJonas Devlieghere     SmallString<128> P;
14721703543SJonas Devlieghere     Path.toVector(P);
14821703543SJonas Devlieghere     std::error_code EC = makeAbsolute(P);
14921703543SJonas Devlieghere     assert(!EC);
150a3378063SDavid L. Jones     (void)EC;
151adcd0268SBenjamin Kramer     return FilesAndDirs.find(std::string(P.str()));
15221703543SJonas Devlieghere   }
15321703543SJonas Devlieghere 
154fc51490bSJonas Devlieghere   void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
155fc51490bSJonas Devlieghere     vfs::Status S(Path, UniqueID(FSID, FileID++),
156fc51490bSJonas Devlieghere                   std::chrono::system_clock::now(), 0, 0, 1024,
157fc51490bSJonas Devlieghere                   sys::fs::file_type::regular_file, Perms);
158fc51490bSJonas Devlieghere     addEntry(Path, S);
159fc51490bSJonas Devlieghere   }
160fc51490bSJonas Devlieghere 
161fc51490bSJonas Devlieghere   void addDirectory(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
162fc51490bSJonas Devlieghere     vfs::Status S(Path, UniqueID(FSID, FileID++),
163fc51490bSJonas Devlieghere                   std::chrono::system_clock::now(), 0, 0, 0,
164fc51490bSJonas Devlieghere                   sys::fs::file_type::directory_file, Perms);
165fc51490bSJonas Devlieghere     addEntry(Path, S);
166fc51490bSJonas Devlieghere   }
167fc51490bSJonas Devlieghere 
168fc51490bSJonas Devlieghere   void addSymlink(StringRef Path) {
169fc51490bSJonas Devlieghere     vfs::Status S(Path, UniqueID(FSID, FileID++),
170fc51490bSJonas Devlieghere                   std::chrono::system_clock::now(), 0, 0, 0,
171fc51490bSJonas Devlieghere                   sys::fs::file_type::symlink_file, sys::fs::all_all);
172fc51490bSJonas Devlieghere     addEntry(Path, S);
173fc51490bSJonas Devlieghere   }
174fc51490bSJonas Devlieghere };
175fc51490bSJonas Devlieghere 
17621703543SJonas Devlieghere class ErrorDummyFileSystem : public DummyFileSystem {
17721703543SJonas Devlieghere   std::error_code setCurrentWorkingDirectory(const Twine &Path) override {
17821703543SJonas Devlieghere     return llvm::errc::no_such_file_or_directory;
17921703543SJonas Devlieghere   }
18021703543SJonas Devlieghere };
18121703543SJonas Devlieghere 
182fc51490bSJonas Devlieghere /// Replace back-slashes by front-slashes.
183fc51490bSJonas Devlieghere std::string getPosixPath(std::string S) {
184fc51490bSJonas Devlieghere   SmallString<128> Result;
185fc51490bSJonas Devlieghere   llvm::sys::path::native(S, Result, llvm::sys::path::Style::posix);
186adcd0268SBenjamin Kramer   return std::string(Result.str());
187fc51490bSJonas Devlieghere }
188fc51490bSJonas Devlieghere } // end anonymous namespace
189fc51490bSJonas Devlieghere 
190fc51490bSJonas Devlieghere TEST(VirtualFileSystemTest, StatusQueries) {
191fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
192fc51490bSJonas Devlieghere   ErrorOr<vfs::Status> Status((std::error_code()));
193fc51490bSJonas Devlieghere 
194fc51490bSJonas Devlieghere   D->addRegularFile("/foo");
195fc51490bSJonas Devlieghere   Status = D->status("/foo");
196fc51490bSJonas Devlieghere   ASSERT_FALSE(Status.getError());
197fc51490bSJonas Devlieghere   EXPECT_TRUE(Status->isStatusKnown());
198fc51490bSJonas Devlieghere   EXPECT_FALSE(Status->isDirectory());
199fc51490bSJonas Devlieghere   EXPECT_TRUE(Status->isRegularFile());
200fc51490bSJonas Devlieghere   EXPECT_FALSE(Status->isSymlink());
201fc51490bSJonas Devlieghere   EXPECT_FALSE(Status->isOther());
202fc51490bSJonas Devlieghere   EXPECT_TRUE(Status->exists());
203fc51490bSJonas Devlieghere 
204fc51490bSJonas Devlieghere   D->addDirectory("/bar");
205fc51490bSJonas Devlieghere   Status = D->status("/bar");
206fc51490bSJonas Devlieghere   ASSERT_FALSE(Status.getError());
207fc51490bSJonas Devlieghere   EXPECT_TRUE(Status->isStatusKnown());
208fc51490bSJonas Devlieghere   EXPECT_TRUE(Status->isDirectory());
209fc51490bSJonas Devlieghere   EXPECT_FALSE(Status->isRegularFile());
210fc51490bSJonas Devlieghere   EXPECT_FALSE(Status->isSymlink());
211fc51490bSJonas Devlieghere   EXPECT_FALSE(Status->isOther());
212fc51490bSJonas Devlieghere   EXPECT_TRUE(Status->exists());
213fc51490bSJonas Devlieghere 
214fc51490bSJonas Devlieghere   D->addSymlink("/baz");
215fc51490bSJonas Devlieghere   Status = D->status("/baz");
216fc51490bSJonas Devlieghere   ASSERT_FALSE(Status.getError());
217fc51490bSJonas Devlieghere   EXPECT_TRUE(Status->isStatusKnown());
218fc51490bSJonas Devlieghere   EXPECT_FALSE(Status->isDirectory());
219fc51490bSJonas Devlieghere   EXPECT_FALSE(Status->isRegularFile());
220fc51490bSJonas Devlieghere   EXPECT_TRUE(Status->isSymlink());
221fc51490bSJonas Devlieghere   EXPECT_FALSE(Status->isOther());
222fc51490bSJonas Devlieghere   EXPECT_TRUE(Status->exists());
223fc51490bSJonas Devlieghere 
224fc51490bSJonas Devlieghere   EXPECT_TRUE(Status->equivalent(*Status));
225fc51490bSJonas Devlieghere   ErrorOr<vfs::Status> Status2 = D->status("/foo");
226fc51490bSJonas Devlieghere   ASSERT_FALSE(Status2.getError());
227fc51490bSJonas Devlieghere   EXPECT_FALSE(Status->equivalent(*Status2));
228fc51490bSJonas Devlieghere }
229fc51490bSJonas Devlieghere 
230fc51490bSJonas Devlieghere TEST(VirtualFileSystemTest, BaseOnlyOverlay) {
231fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> D(new DummyFileSystem());
232fc51490bSJonas Devlieghere   ErrorOr<vfs::Status> Status((std::error_code()));
233fc51490bSJonas Devlieghere   EXPECT_FALSE(Status = D->status("/foo"));
234fc51490bSJonas Devlieghere 
235fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(new vfs::OverlayFileSystem(D));
236fc51490bSJonas Devlieghere   EXPECT_FALSE(Status = O->status("/foo"));
237fc51490bSJonas Devlieghere 
238fc51490bSJonas Devlieghere   D->addRegularFile("/foo");
239fc51490bSJonas Devlieghere   Status = D->status("/foo");
240fc51490bSJonas Devlieghere   EXPECT_FALSE(Status.getError());
241fc51490bSJonas Devlieghere 
242fc51490bSJonas Devlieghere   ErrorOr<vfs::Status> Status2((std::error_code()));
243fc51490bSJonas Devlieghere   Status2 = O->status("/foo");
244fc51490bSJonas Devlieghere   EXPECT_FALSE(Status2.getError());
245fc51490bSJonas Devlieghere   EXPECT_TRUE(Status->equivalent(*Status2));
246fc51490bSJonas Devlieghere }
247fc51490bSJonas Devlieghere 
248fc51490bSJonas Devlieghere TEST(VirtualFileSystemTest, GetRealPathInOverlay) {
249fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
250fc51490bSJonas Devlieghere   Lower->addRegularFile("/foo");
251fc51490bSJonas Devlieghere   Lower->addSymlink("/lower_link");
252fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
253fc51490bSJonas Devlieghere 
254fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
255fc51490bSJonas Devlieghere       new vfs::OverlayFileSystem(Lower));
256fc51490bSJonas Devlieghere   O->pushOverlay(Upper);
257fc51490bSJonas Devlieghere 
258fc51490bSJonas Devlieghere   // Regular file.
259fc51490bSJonas Devlieghere   SmallString<16> RealPath;
260fc51490bSJonas Devlieghere   EXPECT_FALSE(O->getRealPath("/foo", RealPath));
261fc51490bSJonas Devlieghere   EXPECT_EQ(RealPath.str(), "/foo");
262fc51490bSJonas Devlieghere 
263fc51490bSJonas Devlieghere   // Expect no error getting real path for symlink in lower overlay.
264fc51490bSJonas Devlieghere   EXPECT_FALSE(O->getRealPath("/lower_link", RealPath));
265fc51490bSJonas Devlieghere   EXPECT_EQ(RealPath.str(), "/symlink");
266fc51490bSJonas Devlieghere 
267fc51490bSJonas Devlieghere   // Try a non-existing link.
268fc51490bSJonas Devlieghere   EXPECT_EQ(O->getRealPath("/upper_link", RealPath),
269fc51490bSJonas Devlieghere             errc::no_such_file_or_directory);
270fc51490bSJonas Devlieghere 
271fc51490bSJonas Devlieghere   // Add a new symlink in upper.
272fc51490bSJonas Devlieghere   Upper->addSymlink("/upper_link");
273fc51490bSJonas Devlieghere   EXPECT_FALSE(O->getRealPath("/upper_link", RealPath));
274fc51490bSJonas Devlieghere   EXPECT_EQ(RealPath.str(), "/symlink");
275fc51490bSJonas Devlieghere }
276fc51490bSJonas Devlieghere 
277fc51490bSJonas Devlieghere TEST(VirtualFileSystemTest, OverlayFiles) {
278fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Base(new DummyFileSystem());
279fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
280fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Top(new DummyFileSystem());
281fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
282fc51490bSJonas Devlieghere       new vfs::OverlayFileSystem(Base));
283fc51490bSJonas Devlieghere   O->pushOverlay(Middle);
284fc51490bSJonas Devlieghere   O->pushOverlay(Top);
285fc51490bSJonas Devlieghere 
286fc51490bSJonas Devlieghere   ErrorOr<vfs::Status> Status1((std::error_code())),
287fc51490bSJonas Devlieghere       Status2((std::error_code())), Status3((std::error_code())),
288fc51490bSJonas Devlieghere       StatusB((std::error_code())), StatusM((std::error_code())),
289fc51490bSJonas Devlieghere       StatusT((std::error_code()));
290fc51490bSJonas Devlieghere 
291fc51490bSJonas Devlieghere   Base->addRegularFile("/foo");
292fc51490bSJonas Devlieghere   StatusB = Base->status("/foo");
293fc51490bSJonas Devlieghere   ASSERT_FALSE(StatusB.getError());
294fc51490bSJonas Devlieghere   Status1 = O->status("/foo");
295fc51490bSJonas Devlieghere   ASSERT_FALSE(Status1.getError());
296fc51490bSJonas Devlieghere   Middle->addRegularFile("/foo");
297fc51490bSJonas Devlieghere   StatusM = Middle->status("/foo");
298fc51490bSJonas Devlieghere   ASSERT_FALSE(StatusM.getError());
299fc51490bSJonas Devlieghere   Status2 = O->status("/foo");
300fc51490bSJonas Devlieghere   ASSERT_FALSE(Status2.getError());
301fc51490bSJonas Devlieghere   Top->addRegularFile("/foo");
302fc51490bSJonas Devlieghere   StatusT = Top->status("/foo");
303fc51490bSJonas Devlieghere   ASSERT_FALSE(StatusT.getError());
304fc51490bSJonas Devlieghere   Status3 = O->status("/foo");
305fc51490bSJonas Devlieghere   ASSERT_FALSE(Status3.getError());
306fc51490bSJonas Devlieghere 
307fc51490bSJonas Devlieghere   EXPECT_TRUE(Status1->equivalent(*StatusB));
308fc51490bSJonas Devlieghere   EXPECT_TRUE(Status2->equivalent(*StatusM));
309fc51490bSJonas Devlieghere   EXPECT_TRUE(Status3->equivalent(*StatusT));
310fc51490bSJonas Devlieghere 
311fc51490bSJonas Devlieghere   EXPECT_FALSE(Status1->equivalent(*Status2));
312fc51490bSJonas Devlieghere   EXPECT_FALSE(Status2->equivalent(*Status3));
313fc51490bSJonas Devlieghere   EXPECT_FALSE(Status1->equivalent(*Status3));
314fc51490bSJonas Devlieghere }
315fc51490bSJonas Devlieghere 
316fc51490bSJonas Devlieghere TEST(VirtualFileSystemTest, OverlayDirsNonMerged) {
317fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
318fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
319fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
320fc51490bSJonas Devlieghere       new vfs::OverlayFileSystem(Lower));
321fc51490bSJonas Devlieghere   O->pushOverlay(Upper);
322fc51490bSJonas Devlieghere 
323fc51490bSJonas Devlieghere   Lower->addDirectory("/lower-only");
324fc51490bSJonas Devlieghere   Upper->addDirectory("/upper-only");
325fc51490bSJonas Devlieghere 
326fc51490bSJonas Devlieghere   // non-merged paths should be the same
327fc51490bSJonas Devlieghere   ErrorOr<vfs::Status> Status1 = Lower->status("/lower-only");
328fc51490bSJonas Devlieghere   ASSERT_FALSE(Status1.getError());
329fc51490bSJonas Devlieghere   ErrorOr<vfs::Status> Status2 = O->status("/lower-only");
330fc51490bSJonas Devlieghere   ASSERT_FALSE(Status2.getError());
331fc51490bSJonas Devlieghere   EXPECT_TRUE(Status1->equivalent(*Status2));
332fc51490bSJonas Devlieghere 
333fc51490bSJonas Devlieghere   Status1 = Upper->status("/upper-only");
334fc51490bSJonas Devlieghere   ASSERT_FALSE(Status1.getError());
335fc51490bSJonas Devlieghere   Status2 = O->status("/upper-only");
336fc51490bSJonas Devlieghere   ASSERT_FALSE(Status2.getError());
337fc51490bSJonas Devlieghere   EXPECT_TRUE(Status1->equivalent(*Status2));
338fc51490bSJonas Devlieghere }
339fc51490bSJonas Devlieghere 
340fc51490bSJonas Devlieghere TEST(VirtualFileSystemTest, MergedDirPermissions) {
341fc51490bSJonas Devlieghere   // merged directories get the permissions of the upper dir
342fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
343fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
344fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
345fc51490bSJonas Devlieghere       new vfs::OverlayFileSystem(Lower));
346fc51490bSJonas Devlieghere   O->pushOverlay(Upper);
347fc51490bSJonas Devlieghere 
348fc51490bSJonas Devlieghere   ErrorOr<vfs::Status> Status((std::error_code()));
349fc51490bSJonas Devlieghere   Lower->addDirectory("/both", sys::fs::owner_read);
350fc51490bSJonas Devlieghere   Upper->addDirectory("/both", sys::fs::owner_all | sys::fs::group_read);
351fc51490bSJonas Devlieghere   Status = O->status("/both");
352fc51490bSJonas Devlieghere   ASSERT_FALSE(Status.getError());
353fc51490bSJonas Devlieghere   EXPECT_EQ(0740, Status->getPermissions());
354fc51490bSJonas Devlieghere 
355fc51490bSJonas Devlieghere   // permissions (as usual) are not recursively applied
356fc51490bSJonas Devlieghere   Lower->addRegularFile("/both/foo", sys::fs::owner_read);
357fc51490bSJonas Devlieghere   Upper->addRegularFile("/both/bar", sys::fs::owner_write);
358fc51490bSJonas Devlieghere   Status = O->status("/both/foo");
359fc51490bSJonas Devlieghere   ASSERT_FALSE(Status.getError());
360fc51490bSJonas Devlieghere   EXPECT_EQ(0400, Status->getPermissions());
361fc51490bSJonas Devlieghere   Status = O->status("/both/bar");
362fc51490bSJonas Devlieghere   ASSERT_FALSE(Status.getError());
363fc51490bSJonas Devlieghere   EXPECT_EQ(0200, Status->getPermissions());
364fc51490bSJonas Devlieghere }
365fc51490bSJonas Devlieghere 
366efe21088SJonas Devlieghere TEST(VirtualFileSystemTest, OverlayIterator) {
367efe21088SJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
368efe21088SJonas Devlieghere   Lower->addRegularFile("/foo");
369efe21088SJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
370efe21088SJonas Devlieghere 
371efe21088SJonas Devlieghere   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
372efe21088SJonas Devlieghere       new vfs::OverlayFileSystem(Lower));
373efe21088SJonas Devlieghere   O->pushOverlay(Upper);
374efe21088SJonas Devlieghere 
375efe21088SJonas Devlieghere   ErrorOr<vfs::Status> Status((std::error_code()));
376efe21088SJonas Devlieghere   {
377efe21088SJonas Devlieghere     auto it = O->overlays_begin();
378efe21088SJonas Devlieghere     auto end = O->overlays_end();
379efe21088SJonas Devlieghere 
380efe21088SJonas Devlieghere     EXPECT_NE(it, end);
381efe21088SJonas Devlieghere 
382efe21088SJonas Devlieghere     Status = (*it)->status("/foo");
383efe21088SJonas Devlieghere     ASSERT_TRUE(Status.getError());
384efe21088SJonas Devlieghere 
385efe21088SJonas Devlieghere     it++;
386efe21088SJonas Devlieghere     EXPECT_NE(it, end);
387efe21088SJonas Devlieghere 
388efe21088SJonas Devlieghere     Status = (*it)->status("/foo");
389efe21088SJonas Devlieghere     ASSERT_FALSE(Status.getError());
390efe21088SJonas Devlieghere     EXPECT_TRUE(Status->exists());
391efe21088SJonas Devlieghere 
392efe21088SJonas Devlieghere     it++;
393efe21088SJonas Devlieghere     EXPECT_EQ(it, end);
394efe21088SJonas Devlieghere   }
395efe21088SJonas Devlieghere 
396efe21088SJonas Devlieghere   {
397efe21088SJonas Devlieghere     auto it = O->overlays_rbegin();
398efe21088SJonas Devlieghere     auto end = O->overlays_rend();
399efe21088SJonas Devlieghere 
400efe21088SJonas Devlieghere     EXPECT_NE(it, end);
401efe21088SJonas Devlieghere 
402efe21088SJonas Devlieghere     Status = (*it)->status("/foo");
403efe21088SJonas Devlieghere     ASSERT_FALSE(Status.getError());
404efe21088SJonas Devlieghere     EXPECT_TRUE(Status->exists());
405efe21088SJonas Devlieghere 
406efe21088SJonas Devlieghere     it++;
407efe21088SJonas Devlieghere     EXPECT_NE(it, end);
408efe21088SJonas Devlieghere 
409efe21088SJonas Devlieghere     Status = (*it)->status("/foo");
410efe21088SJonas Devlieghere     ASSERT_TRUE(Status.getError());
411efe21088SJonas Devlieghere 
412efe21088SJonas Devlieghere     it++;
413efe21088SJonas Devlieghere     EXPECT_EQ(it, end);
414efe21088SJonas Devlieghere   }
415efe21088SJonas Devlieghere }
416efe21088SJonas Devlieghere 
417fc51490bSJonas Devlieghere TEST(VirtualFileSystemTest, BasicRealFSIteration) {
418fad75598SSergej Jaskiewicz   TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
419fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
420fc51490bSJonas Devlieghere 
421fc51490bSJonas Devlieghere   std::error_code EC;
422fad75598SSergej Jaskiewicz   vfs::directory_iterator I = FS->dir_begin(Twine(TestDirectory.path()), EC);
423fc51490bSJonas Devlieghere   ASSERT_FALSE(EC);
424fc51490bSJonas Devlieghere   EXPECT_EQ(vfs::directory_iterator(), I); // empty directory is empty
425fc51490bSJonas Devlieghere 
426fad75598SSergej Jaskiewicz   TempDir _a(TestDirectory.path("a"));
427fad75598SSergej Jaskiewicz   TempDir _ab(TestDirectory.path("a/b"));
428fad75598SSergej Jaskiewicz   TempDir _c(TestDirectory.path("c"));
429fad75598SSergej Jaskiewicz   TempDir _cd(TestDirectory.path("c/d"));
430fc51490bSJonas Devlieghere 
431fad75598SSergej Jaskiewicz   I = FS->dir_begin(Twine(TestDirectory.path()), EC);
432fc51490bSJonas Devlieghere   ASSERT_FALSE(EC);
433fc51490bSJonas Devlieghere   ASSERT_NE(vfs::directory_iterator(), I);
434fc51490bSJonas Devlieghere   // Check either a or c, since we can't rely on the iteration order.
435fc51490bSJonas Devlieghere   EXPECT_TRUE(I->path().endswith("a") || I->path().endswith("c"));
436fc51490bSJonas Devlieghere   I.increment(EC);
437fc51490bSJonas Devlieghere   ASSERT_FALSE(EC);
438fc51490bSJonas Devlieghere   ASSERT_NE(vfs::directory_iterator(), I);
439fc51490bSJonas Devlieghere   EXPECT_TRUE(I->path().endswith("a") || I->path().endswith("c"));
440fc51490bSJonas Devlieghere   I.increment(EC);
441fc51490bSJonas Devlieghere   EXPECT_EQ(vfs::directory_iterator(), I);
442fc51490bSJonas Devlieghere }
443fc51490bSJonas Devlieghere 
44462ab1a1aSSam McCall #ifdef LLVM_ON_UNIX
44515e475e2SSam McCall TEST(VirtualFileSystemTest, MultipleWorkingDirs) {
44615e475e2SSam McCall   // Our root contains a/aa, b/bb, c, where c is a link to a/.
44715e475e2SSam McCall   // Run tests both in root/b/ and root/c/ (to test "normal" and symlink dirs).
44815e475e2SSam McCall   // Interleave operations to show the working directories are independent.
449fad75598SSergej Jaskiewicz   TempDir Root("r", /*Unique*/ true);
450fad75598SSergej Jaskiewicz   TempDir ADir(Root.path("a"));
451fad75598SSergej Jaskiewicz   TempDir BDir(Root.path("b"));
452fad75598SSergej Jaskiewicz   TempLink C(ADir.path(), Root.path("c"));
453fad75598SSergej Jaskiewicz   TempFile AA(ADir.path("aa"), "", "aaaa");
454fad75598SSergej Jaskiewicz   TempFile BB(BDir.path("bb"), "", "bbbb");
45515e475e2SSam McCall   std::unique_ptr<vfs::FileSystem> BFS = vfs::createPhysicalFileSystem(),
45615e475e2SSam McCall                                    CFS = vfs::createPhysicalFileSystem();
45715e475e2SSam McCall 
458fad75598SSergej Jaskiewicz   ASSERT_FALSE(BFS->setCurrentWorkingDirectory(BDir.path()));
459fad75598SSergej Jaskiewicz   ASSERT_FALSE(CFS->setCurrentWorkingDirectory(C.path()));
460fad75598SSergej Jaskiewicz   EXPECT_EQ(BDir.path(), *BFS->getCurrentWorkingDirectory());
461fad75598SSergej Jaskiewicz   EXPECT_EQ(C.path(), *CFS->getCurrentWorkingDirectory());
46215e475e2SSam McCall 
46315e475e2SSam McCall   // openFileForRead(), indirectly.
46415e475e2SSam McCall   auto BBuf = BFS->getBufferForFile("bb");
46515e475e2SSam McCall   ASSERT_TRUE(BBuf);
46615e475e2SSam McCall   EXPECT_EQ("bbbb", (*BBuf)->getBuffer());
46715e475e2SSam McCall 
46815e475e2SSam McCall   auto ABuf = CFS->getBufferForFile("aa");
46915e475e2SSam McCall   ASSERT_TRUE(ABuf);
47015e475e2SSam McCall   EXPECT_EQ("aaaa", (*ABuf)->getBuffer());
47115e475e2SSam McCall 
47215e475e2SSam McCall   // status()
47315e475e2SSam McCall   auto BStat = BFS->status("bb");
47415e475e2SSam McCall   ASSERT_TRUE(BStat);
47515e475e2SSam McCall   EXPECT_EQ("bb", BStat->getName());
47615e475e2SSam McCall 
47715e475e2SSam McCall   auto AStat = CFS->status("aa");
47815e475e2SSam McCall   ASSERT_TRUE(AStat);
47915e475e2SSam McCall   EXPECT_EQ("aa", AStat->getName()); // unresolved name
48015e475e2SSam McCall 
48115e475e2SSam McCall   // getRealPath()
48215e475e2SSam McCall   SmallString<128> BPath;
48315e475e2SSam McCall   ASSERT_FALSE(BFS->getRealPath("bb", BPath));
484fad75598SSergej Jaskiewicz   EXPECT_EQ(BB.path(), BPath);
48515e475e2SSam McCall 
48615e475e2SSam McCall   SmallString<128> APath;
48715e475e2SSam McCall   ASSERT_FALSE(CFS->getRealPath("aa", APath));
488fad75598SSergej Jaskiewicz   EXPECT_EQ(AA.path(), APath); // Reports resolved name.
48915e475e2SSam McCall 
49015e475e2SSam McCall   // dir_begin
49115e475e2SSam McCall   std::error_code EC;
49215e475e2SSam McCall   auto BIt = BFS->dir_begin(".", EC);
49315e475e2SSam McCall   ASSERT_FALSE(EC);
49415e475e2SSam McCall   ASSERT_NE(BIt, vfs::directory_iterator());
495fad75598SSergej Jaskiewicz   EXPECT_EQ((BDir.path() + "/./bb").str(), BIt->path());
49615e475e2SSam McCall   BIt.increment(EC);
49715e475e2SSam McCall   ASSERT_FALSE(EC);
49815e475e2SSam McCall   ASSERT_EQ(BIt, vfs::directory_iterator());
49915e475e2SSam McCall 
50015e475e2SSam McCall   auto CIt = CFS->dir_begin(".", EC);
50115e475e2SSam McCall   ASSERT_FALSE(EC);
50215e475e2SSam McCall   ASSERT_NE(CIt, vfs::directory_iterator());
503fad75598SSergej Jaskiewicz   EXPECT_EQ((ADir.path() + "/./aa").str(),
504fad75598SSergej Jaskiewicz             CIt->path()); // Partly resolved name!
50515e475e2SSam McCall   CIt.increment(EC); // Because likely to read through this path.
50615e475e2SSam McCall   ASSERT_FALSE(EC);
50715e475e2SSam McCall   ASSERT_EQ(CIt, vfs::directory_iterator());
50815e475e2SSam McCall }
50915e475e2SSam McCall 
510fc51490bSJonas Devlieghere TEST(VirtualFileSystemTest, BrokenSymlinkRealFSIteration) {
511fad75598SSergej Jaskiewicz   TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
512fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
513fc51490bSJonas Devlieghere 
514fad75598SSergej Jaskiewicz   TempLink _a("no_such_file", TestDirectory.path("a"));
515fad75598SSergej Jaskiewicz   TempDir _b(TestDirectory.path("b"));
516fad75598SSergej Jaskiewicz   TempLink _c("no_such_file", TestDirectory.path("c"));
517fc51490bSJonas Devlieghere 
518fc51490bSJonas Devlieghere   // Should get no iteration error, but a stat error for the broken symlinks.
519fc51490bSJonas Devlieghere   std::map<std::string, std::error_code> StatResults;
520fc51490bSJonas Devlieghere   std::error_code EC;
521fad75598SSergej Jaskiewicz   for (vfs::directory_iterator
522fad75598SSergej Jaskiewicz            I = FS->dir_begin(Twine(TestDirectory.path()), EC),
523fad75598SSergej Jaskiewicz            E;
524fc51490bSJonas Devlieghere        I != E; I.increment(EC)) {
525fc51490bSJonas Devlieghere     EXPECT_FALSE(EC);
526adcd0268SBenjamin Kramer     StatResults[std::string(sys::path::filename(I->path()))] =
527fc51490bSJonas Devlieghere         FS->status(I->path()).getError();
528fc51490bSJonas Devlieghere   }
529fc51490bSJonas Devlieghere   EXPECT_THAT(
530fc51490bSJonas Devlieghere       StatResults,
531fc51490bSJonas Devlieghere       ElementsAre(
532fc51490bSJonas Devlieghere           Pair("a", std::make_error_code(std::errc::no_such_file_or_directory)),
533fc51490bSJonas Devlieghere           Pair("b", std::error_code()),
534fc51490bSJonas Devlieghere           Pair("c",
535fc51490bSJonas Devlieghere                std::make_error_code(std::errc::no_such_file_or_directory))));
536fc51490bSJonas Devlieghere }
537fc51490bSJonas Devlieghere #endif
538fc51490bSJonas Devlieghere 
539fc51490bSJonas Devlieghere TEST(VirtualFileSystemTest, BasicRealFSRecursiveIteration) {
540fad75598SSergej Jaskiewicz   TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
541fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
542fc51490bSJonas Devlieghere 
543fc51490bSJonas Devlieghere   std::error_code EC;
544fad75598SSergej Jaskiewicz   auto I =
545fad75598SSergej Jaskiewicz       vfs::recursive_directory_iterator(*FS, Twine(TestDirectory.path()), EC);
546fc51490bSJonas Devlieghere   ASSERT_FALSE(EC);
547fc51490bSJonas Devlieghere   EXPECT_EQ(vfs::recursive_directory_iterator(), I); // empty directory is empty
548fc51490bSJonas Devlieghere 
549fad75598SSergej Jaskiewicz   TempDir _a(TestDirectory.path("a"));
550fad75598SSergej Jaskiewicz   TempDir _ab(TestDirectory.path("a/b"));
551fad75598SSergej Jaskiewicz   TempDir _c(TestDirectory.path("c"));
552fad75598SSergej Jaskiewicz   TempDir _cd(TestDirectory.path("c/d"));
553fc51490bSJonas Devlieghere 
554fad75598SSergej Jaskiewicz   I = vfs::recursive_directory_iterator(*FS, Twine(TestDirectory.path()), EC);
555fc51490bSJonas Devlieghere   ASSERT_FALSE(EC);
556fc51490bSJonas Devlieghere   ASSERT_NE(vfs::recursive_directory_iterator(), I);
557fc51490bSJonas Devlieghere 
558fc51490bSJonas Devlieghere   std::vector<std::string> Contents;
559fc51490bSJonas Devlieghere   for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
560fc51490bSJonas Devlieghere        I.increment(EC)) {
561adcd0268SBenjamin Kramer     Contents.push_back(std::string(I->path()));
562fc51490bSJonas Devlieghere   }
563fc51490bSJonas Devlieghere 
564fc51490bSJonas Devlieghere   // Check contents, which may be in any order
565fc51490bSJonas Devlieghere   EXPECT_EQ(4U, Contents.size());
566fc51490bSJonas Devlieghere   int Counts[4] = {0, 0, 0, 0};
567fc51490bSJonas Devlieghere   for (const std::string &Name : Contents) {
568fc51490bSJonas Devlieghere     ASSERT_FALSE(Name.empty());
569fc51490bSJonas Devlieghere     int Index = Name[Name.size() - 1] - 'a';
570fc51490bSJonas Devlieghere     ASSERT_TRUE(Index >= 0 && Index < 4);
571fc51490bSJonas Devlieghere     Counts[Index]++;
572fc51490bSJonas Devlieghere   }
573fc51490bSJonas Devlieghere   EXPECT_EQ(1, Counts[0]); // a
574fc51490bSJonas Devlieghere   EXPECT_EQ(1, Counts[1]); // b
575fc51490bSJonas Devlieghere   EXPECT_EQ(1, Counts[2]); // c
576fc51490bSJonas Devlieghere   EXPECT_EQ(1, Counts[3]); // d
577fc51490bSJonas Devlieghere }
578fc51490bSJonas Devlieghere 
57941fb951fSJonas Devlieghere TEST(VirtualFileSystemTest, BasicRealFSRecursiveIterationNoPush) {
580fad75598SSergej Jaskiewicz   TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
58141fb951fSJonas Devlieghere 
582fad75598SSergej Jaskiewicz   TempDir _a(TestDirectory.path("a"));
583fad75598SSergej Jaskiewicz   TempDir _ab(TestDirectory.path("a/b"));
584fad75598SSergej Jaskiewicz   TempDir _c(TestDirectory.path("c"));
585fad75598SSergej Jaskiewicz   TempDir _cd(TestDirectory.path("c/d"));
586fad75598SSergej Jaskiewicz   TempDir _e(TestDirectory.path("e"));
587fad75598SSergej Jaskiewicz   TempDir _ef(TestDirectory.path("e/f"));
588fad75598SSergej Jaskiewicz   TempDir _g(TestDirectory.path("g"));
58941fb951fSJonas Devlieghere 
59041fb951fSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
59141fb951fSJonas Devlieghere 
59241fb951fSJonas Devlieghere   // Test that calling no_push on entries without subdirectories has no effect.
59341fb951fSJonas Devlieghere   {
59441fb951fSJonas Devlieghere     std::error_code EC;
595fad75598SSergej Jaskiewicz     auto I =
596fad75598SSergej Jaskiewicz         vfs::recursive_directory_iterator(*FS, Twine(TestDirectory.path()), EC);
59741fb951fSJonas Devlieghere     ASSERT_FALSE(EC);
59841fb951fSJonas Devlieghere 
59941fb951fSJonas Devlieghere     std::vector<std::string> Contents;
60041fb951fSJonas Devlieghere     for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
60141fb951fSJonas Devlieghere          I.increment(EC)) {
602adcd0268SBenjamin Kramer       Contents.push_back(std::string(I->path()));
60341fb951fSJonas Devlieghere       char last = I->path().back();
60441fb951fSJonas Devlieghere       switch (last) {
60541fb951fSJonas Devlieghere       case 'b':
60641fb951fSJonas Devlieghere       case 'd':
60741fb951fSJonas Devlieghere       case 'f':
60841fb951fSJonas Devlieghere       case 'g':
60941fb951fSJonas Devlieghere         I.no_push();
61041fb951fSJonas Devlieghere         break;
61141fb951fSJonas Devlieghere       default:
61241fb951fSJonas Devlieghere         break;
61341fb951fSJonas Devlieghere       }
61441fb951fSJonas Devlieghere     }
61541fb951fSJonas Devlieghere     EXPECT_EQ(7U, Contents.size());
61641fb951fSJonas Devlieghere   }
61741fb951fSJonas Devlieghere 
61841fb951fSJonas Devlieghere   // Test that calling no_push skips subdirectories.
61941fb951fSJonas Devlieghere   {
62041fb951fSJonas Devlieghere     std::error_code EC;
621fad75598SSergej Jaskiewicz     auto I =
622fad75598SSergej Jaskiewicz         vfs::recursive_directory_iterator(*FS, Twine(TestDirectory.path()), EC);
62341fb951fSJonas Devlieghere     ASSERT_FALSE(EC);
62441fb951fSJonas Devlieghere 
62541fb951fSJonas Devlieghere     std::vector<std::string> Contents;
62641fb951fSJonas Devlieghere     for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
62741fb951fSJonas Devlieghere          I.increment(EC)) {
628adcd0268SBenjamin Kramer       Contents.push_back(std::string(I->path()));
62941fb951fSJonas Devlieghere       char last = I->path().back();
63041fb951fSJonas Devlieghere       switch (last) {
63141fb951fSJonas Devlieghere       case 'a':
63241fb951fSJonas Devlieghere       case 'c':
63341fb951fSJonas Devlieghere       case 'e':
63441fb951fSJonas Devlieghere         I.no_push();
63541fb951fSJonas Devlieghere         break;
63641fb951fSJonas Devlieghere       default:
63741fb951fSJonas Devlieghere         break;
63841fb951fSJonas Devlieghere       }
63941fb951fSJonas Devlieghere     }
64041fb951fSJonas Devlieghere 
64141fb951fSJonas Devlieghere     // Check contents, which may be in any order
64241fb951fSJonas Devlieghere     EXPECT_EQ(4U, Contents.size());
64341fb951fSJonas Devlieghere     int Counts[7] = {0, 0, 0, 0, 0, 0, 0};
64441fb951fSJonas Devlieghere     for (const std::string &Name : Contents) {
64541fb951fSJonas Devlieghere       ASSERT_FALSE(Name.empty());
64641fb951fSJonas Devlieghere       int Index = Name[Name.size() - 1] - 'a';
64741fb951fSJonas Devlieghere       ASSERT_TRUE(Index >= 0 && Index < 7);
64841fb951fSJonas Devlieghere       Counts[Index]++;
64941fb951fSJonas Devlieghere     }
65041fb951fSJonas Devlieghere     EXPECT_EQ(1, Counts[0]); // a
65141fb951fSJonas Devlieghere     EXPECT_EQ(0, Counts[1]); // b
65241fb951fSJonas Devlieghere     EXPECT_EQ(1, Counts[2]); // c
65341fb951fSJonas Devlieghere     EXPECT_EQ(0, Counts[3]); // d
65441fb951fSJonas Devlieghere     EXPECT_EQ(1, Counts[4]); // e
65541fb951fSJonas Devlieghere     EXPECT_EQ(0, Counts[5]); // f
65641fb951fSJonas Devlieghere     EXPECT_EQ(1, Counts[6]); // g
65741fb951fSJonas Devlieghere   }
65841fb951fSJonas Devlieghere }
65941fb951fSJonas Devlieghere 
660fc51490bSJonas Devlieghere #ifdef LLVM_ON_UNIX
661fc51490bSJonas Devlieghere TEST(VirtualFileSystemTest, BrokenSymlinkRealFSRecursiveIteration) {
662fad75598SSergej Jaskiewicz   TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
663fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = vfs::getRealFileSystem();
664fc51490bSJonas Devlieghere 
665fad75598SSergej Jaskiewicz   TempLink _a("no_such_file", TestDirectory.path("a"));
666fad75598SSergej Jaskiewicz   TempDir _b(TestDirectory.path("b"));
667fad75598SSergej Jaskiewicz   TempLink _ba("no_such_file", TestDirectory.path("b/a"));
668fad75598SSergej Jaskiewicz   TempDir _bb(TestDirectory.path("b/b"));
669fad75598SSergej Jaskiewicz   TempLink _bc("no_such_file", TestDirectory.path("b/c"));
670fad75598SSergej Jaskiewicz   TempLink _c("no_such_file", TestDirectory.path("c"));
671fad75598SSergej Jaskiewicz   TempDir _d(TestDirectory.path("d"));
672fad75598SSergej Jaskiewicz   TempDir _dd(TestDirectory.path("d/d"));
673fad75598SSergej Jaskiewicz   TempDir _ddd(TestDirectory.path("d/d/d"));
674fad75598SSergej Jaskiewicz   TempLink _e("no_such_file", TestDirectory.path("e"));
675fc51490bSJonas Devlieghere 
676fc51490bSJonas Devlieghere   std::vector<std::string> VisitedBrokenSymlinks;
677fc51490bSJonas Devlieghere   std::vector<std::string> VisitedNonBrokenSymlinks;
678fc51490bSJonas Devlieghere   std::error_code EC;
679fad75598SSergej Jaskiewicz   for (vfs::recursive_directory_iterator
680fad75598SSergej Jaskiewicz            I(*FS, Twine(TestDirectory.path()), EC),
681fad75598SSergej Jaskiewicz        E;
682fc51490bSJonas Devlieghere        I != E; I.increment(EC)) {
683fc51490bSJonas Devlieghere     EXPECT_FALSE(EC);
684fc51490bSJonas Devlieghere     (FS->status(I->path()) ? VisitedNonBrokenSymlinks : VisitedBrokenSymlinks)
685adcd0268SBenjamin Kramer         .push_back(std::string(I->path()));
686fc51490bSJonas Devlieghere   }
687fc51490bSJonas Devlieghere 
688fc51490bSJonas Devlieghere   // Check visited file names.
689fc51490bSJonas Devlieghere   EXPECT_THAT(VisitedBrokenSymlinks,
690fad75598SSergej Jaskiewicz               UnorderedElementsAre(_a.path().str(), _ba.path().str(),
691fad75598SSergej Jaskiewicz                                    _bc.path().str(), _c.path().str(),
692fad75598SSergej Jaskiewicz                                    _e.path().str()));
693fc51490bSJonas Devlieghere   EXPECT_THAT(VisitedNonBrokenSymlinks,
694fad75598SSergej Jaskiewicz               UnorderedElementsAre(_b.path().str(), _bb.path().str(),
695fad75598SSergej Jaskiewicz                                    _d.path().str(), _dd.path().str(),
696fad75598SSergej Jaskiewicz                                    _ddd.path().str()));
697fc51490bSJonas Devlieghere }
698fc51490bSJonas Devlieghere #endif
699fc51490bSJonas Devlieghere 
700fc51490bSJonas Devlieghere template <typename DirIter>
701fc51490bSJonas Devlieghere static void checkContents(DirIter I, ArrayRef<StringRef> ExpectedOut) {
702fc51490bSJonas Devlieghere   std::error_code EC;
703fc51490bSJonas Devlieghere   SmallVector<StringRef, 4> Expected(ExpectedOut.begin(), ExpectedOut.end());
704fc51490bSJonas Devlieghere   SmallVector<std::string, 4> InputToCheck;
705fc51490bSJonas Devlieghere 
706fc51490bSJonas Devlieghere   // Do not rely on iteration order to check for contents, sort both
707fc51490bSJonas Devlieghere   // content vectors before comparison.
708fc51490bSJonas Devlieghere   for (DirIter E; !EC && I != E; I.increment(EC))
709adcd0268SBenjamin Kramer     InputToCheck.push_back(std::string(I->path()));
710fc51490bSJonas Devlieghere 
711fc51490bSJonas Devlieghere   llvm::sort(InputToCheck);
712fc51490bSJonas Devlieghere   llvm::sort(Expected);
713fc51490bSJonas Devlieghere   EXPECT_EQ(InputToCheck.size(), Expected.size());
714fc51490bSJonas Devlieghere 
715fc51490bSJonas Devlieghere   unsigned LastElt = std::min(InputToCheck.size(), Expected.size());
716fc51490bSJonas Devlieghere   for (unsigned Idx = 0; Idx != LastElt; ++Idx)
717fc51490bSJonas Devlieghere     EXPECT_EQ(StringRef(InputToCheck[Idx]), Expected[Idx]);
718fc51490bSJonas Devlieghere }
719fc51490bSJonas Devlieghere 
720fc51490bSJonas Devlieghere TEST(VirtualFileSystemTest, OverlayIteration) {
721fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
722fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
723fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
724fc51490bSJonas Devlieghere       new vfs::OverlayFileSystem(Lower));
725fc51490bSJonas Devlieghere   O->pushOverlay(Upper);
726fc51490bSJonas Devlieghere 
727fc51490bSJonas Devlieghere   std::error_code EC;
728fc51490bSJonas Devlieghere   checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
729fc51490bSJonas Devlieghere 
730fc51490bSJonas Devlieghere   Lower->addRegularFile("/file1");
731fc51490bSJonas Devlieghere   checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file1"));
732fc51490bSJonas Devlieghere 
733fc51490bSJonas Devlieghere   Upper->addRegularFile("/file2");
734fc51490bSJonas Devlieghere   checkContents(O->dir_begin("/", EC), {"/file2", "/file1"});
735fc51490bSJonas Devlieghere 
736fc51490bSJonas Devlieghere   Lower->addDirectory("/dir1");
737fc51490bSJonas Devlieghere   Lower->addRegularFile("/dir1/foo");
738fc51490bSJonas Devlieghere   Upper->addDirectory("/dir2");
739fc51490bSJonas Devlieghere   Upper->addRegularFile("/dir2/foo");
740fc51490bSJonas Devlieghere   checkContents(O->dir_begin("/dir2", EC), ArrayRef<StringRef>("/dir2/foo"));
741fc51490bSJonas Devlieghere   checkContents(O->dir_begin("/", EC), {"/dir2", "/file2", "/dir1", "/file1"});
742fc51490bSJonas Devlieghere }
743fc51490bSJonas Devlieghere 
744fc51490bSJonas Devlieghere TEST(VirtualFileSystemTest, OverlayRecursiveIteration) {
745fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
746fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
747fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
748fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
749fc51490bSJonas Devlieghere       new vfs::OverlayFileSystem(Lower));
750fc51490bSJonas Devlieghere   O->pushOverlay(Middle);
751fc51490bSJonas Devlieghere   O->pushOverlay(Upper);
752fc51490bSJonas Devlieghere 
753fc51490bSJonas Devlieghere   std::error_code EC;
754fc51490bSJonas Devlieghere   checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
755fc51490bSJonas Devlieghere                 ArrayRef<StringRef>());
756fc51490bSJonas Devlieghere 
757fc51490bSJonas Devlieghere   Lower->addRegularFile("/file1");
758fc51490bSJonas Devlieghere   checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
759fc51490bSJonas Devlieghere                 ArrayRef<StringRef>("/file1"));
760fc51490bSJonas Devlieghere 
761fc51490bSJonas Devlieghere   Upper->addDirectory("/dir");
762fc51490bSJonas Devlieghere   Upper->addRegularFile("/dir/file2");
763fc51490bSJonas Devlieghere   checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
764fc51490bSJonas Devlieghere                 {"/dir", "/dir/file2", "/file1"});
765fc51490bSJonas Devlieghere 
766fc51490bSJonas Devlieghere   Lower->addDirectory("/dir1");
767fc51490bSJonas Devlieghere   Lower->addRegularFile("/dir1/foo");
768fc51490bSJonas Devlieghere   Lower->addDirectory("/dir1/a");
769fc51490bSJonas Devlieghere   Lower->addRegularFile("/dir1/a/b");
770fc51490bSJonas Devlieghere   Middle->addDirectory("/a");
771fc51490bSJonas Devlieghere   Middle->addDirectory("/a/b");
772fc51490bSJonas Devlieghere   Middle->addDirectory("/a/b/c");
773fc51490bSJonas Devlieghere   Middle->addRegularFile("/a/b/c/d");
774fc51490bSJonas Devlieghere   Middle->addRegularFile("/hiddenByUp");
775fc51490bSJonas Devlieghere   Upper->addDirectory("/dir2");
776fc51490bSJonas Devlieghere   Upper->addRegularFile("/dir2/foo");
777fc51490bSJonas Devlieghere   Upper->addRegularFile("/hiddenByUp");
778fc51490bSJonas Devlieghere   checkContents(vfs::recursive_directory_iterator(*O, "/dir2", EC),
779fc51490bSJonas Devlieghere                 ArrayRef<StringRef>("/dir2/foo"));
780fc51490bSJonas Devlieghere   checkContents(vfs::recursive_directory_iterator(*O, "/", EC),
781fc51490bSJonas Devlieghere                 {"/dir", "/dir/file2", "/dir2", "/dir2/foo", "/hiddenByUp",
782fc51490bSJonas Devlieghere                  "/a", "/a/b", "/a/b/c", "/a/b/c/d", "/dir1", "/dir1/a",
783fc51490bSJonas Devlieghere                  "/dir1/a/b", "/dir1/foo", "/file1"});
784fc51490bSJonas Devlieghere }
785fc51490bSJonas Devlieghere 
786fc51490bSJonas Devlieghere TEST(VirtualFileSystemTest, ThreeLevelIteration) {
787fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
788fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
789fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
790fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
791fc51490bSJonas Devlieghere       new vfs::OverlayFileSystem(Lower));
792fc51490bSJonas Devlieghere   O->pushOverlay(Middle);
793fc51490bSJonas Devlieghere   O->pushOverlay(Upper);
794fc51490bSJonas Devlieghere 
795fc51490bSJonas Devlieghere   std::error_code EC;
796fc51490bSJonas Devlieghere   checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>());
797fc51490bSJonas Devlieghere 
798fc51490bSJonas Devlieghere   Middle->addRegularFile("/file2");
799fc51490bSJonas Devlieghere   checkContents(O->dir_begin("/", EC), ArrayRef<StringRef>("/file2"));
800fc51490bSJonas Devlieghere 
801fc51490bSJonas Devlieghere   Lower->addRegularFile("/file1");
802fc51490bSJonas Devlieghere   Upper->addRegularFile("/file3");
803fc51490bSJonas Devlieghere   checkContents(O->dir_begin("/", EC), {"/file3", "/file2", "/file1"});
804fc51490bSJonas Devlieghere }
805fc51490bSJonas Devlieghere 
806fc51490bSJonas Devlieghere TEST(VirtualFileSystemTest, HiddenInIteration) {
807fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
808fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Middle(new DummyFileSystem());
809fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Upper(new DummyFileSystem());
810fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
811fc51490bSJonas Devlieghere       new vfs::OverlayFileSystem(Lower));
812fc51490bSJonas Devlieghere   O->pushOverlay(Middle);
813fc51490bSJonas Devlieghere   O->pushOverlay(Upper);
814fc51490bSJonas Devlieghere 
815fc51490bSJonas Devlieghere   std::error_code EC;
816fc51490bSJonas Devlieghere   Lower->addRegularFile("/onlyInLow");
817fc51490bSJonas Devlieghere   Lower->addDirectory("/hiddenByMid");
818fc51490bSJonas Devlieghere   Lower->addDirectory("/hiddenByUp");
819fc51490bSJonas Devlieghere   Middle->addRegularFile("/onlyInMid");
820fc51490bSJonas Devlieghere   Middle->addRegularFile("/hiddenByMid");
821fc51490bSJonas Devlieghere   Middle->addDirectory("/hiddenByUp");
822fc51490bSJonas Devlieghere   Upper->addRegularFile("/onlyInUp");
823fc51490bSJonas Devlieghere   Upper->addRegularFile("/hiddenByUp");
824fc51490bSJonas Devlieghere   checkContents(
825fc51490bSJonas Devlieghere       O->dir_begin("/", EC),
826fc51490bSJonas Devlieghere       {"/hiddenByUp", "/onlyInUp", "/hiddenByMid", "/onlyInMid", "/onlyInLow"});
827fc51490bSJonas Devlieghere 
828fc51490bSJonas Devlieghere   // Make sure we get the top-most entry
829fc51490bSJonas Devlieghere   {
830fc51490bSJonas Devlieghere     std::error_code EC;
831fc51490bSJonas Devlieghere     vfs::directory_iterator I = O->dir_begin("/", EC), E;
832fc51490bSJonas Devlieghere     for (; !EC && I != E; I.increment(EC))
833fc51490bSJonas Devlieghere       if (I->path() == "/hiddenByUp")
834fc51490bSJonas Devlieghere         break;
835fc51490bSJonas Devlieghere     ASSERT_NE(E, I);
836fc51490bSJonas Devlieghere     EXPECT_EQ(sys::fs::file_type::regular_file, I->type());
837fc51490bSJonas Devlieghere   }
838fc51490bSJonas Devlieghere   {
839fc51490bSJonas Devlieghere     std::error_code EC;
840fc51490bSJonas Devlieghere     vfs::directory_iterator I = O->dir_begin("/", EC), E;
841fc51490bSJonas Devlieghere     for (; !EC && I != E; I.increment(EC))
842fc51490bSJonas Devlieghere       if (I->path() == "/hiddenByMid")
843fc51490bSJonas Devlieghere         break;
844fc51490bSJonas Devlieghere     ASSERT_NE(E, I);
845fc51490bSJonas Devlieghere     EXPECT_EQ(sys::fs::file_type::regular_file, I->type());
846fc51490bSJonas Devlieghere   }
847fc51490bSJonas Devlieghere }
848fc51490bSJonas Devlieghere 
849937a1047SMichael J. Spencer TEST(ProxyFileSystemTest, Basic) {
850937a1047SMichael J. Spencer   IntrusiveRefCntPtr<vfs::InMemoryFileSystem> Base(
851937a1047SMichael J. Spencer       new vfs::InMemoryFileSystem());
852937a1047SMichael J. Spencer   vfs::ProxyFileSystem PFS(Base);
853937a1047SMichael J. Spencer 
854937a1047SMichael J. Spencer   Base->addFile("/a", 0, MemoryBuffer::getMemBuffer("test"));
855937a1047SMichael J. Spencer 
856937a1047SMichael J. Spencer   auto Stat = PFS.status("/a");
857937a1047SMichael J. Spencer   ASSERT_FALSE(Stat.getError());
858937a1047SMichael J. Spencer 
859937a1047SMichael J. Spencer   auto File = PFS.openFileForRead("/a");
860937a1047SMichael J. Spencer   ASSERT_FALSE(File.getError());
861937a1047SMichael J. Spencer   EXPECT_EQ("test", (*(*File)->getBuffer("ignored"))->getBuffer());
862937a1047SMichael J. Spencer 
863937a1047SMichael J. Spencer   std::error_code EC;
864937a1047SMichael J. Spencer   vfs::directory_iterator I = PFS.dir_begin("/", EC);
865937a1047SMichael J. Spencer   ASSERT_FALSE(EC);
866937a1047SMichael J. Spencer   ASSERT_EQ("/a", I->path());
867937a1047SMichael J. Spencer   I.increment(EC);
868937a1047SMichael J. Spencer   ASSERT_FALSE(EC);
869937a1047SMichael J. Spencer   ASSERT_EQ(vfs::directory_iterator(), I);
870937a1047SMichael J. Spencer 
871937a1047SMichael J. Spencer   ASSERT_FALSE(PFS.setCurrentWorkingDirectory("/"));
872937a1047SMichael J. Spencer 
873937a1047SMichael J. Spencer   auto PWD = PFS.getCurrentWorkingDirectory();
874937a1047SMichael J. Spencer   ASSERT_FALSE(PWD.getError());
875937a1047SMichael J. Spencer   ASSERT_EQ("/", *PWD);
876937a1047SMichael J. Spencer 
877937a1047SMichael J. Spencer   SmallString<16> Path;
878937a1047SMichael J. Spencer   ASSERT_FALSE(PFS.getRealPath("a", Path));
879937a1047SMichael J. Spencer   ASSERT_EQ("/a", Path);
880937a1047SMichael J. Spencer 
881937a1047SMichael J. Spencer   bool Local = true;
882937a1047SMichael J. Spencer   ASSERT_FALSE(PFS.isLocal("/a", Local));
8832a5a0ad1SMichael J. Spencer   EXPECT_FALSE(Local);
884937a1047SMichael J. Spencer }
885937a1047SMichael J. Spencer 
886fc51490bSJonas Devlieghere class InMemoryFileSystemTest : public ::testing::Test {
887fc51490bSJonas Devlieghere protected:
888fc51490bSJonas Devlieghere   llvm::vfs::InMemoryFileSystem FS;
889fc51490bSJonas Devlieghere   llvm::vfs::InMemoryFileSystem NormalizedFS;
890fc51490bSJonas Devlieghere 
891fc51490bSJonas Devlieghere   InMemoryFileSystemTest()
892fc51490bSJonas Devlieghere       : FS(/*UseNormalizedPaths=*/false),
893fc51490bSJonas Devlieghere         NormalizedFS(/*UseNormalizedPaths=*/true) {}
894fc51490bSJonas Devlieghere };
895fc51490bSJonas Devlieghere 
896fc51490bSJonas Devlieghere MATCHER_P2(IsHardLinkTo, FS, Target, "") {
897fc51490bSJonas Devlieghere   StringRef From = arg;
898fc51490bSJonas Devlieghere   StringRef To = Target;
899fc51490bSJonas Devlieghere   auto OpenedFrom = FS->openFileForRead(From);
900fc51490bSJonas Devlieghere   auto OpenedTo = FS->openFileForRead(To);
901fc51490bSJonas Devlieghere   return !OpenedFrom.getError() && !OpenedTo.getError() &&
902fc51490bSJonas Devlieghere          (*OpenedFrom)->status()->getUniqueID() ==
903fc51490bSJonas Devlieghere              (*OpenedTo)->status()->getUniqueID();
904fc51490bSJonas Devlieghere }
905fc51490bSJonas Devlieghere 
906fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, IsEmpty) {
907fc51490bSJonas Devlieghere   auto Stat = FS.status("/a");
908fc51490bSJonas Devlieghere   ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
909fc51490bSJonas Devlieghere   Stat = FS.status("/");
910fc51490bSJonas Devlieghere   ASSERT_EQ(Stat.getError(), errc::no_such_file_or_directory) << FS.toString();
911fc51490bSJonas Devlieghere }
912fc51490bSJonas Devlieghere 
913fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, WindowsPath) {
914fc51490bSJonas Devlieghere   FS.addFile("c:/windows/system128/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
915fc51490bSJonas Devlieghere   auto Stat = FS.status("c:");
916fc51490bSJonas Devlieghere #if !defined(_WIN32)
917fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
918fc51490bSJonas Devlieghere #endif
919fc51490bSJonas Devlieghere   Stat = FS.status("c:/windows/system128/foo.cpp");
920fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
921fc51490bSJonas Devlieghere   FS.addFile("d:/windows/foo.cpp", 0, MemoryBuffer::getMemBuffer(""));
922fc51490bSJonas Devlieghere   Stat = FS.status("d:/windows/foo.cpp");
923fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
924fc51490bSJonas Devlieghere }
925fc51490bSJonas Devlieghere 
926fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, OverlayFile) {
927fc51490bSJonas Devlieghere   FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
928fc51490bSJonas Devlieghere   NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
929fc51490bSJonas Devlieghere   auto Stat = FS.status("/");
930fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
931fc51490bSJonas Devlieghere   Stat = FS.status("/.");
932fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat);
933fc51490bSJonas Devlieghere   Stat = NormalizedFS.status("/.");
934fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << FS.toString();
935fc51490bSJonas Devlieghere   Stat = FS.status("/a");
936fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
937fc51490bSJonas Devlieghere   ASSERT_EQ("/a", Stat->getName());
938fc51490bSJonas Devlieghere }
939fc51490bSJonas Devlieghere 
940fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, OverlayFileNoOwn) {
941fc51490bSJonas Devlieghere   auto Buf = MemoryBuffer::getMemBuffer("a");
942*e763e032SDuncan P. N. Exon Smith   FS.addFileNoOwn("/a", 0, *Buf);
943fc51490bSJonas Devlieghere   auto Stat = FS.status("/a");
944fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
945fc51490bSJonas Devlieghere   ASSERT_EQ("/a", Stat->getName());
946fc51490bSJonas Devlieghere }
947fc51490bSJonas Devlieghere 
948fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, OpenFileForRead) {
949fc51490bSJonas Devlieghere   FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
950fc51490bSJonas Devlieghere   FS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
951fc51490bSJonas Devlieghere   FS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
952fc51490bSJonas Devlieghere   NormalizedFS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a"));
953fc51490bSJonas Devlieghere   NormalizedFS.addFile("././c", 0, MemoryBuffer::getMemBuffer("c"));
954fc51490bSJonas Devlieghere   NormalizedFS.addFile("./d/../d", 0, MemoryBuffer::getMemBuffer("d"));
955fc51490bSJonas Devlieghere   auto File = FS.openFileForRead("/a");
956fc51490bSJonas Devlieghere   ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
957fc51490bSJonas Devlieghere   File = FS.openFileForRead("/a"); // Open again.
958fc51490bSJonas Devlieghere   ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
959fc51490bSJonas Devlieghere   File = NormalizedFS.openFileForRead("/././a"); // Open again.
960fc51490bSJonas Devlieghere   ASSERT_EQ("a", (*(*File)->getBuffer("ignored"))->getBuffer());
961fc51490bSJonas Devlieghere   File = FS.openFileForRead("/");
962fc51490bSJonas Devlieghere   ASSERT_EQ(File.getError(), errc::invalid_argument) << FS.toString();
963fc51490bSJonas Devlieghere   File = FS.openFileForRead("/b");
964fc51490bSJonas Devlieghere   ASSERT_EQ(File.getError(), errc::no_such_file_or_directory) << FS.toString();
965fc51490bSJonas Devlieghere   File = FS.openFileForRead("./c");
966fc51490bSJonas Devlieghere   ASSERT_FALSE(File);
967fc51490bSJonas Devlieghere   File = FS.openFileForRead("e/../d");
968fc51490bSJonas Devlieghere   ASSERT_FALSE(File);
969fc51490bSJonas Devlieghere   File = NormalizedFS.openFileForRead("./c");
970fc51490bSJonas Devlieghere   ASSERT_EQ("c", (*(*File)->getBuffer("ignored"))->getBuffer());
971fc51490bSJonas Devlieghere   File = NormalizedFS.openFileForRead("e/../d");
972fc51490bSJonas Devlieghere   ASSERT_EQ("d", (*(*File)->getBuffer("ignored"))->getBuffer());
973fc51490bSJonas Devlieghere }
974fc51490bSJonas Devlieghere 
975fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, DuplicatedFile) {
976fc51490bSJonas Devlieghere   ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
977fc51490bSJonas Devlieghere   ASSERT_FALSE(FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("a")));
978fc51490bSJonas Devlieghere   ASSERT_TRUE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("a")));
979fc51490bSJonas Devlieghere   ASSERT_FALSE(FS.addFile("/a", 0, MemoryBuffer::getMemBuffer("b")));
980fc51490bSJonas Devlieghere }
981fc51490bSJonas Devlieghere 
982fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, DirectoryIteration) {
983fc51490bSJonas Devlieghere   FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""));
984fc51490bSJonas Devlieghere   FS.addFile("/b/c", 0, MemoryBuffer::getMemBuffer(""));
985fc51490bSJonas Devlieghere 
986fc51490bSJonas Devlieghere   std::error_code EC;
987fc51490bSJonas Devlieghere   vfs::directory_iterator I = FS.dir_begin("/", EC);
988fc51490bSJonas Devlieghere   ASSERT_FALSE(EC);
989fc51490bSJonas Devlieghere   ASSERT_EQ("/a", I->path());
990fc51490bSJonas Devlieghere   I.increment(EC);
991fc51490bSJonas Devlieghere   ASSERT_FALSE(EC);
992fc51490bSJonas Devlieghere   ASSERT_EQ("/b", I->path());
993fc51490bSJonas Devlieghere   I.increment(EC);
994fc51490bSJonas Devlieghere   ASSERT_FALSE(EC);
995fc51490bSJonas Devlieghere   ASSERT_EQ(vfs::directory_iterator(), I);
996fc51490bSJonas Devlieghere 
997fc51490bSJonas Devlieghere   I = FS.dir_begin("/b", EC);
998fc51490bSJonas Devlieghere   ASSERT_FALSE(EC);
999fc51490bSJonas Devlieghere   // When on Windows, we end up with "/b\\c" as the name.  Convert to Posix
1000fc51490bSJonas Devlieghere   // path for the sake of the comparison.
1001adcd0268SBenjamin Kramer   ASSERT_EQ("/b/c", getPosixPath(std::string(I->path())));
1002fc51490bSJonas Devlieghere   I.increment(EC);
1003fc51490bSJonas Devlieghere   ASSERT_FALSE(EC);
1004fc51490bSJonas Devlieghere   ASSERT_EQ(vfs::directory_iterator(), I);
1005fc51490bSJonas Devlieghere }
1006fc51490bSJonas Devlieghere 
1007fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, WorkingDirectory) {
1008fc51490bSJonas Devlieghere   FS.setCurrentWorkingDirectory("/b");
1009fc51490bSJonas Devlieghere   FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
1010fc51490bSJonas Devlieghere 
1011fc51490bSJonas Devlieghere   auto Stat = FS.status("/b/c");
1012fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1013fc51490bSJonas Devlieghere   ASSERT_EQ("/b/c", Stat->getName());
1014fc51490bSJonas Devlieghere   ASSERT_EQ("/b", *FS.getCurrentWorkingDirectory());
1015fc51490bSJonas Devlieghere 
1016fc51490bSJonas Devlieghere   Stat = FS.status("c");
1017fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1018fc51490bSJonas Devlieghere 
1019fc51490bSJonas Devlieghere   NormalizedFS.setCurrentWorkingDirectory("/b/c");
1020fc51490bSJonas Devlieghere   NormalizedFS.setCurrentWorkingDirectory(".");
1021fc51490bSJonas Devlieghere   ASSERT_EQ("/b/c",
1022fc51490bSJonas Devlieghere             getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get()));
1023fc51490bSJonas Devlieghere   NormalizedFS.setCurrentWorkingDirectory("..");
1024fc51490bSJonas Devlieghere   ASSERT_EQ("/b",
1025fc51490bSJonas Devlieghere             getPosixPath(NormalizedFS.getCurrentWorkingDirectory().get()));
1026fc51490bSJonas Devlieghere }
1027fc51490bSJonas Devlieghere 
1028cbb5c868SJonas Devlieghere TEST_F(InMemoryFileSystemTest, IsLocal) {
1029cbb5c868SJonas Devlieghere   FS.setCurrentWorkingDirectory("/b");
1030cbb5c868SJonas Devlieghere   FS.addFile("c", 0, MemoryBuffer::getMemBuffer(""));
1031cbb5c868SJonas Devlieghere 
1032cbb5c868SJonas Devlieghere   std::error_code EC;
1033cbb5c868SJonas Devlieghere   bool IsLocal = true;
1034cbb5c868SJonas Devlieghere   EC = FS.isLocal("c", IsLocal);
1035cbb5c868SJonas Devlieghere   ASSERT_FALSE(EC);
1036cbb5c868SJonas Devlieghere   ASSERT_FALSE(IsLocal);
1037cbb5c868SJonas Devlieghere }
1038cbb5c868SJonas Devlieghere 
1039fc51490bSJonas Devlieghere #if !defined(_WIN32)
1040fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, GetRealPath) {
1041fc51490bSJonas Devlieghere   SmallString<16> Path;
1042fc51490bSJonas Devlieghere   EXPECT_EQ(FS.getRealPath("b", Path), errc::operation_not_permitted);
1043fc51490bSJonas Devlieghere 
1044fc51490bSJonas Devlieghere   auto GetRealPath = [this](StringRef P) {
1045fc51490bSJonas Devlieghere     SmallString<16> Output;
1046fc51490bSJonas Devlieghere     auto EC = FS.getRealPath(P, Output);
1047fc51490bSJonas Devlieghere     EXPECT_FALSE(EC);
1048b2924d99SJonas Devlieghere     return std::string(Output);
1049fc51490bSJonas Devlieghere   };
1050fc51490bSJonas Devlieghere 
1051fc51490bSJonas Devlieghere   FS.setCurrentWorkingDirectory("a");
1052fc51490bSJonas Devlieghere   EXPECT_EQ(GetRealPath("b"), "a/b");
1053fc51490bSJonas Devlieghere   EXPECT_EQ(GetRealPath("../b"), "b");
1054fc51490bSJonas Devlieghere   EXPECT_EQ(GetRealPath("b/./c"), "a/b/c");
1055fc51490bSJonas Devlieghere 
1056fc51490bSJonas Devlieghere   FS.setCurrentWorkingDirectory("/a");
1057fc51490bSJonas Devlieghere   EXPECT_EQ(GetRealPath("b"), "/a/b");
1058fc51490bSJonas Devlieghere   EXPECT_EQ(GetRealPath("../b"), "/b");
1059fc51490bSJonas Devlieghere   EXPECT_EQ(GetRealPath("b/./c"), "/a/b/c");
1060fc51490bSJonas Devlieghere }
1061fc51490bSJonas Devlieghere #endif // _WIN32
1062fc51490bSJonas Devlieghere 
1063fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, AddFileWithUser) {
1064fc51490bSJonas Devlieghere   FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), 0xFEEDFACE);
1065fc51490bSJonas Devlieghere   auto Stat = FS.status("/a");
1066fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1067fc51490bSJonas Devlieghere   ASSERT_TRUE(Stat->isDirectory());
1068fc51490bSJonas Devlieghere   ASSERT_EQ(0xFEEDFACE, Stat->getUser());
1069fc51490bSJonas Devlieghere   Stat = FS.status("/a/b");
1070fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1071fc51490bSJonas Devlieghere   ASSERT_TRUE(Stat->isDirectory());
1072fc51490bSJonas Devlieghere   ASSERT_EQ(0xFEEDFACE, Stat->getUser());
1073fc51490bSJonas Devlieghere   Stat = FS.status("/a/b/c");
1074fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1075fc51490bSJonas Devlieghere   ASSERT_TRUE(Stat->isRegularFile());
1076fc51490bSJonas Devlieghere   ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
1077fc51490bSJonas Devlieghere   ASSERT_EQ(0xFEEDFACE, Stat->getUser());
1078fc51490bSJonas Devlieghere }
1079fc51490bSJonas Devlieghere 
1080fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, AddFileWithGroup) {
1081fc51490bSJonas Devlieghere   FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, 0xDABBAD00);
1082fc51490bSJonas Devlieghere   auto Stat = FS.status("/a");
1083fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1084fc51490bSJonas Devlieghere   ASSERT_TRUE(Stat->isDirectory());
1085fc51490bSJonas Devlieghere   ASSERT_EQ(0xDABBAD00, Stat->getGroup());
1086fc51490bSJonas Devlieghere   Stat = FS.status("/a/b");
1087fc51490bSJonas Devlieghere   ASSERT_TRUE(Stat->isDirectory());
1088fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1089fc51490bSJonas Devlieghere   ASSERT_EQ(0xDABBAD00, Stat->getGroup());
1090fc51490bSJonas Devlieghere   Stat = FS.status("/a/b/c");
1091fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1092fc51490bSJonas Devlieghere   ASSERT_TRUE(Stat->isRegularFile());
1093fc51490bSJonas Devlieghere   ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
1094fc51490bSJonas Devlieghere   ASSERT_EQ(0xDABBAD00, Stat->getGroup());
1095fc51490bSJonas Devlieghere }
1096fc51490bSJonas Devlieghere 
1097fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, AddFileWithFileType) {
1098fc51490bSJonas Devlieghere   FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None,
1099fc51490bSJonas Devlieghere              sys::fs::file_type::socket_file);
1100fc51490bSJonas Devlieghere   auto Stat = FS.status("/a");
1101fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1102fc51490bSJonas Devlieghere   ASSERT_TRUE(Stat->isDirectory());
1103fc51490bSJonas Devlieghere   Stat = FS.status("/a/b");
1104fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1105fc51490bSJonas Devlieghere   ASSERT_TRUE(Stat->isDirectory());
1106fc51490bSJonas Devlieghere   Stat = FS.status("/a/b/c");
1107fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1108fc51490bSJonas Devlieghere   ASSERT_EQ(sys::fs::file_type::socket_file, Stat->getType());
1109fc51490bSJonas Devlieghere   ASSERT_EQ(sys::fs::perms::all_all, Stat->getPermissions());
1110fc51490bSJonas Devlieghere }
1111fc51490bSJonas Devlieghere 
1112fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, AddFileWithPerms) {
1113fc51490bSJonas Devlieghere   FS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"), None, None, None,
1114fc51490bSJonas Devlieghere              sys::fs::perms::owner_read | sys::fs::perms::owner_write);
1115fc51490bSJonas Devlieghere   auto Stat = FS.status("/a");
1116fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1117fc51490bSJonas Devlieghere   ASSERT_TRUE(Stat->isDirectory());
1118fc51490bSJonas Devlieghere   ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
1119fc51490bSJonas Devlieghere                 sys::fs::perms::owner_exe,
1120fc51490bSJonas Devlieghere             Stat->getPermissions());
1121fc51490bSJonas Devlieghere   Stat = FS.status("/a/b");
1122fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1123fc51490bSJonas Devlieghere   ASSERT_TRUE(Stat->isDirectory());
1124fc51490bSJonas Devlieghere   ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write |
1125fc51490bSJonas Devlieghere                 sys::fs::perms::owner_exe,
1126fc51490bSJonas Devlieghere             Stat->getPermissions());
1127fc51490bSJonas Devlieghere   Stat = FS.status("/a/b/c");
1128fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1129fc51490bSJonas Devlieghere   ASSERT_TRUE(Stat->isRegularFile());
1130fc51490bSJonas Devlieghere   ASSERT_EQ(sys::fs::perms::owner_read | sys::fs::perms::owner_write,
1131fc51490bSJonas Devlieghere             Stat->getPermissions());
1132fc51490bSJonas Devlieghere }
1133fc51490bSJonas Devlieghere 
1134fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, AddDirectoryThenAddChild) {
1135fc51490bSJonas Devlieghere   FS.addFile("/a", 0, MemoryBuffer::getMemBuffer(""), /*User=*/None,
1136fc51490bSJonas Devlieghere              /*Group=*/None, sys::fs::file_type::directory_file);
1137fc51490bSJonas Devlieghere   FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("abc"), /*User=*/None,
1138fc51490bSJonas Devlieghere              /*Group=*/None, sys::fs::file_type::regular_file);
1139fc51490bSJonas Devlieghere   auto Stat = FS.status("/a");
1140fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1141fc51490bSJonas Devlieghere   ASSERT_TRUE(Stat->isDirectory());
1142fc51490bSJonas Devlieghere   Stat = FS.status("/a/b");
1143fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n" << FS.toString();
1144fc51490bSJonas Devlieghere   ASSERT_TRUE(Stat->isRegularFile());
1145fc51490bSJonas Devlieghere }
1146fc51490bSJonas Devlieghere 
1147fc51490bSJonas Devlieghere // Test that the name returned by status() is in the same form as the path that
1148fc51490bSJonas Devlieghere // was requested (to match the behavior of RealFileSystem).
1149fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, StatusName) {
1150fc51490bSJonas Devlieghere   NormalizedFS.addFile("/a/b/c", 0, MemoryBuffer::getMemBuffer("abc"),
1151fc51490bSJonas Devlieghere                        /*User=*/None,
1152fc51490bSJonas Devlieghere                        /*Group=*/None, sys::fs::file_type::regular_file);
1153fc51490bSJonas Devlieghere   NormalizedFS.setCurrentWorkingDirectory("/a/b");
1154fc51490bSJonas Devlieghere 
1155fc51490bSJonas Devlieghere   // Access using InMemoryFileSystem::status.
1156fc51490bSJonas Devlieghere   auto Stat = NormalizedFS.status("../b/c");
1157fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
1158fc51490bSJonas Devlieghere                                 << NormalizedFS.toString();
1159fc51490bSJonas Devlieghere   ASSERT_TRUE(Stat->isRegularFile());
1160fc51490bSJonas Devlieghere   ASSERT_EQ("../b/c", Stat->getName());
1161fc51490bSJonas Devlieghere 
1162fc51490bSJonas Devlieghere   // Access using InMemoryFileAdaptor::status.
1163fc51490bSJonas Devlieghere   auto File = NormalizedFS.openFileForRead("../b/c");
1164fc51490bSJonas Devlieghere   ASSERT_FALSE(File.getError()) << File.getError() << "\n"
1165fc51490bSJonas Devlieghere                                 << NormalizedFS.toString();
1166fc51490bSJonas Devlieghere   Stat = (*File)->status();
1167fc51490bSJonas Devlieghere   ASSERT_FALSE(Stat.getError()) << Stat.getError() << "\n"
1168fc51490bSJonas Devlieghere                                 << NormalizedFS.toString();
1169fc51490bSJonas Devlieghere   ASSERT_TRUE(Stat->isRegularFile());
1170fc51490bSJonas Devlieghere   ASSERT_EQ("../b/c", Stat->getName());
1171fc51490bSJonas Devlieghere 
1172fc51490bSJonas Devlieghere   // Access using a directory iterator.
1173fc51490bSJonas Devlieghere   std::error_code EC;
1174fc51490bSJonas Devlieghere   llvm::vfs::directory_iterator It = NormalizedFS.dir_begin("../b", EC);
1175fc51490bSJonas Devlieghere   // When on Windows, we end up with "../b\\c" as the name.  Convert to Posix
1176fc51490bSJonas Devlieghere   // path for the sake of the comparison.
1177adcd0268SBenjamin Kramer   ASSERT_EQ("../b/c", getPosixPath(std::string(It->path())));
1178fc51490bSJonas Devlieghere }
1179fc51490bSJonas Devlieghere 
1180fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, AddHardLinkToFile) {
1181fc51490bSJonas Devlieghere   StringRef FromLink = "/path/to/FROM/link";
1182fc51490bSJonas Devlieghere   StringRef Target = "/path/to/TO/file";
1183fc51490bSJonas Devlieghere   FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1184fc51490bSJonas Devlieghere   EXPECT_TRUE(FS.addHardLink(FromLink, Target));
1185fc51490bSJonas Devlieghere   EXPECT_THAT(FromLink, IsHardLinkTo(&FS, Target));
1186fc51490bSJonas Devlieghere   EXPECT_TRUE(FS.status(FromLink)->getSize() == FS.status(Target)->getSize());
1187fc51490bSJonas Devlieghere   EXPECT_TRUE(FS.getBufferForFile(FromLink)->get()->getBuffer() ==
1188fc51490bSJonas Devlieghere               FS.getBufferForFile(Target)->get()->getBuffer());
1189fc51490bSJonas Devlieghere }
1190fc51490bSJonas Devlieghere 
1191fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, AddHardLinkInChainPattern) {
1192fc51490bSJonas Devlieghere   StringRef Link0 = "/path/to/0/link";
1193fc51490bSJonas Devlieghere   StringRef Link1 = "/path/to/1/link";
1194fc51490bSJonas Devlieghere   StringRef Link2 = "/path/to/2/link";
1195fc51490bSJonas Devlieghere   StringRef Target = "/path/to/target";
1196fc51490bSJonas Devlieghere   FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target file"));
1197fc51490bSJonas Devlieghere   EXPECT_TRUE(FS.addHardLink(Link2, Target));
1198fc51490bSJonas Devlieghere   EXPECT_TRUE(FS.addHardLink(Link1, Link2));
1199fc51490bSJonas Devlieghere   EXPECT_TRUE(FS.addHardLink(Link0, Link1));
1200fc51490bSJonas Devlieghere   EXPECT_THAT(Link0, IsHardLinkTo(&FS, Target));
1201fc51490bSJonas Devlieghere   EXPECT_THAT(Link1, IsHardLinkTo(&FS, Target));
1202fc51490bSJonas Devlieghere   EXPECT_THAT(Link2, IsHardLinkTo(&FS, Target));
1203fc51490bSJonas Devlieghere }
1204fc51490bSJonas Devlieghere 
1205fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, AddHardLinkToAFileThatWasNotAddedBefore) {
1206fc51490bSJonas Devlieghere   EXPECT_FALSE(FS.addHardLink("/path/to/link", "/path/to/target"));
1207fc51490bSJonas Devlieghere }
1208fc51490bSJonas Devlieghere 
1209fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, AddHardLinkFromAFileThatWasAddedBefore) {
1210fc51490bSJonas Devlieghere   StringRef Link = "/path/to/link";
1211fc51490bSJonas Devlieghere   StringRef Target = "/path/to/target";
1212fc51490bSJonas Devlieghere   FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1213fc51490bSJonas Devlieghere   FS.addFile(Link, 0, MemoryBuffer::getMemBuffer("content of link"));
1214fc51490bSJonas Devlieghere   EXPECT_FALSE(FS.addHardLink(Link, Target));
1215fc51490bSJonas Devlieghere }
1216fc51490bSJonas Devlieghere 
1217fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, AddSameHardLinkMoreThanOnce) {
1218fc51490bSJonas Devlieghere   StringRef Link = "/path/to/link";
1219fc51490bSJonas Devlieghere   StringRef Target = "/path/to/target";
1220fc51490bSJonas Devlieghere   FS.addFile(Target, 0, MemoryBuffer::getMemBuffer("content of target"));
1221fc51490bSJonas Devlieghere   EXPECT_TRUE(FS.addHardLink(Link, Target));
1222fc51490bSJonas Devlieghere   EXPECT_FALSE(FS.addHardLink(Link, Target));
1223fc51490bSJonas Devlieghere }
1224fc51490bSJonas Devlieghere 
1225fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, AddFileInPlaceOfAHardLinkWithSameContent) {
1226fc51490bSJonas Devlieghere   StringRef Link = "/path/to/link";
1227fc51490bSJonas Devlieghere   StringRef Target = "/path/to/target";
1228fc51490bSJonas Devlieghere   StringRef Content = "content of target";
1229fc51490bSJonas Devlieghere   EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1230fc51490bSJonas Devlieghere   EXPECT_TRUE(FS.addHardLink(Link, Target));
1231fc51490bSJonas Devlieghere   EXPECT_TRUE(FS.addFile(Link, 0, MemoryBuffer::getMemBuffer(Content)));
1232fc51490bSJonas Devlieghere }
1233fc51490bSJonas Devlieghere 
1234fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, AddFileInPlaceOfAHardLinkWithDifferentContent) {
1235fc51490bSJonas Devlieghere   StringRef Link = "/path/to/link";
1236fc51490bSJonas Devlieghere   StringRef Target = "/path/to/target";
1237fc51490bSJonas Devlieghere   StringRef Content = "content of target";
1238fc51490bSJonas Devlieghere   StringRef LinkContent = "different content of link";
1239fc51490bSJonas Devlieghere   EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1240fc51490bSJonas Devlieghere   EXPECT_TRUE(FS.addHardLink(Link, Target));
1241fc51490bSJonas Devlieghere   EXPECT_FALSE(FS.addFile(Link, 0, MemoryBuffer::getMemBuffer(LinkContent)));
1242fc51490bSJonas Devlieghere }
1243fc51490bSJonas Devlieghere 
1244fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, AddHardLinkToADirectory) {
1245fc51490bSJonas Devlieghere   StringRef Dir = "path/to/dummy/dir";
1246fc51490bSJonas Devlieghere   StringRef Link = "/path/to/link";
1247fc51490bSJonas Devlieghere   StringRef File = "path/to/dummy/dir/target";
1248fc51490bSJonas Devlieghere   StringRef Content = "content of target";
1249fc51490bSJonas Devlieghere   EXPECT_TRUE(FS.addFile(File, 0, MemoryBuffer::getMemBuffer(Content)));
1250fc51490bSJonas Devlieghere   EXPECT_FALSE(FS.addHardLink(Link, Dir));
1251fc51490bSJonas Devlieghere }
1252fc51490bSJonas Devlieghere 
1253fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, AddHardLinkFromADirectory) {
1254fc51490bSJonas Devlieghere   StringRef Dir = "path/to/dummy/dir";
1255fc51490bSJonas Devlieghere   StringRef Target = "path/to/dummy/dir/target";
1256fc51490bSJonas Devlieghere   StringRef Content = "content of target";
1257fc51490bSJonas Devlieghere   EXPECT_TRUE(FS.addFile(Target, 0, MemoryBuffer::getMemBuffer(Content)));
1258fc51490bSJonas Devlieghere   EXPECT_FALSE(FS.addHardLink(Dir, Target));
1259fc51490bSJonas Devlieghere }
1260fc51490bSJonas Devlieghere 
1261fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, AddHardLinkUnderAFile) {
1262fc51490bSJonas Devlieghere   StringRef CommonContent = "content string";
1263fc51490bSJonas Devlieghere   FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer(CommonContent));
1264fc51490bSJonas Devlieghere   FS.addFile("/c/d", 0, MemoryBuffer::getMemBuffer(CommonContent));
1265fc51490bSJonas Devlieghere   EXPECT_FALSE(FS.addHardLink("/c/d/e", "/a/b"));
1266fc51490bSJonas Devlieghere }
1267fc51490bSJonas Devlieghere 
1268fc51490bSJonas Devlieghere TEST_F(InMemoryFileSystemTest, RecursiveIterationWithHardLink) {
1269fc51490bSJonas Devlieghere   std::error_code EC;
1270fc51490bSJonas Devlieghere   FS.addFile("/a/b", 0, MemoryBuffer::getMemBuffer("content string"));
1271fc51490bSJonas Devlieghere   EXPECT_TRUE(FS.addHardLink("/c/d", "/a/b"));
1272fc51490bSJonas Devlieghere   auto I = vfs::recursive_directory_iterator(FS, "/", EC);
1273fc51490bSJonas Devlieghere   ASSERT_FALSE(EC);
1274fc51490bSJonas Devlieghere   std::vector<std::string> Nodes;
1275fc51490bSJonas Devlieghere   for (auto E = vfs::recursive_directory_iterator(); !EC && I != E;
1276fc51490bSJonas Devlieghere        I.increment(EC)) {
1277adcd0268SBenjamin Kramer     Nodes.push_back(getPosixPath(std::string(I->path())));
1278fc51490bSJonas Devlieghere   }
1279fc51490bSJonas Devlieghere   EXPECT_THAT(Nodes, testing::UnorderedElementsAre("/a", "/a/b", "/c", "/c/d"));
1280fc51490bSJonas Devlieghere }
1281fc51490bSJonas Devlieghere 
1282fc51490bSJonas Devlieghere // NOTE: in the tests below, we use '//root/' as our root directory, since it is
1283fc51490bSJonas Devlieghere // a legal *absolute* path on Windows as well as *nix.
1284fc51490bSJonas Devlieghere class VFSFromYAMLTest : public ::testing::Test {
1285fc51490bSJonas Devlieghere public:
1286fc51490bSJonas Devlieghere   int NumDiagnostics;
1287fc51490bSJonas Devlieghere 
1288fc51490bSJonas Devlieghere   void SetUp() override { NumDiagnostics = 0; }
1289fc51490bSJonas Devlieghere 
1290fc51490bSJonas Devlieghere   static void CountingDiagHandler(const SMDiagnostic &, void *Context) {
1291fc51490bSJonas Devlieghere     VFSFromYAMLTest *Test = static_cast<VFSFromYAMLTest *>(Context);
1292fc51490bSJonas Devlieghere     ++Test->NumDiagnostics;
1293fc51490bSJonas Devlieghere   }
1294fc51490bSJonas Devlieghere 
1295fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem>
1296fc51490bSJonas Devlieghere   getFromYAMLRawString(StringRef Content,
1297fc51490bSJonas Devlieghere                        IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS) {
1298fc51490bSJonas Devlieghere     std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(Content);
1299fc51490bSJonas Devlieghere     return getVFSFromYAML(std::move(Buffer), CountingDiagHandler, "", this,
1300fc51490bSJonas Devlieghere                           ExternalFS);
1301fc51490bSJonas Devlieghere   }
1302fc51490bSJonas Devlieghere 
1303fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> getFromYAMLString(
1304fc51490bSJonas Devlieghere       StringRef Content,
1305fc51490bSJonas Devlieghere       IntrusiveRefCntPtr<vfs::FileSystem> ExternalFS = new DummyFileSystem()) {
1306fc51490bSJonas Devlieghere     std::string VersionPlusContent("{\n  'version':0,\n");
1307fc51490bSJonas Devlieghere     VersionPlusContent += Content.slice(Content.find('{') + 1, StringRef::npos);
1308fc51490bSJonas Devlieghere     return getFromYAMLRawString(VersionPlusContent, ExternalFS);
1309fc51490bSJonas Devlieghere   }
1310fc51490bSJonas Devlieghere 
1311fc51490bSJonas Devlieghere   // This is intended as a "XFAIL" for windows hosts.
1312fc51490bSJonas Devlieghere   bool supportsSameDirMultipleYAMLEntries() {
1313fc51490bSJonas Devlieghere     Triple Host(Triple::normalize(sys::getProcessTriple()));
1314fc51490bSJonas Devlieghere     return !Host.isOSWindows();
1315fc51490bSJonas Devlieghere   }
1316fc51490bSJonas Devlieghere };
1317fc51490bSJonas Devlieghere 
1318fc51490bSJonas Devlieghere TEST_F(VFSFromYAMLTest, BasicVFSFromYAML) {
1319fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS;
1320fc51490bSJonas Devlieghere   FS = getFromYAMLString("");
1321fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1322fc51490bSJonas Devlieghere   FS = getFromYAMLString("[]");
1323fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1324fc51490bSJonas Devlieghere   FS = getFromYAMLString("'string'");
1325fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1326fc51490bSJonas Devlieghere   EXPECT_EQ(3, NumDiagnostics);
1327fc51490bSJonas Devlieghere }
1328fc51490bSJonas Devlieghere 
1329fc51490bSJonas Devlieghere TEST_F(VFSFromYAMLTest, MappedFiles) {
1330fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1331fc51490bSJonas Devlieghere   Lower->addRegularFile("//root/foo/bar/a");
1332fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1333fc51490bSJonas Devlieghere       "{ 'roots': [\n"
1334fc51490bSJonas Devlieghere       "{\n"
1335fc51490bSJonas Devlieghere       "  'type': 'directory',\n"
1336fc51490bSJonas Devlieghere       "  'name': '//root/',\n"
1337fc51490bSJonas Devlieghere       "  'contents': [ {\n"
1338fc51490bSJonas Devlieghere       "                  'type': 'file',\n"
1339fc51490bSJonas Devlieghere       "                  'name': 'file1',\n"
1340fc51490bSJonas Devlieghere       "                  'external-contents': '//root/foo/bar/a'\n"
1341fc51490bSJonas Devlieghere       "                },\n"
1342fc51490bSJonas Devlieghere       "                {\n"
1343fc51490bSJonas Devlieghere       "                  'type': 'file',\n"
1344fc51490bSJonas Devlieghere       "                  'name': 'file2',\n"
1345fc51490bSJonas Devlieghere       "                  'external-contents': '//root/foo/b'\n"
1346fc51490bSJonas Devlieghere       "                }\n"
1347fc51490bSJonas Devlieghere       "              ]\n"
1348fc51490bSJonas Devlieghere       "}\n"
1349fc51490bSJonas Devlieghere       "]\n"
1350fc51490bSJonas Devlieghere       "}",
1351fc51490bSJonas Devlieghere       Lower);
1352fc51490bSJonas Devlieghere   ASSERT_TRUE(FS.get() != nullptr);
1353fc51490bSJonas Devlieghere 
1354fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1355fc51490bSJonas Devlieghere       new vfs::OverlayFileSystem(Lower));
1356fc51490bSJonas Devlieghere   O->pushOverlay(FS);
1357fc51490bSJonas Devlieghere 
1358fc51490bSJonas Devlieghere   // file
1359fc51490bSJonas Devlieghere   ErrorOr<vfs::Status> S = O->status("//root/file1");
1360fc51490bSJonas Devlieghere   ASSERT_FALSE(S.getError());
1361fc51490bSJonas Devlieghere   EXPECT_EQ("//root/foo/bar/a", S->getName());
1362fc51490bSJonas Devlieghere   EXPECT_TRUE(S->IsVFSMapped);
1363fc51490bSJonas Devlieghere 
1364fc51490bSJonas Devlieghere   ErrorOr<vfs::Status> SLower = O->status("//root/foo/bar/a");
1365fc51490bSJonas Devlieghere   EXPECT_EQ("//root/foo/bar/a", SLower->getName());
1366fc51490bSJonas Devlieghere   EXPECT_TRUE(S->equivalent(*SLower));
1367fc51490bSJonas Devlieghere   EXPECT_FALSE(SLower->IsVFSMapped);
1368fc51490bSJonas Devlieghere 
1369fc51490bSJonas Devlieghere   // file after opening
1370fc51490bSJonas Devlieghere   auto OpenedF = O->openFileForRead("//root/file1");
1371fc51490bSJonas Devlieghere   ASSERT_FALSE(OpenedF.getError());
1372fc51490bSJonas Devlieghere   auto OpenedS = (*OpenedF)->status();
1373fc51490bSJonas Devlieghere   ASSERT_FALSE(OpenedS.getError());
1374fc51490bSJonas Devlieghere   EXPECT_EQ("//root/foo/bar/a", OpenedS->getName());
1375fc51490bSJonas Devlieghere   EXPECT_TRUE(OpenedS->IsVFSMapped);
1376fc51490bSJonas Devlieghere 
1377fc51490bSJonas Devlieghere   // directory
1378fc51490bSJonas Devlieghere   S = O->status("//root/");
1379fc51490bSJonas Devlieghere   ASSERT_FALSE(S.getError());
1380fc51490bSJonas Devlieghere   EXPECT_TRUE(S->isDirectory());
1381fc51490bSJonas Devlieghere   EXPECT_TRUE(S->equivalent(*O->status("//root/"))); // non-volatile UniqueID
1382fc51490bSJonas Devlieghere 
1383fc51490bSJonas Devlieghere   // broken mapping
1384fc51490bSJonas Devlieghere   EXPECT_EQ(O->status("//root/file2").getError(),
1385fc51490bSJonas Devlieghere             llvm::errc::no_such_file_or_directory);
1386fc51490bSJonas Devlieghere   EXPECT_EQ(0, NumDiagnostics);
1387fc51490bSJonas Devlieghere }
1388fc51490bSJonas Devlieghere 
1389fc51490bSJonas Devlieghere TEST_F(VFSFromYAMLTest, CaseInsensitive) {
1390fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1391fc51490bSJonas Devlieghere   Lower->addRegularFile("//root/foo/bar/a");
1392fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1393fc51490bSJonas Devlieghere       "{ 'case-sensitive': 'false',\n"
1394fc51490bSJonas Devlieghere       "  'roots': [\n"
1395fc51490bSJonas Devlieghere       "{\n"
1396fc51490bSJonas Devlieghere       "  'type': 'directory',\n"
1397fc51490bSJonas Devlieghere       "  'name': '//root/',\n"
1398fc51490bSJonas Devlieghere       "  'contents': [ {\n"
1399fc51490bSJonas Devlieghere       "                  'type': 'file',\n"
1400fc51490bSJonas Devlieghere       "                  'name': 'XX',\n"
1401fc51490bSJonas Devlieghere       "                  'external-contents': '//root/foo/bar/a'\n"
1402fc51490bSJonas Devlieghere       "                }\n"
1403fc51490bSJonas Devlieghere       "              ]\n"
1404fc51490bSJonas Devlieghere       "}]}",
1405fc51490bSJonas Devlieghere       Lower);
1406fc51490bSJonas Devlieghere   ASSERT_TRUE(FS.get() != nullptr);
1407fc51490bSJonas Devlieghere 
1408fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1409fc51490bSJonas Devlieghere       new vfs::OverlayFileSystem(Lower));
1410fc51490bSJonas Devlieghere   O->pushOverlay(FS);
1411fc51490bSJonas Devlieghere 
1412fc51490bSJonas Devlieghere   ErrorOr<vfs::Status> S = O->status("//root/XX");
1413fc51490bSJonas Devlieghere   ASSERT_FALSE(S.getError());
1414fc51490bSJonas Devlieghere 
1415fc51490bSJonas Devlieghere   ErrorOr<vfs::Status> SS = O->status("//root/xx");
1416fc51490bSJonas Devlieghere   ASSERT_FALSE(SS.getError());
1417fc51490bSJonas Devlieghere   EXPECT_TRUE(S->equivalent(*SS));
1418fc51490bSJonas Devlieghere   SS = O->status("//root/xX");
1419fc51490bSJonas Devlieghere   EXPECT_TRUE(S->equivalent(*SS));
1420fc51490bSJonas Devlieghere   SS = O->status("//root/Xx");
1421fc51490bSJonas Devlieghere   EXPECT_TRUE(S->equivalent(*SS));
1422fc51490bSJonas Devlieghere   EXPECT_EQ(0, NumDiagnostics);
1423fc51490bSJonas Devlieghere }
1424fc51490bSJonas Devlieghere 
1425fc51490bSJonas Devlieghere TEST_F(VFSFromYAMLTest, CaseSensitive) {
1426fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1427fc51490bSJonas Devlieghere   Lower->addRegularFile("//root/foo/bar/a");
1428fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1429fc51490bSJonas Devlieghere       "{ 'case-sensitive': 'true',\n"
1430fc51490bSJonas Devlieghere       "  'roots': [\n"
1431fc51490bSJonas Devlieghere       "{\n"
1432fc51490bSJonas Devlieghere       "  'type': 'directory',\n"
1433fc51490bSJonas Devlieghere       "  'name': '//root/',\n"
1434fc51490bSJonas Devlieghere       "  'contents': [ {\n"
1435fc51490bSJonas Devlieghere       "                  'type': 'file',\n"
1436fc51490bSJonas Devlieghere       "                  'name': 'XX',\n"
1437fc51490bSJonas Devlieghere       "                  'external-contents': '//root/foo/bar/a'\n"
1438fc51490bSJonas Devlieghere       "                }\n"
1439fc51490bSJonas Devlieghere       "              ]\n"
1440fc51490bSJonas Devlieghere       "}]}",
1441fc51490bSJonas Devlieghere       Lower);
1442fc51490bSJonas Devlieghere   ASSERT_TRUE(FS.get() != nullptr);
1443fc51490bSJonas Devlieghere 
1444fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1445fc51490bSJonas Devlieghere       new vfs::OverlayFileSystem(Lower));
1446fc51490bSJonas Devlieghere   O->pushOverlay(FS);
1447fc51490bSJonas Devlieghere 
1448fc51490bSJonas Devlieghere   ErrorOr<vfs::Status> SS = O->status("//root/xx");
1449fc51490bSJonas Devlieghere   EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
1450fc51490bSJonas Devlieghere   SS = O->status("//root/xX");
1451fc51490bSJonas Devlieghere   EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
1452fc51490bSJonas Devlieghere   SS = O->status("//root/Xx");
1453fc51490bSJonas Devlieghere   EXPECT_EQ(SS.getError(), llvm::errc::no_such_file_or_directory);
1454fc51490bSJonas Devlieghere   EXPECT_EQ(0, NumDiagnostics);
1455fc51490bSJonas Devlieghere }
1456fc51490bSJonas Devlieghere 
1457fc51490bSJonas Devlieghere TEST_F(VFSFromYAMLTest, IllegalVFSFile) {
1458fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1459fc51490bSJonas Devlieghere 
1460fc51490bSJonas Devlieghere   // invalid YAML at top-level
1461fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString("{]", Lower);
1462fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1463fc51490bSJonas Devlieghere   // invalid YAML in roots
1464fc51490bSJonas Devlieghere   FS = getFromYAMLString("{ 'roots':[}", Lower);
1465fc51490bSJonas Devlieghere   // invalid YAML in directory
1466fc51490bSJonas Devlieghere   FS = getFromYAMLString(
1467fc51490bSJonas Devlieghere       "{ 'roots':[ { 'name': 'foo', 'type': 'directory', 'contents': [}",
1468fc51490bSJonas Devlieghere       Lower);
1469fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1470fc51490bSJonas Devlieghere 
1471fc51490bSJonas Devlieghere   // invalid configuration
1472fc51490bSJonas Devlieghere   FS = getFromYAMLString("{ 'knobular': 'true', 'roots':[] }", Lower);
1473fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1474fc51490bSJonas Devlieghere   FS = getFromYAMLString("{ 'case-sensitive': 'maybe', 'roots':[] }", Lower);
1475fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1476fc51490bSJonas Devlieghere 
1477fc51490bSJonas Devlieghere   // invalid roots
1478fc51490bSJonas Devlieghere   FS = getFromYAMLString("{ 'roots':'' }", Lower);
1479fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1480fc51490bSJonas Devlieghere   FS = getFromYAMLString("{ 'roots':{} }", Lower);
1481fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1482fc51490bSJonas Devlieghere 
1483fc51490bSJonas Devlieghere   // invalid entries
1484fc51490bSJonas Devlieghere   FS = getFromYAMLString(
1485fc51490bSJonas Devlieghere       "{ 'roots':[ { 'type': 'other', 'name': 'me', 'contents': '' }", Lower);
1486fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1487fc51490bSJonas Devlieghere   FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': [], "
1488fc51490bSJonas Devlieghere                          "'external-contents': 'other' }",
1489fc51490bSJonas Devlieghere                          Lower);
1490fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1491fc51490bSJonas Devlieghere   FS = getFromYAMLString(
1492fc51490bSJonas Devlieghere       "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': [] }",
1493fc51490bSJonas Devlieghere       Lower);
1494fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1495fc51490bSJonas Devlieghere   FS = getFromYAMLString(
1496fc51490bSJonas Devlieghere       "{ 'roots':[ { 'type': 'file', 'name': 'me', 'external-contents': {} }",
1497fc51490bSJonas Devlieghere       Lower);
1498fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1499fc51490bSJonas Devlieghere   FS = getFromYAMLString(
1500fc51490bSJonas Devlieghere       "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': {} }",
1501fc51490bSJonas Devlieghere       Lower);
1502fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1503fc51490bSJonas Devlieghere   FS = getFromYAMLString(
1504fc51490bSJonas Devlieghere       "{ 'roots':[ { 'type': 'directory', 'name': 'me', 'contents': '' }",
1505fc51490bSJonas Devlieghere       Lower);
1506fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1507fc51490bSJonas Devlieghere   FS = getFromYAMLString(
1508fc51490bSJonas Devlieghere       "{ 'roots':[ { 'thingy': 'directory', 'name': 'me', 'contents': [] }",
1509fc51490bSJonas Devlieghere       Lower);
1510fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1511fc51490bSJonas Devlieghere 
1512fc51490bSJonas Devlieghere   // missing mandatory fields
1513fc51490bSJonas Devlieghere   FS = getFromYAMLString("{ 'roots':[ { 'type': 'file', 'name': 'me' }", Lower);
1514fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1515fc51490bSJonas Devlieghere   FS = getFromYAMLString(
1516fc51490bSJonas Devlieghere       "{ 'roots':[ { 'type': 'file', 'external-contents': 'other' }", Lower);
1517fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1518fc51490bSJonas Devlieghere   FS = getFromYAMLString("{ 'roots':[ { 'name': 'me', 'contents': [] }", Lower);
1519fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1520fc51490bSJonas Devlieghere 
1521fc51490bSJonas Devlieghere   // duplicate keys
1522fc51490bSJonas Devlieghere   FS = getFromYAMLString("{ 'roots':[], 'roots':[] }", Lower);
1523fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1524fc51490bSJonas Devlieghere   FS = getFromYAMLString(
1525fc51490bSJonas Devlieghere       "{ 'case-sensitive':'true', 'case-sensitive':'true', 'roots':[] }",
1526fc51490bSJonas Devlieghere       Lower);
1527fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1528fc51490bSJonas Devlieghere   FS =
1529fc51490bSJonas Devlieghere       getFromYAMLString("{ 'roots':[{'name':'me', 'name':'you', 'type':'file', "
1530fc51490bSJonas Devlieghere                         "'external-contents':'blah' } ] }",
1531fc51490bSJonas Devlieghere                         Lower);
1532fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1533fc51490bSJonas Devlieghere 
1534fc51490bSJonas Devlieghere   // missing version
1535fc51490bSJonas Devlieghere   FS = getFromYAMLRawString("{ 'roots':[] }", Lower);
1536fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1537fc51490bSJonas Devlieghere 
1538fc51490bSJonas Devlieghere   // bad version number
1539fc51490bSJonas Devlieghere   FS = getFromYAMLRawString("{ 'version':'foo', 'roots':[] }", Lower);
1540fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1541fc51490bSJonas Devlieghere   FS = getFromYAMLRawString("{ 'version':-1, 'roots':[] }", Lower);
1542fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1543fc51490bSJonas Devlieghere   FS = getFromYAMLRawString("{ 'version':100000, 'roots':[] }", Lower);
1544fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1545fc51490bSJonas Devlieghere   EXPECT_EQ(24, NumDiagnostics);
1546fc51490bSJonas Devlieghere }
1547fc51490bSJonas Devlieghere 
1548fc51490bSJonas Devlieghere TEST_F(VFSFromYAMLTest, UseExternalName) {
1549fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1550fc51490bSJonas Devlieghere   Lower->addRegularFile("//root/external/file");
1551fc51490bSJonas Devlieghere 
1552fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS =
1553fc51490bSJonas Devlieghere       getFromYAMLString("{ 'roots': [\n"
1554fc51490bSJonas Devlieghere                         "  { 'type': 'file', 'name': '//root/A',\n"
1555fc51490bSJonas Devlieghere                         "    'external-contents': '//root/external/file'\n"
1556fc51490bSJonas Devlieghere                         "  },\n"
1557fc51490bSJonas Devlieghere                         "  { 'type': 'file', 'name': '//root/B',\n"
1558fc51490bSJonas Devlieghere                         "    'use-external-name': true,\n"
1559fc51490bSJonas Devlieghere                         "    'external-contents': '//root/external/file'\n"
1560fc51490bSJonas Devlieghere                         "  },\n"
1561fc51490bSJonas Devlieghere                         "  { 'type': 'file', 'name': '//root/C',\n"
1562fc51490bSJonas Devlieghere                         "    'use-external-name': false,\n"
1563fc51490bSJonas Devlieghere                         "    'external-contents': '//root/external/file'\n"
1564fc51490bSJonas Devlieghere                         "  }\n"
1565fc51490bSJonas Devlieghere                         "] }",
1566fc51490bSJonas Devlieghere                         Lower);
1567fc51490bSJonas Devlieghere   ASSERT_TRUE(nullptr != FS.get());
1568fc51490bSJonas Devlieghere 
1569fc51490bSJonas Devlieghere   // default true
1570fc51490bSJonas Devlieghere   EXPECT_EQ("//root/external/file", FS->status("//root/A")->getName());
1571fc51490bSJonas Devlieghere   // explicit
1572fc51490bSJonas Devlieghere   EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1573fc51490bSJonas Devlieghere   EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
1574fc51490bSJonas Devlieghere 
1575fc51490bSJonas Devlieghere   // global configuration
1576fc51490bSJonas Devlieghere   FS = getFromYAMLString("{ 'use-external-names': false,\n"
1577fc51490bSJonas Devlieghere                          "  'roots': [\n"
1578fc51490bSJonas Devlieghere                          "  { 'type': 'file', 'name': '//root/A',\n"
1579fc51490bSJonas Devlieghere                          "    'external-contents': '//root/external/file'\n"
1580fc51490bSJonas Devlieghere                          "  },\n"
1581fc51490bSJonas Devlieghere                          "  { 'type': 'file', 'name': '//root/B',\n"
1582fc51490bSJonas Devlieghere                          "    'use-external-name': true,\n"
1583fc51490bSJonas Devlieghere                          "    'external-contents': '//root/external/file'\n"
1584fc51490bSJonas Devlieghere                          "  },\n"
1585fc51490bSJonas Devlieghere                          "  { 'type': 'file', 'name': '//root/C',\n"
1586fc51490bSJonas Devlieghere                          "    'use-external-name': false,\n"
1587fc51490bSJonas Devlieghere                          "    'external-contents': '//root/external/file'\n"
1588fc51490bSJonas Devlieghere                          "  }\n"
1589fc51490bSJonas Devlieghere                          "] }",
1590fc51490bSJonas Devlieghere                          Lower);
1591fc51490bSJonas Devlieghere   ASSERT_TRUE(nullptr != FS.get());
1592fc51490bSJonas Devlieghere 
1593fc51490bSJonas Devlieghere   // default
1594fc51490bSJonas Devlieghere   EXPECT_EQ("//root/A", FS->status("//root/A")->getName());
1595fc51490bSJonas Devlieghere   // explicit
1596fc51490bSJonas Devlieghere   EXPECT_EQ("//root/external/file", FS->status("//root/B")->getName());
1597fc51490bSJonas Devlieghere   EXPECT_EQ("//root/C", FS->status("//root/C")->getName());
1598fc51490bSJonas Devlieghere }
1599fc51490bSJonas Devlieghere 
1600fc51490bSJonas Devlieghere TEST_F(VFSFromYAMLTest, MultiComponentPath) {
1601fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1602fc51490bSJonas Devlieghere   Lower->addRegularFile("//root/other");
1603fc51490bSJonas Devlieghere 
1604fc51490bSJonas Devlieghere   // file in roots
1605fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS =
1606fc51490bSJonas Devlieghere       getFromYAMLString("{ 'roots': [\n"
1607fc51490bSJonas Devlieghere                         "  { 'type': 'file', 'name': '//root/path/to/file',\n"
1608fc51490bSJonas Devlieghere                         "    'external-contents': '//root/other' }]\n"
1609fc51490bSJonas Devlieghere                         "}",
1610fc51490bSJonas Devlieghere                         Lower);
1611fc51490bSJonas Devlieghere   ASSERT_TRUE(nullptr != FS.get());
1612fc51490bSJonas Devlieghere   EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1613fc51490bSJonas Devlieghere   EXPECT_FALSE(FS->status("//root/path/to").getError());
1614fc51490bSJonas Devlieghere   EXPECT_FALSE(FS->status("//root/path").getError());
1615fc51490bSJonas Devlieghere   EXPECT_FALSE(FS->status("//root/").getError());
1616fc51490bSJonas Devlieghere 
1617fc51490bSJonas Devlieghere   // at the start
1618fc51490bSJonas Devlieghere   FS = getFromYAMLString(
1619fc51490bSJonas Devlieghere       "{ 'roots': [\n"
1620fc51490bSJonas Devlieghere       "  { 'type': 'directory', 'name': '//root/path/to',\n"
1621fc51490bSJonas Devlieghere       "    'contents': [ { 'type': 'file', 'name': 'file',\n"
1622fc51490bSJonas Devlieghere       "                    'external-contents': '//root/other' }]}]\n"
1623fc51490bSJonas Devlieghere       "}",
1624fc51490bSJonas Devlieghere       Lower);
1625fc51490bSJonas Devlieghere   ASSERT_TRUE(nullptr != FS.get());
1626fc51490bSJonas Devlieghere   EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1627fc51490bSJonas Devlieghere   EXPECT_FALSE(FS->status("//root/path/to").getError());
1628fc51490bSJonas Devlieghere   EXPECT_FALSE(FS->status("//root/path").getError());
1629fc51490bSJonas Devlieghere   EXPECT_FALSE(FS->status("//root/").getError());
1630fc51490bSJonas Devlieghere 
1631fc51490bSJonas Devlieghere   // at the end
1632fc51490bSJonas Devlieghere   FS = getFromYAMLString(
1633fc51490bSJonas Devlieghere       "{ 'roots': [\n"
1634fc51490bSJonas Devlieghere       "  { 'type': 'directory', 'name': '//root/',\n"
1635fc51490bSJonas Devlieghere       "    'contents': [ { 'type': 'file', 'name': 'path/to/file',\n"
1636fc51490bSJonas Devlieghere       "                    'external-contents': '//root/other' }]}]\n"
1637fc51490bSJonas Devlieghere       "}",
1638fc51490bSJonas Devlieghere       Lower);
1639fc51490bSJonas Devlieghere   ASSERT_TRUE(nullptr != FS.get());
1640fc51490bSJonas Devlieghere   EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1641fc51490bSJonas Devlieghere   EXPECT_FALSE(FS->status("//root/path/to").getError());
1642fc51490bSJonas Devlieghere   EXPECT_FALSE(FS->status("//root/path").getError());
1643fc51490bSJonas Devlieghere   EXPECT_FALSE(FS->status("//root/").getError());
1644fc51490bSJonas Devlieghere }
1645fc51490bSJonas Devlieghere 
1646fc51490bSJonas Devlieghere TEST_F(VFSFromYAMLTest, TrailingSlashes) {
1647fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1648fc51490bSJonas Devlieghere   Lower->addRegularFile("//root/other");
1649fc51490bSJonas Devlieghere 
1650fc51490bSJonas Devlieghere   // file in roots
1651fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1652fc51490bSJonas Devlieghere       "{ 'roots': [\n"
1653fc51490bSJonas Devlieghere       "  { 'type': 'directory', 'name': '//root/path/to////',\n"
1654fc51490bSJonas Devlieghere       "    'contents': [ { 'type': 'file', 'name': 'file',\n"
1655fc51490bSJonas Devlieghere       "                    'external-contents': '//root/other' }]}]\n"
1656fc51490bSJonas Devlieghere       "}",
1657fc51490bSJonas Devlieghere       Lower);
1658fc51490bSJonas Devlieghere   ASSERT_TRUE(nullptr != FS.get());
1659fc51490bSJonas Devlieghere   EXPECT_FALSE(FS->status("//root/path/to/file").getError());
1660fc51490bSJonas Devlieghere   EXPECT_FALSE(FS->status("//root/path/to").getError());
1661fc51490bSJonas Devlieghere   EXPECT_FALSE(FS->status("//root/path").getError());
1662fc51490bSJonas Devlieghere   EXPECT_FALSE(FS->status("//root/").getError());
1663fc51490bSJonas Devlieghere }
1664fc51490bSJonas Devlieghere 
1665fc51490bSJonas Devlieghere TEST_F(VFSFromYAMLTest, DirectoryIteration) {
1666fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1667fc51490bSJonas Devlieghere   Lower->addDirectory("//root/");
1668fc51490bSJonas Devlieghere   Lower->addDirectory("//root/foo");
1669fc51490bSJonas Devlieghere   Lower->addDirectory("//root/foo/bar");
1670fc51490bSJonas Devlieghere   Lower->addRegularFile("//root/foo/bar/a");
1671fc51490bSJonas Devlieghere   Lower->addRegularFile("//root/foo/bar/b");
1672fc51490bSJonas Devlieghere   Lower->addRegularFile("//root/file3");
1673fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1674fc51490bSJonas Devlieghere       "{ 'use-external-names': false,\n"
1675fc51490bSJonas Devlieghere       "  'roots': [\n"
1676fc51490bSJonas Devlieghere       "{\n"
1677fc51490bSJonas Devlieghere       "  'type': 'directory',\n"
1678fc51490bSJonas Devlieghere       "  'name': '//root/',\n"
1679fc51490bSJonas Devlieghere       "  'contents': [ {\n"
1680fc51490bSJonas Devlieghere       "                  'type': 'file',\n"
1681fc51490bSJonas Devlieghere       "                  'name': 'file1',\n"
1682fc51490bSJonas Devlieghere       "                  'external-contents': '//root/foo/bar/a'\n"
1683fc51490bSJonas Devlieghere       "                },\n"
1684fc51490bSJonas Devlieghere       "                {\n"
1685fc51490bSJonas Devlieghere       "                  'type': 'file',\n"
1686fc51490bSJonas Devlieghere       "                  'name': 'file2',\n"
1687fc51490bSJonas Devlieghere       "                  'external-contents': '//root/foo/bar/b'\n"
1688fc51490bSJonas Devlieghere       "                }\n"
1689fc51490bSJonas Devlieghere       "              ]\n"
1690fc51490bSJonas Devlieghere       "}\n"
1691fc51490bSJonas Devlieghere       "]\n"
1692fc51490bSJonas Devlieghere       "}",
1693fc51490bSJonas Devlieghere       Lower);
1694fc51490bSJonas Devlieghere   ASSERT_TRUE(FS.get() != nullptr);
1695fc51490bSJonas Devlieghere 
1696fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1697fc51490bSJonas Devlieghere       new vfs::OverlayFileSystem(Lower));
1698fc51490bSJonas Devlieghere   O->pushOverlay(FS);
1699fc51490bSJonas Devlieghere 
1700fc51490bSJonas Devlieghere   std::error_code EC;
1701fc51490bSJonas Devlieghere   checkContents(O->dir_begin("//root/", EC),
1702fc51490bSJonas Devlieghere                 {"//root/file1", "//root/file2", "//root/file3", "//root/foo"});
1703fc51490bSJonas Devlieghere 
1704fc51490bSJonas Devlieghere   checkContents(O->dir_begin("//root/foo/bar", EC),
1705fc51490bSJonas Devlieghere                 {"//root/foo/bar/a", "//root/foo/bar/b"});
1706fc51490bSJonas Devlieghere }
1707fc51490bSJonas Devlieghere 
1708fc51490bSJonas Devlieghere TEST_F(VFSFromYAMLTest, DirectoryIterationSameDirMultipleEntries) {
1709fc51490bSJonas Devlieghere   // https://llvm.org/bugs/show_bug.cgi?id=27725
1710fc51490bSJonas Devlieghere   if (!supportsSameDirMultipleYAMLEntries())
1711fc51490bSJonas Devlieghere     return;
1712fc51490bSJonas Devlieghere 
1713fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1714fc51490bSJonas Devlieghere   Lower->addDirectory("//root/zab");
1715fc51490bSJonas Devlieghere   Lower->addDirectory("//root/baz");
1716fc51490bSJonas Devlieghere   Lower->addRegularFile("//root/zab/a");
1717fc51490bSJonas Devlieghere   Lower->addRegularFile("//root/zab/b");
1718fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1719fc51490bSJonas Devlieghere       "{ 'use-external-names': false,\n"
1720fc51490bSJonas Devlieghere       "  'roots': [\n"
1721fc51490bSJonas Devlieghere       "{\n"
1722fc51490bSJonas Devlieghere       "  'type': 'directory',\n"
1723fc51490bSJonas Devlieghere       "  'name': '//root/baz/',\n"
1724fc51490bSJonas Devlieghere       "  'contents': [ {\n"
1725fc51490bSJonas Devlieghere       "                  'type': 'file',\n"
1726fc51490bSJonas Devlieghere       "                  'name': 'x',\n"
1727fc51490bSJonas Devlieghere       "                  'external-contents': '//root/zab/a'\n"
1728fc51490bSJonas Devlieghere       "                }\n"
1729fc51490bSJonas Devlieghere       "              ]\n"
1730fc51490bSJonas Devlieghere       "},\n"
1731fc51490bSJonas Devlieghere       "{\n"
1732fc51490bSJonas Devlieghere       "  'type': 'directory',\n"
1733fc51490bSJonas Devlieghere       "  'name': '//root/baz/',\n"
1734fc51490bSJonas Devlieghere       "  'contents': [ {\n"
1735fc51490bSJonas Devlieghere       "                  'type': 'file',\n"
1736fc51490bSJonas Devlieghere       "                  'name': 'y',\n"
1737fc51490bSJonas Devlieghere       "                  'external-contents': '//root/zab/b'\n"
1738fc51490bSJonas Devlieghere       "                }\n"
1739fc51490bSJonas Devlieghere       "              ]\n"
1740fc51490bSJonas Devlieghere       "}\n"
1741fc51490bSJonas Devlieghere       "]\n"
1742fc51490bSJonas Devlieghere       "}",
1743fc51490bSJonas Devlieghere       Lower);
1744fc51490bSJonas Devlieghere   ASSERT_TRUE(FS.get() != nullptr);
1745fc51490bSJonas Devlieghere 
1746fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1747fc51490bSJonas Devlieghere       new vfs::OverlayFileSystem(Lower));
1748fc51490bSJonas Devlieghere   O->pushOverlay(FS);
1749fc51490bSJonas Devlieghere 
1750fc51490bSJonas Devlieghere   std::error_code EC;
1751fc51490bSJonas Devlieghere 
1752fc51490bSJonas Devlieghere   checkContents(O->dir_begin("//root/baz/", EC),
1753fc51490bSJonas Devlieghere                 {"//root/baz/x", "//root/baz/y"});
1754fc51490bSJonas Devlieghere }
1755fc51490bSJonas Devlieghere 
1756fc51490bSJonas Devlieghere TEST_F(VFSFromYAMLTest, RecursiveDirectoryIterationLevel) {
1757fc51490bSJonas Devlieghere 
1758fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1759fc51490bSJonas Devlieghere   Lower->addDirectory("//root/a");
1760fc51490bSJonas Devlieghere   Lower->addDirectory("//root/a/b");
1761fc51490bSJonas Devlieghere   Lower->addDirectory("//root/a/b/c");
1762fc51490bSJonas Devlieghere   Lower->addRegularFile("//root/a/b/c/file");
1763fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1764fc51490bSJonas Devlieghere       "{ 'use-external-names': false,\n"
1765fc51490bSJonas Devlieghere       "  'roots': [\n"
1766fc51490bSJonas Devlieghere       "{\n"
1767fc51490bSJonas Devlieghere       "  'type': 'directory',\n"
1768fc51490bSJonas Devlieghere       "  'name': '//root/a/b/c/',\n"
1769fc51490bSJonas Devlieghere       "  'contents': [ {\n"
1770fc51490bSJonas Devlieghere       "                  'type': 'file',\n"
1771fc51490bSJonas Devlieghere       "                  'name': 'file',\n"
1772fc51490bSJonas Devlieghere       "                  'external-contents': '//root/a/b/c/file'\n"
1773fc51490bSJonas Devlieghere       "                }\n"
1774fc51490bSJonas Devlieghere       "              ]\n"
1775fc51490bSJonas Devlieghere       "},\n"
1776fc51490bSJonas Devlieghere       "]\n"
1777fc51490bSJonas Devlieghere       "}",
1778fc51490bSJonas Devlieghere       Lower);
1779fc51490bSJonas Devlieghere   ASSERT_TRUE(FS.get() != nullptr);
1780fc51490bSJonas Devlieghere 
1781fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::OverlayFileSystem> O(
1782fc51490bSJonas Devlieghere       new vfs::OverlayFileSystem(Lower));
1783fc51490bSJonas Devlieghere   O->pushOverlay(FS);
1784fc51490bSJonas Devlieghere 
1785fc51490bSJonas Devlieghere   std::error_code EC;
1786fc51490bSJonas Devlieghere 
1787fc51490bSJonas Devlieghere   // Test recursive_directory_iterator level()
1788fc51490bSJonas Devlieghere   vfs::recursive_directory_iterator I = vfs::recursive_directory_iterator(
1789fc51490bSJonas Devlieghere                                         *O, "//root", EC),
1790fc51490bSJonas Devlieghere                                     E;
1791fc51490bSJonas Devlieghere   ASSERT_FALSE(EC);
1792fc51490bSJonas Devlieghere   for (int l = 0; I != E; I.increment(EC), ++l) {
1793fc51490bSJonas Devlieghere     ASSERT_FALSE(EC);
1794fc51490bSJonas Devlieghere     EXPECT_EQ(I.level(), l);
1795fc51490bSJonas Devlieghere   }
1796fc51490bSJonas Devlieghere   EXPECT_EQ(I, E);
1797fc51490bSJonas Devlieghere }
1798fc51490bSJonas Devlieghere 
1799fc51490bSJonas Devlieghere TEST_F(VFSFromYAMLTest, RelativePaths) {
1800fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1801fc51490bSJonas Devlieghere   // Filename at root level without a parent directory.
1802fc51490bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
1803fc51490bSJonas Devlieghere       "{ 'roots': [\n"
1804fc51490bSJonas Devlieghere       "  { 'type': 'file', 'name': 'file-not-in-directory.h',\n"
1805fc51490bSJonas Devlieghere       "    'external-contents': '//root/external/file'\n"
1806fc51490bSJonas Devlieghere       "  }\n"
1807fc51490bSJonas Devlieghere       "] }",
1808fc51490bSJonas Devlieghere       Lower);
1809fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1810fc51490bSJonas Devlieghere 
1811fc51490bSJonas Devlieghere   // Relative file path.
1812fc51490bSJonas Devlieghere   FS = getFromYAMLString("{ 'roots': [\n"
1813fc51490bSJonas Devlieghere                          "  { 'type': 'file', 'name': 'relative/file/path.h',\n"
1814fc51490bSJonas Devlieghere                          "    'external-contents': '//root/external/file'\n"
1815fc51490bSJonas Devlieghere                          "  }\n"
1816fc51490bSJonas Devlieghere                          "] }",
1817fc51490bSJonas Devlieghere                          Lower);
1818fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1819fc51490bSJonas Devlieghere 
1820fc51490bSJonas Devlieghere   // Relative directory path.
1821fc51490bSJonas Devlieghere   FS = getFromYAMLString(
1822fc51490bSJonas Devlieghere       "{ 'roots': [\n"
1823fc51490bSJonas Devlieghere       "  { 'type': 'directory', 'name': 'relative/directory/path.h',\n"
1824fc51490bSJonas Devlieghere       "    'contents': []\n"
1825fc51490bSJonas Devlieghere       "  }\n"
1826fc51490bSJonas Devlieghere       "] }",
1827fc51490bSJonas Devlieghere       Lower);
1828fc51490bSJonas Devlieghere   EXPECT_EQ(nullptr, FS.get());
1829fc51490bSJonas Devlieghere 
1830fc51490bSJonas Devlieghere   EXPECT_EQ(3, NumDiagnostics);
1831fc51490bSJonas Devlieghere }
183291e13164SVolodymyr Sapsai 
183391e13164SVolodymyr Sapsai TEST_F(VFSFromYAMLTest, NonFallthroughDirectoryIteration) {
183491e13164SVolodymyr Sapsai   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
183591e13164SVolodymyr Sapsai   Lower->addDirectory("//root/");
183691e13164SVolodymyr Sapsai   Lower->addRegularFile("//root/a");
183791e13164SVolodymyr Sapsai   Lower->addRegularFile("//root/b");
183891e13164SVolodymyr Sapsai   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
183991e13164SVolodymyr Sapsai       "{ 'use-external-names': false,\n"
184091e13164SVolodymyr Sapsai       "  'fallthrough': false,\n"
184191e13164SVolodymyr Sapsai       "  'roots': [\n"
184291e13164SVolodymyr Sapsai       "{\n"
184391e13164SVolodymyr Sapsai       "  'type': 'directory',\n"
184491e13164SVolodymyr Sapsai       "  'name': '//root/',\n"
184591e13164SVolodymyr Sapsai       "  'contents': [ {\n"
184691e13164SVolodymyr Sapsai       "                  'type': 'file',\n"
184791e13164SVolodymyr Sapsai       "                  'name': 'c',\n"
184891e13164SVolodymyr Sapsai       "                  'external-contents': '//root/a'\n"
184991e13164SVolodymyr Sapsai       "                }\n"
185091e13164SVolodymyr Sapsai       "              ]\n"
185191e13164SVolodymyr Sapsai       "}\n"
185291e13164SVolodymyr Sapsai       "]\n"
185391e13164SVolodymyr Sapsai       "}",
185491e13164SVolodymyr Sapsai       Lower);
185591e13164SVolodymyr Sapsai   ASSERT_TRUE(FS.get() != nullptr);
185691e13164SVolodymyr Sapsai 
185791e13164SVolodymyr Sapsai   std::error_code EC;
185891e13164SVolodymyr Sapsai   checkContents(FS->dir_begin("//root/", EC),
185991e13164SVolodymyr Sapsai                 {"//root/c"});
186091e13164SVolodymyr Sapsai }
186191e13164SVolodymyr Sapsai 
186291e13164SVolodymyr Sapsai TEST_F(VFSFromYAMLTest, DirectoryIterationWithDuplicates) {
186391e13164SVolodymyr Sapsai   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
186491e13164SVolodymyr Sapsai   Lower->addDirectory("//root/");
186591e13164SVolodymyr Sapsai   Lower->addRegularFile("//root/a");
186691e13164SVolodymyr Sapsai   Lower->addRegularFile("//root/b");
186791e13164SVolodymyr Sapsai   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
186891e13164SVolodymyr Sapsai       "{ 'use-external-names': false,\n"
186991e13164SVolodymyr Sapsai       "  'roots': [\n"
187091e13164SVolodymyr Sapsai       "{\n"
187191e13164SVolodymyr Sapsai       "  'type': 'directory',\n"
187291e13164SVolodymyr Sapsai       "  'name': '//root/',\n"
187391e13164SVolodymyr Sapsai       "  'contents': [ {\n"
187491e13164SVolodymyr Sapsai       "                  'type': 'file',\n"
187591e13164SVolodymyr Sapsai       "                  'name': 'a',\n"
187691e13164SVolodymyr Sapsai       "                  'external-contents': '//root/a'\n"
187791e13164SVolodymyr Sapsai       "                }\n"
187891e13164SVolodymyr Sapsai       "              ]\n"
187991e13164SVolodymyr Sapsai       "}\n"
188091e13164SVolodymyr Sapsai       "]\n"
188191e13164SVolodymyr Sapsai       "}",
188291e13164SVolodymyr Sapsai 	  Lower);
188391e13164SVolodymyr Sapsai   ASSERT_TRUE(FS.get() != nullptr);
188491e13164SVolodymyr Sapsai 
188591e13164SVolodymyr Sapsai   std::error_code EC;
188691e13164SVolodymyr Sapsai   checkContents(FS->dir_begin("//root/", EC),
188791e13164SVolodymyr Sapsai                 {"//root/a", "//root/b"});
188891e13164SVolodymyr Sapsai }
188991e13164SVolodymyr Sapsai 
189091e13164SVolodymyr Sapsai TEST_F(VFSFromYAMLTest, DirectoryIterationErrorInVFSLayer) {
189191e13164SVolodymyr Sapsai   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
189291e13164SVolodymyr Sapsai   Lower->addDirectory("//root/");
189391e13164SVolodymyr Sapsai   Lower->addDirectory("//root/foo");
189491e13164SVolodymyr Sapsai   Lower->addRegularFile("//root/foo/a");
189591e13164SVolodymyr Sapsai   Lower->addRegularFile("//root/foo/b");
189691e13164SVolodymyr Sapsai   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
189791e13164SVolodymyr Sapsai       "{ 'use-external-names': false,\n"
189891e13164SVolodymyr Sapsai       "  'roots': [\n"
189991e13164SVolodymyr Sapsai       "{\n"
190091e13164SVolodymyr Sapsai       "  'type': 'directory',\n"
190191e13164SVolodymyr Sapsai       "  'name': '//root/',\n"
190291e13164SVolodymyr Sapsai       "  'contents': [ {\n"
190391e13164SVolodymyr Sapsai       "                  'type': 'file',\n"
190491e13164SVolodymyr Sapsai       "                  'name': 'bar/a',\n"
190591e13164SVolodymyr Sapsai       "                  'external-contents': '//root/foo/a'\n"
190691e13164SVolodymyr Sapsai       "                }\n"
190791e13164SVolodymyr Sapsai       "              ]\n"
190891e13164SVolodymyr Sapsai       "}\n"
190991e13164SVolodymyr Sapsai       "]\n"
191091e13164SVolodymyr Sapsai       "}",
191191e13164SVolodymyr Sapsai       Lower);
191291e13164SVolodymyr Sapsai   ASSERT_TRUE(FS.get() != nullptr);
191391e13164SVolodymyr Sapsai 
191491e13164SVolodymyr Sapsai   std::error_code EC;
191591e13164SVolodymyr Sapsai   checkContents(FS->dir_begin("//root/foo", EC),
191691e13164SVolodymyr Sapsai                 {"//root/foo/a", "//root/foo/b"});
191791e13164SVolodymyr Sapsai }
19187610033fSVolodymyr Sapsai 
19197610033fSVolodymyr Sapsai TEST_F(VFSFromYAMLTest, GetRealPath) {
19207610033fSVolodymyr Sapsai   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
1921ab73426cSVolodymyr Sapsai   Lower->addDirectory("//dir/");
19227610033fSVolodymyr Sapsai   Lower->addRegularFile("/foo");
19237610033fSVolodymyr Sapsai   Lower->addSymlink("/link");
19247610033fSVolodymyr Sapsai   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
19257610033fSVolodymyr Sapsai       "{ 'use-external-names': false,\n"
19267610033fSVolodymyr Sapsai       "  'roots': [\n"
19277610033fSVolodymyr Sapsai       "{\n"
19287610033fSVolodymyr Sapsai       "  'type': 'directory',\n"
1929ab73426cSVolodymyr Sapsai       "  'name': '//root/',\n"
19307610033fSVolodymyr Sapsai       "  'contents': [ {\n"
19317610033fSVolodymyr Sapsai       "                  'type': 'file',\n"
19327610033fSVolodymyr Sapsai       "                  'name': 'bar',\n"
19337610033fSVolodymyr Sapsai       "                  'external-contents': '/link'\n"
19347610033fSVolodymyr Sapsai       "                }\n"
19357610033fSVolodymyr Sapsai       "              ]\n"
19367610033fSVolodymyr Sapsai       "},\n"
19377610033fSVolodymyr Sapsai       "{\n"
19387610033fSVolodymyr Sapsai       "  'type': 'directory',\n"
1939ab73426cSVolodymyr Sapsai       "  'name': '//dir/',\n"
19407610033fSVolodymyr Sapsai       "  'contents': []\n"
19417610033fSVolodymyr Sapsai       "}\n"
19427610033fSVolodymyr Sapsai       "]\n"
19437610033fSVolodymyr Sapsai       "}",
19447610033fSVolodymyr Sapsai       Lower);
19457610033fSVolodymyr Sapsai   ASSERT_TRUE(FS.get() != nullptr);
19467610033fSVolodymyr Sapsai 
19477610033fSVolodymyr Sapsai   // Regular file present in underlying file system.
19487610033fSVolodymyr Sapsai   SmallString<16> RealPath;
19497610033fSVolodymyr Sapsai   EXPECT_FALSE(FS->getRealPath("/foo", RealPath));
19507610033fSVolodymyr Sapsai   EXPECT_EQ(RealPath.str(), "/foo");
19517610033fSVolodymyr Sapsai 
19527610033fSVolodymyr Sapsai   // File present in YAML pointing to symlink in underlying file system.
1953ab73426cSVolodymyr Sapsai   EXPECT_FALSE(FS->getRealPath("//root/bar", RealPath));
19547610033fSVolodymyr Sapsai   EXPECT_EQ(RealPath.str(), "/symlink");
19557610033fSVolodymyr Sapsai 
19567610033fSVolodymyr Sapsai   // Directories should fall back to the underlying file system is possible.
1957ab73426cSVolodymyr Sapsai   EXPECT_FALSE(FS->getRealPath("//dir/", RealPath));
1958ab73426cSVolodymyr Sapsai   EXPECT_EQ(RealPath.str(), "//dir/");
19597610033fSVolodymyr Sapsai 
19607610033fSVolodymyr Sapsai   // Try a non-existing file.
19617610033fSVolodymyr Sapsai   EXPECT_EQ(FS->getRealPath("/non_existing", RealPath),
19627610033fSVolodymyr Sapsai             errc::no_such_file_or_directory);
19637610033fSVolodymyr Sapsai }
196421703543SJonas Devlieghere 
196521703543SJonas Devlieghere TEST_F(VFSFromYAMLTest, WorkingDirectory) {
196621703543SJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
196721703543SJonas Devlieghere   Lower->addDirectory("//root/");
196821703543SJonas Devlieghere   Lower->addDirectory("//root/foo");
196921703543SJonas Devlieghere   Lower->addRegularFile("//root/foo/a");
197021703543SJonas Devlieghere   Lower->addRegularFile("//root/foo/b");
197121703543SJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
197221703543SJonas Devlieghere       "{ 'use-external-names': false,\n"
197321703543SJonas Devlieghere       "  'roots': [\n"
197421703543SJonas Devlieghere       "{\n"
197521703543SJonas Devlieghere       "  'type': 'directory',\n"
197621703543SJonas Devlieghere       "  'name': '//root/bar',\n"
197721703543SJonas Devlieghere       "  'contents': [ {\n"
197821703543SJonas Devlieghere       "                  'type': 'file',\n"
197921703543SJonas Devlieghere       "                  'name': 'a',\n"
198021703543SJonas Devlieghere       "                  'external-contents': '//root/foo/a'\n"
198121703543SJonas Devlieghere       "                }\n"
198221703543SJonas Devlieghere       "              ]\n"
198321703543SJonas Devlieghere       "}\n"
198421703543SJonas Devlieghere       "]\n"
198521703543SJonas Devlieghere       "}",
198621703543SJonas Devlieghere       Lower);
198721703543SJonas Devlieghere   ASSERT_TRUE(FS.get() != nullptr);
198821703543SJonas Devlieghere   std::error_code EC = FS->setCurrentWorkingDirectory("//root/bar");
198921703543SJonas Devlieghere   ASSERT_FALSE(EC);
199021703543SJonas Devlieghere 
199121703543SJonas Devlieghere   llvm::ErrorOr<std::string> WorkingDir = FS->getCurrentWorkingDirectory();
199221703543SJonas Devlieghere   ASSERT_TRUE(WorkingDir);
199321703543SJonas Devlieghere   EXPECT_EQ(*WorkingDir, "//root/bar");
199421703543SJonas Devlieghere 
199521703543SJonas Devlieghere   llvm::ErrorOr<vfs::Status> Status = FS->status("./a");
199621703543SJonas Devlieghere   ASSERT_FALSE(Status.getError());
199721703543SJonas Devlieghere   EXPECT_TRUE(Status->isStatusKnown());
199821703543SJonas Devlieghere   EXPECT_FALSE(Status->isDirectory());
199921703543SJonas Devlieghere   EXPECT_TRUE(Status->isRegularFile());
200021703543SJonas Devlieghere   EXPECT_FALSE(Status->isSymlink());
200121703543SJonas Devlieghere   EXPECT_FALSE(Status->isOther());
200221703543SJonas Devlieghere   EXPECT_TRUE(Status->exists());
200321703543SJonas Devlieghere 
200421703543SJonas Devlieghere   EC = FS->setCurrentWorkingDirectory("bogus");
200521703543SJonas Devlieghere   ASSERT_TRUE(EC);
200621703543SJonas Devlieghere   WorkingDir = FS->getCurrentWorkingDirectory();
200721703543SJonas Devlieghere   ASSERT_TRUE(WorkingDir);
200821703543SJonas Devlieghere   EXPECT_EQ(*WorkingDir, "//root/bar");
200921703543SJonas Devlieghere 
201021703543SJonas Devlieghere   EC = FS->setCurrentWorkingDirectory("//root/");
201121703543SJonas Devlieghere   ASSERT_FALSE(EC);
201221703543SJonas Devlieghere   WorkingDir = FS->getCurrentWorkingDirectory();
201321703543SJonas Devlieghere   ASSERT_TRUE(WorkingDir);
201421703543SJonas Devlieghere   EXPECT_EQ(*WorkingDir, "//root/");
201521703543SJonas Devlieghere 
201621703543SJonas Devlieghere   EC = FS->setCurrentWorkingDirectory("bar");
201721703543SJonas Devlieghere   ASSERT_FALSE(EC);
201821703543SJonas Devlieghere   WorkingDir = FS->getCurrentWorkingDirectory();
201921703543SJonas Devlieghere   ASSERT_TRUE(WorkingDir);
202021703543SJonas Devlieghere   EXPECT_EQ(*WorkingDir, "//root/bar");
202121703543SJonas Devlieghere }
202221703543SJonas Devlieghere 
202321703543SJonas Devlieghere TEST_F(VFSFromYAMLTest, WorkingDirectoryFallthrough) {
202421703543SJonas Devlieghere   IntrusiveRefCntPtr<DummyFileSystem> Lower(new DummyFileSystem());
202521703543SJonas Devlieghere   Lower->addDirectory("//root/");
202621703543SJonas Devlieghere   Lower->addDirectory("//root/foo");
202721703543SJonas Devlieghere   Lower->addRegularFile("//root/foo/a");
202821703543SJonas Devlieghere   Lower->addRegularFile("//root/foo/b");
202921703543SJonas Devlieghere   Lower->addRegularFile("//root/c");
203021703543SJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
203121703543SJonas Devlieghere       "{ 'use-external-names': false,\n"
203221703543SJonas Devlieghere       "  'roots': [\n"
203321703543SJonas Devlieghere       "{\n"
203421703543SJonas Devlieghere       "  'type': 'directory',\n"
203521703543SJonas Devlieghere       "  'name': '//root/bar',\n"
203621703543SJonas Devlieghere       "  'contents': [ {\n"
203721703543SJonas Devlieghere       "                  'type': 'file',\n"
203821703543SJonas Devlieghere       "                  'name': 'a',\n"
203921703543SJonas Devlieghere       "                  'external-contents': '//root/foo/a'\n"
204021703543SJonas Devlieghere       "                }\n"
204121703543SJonas Devlieghere       "              ]\n"
2042f2f77499SJonas Devlieghere       "},\n"
2043f2f77499SJonas Devlieghere       "{\n"
2044f2f77499SJonas Devlieghere       "  'type': 'directory',\n"
2045f2f77499SJonas Devlieghere       "  'name': '//root/bar/baz',\n"
2046f2f77499SJonas Devlieghere       "  'contents': [ {\n"
2047f2f77499SJonas Devlieghere       "                  'type': 'file',\n"
2048f2f77499SJonas Devlieghere       "                  'name': 'a',\n"
2049f2f77499SJonas Devlieghere       "                  'external-contents': '//root/foo/a'\n"
2050f2f77499SJonas Devlieghere       "                }\n"
2051f2f77499SJonas Devlieghere       "              ]\n"
205221703543SJonas Devlieghere       "}\n"
205321703543SJonas Devlieghere       "]\n"
205421703543SJonas Devlieghere       "}",
205521703543SJonas Devlieghere       Lower);
205621703543SJonas Devlieghere   ASSERT_TRUE(FS.get() != nullptr);
205721703543SJonas Devlieghere   std::error_code EC = FS->setCurrentWorkingDirectory("//root/");
205821703543SJonas Devlieghere   ASSERT_FALSE(EC);
205921703543SJonas Devlieghere   ASSERT_TRUE(FS.get() != nullptr);
206021703543SJonas Devlieghere 
206121703543SJonas Devlieghere   llvm::ErrorOr<vfs::Status> Status = FS->status("bar/a");
206221703543SJonas Devlieghere   ASSERT_FALSE(Status.getError());
206321703543SJonas Devlieghere   EXPECT_TRUE(Status->exists());
206421703543SJonas Devlieghere 
206521703543SJonas Devlieghere   Status = FS->status("foo/a");
206621703543SJonas Devlieghere   ASSERT_FALSE(Status.getError());
206721703543SJonas Devlieghere   EXPECT_TRUE(Status->exists());
206821703543SJonas Devlieghere 
206921703543SJonas Devlieghere   EC = FS->setCurrentWorkingDirectory("//root/bar");
207021703543SJonas Devlieghere   ASSERT_FALSE(EC);
207121703543SJonas Devlieghere 
207221703543SJonas Devlieghere   Status = FS->status("./a");
207321703543SJonas Devlieghere   ASSERT_FALSE(Status.getError());
207421703543SJonas Devlieghere   EXPECT_TRUE(Status->exists());
207521703543SJonas Devlieghere 
207621703543SJonas Devlieghere   Status = FS->status("./b");
207721703543SJonas Devlieghere   ASSERT_TRUE(Status.getError());
207821703543SJonas Devlieghere 
207921703543SJonas Devlieghere   Status = FS->status("./c");
208021703543SJonas Devlieghere   ASSERT_TRUE(Status.getError());
208121703543SJonas Devlieghere 
208221703543SJonas Devlieghere   EC = FS->setCurrentWorkingDirectory("//root/");
208321703543SJonas Devlieghere   ASSERT_FALSE(EC);
208421703543SJonas Devlieghere 
208521703543SJonas Devlieghere   Status = FS->status("c");
208621703543SJonas Devlieghere   ASSERT_FALSE(Status.getError());
208721703543SJonas Devlieghere   EXPECT_TRUE(Status->exists());
2088f2f77499SJonas Devlieghere 
2089f2f77499SJonas Devlieghere   Status = FS->status("./bar/baz/a");
2090f2f77499SJonas Devlieghere   ASSERT_FALSE(Status.getError());
2091f2f77499SJonas Devlieghere   EXPECT_TRUE(Status->exists());
2092f2f77499SJonas Devlieghere 
2093f2f77499SJonas Devlieghere   EC = FS->setCurrentWorkingDirectory("//root/bar");
2094f2f77499SJonas Devlieghere   ASSERT_FALSE(EC);
2095f2f77499SJonas Devlieghere 
2096f2f77499SJonas Devlieghere   Status = FS->status("./baz/a");
2097f2f77499SJonas Devlieghere   ASSERT_FALSE(Status.getError());
2098f2f77499SJonas Devlieghere   EXPECT_TRUE(Status->exists());
2099f2f77499SJonas Devlieghere 
2100f2f77499SJonas Devlieghere   Status = FS->status("../bar/baz/a");
2101f2f77499SJonas Devlieghere   ASSERT_FALSE(Status.getError());
2102f2f77499SJonas Devlieghere   EXPECT_TRUE(Status->exists());
210321703543SJonas Devlieghere }
210421703543SJonas Devlieghere 
210521703543SJonas Devlieghere TEST_F(VFSFromYAMLTest, WorkingDirectoryFallthroughInvalid) {
210621703543SJonas Devlieghere   IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem());
210721703543SJonas Devlieghere   Lower->addDirectory("//root/");
210821703543SJonas Devlieghere   Lower->addDirectory("//root/foo");
210921703543SJonas Devlieghere   Lower->addRegularFile("//root/foo/a");
211021703543SJonas Devlieghere   Lower->addRegularFile("//root/foo/b");
211121703543SJonas Devlieghere   Lower->addRegularFile("//root/c");
211221703543SJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString(
211321703543SJonas Devlieghere       "{ 'use-external-names': false,\n"
211421703543SJonas Devlieghere       "  'roots': [\n"
211521703543SJonas Devlieghere       "{\n"
211621703543SJonas Devlieghere       "  'type': 'directory',\n"
211721703543SJonas Devlieghere       "  'name': '//root/bar',\n"
211821703543SJonas Devlieghere       "  'contents': [ {\n"
211921703543SJonas Devlieghere       "                  'type': 'file',\n"
212021703543SJonas Devlieghere       "                  'name': 'a',\n"
212121703543SJonas Devlieghere       "                  'external-contents': '//root/foo/a'\n"
212221703543SJonas Devlieghere       "                }\n"
212321703543SJonas Devlieghere       "              ]\n"
212421703543SJonas Devlieghere       "}\n"
212521703543SJonas Devlieghere       "]\n"
212621703543SJonas Devlieghere       "}",
212721703543SJonas Devlieghere       Lower);
212821703543SJonas Devlieghere   ASSERT_TRUE(FS.get() != nullptr);
212921703543SJonas Devlieghere   std::error_code EC = FS->setCurrentWorkingDirectory("//root/");
213021703543SJonas Devlieghere   ASSERT_FALSE(EC);
213121703543SJonas Devlieghere   ASSERT_TRUE(FS.get() != nullptr);
213221703543SJonas Devlieghere 
213321703543SJonas Devlieghere   llvm::ErrorOr<vfs::Status> Status = FS->status("bar/a");
213421703543SJonas Devlieghere   ASSERT_FALSE(Status.getError());
213521703543SJonas Devlieghere   EXPECT_TRUE(Status->exists());
213621703543SJonas Devlieghere 
213721703543SJonas Devlieghere   Status = FS->status("foo/a");
213821703543SJonas Devlieghere   ASSERT_TRUE(Status.getError());
213921703543SJonas Devlieghere }
214042df3e29SJonas Devlieghere 
214142df3e29SJonas Devlieghere TEST_F(VFSFromYAMLTest, YAMLVFSWriterTest) {
2142fad75598SSergej Jaskiewicz   TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
2143fad75598SSergej Jaskiewicz   TempDir _a(TestDirectory.path("a"));
2144fad75598SSergej Jaskiewicz   TempFile _ab(TestDirectory.path("a, b"));
2145fad75598SSergej Jaskiewicz   TempDir _c(TestDirectory.path("c"));
2146fad75598SSergej Jaskiewicz   TempFile _cd(TestDirectory.path("c/d"));
2147fad75598SSergej Jaskiewicz   TempDir _e(TestDirectory.path("e"));
2148fad75598SSergej Jaskiewicz   TempDir _ef(TestDirectory.path("e/f"));
2149fad75598SSergej Jaskiewicz   TempFile _g(TestDirectory.path("g"));
2150fad75598SSergej Jaskiewicz   TempDir _h(TestDirectory.path("h"));
215142df3e29SJonas Devlieghere 
215242df3e29SJonas Devlieghere   vfs::YAMLVFSWriter VFSWriter;
2153fad75598SSergej Jaskiewicz   VFSWriter.addDirectoryMapping(_a.path(), "//root/a");
2154fad75598SSergej Jaskiewicz   VFSWriter.addFileMapping(_ab.path(), "//root/a/b");
2155fad75598SSergej Jaskiewicz   VFSWriter.addFileMapping(_cd.path(), "//root/c/d");
2156fad75598SSergej Jaskiewicz   VFSWriter.addDirectoryMapping(_e.path(), "//root/e");
2157fad75598SSergej Jaskiewicz   VFSWriter.addDirectoryMapping(_ef.path(), "//root/e/f");
2158fad75598SSergej Jaskiewicz   VFSWriter.addFileMapping(_g.path(), "//root/g");
2159fad75598SSergej Jaskiewicz   VFSWriter.addDirectoryMapping(_h.path(), "//root/h");
216042df3e29SJonas Devlieghere 
216142df3e29SJonas Devlieghere   std::string Buffer;
216242df3e29SJonas Devlieghere   raw_string_ostream OS(Buffer);
216342df3e29SJonas Devlieghere   VFSWriter.write(OS);
216442df3e29SJonas Devlieghere   OS.flush();
216542df3e29SJonas Devlieghere 
216642df3e29SJonas Devlieghere   IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem());
216742df3e29SJonas Devlieghere   Lower->addDirectory("//root/");
216842df3e29SJonas Devlieghere   Lower->addDirectory("//root/a");
216942df3e29SJonas Devlieghere   Lower->addRegularFile("//root/a/b");
217042df3e29SJonas Devlieghere   Lower->addDirectory("//root/b");
217142df3e29SJonas Devlieghere   Lower->addDirectory("//root/c");
217242df3e29SJonas Devlieghere   Lower->addRegularFile("//root/c/d");
217342df3e29SJonas Devlieghere   Lower->addDirectory("//root/e");
217442df3e29SJonas Devlieghere   Lower->addDirectory("//root/e/f");
21755c145034SJan Korous   Lower->addRegularFile("//root/g");
21765c145034SJan Korous   Lower->addDirectory("//root/h");
217742df3e29SJonas Devlieghere 
217842df3e29SJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLRawString(Buffer, Lower);
217942df3e29SJonas Devlieghere   ASSERT_TRUE(FS.get() != nullptr);
218042df3e29SJonas Devlieghere 
2181fad75598SSergej Jaskiewicz   EXPECT_TRUE(FS->exists(_a.path()));
2182fad75598SSergej Jaskiewicz   EXPECT_TRUE(FS->exists(_ab.path()));
2183fad75598SSergej Jaskiewicz   EXPECT_TRUE(FS->exists(_c.path()));
2184fad75598SSergej Jaskiewicz   EXPECT_TRUE(FS->exists(_cd.path()));
2185fad75598SSergej Jaskiewicz   EXPECT_TRUE(FS->exists(_e.path()));
2186fad75598SSergej Jaskiewicz   EXPECT_TRUE(FS->exists(_ef.path()));
2187fad75598SSergej Jaskiewicz   EXPECT_TRUE(FS->exists(_g.path()));
2188fad75598SSergej Jaskiewicz   EXPECT_TRUE(FS->exists(_h.path()));
218942df3e29SJonas Devlieghere }
2190c0330bc0SJan Korous 
219159ba19c5SJonas Devlieghere TEST_F(VFSFromYAMLTest, YAMLVFSWriterTest2) {
2192fad75598SSergej Jaskiewicz   TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
2193fad75598SSergej Jaskiewicz   TempDir _a(TestDirectory.path("a"));
2194fad75598SSergej Jaskiewicz   TempFile _ab(TestDirectory.path("a/b"));
2195fad75598SSergej Jaskiewicz   TempDir _ac(TestDirectory.path("a/c"));
2196fad75598SSergej Jaskiewicz   TempFile _acd(TestDirectory.path("a/c/d"));
2197fad75598SSergej Jaskiewicz   TempFile _ace(TestDirectory.path("a/c/e"));
2198fad75598SSergej Jaskiewicz   TempFile _acf(TestDirectory.path("a/c/f"));
2199fad75598SSergej Jaskiewicz   TempDir _ag(TestDirectory.path("a/g"));
2200fad75598SSergej Jaskiewicz   TempFile _agh(TestDirectory.path("a/g/h"));
220159ba19c5SJonas Devlieghere 
220259ba19c5SJonas Devlieghere   vfs::YAMLVFSWriter VFSWriter;
2203fad75598SSergej Jaskiewicz   VFSWriter.addDirectoryMapping(_a.path(), "//root/a");
2204fad75598SSergej Jaskiewicz   VFSWriter.addFileMapping(_ab.path(), "//root/a/b");
2205fad75598SSergej Jaskiewicz   VFSWriter.addDirectoryMapping(_ac.path(), "//root/a/c");
2206fad75598SSergej Jaskiewicz   VFSWriter.addFileMapping(_acd.path(), "//root/a/c/d");
2207fad75598SSergej Jaskiewicz   VFSWriter.addFileMapping(_ace.path(), "//root/a/c/e");
2208fad75598SSergej Jaskiewicz   VFSWriter.addFileMapping(_acf.path(), "//root/a/c/f");
2209fad75598SSergej Jaskiewicz   VFSWriter.addDirectoryMapping(_ag.path(), "//root/a/g");
2210fad75598SSergej Jaskiewicz   VFSWriter.addFileMapping(_agh.path(), "//root/a/g/h");
221159ba19c5SJonas Devlieghere 
221259ba19c5SJonas Devlieghere   std::string Buffer;
221359ba19c5SJonas Devlieghere   raw_string_ostream OS(Buffer);
221459ba19c5SJonas Devlieghere   VFSWriter.write(OS);
221559ba19c5SJonas Devlieghere   OS.flush();
221659ba19c5SJonas Devlieghere 
221759ba19c5SJonas Devlieghere   IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem());
221859ba19c5SJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLRawString(Buffer, Lower);
2219759465eeSJan Korous   EXPECT_TRUE(FS.get() != nullptr);
222059ba19c5SJonas Devlieghere }
222159ba19c5SJonas Devlieghere 
222258bc507bSJonas Devlieghere TEST_F(VFSFromYAMLTest, YAMLVFSWriterTest3) {
2223fad75598SSergej Jaskiewicz   TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
2224fad75598SSergej Jaskiewicz   TempDir _a(TestDirectory.path("a"));
2225fad75598SSergej Jaskiewicz   TempFile _ab(TestDirectory.path("a/b"));
2226fad75598SSergej Jaskiewicz   TempDir _ac(TestDirectory.path("a/c"));
2227fad75598SSergej Jaskiewicz   TempDir _acd(TestDirectory.path("a/c/d"));
2228fad75598SSergej Jaskiewicz   TempDir _acde(TestDirectory.path("a/c/d/e"));
2229fad75598SSergej Jaskiewicz   TempFile _acdef(TestDirectory.path("a/c/d/e/f"));
2230fad75598SSergej Jaskiewicz   TempFile _acdeg(TestDirectory.path("a/c/d/e/g"));
2231fad75598SSergej Jaskiewicz   TempDir _ah(TestDirectory.path("a/h"));
2232fad75598SSergej Jaskiewicz   TempFile _ahi(TestDirectory.path("a/h/i"));
223358bc507bSJonas Devlieghere 
223458bc507bSJonas Devlieghere   vfs::YAMLVFSWriter VFSWriter;
2235fad75598SSergej Jaskiewicz   VFSWriter.addDirectoryMapping(_a.path(), "//root/a");
2236fad75598SSergej Jaskiewicz   VFSWriter.addFileMapping(_ab.path(), "//root/a/b");
2237fad75598SSergej Jaskiewicz   VFSWriter.addDirectoryMapping(_ac.path(), "//root/a/c");
2238fad75598SSergej Jaskiewicz   VFSWriter.addDirectoryMapping(_acd.path(), "//root/a/c/d");
2239fad75598SSergej Jaskiewicz   VFSWriter.addDirectoryMapping(_acde.path(), "//root/a/c/d/e");
2240fad75598SSergej Jaskiewicz   VFSWriter.addFileMapping(_acdef.path(), "//root/a/c/d/e/f");
2241fad75598SSergej Jaskiewicz   VFSWriter.addFileMapping(_acdeg.path(), "//root/a/c/d/e/g");
2242fad75598SSergej Jaskiewicz   VFSWriter.addDirectoryMapping(_ahi.path(), "//root/a/h");
2243fad75598SSergej Jaskiewicz   VFSWriter.addFileMapping(_ahi.path(), "//root/a/h/i");
224458bc507bSJonas Devlieghere 
224558bc507bSJonas Devlieghere   std::string Buffer;
224658bc507bSJonas Devlieghere   raw_string_ostream OS(Buffer);
224758bc507bSJonas Devlieghere   VFSWriter.write(OS);
224858bc507bSJonas Devlieghere   OS.flush();
224958bc507bSJonas Devlieghere 
225058bc507bSJonas Devlieghere   IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem());
225158bc507bSJonas Devlieghere   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLRawString(Buffer, Lower);
2252759465eeSJan Korous   EXPECT_TRUE(FS.get() != nullptr);
225358bc507bSJonas Devlieghere }
225458bc507bSJonas Devlieghere 
2255c0330bc0SJan Korous TEST_F(VFSFromYAMLTest, YAMLVFSWriterTestHandleDirs) {
2256fad75598SSergej Jaskiewicz   TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
2257fad75598SSergej Jaskiewicz   TempDir _a(TestDirectory.path("a"));
2258fad75598SSergej Jaskiewicz   TempDir _b(TestDirectory.path("b"));
2259fad75598SSergej Jaskiewicz   TempDir _c(TestDirectory.path("c"));
2260c0330bc0SJan Korous 
2261c0330bc0SJan Korous   vfs::YAMLVFSWriter VFSWriter;
2262fad75598SSergej Jaskiewicz   VFSWriter.addDirectoryMapping(_a.path(), "//root/a");
2263fad75598SSergej Jaskiewicz   VFSWriter.addDirectoryMapping(_b.path(), "//root/b");
2264fad75598SSergej Jaskiewicz   VFSWriter.addDirectoryMapping(_c.path(), "//root/c");
2265c0330bc0SJan Korous 
2266c0330bc0SJan Korous   std::string Buffer;
2267c0330bc0SJan Korous   raw_string_ostream OS(Buffer);
2268c0330bc0SJan Korous   VFSWriter.write(OS);
2269c0330bc0SJan Korous   OS.flush();
2270c0330bc0SJan Korous 
2271c0330bc0SJan Korous   // We didn't add a single file - only directories.
2272c0330bc0SJan Korous   EXPECT_TRUE(Buffer.find("'type': 'file'") == std::string::npos);
2273c0330bc0SJan Korous 
2274c0330bc0SJan Korous   IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower(new ErrorDummyFileSystem());
2275c0330bc0SJan Korous   Lower->addDirectory("//root/a");
2276c0330bc0SJan Korous   Lower->addDirectory("//root/b");
2277c0330bc0SJan Korous   Lower->addDirectory("//root/c");
2278c0330bc0SJan Korous   // canaries
2279c0330bc0SJan Korous   Lower->addRegularFile("//root/a/a");
2280c0330bc0SJan Korous   Lower->addRegularFile("//root/b/b");
2281c0330bc0SJan Korous   Lower->addRegularFile("//root/c/c");
2282c0330bc0SJan Korous 
2283c0330bc0SJan Korous   IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLRawString(Buffer, Lower);
2284c0330bc0SJan Korous   ASSERT_TRUE(FS.get() != nullptr);
2285c0330bc0SJan Korous 
2286fad75598SSergej Jaskiewicz   EXPECT_FALSE(FS->exists(_a.path("a")));
2287fad75598SSergej Jaskiewicz   EXPECT_FALSE(FS->exists(_b.path("b")));
2288fad75598SSergej Jaskiewicz   EXPECT_FALSE(FS->exists(_c.path("c")));
2289c0330bc0SJan Korous }
2290