clang-tools  15.0.0git
ConfigYAMLTests.cpp
Go to the documentation of this file.
1 //===-- ConfigYAMLTests.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-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Annotations.h"
10 #include "ConfigFragment.h"
11 #include "ConfigTesting.h"
12 #include "Protocol.h"
13 #include "llvm/ADT/None.h"
14 #include "llvm/ADT/StringRef.h"
15 #include "llvm/Support/SMLoc.h"
16 #include "llvm/Support/SourceMgr.h"
17 #include "llvm/Testing/Support/SupportHelpers.h"
18 #include "gmock/gmock.h"
19 #include "gtest/gtest.h"
20 
21 namespace clang {
22 namespace clangd {
23 namespace config {
24 
25 // PrintTo is a magic identifier of GTest
26 // NOLINTNEXTLINE (readability-identifier-naming)
27 template <typename T> void PrintTo(const Located<T> &V, std::ostream *OS) {
28  *OS << ::testing::PrintToString(*V);
29 }
30 
31 namespace {
32 using ::testing::AllOf;
33 using ::testing::ElementsAre;
34 using ::testing::IsEmpty;
35 
36 MATCHER_P(val, Value, "") {
37  if (*arg == Value)
38  return true;
39  *result_listener << "value is " << *arg;
40  return false;
41 }
42 
43 MATCHER_P2(PairVal, Value1, Value2, "") {
44  if (*arg.first == Value1 && *arg.second == Value2)
45  return true;
46  *result_listener << "values are [" << *arg.first << ", " << *arg.second
47  << "]";
48  return false;
49 }
50 
51 TEST(ParseYAML, SyntacticForms) {
52  CapturedDiags Diags;
53  const char *YAML = R"yaml(
54 If:
55  PathMatch:
56  - 'abc'
57 CompileFlags: { Add: [foo, bar] }
58 ---
59 CompileFlags:
60  Add: |
61  b
62  az
63 ---
64 Index:
65  Background: Skip
66 ---
67 Diagnostics:
68  ClangTidy:
69  CheckOptions:
70  IgnoreMacros: true
71  example-check.ExampleOption: 0
72  UnusedIncludes: Strict
73  )yaml";
74  auto Results = Fragment::parseYAML(YAML, "config.yaml", Diags.callback());
75  EXPECT_THAT(Diags.Diagnostics, IsEmpty());
76  EXPECT_THAT(Diags.Files, ElementsAre("config.yaml"));
77  ASSERT_EQ(Results.size(), 4u);
78  EXPECT_FALSE(Results[0].If.HasUnrecognizedCondition);
79  EXPECT_THAT(Results[0].If.PathMatch, ElementsAre(val("abc")));
80  EXPECT_THAT(Results[0].CompileFlags.Add, ElementsAre(val("foo"), val("bar")));
81 
82  EXPECT_THAT(Results[1].CompileFlags.Add, ElementsAre(val("b\naz\n")));
83 
84  ASSERT_TRUE(Results[2].Index.Background);
85  EXPECT_EQ("Skip", *Results[2].Index.Background.getValue());
86  EXPECT_THAT(Results[3].Diagnostics.ClangTidy.CheckOptions,
87  ElementsAre(PairVal("IgnoreMacros", "true"),
88  PairVal("example-check.ExampleOption", "0")));
89  EXPECT_TRUE(Results[3].Diagnostics.UnusedIncludes);
90  EXPECT_EQ("Strict", *Results[3].Diagnostics.UnusedIncludes.getValue());
91 }
92 
93 TEST(ParseYAML, Locations) {
94  CapturedDiags Diags;
95  Annotations YAML(R"yaml(
96 If:
97  PathMatch: [['???bad***regex(((']]
98  )yaml");
99  auto Results =
100  Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
101  EXPECT_THAT(Diags.Diagnostics, IsEmpty());
102  ASSERT_EQ(Results.size(), 1u);
103  ASSERT_NE(Results.front().Source.Manager, nullptr);
104  EXPECT_EQ(toRange(Results.front().If.PathMatch.front().Range,
105  *Results.front().Source.Manager),
106  YAML.range());
107 }
108 
109 TEST(ParseYAML, ConfigDiagnostics) {
110  CapturedDiags Diags;
111  Annotations YAML(R"yaml(
112 If:
113  $unknown[[UnknownCondition]]: "foo"
114 CompileFlags:
115  Add: 'first'
116 ---
117 CompileFlags: {$unexpected^
118 )yaml");
119  auto Results =
120  Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
121 
122  ASSERT_THAT(
124  ElementsAre(AllOf(diagMessage("Unknown If key 'UnknownCondition'"),
125  diagKind(llvm::SourceMgr::DK_Warning),
126  diagPos(YAML.range("unknown").start),
127  diagRange(YAML.range("unknown"))),
128  AllOf(diagMessage("Unexpected token. Expected Key, Flow "
129  "Entry, or Flow Mapping End."),
130  diagKind(llvm::SourceMgr::DK_Error),
131  diagPos(YAML.point("unexpected")),
132  diagRange(llvm::None))));
133 
134  ASSERT_EQ(Results.size(), 1u); // invalid fragment discarded.
135  EXPECT_THAT(Results.front().CompileFlags.Add, ElementsAre(val("first")));
136  EXPECT_TRUE(Results.front().If.HasUnrecognizedCondition);
137 }
138 
139 TEST(ParseYAML, Invalid) {
140  CapturedDiags Diags;
141  const char *YAML = R"yaml(
142 If:
143 
144 horrible
145 ---
146 - 1
147  )yaml";
148  auto Results = Fragment::parseYAML(YAML, "config.yaml", Diags.callback());
149  EXPECT_THAT(Diags.Diagnostics,
150  ElementsAre(diagMessage("If should be a dictionary"),
151  diagMessage("Config should be a dictionary")));
152  ASSERT_THAT(Results, IsEmpty());
153 }
154 
155 TEST(ParseYAML, ExternalBlockNone) {
156  CapturedDiags Diags;
157  Annotations YAML(R"yaml(
158 Index:
159  External: None
160  )yaml");
161  auto Results =
162  Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
163  ASSERT_THAT(Diags.Diagnostics, IsEmpty());
164  ASSERT_EQ(Results.size(), 1u);
165  ASSERT_TRUE(Results[0].Index.External);
166  EXPECT_FALSE(Results[0].Index.External.getValue()->File.hasValue());
167  EXPECT_FALSE(Results[0].Index.External.getValue()->MountPoint.hasValue());
168  EXPECT_FALSE(Results[0].Index.External.getValue()->Server.hasValue());
169  EXPECT_THAT(*Results[0].Index.External.getValue()->IsNone, testing::Eq(true));
170 }
171 
172 TEST(ParseYAML, ExternalBlock) {
173  CapturedDiags Diags;
174  Annotations YAML(R"yaml(
175 Index:
176  External:
177  File: "foo"
178  Server: ^"bar"
179  MountPoint: "baz"
180  )yaml");
181  auto Results =
182  Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
183  ASSERT_EQ(Results.size(), 1u);
184  ASSERT_TRUE(Results[0].Index.External);
185  EXPECT_THAT(*Results[0].Index.External.getValue()->File, val("foo"));
186  EXPECT_THAT(*Results[0].Index.External.getValue()->MountPoint, val("baz"));
187  ASSERT_THAT(Diags.Diagnostics, IsEmpty());
188  EXPECT_THAT(*Results[0].Index.External.getValue()->Server, val("bar"));
189 }
190 
191 TEST(ParseYAML, AllScopes) {
192  CapturedDiags Diags;
193  Annotations YAML(R"yaml(
194 Completion:
195  AllScopes: True
196  )yaml");
197  auto Results =
198  Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
199  ASSERT_THAT(Diags.Diagnostics, IsEmpty());
200  ASSERT_EQ(Results.size(), 1u);
201  EXPECT_THAT(Results[0].Completion.AllScopes, llvm::ValueIs(val(true)));
202 }
203 
204 TEST(ParseYAML, AllScopesWarn) {
205  CapturedDiags Diags;
206  Annotations YAML(R"yaml(
207 Completion:
208  AllScopes: $diagrange[[Truex]]
209  )yaml");
210  auto Results =
211  Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
212  EXPECT_THAT(Diags.Diagnostics,
213  ElementsAre(AllOf(diagMessage("AllScopes should be a boolean"),
214  diagKind(llvm::SourceMgr::DK_Warning),
215  diagPos(YAML.range("diagrange").start),
216  diagRange(YAML.range("diagrange")))));
217  ASSERT_EQ(Results.size(), 1u);
218  EXPECT_THAT(Results[0].Completion.AllScopes, testing::Eq(llvm::None));
219 }
220 
221 TEST(ParseYAML, ShowAKA) {
222  CapturedDiags Diags;
223  Annotations YAML(R"yaml(
224 Hover:
225  ShowAKA: True
226  )yaml");
227  auto Results =
228  Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
229  ASSERT_THAT(Diags.Diagnostics, IsEmpty());
230  ASSERT_EQ(Results.size(), 1u);
231  EXPECT_THAT(Results[0].Hover.ShowAKA, llvm::ValueIs(val(true)));
232 }
233 
234 TEST(ParseYAML, InlayHints) {
235  CapturedDiags Diags;
236  Annotations YAML(R"yaml(
237 InlayHints:
238  Enabled: No
239  ParameterNames: Yes
240  )yaml");
241  auto Results =
242  Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
243  ASSERT_THAT(Diags.Diagnostics, IsEmpty());
244  ASSERT_EQ(Results.size(), 1u);
245  EXPECT_THAT(Results[0].InlayHints.Enabled, llvm::ValueIs(val(false)));
246  EXPECT_THAT(Results[0].InlayHints.ParameterNames, llvm::ValueIs(val(true)));
247  EXPECT_EQ(Results[0].InlayHints.DeducedTypes, llvm::None);
248 }
249 
250 TEST(ParseYAML, IncludesIgnoreHeader) {
251  CapturedDiags Diags;
252  Annotations YAML(R"yaml(
253 Diagnostics:
254  Includes:
255  IgnoreHeader: [foo, bar]
256  )yaml");
257  auto Results =
258  Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
259  ASSERT_THAT(Diags.Diagnostics, IsEmpty());
260  ASSERT_EQ(Results.size(), 1u);
261  EXPECT_THAT(Results[0].Diagnostics.Includes.IgnoreHeader,
262  ElementsAre(val("foo"), val("bar")));
263 }
264 } // namespace
265 } // namespace config
266 } // namespace clangd
267 } // namespace clang
clang::clangd::IndexFileFormat::YAML
@ YAML
clang::clangd::TEST
TEST(BackgroundQueueTest, Priority)
Definition: BackgroundIndexTests.cpp:750
clang::clangd::MATCHER_P2
MATCHER_P2(hasFlag, Flag, Path, "")
Definition: GlobalCompilationDatabaseTests.cpp:446
clang::clangd::config::Fragment::parseYAML
static std::vector< Fragment > parseYAML(llvm::StringRef YAML, llvm::StringRef BufferName, DiagnosticCallback)
Parses fragments from a YAML file (one from each — delimited document).
Definition: ConfigYAML.cpp:413
Diagnostics
WantDiagnostics Diagnostics
Definition: TUScheduler.cpp:602
clang::clangd::config::CapturedDiags::callback
std::function< void(const llvm::SMDiagnostic &)> callback()
Definition: ConfigTesting.h:25
clang::clangd::config::Located
An entity written in config along, with its optional location in the file.
Definition: ConfigFragment.h:47
Protocol.h
clang::clangd::config::MATCHER_P
MATCHER_P(diagMessage, M, "")
Definition: ConfigTesting.h:68
ConfigTesting.h
Results
std::vector< CodeCompletionResult > Results
Definition: CodeComplete.cpp:780
Annotations.h
clang::clangd::config::CapturedDiags::Files
std::vector< std::string > Files
Definition: ConfigTesting.h:60
Index
const SymbolIndex * Index
Definition: Dexp.cpp:98
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ApplyReplacements.h:27
OS
llvm::raw_string_ostream OS
Definition: TraceTests.cpp:160
Diags
CapturedDiags Diags
Definition: ConfigCompileTests.cpp:39
clang::clangd::config::PrintTo
void PrintTo(const Located< T > &V, std::ostream *OS)
Definition: ConfigYAMLTests.cpp:27
clang::clangd::config::CapturedDiags::Diagnostics
std::vector< Diag > Diagnostics
Definition: ConfigTesting.h:59
clang::clangd::config::toRange
Range toRange(llvm::SMRange R, const llvm::SourceMgr &SM)
Definition: ConfigTesting.h:81
ConfigFragment.h