brintos

brintos / llvm-project-archived public Read only

0
0
Text · 6.8 KiB · 36a9c38 Raw
216 lines · cpp
1//===-- ConfigProviderTests.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 "Config.h"10#include "ConfigProvider.h"11#include "ConfigTesting.h"12#include "TestFS.h"13#include "llvm/Support/Path.h"14#include "llvm/Support/SourceMgr.h"15#include "gmock/gmock.h"16#include "gtest/gtest.h"17#include <atomic>18#include <chrono>19 20namespace clang {21namespace clangd {22namespace config {23namespace {24using ::testing::ElementsAre;25using ::testing::IsEmpty;26 27// Provider that appends an arg to compile flags.28// The arg is prefix<N>, where N is the times getFragments() was called.29// It also yields a diagnostic each time it's called.30class FakeProvider : public Provider {31  std::string Prefix;32  mutable std::atomic<unsigned> Index = {0};33 34  std::vector<CompiledFragment>35  getFragments(const Params &, DiagnosticCallback DC) const override {36    DC(llvm::SMDiagnostic("", llvm::SourceMgr::DK_Error, Prefix));37    CompiledFragment F =38        [Arg(Prefix + std::to_string(++Index))](const Params &P, Config &C) {39          C.CompileFlags.Edits.push_back(40              [Arg](std::vector<std::string> &Argv) { Argv.push_back(Arg); });41          return true;42        };43    return {F};44  }45 46public:47  FakeProvider(llvm::StringRef Prefix) : Prefix(Prefix) {}48};49 50std::vector<std::string> getAddedArgs(Config &C) {51  std::vector<std::string> Argv;52  for (auto &Edit : C.CompileFlags.Edits)53    Edit(Argv);54  return Argv;55}56 57// The provider from combine() should invoke its providers in order, and not58// cache their results.59TEST(ProviderTest, Combine) {60  CapturedDiags Diags;61  FakeProvider Foo("foo");62  FakeProvider Bar("bar");63  auto Combined = Provider::combine({&Foo, &Bar});64  Config Cfg = Combined->getConfig(Params(), Diags.callback());65  EXPECT_THAT(Diags.Diagnostics,66              ElementsAre(diagMessage("foo"), diagMessage("bar")));67  EXPECT_THAT(getAddedArgs(Cfg), ElementsAre("foo1", "bar1"));68  Diags.Diagnostics.clear();69 70  Cfg = Combined->getConfig(Params(), Diags.callback());71  EXPECT_THAT(Diags.Diagnostics,72              ElementsAre(diagMessage("foo"), diagMessage("bar")));73  EXPECT_THAT(getAddedArgs(Cfg), ElementsAre("foo2", "bar2"));74}75 76const char *AddFooWithErr = R"yaml(77CompileFlags:78  Add: foo79  Unknown: 4280)yaml";81 82const char *AddFooWithTypoErr = R"yaml(83CompileFlags:84  Add: foo85  Removr: 4286)yaml";87 88const char *AddBarBaz = R"yaml(89CompileFlags:90  Add: bar91---92CompileFlags:93  Add: baz94)yaml";95 96TEST(ProviderTest, FromYAMLFile) {97  MockFS FS;98  FS.Files["foo.yaml"] = AddFooWithErr;99 100  CapturedDiags Diags;101  auto P = Provider::fromYAMLFile(testPath("foo.yaml"), /*Directory=*/"", FS);102  auto Cfg = P->getConfig(Params(), Diags.callback());103  EXPECT_THAT(Diags.Diagnostics,104              ElementsAre(diagMessage("Unknown CompileFlags key 'Unknown'")));105  EXPECT_THAT(Diags.Files, ElementsAre(testPath("foo.yaml")));106  EXPECT_THAT(getAddedArgs(Cfg), ElementsAre("foo"));107  Diags.clear();108 109  Cfg = P->getConfig(Params(), Diags.callback());110  EXPECT_THAT(Diags.Diagnostics, IsEmpty()) << "Cached, not re-parsed";111  EXPECT_THAT(Diags.Files, IsEmpty());112  EXPECT_THAT(getAddedArgs(Cfg), ElementsAre("foo"));113 114  FS.Files["foo.yaml"] = AddFooWithTypoErr;115  Cfg = P->getConfig(Params(), Diags.callback());116  EXPECT_THAT(117      Diags.Diagnostics,118      ElementsAre(diagMessage(119          "Unknown CompileFlags key 'Removr'; did you mean 'Remove'?")));120  EXPECT_THAT(Diags.Files, ElementsAre(testPath("foo.yaml")));121  EXPECT_THAT(getAddedArgs(Cfg), ElementsAre("foo"));122  Diags.clear();123 124  FS.Files["foo.yaml"] = AddBarBaz;125  Cfg = P->getConfig(Params(), Diags.callback());126  EXPECT_THAT(Diags.Diagnostics, IsEmpty()) << "New config, no errors";127  EXPECT_THAT(Diags.Files, ElementsAre(testPath("foo.yaml")));128  EXPECT_THAT(getAddedArgs(Cfg), ElementsAre("bar", "baz"));129  Diags.clear();130 131  FS.Files.erase("foo.yaml");132  Cfg = P->getConfig(Params(), Diags.callback());133  EXPECT_THAT(Diags.Diagnostics, IsEmpty()) << "Missing file is not an error";134  EXPECT_THAT(Diags.Files, IsEmpty());135  EXPECT_THAT(getAddedArgs(Cfg), IsEmpty());136}137 138TEST(ProviderTest, FromAncestorRelativeYAMLFiles) {139  MockFS FS;140  FS.Files["a/b/c/foo.yaml"] = AddBarBaz;141  FS.Files["a/foo.yaml"] = AddFooWithErr;142 143  std::string ABCPath =144      testPath("a/b/c/d/test.cc", llvm::sys::path::Style::posix);145  Params ABCParams;146  ABCParams.Path = ABCPath;147  std::string APath =148      testPath("a/b/e/f/test.cc", llvm::sys::path::Style::posix);149  Params AParams;150  AParams.Path = APath;151 152  CapturedDiags Diags;153  auto P = Provider::fromAncestorRelativeYAMLFiles("foo.yaml", FS);154 155  auto Cfg = P->getConfig(Params(), Diags.callback());156  EXPECT_THAT(Diags.Diagnostics, IsEmpty());157  EXPECT_THAT(Diags.Files, IsEmpty());158  EXPECT_THAT(getAddedArgs(Cfg), IsEmpty());159 160  Cfg = P->getConfig(ABCParams, Diags.callback());161  EXPECT_THAT(Diags.Diagnostics,162              ElementsAre(diagMessage("Unknown CompileFlags key 'Unknown'")));163  // FIXME: fails on windows: paths have mixed slashes like C:\a/b\c.yaml164  EXPECT_THAT(Diags.Files,165              ElementsAre(testPath("a/foo.yaml"), testPath("a/b/c/foo.yaml")));166  EXPECT_THAT(getAddedArgs(Cfg), ElementsAre("foo", "bar", "baz"));167  Diags.clear();168 169  Cfg = P->getConfig(AParams, Diags.callback());170  EXPECT_THAT(Diags.Diagnostics, IsEmpty()) << "Cached config";171  EXPECT_THAT(Diags.Files, IsEmpty());172  EXPECT_THAT(getAddedArgs(Cfg), ElementsAre("foo"));173 174  FS.Files.erase("a/foo.yaml");175  Cfg = P->getConfig(ABCParams, Diags.callback());176  EXPECT_THAT(Diags.Diagnostics, IsEmpty());177  EXPECT_THAT(Diags.Files, IsEmpty());178  EXPECT_THAT(getAddedArgs(Cfg), ElementsAre("bar", "baz"));179}180 181TEST(ProviderTest, SourceInfo) {182  MockFS FS;183 184  FS.Files["baz/foo.yaml"] = R"yaml(185If:186  PathMatch: .*187  PathExclude: bar.h188CompileFlags:189  Add: bar190)yaml";191  const auto BarPath = testPath("baz/bar.h", llvm::sys::path::Style::posix);192  CapturedDiags Diags;193  Params Bar;194  Bar.Path = BarPath;195 196  // This should be an absolute match/exclude hence baz/bar.h should not be197  // excluded.198  auto P =199      Provider::fromYAMLFile(testPath("baz/foo.yaml"), /*Directory=*/"", FS);200  auto Cfg = P->getConfig(Bar, Diags.callback());201  ASSERT_THAT(Diags.Diagnostics, IsEmpty());202  EXPECT_THAT(getAddedArgs(Cfg), ElementsAre("bar"));203  Diags.clear();204 205  // This should be a relative match/exclude hence baz/bar.h should be excluded.206  P = Provider::fromAncestorRelativeYAMLFiles("foo.yaml", FS);207  Cfg = P->getConfig(Bar, Diags.callback());208  ASSERT_THAT(Diags.Diagnostics, IsEmpty());209  EXPECT_THAT(getAddedArgs(Cfg), IsEmpty());210  Diags.clear();211}212} // namespace213} // namespace config214} // namespace clangd215} // namespace clang216