//===-- 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