blackfriday/inline_test.go
Martin Probst 11e042f6c1 Avoid raw mode parsing so that raw mode tags like <script> don't cause issues.
Certain tags like <script> but also <title> and others switch an HTML5 parser
into raw mode, which causes the rest of the HTML string to be always parsed as
text, including any elements or entities that we do want to support (e.g. <p>).

As we're going to escape any of the raw text elements anyway (it's e.g. script,
style, title, xmp, noframes, and a couple of others) we can just switch of raw
text parsing by disabling it after each starting tag.
2014-05-03 13:26:52 +02:00

904 lines
25 KiB
Go

//
// Blackfriday Markdown Processor
// Available at http://github.com/russross/blackfriday
//
// Copyright © 2011 Russ Ross <russ@russross.com>.
// Distributed under the Simplified BSD License.
// See README.md for details.
//
//
// Unit tests for inline parsing
//
package blackfriday
import (
"testing"
)
func runMarkdownInline(input string, extensions, htmlFlags int) string {
extensions |= EXTENSION_AUTOLINK
extensions |= EXTENSION_STRIKETHROUGH
htmlFlags |= HTML_USE_XHTML
renderer := HtmlRenderer(htmlFlags, "", "")
return string(Markdown([]byte(input), renderer, extensions))
}
func doTestsInline(t *testing.T, tests []string) {
doTestsInlineParam(t, tests, 0, 0)
}
func doSafeTestsInline(t *testing.T, tests []string) {
doTestsInlineParam(t, tests, 0, HTML_SAFELINK)
}
func doTestsInlineParam(t *testing.T, tests []string, extensions, htmlFlags int) {
// catch and report panics
var candidate string
/*
defer func() {
if err := recover(); err != nil {
t.Errorf("\npanic while processing [%#v] (%v)\n", candidate, err)
}
}()
*/
for i := 0; i+1 < len(tests); i += 2 {
input := tests[i]
candidate = input
expected := tests[i+1]
actual := runMarkdownInline(candidate, extensions, htmlFlags)
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]
_ = runMarkdownInline(candidate, extensions, htmlFlags)
}
}
}
}
}
func TestRawHtmlTag(t *testing.T) {
tests := []string{
"zz <style>p {}</style>\n",
"<p>zz &lt;style&gt;p {}&lt;/style&gt;</p>\n",
"zz <STYLE>p {}</STYLE>\n",
"<p>zz &lt;style&gt;p {}&lt;/style&gt;</p>\n",
"<SCRIPT>alert()</SCRIPT>\n",
"<p>&lt;script&gt;alert()&lt;/script&gt;</p>\n",
"zz <SCRIPT>alert()</SCRIPT>\n",
"<p>zz &lt;script&gt;alert()&lt;/script&gt;</p>\n",
"zz <script>alert()</script>\n",
"<p>zz &lt;script&gt;alert()&lt;/script&gt;</p>\n",
" <script>alert()</script>\n",
"<p>&lt;script&gt;alert()&lt;/script&gt;</p>\n",
"<script>alert()</script>\n",
"&lt;script&gt;alert()&lt;/script&gt;\n",
"<script src='foo'></script>\n",
"&lt;script src=&#39;foo&#39;&gt;&lt;/script&gt;\n",
"<script src='a>b'></script>\n",
"&lt;script src=&#39;a&gt;b&#39;&gt;&lt;/script&gt;\n",
"zz <script src='foo'></script>\n",
"<p>zz &lt;script src=&#39;foo&#39;&gt;&lt;/script&gt;</p>\n",
"zz <script src=foo></script>\n",
"<p>zz &lt;script src=foo&gt;&lt;/script&gt;</p>\n",
`<script><script src="http://example.com/exploit.js"></SCRIPT></script>`,
"&lt;script&gt;&lt;script src=&#34;http://example.com/exploit.js&#34;&gt;&lt;/script&gt;&lt;/script&gt;\n",
`'';!--"<XSS>=&{()}`,
"<p>&#39;&#39;;!--&#34;&lt;xss&gt;=&amp;{()}</p>\n",
"<SCRIPT SRC=http://ha.ckers.org/xss.js></SCRIPT>",
"<p>&lt;script SRC=http://ha.ckers.org/xss.js&gt;&lt;/script&gt;</p>\n",
"<SCRIPT \nSRC=http://ha.ckers.org/xss.js></SCRIPT>",
"<p>&lt;script \nSRC=http://ha.ckers.org/xss.js&gt;&lt;/script&gt;</p>\n",
`<IMG SRC="javascript:alert('XSS');">`,
"<p><img></p>\n",
"<IMG SRC=javascript:alert('XSS')>",
"<p><img></p>\n",
"<IMG SRC=JaVaScRiPt:alert('XSS')>",
"<p><img></p>\n",
"<IMG SRC=`javascript:alert(\"RSnake says, 'XSS'\")`>",
"<p><img></p>\n",
`<a onmouseover="alert(document.cookie)">xss link</a>`,
"<p><a>xss link</a></p>\n",
"<a onmouseover=alert(document.cookie)>xss link</a>",
"<p><a>xss link</a></p>\n",
`<IMG """><SCRIPT>alert("XSS")</SCRIPT>">`,
"<p><img>&lt;script&gt;alert(&#34;XSS&#34;)&lt;/script&gt;&#34;&gt;</p>\n",
"<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>",
"<p><img></p>\n",
`<IMG SRC=# onmouseover="alert('xxs')">`,
"<p><img></p>\n",
`<IMG SRC= onmouseover="alert('xxs')">`,
"<p><img></p>\n",
`<IMG onmouseover="alert('xxs')">`,
"<p><img></p>\n",
"<IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>",
"<p><img></p>\n",
"<IMG SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>",
"<p><img></p>\n",
"<IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>",
"<p><img></p>\n",
`<IMG SRC="javascriptascript:alert('XSS');">`,
"<p><img></p>\n",
`<IMG SRC="jav&#x09;ascript:alert('XSS');">`,
"<p><img></p>\n",
`<IMG SRC="jav&#x0A;ascript:alert('XSS');">`,
"<p><img></p>\n",
`<IMG SRC="jav&#x0D;ascript:alert('XSS');">`,
"<p><img></p>\n",
`<IMG SRC=" &#14; javascript:alert('XSS');">`,
"<p><img></p>\n",
`<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>`,
"<p>&lt;script/XSS SRC=&#34;http://ha.ckers.org/xss.js&#34;&gt;&lt;/script&gt;</p>\n",
"<BODY onload!#$%&()*~+-_.,:;?@[/|\\]^`=alert(\"XSS\")>",
"<p>&lt;body onload!#$%&amp;()*~+-_.,:;?@[/|\\]^`=alert(&#34;XSS&#34;)&gt;</p>\n",
`<SCRIPT/SRC="http://ha.ckers.org/xss.js"></SCRIPT>`,
"<p>&lt;script/SRC=&#34;http://ha.ckers.org/xss.js&#34;&gt;&lt;/script&gt;</p>\n",
`<<SCRIPT>alert("XSS");//<</SCRIPT>`,
"<p>&lt;&lt;script&gt;alert(&#34;XSS&#34;);//&lt;&lt;/script&gt;</p>\n",
"<SCRIPT SRC=http://ha.ckers.org/xss.js?< B >",
"<p>&lt;script SRC=http://ha.ckers.org/xss.js?&lt; B &gt;</p>\n",
"<SCRIPT SRC=//ha.ckers.org/.j>",
"<p>&lt;script SRC=//ha.ckers.org/.j&gt;</p>\n",
`<IMG SRC="javascript:alert('XSS')"`,
"<p>&lt;IMG SRC=&#34;javascript:alert(&#39;XSS&#39;)&#34;</p>\n",
"<iframe src=http://ha.ckers.org/scriptlet.html <",
// The hyperlink gets linkified, the <iframe> gets escaped
"<p>&lt;iframe src=<a href=\"http://ha.ckers.org/scriptlet.html\">http://ha.ckers.org/scriptlet.html</a> &lt;</p>\n",
// Additonal token types: SelfClosing, Comment, DocType.
"<br/>",
"<p><br></p>\n",
"<!-- Comment -->",
"<!-- Comment -->\n",
"<!DOCTYPE test>",
"<p>&lt;!DOCTYPE test&gt;</p>\n",
"<hr>",
"<hr>\n",
}
doTestsInlineParam(t, tests, 0, HTML_SKIP_STYLE|HTML_SANITIZE_OUTPUT)
}
func TestQuoteEscaping(t *testing.T) {
tests := []string{
// Make sure quotes are transported correctly (different entities or
// unicode, but correct semantics)
"<p>Here are some &quot;quotes&quot;.</p>\n",
"<p>Here are some &#34;quotes&#34;.</p>\n",
"<p>Here are some &ldquo;quotes&rdquo;.</p>\n",
"<p>Here are some \u201Cquotes\u201D.</p>\n",
// Within a <script> tag, content gets parsed by the raw text parsing rules.
// This test makes sure we correctly disable those parsing rules and do not
// escape e.g. the closing </p>.
`Here are <script> some "quotes".`,
"<p>Here are &lt;script&gt; some &#34;quotes&#34;.</p>\n",
// Same test for an unknown element that does not switch into raw mode.
`Here are <eviltag> some "quotes".`,
"<p>Here are &lt;eviltag&gt; some &#34;quotes&#34;.</p>\n",
}
doTestsInlineParam(t, tests, 0, HTML_SKIP_STYLE|HTML_SANITIZE_OUTPUT)
}
func TestEmphasis(t *testing.T) {
var tests = []string{
"nothing inline\n",
"<p>nothing inline</p>\n",
"simple *inline* test\n",
"<p>simple <em>inline</em> test</p>\n",
"*at the* beginning\n",
"<p><em>at the</em> beginning</p>\n",
"at the *end*\n",
"<p>at the <em>end</em></p>\n",
"*try two* in *one line*\n",
"<p><em>try two</em> in <em>one line</em></p>\n",
"over *two\nlines* test\n",
"<p>over <em>two\nlines</em> test</p>\n",
"odd *number of* markers* here\n",
"<p>odd <em>number of</em> markers* here</p>\n",
"odd *number\nof* markers* here\n",
"<p>odd <em>number\nof</em> markers* here</p>\n",
"simple _inline_ test\n",
"<p>simple <em>inline</em> test</p>\n",
"_at the_ beginning\n",
"<p><em>at the</em> beginning</p>\n",
"at the _end_\n",
"<p>at the <em>end</em></p>\n",
"_try two_ in _one line_\n",
"<p><em>try two</em> in <em>one line</em></p>\n",
"over _two\nlines_ test\n",
"<p>over <em>two\nlines</em> test</p>\n",
"odd _number of_ markers_ here\n",
"<p>odd <em>number of</em> markers_ here</p>\n",
"odd _number\nof_ markers_ here\n",
"<p>odd <em>number\nof</em> markers_ here</p>\n",
"mix of *markers_\n",
"<p>mix of *markers_</p>\n",
}
doTestsInline(t, tests)
}
func TestStrong(t *testing.T) {
var tests = []string{
"nothing inline\n",
"<p>nothing inline</p>\n",
"simple **inline** test\n",
"<p>simple <strong>inline</strong> test</p>\n",
"**at the** beginning\n",
"<p><strong>at the</strong> beginning</p>\n",
"at the **end**\n",
"<p>at the <strong>end</strong></p>\n",
"**try two** in **one line**\n",
"<p><strong>try two</strong> in <strong>one line</strong></p>\n",
"over **two\nlines** test\n",
"<p>over <strong>two\nlines</strong> test</p>\n",
"odd **number of** markers** here\n",
"<p>odd <strong>number of</strong> markers** here</p>\n",
"odd **number\nof** markers** here\n",
"<p>odd <strong>number\nof</strong> markers** here</p>\n",
"simple __inline__ test\n",
"<p>simple <strong>inline</strong> test</p>\n",
"__at the__ beginning\n",
"<p><strong>at the</strong> beginning</p>\n",
"at the __end__\n",
"<p>at the <strong>end</strong></p>\n",
"__try two__ in __one line__\n",
"<p><strong>try two</strong> in <strong>one line</strong></p>\n",
"over __two\nlines__ test\n",
"<p>over <strong>two\nlines</strong> test</p>\n",
"odd __number of__ markers__ here\n",
"<p>odd <strong>number of</strong> markers__ here</p>\n",
"odd __number\nof__ markers__ here\n",
"<p>odd <strong>number\nof</strong> markers__ here</p>\n",
"mix of **markers__\n",
"<p>mix of **markers__</p>\n",
}
doTestsInline(t, tests)
}
func TestEmphasisMix(t *testing.T) {
var tests = []string{
"***triple emphasis***\n",
"<p><strong><em>triple emphasis</em></strong></p>\n",
"***triple\nemphasis***\n",
"<p><strong><em>triple\nemphasis</em></strong></p>\n",
"___triple emphasis___\n",
"<p><strong><em>triple emphasis</em></strong></p>\n",
"***triple emphasis___\n",
"<p>***triple emphasis___</p>\n",
"*__triple emphasis__*\n",
"<p><em><strong>triple emphasis</strong></em></p>\n",
"__*triple emphasis*__\n",
"<p><strong><em>triple emphasis</em></strong></p>\n",
"**improper *nesting** is* bad\n",
"<p><strong>improper *nesting</strong> is* bad</p>\n",
"*improper **nesting* is** bad\n",
"<p><em>improper **nesting</em> is** bad</p>\n",
}
doTestsInline(t, tests)
}
func TestStrikeThrough(t *testing.T) {
var tests = []string{
"nothing inline\n",
"<p>nothing inline</p>\n",
"simple ~~inline~~ test\n",
"<p>simple <del>inline</del> test</p>\n",
"~~at the~~ beginning\n",
"<p><del>at the</del> beginning</p>\n",
"at the ~~end~~\n",
"<p>at the <del>end</del></p>\n",
"~~try two~~ in ~~one line~~\n",
"<p><del>try two</del> in <del>one line</del></p>\n",
"over ~~two\nlines~~ test\n",
"<p>over <del>two\nlines</del> test</p>\n",
"odd ~~number of~~ markers~~ here\n",
"<p>odd <del>number of</del> markers~~ here</p>\n",
"odd ~~number\nof~~ markers~~ here\n",
"<p>odd <del>number\nof</del> markers~~ here</p>\n",
}
doTestsInline(t, tests)
}
func TestCodeSpan(t *testing.T) {
var tests = []string{
"`source code`\n",
"<p><code>source code</code></p>\n",
"` source code with spaces `\n",
"<p><code>source code with spaces</code></p>\n",
"` source code with spaces `not here\n",
"<p><code>source code with spaces</code>not here</p>\n",
"a `single marker\n",
"<p>a `single marker</p>\n",
"a single multi-tick marker with ``` no text\n",
"<p>a single multi-tick marker with ``` no text</p>\n",
"markers with ` ` a space\n",
"<p>markers with a space</p>\n",
"`source code` and a `stray\n",
"<p><code>source code</code> and a `stray</p>\n",
"`source *with* _awkward characters_ in it`\n",
"<p><code>source *with* _awkward characters_ in it</code></p>\n",
"`split over\ntwo lines`\n",
"<p><code>split over\ntwo lines</code></p>\n",
"```multiple ticks``` for the marker\n",
"<p><code>multiple ticks</code> for the marker</p>\n",
"```multiple ticks `with` ticks inside```\n",
"<p><code>multiple ticks `with` ticks inside</code></p>\n",
}
doTestsInline(t, tests)
}
func TestLineBreak(t *testing.T) {
var tests = []string{
"this line \nhas a break\n",
"<p>this line<br />\nhas a break</p>\n",
"this line \ndoes not\n",
"<p>this line\ndoes not</p>\n",
"this has an \nextra space\n",
"<p>this has an<br />\nextra space</p>\n",
}
doTestsInline(t, tests)
}
func TestInlineLink(t *testing.T) {
var tests = []string{
"[foo](/bar/)\n",
"<p><a href=\"/bar/\">foo</a></p>\n",
"[foo with a title](/bar/ \"title\")\n",
"<p><a href=\"/bar/\" title=\"title\">foo with a title</a></p>\n",
"[foo with a title](/bar/\t\"title\")\n",
"<p><a href=\"/bar/\" title=\"title\">foo with a title</a></p>\n",
"[foo with a title](/bar/ \"title\" )\n",
"<p><a href=\"/bar/\" title=\"title\">foo with a title</a></p>\n",
"[foo with a title](/bar/ title with no quotes)\n",
"<p><a href=\"/bar/ title with no quotes\">foo with a title</a></p>\n",
"[foo]()\n",
"<p>[foo]()</p>\n",
"![foo](/bar/)\n",
"<p><img src=\"/bar/\" alt=\"foo\" />\n</p>\n",
"![foo with a title](/bar/ \"title\")\n",
"<p><img src=\"/bar/\" alt=\"foo with a title\" title=\"title\" />\n</p>\n",
"![foo with a title](/bar/\t\"title\")\n",
"<p><img src=\"/bar/\" alt=\"foo with a title\" title=\"title\" />\n</p>\n",
"![foo with a title](/bar/ \"title\" )\n",
"<p><img src=\"/bar/\" alt=\"foo with a title\" title=\"title\" />\n</p>\n",
"![foo with a title](/bar/ title with no quotes)\n",
"<p><img src=\"/bar/ title with no quotes\" alt=\"foo with a title\" />\n</p>\n",
"![foo]()\n",
"<p>![foo]()</p>\n",
"[a link]\t(/with_a_tab/)\n",
"<p><a href=\"/with_a_tab/\">a link</a></p>\n",
"[a link] (/with_spaces/)\n",
"<p><a href=\"/with_spaces/\">a link</a></p>\n",
"[text (with) [[nested] (brackets)]](/url/)\n",
"<p><a href=\"/url/\">text (with) [[nested] (brackets)]</a></p>\n",
"[text (with) [broken nested] (brackets)]](/url/)\n",
"<p>[text (with) <a href=\"brackets\">broken nested</a>]](/url/)</p>\n",
"[text\nwith a newline](/link/)\n",
"<p><a href=\"/link/\">text\nwith a newline</a></p>\n",
"[text in brackets] [followed](/by a link/)\n",
"<p>[text in brackets] <a href=\"/by a link/\">followed</a></p>\n",
"[link with\\] a closing bracket](/url/)\n",
"<p><a href=\"/url/\">link with] a closing bracket</a></p>\n",
"[link with\\[ an opening bracket](/url/)\n",
"<p><a href=\"/url/\">link with[ an opening bracket</a></p>\n",
"[link with\\) a closing paren](/url/)\n",
"<p><a href=\"/url/\">link with) a closing paren</a></p>\n",
"[link with\\( an opening paren](/url/)\n",
"<p><a href=\"/url/\">link with( an opening paren</a></p>\n",
"[link]( with whitespace)\n",
"<p><a href=\"with whitespace\">link</a></p>\n",
"[link]( with whitespace )\n",
"<p><a href=\"with whitespace\">link</a></p>\n",
"[![image](someimage)](with image)\n",
"<p><a href=\"with image\"><img src=\"someimage\" alt=\"image\" />\n</a></p>\n",
"[link](url \"one quote)\n",
"<p><a href=\"url &quot;one quote\">link</a></p>\n",
"[link](url 'one quote)\n",
"<p><a href=\"url 'one quote\">link</a></p>\n",
"[link](<url>)\n",
"<p><a href=\"url\">link</a></p>\n",
"[link & ampersand](/url/)\n",
"<p><a href=\"/url/\">link &amp; ampersand</a></p>\n",
"[link &amp; ampersand](/url/)\n",
"<p><a href=\"/url/\">link &amp; ampersand</a></p>\n",
"[link](/url/&query)\n",
"<p><a href=\"/url/&amp;query\">link</a></p>\n",
"[[t]](/t)\n",
"<p><a href=\"/t\">[t]</a></p>\n",
}
doTestsInline(t, tests)
}
func TestNofollowLink(t *testing.T) {
var tests = []string{
"[foo](http://bar.com/foo/)\n",
"<p><a href=\"http://bar.com/foo/\" rel=\"nofollow\">foo</a></p>\n",
}
doTestsInlineParam(t, tests, 0, HTML_SAFELINK|HTML_NOFOLLOW_LINKS|HTML_SANITIZE_OUTPUT)
// HTML_SANITIZE_OUTPUT won't allow relative links, so test that separately:
tests = []string{
"[foo](/bar/)\n",
"<p><a href=\"/bar/\">foo</a></p>\n",
}
doTestsInlineParam(t, tests, 0, HTML_SAFELINK|HTML_NOFOLLOW_LINKS)
}
func TestHrefTargetBlank(t *testing.T) {
var tests = []string{
// internal link
"[foo](/bar/)\n",
"<p><a href=\"/bar/\">foo</a></p>\n",
"[foo](http://example.com)\n",
"<p><a href=\"http://example.com\" target=\"_blank\">foo</a></p>\n",
}
doTestsInlineParam(t, tests, 0, HTML_SAFELINK|HTML_HREF_TARGET_BLANK)
}
func TestSafeInlineLink(t *testing.T) {
var tests = []string{
"[foo](/bar/)\n",
"<p><a href=\"/bar/\">foo</a></p>\n",
"[foo](http://bar/)\n",
"<p><a href=\"http://bar/\">foo</a></p>\n",
"[foo](https://bar/)\n",
"<p><a href=\"https://bar/\">foo</a></p>\n",
"[foo](ftp://bar/)\n",
"<p><a href=\"ftp://bar/\">foo</a></p>\n",
"[foo](mailto://bar/)\n",
"<p><a href=\"mailto://bar/\">foo</a></p>\n",
// Not considered safe
"[foo](baz://bar/)\n",
"<p><tt>foo</tt></p>\n",
}
doSafeTestsInline(t, tests)
}
func TestReferenceLink(t *testing.T) {
var tests = []string{
"[link][ref]\n",
"<p>[link][ref]</p>\n",
"[link][ref]\n [ref]: /url/ \"title\"\n",
"<p><a href=\"/url/\" title=\"title\">link</a></p>\n",
"[link][ref]\n [ref]: /url/\n",
"<p><a href=\"/url/\">link</a></p>\n",
" [ref]: /url/\n",
"",
" [ref]: /url/\n[ref2]: /url/\n [ref3]: /url/\n",
"",
" [ref]: /url/\n[ref2]: /url/\n [ref3]: /url/\n [4spaces]: /url/\n",
"<pre><code>[4spaces]: /url/\n</code></pre>\n",
"[hmm](ref2)\n [ref]: /url/\n[ref2]: /url/\n [ref3]: /url/\n",
"<p><a href=\"ref2\">hmm</a></p>\n",
"[ref]\n",
"<p>[ref]</p>\n",
"[ref]\n [ref]: /url/ \"title\"\n",
"<p><a href=\"/url/\" title=\"title\">ref</a></p>\n",
}
doTestsInline(t, tests)
}
func TestTags(t *testing.T) {
var tests = []string{
"a <span>tag</span>\n",
"<p>a <span>tag</span></p>\n",
"<span>tag</span>\n",
"<p><span>tag</span></p>\n",
"<span>mismatch</spandex>\n",
"<p><span>mismatch</spandex></p>\n",
"a <singleton /> tag\n",
"<p>a <singleton /> tag</p>\n",
}
doTestsInline(t, tests)
}
func TestAutoLink(t *testing.T) {
var tests = []string{
"http://foo.com/\n",
"<p><a href=\"http://foo.com/\">http://foo.com/</a></p>\n",
"1 http://foo.com/\n",
"<p>1 <a href=\"http://foo.com/\">http://foo.com/</a></p>\n",
"1http://foo.com/\n",
"<p>1<a href=\"http://foo.com/\">http://foo.com/</a></p>\n",
"1.http://foo.com/\n",
"<p>1.<a href=\"http://foo.com/\">http://foo.com/</a></p>\n",
"1. http://foo.com/\n",
"<ol>\n<li><a href=\"http://foo.com/\">http://foo.com/</a></li>\n</ol>\n",
"-http://foo.com/\n",
"<p>-<a href=\"http://foo.com/\">http://foo.com/</a></p>\n",
"- http://foo.com/\n",
"<ul>\n<li><a href=\"http://foo.com/\">http://foo.com/</a></li>\n</ul>\n",
"_http://foo.com/\n",
"<p>_<a href=\"http://foo.com/\">http://foo.com/</a></p>\n",
"令狐http://foo.com/\n",
"<p>令狐<a href=\"http://foo.com/\">http://foo.com/</a></p>\n",
"令狐 http://foo.com/\n",
"<p>令狐 <a href=\"http://foo.com/\">http://foo.com/</a></p>\n",
"ahttp://foo.com/\n",
"<p>ahttp://foo.com/</p>\n",
">http://foo.com/\n",
"<blockquote>\n<p><a href=\"http://foo.com/\">http://foo.com/</a></p>\n</blockquote>\n",
"> http://foo.com/\n",
"<blockquote>\n<p><a href=\"http://foo.com/\">http://foo.com/</a></p>\n</blockquote>\n",
"go to <http://foo.com/>\n",
"<p>go to <a href=\"http://foo.com/\">http://foo.com/</a></p>\n",
"a secure <https://link.org>\n",
"<p>a secure <a href=\"https://link.org\">https://link.org</a></p>\n",
"an email <mailto:some@one.com>\n",
"<p>an email <a href=\"mailto:some@one.com\">some@one.com</a></p>\n",
"an email <mailto://some@one.com>\n",
"<p>an email <a href=\"mailto://some@one.com\">some@one.com</a></p>\n",
"an email <some@one.com>\n",
"<p>an email <a href=\"mailto:some@one.com\">some@one.com</a></p>\n",
"an ftp <ftp://old.com>\n",
"<p>an ftp <a href=\"ftp://old.com\">ftp://old.com</a></p>\n",
"an ftp <ftp:old.com>\n",
"<p>an ftp <a href=\"ftp:old.com\">ftp:old.com</a></p>\n",
"a link with <http://new.com?query=foo&bar>\n",
"<p>a link with <a href=\"http://new.com?query=foo&amp;bar\">" +
"http://new.com?query=foo&amp;bar</a></p>\n",
"quotes mean a tag <http://new.com?query=\"foo\"&bar>\n",
"<p>quotes mean a tag <http://new.com?query=\"foo\"&bar></p>\n",
"quotes mean a tag <http://new.com?query='foo'&bar>\n",
"<p>quotes mean a tag <http://new.com?query='foo'&bar></p>\n",
"unless escaped <http://new.com?query=\\\"foo\\\"&bar>\n",
"<p>unless escaped <a href=\"http://new.com?query=&quot;foo&quot;&amp;bar\">" +
"http://new.com?query=&quot;foo&quot;&amp;bar</a></p>\n",
"even a > can be escaped <http://new.com?q=\\>&etc>\n",
"<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",
"<a href=\"http://fancy.com\">http://fancy.com</a>\n",
"<p><a href=\"http://fancy.com\">http://fancy.com</a></p>\n",
"<a href=\"http://fancy.com\">This is a link</a>\n",
"<p><a href=\"http://fancy.com\">This is a link</a></p>\n",
"<a href=\"http://www.fancy.com/A_B.pdf\">http://www.fancy.com/A_B.pdf</a>\n",
"<p><a href=\"http://www.fancy.com/A_B.pdf\">http://www.fancy.com/A_B.pdf</a></p>\n",
"(<a href=\"http://www.fancy.com/A_B\">http://www.fancy.com/A_B</a> (\n",
"<p>(<a href=\"http://www.fancy.com/A_B\">http://www.fancy.com/A_B</a> (</p>\n",
"(<a href=\"http://www.fancy.com/A_B\">http://www.fancy.com/A_B</a> (part two: <a href=\"http://www.fancy.com/A_B\">http://www.fancy.com/A_B</a>)).\n",
"<p>(<a href=\"http://www.fancy.com/A_B\">http://www.fancy.com/A_B</a> (part two: <a href=\"http://www.fancy.com/A_B\">http://www.fancy.com/A_B</a>)).</p>\n",
"http://www.foo.com<br />\n",
"<p><a href=\"http://www.foo.com\">http://www.foo.com</a><br /></p>\n",
"http://foo.com/viewtopic.php?f=18&amp;t=297",
"<p><a href=\"http://foo.com/viewtopic.php?f=18&amp;t=297\">http://foo.com/viewtopic.php?f=18&amp;t=297</a></p>\n",
"http://foo.com/viewtopic.php?param=&quot;18&quot;zz",
"<p><a href=\"http://foo.com/viewtopic.php?param=&quot;18&quot;zz\">http://foo.com/viewtopic.php?param=&quot;18&quot;zz</a></p>\n",
"http://foo.com/viewtopic.php?param=&quot;18&quot;",
"<p><a href=\"http://foo.com/viewtopic.php?param=&quot;18&quot;\">http://foo.com/viewtopic.php?param=&quot;18&quot;</a></p>\n",
}
doTestsInline(t, tests)
}
func TestFootnotes(t *testing.T) {
tests := []string{
"testing footnotes.[^a]\n\n[^a]: This is the note\n",
`<p>testing footnotes.<sup class="footnote-ref" id="fnref:a"><a rel="footnote" href="#fn:a">1</a></sup></p>
<div class="footnotes">
<hr />
<ol>
<li id="fn:a">This is the note
</li>
</ol>
</div>
`,
`testing long[^b] notes.
[^b]: Paragraph 1
Paragraph 2
` + "```\n\tsome code\n\t```" + `
Paragraph 3
No longer in the footnote
`,
`<p>testing long<sup class="footnote-ref" id="fnref:b"><a rel="footnote" href="#fn:b">1</a></sup> notes.</p>
<p>No longer in the footnote</p>
<div class="footnotes">
<hr />
<ol>
<li id="fn:b"><p>Paragraph 1</p>
<p>Paragraph 2</p>
<p><code>
some code
</code></p>
<p>Paragraph 3</p>
</li>
</ol>
</div>
`,
`testing[^c] multiple[^d] notes.
[^c]: this is [note] c
omg
[^d]: this is note d
what happens here
[note]: /link/c
`,
`<p>testing<sup class="footnote-ref" id="fnref:c"><a rel="footnote" href="#fn:c">1</a></sup> multiple<sup class="footnote-ref" id="fnref:d"><a rel="footnote" href="#fn:d">2</a></sup> notes.</p>
<p>omg</p>
<p>what happens here</p>
<div class="footnotes">
<hr />
<ol>
<li id="fn:c">this is <a href="/link/c">note</a> c
</li>
<li id="fn:d">this is note d
</li>
</ol>
</div>
`,
"testing inline^[this is the note] notes.\n",
`<p>testing inline<sup class="footnote-ref" id="fnref:this-is-the-note"><a rel="footnote" href="#fn:this-is-the-note">1</a></sup> notes.</p>
<div class="footnotes">
<hr />
<ol>
<li id="fn:this-is-the-note">this is the note</li>
</ol>
</div>
`,
"testing multiple[^1] types^[inline note] of notes[^2]\n\n[^2]: the second deferred note\n[^1]: the first deferred note\n\n\twhich happens to be a block\n",
`<p>testing multiple<sup class="footnote-ref" id="fnref:1"><a rel="footnote" href="#fn:1">1</a></sup> types<sup class="footnote-ref" id="fnref:inline-note"><a rel="footnote" href="#fn:inline-note">2</a></sup> of notes<sup class="footnote-ref" id="fnref:2"><a rel="footnote" href="#fn:2">3</a></sup></p>
<div class="footnotes">
<hr />
<ol>
<li id="fn:1"><p>the first deferred note</p>
<p>which happens to be a block</p>
</li>
<li id="fn:inline-note">inline note</li>
<li id="fn:2">the second deferred note
</li>
</ol>
</div>
`,
`This is a footnote[^1]^[and this is an inline footnote]
[^1]: the footnote text.
may be multiple paragraphs.
`,
`<p>This is a footnote<sup class="footnote-ref" id="fnref:1"><a rel="footnote" href="#fn:1">1</a></sup><sup class="footnote-ref" id="fnref:and-this-is-an-i"><a rel="footnote" href="#fn:and-this-is-an-i">2</a></sup></p>
<div class="footnotes">
<hr />
<ol>
<li id="fn:1"><p>the footnote text.</p>
<p>may be multiple paragraphs.</p>
</li>
<li id="fn:and-this-is-an-i">and this is an inline footnote</li>
</ol>
</div>
`,
"empty footnote[^]\n\n[^]: fn text",
"<p>empty footnote<sup class=\"footnote-ref\" id=\"fnref:\"><a rel=\"footnote\" href=\"#fn:\">1</a></sup></p>\n<div class=\"footnotes\">\n\n<hr />\n\n<ol>\n<li id=\"fn:\">fn text\n</li>\n</ol>\n</div>\n",
}
doTestsInlineParam(t, tests, EXTENSION_FOOTNOTES, 0)
}