// // Blackfriday Markdown Processor // Available at http://github.com/russross/blackfriday // // Copyright © 2011 Russ Ross . // Distributed under the Simplified BSD License. // See README.md for details. // // // Unit tests for block parsing // package blackfriday import ( "testing" ) func runMarkdownBlock(input string, extensions int) string { htmlFlags := 0 htmlFlags |= HTML_USE_XHTML renderer := HtmlRenderer(htmlFlags, "", "") return string(Markdown([]byte(input), renderer, extensions)) } func doTestsBlock(t *testing.T, tests []string, extensions int) { // catch and report panics var candidate string defer func() { if err := recover(); err != nil { t.Errorf("\npanic while processing [%#v]\n", candidate) } }() for i := 0; i+1 < len(tests); i += 2 { input := tests[i] candidate = input expected := tests[i+1] actual := runMarkdownBlock(candidate, extensions) if actual != expected { t.Errorf("\nInput [%#v]\nExpected[%#v]\nActual [%#v]", candidate, expected, actual) } // now test every substring to stress test bounds checking if !testing.Short() { for start := 0; start < len(input); start++ { for end := start + 1; end <= len(input); end++ { candidate = input[start:end] _ = runMarkdownBlock(candidate, extensions) } } } } } func TestPrefixHeaderNoExtensions(t *testing.T) { var tests = []string{ "# Header 1\n", "

Header 1

\n", "## Header 2\n", "

Header 2

\n", "### Header 3\n", "

Header 3

\n", "#### Header 4\n", "

Header 4

\n", "##### Header 5\n", "
Header 5
\n", "###### Header 6\n", "
Header 6
\n", "####### Header 7\n", "
# Header 7
\n", "#Header 1\n", "

Header 1

\n", "##Header 2\n", "

Header 2

\n", "###Header 3\n", "

Header 3

\n", "####Header 4\n", "

Header 4

\n", "#####Header 5\n", "
Header 5
\n", "######Header 6\n", "
Header 6
\n", "#######Header 7\n", "
#Header 7
\n", "Hello\n# Header 1\nGoodbye\n", "

Hello

\n\n

Header 1

\n\n

Goodbye

\n", "* List\n# Header\n* List\n", "\n", "* List\n#Header\n* List\n", "\n", "* List\n * Nested list\n # Nested header\n", "\n", } doTestsBlock(t, tests, 0) } func TestPrefixHeaderSpaceExtension(t *testing.T) { var tests = []string{ "# Header 1\n", "

Header 1

\n", "## Header 2\n", "

Header 2

\n", "### Header 3\n", "

Header 3

\n", "#### Header 4\n", "

Header 4

\n", "##### Header 5\n", "
Header 5
\n", "###### Header 6\n", "
Header 6
\n", "####### Header 7\n", "

####### Header 7

\n", "#Header 1\n", "

#Header 1

\n", "##Header 2\n", "

##Header 2

\n", "###Header 3\n", "

###Header 3

\n", "####Header 4\n", "

####Header 4

\n", "#####Header 5\n", "

#####Header 5

\n", "######Header 6\n", "

######Header 6

\n", "#######Header 7\n", "

#######Header 7

\n", "Hello\n# Header 1\nGoodbye\n", "

Hello

\n\n

Header 1

\n\n

Goodbye

\n", "* List\n# Header\n* List\n", "\n", "* List\n#Header\n* List\n", "\n", "* List\n * Nested list\n # Nested header\n", "\n", } doTestsBlock(t, tests, EXTENSION_SPACE_HEADERS) } func TestUnderlineHeaders(t *testing.T) { var tests = []string{ "Header 1\n========\n", "

Header 1

\n", "Header 2\n--------\n", "

Header 2

\n", "A\n=\n", "

A

\n", "B\n-\n", "

B

\n", "Paragraph\nHeader\n=\n", "

Paragraph

\n\n

Header

\n", "Header\n===\nParagraph\n", "

Header

\n\n

Paragraph

