brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.8 KiB · 3d49427 Raw
273 lines · cpp
1//===-- TestCompletion.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 "lldb/Host/FileSystem.h"10#include "lldb/Interpreter/CommandCompletions.h"11#include "lldb/Utility/StringList.h"12#include "lldb/Utility/TildeExpressionResolver.h"13 14#include "gmock/gmock.h"15#include "gtest/gtest.h"16 17#include "TestingSupport/MockTildeExpressionResolver.h"18#include "TestingSupport/SubsystemRAII.h"19#include "TestingSupport/TestUtilities.h"20#include "llvm/ADT/SmallString.h"21#include "llvm/Support/FileSystem.h"22#include "llvm/Support/Path.h"23#include "llvm/Support/raw_ostream.h"24 25namespace fs = llvm::sys::fs;26namespace path = llvm::sys::path;27using namespace llvm;28using namespace lldb_private;29 30namespace {31 32class CompletionTest : public testing::Test {33  SubsystemRAII<FileSystem> subsystems;34 35protected:36  /// Unique temporary directory in which all created filesystem entities must37  /// be placed. It is removed at the end of the test suite.38  SmallString<128> BaseDir;39 40  /// The working directory that we got when starting the test. Every test41  /// should chdir into this directory first because some tests maybe chdir42  /// into another one during their run.43  static SmallString<128> OriginalWorkingDir;44 45  SmallString<128> DirFoo;46  SmallString<128> DirFooA;47  SmallString<128> DirFooB;48  SmallString<128> DirFooC;49  SmallString<128> DirBar;50  SmallString<128> DirBaz;51  SmallString<128> DirTestFolder;52  SmallString<128> DirNested;53 54  SmallString<128> FileAA;55  SmallString<128> FileAB;56  SmallString<128> FileAC;57  SmallString<128> FileFoo;58  SmallString<128> FileBar;59  SmallString<128> FileBaz;60 61  void SetUp() override {62    // chdir back into the original working dir this test binary started with.63    // A previous test may have changed the working dir.64    ASSERT_NO_ERROR(fs::set_current_path(OriginalWorkingDir));65 66    // Get the name of the current test. To prevent that by chance two tests67    // get the same temporary directory if createUniqueDirectory fails.68    auto test_info = ::testing::UnitTest::GetInstance()->current_test_info();69    ASSERT_TRUE(test_info != nullptr);70    std::string name = test_info->name();71    ASSERT_NO_ERROR(fs::createUniqueDirectory("FsCompletion-" + name, BaseDir));72 73    const char *DirNames[] = {"foo", "fooa", "foob",        "fooc",74                              "bar", "baz",  "test_folder", "foo/nested"};75    const char *FileNames[] = {"aa1234.tmp",  "ab1234.tmp",  "ac1234.tmp",76                               "foo1234.tmp", "bar1234.tmp", "baz1234.tmp"};77    SmallString<128> *Dirs[] = {&DirFoo, &DirFooA, &DirFooB,       &DirFooC,78                                &DirBar, &DirBaz,  &DirTestFolder, &DirNested};79    for (auto Dir : llvm::zip(DirNames, Dirs)) {80      auto &Path = *std::get<1>(Dir);81      Path = BaseDir;82      path::append(Path, std::get<0>(Dir));83      ASSERT_NO_ERROR(fs::create_directories(Path));84    }85 86    SmallString<128> *Files[] = {&FileAA,  &FileAB,  &FileAC,87                                 &FileFoo, &FileBar, &FileBaz};88    for (auto File : llvm::zip(FileNames, Files)) {89      auto &Path = *std::get<1>(File);90      Path = BaseDir;91      path::append(Path, std::get<0>(File));92      int FD;93      ASSERT_NO_ERROR(fs::createUniqueFile(Path, FD, Path));94      ::close(FD);95    }96  }97 98  static void SetUpTestCase() {99    ASSERT_NO_ERROR(fs::current_path(OriginalWorkingDir));100  }101 102  void TearDown() override {103    ASSERT_NO_ERROR(fs::remove_directories(BaseDir));104  }105 106  static bool HasEquivalentFile(const Twine &Path, const StringList &Paths) {107    for (size_t I = 0; I < Paths.GetSize(); ++I) {108      if (fs::equivalent(Path, Paths[I]))109        return true;110    }111    return false;112  }113 114  void DoDirCompletions(const Twine &Prefix,115                        StandardTildeExpressionResolver &Resolver,116                        StringList &Results) {117    // When a partial name matches, it returns all matches.  If it matches both118    // a full name AND some partial names, it returns all of them.119    CommandCompletions::DiskDirectories(Prefix + "foo", Results, Resolver);120    ASSERT_EQ(4u, Results.GetSize());121    EXPECT_TRUE(HasEquivalentFile(DirFoo, Results));122    EXPECT_TRUE(HasEquivalentFile(DirFooA, Results));123    EXPECT_TRUE(HasEquivalentFile(DirFooB, Results));124    EXPECT_TRUE(HasEquivalentFile(DirFooC, Results));125 126    // If it matches only partial names, it still works as expected.127    CommandCompletions::DiskDirectories(Twine(Prefix) + "b", Results, Resolver);128    ASSERT_EQ(2u, Results.GetSize());129    EXPECT_TRUE(HasEquivalentFile(DirBar, Results));130    EXPECT_TRUE(HasEquivalentFile(DirBaz, Results));131  }132};133 134SmallString<128> CompletionTest::OriginalWorkingDir;135} // namespace136 137static std::vector<std::string> toVector(const StringList &SL) {138  std::vector<std::string> Result;139  for (size_t Idx = 0; Idx < SL.GetSize(); ++Idx)140    Result.push_back(SL[Idx]);141  return Result;142}143using testing::UnorderedElementsAre;144 145TEST_F(CompletionTest, DirCompletionAbsolute) {146  // All calls to DiskDirectories() return only directories, even when147  // there are files which also match.  The tests below all check this148  // by asserting an exact result count, and verifying against known149  // folders.150 151  std::string Prefixes[] = {(Twine(BaseDir) + "/").str(), ""};152 153  StandardTildeExpressionResolver Resolver;154  StringList Results;155 156  // When a directory is specified that doesn't end in a slash, it searches157  // for that directory, not items under it.158  // Sanity check that the path we complete on exists and isn't too long.159  CommandCompletions::DiskDirectories(Twine(BaseDir) + "/fooa", Results,160                                      Resolver);161  ASSERT_EQ(1u, Results.GetSize());162  EXPECT_TRUE(HasEquivalentFile(DirFooA, Results));163 164  CommandCompletions::DiskDirectories(Twine(BaseDir) + "/.", Results, Resolver);165  ASSERT_EQ(0u, Results.GetSize());166 167  // When the same directory ends with a slash, it finds all children.168  CommandCompletions::DiskDirectories(Prefixes[0], Results, Resolver);169  ASSERT_EQ(7u, Results.GetSize());170  EXPECT_TRUE(HasEquivalentFile(DirFoo, Results));171  EXPECT_TRUE(HasEquivalentFile(DirFooA, Results));172  EXPECT_TRUE(HasEquivalentFile(DirFooB, Results));173  EXPECT_TRUE(HasEquivalentFile(DirFooC, Results));174  EXPECT_TRUE(HasEquivalentFile(DirBar, Results));175  EXPECT_TRUE(HasEquivalentFile(DirBaz, Results));176  EXPECT_TRUE(HasEquivalentFile(DirTestFolder, Results));177 178  DoDirCompletions(Twine(BaseDir) + "/", Resolver, Results);179  llvm::sys::fs::set_current_path(BaseDir);180  DoDirCompletions("", Resolver, Results);181}182 183TEST_F(CompletionTest, FileCompletionAbsolute) {184  // All calls to DiskFiles() return both files and directories  The tests below185  // all check this by asserting an exact result count, and verifying against186  // known folders.187 188  StandardTildeExpressionResolver Resolver;189  StringList Results;190  // When an item is specified that doesn't end in a slash but exactly matches191  // one item, it returns that item.192  CommandCompletions::DiskFiles(Twine(BaseDir) + "/fooa", Results, Resolver);193  ASSERT_EQ(1u, Results.GetSize());194  EXPECT_TRUE(HasEquivalentFile(DirFooA, Results));195 196  // The previous check verified a directory match.  But it should work for197  // files too.198  CommandCompletions::DiskFiles(Twine(BaseDir) + "/aa", Results, Resolver);199  ASSERT_EQ(1u, Results.GetSize());200  EXPECT_TRUE(HasEquivalentFile(FileAA, Results));201 202  // When it ends with a slash, it should find all files and directories.203  CommandCompletions::DiskFiles(Twine(BaseDir) + "/", Results, Resolver);204  ASSERT_EQ(13u, Results.GetSize());205  EXPECT_TRUE(HasEquivalentFile(DirFoo, Results));206  EXPECT_TRUE(HasEquivalentFile(DirFooA, Results));207  EXPECT_TRUE(HasEquivalentFile(DirFooB, Results));208  EXPECT_TRUE(HasEquivalentFile(DirFooC, Results));209  EXPECT_TRUE(HasEquivalentFile(DirBar, Results));210  EXPECT_TRUE(HasEquivalentFile(DirBaz, Results));211  EXPECT_TRUE(HasEquivalentFile(DirTestFolder, Results));212 213  EXPECT_TRUE(HasEquivalentFile(FileAA, Results));214  EXPECT_TRUE(HasEquivalentFile(FileAB, Results));215  EXPECT_TRUE(HasEquivalentFile(FileAC, Results));216  EXPECT_TRUE(HasEquivalentFile(FileFoo, Results));217  EXPECT_TRUE(HasEquivalentFile(FileBar, Results));218  EXPECT_TRUE(HasEquivalentFile(FileBaz, Results));219 220  // When a partial name matches, it returns all file & directory matches.221  CommandCompletions::DiskFiles(Twine(BaseDir) + "/foo", Results, Resolver);222  ASSERT_EQ(5u, Results.GetSize());223  EXPECT_TRUE(HasEquivalentFile(DirFoo, Results));224  EXPECT_TRUE(HasEquivalentFile(DirFooA, Results));225  EXPECT_TRUE(HasEquivalentFile(DirFooB, Results));226  EXPECT_TRUE(HasEquivalentFile(DirFooC, Results));227  EXPECT_TRUE(HasEquivalentFile(FileFoo, Results));228}229 230TEST_F(CompletionTest, DirCompletionUsername) {231  MockTildeExpressionResolver Resolver("James", BaseDir);232  Resolver.AddKnownUser("Kirk", DirFooB);233  Resolver.AddKnownUser("Lars", DirFooC);234  Resolver.AddKnownUser("Jason", DirFoo);235  Resolver.AddKnownUser("Larry", DirFooA);236  std::string sep = std::string(path::get_separator());237 238  // Just resolving current user's home directory by itself should return the239  // directory.240  StringList Results;241  CommandCompletions::DiskDirectories("~", Results, Resolver);242  EXPECT_THAT(toVector(Results), UnorderedElementsAre("~" + sep));243 244  // With a slash appended, it should return all items in the directory.245  CommandCompletions::DiskDirectories("~/", Results, Resolver);246  EXPECT_THAT(toVector(Results),247              UnorderedElementsAre(248                  "~/foo" + sep, "~/fooa" + sep, "~/foob" + sep, "~/fooc" + sep,249                  "~/bar" + sep, "~/baz" + sep, "~/test_folder" + sep));250 251  // Check that we can complete directories in nested paths252  CommandCompletions::DiskDirectories("~/foo/", Results, Resolver);253  EXPECT_THAT(toVector(Results), UnorderedElementsAre("~/foo/nested" + sep));254 255  CommandCompletions::DiskDirectories("~/foo/nes", Results, Resolver);256  EXPECT_THAT(toVector(Results), UnorderedElementsAre("~/foo/nested" + sep));257 258  // With ~username syntax it should return one match if there is an exact259  // match.  It shouldn't translate to the actual directory, it should keep the260  // form the user typed.261  CommandCompletions::DiskDirectories("~Lars", Results, Resolver);262  EXPECT_THAT(toVector(Results), UnorderedElementsAre("~Lars" + sep));263 264  // But with a username that is not found, no results are returned.265  CommandCompletions::DiskDirectories("~Dave", Results, Resolver);266  EXPECT_THAT(toVector(Results), UnorderedElementsAre());267 268  // And if there are multiple matches, it should return all of them.269  CommandCompletions::DiskDirectories("~La", Results, Resolver);270  EXPECT_THAT(toVector(Results),271              UnorderedElementsAre("~Lars" + sep, "~Larry" + sep));272}273