@@ -41,7 +41,9 @@ struct DummyFile : public vfs::File {
4141class DummyFileSystem : public vfs ::FileSystem {
4242 int FSID; // used to produce UniqueIDs
4343 int FileID; // used to produce UniqueIDs
44+ std::string WorkingDirectory;
4445 std::map<std::string, vfs::Status> FilesAndDirs;
46+ typedef std::map<std::string, vfs::Status>::const_iterator const_iterator;
4547
4648 static int getNextFSID () {
4749 static int Count = 0 ;
@@ -52,8 +54,7 @@ class DummyFileSystem : public vfs::FileSystem {
5254 DummyFileSystem () : FSID(getNextFSID()), FileID(0 ) {}
5355
5456 ErrorOr<vfs::Status> status (const Twine &Path) override {
55- std::map<std::string, vfs::Status>::iterator I =
56- FilesAndDirs.find (Path.str ());
57+ auto I = findEntry (Path);
5758 if (I == FilesAndDirs.end ())
5859 return make_error_code (llvm::errc::no_such_file_or_directory);
5960 return I->second ;
@@ -66,15 +67,16 @@ class DummyFileSystem : public vfs::FileSystem {
6667 return S.getError ();
6768 }
6869 llvm::ErrorOr<std::string> getCurrentWorkingDirectory () const override {
69- return std::string () ;
70+ return WorkingDirectory ;
7071 }
7172 std::error_code setCurrentWorkingDirectory (const Twine &Path) override {
73+ WorkingDirectory = Path.str ();
7274 return std::error_code ();
7375 }
7476 // Map any symlink to "/symlink".
7577 std::error_code getRealPath (const Twine &Path,
7678 SmallVectorImpl<char > &Output) const override {
77- auto I = FilesAndDirs. find (Path. str () );
79+ auto I = findEntry (Path);
7880 if (I == FilesAndDirs.end ())
7981 return make_error_code (llvm::errc::no_such_file_or_directory);
8082 if (I->second .isSymlink ()) {
@@ -136,6 +138,14 @@ class DummyFileSystem : public vfs::FileSystem {
136138 FilesAndDirs[Path] = Status;
137139 }
138140
141+ const_iterator findEntry (const Twine &Path) const {
142+ SmallString<128 > P;
143+ Path.toVector (P);
144+ std::error_code EC = makeAbsolute (P);
145+ assert (!EC);
146+ return FilesAndDirs.find (P.str ());
147+ }
148+
139149 void addRegularFile (StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {
140150 vfs::Status S (Path, UniqueID (FSID, FileID++),
141151 std::chrono::system_clock::now (), 0 , 0 , 1024 ,
@@ -158,6 +168,12 @@ class DummyFileSystem : public vfs::FileSystem {
158168 }
159169};
160170
171+ class ErrorDummyFileSystem : public DummyFileSystem {
172+ std::error_code setCurrentWorkingDirectory (const Twine &Path) override {
173+ return llvm::errc::no_such_file_or_directory;
174+ }
175+ };
176+
161177// / Replace back-slashes by front-slashes.
162178std::string getPosixPath (std::string S) {
163179 SmallString<128 > Result;
@@ -1994,3 +2010,154 @@ TEST_F(VFSFromYAMLTest, GetRealPath) {
19942010 EXPECT_EQ (FS->getRealPath (" /non_existing" , RealPath),
19952011 errc::no_such_file_or_directory);
19962012}
2013+
2014+ TEST_F (VFSFromYAMLTest, WorkingDirectory) {
2015+ IntrusiveRefCntPtr<DummyFileSystem> Lower (new DummyFileSystem ());
2016+ Lower->addDirectory (" //root/" );
2017+ Lower->addDirectory (" //root/foo" );
2018+ Lower->addRegularFile (" //root/foo/a" );
2019+ Lower->addRegularFile (" //root/foo/b" );
2020+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString (
2021+ " { 'use-external-names': false,\n "
2022+ " 'roots': [\n "
2023+ " {\n "
2024+ " 'type': 'directory',\n "
2025+ " 'name': '//root/bar',\n "
2026+ " 'contents': [ {\n "
2027+ " 'type': 'file',\n "
2028+ " 'name': 'a',\n "
2029+ " 'external-contents': '//root/foo/a'\n "
2030+ " }\n "
2031+ " ]\n "
2032+ " }\n "
2033+ " ]\n "
2034+ " }" ,
2035+ Lower);
2036+ ASSERT_TRUE (FS.get () != nullptr );
2037+ std::error_code EC = FS->setCurrentWorkingDirectory (" //root/bar" );
2038+ ASSERT_FALSE (EC);
2039+
2040+ llvm::ErrorOr<std::string> WorkingDir = FS->getCurrentWorkingDirectory ();
2041+ ASSERT_TRUE (WorkingDir);
2042+ EXPECT_EQ (*WorkingDir, " //root/bar" );
2043+
2044+ llvm::ErrorOr<vfs::Status> Status = FS->status (" ./a" );
2045+ ASSERT_FALSE (Status.getError ());
2046+ EXPECT_TRUE (Status->isStatusKnown ());
2047+ EXPECT_FALSE (Status->isDirectory ());
2048+ EXPECT_TRUE (Status->isRegularFile ());
2049+ EXPECT_FALSE (Status->isSymlink ());
2050+ EXPECT_FALSE (Status->isOther ());
2051+ EXPECT_TRUE (Status->exists ());
2052+
2053+ EC = FS->setCurrentWorkingDirectory (" bogus" );
2054+ ASSERT_TRUE (EC);
2055+ WorkingDir = FS->getCurrentWorkingDirectory ();
2056+ ASSERT_TRUE (WorkingDir);
2057+ EXPECT_EQ (*WorkingDir, " //root/bar" );
2058+
2059+ EC = FS->setCurrentWorkingDirectory (" //root/" );
2060+ ASSERT_FALSE (EC);
2061+ WorkingDir = FS->getCurrentWorkingDirectory ();
2062+ ASSERT_TRUE (WorkingDir);
2063+ EXPECT_EQ (*WorkingDir, " //root/" );
2064+
2065+ EC = FS->setCurrentWorkingDirectory (" bar" );
2066+ ASSERT_FALSE (EC);
2067+ WorkingDir = FS->getCurrentWorkingDirectory ();
2068+ ASSERT_TRUE (WorkingDir);
2069+ EXPECT_EQ (*WorkingDir, " //root/bar" );
2070+ }
2071+
2072+ TEST_F (VFSFromYAMLTest, WorkingDirectoryFallthrough) {
2073+ IntrusiveRefCntPtr<DummyFileSystem> Lower (new DummyFileSystem ());
2074+ Lower->addDirectory (" //root/" );
2075+ Lower->addDirectory (" //root/foo" );
2076+ Lower->addRegularFile (" //root/foo/a" );
2077+ Lower->addRegularFile (" //root/foo/b" );
2078+ Lower->addRegularFile (" //root/c" );
2079+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString (
2080+ " { 'use-external-names': false,\n "
2081+ " 'roots': [\n "
2082+ " {\n "
2083+ " 'type': 'directory',\n "
2084+ " 'name': '//root/bar',\n "
2085+ " 'contents': [ {\n "
2086+ " 'type': 'file',\n "
2087+ " 'name': 'a',\n "
2088+ " 'external-contents': '//root/foo/a'\n "
2089+ " }\n "
2090+ " ]\n "
2091+ " }\n "
2092+ " ]\n "
2093+ " }" ,
2094+ Lower);
2095+ ASSERT_TRUE (FS.get () != nullptr );
2096+ std::error_code EC = FS->setCurrentWorkingDirectory (" //root/" );
2097+ ASSERT_FALSE (EC);
2098+ ASSERT_TRUE (FS.get () != nullptr );
2099+
2100+ llvm::ErrorOr<vfs::Status> Status = FS->status (" bar/a" );
2101+ ASSERT_FALSE (Status.getError ());
2102+ EXPECT_TRUE (Status->exists ());
2103+
2104+ Status = FS->status (" foo/a" );
2105+ ASSERT_FALSE (Status.getError ());
2106+ EXPECT_TRUE (Status->exists ());
2107+
2108+ EC = FS->setCurrentWorkingDirectory (" //root/bar" );
2109+ ASSERT_FALSE (EC);
2110+
2111+ Status = FS->status (" ./a" );
2112+ ASSERT_FALSE (Status.getError ());
2113+ EXPECT_TRUE (Status->exists ());
2114+
2115+ Status = FS->status (" ./b" );
2116+ ASSERT_TRUE (Status.getError ());
2117+
2118+ Status = FS->status (" ./c" );
2119+ ASSERT_TRUE (Status.getError ());
2120+
2121+ EC = FS->setCurrentWorkingDirectory (" //root/" );
2122+ ASSERT_FALSE (EC);
2123+
2124+ Status = FS->status (" c" );
2125+ ASSERT_FALSE (Status.getError ());
2126+ EXPECT_TRUE (Status->exists ());
2127+ }
2128+
2129+ TEST_F (VFSFromYAMLTest, WorkingDirectoryFallthroughInvalid) {
2130+ IntrusiveRefCntPtr<ErrorDummyFileSystem> Lower (new ErrorDummyFileSystem ());
2131+ Lower->addDirectory (" //root/" );
2132+ Lower->addDirectory (" //root/foo" );
2133+ Lower->addRegularFile (" //root/foo/a" );
2134+ Lower->addRegularFile (" //root/foo/b" );
2135+ Lower->addRegularFile (" //root/c" );
2136+ IntrusiveRefCntPtr<vfs::FileSystem> FS = getFromYAMLString (
2137+ " { 'use-external-names': false,\n "
2138+ " 'roots': [\n "
2139+ " {\n "
2140+ " 'type': 'directory',\n "
2141+ " 'name': '//root/bar',\n "
2142+ " 'contents': [ {\n "
2143+ " 'type': 'file',\n "
2144+ " 'name': 'a',\n "
2145+ " 'external-contents': '//root/foo/a'\n "
2146+ " }\n "
2147+ " ]\n "
2148+ " }\n "
2149+ " ]\n "
2150+ " }" ,
2151+ Lower);
2152+ ASSERT_TRUE (FS.get () != nullptr );
2153+ std::error_code EC = FS->setCurrentWorkingDirectory (" //root/" );
2154+ ASSERT_FALSE (EC);
2155+ ASSERT_TRUE (FS.get () != nullptr );
2156+
2157+ llvm::ErrorOr<vfs::Status> Status = FS->status (" bar/a" );
2158+ ASSERT_FALSE (Status.getError ());
2159+ EXPECT_TRUE (Status->exists ());
2160+
2161+ Status = FS->status (" foo/a" );
2162+ ASSERT_TRUE (Status.getError ());
2163+ }
0 commit comments