\n", "Header\n===\nAnother header\n---\n", "

Header

\n\n

Another header

\n", " Header\n======\n", "

Header

\n", " Code\n========\n", "
Code\n
\n\n

========

\n", "Header with *inline*\n=====\n", "

Header with inline

\n", "* List\n * Sublist\n Not a header\n ------\n", "\n", "Paragraph\n\n\n\n\nHeader\n===\n", "

Paragraph

\n\n

Header

\n", "Trailing space \n==== \n\n", "

Trailing space

\n", "Trailing spaces\n==== \n\n", "

Trailing spaces

\n", "Double underline\n=====\n=====\n", "

Double underline

\n\n

=====

\n", } doTestsBlock(t, tests, 0) } func TestHorizontalRule(t *testing.T) { var tests = []string{ "-\n", "

-

\n", "--\n", "

--

\n", "---\n", "
\n", "----\n", "
\n", "*\n", "

*

\n", "**\n", "

**

\n", "***\n", "
\n", "****\n", "
\n", "_\n", "

_

\n", "__\n", "

__

\n", "___\n", "
\n", "____\n", "
\n", "-*-\n", "

-*-

\n", "- - -\n", "
\n", "* * *\n", "
\n", "_ _ _\n", "
\n", "-----*\n", "

-----*

\n", " ------ \n", "
\n", "Hello\n***\n", "

Hello

\n\n
\n", "---\n***\n___\n", "
\n\n
\n\n
\n", } doTestsBlock(t, tests, 0) } func TestUnorderedList(t *testing.T) { var tests = []string{ "* Hello\n", "\n", "* Yin\n* Yang\n", "\n", "* Ting\n* Bong\n* Goo\n", "\n", "* Yin\n\n* Yang\n", "\n", "* Ting\n\n* Bong\n* Goo\n", "\n", "+ Hello\n", "\n", "+ Yin\n+ Yang\n", "\n", "+ Ting\n+ Bong\n+ Goo\n", "\n", "+ Yin\n\n+ Yang\n", "\n", "+ Ting\n\n+ Bong\n+ Goo\n", "\n", "- Hello\n", "\n", "- Yin\n- Yang\n", "\n", "- Ting\n- Bong\n- Goo\n", "\n", "- Yin\n\n- Yang\n", "\n", "- Ting\n\n- Bong\n- Goo\n", "\n", "*Hello\n", "

*Hello

\n", "* Hello \n", "\n", "* Hello \n Next line \n", "\n", "Paragraph\n* No linebreak\n", "

Paragraph\n* No linebreak

\n", "Paragraph\n\n* Linebreak\n", "

Paragraph

\n\n\n", "* List\n * Nested list\n", "\n", "* List\n\n * Nested list\n", "\n", "* List\n Second line\n\n + Nested\n", "\n", "* List\n + Nested\n\n Continued\n", "\n", "* List\n * shallow indent\n", "\n", "* List\n" + " * shallow indent\n" + " * part of second list\n" + " * still second\n" + " * almost there\n" + " * third level\n", "\n", "* List\n extra indent, same paragraph\n", "\n", "* List\n\n code block\n", "\n", "* List\n\n code block with spaces\n", "\n", } doTestsBlock(t, tests, 0) } func TestOrderedList(t *testing.T) { var tests = []string{ "1. Hello\n", "
    \n
  1. Hello
  2. \n
\n", "1. Yin\n2. Yang\n", "
    \n
  1. Yin
  2. \n
  3. Yang
  4. \n
\n", "1. Ting\n2. Bong\n3. Goo\n", "
    \n
  1. Ting
  2. \n
  3. Bong
  4. \n
  5. Goo
  6. \n
\n", "1. Yin\n\n2. Yang\n", "
    \n
  1. Yin

  2. \n\n
  3. Yang

  4. \n
\n", "1. Ting\n\n2. Bong\n3. Goo\n", "
    \n
  1. Ting

  2. \n\n
  3. Bong

  4. \n\n
  5. Goo

  6. \n
