| //===-- FormattedStringTests.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 "FormattedString.h" |
| #include "clang/Basic/LLVM.h" |
| #include "llvm/ADT/StringRef.h" |
| |
| #include "gmock/gmock.h" |
| #include "gtest/gtest.h" |
| |
| namespace clang { |
| namespace clangd { |
| namespace { |
| |
| TEST(FormattedString, Basic) { |
| FormattedString S; |
| EXPECT_EQ(S.renderAsPlainText(), ""); |
| EXPECT_EQ(S.renderAsMarkdown(), ""); |
| |
| S.appendText("foobar "); |
| S.appendText("baz"); |
| EXPECT_EQ(S.renderAsPlainText(), "foobar baz"); |
| EXPECT_EQ(S.renderAsMarkdown(), "foobar baz"); |
| |
| S = FormattedString(); |
| S.appendInlineCode("foobar"); |
| EXPECT_EQ(S.renderAsPlainText(), "foobar"); |
| EXPECT_EQ(S.renderAsMarkdown(), "`foobar`"); |
| |
| S = FormattedString(); |
| S.appendCodeBlock("foobar"); |
| EXPECT_EQ(S.renderAsPlainText(), "foobar"); |
| EXPECT_EQ(S.renderAsMarkdown(), "```cpp\n" |
| "foobar\n" |
| "```\n"); |
| } |
| |
| TEST(FormattedString, CodeBlocks) { |
| FormattedString S; |
| S.appendCodeBlock("foobar"); |
| S.appendCodeBlock("bazqux", "javascript"); |
| S.appendText("after"); |
| |
| std::string ExpectedText = R"(foobar |
| |
| bazqux |
| |
| after)"; |
| EXPECT_EQ(S.renderAsPlainText(), ExpectedText); |
| std::string ExpectedMarkdown = R"md(```cpp |
| foobar |
| ``` |
| ```javascript |
| bazqux |
| ``` |
| after)md"; |
| EXPECT_EQ(S.renderAsMarkdown(), ExpectedMarkdown); |
| |
| S = FormattedString(); |
| S.appendInlineCode("foobar"); |
| S.appendInlineCode("bazqux"); |
| EXPECT_EQ(S.renderAsPlainText(), "foobar bazqux"); |
| EXPECT_EQ(S.renderAsMarkdown(), "`foobar` `bazqux`"); |
| |
| S = FormattedString(); |
| S.appendText("foo"); |
| S.appendInlineCode("bar"); |
| S.appendText("baz"); |
| |
| EXPECT_EQ(S.renderAsPlainText(), "foo bar baz"); |
| EXPECT_EQ(S.renderAsMarkdown(), "foo `bar` baz"); |
| } |
| |
| TEST(FormattedString, Escaping) { |
| // Check some ASCII punctuation |
| FormattedString S; |
| S.appendText("*!`"); |
| EXPECT_EQ(S.renderAsMarkdown(), "\\*\\!\\`"); |
| |
| // Check all ASCII punctuation. |
| S = FormattedString(); |
| std::string Punctuation = R"txt(!"#$%&'()*+,-./:;<=>?@[\]^_`{|}~)txt"; |
| // Same text, with each character escaped. |
| std::string EscapedPunctuation; |
| EscapedPunctuation.reserve(2 * Punctuation.size()); |
| for (char C : Punctuation) |
| EscapedPunctuation += std::string("\\") + C; |
| S.appendText(Punctuation); |
| EXPECT_EQ(S.renderAsMarkdown(), EscapedPunctuation); |
| |
| // In code blocks we don't need to escape ASCII punctuation. |
| S = FormattedString(); |
| S.appendInlineCode("* foo !+ bar * baz"); |
| EXPECT_EQ(S.renderAsMarkdown(), "`* foo !+ bar * baz`"); |
| S = FormattedString(); |
| S.appendCodeBlock("#define FOO\n* foo !+ bar * baz"); |
| EXPECT_EQ(S.renderAsMarkdown(), "```cpp\n" |
| "#define FOO\n* foo !+ bar * baz\n" |
| "```\n"); |
| |
| // But we have to escape the backticks. |
| S = FormattedString(); |
| S.appendInlineCode("foo`bar`baz"); |
| EXPECT_EQ(S.renderAsMarkdown(), "`foo``bar``baz`"); |
| |
| S = FormattedString(); |
| S.appendCodeBlock("foo`bar`baz"); |
| EXPECT_EQ(S.renderAsMarkdown(), "```cpp\n" |
| "foo`bar`baz\n" |
| "```\n"); |
| |
| // Inline code blocks starting or ending with backticks should add spaces. |
| S = FormattedString(); |
| S.appendInlineCode("`foo"); |
| EXPECT_EQ(S.renderAsMarkdown(), "` ``foo `"); |
| S = FormattedString(); |
| S.appendInlineCode("foo`"); |
| EXPECT_EQ(S.renderAsMarkdown(), "` foo`` `"); |
| S = FormattedString(); |
| S.appendInlineCode("`foo`"); |
| EXPECT_EQ(S.renderAsMarkdown(), "` ``foo`` `"); |
| |
| // Should also add extra spaces if the block stars and ends with spaces. |
| S = FormattedString(); |
| S.appendInlineCode(" foo "); |
| EXPECT_EQ(S.renderAsMarkdown(), "` foo `"); |
| S = FormattedString(); |
| S.appendInlineCode("foo "); |
| EXPECT_EQ(S.renderAsMarkdown(), "`foo `"); |
| S = FormattedString(); |
| S.appendInlineCode(" foo"); |
| EXPECT_EQ(S.renderAsMarkdown(), "` foo`"); |
| |
| // Code blocks might need more than 3 backticks. |
| S = FormattedString(); |
| S.appendCodeBlock("foobarbaz `\nqux"); |
| EXPECT_EQ(S.renderAsMarkdown(), "```cpp\n" |
| "foobarbaz `\nqux\n" |
| "```\n"); |
| S = FormattedString(); |
| S.appendCodeBlock("foobarbaz ``\nqux"); |
| EXPECT_EQ(S.renderAsMarkdown(), "```cpp\n" |
| "foobarbaz ``\nqux\n" |
| "```\n"); |
| S = FormattedString(); |
| S.appendCodeBlock("foobarbaz ```\nqux"); |
| EXPECT_EQ(S.renderAsMarkdown(), "````cpp\n" |
| "foobarbaz ```\nqux\n" |
| "````\n"); |
| S = FormattedString(); |
| S.appendCodeBlock("foobarbaz ` `` ``` ```` `\nqux"); |
| EXPECT_EQ(S.renderAsMarkdown(), "`````cpp\n" |
| "foobarbaz ` `` ``` ```` `\nqux\n" |
| "`````\n"); |
| } |
| |
| TEST(FormattedString, MarkdownWhitespace) { |
| // Whitespace should be added as separators between blocks. |
| FormattedString S; |
| S.appendText("foo"); |
| S.appendText("bar"); |
| EXPECT_EQ(S.renderAsMarkdown(), "foo bar"); |
| |
| S = FormattedString(); |
| S.appendInlineCode("foo"); |
| S.appendInlineCode("bar"); |
| EXPECT_EQ(S.renderAsMarkdown(), "`foo` `bar`"); |
| |
| // However, we don't want to add any extra whitespace. |
| S = FormattedString(); |
| S.appendText("foo "); |
| S.appendInlineCode("bar"); |
| EXPECT_EQ(S.renderAsMarkdown(), "foo `bar`"); |
| |
| S = FormattedString(); |
| S.appendText("foo\n"); |
| S.appendInlineCode("bar"); |
| EXPECT_EQ(S.renderAsMarkdown(), "foo\n`bar`"); |
| |
| S = FormattedString(); |
| S.appendInlineCode("foo"); |
| S.appendText(" bar"); |
| EXPECT_EQ(S.renderAsMarkdown(), "`foo` bar"); |
| |
| S = FormattedString(); |
| S.appendText("foo"); |
| S.appendCodeBlock("bar"); |
| S.appendText("baz"); |
| EXPECT_EQ(S.renderAsMarkdown(), "foo\n```cpp\nbar\n```\nbaz"); |
| } |
| |
| |
| } // namespace |
| } // namespace clangd |
| } // namespace clang |