clang-tools 22.0.0git
MarkupTests.cpp
Go to the documentation of this file.
1//===-- MarkupTests.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#include "support/Markup.h"
9#include "clang/Basic/LLVM.h"
10#include "llvm/ADT/StringRef.h"
11#include "gmock/gmock.h"
12#include "gtest/gtest.h"
13
14namespace clang {
15namespace clangd {
16namespace markup {
17namespace {
18
19std::string escape(llvm::StringRef Text) {
21}
22
23std::string dontEscape(llvm::StringRef Text) {
24 return Paragraph().appendText(Text.str()).asMarkdown();
25}
26
27MATCHER_P(escaped, C, "") {
28 return testing::ExplainMatchResult(::testing::HasSubstr(std::string{'\\', C}),
29 arg, result_listener);
30}
31
32MATCHER(escapedNone, "") {
33 return testing::ExplainMatchResult(::testing::Not(::testing::HasSubstr("\\")),
34 arg, result_listener);
35}
36
37TEST(Render, Escaping) {
38 // Check all ASCII punctuation.
39 std::string Punctuation = R"txt(!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~)txt";
40 std::string EscapedPunc = R"txt(!"#$%&'()\*+,-./:;<=>?@[\\]^\_\`{|}~)txt";
41 EXPECT_EQ(escape(Punctuation), EscapedPunc);
42
43 // Inline code
44 EXPECT_EQ(escape("`foo`"), R"(\`foo\`)");
45 EXPECT_EQ(escape("`foo"), R"(\`foo)");
46 EXPECT_EQ(escape("foo`"), R"(foo\`)");
47 EXPECT_EQ(escape("``foo``"), R"(\`\`foo\`\`)");
48 // Code blocks
49 EXPECT_EQ(escape("```"), R"(\`\`\`)"); // This could also be inline code!
50 EXPECT_EQ(escape("~~~"), R"(\~~~)");
51
52 // Rulers and headings
53 EXPECT_THAT(escape("## Heading"), escaped('#'));
54 EXPECT_THAT(escape("Foo # bar"), escapedNone());
55 EXPECT_EQ(escape("---"), R"(\---)");
56 EXPECT_EQ(escape("-"), R"(\-)");
57 EXPECT_EQ(escape("==="), R"(\===)");
58 EXPECT_EQ(escape("="), R"(\=)");
59 EXPECT_EQ(escape("***"), R"(\*\*\*)"); // \** could start emphasis!
60
61 // HTML tags.
62 EXPECT_THAT(escape("<pre"), escaped('<'));
63 EXPECT_THAT(escape("< pre"), escapedNone());
64 EXPECT_THAT(escape("if a<b then"), escaped('<'));
65 EXPECT_THAT(escape("if a<b then c."), escapedNone());
66 EXPECT_THAT(escape("if a<b then c='foo'."), escaped('<'));
67 EXPECT_THAT(escape("std::vector<T>"), escaped('<'));
68 EXPECT_THAT(escape("std::vector<std::string>"), escaped('<'));
69 EXPECT_THAT(escape("std::map<int, int>"), escapedNone());
70 // Autolinks
71 EXPECT_THAT(escape("Email <foo@bar.com>"), escapedNone());
72 EXPECT_THAT(escape("Website <http://foo.bar>"), escapedNone());
73
74 // Bullet lists.
75 EXPECT_THAT(escape("- foo"), escaped('-'));
76 EXPECT_THAT(escape("* foo"), escaped('*'));
77 EXPECT_THAT(escape("+ foo"), escaped('+'));
78 EXPECT_THAT(escape("+"), escaped('+'));
79 EXPECT_THAT(escape("a + foo"), escapedNone());
80 EXPECT_THAT(escape("a+ foo"), escapedNone());
81 EXPECT_THAT(escape("1. foo"), escaped('.'));
82 EXPECT_THAT(escape("a. foo"), escapedNone());
83
84 // Emphasis.
85 EXPECT_EQ(escape("*foo*"), R"(\*foo\*)");
86 EXPECT_EQ(escape("**foo**"), R"(\*\*foo\*\*)");
87 EXPECT_THAT(escape("*foo"), escaped('*'));
88 EXPECT_THAT(escape("foo *"), escapedNone());
89 EXPECT_THAT(escape("foo * bar"), escapedNone());
90 EXPECT_THAT(escape("foo_bar"), escapedNone());
91 EXPECT_THAT(escape("foo _bar"), escaped('_'));
92 EXPECT_THAT(escape("foo_ bar"), escaped('_'));
93 EXPECT_THAT(escape("foo _ bar"), escapedNone());
94
95 // HTML entities.
96 EXPECT_THAT(escape("fish &chips;"), escaped('&'));
97 EXPECT_THAT(escape("fish & chips;"), escapedNone());
98 EXPECT_THAT(escape("fish &chips"), escapedNone());
99 EXPECT_THAT(escape("foo &#42; bar"), escaped('&'));
100 EXPECT_THAT(escape("foo &#xaf; bar"), escaped('&'));
101 EXPECT_THAT(escape("foo &?; bar"), escapedNone());
102
103 // Links.
104 EXPECT_THAT(escape("[foo](bar)"), escaped(']'));
105 EXPECT_THAT(escape("[foo]: bar"), escaped(']'));
106 // No need to escape these, as the target never exists.
107 EXPECT_THAT(escape("[foo][]"), escapedNone());
108 EXPECT_THAT(escape("[foo][bar]"), escapedNone());
109 EXPECT_THAT(escape("[foo]"), escapedNone());
110
111 // In code blocks we don't need to escape ASCII punctuation.
113 P.appendCode("* foo !+ bar * baz");
114 EXPECT_EQ(P.asEscapedMarkdown(), "`* foo !+ bar * baz`");
115
116 // But we have to escape the backticks.
117 P = Paragraph();
118 P.appendCode("foo`bar`baz", /*Preserve=*/true);
119 EXPECT_EQ(P.asEscapedMarkdown(), "`foo``bar``baz`");
120 // In plain-text, we fall back to different quotes.
121 EXPECT_EQ(P.asPlainText(), "'foo`bar`baz'");
122
123 // Inline code blocks starting or ending with backticks should add spaces.
124 P = Paragraph();
125 P.appendCode("`foo");
126 EXPECT_EQ(P.asEscapedMarkdown(), "` ``foo `");
127 P = Paragraph();
128 P.appendCode("foo`");
129 EXPECT_EQ(P.asEscapedMarkdown(), "` foo`` `");
130 P = Paragraph();
131 P.appendCode("`foo`");
132 EXPECT_EQ(P.asEscapedMarkdown(), "` ``foo`` `");
133
134 // Code blocks might need more than 3 backticks.
135 Document D;
136 D.addCodeBlock("foobarbaz `\nqux");
137 EXPECT_EQ(D.asEscapedMarkdown(), "```cpp\n"
138 "foobarbaz `\nqux\n"
139 "```");
140 D = Document();
141 D.addCodeBlock("foobarbaz ``\nqux");
142 EXPECT_THAT(D.asEscapedMarkdown(), "```cpp\n"
143 "foobarbaz ``\nqux\n"
144 "```");
145 D = Document();
146 D.addCodeBlock("foobarbaz ```\nqux");
147 EXPECT_EQ(D.asEscapedMarkdown(), "````cpp\n"
148 "foobarbaz ```\nqux\n"
149 "````");
150 D = Document();
151 D.addCodeBlock("foobarbaz ` `` ``` ```` `\nqux");
152 EXPECT_EQ(D.asEscapedMarkdown(), "`````cpp\n"
153 "foobarbaz ` `` ``` ```` `\nqux\n"
154 "`````");
155}
156
157TEST(Render, NoEscaping) {
158 // Check all ASCII punctuation.
159 std::string Punctuation = R"txt(!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~)txt";
160 EXPECT_EQ(dontEscape(Punctuation), Punctuation);
161
162 // Inline code
163 EXPECT_THAT(dontEscape("`foo`"), escapedNone());
164 EXPECT_THAT(dontEscape("`foo"), escapedNone());
165 EXPECT_THAT(dontEscape("foo`"), escapedNone());
166 EXPECT_THAT(dontEscape("``foo``"), escapedNone());
167 // Code blocks
168 EXPECT_THAT(dontEscape("```"), escapedNone());
169 EXPECT_THAT(dontEscape("~~~"), escapedNone());
170
171 // Rulers and headings
172 EXPECT_THAT(dontEscape("## Heading"), escapedNone());
173 EXPECT_THAT(dontEscape("Foo # bar"), escapedNone());
174 EXPECT_THAT(dontEscape("---"), escapedNone());
175 EXPECT_THAT(dontEscape("-"), escapedNone());
176 EXPECT_THAT(dontEscape("==="), escapedNone());
177 EXPECT_THAT(dontEscape("="), escapedNone());
178 EXPECT_THAT(dontEscape("***"), escapedNone()); // \** could start emphasis!
179
180 // HTML tags.
181 EXPECT_THAT(dontEscape("<pre"), escaped('<'));
182 EXPECT_THAT(dontEscape("< pre"), escapedNone());
183 EXPECT_THAT(dontEscape("if a<b then"), escaped('<'));
184 EXPECT_THAT(dontEscape("if a<b then c."), escapedNone());
185 EXPECT_THAT(dontEscape("if a<b then c='foo'."), escaped('<'));
186 EXPECT_THAT(dontEscape("std::vector<T>"), escaped('<'));
187 EXPECT_THAT(dontEscape("std::vector<std::string>"), escaped('<'));
188 EXPECT_THAT(dontEscape("std::map<int, int>"), escapedNone());
189 // Autolinks
190 EXPECT_THAT(dontEscape("Email <foo@bar.com>"), escapedNone());
191 EXPECT_THAT(dontEscape("Website <http://foo.bar>"), escapedNone());
192
193 // Bullet lists.
194 EXPECT_THAT(dontEscape("- foo"), escapedNone());
195 EXPECT_THAT(dontEscape("* foo"), escapedNone());
196 EXPECT_THAT(dontEscape("+ foo"), escapedNone());
197 EXPECT_THAT(dontEscape("+"), escapedNone());
198 EXPECT_THAT(dontEscape("a + foo"), escapedNone());
199 EXPECT_THAT(dontEscape("a+ foo"), escapedNone());
200 EXPECT_THAT(dontEscape("1. foo"), escapedNone());
201 EXPECT_THAT(dontEscape("a. foo"), escapedNone());
202
203 // Emphasis.
204 EXPECT_THAT(dontEscape("*foo*"), escapedNone());
205 EXPECT_THAT(dontEscape("**foo**"), escapedNone());
206 EXPECT_THAT(dontEscape("*foo"), escapedNone());
207 EXPECT_THAT(dontEscape("foo *"), escapedNone());
208 EXPECT_THAT(dontEscape("foo * bar"), escapedNone());
209 EXPECT_THAT(dontEscape("foo_bar"), escapedNone());
210 EXPECT_THAT(dontEscape("foo _bar"), escapedNone());
211 EXPECT_THAT(dontEscape("foo_ bar"), escapedNone());
212 EXPECT_THAT(dontEscape("foo _ bar"), escapedNone());
213
214 // HTML entities.
215 EXPECT_THAT(dontEscape("fish &chips;"), escaped('&'));
216 EXPECT_THAT(dontEscape("fish & chips;"), escapedNone());
217 EXPECT_THAT(dontEscape("fish &chips"), escapedNone());
218 EXPECT_THAT(dontEscape("foo &#42; bar"), escaped('&'));
219 EXPECT_THAT(dontEscape("foo &#xaf; bar"), escaped('&'));
220 EXPECT_THAT(dontEscape("foo &?; bar"), escapedNone());
221
222 // Links.
223 EXPECT_THAT(dontEscape("[foo](bar)"), escapedNone());
224 EXPECT_THAT(dontEscape("[foo]: bar"), escapedNone());
225 // No need to escape these, as the target never exists.
226 EXPECT_THAT(dontEscape("[foo][]"), escapedNone());
227 EXPECT_THAT(dontEscape("[foo][bar]"), escapedNone());
228 EXPECT_THAT(dontEscape("[foo]"), escapedNone());
229
230 // In code blocks we don't need to escape ASCII punctuation.
232 P.appendCode("* foo !+ bar * baz");
233 EXPECT_EQ(P.asMarkdown(), "`* foo !+ bar * baz`");
234
235 // But we have to escape the backticks.
236 P = Paragraph();
237 P.appendCode("foo`bar`baz", /*Preserve=*/true);
238 EXPECT_EQ(P.asMarkdown(), "`foo``bar``baz`");
239
240 // Inline code blocks starting or ending with backticks should add spaces.
241 P = Paragraph();
242 P.appendCode("`foo");
243 EXPECT_EQ(P.asMarkdown(), "` ``foo `");
244 P = Paragraph();
245 P.appendCode("foo`");
246 EXPECT_EQ(P.asMarkdown(), "` foo`` `");
247 P = Paragraph();
248 P.appendCode("`foo`");
249 EXPECT_EQ(P.asMarkdown(), "` ``foo`` `");
250
251 // Code blocks might need more than 3 backticks.
252 Document D;
253 D.addCodeBlock("foobarbaz `\nqux");
254 EXPECT_EQ(D.asMarkdown(), "```cpp\n"
255 "foobarbaz `\nqux\n"
256 "```");
257 D = Document();
258 D.addCodeBlock("foobarbaz ``\nqux");
259 EXPECT_THAT(D.asMarkdown(), "```cpp\n"
260 "foobarbaz ``\nqux\n"
261 "```");
262 D = Document();
263 D.addCodeBlock("foobarbaz ```\nqux");
264 EXPECT_EQ(D.asMarkdown(), "````cpp\n"
265 "foobarbaz ```\nqux\n"
266 "````");
267 D = Document();
268 D.addCodeBlock("foobarbaz ` `` ``` ```` `\nqux");
269 EXPECT_EQ(D.asMarkdown(), "`````cpp\n"
270 "foobarbaz ` `` ``` ```` `\nqux\n"
271 "`````");
272}
273
274TEST(Paragraph, SeparationOfChunks) {
275 // This test keeps appending contents to a single Paragraph and checks
276 // expected accumulated contents after each one.
277 // Purpose is to check for separation between different chunks.
278 Paragraph P;
279
280 P.appendText("after ");
281 EXPECT_EQ(P.asEscapedMarkdown(), "after");
282 EXPECT_EQ(P.asMarkdown(), "after");
283 EXPECT_EQ(P.asPlainText(), "after");
284
285 P.appendCode("foobar").appendSpace();
286 EXPECT_EQ(P.asEscapedMarkdown(), "after `foobar`");
287 EXPECT_EQ(P.asMarkdown(), "after `foobar`");
288 EXPECT_EQ(P.asPlainText(), "after foobar");
289
290 P.appendText("bat");
291 EXPECT_EQ(P.asEscapedMarkdown(), "after `foobar` bat");
292 EXPECT_EQ(P.asMarkdown(), "after `foobar` bat");
293 EXPECT_EQ(P.asPlainText(), "after foobar bat");
294
295 P.appendCode("no").appendCode("space");
296 EXPECT_EQ(P.asEscapedMarkdown(), "after `foobar` bat`no` `space`");
297 EXPECT_EQ(P.asMarkdown(), "after `foobar` bat`no` `space`");
298 EXPECT_EQ(P.asPlainText(), "after foobar batno space");
299
300 P.appendText(" text");
301 EXPECT_EQ(P.asEscapedMarkdown(), "after `foobar` bat`no` `space` text");
302 EXPECT_EQ(P.asMarkdown(), "after `foobar` bat`no` `space` text");
303 EXPECT_EQ(P.asPlainText(), "after foobar batno space text");
304
305 P.appendSpace().appendCode("code").appendText(".\n newline");
306 EXPECT_EQ(P.asEscapedMarkdown(),
307 "after `foobar` bat`no` `space` text `code`. \n newline");
308 EXPECT_EQ(P.asMarkdown(),
309 "after `foobar` bat`no` `space` text `code`. \n newline");
310 EXPECT_EQ(P.asPlainText(), "after foobar batno space text code.\nnewline");
311}
312
313TEST(Paragraph, SeparationOfChunks2) {
314 // This test keeps appending contents to a single Paragraph and checks
315 // expected accumulated contents after each one.
316 // Purpose is to check for separation between different chunks
317 // where the spacing is in the appended string rather set by appendSpace.
318 Paragraph P;
319
320 P.appendText("after ");
321 EXPECT_EQ(P.asEscapedMarkdown(), "after");
322 EXPECT_EQ(P.asMarkdown(), "after");
323 EXPECT_EQ(P.asPlainText(), "after");
324
325 P.appendText("foobar");
326 EXPECT_EQ(P.asEscapedMarkdown(), "after foobar");
327 EXPECT_EQ(P.asMarkdown(), "after foobar");
328 EXPECT_EQ(P.asPlainText(), "after foobar");
329
330 P.appendText(" bat");
331 EXPECT_EQ(P.asEscapedMarkdown(), "after foobar bat");
332 EXPECT_EQ(P.asMarkdown(), "after foobar bat");
333 EXPECT_EQ(P.asPlainText(), "after foobar bat");
334
335 P.appendText("baz");
336 EXPECT_EQ(P.asEscapedMarkdown(), "after foobar batbaz");
337 EXPECT_EQ(P.asMarkdown(), "after foobar batbaz");
338 EXPECT_EQ(P.asPlainText(), "after foobar batbaz");
339
340 P.appendText(" faz ");
341 EXPECT_EQ(P.asEscapedMarkdown(), "after foobar batbaz faz");
342 EXPECT_EQ(P.asMarkdown(), "after foobar batbaz faz");
343 EXPECT_EQ(P.asPlainText(), "after foobar batbaz faz");
344
345 P.appendText(" bar ");
346 EXPECT_EQ(P.asEscapedMarkdown(), "after foobar batbaz faz bar");
347 EXPECT_EQ(P.asMarkdown(), "after foobar batbaz faz bar");
348 EXPECT_EQ(P.asPlainText(), "after foobar batbaz faz bar");
349
350 P.appendText("qux");
351 EXPECT_EQ(P.asEscapedMarkdown(), "after foobar batbaz faz bar qux");
352 EXPECT_EQ(P.asMarkdown(), "after foobar batbaz faz bar qux");
353 EXPECT_EQ(P.asPlainText(), "after foobar batbaz faz bar qux");
354}
355
356TEST(Paragraph, SeparationOfChunks3) {
357 // This test keeps appending contents to a single Paragraph and checks
358 // expected accumulated contents after each one.
359 // Purpose is to check for separation between different chunks
360 // where the spacing is in the appended string rather set by appendSpace.
361 Paragraph P;
362
363 P.appendText("after \n");
364 EXPECT_EQ(P.asEscapedMarkdown(), "after");
365 EXPECT_EQ(P.asMarkdown(), "after");
366 EXPECT_EQ(P.asPlainText(), "after");
367
368 P.appendText(" foobar\n");
369 EXPECT_EQ(P.asEscapedMarkdown(), "after \n foobar");
370 EXPECT_EQ(P.asMarkdown(), "after \n foobar");
371 EXPECT_EQ(P.asPlainText(), "after\nfoobar");
372
373 P.appendText("- bat\n");
374 EXPECT_EQ(P.asEscapedMarkdown(), "after \n foobar \n\\- bat");
375 EXPECT_EQ(P.asMarkdown(), "after \n foobar\n- bat");
376 EXPECT_EQ(P.asPlainText(), "after\nfoobar\n- bat");
377
378 P.appendText("- baz");
379 EXPECT_EQ(P.asEscapedMarkdown(), "after \n foobar \n\\- bat \n\\- baz");
380 EXPECT_EQ(P.asMarkdown(), "after \n foobar\n- bat\n- baz");
381 EXPECT_EQ(P.asPlainText(), "after\nfoobar\n- bat\n- baz");
382
383 P.appendText(" faz ");
384 EXPECT_EQ(P.asEscapedMarkdown(),
385 "after \n foobar \n\\- bat \n\\- baz faz");
386 EXPECT_EQ(P.asMarkdown(), "after \n foobar\n- bat\n- baz faz");
387 EXPECT_EQ(P.asPlainText(), "after\nfoobar\n- bat\n- baz faz");
388}
389
390TEST(Paragraph, PunctuationLineBreaks) {
391
392 struct {
393 std::string Text;
394 std::string EscapedMarkdown;
395 std::string Markdown;
396 std::string PlainText;
397 } Cases[] = {
398 {"Line ending with dot.\nForces a visual linebreak.",
399 "Line ending with dot. \nForces a visual linebreak.",
400 "Line ending with dot. \nForces a visual linebreak.",
401 "Line ending with dot.\nForces a visual linebreak."},
402 {"Line ending with colon:\nForces a visual linebreak.",
403 "Line ending with colon: \nForces a visual linebreak.",
404 "Line ending with colon: \nForces a visual linebreak.",
405 "Line ending with colon:\nForces a visual linebreak."},
406 {"Line ending with semicolon:\nForces a visual linebreak.",
407 "Line ending with semicolon: \nForces a visual linebreak.",
408 "Line ending with semicolon: \nForces a visual linebreak.",
409 "Line ending with semicolon:\nForces a visual linebreak."},
410 {"Line ending with comma,\nForces a visual linebreak.",
411 "Line ending with comma, \nForces a visual linebreak.",
412 "Line ending with comma, \nForces a visual linebreak.",
413 "Line ending with comma,\nForces a visual linebreak."},
414 {"Line ending with exclamation mark!\nForces a visual linebreak.",
415 "Line ending with exclamation mark! \nForces a visual linebreak.",
416 "Line ending with exclamation mark! \nForces a visual linebreak.",
417 "Line ending with exclamation mark!\nForces a visual linebreak."},
418 {"Line ending with question mark?\nForces a visual linebreak.",
419 "Line ending with question mark? \nForces a visual linebreak.",
420 "Line ending with question mark? \nForces a visual linebreak.",
421 "Line ending with question mark?\nForces a visual linebreak."},
422 };
423
424 for (const auto &C : Cases) {
425 Paragraph P;
426 P.appendText(C.Text);
427 EXPECT_EQ(P.asEscapedMarkdown(), C.EscapedMarkdown);
428 EXPECT_EQ(P.asMarkdown(), C.Markdown);
429 EXPECT_EQ(P.asPlainText(), C.PlainText);
430 }
431}
432
433TEST(Paragraph, LineBreakIndicators) {
434
435 struct {
436 std::string Text;
437 std::string EscapedMarkdown;
438 std::string Markdown;
439 std::string PlainText;
440 } Cases[] = {
441 {"Visual linebreak for\n- list items\n- and so on",
442 "Visual linebreak for \n\\- list items \n\\- and so on",
443 "Visual linebreak for\n- list items\n- and so on",
444 "Visual linebreak for\n- list items\n- and so on"},
445 {"Visual linebreak for\n* list items\n* and so on",
446 "Visual linebreak for \n\\* list items \n\\* and so on",
447 "Visual linebreak for\n* list items\n* and so on",
448 "Visual linebreak for\n* list items\n* and so on"},
449 {"Visual linebreak for\n@command any doxygen command\n\\other other "
450 "doxygen command",
451 "Visual linebreak for \n@command any doxygen command \n\\\\other "
452 "other doxygen command",
453 "Visual linebreak for \n@command any doxygen command \n\\other other "
454 "doxygen command",
455 "Visual linebreak for\n@command any doxygen command\n\\other other "
456 "doxygen command"},
457 {"Visual linebreak for\n>blockquoute line 1\n> blockquoute line 2",
458 "Visual linebreak for \n\\>blockquoute line 1 \n\\> blockquoute line "
459 "2",
460 "Visual linebreak for\n>blockquoute line 1\n> blockquoute line 2",
461 "Visual linebreak for\n>blockquoute line 1\n> blockquoute line 2"},
462 {"Visual linebreak for\n# Heading 1\ntext under heading\n## Heading "
463 "2\ntext under heading 2",
464 "Visual linebreak for \n\\# Heading 1\ntext under heading \n\\## "
465 "Heading 2\ntext under heading 2",
466 "Visual linebreak for\n# Heading 1\ntext under heading\n## Heading "
467 "2\ntext under heading 2",
468 "Visual linebreak for\n# Heading 1 text under heading\n## Heading 2 "
469 "text under heading 2"},
470 {"Visual linebreak for\n`inline code`",
471 "Visual linebreak for \n\\`inline code\\`",
472 "Visual linebreak for\n`inline code`",
473 "Visual linebreak for\n`inline code`"},
474 };
475
476 for (const auto &C : Cases) {
477 Paragraph P;
478 P.appendText(C.Text);
479 EXPECT_EQ(P.asEscapedMarkdown(), C.EscapedMarkdown);
480 EXPECT_EQ(P.asMarkdown(), C.Markdown);
481 EXPECT_EQ(P.asPlainText(), C.PlainText);
482 }
483}
484
485TEST(Paragraph, ExtraSpaces) {
486 // Make sure spaces inside chunks are preserved for markdown
487 // and dropped for plain text.
488 Paragraph P;
489 P.appendText("foo\n \t baz");
490 P.appendCode(" bar\n");
491 EXPECT_EQ(P.asEscapedMarkdown(), "foo\n \t baz`bar`");
492 EXPECT_EQ(P.asMarkdown(), "foo\n \t baz`bar`");
493 EXPECT_EQ(P.asPlainText(), "foo bazbar");
494}
495
496TEST(Paragraph, SpacesCollapsed) {
497 Paragraph P;
498 P.appendText(" foo bar ");
499 P.appendText(" baz ");
500 EXPECT_EQ(P.asEscapedMarkdown(), "foo bar baz");
501 EXPECT_EQ(P.asMarkdown(), "foo bar baz");
502 EXPECT_EQ(P.asPlainText(), "foo bar baz");
503}
504
505TEST(Paragraph, NewLines) {
506 // New lines before and after chunks are dropped.
507 Paragraph P;
508 P.appendText(" \n foo\nbar\n ");
509 P.appendCode(" \n foo\nbar \n ");
510 EXPECT_EQ(P.asEscapedMarkdown(), "foo\nbar\n `foo bar`");
511 EXPECT_EQ(P.asMarkdown(), "foo\nbar\n `foo bar`");
512 EXPECT_EQ(P.asPlainText(), "foo bar foo bar");
513}
514
515TEST(Paragraph, BoldText) {
516 Paragraph P;
517 P.appendBoldText("");
518 EXPECT_EQ(P.asEscapedMarkdown(), "");
519 EXPECT_EQ(P.asMarkdown(), "");
520 EXPECT_EQ(P.asPlainText(), "");
521
522 P.appendBoldText(" \n foo\nbar\n ");
523 EXPECT_EQ(P.asEscapedMarkdown(), "\\*\\*foo bar\\*\\*");
524 EXPECT_EQ(P.asMarkdown(), "**foo bar**");
525 EXPECT_EQ(P.asPlainText(), "**foo bar**");
526
527 P.appendSpace().appendBoldText("foobar");
528 EXPECT_EQ(P.asEscapedMarkdown(), "\\*\\*foo bar\\*\\* \\*\\*foobar\\*\\*");
529 EXPECT_EQ(P.asMarkdown(), "**foo bar** **foobar**");
530 EXPECT_EQ(P.asPlainText(), "**foo bar** **foobar**");
531}
532
533TEST(Paragraph, EmphasizedText) {
534 Paragraph P;
535 P.appendEmphasizedText("");
536 EXPECT_EQ(P.asEscapedMarkdown(), "");
537 EXPECT_EQ(P.asMarkdown(), "");
538 EXPECT_EQ(P.asPlainText(), "");
539
540 P.appendEmphasizedText(" \n foo\nbar\n ");
541 EXPECT_EQ(P.asEscapedMarkdown(), "\\*foo bar\\*");
542 EXPECT_EQ(P.asMarkdown(), "*foo bar*");
543 EXPECT_EQ(P.asPlainText(), "*foo bar*");
544
545 P.appendSpace().appendEmphasizedText("foobar");
546 EXPECT_EQ(P.asEscapedMarkdown(), "\\*foo bar\\* \\*foobar\\*");
547 EXPECT_EQ(P.asMarkdown(), "*foo bar* *foobar*");
548 EXPECT_EQ(P.asPlainText(), "*foo bar* *foobar*");
549}
550
551TEST(Document, Separators) {
552 Document D;
553 D.addParagraph().appendText("foo");
554 D.addCodeBlock("test");
555 D.addParagraph().appendText("bar");
556
557 const char ExpectedMarkdown[] = R"md(foo
558
559```cpp
560test
561```
562
563bar)md";
564 EXPECT_EQ(D.asEscapedMarkdown(), ExpectedMarkdown);
565 EXPECT_EQ(D.asMarkdown(), ExpectedMarkdown);
566
567 const char ExpectedText[] = R"pt(foo
568
569test
570
571bar)pt";
572 EXPECT_EQ(D.asPlainText(), ExpectedText);
573}
574
575TEST(Document, Ruler) {
576 Document D;
577 D.addParagraph().appendText("foo");
578 D.addRuler();
579
580 // Ruler followed by paragraph.
581 D.addParagraph().appendText("bar");
582 EXPECT_EQ(D.asEscapedMarkdown(), "foo\n\n---\nbar");
583 EXPECT_EQ(D.asMarkdown(), "foo\n\n---\nbar");
584 EXPECT_EQ(D.asPlainText(), "foo\n\nbar");
585
586 D = Document();
587 D.addParagraph().appendText("foo");
588 D.addRuler();
589 D.addCodeBlock("bar");
590 // Ruler followed by a codeblock.
591 EXPECT_EQ(D.asEscapedMarkdown(), "foo\n\n---\n```cpp\nbar\n```");
592 EXPECT_EQ(D.asMarkdown(), "foo\n\n---\n```cpp\nbar\n```");
593 EXPECT_EQ(D.asPlainText(), "foo\n\nbar");
594
595 // Ruler followed by another ruler
596 D = Document();
597 D.addParagraph().appendText("foo");
598 D.addRuler();
599 D.addRuler();
600 EXPECT_EQ(D.asEscapedMarkdown(), "foo");
601 EXPECT_EQ(D.asMarkdown(), "foo");
602 EXPECT_EQ(D.asPlainText(), "foo");
603
604 // Multiple rulers between blocks
605 D.addRuler();
606 D.addParagraph().appendText("foo");
607 EXPECT_EQ(D.asEscapedMarkdown(), "foo\n\n---\nfoo");
608 EXPECT_EQ(D.asMarkdown(), "foo\n\n---\nfoo");
609 EXPECT_EQ(D.asPlainText(), "foo\n\nfoo");
610}
611
612TEST(Document, Append) {
613 Document D;
614 D.addParagraph().appendText("foo");
615 D.addRuler();
616 Document E;
617 E.addRuler();
618 E.addParagraph().appendText("bar");
619 D.append(std::move(E));
620 EXPECT_EQ(D.asEscapedMarkdown(), "foo\n\n---\nbar");
621 EXPECT_EQ(D.asMarkdown(), "foo\n\n---\nbar");
622}
623
624TEST(Document, Heading) {
625 Document D;
626 D.addHeading(1).appendText("foo");
627 D.addHeading(2).appendText("bar");
628 D.addParagraph().appendText("baz");
629 EXPECT_EQ(D.asEscapedMarkdown(), "# foo\n\n## bar\n\nbaz");
630 EXPECT_EQ(D.asMarkdown(), "# foo\n\n## bar\n\nbaz");
631 EXPECT_EQ(D.asPlainText(), "foo\n\nbar\n\nbaz");
632}
633
634TEST(CodeBlock, Render) {
635 Document D;
636 // Code blocks preserves any extra spaces.
637 D.addCodeBlock("foo\n bar\n baz");
638
639 llvm::StringRef ExpectedMarkdown =
640 R"md(```cpp
641foo
642 bar
643 baz
644```)md";
645 llvm::StringRef ExpectedPlainText =
646 R"pt(foo
647 bar
648 baz)pt";
649 EXPECT_EQ(D.asEscapedMarkdown(), ExpectedMarkdown);
650 EXPECT_EQ(D.asMarkdown(), ExpectedMarkdown);
651 EXPECT_EQ(D.asPlainText(), ExpectedPlainText);
652 D.addCodeBlock("foo");
653 ExpectedMarkdown =
654 R"md(```cpp
655foo
656 bar
657 baz
658```
659
660```cpp
661foo
662```)md";
663 EXPECT_EQ(D.asEscapedMarkdown(), ExpectedMarkdown);
664 EXPECT_EQ(D.asMarkdown(), ExpectedMarkdown);
665 ExpectedPlainText =
666 R"pt(foo
667 bar
668 baz
669
670foo)pt";
671 EXPECT_EQ(D.asPlainText(), ExpectedPlainText);
672
673 Document D2;
674 D2.addCodeBlock("");
675 EXPECT_EQ(D2.asEscapedMarkdown(), "```cpp\n```");
676 EXPECT_EQ(D2.asMarkdown(), "```cpp\n```");
677 EXPECT_EQ(D2.asPlainText(), "");
678}
679
680TEST(BulletList, Render) {
681 BulletList L;
682 // Flat list
683 L.addItem().addParagraph().appendText("foo");
684 EXPECT_EQ(L.asEscapedMarkdown(), "- foo");
685 EXPECT_EQ(L.asMarkdown(), "- foo");
686 EXPECT_EQ(L.asPlainText(), "- foo");
687
688 L.addItem().addParagraph().appendText("bar");
689 llvm::StringRef Expected = R"md(- foo
690- bar)md";
691 EXPECT_EQ(L.asEscapedMarkdown(), Expected);
692 EXPECT_EQ(L.asMarkdown(), Expected);
693 EXPECT_EQ(L.asPlainText(), Expected);
694
695 // Nested list, with a single item.
696 Document &D = L.addItem();
697 // First item with 2 paragraphs - foo\n\n baz
698 D.addParagraph().appendText("foo");
699 D.addParagraph().appendText("baz");
700
701 // Nest one level.
702 Document &Inner = D.addBulletList().addItem();
703 Inner.addParagraph().appendText("foo");
704
705 // Nest one more level.
706 BulletList &InnerList = Inner.addBulletList();
707 // Single item, baz\nbaz
708 Document &DeepDoc = InnerList.addItem();
709 DeepDoc.addParagraph().appendText("baz");
710 DeepDoc.addParagraph().appendText("baz");
711 StringRef ExpectedMarkdown = R"md(- foo
712- bar
713- foo
714
715 baz
716
717 - foo
718
719 - baz
720
721 baz)md";
722 EXPECT_EQ(L.asEscapedMarkdown(), ExpectedMarkdown);
723 EXPECT_EQ(L.asMarkdown(), ExpectedMarkdown);
724 StringRef ExpectedPlainText = R"pt(- foo
725- bar
726- foo
727
728 baz
729
730 - foo
731
732 - baz
733
734 baz)pt";
735 EXPECT_EQ(L.asPlainText(), ExpectedPlainText);
736
737 // Termination
738 Inner.addParagraph().appendText("after");
739 ExpectedMarkdown = R"md(- foo
740- bar
741- foo
742
743 baz
744
745 - foo
746
747 - baz
748
749 baz
750
751 after)md";
752 EXPECT_EQ(L.asEscapedMarkdown(), ExpectedMarkdown);
753 EXPECT_EQ(L.asMarkdown(), ExpectedMarkdown);
754 ExpectedPlainText = R"pt(- foo
755- bar
756- foo
757
758 baz
759
760 - foo
761
762 - baz
763
764 baz
765
766 after)pt";
767 EXPECT_EQ(L.asPlainText(), ExpectedPlainText);
768}
769
770} // namespace
771} // namespace markup
772} // namespace clangd
773} // namespace clang
Represents parts of the markup that can contain strings, like inline code, code block or plain text.
Definition Markup.h:45
std::string asMarkdown() const
Doesn't contain any trailing newlines.
Paragraph & appendText(llvm::StringRef Text)
Append plain text to the end of the string.
Definition Markup.cpp:761
std::string asEscapedMarkdown() const
Doesn't contain any trailing newlines and escaped markdown syntax.
FIXME: Skip testing on windows temporarily due to the different escaping code mode.
Definition AST.cpp:45
MATCHER_P(named, N, "")
TEST(BackgroundQueueTest, Priority)
cppcoreguidelines::ProBoundsAvoidUncheckedContainerAccessCheck P
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//