//
// Blackfriday Markdown Processor
// Available at http://github.com/danog/blackfriday
//
// Copyright © 2011 Russ Ross Hello Goodbye List List List List List Nested list ####### Header 7 #Header 1 ##Header 2 ###Header 3 ####Header 4 #####Header 5 ######Header 6 #######Header 7 Hello Goodbye List List List Nested list } Hello Goodbye List List List List List Nested list List List List List List Nested list Hello Goodbye List List List List List Nested list Hello Goodbye List List List List List Nested list Paragraph Paragraph ======== Paragraph ===== Paragraph Paragraph Paragraph ===== - -- * ** _ __ -*- -----* Hello Yin Yang Ting Bong Goo Yin Yang Ting Bong Goo Yin Yang Ting Bong Goo *Hello Paragraph\n* No linebreak Paragraph List List\nSecond line List Continued List List List normal text Yin Yang Ting Bong Goo 1 Hello 1.Hello Paragraph\n1. No linebreak Paragraph List List\nSecond line List Continued List List Definition a Definition b Definition a Definition b Definition c Term 1\n:Definition a Definition a Definition b Text 1 Definition a Text 1 Definition b Text 2 Not nested ordered listHeader 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",
"Header 1
\n\n\n
\n",
"* List\n#Header\n* List\n",
"Header
\n
\n",
"* List\n * Nested list\n # Nested header\n",
"Header
\n
\n",
"#Header 1 \\#\n",
"\n
Nested header
Header 1 #
\n",
"#Header 1 \\# foo\n",
"Header 1 # foo
\n",
"#Header 1 #\\##\n",
"Header 1 ##
\n",
}
doTestsBlock(t, tests, 0)
}
func TestPrefixHeaderSpaceExtension(t *testing.T) {
t.Parallel()
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 1
\n\n\n
\n",
"* List\n#Header\n* List\n",
"Header
\n
\n",
"* List\n * Nested list\n # Nested header\n",
"\n
\n",
}
doTestsBlock(t, tests, SpaceHeadings)
}
func TestPrefixHeaderIdExtension(t *testing.T) {
t.Parallel()
var tests = []string{
"# Header 1 {#someid}\n",
"\n
Nested header
Header 1
\n",
"# Header 1 {#someid} \n",
"Header 1
\n",
"# Header 1 {#someid}\n",
"Header 1
\n",
"# Header 1 {#someid\n",
"Header 1 {#someid
\n",
"# Header 1 {#someid\n",
"Header 1 {#someid
\n",
"# Header 1 {#someid}}\n",
"Header 1
\n\nHeader 2
\n",
"### Header 3 {#someid}\n",
"Header 3
\n",
"#### Header 4 {#someid}\n",
"Header 4
\n",
"##### Header 5 {#someid}\n",
"Header 5
\n",
"###### Header 6 {#someid}\n",
"Header 6
\n",
"####### Header 7 {#someid}\n",
"# Header 7
\n",
"# Header 1 # {#someid}\n",
"Header 1
\n",
"## Header 2 ## {#someid}\n",
"Header 2
\n",
"Hello\n# Header 1\nGoodbye\n",
"Header 1
\n\n\n
\n",
"* List\n#Header {#someid}\n* List\n",
"Header
\n
\n",
"* List\n * Nested list\n # Nested header {#someid}\n",
"Header
\n
\n",
}
doTestsBlock(t, tests, HeadingIDs)
}
func TestPrefixHeaderIdExtensionWithPrefixAndSuffix(t *testing.T) {
t.Parallel()
var tests = []string{
"# header 1 {#someid}\n",
"\n
Nested header
header 1
\n",
"## header 2 {#someid}\n",
"header 2
\n",
"### header 3 {#someid}\n",
"header 3
\n",
"#### header 4 {#someid}\n",
"header 4
\n",
"##### header 5 {#someid}\n",
"header 5
\n",
"###### header 6 {#someid}\n",
"header 6
\n",
"####### header 7 {#someid}\n",
"# header 7
\n",
"# header 1 # {#someid}\n",
"header 1
\n",
"## header 2 ## {#someid}\n",
"header 2
\n",
"* List\n# Header {#someid}\n* List\n",
"\n
\n",
"* List\n#Header {#someid}\n* List\n",
"Header
\n
\n",
"* List\n * Nested list\n # Nested header {#someid}\n",
"Header
\n
\n",
}
parameters := HTMLRendererParameters{
HeadingIDPrefix: "PRE:",
HeadingIDSuffix: ":POST",
}
doTestsParam(t, tests, TestParams{
extensions: HeadingIDs,
HTMLFlags: UseXHTML,
HTMLRendererParameters: parameters,
})
}
func TestPrefixAutoHeaderIdExtension(t *testing.T) {
t.Parallel()
var tests = []string{
"# Header 1\n",
"\n
Nested header
Header 1
\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",
"Header 1
\n\n\n
\n",
"* List\n#Header\n* List\n",
"Header
\n
\n",
"* List\n * Nested list\n # Nested header\n",
"Header
\n
\n",
"# Header\n\n# Header\n",
"\n
Nested header
Header
\n\nHeader
\n",
"# Header 1\n\n# Header 1",
"Header 1
\n\nHeader 1
\n",
"# Header\n\n# Header 1\n\n# Header\n\n# Header",
"Header
\n\nHeader 1
\n\nHeader
\n\nHeader
\n",
}
doTestsBlock(t, tests, AutoHeadingIDs)
}
func TestPrefixAutoHeaderIdExtensionWithPrefixAndSuffix(t *testing.T) {
t.Parallel()
var tests = []string{
"# Header 1\n",
"Header 1
\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",
"Header 1
\n\n\n
\n",
"* List\n#Header\n* List\n",
"Header
\n
\n",
"* List\n * Nested list\n # Nested header\n",
"Header
\n
\n",
"# Header\n\n# Header\n",
"\n
Nested header
Header
\n\nHeader
\n",
"# Header 1\n\n# Header 1",
"Header 1
\n\nHeader 1
\n",
"# Header\n\n# Header 1\n\n# Header\n\n# Header",
"Header
\n\nHeader 1
\n\nHeader
\n\nHeader
\n",
}
parameters := HTMLRendererParameters{
HeadingIDPrefix: "PRE:",
HeadingIDSuffix: ":POST",
}
doTestsParam(t, tests, TestParams{
extensions: AutoHeadingIDs,
HTMLFlags: UseXHTML,
HTMLRendererParameters: parameters,
})
}
func TestPrefixHeaderLevelOffset(t *testing.T) {
t.Parallel()
var offsetTests = []struct {
offset int
tests []string
}{{
offset: 0,
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",
},
}, {
offset: 1,
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",
},
}, {
offset: -1,
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",
},
}}
for _, offsetTest := range offsetTests {
offset := offsetTest.offset
tests := offsetTest.tests
doTestsParam(t, tests, TestParams{
HTMLRendererParameters: HTMLRendererParameters{HeadingLevelOffset: offset},
})
}
}
func TestPrefixMultipleHeaderExtensions(t *testing.T) {
t.Parallel()
var tests = []string{
"# Header\n\n# Header {#header}\n\n# Header 1",
"Header
\n\nHeader
\n\nHeader 1
\n",
}
doTestsBlock(t, tests, AutoHeadingIDs|HeadingIDs)
}
func TestUnderlineHeaders(t *testing.T) {
t.Parallel()
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",
"Header
\n",
"Header\n===\nParagraph\n",
"Header
\n\nHeader
\n\nAnother header
\n",
" Header\n======\n",
"Header
\n",
" Code\n========\n",
"
\n\nCode\n
Header with inline
\n",
"* List\n * Sublist\n Not a header\n ------\n",
"\n
\n",
"Paragraph\n\n\n\n\nHeader\n===\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\nHeader 1
\n",
"Header 2\n--------\n",
"Header 2
\n",
"A\n=\n",
"A
\n",
"B\n-\n",
"B
\n",
"Paragraph\nHeader\n=\n",
"Header
\n",
"Header\n===\nParagraph\n",
"Header
\n\nHeader
\n\nAnother header
\n",
" Header\n======\n",
"Header
\n",
"Header with *inline*\n=====\n",
"Header with inline
\n",
"Paragraph\n\n\n\n\nHeader\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\nHeader
\n\nHeader
\n",
"Header 1\n========\n\nHeader 1\n========\n",
"Header 1
\n\nHeader 1
\n",
}
doTestsBlock(t, tests, AutoHeadingIDs)
}
func TestHorizontalRule(t *testing.T) {
t.Parallel()
var tests = []string{
"-\n",
"
\n",
"----\n",
"
\n",
"*\n",
"
\n",
"****\n",
"
\n",
"_\n",
"
\n",
"____\n",
"
\n",
"-*-\n",
"
\n",
"* * *\n",
"
\n",
"_ _ _\n",
"
\n",
"-----*\n",
"
\n",
"Hello\n***\n",
"
\n",
"---\n***\n___\n",
"
\n\n
\n\n
\n",
}
doTestsBlock(t, tests, 0)
}
func TestUnorderedList(t *testing.T) {
t.Parallel()
var tests = []string{
"* Hello\n",
"\n
\n",
"* Yin\n* Yang\n",
"\n
\n",
"* Ting\n* Bong\n* Goo\n",
"\n
\n",
"* Yin\n\n* Yang\n",
"\n
\n",
"* Ting\n\n* Bong\n* Goo\n",
"\n
\n",
"+ Hello\n",
"\n
\n",
"+ Yin\n+ Yang\n",
"\n
\n",
"+ Ting\n+ Bong\n+ Goo\n",
"\n
\n",
"+ Yin\n\n+ Yang\n",
"\n
\n",
"+ Ting\n\n+ Bong\n+ Goo\n",
"\n
\n",
"- Hello\n",
"\n
\n",
"- Yin\n- Yang\n",
"\n
\n",
"- Ting\n- Bong\n- Goo\n",
"\n
\n",
"- Yin\n\n- Yang\n",
"\n
\n",
"- Ting\n\n- Bong\n- Goo\n",
"\n
\n",
"*Hello\n",
"\n
\n",
"* Hello \n Next line \n",
"\n
\n",
"Paragraph\n* No linebreak\n",
"\n
\n",
"* List\n * Nested list\n",
"\n
\n",
"* List\n\n * Nested list\n",
"\n
\n
\n",
"* List\n Second line\n\n + Nested\n",
"\n
\n
\n",
"* List\n + Nested\n\n Continued\n",
"\n
\n
\n",
"* List\n * shallow indent\n",
"\n
\n\n\n
\n",
"* List\n" +
" * shallow indent\n" +
" * part of second list\n" +
" * still second\n" +
" * almost there\n" +
" * third level\n",
"\n
\n" +
"
\n",
"* List\n extra indent, same paragraph\n",
"\n" +
"
\n" +
"
\n
\n",
"* List\n\n code block\n",
"\n
\n",
"* List\n\n code block with spaces\n",
"code block\n
\n
\n",
"* List\n\n * sublist\n\n normal text\n\n * another sublist\n",
" code block with spaces\n
\n
\n",
}
doTestsBlock(t, tests, 0)
}
func TestOrderedList(t *testing.T) {
t.Parallel()
var tests = []string{
"1. Hello\n",
"\n
\n\n\n
\n
\n",
"1. Yin\n2. Yang\n",
"\n
\n",
"1. Ting\n2. Bong\n3. Goo\n",
"\n
\n",
"1. Yin\n\n2. Yang\n",
"\n
\n",
"1. Ting\n\n2. Bong\n3. Goo\n",
"\n
\n",
"1 Hello\n",
"\n
\n",
"1. Hello \n Next line \n",
"\n
\n",
"Paragraph\n1. No linebreak\n",
"\n
\n",
"1. List\n 1. Nested list\n",
"\n
\n",
"1. List\n\n 1. Nested list\n",
"\n
\n
\n",
"1. List\n Second line\n\n 1. Nested\n",
"\n
\n
\n",
"1. List\n 1. Nested\n\n Continued\n",
"\n
\n
\n",
"1. List\n 1. shallow indent\n",
"\n
\n\n\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
\n" +
"
\n",
"1. List\n extra indent, same paragraph\n",
"\n" +
"
\n" +
"
\n
\n",
"1. List\n\n code block\n",
"\n
\n",
"1. List\n\n code block with spaces\n",
"code block\n
\n
\n",
"1. List\n * Mixted list\n",
" code block with spaces\n
\n
\n",
"1. List\n * Mixed list\n",
"\n
\n
\n",
"* Start with unordered\n 1. Ordered\n",
"\n
\n
\n",
"* Start with unordered\n 1. Ordered\n",
"\n
\n
\n",
"1. numbers\n1. are ignored\n",
"\n
\n
\n",
}
doTestsBlock(t, tests, 0)
}
func TestDefinitionList(t *testing.T) {
t.Parallel()
var tests = []string{
"Term 1\n: Definition a\n",
"\n
\n",
"Term 1\n: Definition a \n",
"\n
\n",
"Term 1\n: Definition a\n: Definition b\n",
"\n
\n",
"Term 1\n: Definition a\n\nTerm 2\n: Definition b\n",
"\n" +
"
\n",
"Term 1\n: Definition a\n\nTerm 2\n: Definition b\n\nTerm 3\n: Definition c\n",
"\n" +
"
\n",
"Term 1\n: Definition a\n: Definition b\n\nTerm 2\n: Definition c\n",
"\n" +
"
\n",
"Term 1\n\n: Definition a\n\nTerm 2\n\n: Definition b\n",
"\n" +
"
\n",
"Term 1\n\n: Definition a\n\n: Definition b\n\nTerm 2\n\n: Definition c\n",
"\n" +
"
\n",
"Term 1\n: Definition a\nNext line\n",
"\n
\n",
"Term 1\n: Definition a\n Next line\n",
"\n
\n",
"Term 1\n: Definition a \n Next line \n",
"\n
\n",
"Term 1\n: Definition a\nNext line\n\nTerm 2\n: Definition b",
"\n" +
"
\n",
"Term 1\n: Definition a\n",
"\n
\n",
"Term 1\n:Definition a\n",
"\n" +
"
\n" +
"\n\n" +
"
\n" +
"\n\n" +
"
\n" +
"\n\n
\n\n\n
\n\n\n
\n",
"1. Not nested\n2. ordered list\n\n\t1. nested\n\t2. ordered list\n\n\t* nested\n\t* unordered list\n* Not nested\n* unordered list",
"\n
\n\n\n
\n\n\n
\n
\n",
}
doTestsBlock(t, tests, DefinitionLists)
}
func TestPreformattedHtml(t *testing.T) {
t.Parallel()
var tests = []string{
"\n",
"\n",
"
Paragraph\n
Paragraph
\n\nParagraph\n
Paragraph
\n\nParagraph\n
And here?
\n", "Paragraph\n\nParagraph
\n\nAnd here?
\n", } doTestsBlock(t, tests, 0) } func TestPreformattedHtmlLax(t *testing.T) { t.Parallel() var tests = []string{ "Paragraph\nParagraph
\n\nParagraph
\n\nParagraph
\n\nAnd here?
\n", "Paragraph\n\nParagraph
\n\nAnd here?
\n", "Paragraph\nParagraph
\n\nAnd here?
\n", "Paragraph\n\nParagraph
\n\nAnd here?
\n", } doTestsBlock(t, tests, LaxHTMLBlocks) } func TestFencedCodeBlock(t *testing.T) { t.Parallel() var tests = []string{ "``` go\nfunc foo() bool {\n\treturn true;\n}\n```\n", "func foo() bool {\n\treturn true;\n}\n
\n",
"``` go foo bar\nfunc foo() bool {\n\treturn true;\n}\n```\n",
"func foo() bool {\n\treturn 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\nleading spaces\n ```
\n", "Bla bla\n\n``` oz\ncode blocks breakup paragraphs\n```\n\nBla Bla\n", "Bla bla
\n\ncode blocks breakup paragraphs\n
\n\nBla Bla
\n", "Some text before a fenced code block\n``` oz\ncode blocks breakup paragraphs\n```\nAnd some text after a fenced code block", "Some text before a fenced code block
\n\ncode blocks breakup paragraphs\n
\n\nAnd some text after a fenced code block
\n", "`", "`
\n", "Bla bla\n\n``` oz\ncode blocks breakup paragraphs\n```\n\nBla Bla\n\n``` oz\nmultiple code blocks work okay\n```\n\nBla Bla\n", "Bla bla
\n\ncode blocks breakup paragraphs\n
\n\nBla Bla
\n\nmultiple code blocks work okay\n
\n\nBla Bla
\n", "Some text before a fenced code block\n``` oz\ncode blocks breakup paragraphs\n```\nSome text in between\n``` oz\nmultiple code blocks work okay\n```\nAnd some text after a fenced code block", "Some text before a fenced code block
\n\ncode blocks breakup paragraphs\n
\n\nSome text in between
\n\nmultiple code blocks work okay\n
\n\nAnd some text after a fenced code block
\n", "```\n[]:()\n```\n", "[]:()\n
\n",
"```\n[]:()\n[]:)\n[]:(\n[]:x\n[]:testing\n[:testing\n\n[]:\nlinebreak\n[]()\n\n[]:\n[]()\n```",
"[]:()\n[]:)\n[]:(\n[]:x\n[]:testing\n[:testing\n\n[]:\nlinebreak\n[]()\n\n[]:\n[]()\n
\n",
}
doTestsBlock(t, tests, FencedCode)
}
func TestFencedCodeInsideBlockquotes(t *testing.T) {
t.Parallel()
cat := func(s ...string) string { return strings.Join(s, "\n") }
var tests = []string{
cat("> ```go",
"package moo",
"",
"```",
""),
``, // ------------------------------------------- cat("> foo", "> ", "> ```go", "package moo", "```", "> ", "> goo.", ""), `package moo
`, // ------------------------------------------- cat("> foo", "> ", "> quote", "continues", "```", ""), `foo
package moo
goo.
`, // ------------------------------------------- cat("> foo", "> ", "> ```go", "package moo", "```", "> ", "> goo.", "> ", "> ```go", "package zoo", "```", "> ", "> woo.", ""), `foo
quote continues ` + "```" + `
`, } // These 2 alternative forms of blockquoted fenced code blocks should produce same output. forms := [2]string{ cat("> plain quoted text", "> ```fenced", "code", " with leading single space correctly preserved", "okay", "```", "> rest of quoted text"), cat("> plain quoted text", "> ```fenced", "> code", "> with leading single space correctly preserved", "> okay", "> ```", "> rest of quoted text"), } want := `foo
package moo
goo.
package zoo
woo.
` tests = append(tests, forms[0], want) tests = append(tests, forms[1], want) doTestsBlock(t, tests, FencedCode) } func TestTable(t *testing.T) { t.Parallel() var tests = []string{ "a | b\n---|---\nc | d\n", "plain quoted text
code with leading single space correctly preserved okay
rest of quoted text
a | \nb | \n
---|---|
c | \nd | \n
a | b\n---|--\nc | d
\n", "|a|b|c|d|\n|----|----|----|---|\n|e|f|g|h|\n", "a | \nb | \nc | \nd | \n
---|---|---|---|
e | \nf | \ng | \nh | \n
a | \nb | \nc | \nd | \n
---|---|---|---|
e | \nf | \ng | \nh | \n
a | \nb | \nc | \n
---|---|---|
d | \ne | \nf | \n
g | \nh | \n\n |
i | \nj | \nk | \n
n | \no | \np | \n
a | \nb | \nc | \n
---|---|---|
d | \ne | \nf | \n
a | \nb | \n" + "c | \nd | \n
---|---|---|---|
e | \nf | \n" + "g | \nh | \n
a | \nb | \nc | \n
---|
a | \nb | \nc | \nd | \ne | \n
---|---|---|---|---|
f | \ng | \nh | \ni | \nj | \n
a | \nb|c | \nd | \n
---|---|---|
f | \ng|h | \ni | \n
Yin
Yang
Ting
Bong
Goo
Yin
Yang
Ting
Bong
Goo
Yin
Yang
Ting
Bong
Goo
*Hello
\n", "* Hello \n", "Paragraph
\n\nParagraph
\n\nList
\n\nList\nSecond line
\n\nList
\n\nContinued
List
\n\ncode block\n
List
\n\n code block with spaces\n
List
\n\nnormal text
\n\nYin
Yang
Ting
Bong
Goo
1 Hello
\n", "1.Hello\n", "1.Hello
\n", "1. Hello \n", "Paragraph
\n\nParagraph
\n\nList
\n\nList\nSecond line
\n\nList
\n\nContinued
List
\n\ncode block\n
List
\n\n code block with spaces\n
func foo() bool {\n\treturn true;\n}\n
\n",
"``` go foo bar\nfunc foo() bool {\n\treturn true;\n}\n```\n",
"func foo() bool {\n\treturn 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\nleading spaces
\n\n```\n
\n",
}
doTestsBlock(t, tests, FencedCode|NoEmptyLineBeforeBlock)
}
func TestListWithFencedCodeBlock(t *testing.T) {
t.Parallel()
var tests = []string{
"1. one\n\n ```\n code\n ```\n\n2. two\n",
"one
\n\ncode\n
two
one
\n\n- code\n
two
one
\n\n\ncode\n
two
one
\n\n```
\n\ntwo
Some text
\n\n\n", "Some text\n\n\n", "Some text
\n\n\n", "Some text\n\n\n", "Some text
\n\n\n", } doTestsBlock(t, tests, 0) } func TestTOC(t *testing.T) { t.Parallel() var tests = []string{ "# Title\n\n##Subtitle1\n\n##Subtitle2", //"\n\ncode
foo
`, } doTestsParam(t, tests, TestParams{HTMLFlags: UseXHTML | CompletePage}) } func TestIsFenceLine(t *testing.T) { t.Parallel() tests := []struct { data []byte infoRequested bool wantEnd int wantMarker string wantInfo string }{ { data: []byte("```"), wantEnd: 3, wantMarker: "```", }, { data: []byte("```\nstuff here\n"), wantEnd: 4, wantMarker: "```", }, { data: []byte("```\nstuff here\n"), infoRequested: true, wantEnd: 4, wantMarker: "```", }, { data: []byte("stuff here\n```\n"), wantEnd: 0, }, { data: []byte("```"), infoRequested: true, wantEnd: 3, wantMarker: "```", }, { data: []byte("``` go"), infoRequested: true, wantEnd: 6, wantMarker: "```", wantInfo: "go", }, { data: []byte("``` go foo bar"), infoRequested: true, wantEnd: 14, wantMarker: "```", wantInfo: "go foo bar", }, { data: []byte("``` go foo bar "), infoRequested: true, wantEnd: 16, wantMarker: "```", wantInfo: "go foo bar", }, } for _, test := range tests { var info *string if test.infoRequested { info = new(string) } end, marker := isFenceLine(test.data, info, "```") if got, want := end, test.wantEnd; got != want { t.Errorf("got end %v, want %v", got, want) } if got, want := marker, test.wantMarker; got != want { t.Errorf("got marker %q, want %q", got, want) } if test.infoRequested { if got, want := *info, test.wantInfo; got != want { t.Errorf("got info string %q, want %q", got, want) } } } } func TestSanitizedAnchorName(t *testing.T) { tests := []struct { text string want string }{ { text: "This is a header", want: "this-is-a-header", }, { text: "This is also a header", want: "this-is-also-a-header", }, { text: "main.go", want: "main-go", }, { text: "Article 123", want: "article-123", }, { text: "<- Let's try this, shall we?", want: "let-s-try-this-shall-we", }, { text: " ", want: "", }, { text: "Hello, 世界", want: "hello-世界", }, } for _, test := range tests { if got := SanitizedAnchorName(test.text); got != test.want { t.Errorf("SanitizedAnchorName(%q):\ngot %q\nwant %q", test.text, got, test.want) } } }