brintos

brintos / llvm-project-archived public Read only

0
0
Text · 25.9 KiB · af4782c Raw
774 lines · cpp
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-exception6//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) {20  return Paragraph().appendText(Text.str()).asEscapedMarkdown();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 code44  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 blocks49  EXPECT_EQ(escape("```"), R"(\`\`\`)"); // This could also be inline code!50  EXPECT_EQ(escape("~~~"), R"(\~~~)");51 52  // Rulers and headings53  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  // Autolinks71  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.112  Paragraph P = Paragraph();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 code163  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 blocks168  EXPECT_THAT(dontEscape("```"), escapedNone());169  EXPECT_THAT(dontEscape("~~~"), escapedNone());170 171  // Rulers and headings172  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  // Autolinks190  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.231  Paragraph P = Paragraph();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 checks276  // 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 checks315  // expected accumulated contents after each one.316  // Purpose is to check for separation between different chunks317  // 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 checks358  // expected accumulated contents after each one.359  // Purpose is to check for separation between different chunks360  // 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 markdown487  // 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(foo558 559```cpp560test561```562 563bar)md";564  EXPECT_EQ(D.asEscapedMarkdown(), ExpectedMarkdown);565  EXPECT_EQ(D.asMarkdown(), ExpectedMarkdown);566 567  const char ExpectedText[] = R"pt(foo568 569test570 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 ruler596  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 blocks605  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(```cpp641foo642  bar643  baz644```)md";645  llvm::StringRef ExpectedPlainText =646      R"pt(foo647  bar648  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(```cpp655foo656  bar657  baz658```659 660```cpp661foo662```)md";663  EXPECT_EQ(D.asEscapedMarkdown(), ExpectedMarkdown);664  EXPECT_EQ(D.asMarkdown(), ExpectedMarkdown);665  ExpectedPlainText =666      R"pt(foo667  bar668  baz669 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 list683  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(- foo690- 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  baz698  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\nbaz708  Document &DeepDoc = InnerList.addItem();709  DeepDoc.addParagraph().appendText("baz");710  DeepDoc.addParagraph().appendText("baz");711  StringRef ExpectedMarkdown = R"md(- foo712- bar713- foo714 715  baz716 717  - foo718 719    - baz720 721      baz)md";722  EXPECT_EQ(L.asEscapedMarkdown(), ExpectedMarkdown);723  EXPECT_EQ(L.asMarkdown(), ExpectedMarkdown);724  StringRef ExpectedPlainText = R"pt(- foo725- bar726- foo727 728  baz729 730  - foo731 732    - baz733 734      baz)pt";735  EXPECT_EQ(L.asPlainText(), ExpectedPlainText);736 737  // Termination738  Inner.addParagraph().appendText("after");739  ExpectedMarkdown = R"md(- foo740- bar741- foo742 743  baz744 745  - foo746 747    - baz748 749      baz750 751    after)md";752  EXPECT_EQ(L.asEscapedMarkdown(), ExpectedMarkdown);753  EXPECT_EQ(L.asMarkdown(), ExpectedMarkdown);754  ExpectedPlainText = R"pt(- foo755- bar756- foo757 758  baz759 760  - foo761 762    - baz763 764      baz765 766    after)pt";767  EXPECT_EQ(L.asPlainText(), ExpectedPlainText);768}769 770} // namespace771} // namespace markup772} // namespace clangd773} // namespace clang774