291 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			291 lines
		
	
	
		
			7.3 KiB
		
	
	
	
		
			C++
		
	
	
	
//===-- 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 "llvm/Support/raw_ostream.h"
 | 
						|
#include "gmock/gmock.h"
 | 
						|
#include "gtest/gtest.h"
 | 
						|
 | 
						|
namespace clang {
 | 
						|
namespace clangd {
 | 
						|
namespace markup {
 | 
						|
namespace {
 | 
						|
 | 
						|
TEST(Render, Escaping) {
 | 
						|
  // Check some ASCII punctuation
 | 
						|
  Paragraph P;
 | 
						|
  P.appendText("*!`");
 | 
						|
  EXPECT_EQ(P.asMarkdown(), "\\*\\!\\`");
 | 
						|
 | 
						|
  // Check all ASCII punctuation.
 | 
						|
  P = Paragraph();
 | 
						|
  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;
 | 
						|
  P.appendText(Punctuation);
 | 
						|
  EXPECT_EQ(P.asMarkdown(), EscapedPunctuation);
 | 
						|
 | 
						|
  // In code blocks we don't need to escape ASCII punctuation.
 | 
						|
  P = Paragraph();
 | 
						|
  P.appendCode("* foo !+ bar * baz");
 | 
						|
  EXPECT_EQ(P.asMarkdown(), "`* foo !+ bar * baz`");
 | 
						|
 | 
						|
  // But we have to escape the backticks.
 | 
						|
  P = Paragraph();
 | 
						|
  P.appendCode("foo`bar`baz");
 | 
						|
  EXPECT_EQ(P.asMarkdown(), "`foo``bar``baz`");
 | 
						|
 | 
						|
  // Inline code blocks starting or ending with backticks should add spaces.
 | 
						|
  P = Paragraph();
 | 
						|
  P.appendCode("`foo");
 | 
						|
  EXPECT_EQ(P.asMarkdown(), "` ``foo `");
 | 
						|
  P = Paragraph();
 | 
						|
  P.appendCode("foo`");
 | 
						|
  EXPECT_EQ(P.asMarkdown(), "` foo`` `");
 | 
						|
  P = Paragraph();
 | 
						|
  P.appendCode("`foo`");
 | 
						|
  EXPECT_EQ(P.asMarkdown(), "` ``foo`` `");
 | 
						|
 | 
						|
  // Code blocks might need more than 3 backticks.
 | 
						|
  Document D;
 | 
						|
  D.addCodeBlock("foobarbaz `\nqux");
 | 
						|
  EXPECT_EQ(D.asMarkdown(), "```cpp\n"
 | 
						|
                            "foobarbaz `\nqux\n"
 | 
						|
                            "```");
 | 
						|
  D = Document();
 | 
						|
  D.addCodeBlock("foobarbaz ``\nqux");
 | 
						|
  EXPECT_THAT(D.asMarkdown(), "```cpp\n"
 | 
						|
                              "foobarbaz ``\nqux\n"
 | 
						|
                              "```");
 | 
						|
  D = Document();
 | 
						|
  D.addCodeBlock("foobarbaz ```\nqux");
 | 
						|
  EXPECT_EQ(D.asMarkdown(), "````cpp\n"
 | 
						|
                            "foobarbaz ```\nqux\n"
 | 
						|
                            "````");
 | 
						|
  D = Document();
 | 
						|
  D.addCodeBlock("foobarbaz ` `` ``` ```` `\nqux");
 | 
						|
  EXPECT_EQ(D.asMarkdown(), "`````cpp\n"
 | 
						|
                            "foobarbaz ` `` ``` ```` `\nqux\n"
 | 
						|
                            "`````");
 | 
						|
}
 | 
						|
 | 
						|
TEST(Paragraph, SeparationOfChunks) {
 | 
						|
  // This test keeps appending contents to a single Paragraph and checks
 | 
						|
  // expected accumulated contents after each one.
 | 
						|
  // Purpose is to check for separation between different chunks.
 | 
						|
  Paragraph P;
 | 
						|
 | 
						|
  P.appendText("after");
 | 
						|
  EXPECT_EQ(P.asMarkdown(), "after");
 | 
						|
  EXPECT_EQ(P.asPlainText(), "after");
 | 
						|
 | 
						|
  P.appendCode("foobar");
 | 
						|
  EXPECT_EQ(P.asMarkdown(), "after `foobar`");
 | 
						|
  EXPECT_EQ(P.asPlainText(), "after foobar");
 | 
						|
 | 
						|
  P.appendText("bat");
 | 
						|
  EXPECT_EQ(P.asMarkdown(), "after `foobar` bat");
 | 
						|
  EXPECT_EQ(P.asPlainText(), "after foobar bat");
 | 
						|
}
 | 
						|
 | 
						|
TEST(Paragraph, ExtraSpaces) {
 | 
						|
  // Make sure spaces inside chunks are dropped.
 | 
						|
  Paragraph P;
 | 
						|
  P.appendText("foo\n   \t   baz");
 | 
						|
  P.appendCode(" bar\n");
 | 
						|
  EXPECT_EQ(P.asMarkdown(), "foo baz `bar`");
 | 
						|
  EXPECT_EQ(P.asPlainText(), "foo baz bar");
 | 
						|
}
 | 
						|
 | 
						|
TEST(Paragraph, NewLines) {
 | 
						|
  // New lines before and after chunks are dropped.
 | 
						|
  Paragraph P;
 | 
						|
  P.appendText(" \n foo\nbar\n ");
 | 
						|
  P.appendCode(" \n foo\nbar \n ");
 | 
						|
  EXPECT_EQ(P.asMarkdown(), "foo bar `foo bar`");
 | 
						|
  EXPECT_EQ(P.asPlainText(), "foo bar foo bar");
 | 
						|
}
 | 
						|
 | 
						|
TEST(Document, Separators) {
 | 
						|
  Document D;
 | 
						|
  D.addParagraph().appendText("foo");
 | 
						|
  D.addCodeBlock("test");
 | 
						|
  D.addParagraph().appendText("bar");
 | 
						|
 | 
						|
  const char ExpectedMarkdown[] = R"md(foo  
 | 
						|
```cpp
 | 
						|
test
 | 
						|
```
 | 
						|
bar)md";
 | 
						|
  EXPECT_EQ(D.asMarkdown(), ExpectedMarkdown);
 | 
						|
 | 
						|
  const char ExpectedText[] = R"pt(foo
 | 
						|
 | 
						|
test
 | 
						|
 | 
						|
bar)pt";
 | 
						|
  EXPECT_EQ(D.asPlainText(), ExpectedText);
 | 
						|
}
 | 
						|
 | 
						|
TEST(Document, Ruler) {
 | 
						|
  Document D;
 | 
						|
  D.addParagraph().appendText("foo");
 | 
						|
  D.addRuler();
 | 
						|
 | 
						|
  // Ruler followed by paragraph.
 | 
						|
  D.addParagraph().appendText("bar");
 | 
						|
  EXPECT_EQ(D.asMarkdown(), "foo  \n\n---\nbar");
 | 
						|
  EXPECT_EQ(D.asPlainText(), "foo\n\nbar");
 | 
						|
 | 
						|
  D = Document();
 | 
						|
  D.addParagraph().appendText("foo");
 | 
						|
  D.addRuler();
 | 
						|
  D.addCodeBlock("bar");
 | 
						|
  // Ruler followed by a codeblock.
 | 
						|
  EXPECT_EQ(D.asMarkdown(), "foo  \n\n---\n```cpp\nbar\n```");
 | 
						|
  EXPECT_EQ(D.asPlainText(), "foo\n\nbar");
 | 
						|
 | 
						|
  // Ruler followed by another ruler
 | 
						|
  D = Document();
 | 
						|
  D.addParagraph().appendText("foo");
 | 
						|
  D.addRuler();
 | 
						|
  D.addRuler();
 | 
						|
  EXPECT_EQ(D.asMarkdown(), "foo");
 | 
						|
  EXPECT_EQ(D.asPlainText(), "foo");
 | 
						|
 | 
						|
  // Multiple rulers between blocks
 | 
						|
  D.addRuler();
 | 
						|
  D.addParagraph().appendText("foo");
 | 
						|
  EXPECT_EQ(D.asMarkdown(), "foo  \n\n---\nfoo");
 | 
						|
  EXPECT_EQ(D.asPlainText(), "foo\n\nfoo");
 | 
						|
}
 | 
						|
 | 
						|
TEST(Document, Heading) {
 | 
						|
  Document D;
 | 
						|
  D.addHeading(1).appendText("foo");
 | 
						|
  D.addHeading(2).appendText("bar");
 | 
						|
  D.addParagraph().appendText("baz");
 | 
						|
  EXPECT_EQ(D.asMarkdown(), "# foo  \n## bar  \nbaz");
 | 
						|
  EXPECT_EQ(D.asPlainText(), "foo\nbar\nbaz");
 | 
						|
}
 | 
						|
 | 
						|
TEST(CodeBlock, Render) {
 | 
						|
  Document D;
 | 
						|
  // Code blocks preserves any extra spaces.
 | 
						|
  D.addCodeBlock("foo\n  bar\n  baz");
 | 
						|
 | 
						|
  llvm::StringRef ExpectedMarkdown =
 | 
						|
      R"md(```cpp
 | 
						|
foo
 | 
						|
  bar
 | 
						|
  baz
 | 
						|
```)md";
 | 
						|
  llvm::StringRef ExpectedPlainText =
 | 
						|
      R"pt(foo
 | 
						|
  bar
 | 
						|
  baz)pt";
 | 
						|
  EXPECT_EQ(D.asMarkdown(), ExpectedMarkdown);
 | 
						|
  EXPECT_EQ(D.asPlainText(), ExpectedPlainText);
 | 
						|
  D.addCodeBlock("foo");
 | 
						|
  ExpectedMarkdown =
 | 
						|
      R"md(```cpp
 | 
						|
foo
 | 
						|
  bar
 | 
						|
  baz
 | 
						|
```
 | 
						|
```cpp
 | 
						|
foo
 | 
						|
```)md";
 | 
						|
  EXPECT_EQ(D.asMarkdown(), ExpectedMarkdown);
 | 
						|
  ExpectedPlainText =
 | 
						|
      R"pt(foo
 | 
						|
  bar
 | 
						|
  baz
 | 
						|
 | 
						|
foo)pt";
 | 
						|
  EXPECT_EQ(D.asPlainText(), ExpectedPlainText);
 | 
						|
}
 | 
						|
 | 
						|
TEST(BulletList, Render) {
 | 
						|
  BulletList L;
 | 
						|
  // Flat list
 | 
						|
  L.addItem().addParagraph().appendText("foo");
 | 
						|
  EXPECT_EQ(L.asMarkdown(), "- foo");
 | 
						|
  EXPECT_EQ(L.asPlainText(), "- foo");
 | 
						|
 | 
						|
  L.addItem().addParagraph().appendText("bar");
 | 
						|
  llvm::StringRef Expected = R"md(- foo
 | 
						|
- bar)md";
 | 
						|
  EXPECT_EQ(L.asMarkdown(), Expected);
 | 
						|
  EXPECT_EQ(L.asPlainText(), Expected);
 | 
						|
 | 
						|
  // Nested list, with a single item.
 | 
						|
  Document &D = L.addItem();
 | 
						|
  // First item with foo\nbaz
 | 
						|
  D.addParagraph().appendText("foo");
 | 
						|
  D.addParagraph().appendText("baz");
 | 
						|
 | 
						|
  // Nest one level.
 | 
						|
  Document &Inner = D.addBulletList().addItem();
 | 
						|
  Inner.addParagraph().appendText("foo");
 | 
						|
 | 
						|
  // Nest one more level.
 | 
						|
  BulletList &InnerList = Inner.addBulletList();
 | 
						|
  // Single item, baz\nbaz
 | 
						|
  Document &DeepDoc = InnerList.addItem();
 | 
						|
  DeepDoc.addParagraph().appendText("baz");
 | 
						|
  DeepDoc.addParagraph().appendText("baz");
 | 
						|
  StringRef ExpectedMarkdown = R"md(- foo
 | 
						|
- bar
 | 
						|
- foo  
 | 
						|
  baz  
 | 
						|
  - foo  
 | 
						|
    - baz  
 | 
						|
      baz)md";
 | 
						|
  EXPECT_EQ(L.asMarkdown(), ExpectedMarkdown);
 | 
						|
  StringRef ExpectedPlainText = R"pt(- foo
 | 
						|
- bar
 | 
						|
- foo
 | 
						|
  baz
 | 
						|
  - foo
 | 
						|
    - baz
 | 
						|
      baz)pt";
 | 
						|
  EXPECT_EQ(L.asPlainText(), ExpectedPlainText);
 | 
						|
 | 
						|
  // Termination
 | 
						|
  Inner.addParagraph().appendText("after");
 | 
						|
  ExpectedMarkdown = R"md(- foo
 | 
						|
- bar
 | 
						|
- foo  
 | 
						|
  baz  
 | 
						|
  - foo  
 | 
						|
    - baz  
 | 
						|
      baz
 | 
						|
    
 | 
						|
    after)md";
 | 
						|
  EXPECT_EQ(L.asMarkdown(), ExpectedMarkdown);
 | 
						|
  ExpectedPlainText = R"pt(- foo
 | 
						|
- bar
 | 
						|
- foo
 | 
						|
  baz
 | 
						|
  - foo
 | 
						|
    - baz
 | 
						|
      baz
 | 
						|
    after)pt";
 | 
						|
  EXPECT_EQ(L.asPlainText(), ExpectedPlainText);
 | 
						|
}
 | 
						|
 | 
						|
} // namespace
 | 
						|
} // namespace markup
 | 
						|
} // namespace clangd
 | 
						|
} // namespace clang
 |