2011-06-01 20:17:17 +02:00
//
2011-06-28 04:11:32 +02:00
// Blackfriday Markdown Processor
// Available at http://github.com/russross/blackfriday
//
// Copyright © 2011 Russ Ross <russ@russross.com>.
2011-06-28 19:30:10 +02:00
// Distributed under the Simplified BSD License.
2011-06-28 04:11:32 +02:00
// See README.md for details.
2011-06-01 20:17:17 +02:00
//
//
// Unit tests for inline parsing
//
package blackfriday
import (
2014-05-25 20:07:05 +02:00
"regexp"
2011-06-01 20:17:17 +02:00
"testing"
2014-05-25 20:07:05 +02:00
"strings"
2011-06-01 20:17:17 +02:00
)
2014-12-17 00:17:49 +01:00
func runMarkdownInline ( input string , opts Options , htmlFlags int , params HtmlRendererParameters ) string {
opts . Extensions |= EXTENSION_AUTOLINK
opts . Extensions |= EXTENSION_STRIKETHROUGH
2011-06-01 20:17:17 +02:00
2011-06-28 23:55:27 +02:00
htmlFlags |= HTML_USE_XHTML
2011-06-01 20:17:17 +02:00
2014-05-25 20:07:05 +02:00
renderer := HtmlRendererWithParameters ( htmlFlags , "" , "" , params )
2011-06-01 20:17:17 +02:00
2014-12-17 00:17:49 +01:00
return string ( MarkdownOptions ( [ ] byte ( input ) , renderer , opts ) )
2011-06-01 20:17:17 +02:00
}
2011-06-27 18:13:13 +02:00
func doTestsInline ( t * testing . T , tests [ ] string ) {
2014-12-17 00:17:49 +01:00
doTestsInlineParam ( t , tests , Options { } , 0 , HtmlRendererParameters { } )
2013-04-13 21:18:14 +02:00
}
2014-05-25 20:22:33 +02:00
func doLinkTestsInline ( t * testing . T , tests [ ] string ) {
doTestsInline ( t , tests )
prefix := "http://localhost"
params := HtmlRendererParameters { AbsolutePrefix : prefix }
transformTests := transformLinks ( tests , prefix )
2014-12-17 00:17:49 +01:00
doTestsInlineParam ( t , transformTests , Options { } , 0 , params )
doTestsInlineParam ( t , transformTests , Options { } , commonHtmlFlags , params )
2014-05-25 20:22:33 +02:00
}
2013-12-19 11:00:47 +01:00
func doSafeTestsInline ( t * testing . T , tests [ ] string ) {
2014-12-17 00:17:49 +01:00
doTestsInlineParam ( t , tests , Options { } , HTML_SAFELINK , HtmlRendererParameters { } )
2014-05-25 20:22:33 +02:00
// All the links in this test should not have the prefix appended, so
// just rerun it with different parameters and the same expectations.
prefix := "http://localhost"
params := HtmlRendererParameters { AbsolutePrefix : prefix }
transformTests := transformLinks ( tests , prefix )
2014-12-17 00:17:49 +01:00
doTestsInlineParam ( t , transformTests , Options { } , HTML_SAFELINK , params )
2013-12-19 11:00:47 +01:00
}
2014-12-17 00:17:49 +01:00
func doTestsInlineParam ( t * testing . T , tests [ ] string , opts Options , htmlFlags int ,
2014-05-25 20:07:05 +02:00
params HtmlRendererParameters ) {
2011-07-03 18:51:07 +02:00
// catch and report panics
var candidate string
2013-06-26 17:57:51 +02:00
/ *
defer func ( ) {
if err := recover ( ) ; err != nil {
t . Errorf ( "\npanic while processing [%#v] (%v)\n" , candidate , err )
}
} ( )
* /
2011-07-03 18:51:07 +02:00
2011-06-01 20:17:17 +02:00
for i := 0 ; i + 1 < len ( tests ) ; i += 2 {
input := tests [ i ]
2011-07-03 18:51:07 +02:00
candidate = input
2011-06-01 20:17:17 +02:00
expected := tests [ i + 1 ]
2014-12-17 00:17:49 +01:00
actual := runMarkdownInline ( candidate , opts , htmlFlags , params )
2011-06-01 20:17:17 +02:00
if actual != expected {
t . Errorf ( "\nInput [%#v]\nExpected[%#v]\nActual [%#v]" ,
2011-07-03 18:51:07 +02: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 ]
2014-12-17 00:17:49 +01:00
_ = runMarkdownInline ( candidate , opts , htmlFlags , params )
2011-07-03 18:51:07 +02:00
}
}
2011-06-01 20:17:17 +02:00
}
}
}
2014-05-25 20:22:33 +02:00
func transformLinks ( tests [ ] string , prefix string ) [ ] string {
newTests := make ( [ ] string , len ( tests ) )
anchorRe := regexp . MustCompile ( ` <a href="/(.*?)" ` )
imgRe := regexp . MustCompile ( ` <img src="/(.*?)" ` )
for i , test := range tests {
if i % 2 == 1 {
test = anchorRe . ReplaceAllString ( test , ` <a href=" ` + prefix + ` /$1" ` )
test = imgRe . ReplaceAllString ( test , ` <img src=" ` + prefix + ` /$1" ` )
}
newTests [ i ] = test
}
return newTests
}
2011-06-01 20:17:17 +02: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" ,
2015-10-13 18:57:07 +02:00
"*What is A\\* algorithm?*\n" ,
"<p><em>What is A* algorithm?</em></p>\n" ,
2011-06-01 20:17:17 +02:00
}
2011-06-27 18:13:13 +02:00
doTestsInline ( t , tests )
2011-06-01 20:17:17 +02:00
}
2014-12-17 00:17:49 +01:00
func TestReferenceOverride ( t * testing . T ) {
var tests = [ ] string {
"test [ref1][]\n" ,
"<p>test <a href=\"http://www.ref1.com/\" title=\"Reference 1\">ref1</a></p>\n" ,
"test [my ref][ref1]\n" ,
"<p>test <a href=\"http://www.ref1.com/\" title=\"Reference 1\">my ref</a></p>\n" ,
"test [ref2][]\n\n[ref2]: http://www.leftalone.com/ (Ref left alone)\n" ,
"<p>test <a href=\"http://www.overridden.com/\" title=\"Reference Overridden\">ref2</a></p>\n" ,
"test [ref3][]\n\n[ref3]: http://www.leftalone.com/ (Ref left alone)\n" ,
"<p>test <a href=\"http://www.leftalone.com/\" title=\"Ref left alone\">ref3</a></p>\n" ,
"test [ref4][]\n\n[ref4]: http://zombo.com/ (You can do anything)\n" ,
"<p>test [ref4][]</p>\n" ,
"test [!(*http.ServeMux).ServeHTTP][] complicated ref\n" ,
"<p>test <a href=\"http://localhost:6060/pkg/net/http/#ServeMux.ServeHTTP\" title=\"ServeHTTP docs\">!(*http.ServeMux).ServeHTTP</a> complicated ref</p>\n" ,
2015-05-06 14:57:15 +02:00
"test [ref5][]\n" ,
"<p>test <a href=\"http://www.ref5.com/\" title=\"Reference 5\">Moo</a></p>\n" ,
2014-12-17 00:17:49 +01:00
}
doTestsInlineParam ( t , tests , Options {
ReferenceOverride : func ( reference string ) ( rv * Reference , overridden bool ) {
switch reference {
case "ref1" :
// just an overriden reference exists without definition
return & Reference {
Link : "http://www.ref1.com/" ,
Title : "Reference 1" } , true
case "ref2" :
// overridden exists and reference defined
return & Reference {
Link : "http://www.overridden.com/" ,
Title : "Reference Overridden" } , true
case "ref3" :
// not overridden and reference defined
return nil , false
case "ref4" :
// overridden missing and defined
return nil , true
case "!(*http.ServeMux).ServeHTTP" :
return & Reference {
Link : "http://localhost:6060/pkg/net/http/#ServeMux.ServeHTTP" ,
Title : "ServeHTTP docs" } , true
2015-05-06 14:57:15 +02:00
case "ref5" :
return & Reference {
Link : "http://www.ref5.com/" ,
Title : "Reference 5" ,
Text : "Moo" ,
} , true
2014-12-17 00:17:49 +01:00
}
return nil , false
} } , 0 , HtmlRendererParameters { } )
}
2011-06-01 20:17:17 +02: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" ,
2015-10-12 20:06:27 +02:00
"**`/usr`** : this folder is named `usr`\n" ,
"<p><strong><code>/usr</code></strong> : this folder is named <code>usr</code></p>\n" ,
"**`/usr`** :\n\n this folder is named `usr`\n" ,
"<p><strong><code>/usr</code></strong> :</p>\n\n<p>this folder is named <code>usr</code></p>\n" ,
2011-06-01 20:17:17 +02:00
}
2011-06-27 18:13:13 +02:00
doTestsInline ( t , tests )
2011-06-01 20:17:17 +02: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" ,
2015-10-12 20:06:27 +02:00
"<p>*improper <strong>nesting* is</strong> bad</p>\n" ,
2011-06-01 20:17:17 +02:00
}
2011-06-27 18:13:13 +02:00
doTestsInline ( t , tests )
2011-06-01 20:17:17 +02:00
}
2014-12-24 22:05:29 +01:00
func TestEmphasisLink ( t * testing . T ) {
var tests = [ ] string {
"[first](before) *text[second] (inside)text* [third](after)\n" ,
"<p><a href=\"before\">first</a> <em>text<a href=\"inside\">second</a>text</em> <a href=\"after\">third</a></p>\n" ,
"*incomplete [link] definition*\n" ,
"<p><em>incomplete [link] definition</em></p>\n" ,
"*it's [emphasis*] (not link)\n" ,
"<p><em>it's [emphasis</em>] (not link)</p>\n" ,
"*it's [emphasis*] and *[asterisk]\n" ,
"<p><em>it's [emphasis</em>] and *[asterisk]</p>\n" ,
}
doTestsInline ( t , tests )
}
2011-06-01 20:17:17 +02: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-27 18:13:13 +02:00
doTestsInline ( t , tests )
2011-06-01 20:17:17 +02: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-29 23:38:35 +02:00
"<p>markers with a space</p>\n" ,
2011-06-01 20:17:17 +02:00
"`source code` and a `stray\n" ,
"<p><code>source code</code> and a `stray</p>\n" ,
2011-06-02 02:52:55 +02:00
"`source *with* _awkward characters_ in it`\n" ,
"<p><code>source *with* _awkward characters_ in it</code></p>\n" ,
2011-06-01 20:17:17 +02: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-27 18:13:13 +02:00
doTestsInline ( t , tests )
2011-06-01 20:17:17 +02:00
}
2011-06-02 02:52:55 +02: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 00:06:16 +02:00
"<p>this line\ndoes not</p>\n" ,
2011-06-02 02:52:55 +02:00
2015-04-23 10:49:08 +02:00
"this line\\\ndoes not\n" ,
"<p>this line\\\ndoes not</p>\n" ,
"this line\\ \ndoes not\n" ,
"<p>this line\\\ndoes not</p>\n" ,
2011-06-02 02:52:55 +02:00
"this has an \nextra space\n" ,
"<p>this has an<br />\nextra space</p>\n" ,
}
2011-06-27 18:13:13 +02:00
doTestsInline ( t , tests )
2015-04-23 10:49:08 +02:00
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 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" ,
}
2015-05-06 14:41:12 +02:00
doTestsInlineParam ( t , tests , Options {
Extensions : EXTENSION_BACKSLASH_LINE_BREAK } ,
0 , HtmlRendererParameters { } )
2011-06-02 02:52:55 +02:00
}
2011-06-25 00:39:50 +02: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-29 21:00:54 +02:00
"<p>[foo]()</p>\n" ,
2011-06-25 00:39:50 +02:00
"![foo](/bar/)\n" ,
2015-05-25 21:41:06 +02:00
"<p><img src=\"/bar/\" alt=\"foo\" /></p>\n" ,
2011-06-25 00:39:50 +02:00
"![foo with a title](/bar/ \"title\")\n" ,
2015-05-25 21:41:06 +02:00
"<p><img src=\"/bar/\" alt=\"foo with a title\" title=\"title\" /></p>\n" ,
2011-06-25 00:39:50 +02:00
"![foo with a title](/bar/\t\"title\")\n" ,
2015-05-25 21:41:06 +02:00
"<p><img src=\"/bar/\" alt=\"foo with a title\" title=\"title\" /></p>\n" ,
2011-06-25 00:39:50 +02:00
"![foo with a title](/bar/ \"title\" )\n" ,
2015-05-25 21:41:06 +02:00
"<p><img src=\"/bar/\" alt=\"foo with a title\" title=\"title\" /></p>\n" ,
2011-06-25 00:39:50 +02:00
"![foo with a title](/bar/ title with no quotes)\n" ,
2015-05-25 21:41:06 +02:00
"<p><img src=\"/bar/ title with no quotes\" alt=\"foo with a title\" /></p>\n" ,
2011-06-25 00:39:50 +02:00
2014-09-21 15:29:24 +02:00
"![](img.jpg)\n" ,
2015-05-25 21:41:06 +02:00
"<p><img src=\"img.jpg\" alt=\"\" /></p>\n" ,
2014-09-21 15:29:24 +02:00
"[link](url)\n" ,
"<p><a href=\"url\">link</a></p>\n" ,
2011-06-25 00:39:50 +02:00
"![foo]()\n" ,
2011-06-29 21:00:54 +02:00
"<p>![foo]()</p>\n" ,
2011-06-25 00:39:50 +02: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 07:51:20 +02:00
"[![image](someimage)](with image)\n" ,
2015-05-25 21:41:06 +02:00
"<p><a href=\"with image\"><img src=\"someimage\" alt=\"image\" /></a></p>\n" ,
2013-09-09 07:51:20 +02:00
2011-06-25 00:39:50 +02: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-11 20:47:43 +02:00
"[[t]](/t)\n" ,
"<p><a href=\"/t\">[t]</a></p>\n" ,
2015-02-20 10:06:55 +01:00
"[link](</>)\n" ,
"<p><a href=\"/\">link</a></p>\n" ,
"[link](<./>)\n" ,
"<p><a href=\"./\">link</a></p>\n" ,
"[link](<../>)\n" ,
"<p><a href=\"../\">link</a></p>\n" ,
2011-06-25 00:39:50 +02:00
}
2014-05-25 20:22:33 +02:00
doLinkTestsInline ( t , tests )
2011-06-25 00:39:50 +02:00
}
2015-03-15 00:46:32 +01:00
func TestRelAttrLink ( t * testing . T ) {
var nofollowTests = [ ] string {
2014-03-21 04:17:31 +01:00
"[foo](http://bar.com/foo/)\n" ,
"<p><a href=\"http://bar.com/foo/\" rel=\"nofollow\">foo</a></p>\n" ,
2014-09-19 19:30:00 +02:00
2014-05-01 20:43:42 +02:00
"[foo](/bar/)\n" ,
"<p><a href=\"/bar/\">foo</a></p>\n" ,
2015-02-20 10:06:55 +01:00
"[foo](/)\n" ,
"<p><a href=\"/\">foo</a></p>\n" ,
"[foo](./)\n" ,
"<p><a href=\"./\">foo</a></p>\n" ,
"[foo](../)\n" ,
"<p><a href=\"../\">foo</a></p>\n" ,
"[foo](../bar)\n" ,
"<p><a href=\"../bar\">foo</a></p>\n" ,
2014-05-01 20:43:42 +02:00
}
2015-05-06 14:41:12 +02:00
doTestsInlineParam ( t , nofollowTests , Options { } , HTML_SAFELINK | HTML_NOFOLLOW_LINKS ,
2015-03-15 00:46:32 +01:00
HtmlRendererParameters { } )
var noreferrerTests = [ ] string {
"[foo](http://bar.com/foo/)\n" ,
"<p><a href=\"http://bar.com/foo/\" rel=\"noreferrer\">foo</a></p>\n" ,
"[foo](/bar/)\n" ,
"<p><a href=\"/bar/\">foo</a></p>\n" ,
}
2015-05-06 14:41:12 +02:00
doTestsInlineParam ( t , noreferrerTests , Options { } , HTML_SAFELINK | HTML_NOREFERRER_LINKS ,
2015-03-15 00:46:32 +01:00
HtmlRendererParameters { } )
var nofollownoreferrerTests = [ ] string {
"[foo](http://bar.com/foo/)\n" ,
"<p><a href=\"http://bar.com/foo/\" rel=\"nofollow noreferrer\">foo</a></p>\n" ,
"[foo](/bar/)\n" ,
"<p><a href=\"/bar/\">foo</a></p>\n" ,
}
2015-05-06 14:41:12 +02:00
doTestsInlineParam ( t , nofollownoreferrerTests , Options { } , HTML_SAFELINK | HTML_NOFOLLOW_LINKS | HTML_NOREFERRER_LINKS ,
2014-09-19 19:30:00 +02:00
HtmlRendererParameters { } )
2014-02-25 15:21:57 +01:00
}
2014-03-21 03:52:46 +01:00
func TestHrefTargetBlank ( t * testing . T ) {
var tests = [ ] string {
2014-05-01 22:08:32 +02:00
// internal link
2014-03-21 03:52:46 +01:00
"[foo](/bar/)\n" ,
"<p><a href=\"/bar/\">foo</a></p>\n" ,
2015-02-20 10:06:55 +01:00
"[foo](/)\n" ,
"<p><a href=\"/\">foo</a></p>\n" ,
"[foo](./)\n" ,
"<p><a href=\"./\">foo</a></p>\n" ,
"[foo](./bar)\n" ,
"<p><a href=\"./bar\">foo</a></p>\n" ,
"[foo](../)\n" ,
"<p><a href=\"../\">foo</a></p>\n" ,
"[foo](../bar)\n" ,
"<p><a href=\"../bar\">foo</a></p>\n" ,
2014-03-21 03:52:46 +01:00
"[foo](http://example.com)\n" ,
"<p><a href=\"http://example.com\" target=\"_blank\">foo</a></p>\n" ,
}
2014-12-17 00:17:49 +01:00
doTestsInlineParam ( t , tests , Options { } , HTML_SAFELINK | HTML_HREF_TARGET_BLANK , HtmlRendererParameters { } )
2014-02-25 15:21:57 +01:00
}
2013-12-19 11:00:47 +01:00
func TestSafeInlineLink ( t * testing . T ) {
var tests = [ ] string {
"[foo](/bar/)\n" ,
"<p><a href=\"/bar/\">foo</a></p>\n" ,
2015-02-20 10:06:55 +01:00
"[foo](/)\n" ,
"<p><a href=\"/\">foo</a></p>\n" ,
"[foo](./)\n" ,
"<p><a href=\"./\">foo</a></p>\n" ,
"[foo](../)\n" ,
"<p><a href=\"../\">foo</a></p>\n" ,
2013-12-19 11:00:47 +01:00
"[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 00:39:50 +02: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" ,
2015-02-20 10:06:55 +01:00
"[ref]\n [ref]: ../url/ \"title\"\n" ,
"<p><a href=\"../url/\" title=\"title\">ref</a></p>\n" ,
2011-06-25 00:39:50 +02:00
}
2014-05-25 20:22:33 +02:00
doLinkTestsInline ( t , tests )
2011-06-25 00:39:50 +02: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-27 18:13:13 +02:00
doTestsInline ( t , tests )
2011-06-25 00:39:50 +02:00
}
func TestAutoLink ( t * testing . T ) {
var tests = [ ] string {
2013-08-09 11:24:26 +02: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 00:39:50 +02: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-25 20:42:34 +01: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-25 20:59:38 +01:00
"http://www.foo.com<br />\n" ,
"<p><a href=\"http://www.foo.com\">http://www.foo.com</a><br /></p>\n" ,
2014-01-26 20:39:38 +01: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-26 22:40:26 +01: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 00:39:50 +02:00
}
2014-05-25 20:22:33 +02:00
doLinkTestsInline ( t , tests )
2011-06-25 00:39:50 +02:00
}
2013-06-25 03:18:47 +02:00
2014-05-25 20:07:05 +02:00
var footnoteTests = [ ] string {
2014-05-24 21:28:37 +02:00
"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 >
2013-06-26 17:57:51 +02:00
< div class = "footnotes" >
< hr / >
< ol >
2013-07-01 03:37:52 +02:00
< li id = "fn:a" > This is the note
2013-06-26 17:57:51 +02:00
< / li >
< / ol >
< / div >
` ,
2013-06-25 03:18:47 +02:00
2014-05-24 21:28:37 +02:00
` testing long [ ^ b ] notes .
2013-06-25 03:18:47 +02:00
[ ^ b ] : Paragraph 1
Paragraph 2
2014-03-21 03:52:46 +01:00
2013-06-25 03:18:47 +02:00
` + " ` ` ` \ n \ tsome code \ n \ t ` ` ` " + `
2014-03-21 03:52:46 +01:00
2013-06-25 03:18:47 +02:00
Paragraph 3
No longer in the footnote
` ,
2014-05-24 21:28:37 +02:00
` < p > testing long < sup class = "footnote-ref" id = "fnref:b" > < a rel = "footnote" href = "#fn:b" > 1 < / a > < / sup > notes . < / p >
2013-06-26 17:57:51 +02:00
< p > No longer in the footnote < / p >
< div class = "footnotes" >
< hr / >
< ol >
2013-07-01 03:37:52 +02:00
< li id = "fn:b" > < p > Paragraph 1 < / p >
2013-06-26 17:57:51 +02:00
< p > Paragraph 2 < / p >
< p > < code >
some code
< / code > < / p >
< p > Paragraph 3 < / p >
< / li >
< / ol >
< / div >
` ,
2013-06-25 03:18:47 +02:00
2014-05-24 21:28:37 +02:00
` testing [ ^ c ] multiple [ ^ d ] notes .
2013-06-25 03:18:47 +02:00
2013-06-26 17:57:51 +02:00
[ ^ c ] : this is [ note ] c
2013-06-25 03:18:47 +02:00
omg
[ ^ d ] : this is note d
what happens here
2013-06-26 17:57:51 +02:00
[ note ] : / link / c
2013-06-25 03:18:47 +02:00
` ,
2014-05-24 21:28:37 +02: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 03:18:47 +02:00
2013-06-26 17:57:51 +02:00
< p > omg < / p >
< p > what happens here < / p >
< div class = "footnotes" >
< hr / >
< ol >
2013-07-01 03:37:52 +02:00
< li id = "fn:c" > this is < a href = "/link/c" > note < / a > c
2013-06-26 17:57:51 +02:00
< / li >
2013-07-01 03:37:52 +02:00
< li id = "fn:d" > this is note d
< / li >
< / ol >
< / div >
` ,
2014-05-24 21:28:37 +02:00
"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 >
2013-07-01 03:37:52 +02:00
< div class = "footnotes" >
< hr / >
< ol >
< li id = "fn:this-is-the-note" > this is the note < / li >
< / ol >
< / div >
` ,
2014-05-24 21:28:37 +02:00
"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 >
2013-07-01 03:37:52 +02:00
< 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 17:57:51 +02:00
< / li >
< / ol >
< / div >
2013-07-08 08:54:25 +02:00
` ,
2014-05-24 21:28:37 +02:00
` This is a footnote [ ^ 1 ] ^ [ and this is an inline footnote ]
2013-07-08 08:54:25 +02:00
[ ^ 1 ] : the footnote text .
may be multiple paragraphs .
` ,
2014-05-24 21:28:37 +02:00
` < 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 >
2013-07-08 08:54:25 +02:00
< 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 17:57:51 +02:00
` ,
2013-07-09 00:34:12 +02:00
2014-05-24 21:28:37 +02: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" ,
2015-04-03 20:05:54 +02:00
"Some text.[^note1]\n\n[^note1]: fn1" ,
"<p>Some text.<sup class=\"footnote-ref\" id=\"fnref:note1\"><a rel=\"footnote\" href=\"#fn:note1\">1</a></sup></p>\n<div class=\"footnotes\">\n\n<hr />\n\n<ol>\n<li id=\"fn:note1\">fn1\n</li>\n</ol>\n</div>\n" ,
"Some text.[^note1][^note2]\n\n[^note1]: fn1\n[^note2]: fn2\n" ,
"<p>Some text.<sup class=\"footnote-ref\" id=\"fnref:note1\"><a rel=\"footnote\" href=\"#fn:note1\">1</a></sup><sup class=\"footnote-ref\" id=\"fnref:note2\"><a rel=\"footnote\" href=\"#fn:note2\">2</a></sup></p>\n<div class=\"footnotes\">\n\n<hr />\n\n<ol>\n<li id=\"fn:note1\">fn1\n</li>\n<li id=\"fn:note2\">fn2\n</li>\n</ol>\n</div>\n" ,
2014-05-24 21:28:37 +02:00
}
func TestFootnotes ( t * testing . T ) {
2014-12-17 00:17:49 +01:00
doTestsInlineParam ( t , footnoteTests , Options { Extensions : EXTENSION_FOOTNOTES } , 0 , HtmlRendererParameters { } )
2014-05-24 21:28:37 +02:00
}
func TestFootnotesWithParameters ( t * testing . T ) {
tests := make ( [ ] string , len ( footnoteTests ) )
prefix := "testPrefix"
2014-05-25 20:07:05 +02:00
returnText := "ret"
re := regexp . MustCompile ( ` (?ms)<li id="fn:(\S+?)">(.*?)</li> ` )
// Transform the test expectations to match the parameters we're using.
2014-05-24 21:28:37 +02:00
for i , test := range footnoteTests {
2014-05-25 20:07:05 +02:00
if i % 2 == 1 {
test = strings . Replace ( test , "fn:" , "fn:" + prefix , - 1 )
test = strings . Replace ( test , "fnref:" , "fnref:" + prefix , - 1 )
test = re . ReplaceAllString ( test , ` <li id="fn:$1">$2 <a class="footnote-return" href="#fnref:$1">ret</a></li> ` )
}
tests [ i ] = test
}
2014-05-24 21:28:37 +02:00
2014-05-25 20:07:05 +02:00
params := HtmlRendererParameters {
FootnoteAnchorPrefix : prefix ,
FootnoteReturnLinkContents : returnText ,
2013-06-25 03:18:47 +02:00
}
2014-12-17 00:17:49 +01:00
doTestsInlineParam ( t , tests , Options { Extensions : EXTENSION_FOOTNOTES } , HTML_FOOTNOTE_RETURN_LINKS , params )
2013-06-25 03:18:47 +02:00
}
2014-11-05 23:18:32 +01:00
func TestSmartDoubleQuotes ( t * testing . T ) {
var tests = [ ] string {
"this should be normal \"quoted\" text.\n" ,
"<p>this should be normal “quoted” text.</p>\n" ,
"this \" single double\n" ,
"<p>this “ single double</p>\n" ,
"two pair of \"some\" quoted \"text\".\n" ,
"<p>two pair of “some” quoted “text”.</p>\n" }
2014-12-17 00:17:49 +01:00
doTestsInlineParam ( t , tests , Options { } , HTML_USE_SMARTYPANTS , HtmlRendererParameters { } )
2014-11-05 23:18:32 +01:00
}
func TestSmartAngledDoubleQuotes ( t * testing . T ) {
var tests = [ ] string {
"this should be angled \"quoted\" text.\n" ,
"<p>this should be angled «quoted» text.</p>\n" ,
"this \" single double\n" ,
"<p>this « single double</p>\n" ,
"two pair of \"some\" quoted \"text\".\n" ,
"<p>two pair of «some» quoted «text».</p>\n" }
2014-12-17 00:17:49 +01:00
doTestsInlineParam ( t , tests , Options { } , HTML_USE_SMARTYPANTS | HTML_SMARTYPANTS_ANGLED_QUOTES , HtmlRendererParameters { } )
2014-11-05 23:18:32 +01:00
}
2015-01-24 23:23:48 +01:00
func TestSmartFractions ( t * testing . T ) {
var tests = [ ] string {
"1/2, 1/4 and 3/4; 1/4th and 3/4ths\n" ,
"<p>½, ¼ and ¾; ¼th and ¾ths</p>\n" ,
"1/2/2015, 1/4/2015, 3/4/2015; 2015/1/2, 2015/1/4, 2015/3/4.\n" ,
"<p>1/2/2015, 1/4/2015, 3/4/2015; 2015/1/2, 2015/1/4, 2015/3/4.</p>\n" }
2015-05-06 14:41:12 +02:00
doTestsInlineParam ( t , tests , Options { } , HTML_USE_SMARTYPANTS , HtmlRendererParameters { } )
2015-01-24 23:23:48 +01:00
tests = [ ] string {
"1/2, 2/3, 81/100 and 1000000/1048576.\n" ,
"<p><sup>1</sup>⁄<sub>2</sub>, <sup>2</sup>⁄<sub>3</sub>, <sup>81</sup>⁄<sub>100</sub> and <sup>1000000</sup>⁄<sub>1048576</sub>.</p>\n" ,
"1/2/2015, 1/4/2015, 3/4/2015; 2015/1/2, 2015/1/4, 2015/3/4.\n" ,
"<p>1/2/2015, 1/4/2015, 3/4/2015; 2015/1/2, 2015/1/4, 2015/3/4.</p>\n" }
2015-05-06 14:41:12 +02:00
doTestsInlineParam ( t , tests , Options { } , HTML_USE_SMARTYPANTS | HTML_SMARTYPANTS_FRACTIONS , HtmlRendererParameters { } )
2015-01-24 23:23:48 +01:00
}