mirror of
https://github.com/russross/blackfriday.git
synced 2024-03-22 13:40:34 +08:00
fixed headers nested in lists, added prefix header unit tests
This commit is contained in:
parent
e22e43bf76
commit
3af64a90ad
39
block.go
39
block.go
|
@ -940,7 +940,7 @@ func blockListItem(out *bytes.Buffer, rndr *render, data []byte, flags *int) int
|
|||
beg = end
|
||||
|
||||
// process the following lines
|
||||
in_empty, has_inside_empty := false, false
|
||||
contains_blank_line, contains_block := false, false
|
||||
for beg < len(data) {
|
||||
end++
|
||||
|
||||
|
@ -950,7 +950,7 @@ func blockListItem(out *bytes.Buffer, rndr *render, data []byte, flags *int) int
|
|||
|
||||
// process an empty line
|
||||
if isEmpty(data[beg:end]) > 0 {
|
||||
in_empty = true
|
||||
contains_blank_line = true
|
||||
beg = end
|
||||
continue
|
||||
}
|
||||
|
@ -967,11 +967,12 @@ func blockListItem(out *bytes.Buffer, rndr *render, data []byte, flags *int) int
|
|||
pre = 8
|
||||
}
|
||||
|
||||
// check for a new item
|
||||
chunk := data[beg+i : end]
|
||||
|
||||
// check for a nested list item
|
||||
if (blockUliPrefix(chunk) > 0 && !isHRule(chunk)) || blockOliPrefix(chunk) > 0 {
|
||||
if in_empty {
|
||||
has_inside_empty = true
|
||||
if contains_blank_line {
|
||||
contains_block = true
|
||||
}
|
||||
|
||||
if pre == orgpre { // the following item must have the same indentation
|
||||
|
@ -982,19 +983,29 @@ func blockListItem(out *bytes.Buffer, rndr *render, data []byte, flags *int) int
|
|||
sublist = work.Len()
|
||||
}
|
||||
} else {
|
||||
// only join indented stuff after empty lines
|
||||
if in_empty && i < 4 && data[beg] != '\t' {
|
||||
*flags |= LIST_ITEM_END_OF_LIST
|
||||
break
|
||||
// how about a nested prefix header?
|
||||
if isPrefixHeader(rndr, chunk) {
|
||||
// only nest headers that are indented
|
||||
if contains_blank_line && i < 4 && data[beg] != '\t' {
|
||||
*flags |= LIST_ITEM_END_OF_LIST
|
||||
break
|
||||
}
|
||||
contains_block = true
|
||||
} else {
|
||||
if in_empty {
|
||||
work.WriteByte('\n')
|
||||
has_inside_empty = true
|
||||
// only join stuff after empty lines when indented
|
||||
if contains_blank_line && i < 4 && data[beg] != '\t' {
|
||||
*flags |= LIST_ITEM_END_OF_LIST
|
||||
break
|
||||
} else {
|
||||
if contains_blank_line {
|
||||
work.WriteByte('\n')
|
||||
contains_block = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
in_empty = false
|
||||
contains_blank_line = false
|
||||
|
||||
// add the line into the working buffer without prefix
|
||||
work.Write(data[beg+i : end])
|
||||
|
@ -1002,7 +1013,7 @@ func blockListItem(out *bytes.Buffer, rndr *render, data []byte, flags *int) int
|
|||
}
|
||||
|
||||
// render li contents
|
||||
if has_inside_empty {
|
||||
if contains_block {
|
||||
*flags |= LIST_ITEM_CONTAINS_BLOCK
|
||||
}
|
||||
|
||||
|
|
162
block_test.go
Normal file
162
block_test.go
Normal file
|
@ -0,0 +1,162 @@
|
|||
//
|
||||
// Black Friday Markdown Processor
|
||||
// Originally based on http://github.com/tanoku/upskirt
|
||||
// by Russ Ross <russ@russross.com>
|
||||
//
|
||||
|
||||
//
|
||||
// Unit tests for block parsing
|
||||
//
|
||||
|
||||
package blackfriday
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func runMarkdownBlock(input string, extensions uint32) string {
|
||||
html_flags := 0
|
||||
html_flags |= HTML_USE_XHTML
|
||||
|
||||
renderer := HtmlRenderer(html_flags)
|
||||
|
||||
return string(Markdown([]byte(input), renderer, extensions))
|
||||
}
|
||||
|
||||
func doTestsBlock(t *testing.T, tests []string, extensions uint32) {
|
||||
for i := 0; i+1 < len(tests); i += 2 {
|
||||
input := tests[i]
|
||||
expected := tests[i+1]
|
||||
actual := runMarkdownBlock(input, extensions)
|
||||
if actual != expected {
|
||||
t.Errorf("\nInput [%#v]\nExpected[%#v]\nActual [%#v]",
|
||||
input, expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestPrefixHeaderNoExtensions(t *testing.T) {
|
||||
var tests = []string{
|
||||
"# Header 1\n",
|
||||
"<h1>Header 1</h1>\n",
|
||||
|
||||
"## Header 2\n",
|
||||
"<h2>Header 2</h2>\n",
|
||||
|
||||
"### Header 3\n",
|
||||
"<h3>Header 3</h3>\n",
|
||||
|
||||
"#### Header 4\n",
|
||||
"<h4>Header 4</h4>\n",
|
||||
|
||||
"##### Header 5\n",
|
||||
"<h5>Header 5</h5>\n",
|
||||
|
||||
"###### Header 6\n",
|
||||
"<h6>Header 6</h6>\n",
|
||||
|
||||
"####### Header 7\n",
|
||||
"<h6># Header 7</h6>\n",
|
||||
|
||||
"#Header 1\n",
|
||||
"<h1>Header 1</h1>\n",
|
||||
|
||||
"##Header 2\n",
|
||||
"<h2>Header 2</h2>\n",
|
||||
|
||||
"###Header 3\n",
|
||||
"<h3>Header 3</h3>\n",
|
||||
|
||||
"####Header 4\n",
|
||||
"<h4>Header 4</h4>\n",
|
||||
|
||||
"#####Header 5\n",
|
||||
"<h5>Header 5</h5>\n",
|
||||
|
||||
"######Header 6\n",
|
||||
"<h6>Header 6</h6>\n",
|
||||
|
||||
"#######Header 7\n",
|
||||
"<h6>#Header 7</h6>\n",
|
||||
|
||||
"Hello\n# Header 1\nGoodbye\n",
|
||||
"<p>Hello</p>\n\n<h1>Header 1</h1>\n\n<p>Goodbye</p>\n",
|
||||
|
||||
"* List\n# Header\n* List\n",
|
||||
"<ul>\n<li><p>List</p>\n\n<h1>Header</h1></li>\n<li><p>List</p></li>\n</ul>\n",
|
||||
|
||||
"* List\n#Header\n* List\n",
|
||||
"<ul>\n<li><p>List</p>\n\n<h1>Header</h1></li>\n<li><p>List</p></li>\n</ul>\n",
|
||||
|
||||
"* List\n * Nested list\n # Nested header\n",
|
||||
"<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" +
|
||||
"<h1>Nested header</h1></li>\n</ul></li>\n</ul>\n",
|
||||
|
||||
"* List\n * Sublist\n Not a header\n ------\n",
|
||||
"<ul>\n<li>List\n\n<ul>\n<li>Sublist\nNot a header\n------</li>\n</ul></li>\n</ul>\n",
|
||||
}
|
||||
doTestsBlock(t, tests, 0)
|
||||
}
|
||||
|
||||
func TestPrefixHeaderSpaceExtension(t *testing.T) {
|
||||
var tests = []string{
|
||||
"# Header 1\n",
|
||||
"<h1>Header 1</h1>\n",
|
||||
|
||||
"## Header 2\n",
|
||||
"<h2>Header 2</h2>\n",
|
||||
|
||||
"### Header 3\n",
|
||||
"<h3>Header 3</h3>\n",
|
||||
|
||||
"#### Header 4\n",
|
||||
"<h4>Header 4</h4>\n",
|
||||
|
||||
"##### Header 5\n",
|
||||
"<h5>Header 5</h5>\n",
|
||||
|
||||
"###### Header 6\n",
|
||||
"<h6>Header 6</h6>\n",
|
||||
|
||||
"####### Header 7\n",
|
||||
"<p>####### Header 7</p>\n",
|
||||
|
||||
"#Header 1\n",
|
||||
"<p>#Header 1</p>\n",
|
||||
|
||||
"##Header 2\n",
|
||||
"<p>##Header 2</p>\n",
|
||||
|
||||
"###Header 3\n",
|
||||
"<p>###Header 3</p>\n",
|
||||
|
||||
"####Header 4\n",
|
||||
"<p>####Header 4</p>\n",
|
||||
|
||||
"#####Header 5\n",
|
||||
"<p>#####Header 5</p>\n",
|
||||
|
||||
"######Header 6\n",
|
||||
"<p>######Header 6</p>\n",
|
||||
|
||||
"#######Header 7\n",
|
||||
"<p>#######Header 7</p>\n",
|
||||
|
||||
"Hello\n# Header 1\nGoodbye\n",
|
||||
"<p>Hello</p>\n\n<h1>Header 1</h1>\n\n<p>Goodbye</p>\n",
|
||||
|
||||
"* List\n# Header\n* List\n",
|
||||
"<ul>\n<li><p>List</p>\n\n<h1>Header</h1></li>\n<li><p>List</p></li>\n</ul>\n",
|
||||
|
||||
"* List\n#Header\n* List\n",
|
||||
"<ul>\n<li>List\n#Header</li>\n<li>List</li>\n</ul>\n",
|
||||
|
||||
"* List\n * Nested list\n # Nested header\n",
|
||||
"<ul>\n<li><p>List</p>\n\n<ul>\n<li><p>Nested list</p>\n\n" +
|
||||
"<h1>Nested header</h1></li>\n</ul></li>\n</ul>\n",
|
||||
|
||||
"* List\n * Sublist\n Not a header\n ------\n",
|
||||
"<ul>\n<li>List\n\n<ul>\n<li>Sublist\nNot a header\n------</li>\n</ul></li>\n</ul>\n",
|
||||
}
|
||||
doTestsBlock(t, tests, EXTENSION_SPACE_HEADERS)
|
||||
}
|
|
@ -14,7 +14,7 @@ import (
|
|||
"testing"
|
||||
)
|
||||
|
||||
func runMarkdown(input string) string {
|
||||
func runMarkdownInline(input string) string {
|
||||
var extensions uint32
|
||||
extensions |= EXTENSION_NO_INTRA_EMPHASIS
|
||||
extensions |= EXTENSION_TABLES
|
||||
|
@ -35,11 +35,11 @@ func runMarkdown(input string) string {
|
|||
return string(Markdown([]byte(input), renderer, extensions))
|
||||
}
|
||||
|
||||
func doTests(t *testing.T, tests []string) {
|
||||
func doTestsInline(t *testing.T, tests []string) {
|
||||
for i := 0; i+1 < len(tests); i += 2 {
|
||||
input := tests[i]
|
||||
expected := tests[i+1]
|
||||
actual := runMarkdown(input)
|
||||
actual := runMarkdownInline(input)
|
||||
if actual != expected {
|
||||
t.Errorf("\nInput [%#v]\nExpected[%#v]\nActual [%#v]",
|
||||
input, expected, actual)
|
||||
|
@ -97,7 +97,7 @@ func TestEmphasis(t *testing.T) {
|
|||
"mix of *markers_\n",
|
||||
"<p>mix of *markers_</p>\n",
|
||||
}
|
||||
doTests(t, tests)
|
||||
doTestsInline(t, tests)
|
||||
}
|
||||
|
||||
func TestStrong(t *testing.T) {
|
||||
|
@ -150,7 +150,7 @@ func TestStrong(t *testing.T) {
|
|||
"mix of **markers__\n",
|
||||
"<p>mix of **markers__</p>\n",
|
||||
}
|
||||
doTests(t, tests)
|
||||
doTestsInline(t, tests)
|
||||
}
|
||||
|
||||
func TestEmphasisMix(t *testing.T) {
|
||||
|
@ -179,7 +179,7 @@ func TestEmphasisMix(t *testing.T) {
|
|||
"*improper **nesting* is** bad\n",
|
||||
"<p><em>improper **nesting</em> is** bad</p>\n",
|
||||
}
|
||||
doTests(t, tests)
|
||||
doTestsInline(t, tests)
|
||||
}
|
||||
|
||||
func TestStrikeThrough(t *testing.T) {
|
||||
|
@ -208,7 +208,7 @@ func TestStrikeThrough(t *testing.T) {
|
|||
"odd ~~number\nof~~ markers~~ here\n",
|
||||
"<p>odd <del>number\nof</del> markers~~ here</p>\n",
|
||||
}
|
||||
doTests(t, tests)
|
||||
doTestsInline(t, tests)
|
||||
}
|
||||
|
||||
func TestCodeSpan(t *testing.T) {
|
||||
|
@ -246,7 +246,7 @@ func TestCodeSpan(t *testing.T) {
|
|||
"```multiple ticks `with` ticks inside```\n",
|
||||
"<p><code>multiple ticks `with` ticks inside</code></p>\n",
|
||||
}
|
||||
doTests(t, tests)
|
||||
doTestsInline(t, tests)
|
||||
}
|
||||
|
||||
func TestLineBreak(t *testing.T) {
|
||||
|
@ -260,7 +260,7 @@ func TestLineBreak(t *testing.T) {
|
|||
"this has an \nextra space\n",
|
||||
"<p>this has an<br />\nextra space</p>\n",
|
||||
}
|
||||
doTests(t, tests)
|
||||
doTestsInline(t, tests)
|
||||
}
|
||||
|
||||
func TestInlineLink(t *testing.T) {
|
||||
|
@ -355,7 +355,7 @@ func TestInlineLink(t *testing.T) {
|
|||
"[link](/url/&query)\n",
|
||||
"<p><a href=\"/url/&query\">link</a></p>\n",
|
||||
}
|
||||
doTests(t, tests)
|
||||
doTestsInline(t, tests)
|
||||
}
|
||||
|
||||
func TestReferenceLink(t *testing.T) {
|
||||
|
@ -387,7 +387,7 @@ func TestReferenceLink(t *testing.T) {
|
|||
"[ref]\n [ref]: /url/ \"title\"\n",
|
||||
"<p><a href=\"/url/\" title=\"title\">ref</a></p>\n",
|
||||
}
|
||||
doTests(t, tests)
|
||||
doTestsInline(t, tests)
|
||||
}
|
||||
|
||||
func TestTags(t *testing.T) {
|
||||
|
@ -404,7 +404,7 @@ func TestTags(t *testing.T) {
|
|||
"a <singleton /> tag\n",
|
||||
"<p>a <singleton /> tag</p>\n",
|
||||
}
|
||||
doTests(t, tests)
|
||||
doTestsInline(t, tests)
|
||||
}
|
||||
|
||||
func TestAutoLink(t *testing.T) {
|
||||
|
@ -448,5 +448,5 @@ func TestAutoLink(t *testing.T) {
|
|||
"<p>even a > can be escaped <a href=\"http://new.com?q=>&etc\">" +
|
||||
"http://new.com?q=>&etc</a></p>\n",
|
||||
}
|
||||
doTests(t, tests)
|
||||
doTestsInline(t, tests)
|
||||
}
|
||||
|
|
|
@ -13,21 +13,15 @@ package blackfriday
|
|||
import (
|
||||
"io/ioutil"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func runReferenceMarkdown(input string) string {
|
||||
func runMarkdownReference(input string) string {
|
||||
renderer := HtmlRenderer(0)
|
||||
return string(Markdown([]byte(input), renderer, 0))
|
||||
}
|
||||
|
||||
// disregard dos vs. unix line endings differences
|
||||
func normalizeEol(s string) string {
|
||||
return strings.Replace(s, "\r\n", "\n", -1)
|
||||
}
|
||||
|
||||
func doFileTests(t *testing.T, files []string) {
|
||||
func doTestsReference(t *testing.T, files []string) {
|
||||
for _, basename := range files {
|
||||
fn := filepath.Join("upskirtref", basename+".text")
|
||||
actualdata, err := ioutil.ReadFile(fn)
|
||||
|
@ -43,8 +37,8 @@ func doFileTests(t *testing.T, files []string) {
|
|||
}
|
||||
|
||||
actual := string(actualdata)
|
||||
actual = normalizeEol(string(runReferenceMarkdown(actual)))
|
||||
expected := normalizeEol(string(expecteddata))
|
||||
actual = string(runMarkdownReference(actual))
|
||||
expected := string(expecteddata)
|
||||
if actual != expected {
|
||||
t.Errorf("\n [%#v]\nExpected[%#v]\nActual [%#v]",
|
||||
basename+".text", expected, actual)
|
||||
|
@ -77,5 +71,5 @@ func TestReference(t *testing.T) {
|
|||
"Tabs",
|
||||
"Tidyness",
|
||||
}
|
||||
doFileTests(t, files)
|
||||
doTestsReference(t, files)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user