fixed headers nested in lists, added prefix header unit tests

This commit is contained in:
Russ Ross 2011-06-27 10:13:13 -06:00
parent e22e43bf76
commit 3af64a90ad
4 changed files with 205 additions and 38 deletions

View File

@ -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
View 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)
}

View File

@ -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/&amp;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 &gt; can be escaped <a href=\"http://new.com?q=&gt;&amp;etc\">" +
"http://new.com?q=&gt;&amp;etc</a></p>\n",
}
doTests(t, tests)
doTestsInline(t, tests)
}

View File

@ -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)
}