\n", "1 Hello\n", "

1 Hello

\n", "1.Hello\n", "

1.Hello

\n", "1. Hello \n", "
    \n
  1. Hello
  2. \n
\n", "1. Hello \n Next line \n", "
    \n
  1. Hello\nNext line
  2. \n
\n", "Paragraph\n1. No linebreak\n", "

Paragraph\n1. No linebreak

\n", "Paragraph\n\n1. Linebreak\n", "

Paragraph

\n\n
    \n
  1. Linebreak
  2. \n
\n", "1. List\n 1. Nested list\n", "
    \n
  1. List\n\n
      \n
    1. Nested list
    2. \n
  2. \n
\n", "1. List\n\n 1. Nested list\n", "
    \n
  1. List

    \n\n
      \n
    1. Nested list
    2. \n
  2. \n
\n", "1. List\n Second line\n\n 1. Nested\n", "
    \n
  1. List\nSecond line

    \n\n
      \n
    1. Nested
    2. \n
  2. \n
\n", "1. List\n 1. Nested\n\n Continued\n", "
    \n
  1. List

    \n\n
      \n
    1. Nested
    2. \n
    \n\n

    Continued

  2. \n
\n", "1. List\n 1. shallow indent\n", "
    \n
  1. List\n\n
      \n
    1. shallow indent
    2. \n
  2. \n
\n", "1. List\n" + " 1. shallow indent\n" + " 2. part of second list\n" + " 3. still second\n" + " 4. almost there\n" + " 1. third level\n", "
    \n" + "
  1. List\n\n" + "
      \n" + "
    1. shallow indent
    2. \n" + "
    3. part of second list
    4. \n" + "
    5. still second
    6. \n" + "
    7. almost there\n\n" + "
        \n" + "
      1. third level
      2. \n" + "
    8. \n" + "
  2. \n" + "
\n", "1. List\n extra indent, same paragraph\n", "
    \n
  1. List\n extra indent, same paragraph
  2. \n
\n", "1. List\n\n code block\n", "
    \n
  1. List

    \n\n
    code block\n
  2. \n
\n", "1. List\n\n code block with spaces\n", "
    \n
  1. List

    \n\n
      code block with spaces\n
  2. \n
\n", "1. List\n * Mixted list\n", "
    \n
  1. List\n\n
      \n
    • Mixted list
    • \n
  2. \n
\n", "1. List\n * Mixed list\n", "
    \n
  1. List\n\n
      \n
    • Mixed list
    • \n
  2. \n
\n", "* Start with unordered\n 1. Ordered\n", "\n", "* Start with unordered\n 1. Ordered\n", "\n", "1. numbers\n1. are ignored\n", "
    \n
  1. numbers
  2. \n
  3. are ignored
  4. \n
\n", } doTestsBlock(t, tests, 0) } func TestPreformattedHtml(t *testing.T) { var tests = []string{ "
\n", "
\n", "
\n
\n", "
\n
\n", "
\n
\nParagraph\n", "

\n
\nParagraph

\n", "
\n
\n", "
\n
\n", "
\nAnything here\n
\n", "
\nAnything here\n
\n", "
\n Anything here\n
\n", "
\n Anything here\n
\n", "
\nAnything here\n
\n", "
\nAnything here\n
\n", "
\nThis is *not* &proceessed\n
\n", "
\nThis is *not* &proceessed\n
\n", "\n Something\n\n", "

\n Something\n

\n", "
\n Something here\n\n", "

\n Something here\n

\n", "Paragraph\n
\nHere? >&<\n
\n", "

Paragraph\n

\nHere? >&<\n

\n", "Paragraph\n\n
\nHow about here? >&<\n
\n", "

Paragraph

\n\n
\nHow about here? >&<\n
\n", "Paragraph\n
\nHere? >&<\n
\nAnd here?\n", "

Paragraph\n

\nHere? >&<\n
\nAnd here?

\n", "Paragraph\n\n
\nHow about here? >&<\n
\nAnd here?\n", "

