2011-06-02 02:17:17 +08:00
//
2011-06-28 10:11:32 +08:00
// Blackfriday Markdown Processor
// Available at http://github.com/russross/blackfriday
//
// Copyright © 2011 Russ Ross <russ@russross.com>.
2011-06-29 01:30:10 +08:00
// Distributed under the Simplified BSD License.
2011-06-28 10:11:32 +08:00
// See README.md for details.
2011-06-02 02:17:17 +08:00
//
//
// Unit tests for inline parsing
//
package blackfriday
import (
"testing"
)
2013-04-14 03:18:14 +08:00
func runMarkdownInline ( input string , extensions , htmlFlags int ) string {
2011-06-02 02:17:17 +08:00
extensions |= EXTENSION_AUTOLINK
extensions |= EXTENSION_STRIKETHROUGH
2011-06-29 05:55:27 +08:00
htmlFlags |= HTML_USE_XHTML
2011-06-02 02:17:17 +08:00
2011-06-30 00:08:56 +08:00
renderer := HtmlRenderer ( htmlFlags , "" , "" )
2011-06-02 02:17:17 +08:00
return string ( Markdown ( [ ] byte ( input ) , renderer , extensions ) )
}
2011-06-28 00:13:13 +08:00
func doTestsInline ( t * testing . T , tests [ ] string ) {
2013-04-14 03:18:14 +08:00
doTestsInlineParam ( t , tests , 0 , 0 )
}
2013-12-19 18:00:47 +08:00
func doSafeTestsInline ( t * testing . T , tests [ ] string ) {
doTestsInlineParam ( t , tests , 0 , HTML_SAFELINK )
}
2013-04-14 03:18:14 +08:00
func doTestsInlineParam ( t * testing . T , tests [ ] string , extensions , htmlFlags int ) {
2011-07-04 00:51:07 +08:00
// catch and report panics
var candidate string
2013-06-26 23:57:51 +08:00
/ *
defer func ( ) {
if err := recover ( ) ; err != nil {
t . Errorf ( "\npanic while processing [%#v] (%v)\n" , candidate , err )
}
} ( )
* /
2011-07-04 00:51:07 +08:00
2011-06-02 02:17:17 +08:00
for i := 0 ; i + 1 < len ( tests ) ; i += 2 {
input := tests [ i ]
2011-07-04 00:51:07 +08:00
candidate = input
2011-06-02 02:17:17 +08:00
expected := tests [ i + 1 ]
2013-04-14 03:18:14 +08:00
actual := runMarkdownInline ( candidate , extensions , htmlFlags )
2011-06-02 02:17:17 +08:00
if actual != expected {
t . Errorf ( "\nInput [%#v]\nExpected[%#v]\nActual [%#v]" ,
2011-07-04 00:51:07 +08:00
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 ]
2013-04-14 03:18:14 +08:00
_ = runMarkdownInline ( candidate , extensions , htmlFlags )
2011-07-04 00:51:07 +08:00
}
}
2011-06-02 02:17:17 +08:00
}
}
}
2013-04-14 03:21:47 +08:00
func TestRawHtmlTag ( t * testing . T ) {
tests := [ ] string {
"zz <style>p {}</style>\n" ,
"<p>zz p {}</p>\n" ,
2013-04-14 03:34:37 +08:00
"zz <STYLE>p {}</STYLE>\n" ,
"<p>zz p {}</p>\n" ,
2013-04-14 03:57:16 +08:00
"<SCRIPT>alert()</SCRIPT>\n" ,
"<p>alert()</p>\n" ,
"zz <SCRIPT>alert()</SCRIPT>\n" ,
"<p>zz alert()</p>\n" ,
"zz <script>alert()</script>\n" ,
"<p>zz alert()</p>\n" ,
" <script>alert()</script>\n" ,
"<p>alert()</p>\n" ,
2013-04-14 04:24:30 +08:00
"<script>alert()</script>\n" ,
2014-01-22 07:14:35 +08:00
"alert()\n" ,
2013-04-14 06:42:47 +08:00
2013-04-18 08:15:47 +08:00
"<script src='foo'></script>\n" ,
2014-01-22 07:14:35 +08:00
"\n" ,
"<script src='a>b'></script>\n" ,
"\n" ,
2013-04-18 08:15:47 +08:00
2013-04-14 06:42:47 +08:00
"zz <script src='foo'></script>\n" ,
"<p>zz </p>\n" ,
"zz <script src=foo></script>\n" ,
"<p>zz </p>\n" ,
2014-01-22 07:14:35 +08:00
` <script><script src="http://example.com/exploit.js"></SCRIPT></script> ` ,
"\n" ,
` '';!--"<XSS>=& { ()} ` ,
"<p>'';!--"=&{()}</p>\n" ,
"<SCRIPT SRC=http://ha.ckers.org/xss.js></SCRIPT>" ,
"<p></p>\n" ,
"<SCRIPT \nSRC=http://ha.ckers.org/xss.js></SCRIPT>" ,
"<p></p>\n" ,
` <IMG SRC="javascript:alert('XSS');"> ` ,
"<p></p>\n" ,
"<IMG SRC=javascript:alert('XSS')>" ,
"<p></p>\n" ,
"<IMG SRC=JaVaScRiPt:alert('XSS')>" ,
"<p></p>\n" ,
"<IMG SRC=`javascript:alert(\"RSnake says, 'XSS'\")`>" ,
"<p></p>\n" ,
` <a onmouseover="alert(document.cookie)">xss link</a> ` ,
"<p>xss link</a></p>\n" ,
"<a onmouseover=alert(document.cookie)>xss link</a>" ,
"<p>xss link</a></p>\n" ,
// XXX: this doesn't pass yet
//`<IMG """><SCRIPT>alert("XSS")</SCRIPT>">`,
//"<p></p>\n",
"<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>" ,
"<p></p>\n" ,
` <IMG SRC=# onmouseover="alert('xxs')"> ` ,
"<p></p>\n" ,
` <IMG SRC= onmouseover="alert('xxs')"> ` ,
"<p></p>\n" ,
` <IMG onmouseover="alert('xxs')"> ` ,
"<p></p>\n" ,
"<IMG SRC=javascript:alert('XSS')>" ,
"<p></p>\n" ,
"<IMG SRC=javascript:alert('XSS')>" ,
"<p></p>\n" ,
"<IMG SRC=javascript:alert('XSS')>" ,
"<p></p>\n" ,
` <IMG SRC="javascriptascript:alert('XSS');"> ` ,
"<p></p>\n" ,
` <IMG SRC="jav	ascript:alert('XSS');"> ` ,
"<p></p>\n" ,
` <IMG SRC="jav
ascript:alert('XSS');"> ` ,
"<p></p>\n" ,
` <IMG SRC="jav
ascript:alert('XSS');"> ` ,
"<p></p>\n" ,
` <IMG SRC="  javascript:alert('XSS');"> ` ,
"<p></p>\n" ,
` <SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT> ` ,
"<p></p>\n" ,
// XXX: this doesn't pass yet
//"<BODY onload!#$%&()*~+-_.,:;?@[/|\\]^`=alert(\"XSS\")>",
//"\n",
` <SCRIPT/SRC="http://ha.ckers.org/xss.js"></SCRIPT> ` ,
"<p></p>\n" ,
// XXX: this doesn't pass yet
//`<<SCRIPT>alert("XSS");//<</SCRIPT>`,
//"",
"<SCRIPT SRC=http://ha.ckers.org/xss.js?< B >" ,
"<p></p>\n" ,
"<SCRIPT SRC=//ha.ckers.org/.j>" ,
"<p></p>\n" ,
// XXX: this doesn't pass yet
//`<IMG SRC="javascript:alert('XSS')"`,
//"",
// XXX: this doesn't pass yet
//"<iframe src=http://ha.ckers.org/scriptlet.html <",
//"",
2013-04-14 03:21:47 +08:00
}
2014-01-22 07:23:43 +08:00
doTestsInlineParam ( t , tests , 0 , HTML_SKIP_STYLE | HTML_SANITIZE_OUTPUT )
2013-04-14 03:21:47 +08:00
}
2011-06-02 02:17:17 +08:00
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" ,
}
2011-06-28 00:13:13 +08:00
doTestsInline ( t , tests )
2011-06-02 02:17:17 +08:00
}
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" ,
}
2011-06-28 00:13:13 +08:00
doTestsInline ( t , tests )
2011-06-02 02:17:17 +08:00
}
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" ,
}
2011-06-28 00:13:13 +08:00
doTestsInline ( t , tests )
2011-06-02 02:17:17 +08:00
}
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" ,
}
2011-06-28 00:13:13 +08:00
doTestsInline ( t , tests )
2011-06-02 02:17:17 +08:00
}
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" ,
2011-06-30 05:38:35 +08:00
"<p>markers with a space</p>\n" ,
2011-06-02 02:17:17 +08:00
"`source code` and a `stray\n" ,
"<p><code>source code</code> and a `stray</p>\n" ,
2011-06-02 08:52:55 +08:00
"`source *with* _awkward characters_ in it`\n" ,
"<p><code>source *with* _awkward characters_ in it</code></p>\n" ,
2011-06-02 02:17:17 +08:00
"`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" ,
}
2011-06-28 00:13:13 +08:00
doTestsInline ( t , tests )
2011-06-02 02:17:17 +08:00
}
2011-06-02 08:52:55 +08:00
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" ,
2011-06-28 06:06:16 +08:00
"<p>this line\ndoes not</p>\n" ,
2011-06-02 08:52:55 +08:00
"this has an \nextra space\n" ,
"<p>this has an<br />\nextra space</p>\n" ,
}
2011-06-28 00:13:13 +08:00
doTestsInline ( t , tests )
2011-06-02 08:52:55 +08:00
}
2011-06-25 06:39:50 +08:00
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" ,
2011-06-30 03:00:54 +08:00
"<p>[foo]()</p>\n" ,
2011-06-25 06:39:50 +08:00
"![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" ,
2011-06-30 03:00:54 +08:00
"<p>![foo]()</p>\n" ,
2011-06-25 06:39:50 +08:00
"[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" ,
2013-09-09 13:51:20 +08:00
"[![image](someimage)](with image)\n" ,
"<p><a href=\"with image\"><img src=\"someimage\" alt=\"image\" />\n</a></p>\n" ,
2011-06-25 06:39:50 +08:00
"[link](url \"one quote)\n" ,
"<p><a href=\"url "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 & ampersand</a></p>\n" ,
"[link & ampersand](/url/)\n" ,
"<p><a href=\"/url/\">link & ampersand</a></p>\n" ,
"[link](/url/&query)\n" ,
"<p><a href=\"/url/&query\">link</a></p>\n" ,
2013-09-12 02:47:43 +08:00
"[[t]](/t)\n" ,
"<p><a href=\"/t\">[t]</a></p>\n" ,
2011-06-25 06:39:50 +08:00
}
2011-06-28 00:13:13 +08:00
doTestsInline ( t , tests )
2011-06-25 06:39:50 +08:00
}
2014-02-25 22:21:57 +08:00
func TestNofollowLink ( t * testing . T ) {
var tests = [ ] string {
"[foo](/bar/)\n" ,
"<p><a href=\"/bar/\" rel=\"nofollow\">foo</a></p>\n" ,
}
doTestsInlineParam ( t , tests , 0 , HTML_SAFELINK | HTML_NOFOLLOW_LINKS )
}
2013-12-19 18:00:47 +08:00
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 )
}
2011-06-25 06:39:50 +08:00
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" ,
}
2011-06-28 00:13:13 +08:00
doTestsInline ( t , tests )
2011-06-25 06:39:50 +08:00
}
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" ,
}
2011-06-28 00:13:13 +08:00
doTestsInline ( t , tests )
2011-06-25 06:39:50 +08:00
}
func TestAutoLink ( t * testing . T ) {
var tests = [ ] string {
2013-08-09 17:24:26 +08:00
"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" ,
2011-06-25 06:39:50 +08:00
"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&bar\">" +
"http://new.com?query=foo&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="foo"&bar\">" +
"http://new.com?query="foo"&bar</a></p>\n" ,
"even a > can be escaped <http://new.com?q=\\>&etc>\n" ,
"<p>even a > can be escaped <a href=\"http://new.com?q=>&etc\">" +
"http://new.com?q=>&etc</a></p>\n" ,
2014-01-26 03:42:34 +08:00
"<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" ,
2014-01-26 03:59:38 +08:00
"http://www.foo.com<br />\n" ,
"<p><a href=\"http://www.foo.com\">http://www.foo.com</a><br /></p>\n" ,
2014-01-27 03:39:38 +08:00
"http://foo.com/viewtopic.php?f=18&t=297" ,
"<p><a href=\"http://foo.com/viewtopic.php?f=18&t=297\">http://foo.com/viewtopic.php?f=18&t=297</a></p>\n" ,
"http://foo.com/viewtopic.php?param="18"zz" ,
"<p><a href=\"http://foo.com/viewtopic.php?param="18"zz\">http://foo.com/viewtopic.php?param="18"zz</a></p>\n" ,
2014-01-27 05:40:26 +08:00
"http://foo.com/viewtopic.php?param="18"" ,
"<p><a href=\"http://foo.com/viewtopic.php?param="18"\">http://foo.com/viewtopic.php?param="18"</a></p>\n" ,
2011-06-25 06:39:50 +08:00
}
2011-06-28 00:13:13 +08:00
doTestsInline ( t , tests )
2011-06-25 06:39:50 +08:00
}
2013-06-25 09:18:47 +08:00
func TestFootnotes ( t * testing . T ) {
tests := [ ] string {
"testing footnotes.[^a]\n\n[^a]: This is the note\n" ,
2013-06-26 23:57:51 +08:00
` < 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 >
2013-07-01 09:37:52 +08:00
< li id = "fn:a" > This is the note
2013-06-26 23:57:51 +08:00
< / li >
< / ol >
< / div >
` ,
2013-06-25 09:18:47 +08:00
` testing long [ ^ b ] notes .
[ ^ b ] : Paragraph 1
Paragraph 2
2013-06-26 23:57:51 +08:00
2013-06-25 09:18:47 +08:00
` + " ` ` ` \ n \ tsome code \ n \ t ` ` ` " + `
Paragraph 3
No longer in the footnote
` ,
2013-06-26 23:57:51 +08:00
` < 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 >
2013-07-01 09:37:52 +08:00
< li id = "fn:b" > < p > Paragraph 1 < / p >
2013-06-26 23:57:51 +08:00
< p > Paragraph 2 < / p >
< p > < code >
some code
< / code > < / p >
< p > Paragraph 3 < / p >
< / li >
< / ol >
< / div >
` ,
2013-06-25 09:18:47 +08:00
` testing [ ^ c ] multiple [ ^ d ] notes .
2013-06-26 23:57:51 +08:00
[ ^ c ] : this is [ note ] c
2013-06-25 09:18:47 +08:00
omg
[ ^ d ] : this is note d
what happens here
2013-06-26 23:57:51 +08:00
[ note ] : / link / c
2013-06-25 09:18:47 +08:00
` ,
2013-06-26 23:57:51 +08:00
` < 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 >
2013-06-25 09:18:47 +08:00
2013-06-26 23:57:51 +08:00
< p > omg < / p >
< p > what happens here < / p >
< div class = "footnotes" >
< hr / >
< ol >
2013-07-01 09:37:52 +08:00
< li id = "fn:c" > this is < a href = "/link/c" > note < / a > c
2013-06-26 23:57:51 +08:00
< / li >
2013-07-01 09:37:52 +08:00
< 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
2013-06-26 23:57:51 +08:00
< / li >
< / ol >
< / div >
2013-07-08 14:54:25 +08:00
` ,
` 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 >
2013-06-26 23:57:51 +08:00
` ,
2013-07-09 06:34:12 +08:00
"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" ,
2013-06-25 09:18:47 +08:00
}
2013-06-26 23:57:51 +08:00
doTestsInlineParam ( t , tests , EXTENSION_FOOTNOTES , 0 )
2013-06-25 09:18:47 +08:00
}