blob: e8077563df1a0cfed329f7016dc2cb7f6defa3ff [file] [log] [blame]
//===-- 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