brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.2 KiB · e3c2b5a Raw
345 lines · cpp
1//===-- FileSystemTest.cpp ------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "gmock/gmock.h"10#include "gtest/gtest.h"11 12#include "lldb/Host/FileSystem.h"13#include "llvm/Support/Errc.h"14 15extern const char *TestMainArgv0;16 17using namespace lldb_private;18using namespace llvm;19using llvm::sys::fs::UniqueID;20 21// Modified from llvm/unittests/Support/VirtualFileSystemTest.cpp22namespace {23struct DummyFile : public vfs::File {24  vfs::Status S;25  explicit DummyFile(vfs::Status S) : S(S) {}26  llvm::ErrorOr<vfs::Status> status() override { return S; }27  llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>28  getBuffer(const Twine &Name, int64_t FileSize, bool RequiresNullTerminator,29            bool IsVolatile) override {30    llvm_unreachable("unimplemented");31  }32  std::error_code close() override { return std::error_code(); }33};34 35class DummyFileSystem : public vfs::FileSystem {36  int FSID;   // used to produce UniqueIDs37  int FileID = 0; // used to produce UniqueIDs38  std::string cwd;39  std::map<std::string, vfs::Status> FilesAndDirs;40 41  static int getNextFSID() {42    static int Count = 0;43    return Count++;44  }45 46public:47  DummyFileSystem() : FSID(getNextFSID()) {}48 49  ErrorOr<vfs::Status> status(const Twine &Path) override {50    std::map<std::string, vfs::Status>::iterator I =51        FilesAndDirs.find(Path.str());52    if (I == FilesAndDirs.end())53      return make_error_code(llvm::errc::no_such_file_or_directory);54    // Simulate a broken symlink, where it points to a file/dir that55    // does not exist.56    if (I->second.isSymlink() &&57        I->second.getPermissions() == sys::fs::perms::no_perms)58      return std::error_code(ENOENT, std::generic_category());59    return I->second;60  }61  ErrorOr<std::unique_ptr<vfs::File>>62  openFileForRead(const Twine &Path) override {63    auto S = status(Path);64    if (S)65      return std::unique_ptr<vfs::File>(new DummyFile{*S});66    return S.getError();67  }68  llvm::ErrorOr<std::string> getCurrentWorkingDirectory() const override {69    return cwd;70  }71  std::error_code setCurrentWorkingDirectory(const Twine &Path) override {72    cwd = Path.str();73    return std::error_code();74  }75  // Map any symlink to "/symlink".76  std::error_code getRealPath(const Twine &Path,77                              SmallVectorImpl<char> &Output) override {78    auto I = FilesAndDirs.find(Path.str());79    if (I == FilesAndDirs.end())80      return make_error_code(llvm::errc::no_such_file_or_directory);81    if (I->second.isSymlink()) {82      Output.clear();83      Twine("/symlink").toVector(Output);84      return std::error_code();85    }86    Output.clear();87    Path.toVector(Output);88    return std::error_code();89  }90 91  struct DirIterImpl : public llvm::vfs::detail::DirIterImpl {92    std::map<std::string, vfs::Status> &FilesAndDirs;93    std::map<std::string, vfs::Status>::iterator I;94    std::string Path;95    bool isInPath(StringRef S) {96      if (Path.size() < S.size() && S.starts_with(Path)) {97        auto LastSep = S.find_last_of('/');98        if (LastSep == Path.size() || LastSep == Path.size() - 1)99          return true;100      }101      return false;102    }103    DirIterImpl(std::map<std::string, vfs::Status> &FilesAndDirs,104                const Twine &_Path)105        : FilesAndDirs(FilesAndDirs), I(FilesAndDirs.begin()),106          Path(_Path.str()) {107      for (; I != FilesAndDirs.end(); ++I) {108        if (isInPath(I->first)) {109          CurrentEntry = vfs::directory_entry(std::string(I->second.getName()),110                                              I->second.getType());111          break;112        }113      }114    }115    std::error_code increment() override {116      ++I;117      for (; I != FilesAndDirs.end(); ++I) {118        if (isInPath(I->first)) {119          CurrentEntry = vfs::directory_entry(std::string(I->second.getName()),120                                              I->second.getType());121          break;122        }123      }124      if (I == FilesAndDirs.end())125        CurrentEntry = vfs::directory_entry();126      return std::error_code();127    }128  };129 130  vfs::directory_iterator dir_begin(const Twine &Dir,131                                    std::error_code &EC) override {132    return vfs::directory_iterator(133        std::make_shared<DirIterImpl>(FilesAndDirs, Dir));134  }135 136  void addEntry(StringRef Path, const vfs::Status &Status) {137    FilesAndDirs[std::string(Path)] = Status;138  }139 140  void addRegularFile(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {141    vfs::Status S(Path, UniqueID(FSID, FileID++),142                  std::chrono::system_clock::now(), 0, 0, 1024,143                  sys::fs::file_type::regular_file, Perms);144    addEntry(Path, S);145  }146 147  void addDirectory(StringRef Path, sys::fs::perms Perms = sys::fs::all_all) {148    vfs::Status S(Path, UniqueID(FSID, FileID++),149                  std::chrono::system_clock::now(), 0, 0, 0,150                  sys::fs::file_type::directory_file, Perms);151    addEntry(Path, S);152  }153 154  void addSymlink(StringRef Path) {155    vfs::Status S(Path, UniqueID(FSID, FileID++),156                  std::chrono::system_clock::now(), 0, 0, 0,157                  sys::fs::file_type::symlink_file, sys::fs::all_all);158    addEntry(Path, S);159  }160 161  void addBrokenSymlink(StringRef Path) {162    vfs::Status S(Path, UniqueID(FSID, FileID++),163                  std::chrono::system_clock::now(), 0, 0, 0,164                  sys::fs::file_type::symlink_file, sys::fs::no_perms);165    addEntry(Path, S);166  }167};168} // namespace169 170TEST(FileSystemTest, FileAndDirectoryComponents) {171  using namespace std::chrono;172  FileSystem fs;173 174#ifdef _WIN32175  FileSpec fs1("C:\\FILE\\THAT\\DOES\\NOT\\EXIST.TXT");176#else177  FileSpec fs1("/file/that/does/not/exist.txt");178#endif179  FileSpec fs2(TestMainArgv0);180 181  fs.Resolve(fs2);182 183  EXPECT_EQ(system_clock::time_point(), fs.GetModificationTime(fs1));184  EXPECT_LT(system_clock::time_point() + hours(24 * 365 * 20),185            fs.GetModificationTime(fs2));186}187 188static IntrusiveRefCntPtr<DummyFileSystem> GetSimpleDummyFS() {189  auto D = makeIntrusiveRefCnt<DummyFileSystem>();190  D->addRegularFile("/foo");191  D->addDirectory("/bar");192  D->addSymlink("/baz");193  D->addBrokenSymlink("/lux");194  D->addRegularFile("/qux", ~sys::fs::perms::all_read);195  D->setCurrentWorkingDirectory("/");196  return D;197}198 199TEST(FileSystemTest, Exists) {200  FileSystem fs(GetSimpleDummyFS());201 202  EXPECT_TRUE(fs.Exists("/foo"));203  EXPECT_TRUE(fs.Exists(FileSpec("/foo", FileSpec::Style::posix)));204}205 206TEST(FileSystemTest, Readable) {207  FileSystem fs(GetSimpleDummyFS());208 209  EXPECT_TRUE(fs.Readable("/foo"));210  EXPECT_TRUE(fs.Readable(FileSpec("/foo", FileSpec::Style::posix)));211 212  EXPECT_FALSE(fs.Readable("/qux"));213  EXPECT_FALSE(fs.Readable(FileSpec("/qux", FileSpec::Style::posix)));214}215 216TEST(FileSystemTest, GetByteSize) {217  FileSystem fs(GetSimpleDummyFS());218 219  EXPECT_EQ((uint64_t)1024, fs.GetByteSize("/foo"));220  EXPECT_EQ((uint64_t)1024,221            fs.GetByteSize(FileSpec("/foo", FileSpec::Style::posix)));222}223 224TEST(FileSystemTest, GetPermissions) {225  FileSystem fs(GetSimpleDummyFS());226 227  EXPECT_EQ(sys::fs::all_all, fs.GetPermissions("/foo"));228  EXPECT_EQ(sys::fs::all_all,229            fs.GetPermissions(FileSpec("/foo", FileSpec::Style::posix)));230}231 232TEST(FileSystemTest, MakeAbsolute) {233  FileSystem fs(GetSimpleDummyFS());234 235  {236    StringRef foo_relative = "foo";237    SmallString<16> foo(foo_relative);238    auto EC = fs.MakeAbsolute(foo);239    EXPECT_FALSE(EC);240    EXPECT_TRUE(foo.equals("/foo"));241  }242 243  {244    FileSpec file_spec("foo");245    auto EC = fs.MakeAbsolute(file_spec);246    EXPECT_FALSE(EC);247    EXPECT_EQ(FileSpec("/foo"), file_spec);248  }249}250 251TEST(FileSystemTest, Resolve) {252  FileSystem fs(GetSimpleDummyFS());253 254  {255    StringRef foo_relative = "foo";256    SmallString<16> foo(foo_relative);257    fs.Resolve(foo);258    EXPECT_TRUE(foo.equals("/foo"));259  }260 261  {262    FileSpec file_spec("foo");263    fs.Resolve(file_spec);264    EXPECT_EQ(FileSpec("/foo"), file_spec);265  }266 267  {268    StringRef foo_relative = "bogus";269    SmallString<16> foo(foo_relative);270    fs.Resolve(foo);271    EXPECT_TRUE(foo.equals("bogus"));272  }273 274  {275    FileSpec file_spec("bogus");276    fs.Resolve(file_spec);277    EXPECT_EQ(FileSpec("bogus"), file_spec);278  }279}280 281FileSystem::EnumerateDirectoryResult282VFSCallback(void *baton, llvm::sys::fs::file_type file_type,283            llvm::StringRef path) {284  auto visited = static_cast<std::vector<std::string> *>(baton);285  visited->push_back(path.str());286  return FileSystem::eEnumerateDirectoryResultNext;287}288 289TEST(FileSystemTest, EnumerateDirectory) {290  FileSystem fs(GetSimpleDummyFS());291 292  std::vector<std::string> visited;293 294  constexpr bool find_directories = true;295  constexpr bool find_files = true;296  constexpr bool find_other = true;297 298  fs.EnumerateDirectory("/", find_directories, find_files, find_other,299                        VFSCallback, &visited);300 301  EXPECT_THAT(visited,302              testing::UnorderedElementsAre("/foo", "/bar", "/baz", "/qux"));303}304 305TEST(FileSystemTest, OpenErrno) {306#ifdef _WIN32307  FileSpec spec("C:\\FILE\\THAT\\DOES\\NOT\\EXIST.TXT");308#else309  FileSpec spec("/file/that/does/not/exist.txt");310#endif311  FileSystem fs;312  auto file = fs.Open(spec, File::eOpenOptionReadOnly, 0, true);313  ASSERT_FALSE(file);314  std::error_code code = errorToErrorCode(file.takeError());315  EXPECT_EQ(code.category(), std::system_category());316  EXPECT_EQ(code.value(), ENOENT);317}318 319TEST(FileSystemTest, EmptyTest) {320  FileSpec spec;321  FileSystem fs;322 323  {324    std::error_code ec;325    fs.DirBegin(spec, ec);326    EXPECT_EQ(ec.category(), std::system_category());327    EXPECT_EQ(ec.value(), ENOENT);328  }329 330  {331    llvm::ErrorOr<vfs::Status> status = fs.GetStatus(spec);332    ASSERT_FALSE(status);333    EXPECT_EQ(status.getError().category(), std::system_category());334    EXPECT_EQ(status.getError().value(), ENOENT);335  }336 337  EXPECT_EQ(sys::TimePoint<>(), fs.GetModificationTime(spec));338  EXPECT_EQ(static_cast<uint64_t>(0), fs.GetByteSize(spec));339  EXPECT_EQ(llvm::sys::fs::perms::perms_not_known, fs.GetPermissions(spec));340  EXPECT_FALSE(fs.Exists(spec));341  EXPECT_FALSE(fs.Readable(spec));342  EXPECT_FALSE(fs.IsDirectory(spec));343  EXPECT_FALSE(fs.IsLocal(spec));344}345