clang-tools 22.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/StringRef.h"
14#include "llvm/Support/SMLoc.h"
15#include "llvm/Support/SourceMgr.h"
16#include "llvm/Testing/Support/SupportHelpers.h"
17#include "gmock/gmock.h"
18#include "gtest/gtest.h"
19
20namespace clang {
21namespace clangd {
22namespace config {
23
24// PrintTo is a magic identifier of GTest
25// NOLINTNEXTLINE (readability-identifier-naming)
26template <typename T> void PrintTo(const Located<T> &V, std::ostream *OS) {
27 *OS << ::testing::PrintToString(*V);
28}
29
30namespace {
31using ::testing::AllOf;
32using ::testing::ElementsAre;
33using ::testing::IsEmpty;
34
35MATCHER_P(val, Value, "") {
36 if (*arg == Value)
37 return true;
38 *result_listener << "value is " << *arg;
39 return false;
40}
41
42MATCHER_P2(PairVal, Value1, Value2, "") {
43 if (*arg.first == Value1 && *arg.second == Value2)
44 return true;
45 *result_listener << "values are [" << *arg.first << ", " << *arg.second
46 << "]";
47 return false;
48}
49
50TEST(ParseYAML, SyntacticForms) {
51 CapturedDiags Diags;
52 const char *YAML = R"yaml(
53If:
54 PathMatch:
55 - 'abc'
56CompileFlags: { Add: [foo, bar] }
57---
58CompileFlags:
59 Add: |
60 b
61 az
62---
63Index:
64 Background: Skip
65---
66Diagnostics:
67 ClangTidy:
68 CheckOptions:
69 example-check.ExampleOption: 0
70 UnusedIncludes: Strict
71 )yaml";
72 auto Results = Fragment::parseYAML(YAML, "config.yaml", Diags.callback());
73 EXPECT_THAT(Diags.Diagnostics, IsEmpty());
74 EXPECT_THAT(Diags.Files, ElementsAre("config.yaml"));
75 ASSERT_EQ(Results.size(), 4u);
76 EXPECT_FALSE(Results[0].If.HasUnrecognizedCondition);
77 EXPECT_THAT(Results[0].If.PathMatch, ElementsAre(val("abc")));
78 EXPECT_THAT(Results[0].CompileFlags.Add, ElementsAre(val("foo"), val("bar")));
79
80 EXPECT_THAT(Results[1].CompileFlags.Add, ElementsAre(val("b\naz\n")));
81
82 ASSERT_TRUE(Results[2].Index.Background);
83 EXPECT_EQ("Skip", **Results[2].Index.Background);
84 EXPECT_THAT(Results[3].Diagnostics.ClangTidy.CheckOptions,
85 ElementsAre(PairVal("example-check.ExampleOption", "0")));
86 EXPECT_TRUE(Results[3].Diagnostics.UnusedIncludes);
87 EXPECT_EQ("Strict", **Results[3].Diagnostics.UnusedIncludes);
88}
89
90TEST(ParseYAML, Locations) {
91 CapturedDiags Diags;
92 Annotations YAML(R"yaml(
93If:
94 PathMatch: [['???bad***regex(((']]
95 )yaml");
96 auto Results =
97 Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
98 EXPECT_THAT(Diags.Diagnostics, IsEmpty());
99 ASSERT_EQ(Results.size(), 1u);
100 ASSERT_NE(Results.front().Source.Manager, nullptr);
101 EXPECT_EQ(toRange(Results.front().If.PathMatch.front().Range,
102 *Results.front().Source.Manager),
103 YAML.range());
104}
105
106TEST(ParseYAML, ConfigDiagnostics) {
107 CapturedDiags Diags;
108 Annotations YAML(R"yaml(
109If:
110 $unknown[[UnknownCondition]]: "foo"
111CompileFlags:
112 Add: 'first'
113---
114CompileFlags: {$unexpected^
115)yaml");
116 auto Results =
117 Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
118
119 ASSERT_THAT(
120 Diags.Diagnostics,
121 ElementsAre(AllOf(diagMessage("Unknown If key 'UnknownCondition'"),
122 diagKind(llvm::SourceMgr::DK_Warning),
123 diagPos(YAML.range("unknown").start),
124 diagRange(YAML.range("unknown"))),
125 AllOf(diagMessage("Unexpected token. Expected Key, Flow "
126 "Entry, or Flow Mapping End."),
127 diagKind(llvm::SourceMgr::DK_Error),
128 diagPos(YAML.point("unexpected")),
129 diagRange(std::nullopt))));
130
131 ASSERT_EQ(Results.size(), 1u); // invalid fragment discarded.
132 EXPECT_THAT(Results.front().CompileFlags.Add, ElementsAre(val("first")));
133 EXPECT_TRUE(Results.front().If.HasUnrecognizedCondition);
134}
135
136TEST(ParseYAML, Invalid) {
137 CapturedDiags Diags;
138 const char *YAML = R"yaml(
139If:
140
141horrible
142---
143- 1
144 )yaml";
145 auto Results = Fragment::parseYAML(YAML, "config.yaml", Diags.callback());
146 EXPECT_THAT(Diags.Diagnostics,
147 ElementsAre(diagMessage("If should be a dictionary"),
148 diagMessage("Config should be a dictionary")));
149 ASSERT_THAT(Results, IsEmpty());
150}
151
152TEST(ParseYAML, ExternalBlockNone) {
153 CapturedDiags Diags;
154 Annotations YAML(R"yaml(
155Index:
156 External: None
157 )yaml");
158 auto Results =
159 Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
160 ASSERT_THAT(Diags.Diagnostics, IsEmpty());
161 ASSERT_EQ(Results.size(), 1u);
162 ASSERT_TRUE(Results[0].Index.External);
163 EXPECT_FALSE((*Results[0].Index.External)->File.has_value());
164 EXPECT_FALSE((*Results[0].Index.External)->MountPoint.has_value());
165 EXPECT_FALSE((*Results[0].Index.External)->Server.has_value());
166 EXPECT_THAT(*(*Results[0].Index.External)->IsNone, testing::Eq(true));
167}
168
169TEST(ParseYAML, ExternalBlock) {
170 CapturedDiags Diags;
171 Annotations YAML(R"yaml(
172Index:
173 External:
174 File: "foo"
175 Server: ^"bar"
176 MountPoint: "baz"
177 )yaml");
178 auto Results =
179 Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
180 ASSERT_EQ(Results.size(), 1u);
181 ASSERT_TRUE(Results[0].Index.External);
182 EXPECT_THAT(*(*Results[0].Index.External)->File, val("foo"));
183 EXPECT_THAT(*(*Results[0].Index.External)->MountPoint, val("baz"));
184 ASSERT_THAT(Diags.Diagnostics, IsEmpty());
185 EXPECT_THAT(*(*Results[0].Index.External)->Server, val("bar"));
186}
187
188TEST(ParseYAML, AllScopes) {
189 CapturedDiags Diags;
190 Annotations YAML(R"yaml(
191Completion:
192 AllScopes: True
193 )yaml");
194 auto Results =
195 Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
196 ASSERT_THAT(Diags.Diagnostics, IsEmpty());
197 ASSERT_EQ(Results.size(), 1u);
198 EXPECT_THAT(Results[0].Completion.AllScopes, llvm::ValueIs(val(true)));
199}
200
201TEST(ParseYAML, AllScopesWarn) {
202 CapturedDiags Diags;
203 Annotations YAML(R"yaml(
204Completion:
205 AllScopes: $diagrange[[Truex]]
206 )yaml");
207 auto Results =
208 Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
209 EXPECT_THAT(Diags.Diagnostics,
210 ElementsAre(AllOf(diagMessage("AllScopes should be a boolean"),
211 diagKind(llvm::SourceMgr::DK_Warning),
212 diagPos(YAML.range("diagrange").start),
213 diagRange(YAML.range("diagrange")))));
214 ASSERT_EQ(Results.size(), 1u);
215 EXPECT_THAT(Results[0].Completion.AllScopes, testing::Eq(std::nullopt));
216}
217
218TEST(ParseYAML, CodePatterns) {
219 CapturedDiags Diags;
220 Annotations YAML(R"yaml(
221 Completion:
222 CodePatterns: None
223 )yaml");
224 auto Results =
225 Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
226 ASSERT_THAT(Diags.Diagnostics, IsEmpty());
227 ASSERT_EQ(Results.size(), 1u);
228 EXPECT_THAT(Results[0].Completion.CodePatterns, llvm::ValueIs(val("None")));
229}
230
231TEST(ParseYAML, Hover) {
232 CapturedDiags Diags;
233 Annotations YAML(R"yaml(
234Hover:
235 ShowAKA: True
236 MacroContentsLimit: 4096
237 )yaml");
238 auto Results =
239 Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
240 ASSERT_THAT(Diags.Diagnostics, IsEmpty());
241 ASSERT_EQ(Results.size(), 1u);
242 EXPECT_THAT(Results[0].Hover.ShowAKA, llvm::ValueIs(val(true)));
243 EXPECT_THAT(Results[0].Hover.MacroContentsLimit, llvm::ValueIs(val(4096U)));
244}
245
246TEST(ParseYAML, InlayHints) {
247 CapturedDiags Diags;
248 Annotations YAML(R"yaml(
249InlayHints:
250 Enabled: No
251 ParameterNames: Yes
252 )yaml");
253 auto Results =
254 Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
255 ASSERT_THAT(Diags.Diagnostics, IsEmpty());
256 ASSERT_EQ(Results.size(), 1u);
257 EXPECT_THAT(Results[0].InlayHints.Enabled, llvm::ValueIs(val(false)));
258 EXPECT_THAT(Results[0].InlayHints.ParameterNames, llvm::ValueIs(val(true)));
259 EXPECT_EQ(Results[0].InlayHints.DeducedTypes, std::nullopt);
260}
261
262TEST(ParseYAML, SemanticTokens) {
263 CapturedDiags Diags;
264 Annotations YAML(R"yaml(
265SemanticTokens:
266 DisabledKinds: [ Operator, InactiveCode]
267 DisabledModifiers: Readonly
268 )yaml");
269 auto Results =
270 Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
271 ASSERT_THAT(Diags.Diagnostics, IsEmpty());
272 ASSERT_EQ(Results.size(), 1u);
273 EXPECT_THAT(Results[0].SemanticTokens.DisabledKinds,
274 ElementsAre(val("Operator"), val("InactiveCode")));
275 EXPECT_THAT(Results[0].SemanticTokens.DisabledModifiers,
276 ElementsAre(val("Readonly")));
277}
278
279TEST(ParseYAML, IncludesIgnoreHeader) {
280 CapturedDiags Diags;
281 Annotations YAML(R"yaml(
282Diagnostics:
283 Includes:
284 IgnoreHeader: [foo, bar]
285 )yaml");
286 auto Results =
287 Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
288 ASSERT_THAT(Diags.Diagnostics, IsEmpty());
289 ASSERT_EQ(Results.size(), 1u);
290 EXPECT_THAT(Results[0].Diagnostics.Includes.IgnoreHeader,
291 ElementsAre(val("foo"), val("bar")));
292}
293
294TEST(ParseYAML, IncludesAnalyzeAngledIncludes) {
295 CapturedDiags Diags;
296 Annotations YAML(R"yaml(
297Diagnostics:
298 Includes:
299 AnalyzeAngledIncludes: true
300 )yaml");
301 auto Results =
302 Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
303 ASSERT_THAT(Diags.Diagnostics, IsEmpty());
304 ASSERT_EQ(Results.size(), 1u);
305 EXPECT_THAT(Results[0].Diagnostics.Includes.AnalyzeAngledIncludes,
306 llvm::ValueIs(val(true)));
307}
308
309TEST(ParseYAML, Style) {
310 CapturedDiags Diags;
311 Annotations YAML(R"yaml(
312Style:
313 FullyQualifiedNamespaces: [foo, bar]
314 AngledHeaders: ["foo", "bar"]
315 QuotedHeaders: ["baz", "baar"])yaml");
316 auto Results =
317 Fragment::parseYAML(YAML.code(), "config.yaml", Diags.callback());
318 ASSERT_THAT(Diags.Diagnostics, IsEmpty());
319 ASSERT_EQ(Results.size(), 1u);
320 EXPECT_THAT(Results[0].Style.FullyQualifiedNamespaces,
321 ElementsAre(val("foo"), val("bar")));
322 EXPECT_THAT(Results[0].Style.AngledHeaders,
323 ElementsAre(val("foo"), val("bar")));
324 EXPECT_THAT(Results[0].Style.QuotedHeaders,
325 ElementsAre(val("baz"), val("baar")));
326}
327} // namespace
328} // namespace config
329} // namespace clangd
330} // namespace clang
MATCHER_P(diagMessage, M, "")
Range toRange(llvm::SMRange R, const llvm::SourceMgr &SM)
void PrintTo(const Located< T > &V, std::ostream *OS)
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:45
MATCHER_P2(hasFlag, Flag, Path, "")
TEST(BackgroundQueueTest, Priority)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
static std::vector< Fragment > parseYAML(llvm::StringRef YAML, llvm::StringRef BufferName, DiagnosticCallback)
Parses fragments from a YAML file (one from each — delimited document).
An entity written in config along, with its optional location in the file.