219 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			219 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- ConfigYAMLTests.cpp -----------------------------------------------===//
 | 
						|
//
 | 
						|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | 
						|
// See https://llvm.org/LICENSE.txt for license information.
 | 
						|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | 
						|
//
 | 
						|
//===----------------------------------------------------------------------===//
 | 
						|
 | 
						|
#include "Annotations.h"
 | 
						|
#include "ConfigFragment.h"
 | 
						|
#include "ConfigTesting.h"
 | 
						|
#include "Protocol.h"
 | 
						|
#include "llvm/ADT/None.h"
 | 
						|
#include "llvm/ADT/StringRef.h"
 | 
						|
#include "llvm/Support/SMLoc.h"
 | 
						|
#include "llvm/Support/ScopedPrinter.h"
 | 
						|
#include "llvm/Support/SourceMgr.h"
 | 
						|
#include "llvm/Testing/Support/SupportHelpers.h"
 | 
						|
#include "gmock/gmock.h"
 | 
						|
#include "gtest/gtest.h"
 | 
						|
 | 
						|
namespace clang {
 | 
						|
namespace clangd {
 | 
						|
namespace config {
 | 
						|
template <typename T> void PrintTo(const Located<T> &V, std::ostream *OS) {
 | 
						|
  *OS << ::testing::PrintToString(*V);
 | 
						|
}
 | 
						|
 | 
						|
namespace {
 | 
						|
using ::testing::AllOf;
 | 
						|
using ::testing::ElementsAre;
 | 
						|
using ::testing::IsEmpty;
 | 
						|
 | 
						|
MATCHER_P(Val, Value, "") {
 | 
						|
  if (*arg == Value)
 | 
						|
    return true;
 | 
						|
  *result_listener << "value is " << *arg;
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
MATCHER_P2(PairVal, Value1, Value2, "") {
 | 
						|
  if (*arg.first == Value1 && *arg.second == Value2)
 | 
						|
    return true;
 | 
						|
  *result_listener << "values are [" << *arg.first << ", " << *arg.second
 | 
						|
                   << "]";
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
TEST(ParseYAML, SyntacticForms) {
 | 
						|
  CapturedDiags Diags;
 | 
						|
  const char *YAML = R"yaml(
 | 
						|
If:
 | 
						|
  PathMatch:
 | 
						|
    - 'abc'
 | 
						|
CompileFlags: { Add: [foo, bar] }
 | 
						|
---
 | 
						|
CompileFlags:
 | 
						|
  Add: |
 | 
						|
    b
 | 
						|
    az
 | 
						|
---
 | 
						|
Index:
 | 
						|
  Background: Skip
 | 
						|
---
 | 
						|
Diagnostics:
 | 
						|
  ClangTidy:
 | 
						|
    CheckOptions:
 | 
						|
      IgnoreMacros: true
 | 
						|
      example-check.ExampleOption: 0
 | 
						|
  )yaml";
 | 
						|
  auto Results = Fragment::parseYAML(YAML, "config.yaml", Diags.callback());
 | 
						|
  EXPECT_THAT(Diags.Diagnostics, IsEmpty());
 | 
						|
  EXPECT_THAT(Diags.Files, ElementsAre("config.yaml"));
 | 
						|
  ASSERT_EQ(Results.size(), 4u);
 | 
						|
  EXPECT_FALSE(Results[0].If.HasUnrecognizedCondition);
 | 
						|
  EXPECT_THAT(Results[0].If.PathMatch, ElementsAre(Val("abc")));
 | 
						|
  EXPECT_THAT(Results[0].CompileFlags.Add, ElementsAre(Val("foo"), Val("bar")));
 | 
						|
 | 
						|
  EXPECT_THAT(Results[1].CompileFlags.Add, ElementsAre(Val("b\naz\n")));
 | 
						|
 | 
						|
  ASSERT_TRUE(Results[2].Index.Background);
 | 
						|
  EXPECT_EQ("Skip", *Results[2].Index.Background.getValue());
 | 
						|
  EXPECT_THAT(Results[3].Diagnostics.ClangTidy.CheckOptions,
 | 
						|
              ElementsAre(PairVal("IgnoreMacros", "true"),
 | 
						|
                          PairVal("example-check.ExampleOption", "0")));
 | 
						|
}
 | 
						|
 | 
						|
TEST(ParseYAML, Locations) {
 | 
						|
  CapturedDiags Diags;
 | 
						|
  Annotations YAML(R"yaml(
 | 
						|
If:
 | 
						|
  PathMatch: [['???bad***regex(((']]
 | 
						|
  )yaml");
 | 
						|
  auto Results =
 | 
						|
      Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
 | 
						|
  EXPECT_THAT(Diags.Diagnostics, IsEmpty());
 | 
						|
  ASSERT_EQ(Results.size(), 1u);
 | 
						|
  ASSERT_NE(Results.front().Source.Manager, nullptr);
 | 
						|
  EXPECT_EQ(toRange(Results.front().If.PathMatch.front().Range,
 | 
						|
                    *Results.front().Source.Manager),
 | 
						|
            YAML.range());
 | 
						|
}
 | 
						|
 | 
						|
TEST(ParseYAML, ConfigDiagnostics) {
 | 
						|
  CapturedDiags Diags;
 | 
						|
  Annotations YAML(R"yaml(
 | 
						|
If:
 | 
						|
  $unknown[[UnknownCondition]]: "foo"
 | 
						|
CompileFlags:
 | 
						|
  Add: 'first'
 | 
						|
---
 | 
						|
CompileFlags: {$unexpected^
 | 
						|
)yaml");
 | 
						|
  auto Results =
 | 
						|
      Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
 | 
						|
 | 
						|
  ASSERT_THAT(
 | 
						|
      Diags.Diagnostics,
 | 
						|
      ElementsAre(AllOf(DiagMessage("Unknown If key 'UnknownCondition'"),
 | 
						|
                        DiagKind(llvm::SourceMgr::DK_Warning),
 | 
						|
                        DiagPos(YAML.range("unknown").start),
 | 
						|
                        DiagRange(YAML.range("unknown"))),
 | 
						|
                  AllOf(DiagMessage("Unexpected token. Expected Key, Flow "
 | 
						|
                                    "Entry, or Flow Mapping End."),
 | 
						|
                        DiagKind(llvm::SourceMgr::DK_Error),
 | 
						|
                        DiagPos(YAML.point("unexpected")),
 | 
						|
                        DiagRange(llvm::None))));
 | 
						|
 | 
						|
  ASSERT_EQ(Results.size(), 1u); // invalid fragment discarded.
 | 
						|
  EXPECT_THAT(Results.front().CompileFlags.Add, ElementsAre(Val("first")));
 | 
						|
  EXPECT_TRUE(Results.front().If.HasUnrecognizedCondition);
 | 
						|
}
 | 
						|
 | 
						|
TEST(ParseYAML, Invalid) {
 | 
						|
  CapturedDiags Diags;
 | 
						|
  const char *YAML = R"yaml(
 | 
						|
If:
 | 
						|
 | 
						|
horrible
 | 
						|
---
 | 
						|
- 1
 | 
						|
  )yaml";
 | 
						|
  auto Results = Fragment::parseYAML(YAML, "config.yaml", Diags.callback());
 | 
						|
  EXPECT_THAT(Diags.Diagnostics,
 | 
						|
              ElementsAre(DiagMessage("If should be a dictionary"),
 | 
						|
                          DiagMessage("Config should be a dictionary")));
 | 
						|
  ASSERT_THAT(Results, IsEmpty());
 | 
						|
}
 | 
						|
 | 
						|
TEST(ParseYAML, ExternalBlockNone) {
 | 
						|
  CapturedDiags Diags;
 | 
						|
  Annotations YAML(R"yaml(
 | 
						|
Index:
 | 
						|
  External: None
 | 
						|
  )yaml");
 | 
						|
  auto Results =
 | 
						|
      Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
 | 
						|
  ASSERT_THAT(Diags.Diagnostics, IsEmpty());
 | 
						|
  ASSERT_EQ(Results.size(), 1u);
 | 
						|
  ASSERT_TRUE(Results[0].Index.External);
 | 
						|
  EXPECT_FALSE(Results[0].Index.External.getValue()->File.hasValue());
 | 
						|
  EXPECT_FALSE(Results[0].Index.External.getValue()->MountPoint.hasValue());
 | 
						|
  EXPECT_FALSE(Results[0].Index.External.getValue()->Server.hasValue());
 | 
						|
  EXPECT_THAT(*Results[0].Index.External.getValue()->IsNone, testing::Eq(true));
 | 
						|
}
 | 
						|
 | 
						|
TEST(ParseYAML, ExternalBlock) {
 | 
						|
  CapturedDiags Diags;
 | 
						|
  Annotations YAML(R"yaml(
 | 
						|
Index:
 | 
						|
  External:
 | 
						|
    File: "foo"
 | 
						|
    Server: ^"bar"
 | 
						|
    MountPoint: "baz"
 | 
						|
  )yaml");
 | 
						|
  auto Results =
 | 
						|
      Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
 | 
						|
  ASSERT_EQ(Results.size(), 1u);
 | 
						|
  ASSERT_TRUE(Results[0].Index.External);
 | 
						|
  EXPECT_THAT(*Results[0].Index.External.getValue()->File, Val("foo"));
 | 
						|
  EXPECT_THAT(*Results[0].Index.External.getValue()->MountPoint, Val("baz"));
 | 
						|
  ASSERT_THAT(Diags.Diagnostics, IsEmpty());
 | 
						|
  EXPECT_THAT(*Results[0].Index.External.getValue()->Server, Val("bar"));
 | 
						|
}
 | 
						|
 | 
						|
TEST(ParseYAML, AllScopes) {
 | 
						|
  CapturedDiags Diags;
 | 
						|
  Annotations YAML(R"yaml(
 | 
						|
Completion:
 | 
						|
  AllScopes: True
 | 
						|
  )yaml");
 | 
						|
  auto Results =
 | 
						|
      Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
 | 
						|
  ASSERT_THAT(Diags.Diagnostics, IsEmpty());
 | 
						|
  ASSERT_EQ(Results.size(), 1u);
 | 
						|
  EXPECT_THAT(Results[0].Completion.AllScopes, llvm::ValueIs(Val(true)));
 | 
						|
}
 | 
						|
 | 
						|
TEST(ParseYAML, AllScopesWarn) {
 | 
						|
  CapturedDiags Diags;
 | 
						|
  Annotations YAML(R"yaml(
 | 
						|
Completion:
 | 
						|
  AllScopes: $diagrange[[Truex]]
 | 
						|
  )yaml");
 | 
						|
  auto Results =
 | 
						|
      Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
 | 
						|
  EXPECT_THAT(Diags.Diagnostics,
 | 
						|
              ElementsAre(AllOf(DiagMessage("AllScopes should be a boolean"),
 | 
						|
                                DiagKind(llvm::SourceMgr::DK_Warning),
 | 
						|
                                DiagPos(YAML.range("diagrange").start),
 | 
						|
                                DiagRange(YAML.range("diagrange")))));
 | 
						|
  ASSERT_EQ(Results.size(), 1u);
 | 
						|
  EXPECT_THAT(Results[0].Completion.AllScopes, testing::Eq(llvm::None));
 | 
						|
}
 | 
						|
} // namespace
 | 
						|
} // namespace config
 | 
						|
} // namespace clangd
 | 
						|
} // namespace clang
 |