Paragraph

\n\n

\nHow about here? >&<\n
\nAnd here?

\n", "Paragraph\n
\nHere? >&<\n
\n\nAnd here?\n", "

Paragraph\n

\nHere? >&<\n

\n\n

And here?

\n", "Paragraph\n\n
\nHow about here? >&<\n
\n\nAnd here?\n", "

Paragraph

\n\n
\nHow about here? >&<\n
\n\n

And here?

\n", } doTestsBlock(t, tests, 0) } func TestPreformattedHtmlLax(t *testing.T) { var tests = []string{ "Paragraph\n
\nHere? >&<\n
\n", "

Paragraph

\n\n
\nHere? >&<\n
\n", "Paragraph\n\n
\nHow about here? >&<\n
\n", "

Paragraph

\n\n
\nHow about here? >&<\n
\n", "Paragraph\n
\nHere? >&<\n
\nAnd here?\n", "

Paragraph

\n\n
\nHere? >&<\n
\n\n

And here?

\n", "Paragraph\n\n
\nHow about here? >&<\n
\nAnd here?\n", "

Paragraph

\n\n
\nHow about here? >&<\n
\n\n

And here?

\n", "Paragraph\n
\nHere? >&<\n
\n\nAnd here?\n", "

Paragraph

\n\n
\nHere? >&<\n
\n\n

And here?

\n", "Paragraph\n\n
\nHow about here? >&<\n
\n\nAnd here?\n", "

Paragraph

\n\n
\nHow about here? >&<\n
\n\n

And here?

\n", } doTestsBlock(t, tests, EXTENSION_LAX_HTML_BLOCKS) } func TestFencedCodeBlock(t *testing.T) { var tests = []string{ "``` go\nfunc foo() bool {\n\treturn true;\n}\n```\n", "
func foo() bool {\n    return true;\n}\n
\n", "``` c\n/* special & char < > \" escaping */\n```\n", "
/* special & char < > " escaping */\n
\n", "``` c\nno *inline* processing ~~of text~~\n```\n", "
no *inline* processing ~~of text~~\n
\n", "```\nNo language\n```\n", "
No language\n
\n", "``` {ocaml}\nlanguage in braces\n```\n", "
language in braces\n
\n", "``` {ocaml} \nwith extra whitespace\n```\n", "
with extra whitespace\n
\n", "```{ ocaml }\nwith extra whitespace\n```\n", "
with extra whitespace\n
\n", "~ ~~ java\nWith whitespace\n~~~\n", "

~ ~~ java\nWith whitespace\n~~~

\n", "~~\nonly two\n~~\n", "

~~\nonly two\n~~

\n", "```` python\nextra\n````\n", "
extra\n
\n", "~~~ perl\nthree to start, four to end\n~~~~\n", "

~~~ perl\nthree to start, four to end\n~~~~

\n", "~~~~ perl\nfour to start, three to end\n~~~\n", "

~~~~ perl\nfour to start, three to end\n~~~

\n", "~~~ bash\ntildes\n~~~\n", "
tildes\n
\n", "``` lisp\nno ending\n", "

``` lisp\nno ending

\n", "~~~ lisp\nend with language\n~~~ lisp\n", "

~~~ lisp\nend with language\n~~~ lisp

\n", "```\nmismatched begin and end\n~~~\n", "

```\nmismatched begin and end\n~~~

\n", "~~~\nmismatched begin and end\n```\n", "

~~~\nmismatched begin and end\n```

\n", " ``` oz\nleading spaces\n```\n", "
leading spaces\n
\n", " ``` oz\nleading spaces\n ```\n", "
leading spaces\n
\n", " ``` oz\nleading spaces\n ```\n", "
leading spaces\n
\n", "``` oz\nleading spaces\n ```\n", "
leading spaces\n
\n", " ``` oz\nleading spaces\n ```\n", "
``` oz\n
\n\n

leading spaces\n ```

\n", } doTestsBlock(t, tests, EXTENSION_FENCED_CODE) }