1package md2man 2 3import ( 4 "testing" 5 6 "github.com/russross/blackfriday/v2" 7) 8 9type TestParams struct { 10 extensions blackfriday.Extensions 11} 12 13func TestEmphasis(t *testing.T) { 14 var tests = []string{ 15 "nothing inline\n", 16 ".nh\n\n.PP\nnothing inline\n", 17 18 "simple *inline* test\n", 19 ".nh\n\n.PP\nsimple \\fIinline\\fP test\n", 20 21 "*at the* beginning\n", 22 ".nh\n\n.PP\n\\fIat the\\fP beginning\n", 23 24 "at the *end*\n", 25 ".nh\n\n.PP\nat the \\fIend\\fP\n", 26 27 "*try two* in *one line*\n", 28 ".nh\n\n.PP\n\\fItry two\\fP in \\fIone line\\fP\n", 29 30 "over *two\nlines* test\n", 31 ".nh\n\n.PP\nover \\fItwo\nlines\\fP test\n", 32 33 "odd *number of* markers* here\n", 34 ".nh\n\n.PP\nodd \\fInumber of\\fP markers* here\n", 35 36 "odd *number\nof* markers* here\n", 37 ".nh\n\n.PP\nodd \\fInumber\nof\\fP markers* here\n", 38 39 "simple _inline_ test\n", 40 ".nh\n\n.PP\nsimple \\fIinline\\fP test\n", 41 42 "_at the_ beginning\n", 43 ".nh\n\n.PP\n\\fIat the\\fP beginning\n", 44 45 "at the _end_\n", 46 ".nh\n\n.PP\nat the \\fIend\\fP\n", 47 48 "_try two_ in _one line_\n", 49 ".nh\n\n.PP\n\\fItry two\\fP in \\fIone line\\fP\n", 50 51 "over _two\nlines_ test\n", 52 ".nh\n\n.PP\nover \\fItwo\nlines\\fP test\n", 53 54 "odd _number of_ markers_ here\n", 55 ".nh\n\n.PP\nodd \\fInumber of\\fP markers\\_ here\n", 56 57 "odd _number\nof_ markers_ here\n", 58 ".nh\n\n.PP\nodd \\fInumber\nof\\fP markers\\_ here\n", 59 60 "mix of *markers_\n", 61 ".nh\n\n.PP\nmix of *markers\\_\n", 62 63 "*What is A\\* algorithm?*\n", 64 ".nh\n\n.PP\n\\fIWhat is A* algorithm?\\fP\n", 65 } 66 doTestsInline(t, tests) 67} 68 69func TestStrong(t *testing.T) { 70 var tests = []string{ 71 "nothing inline\n", 72 ".nh\n\n.PP\nnothing inline\n", 73 74 "simple **inline** test\n", 75 ".nh\n\n.PP\nsimple \\fBinline\\fP test\n", 76 77 "**at the** beginning\n", 78 ".nh\n\n.PP\n\\fBat the\\fP beginning\n", 79 80 "at the **end**\n", 81 ".nh\n\n.PP\nat the \\fBend\\fP\n", 82 83 "**try two** in **one line**\n", 84 ".nh\n\n.PP\n\\fBtry two\\fP in \\fBone line\\fP\n", 85 86 "over **two\nlines** test\n", 87 ".nh\n\n.PP\nover \\fBtwo\nlines\\fP test\n", 88 89 "odd **number of** markers** here\n", 90 ".nh\n\n.PP\nodd \\fBnumber of\\fP markers** here\n", 91 92 "odd **number\nof** markers** here\n", 93 ".nh\n\n.PP\nodd \\fBnumber\nof\\fP markers** here\n", 94 95 "simple __inline__ test\n", 96 ".nh\n\n.PP\nsimple \\fBinline\\fP test\n", 97 98 "__at the__ beginning\n", 99 ".nh\n\n.PP\n\\fBat the\\fP beginning\n", 100 101 "at the __end__\n", 102 ".nh\n\n.PP\nat the \\fBend\\fP\n", 103 104 "__try two__ in __one line__\n", 105 ".nh\n\n.PP\n\\fBtry two\\fP in \\fBone line\\fP\n", 106 107 "over __two\nlines__ test\n", 108 ".nh\n\n.PP\nover \\fBtwo\nlines\\fP test\n", 109 110 "odd __number of__ markers__ here\n", 111 ".nh\n\n.PP\nodd \\fBnumber of\\fP markers\\_\\_ here\n", 112 113 "odd __number\nof__ markers__ here\n", 114 ".nh\n\n.PP\nodd \\fBnumber\nof\\fP markers\\_\\_ here\n", 115 116 "mix of **markers__\n", 117 ".nh\n\n.PP\nmix of **markers\\_\\_\n", 118 119 "**`/usr`** : this folder is named `usr`\n", 120 ".nh\n\n.PP\n\\fB\\fB\\fC/usr\\fR\\fP : this folder is named \\fB\\fCusr\\fR\n", 121 122 "**`/usr`** :\n\n this folder is named `usr`\n", 123 ".nh\n\n.PP\n\\fB\\fB\\fC/usr\\fR\\fP :\n\n.PP\nthis folder is named \\fB\\fCusr\\fR\n", 124 } 125 doTestsInline(t, tests) 126} 127 128func TestEmphasisMix(t *testing.T) { 129 var tests = []string{ 130 "***triple emphasis***\n", 131 ".nh\n\n.PP\n\\fB\\fItriple emphasis\\fP\\fP\n", 132 133 "***triple\nemphasis***\n", 134 ".nh\n\n.PP\n\\fB\\fItriple\nemphasis\\fP\\fP\n", 135 136 "___triple emphasis___\n", 137 ".nh\n\n.PP\n\\fB\\fItriple emphasis\\fP\\fP\n", 138 139 "***triple emphasis___\n", 140 ".nh\n\n.PP\n***triple emphasis\\_\\_\\_\n", 141 142 "*__triple emphasis__*\n", 143 ".nh\n\n.PP\n\\fI\\fBtriple emphasis\\fP\\fP\n", 144 145 "__*triple emphasis*__\n", 146 ".nh\n\n.PP\n\\fB\\fItriple emphasis\\fP\\fP\n", 147 148 "**improper *nesting** is* bad\n", 149 ".nh\n\n.PP\n\\fBimproper *nesting\\fP is* bad\n", 150 151 "*improper **nesting* is** bad\n", 152 ".nh\n\n.PP\n*improper \\fBnesting* is\\fP bad\n", 153 } 154 doTestsInline(t, tests) 155} 156 157func TestCodeSpan(t *testing.T) { 158 var tests = []string{ 159 "`source code`\n", 160 ".nh\n\n.PP\n\\fB\\fCsource code\\fR\n", 161 162 "` source code with spaces `\n", 163 ".nh\n\n.PP\n\\fB\\fCsource code with spaces\\fR\n", 164 165 "` source code with spaces `not here\n", 166 ".nh\n\n.PP\n\\fB\\fCsource code with spaces\\fRnot here\n", 167 168 "a `single marker\n", 169 ".nh\n\n.PP\na `single marker\n", 170 171 "a single multi-tick marker with ``` no text\n", 172 ".nh\n\n.PP\na single multi\\-tick marker with ``` no text\n", 173 174 "markers with ` ` a space\n", 175 ".nh\n\n.PP\nmarkers with a space\n", 176 177 "`source code` and a `stray\n", 178 ".nh\n\n.PP\n\\fB\\fCsource code\\fR and a `stray\n", 179 180 "`source *with* _awkward characters_ in it`\n", 181 ".nh\n\n.PP\n\\fB\\fCsource *with* \\_awkward characters\\_ in it\\fR\n", 182 183 "`split over\ntwo lines`\n", 184 ".nh\n\n.PP\n\\fB\\fCsplit over\ntwo lines\\fR\n", 185 186 "```multiple ticks``` for the marker\n", 187 ".nh\n\n.PP\n\\fB\\fCmultiple ticks\\fR for the marker\n", 188 189 "```multiple ticks `with` ticks inside```\n", 190 ".nh\n\n.PP\n\\fB\\fCmultiple ticks `with` ticks inside\\fR\n", 191 } 192 doTestsInline(t, tests) 193} 194 195func TestListLists(t *testing.T) { 196 var tests = []string{ 197 "\n\n**[grpc]**\n: Section for gRPC socket listener settings. Contains three properties:\n - **address** (Default: \"/run/containerd/containerd.sock\")\n - **uid** (Default: 0)\n - **gid** (Default: 0)", 198 ".nh\n\n.TP\n\\fB[grpc]\\fP\nSection for gRPC socket listener settings. Contains three properties:\n.RS\n.IP \\(bu 2\n\\fBaddress\\fP (Default: \"/run/containerd/containerd.sock\")\n.IP \\(bu 2\n\\fBuid\\fP (Default: 0)\n.IP \\(bu 2\n\\fBgid\\fP (Default: 0)\n\n.RE\n\n", 199 } 200 doTestsParam(t, tests, TestParams{blackfriday.DefinitionLists}) 201} 202 203func TestLineBreak(t *testing.T) { 204 var tests = []string{ 205 "this line \nhas a break\n", 206 ".nh\n\n.PP\nthis line\n.br\nhas a break\n", 207 208 "this line \ndoes not\n", 209 ".nh\n\n.PP\nthis line\ndoes not\n", 210 211 "this line\\\ndoes not\n", 212 ".nh\n\n.PP\nthis line\\\\\ndoes not\n", 213 214 "this line\\ \ndoes not\n", 215 ".nh\n\n.PP\nthis line\\\\\ndoes not\n", 216 217 "this has an \nextra space\n", 218 ".nh\n\n.PP\nthis has an\n.br\nextra space\n", 219 } 220 doTestsInline(t, tests) 221 222 tests = []string{ 223 "this line \nhas a break\n", 224 ".nh\n\n.PP\nthis line\n.br\nhas a break\n", 225 226 "this line \ndoes not\n", 227 ".nh\n\n.PP\nthis line\ndoes not\n", 228 229 "this line\\\nhas a break\n", 230 ".nh\n\n.PP\nthis line\n.br\nhas a break\n", 231 232 "this line\\ \ndoes not\n", 233 ".nh\n\n.PP\nthis line\\\\\ndoes not\n", 234 235 "this has an \nextra space\n", 236 ".nh\n\n.PP\nthis has an\n.br\nextra space\n", 237 } 238 doTestsInlineParam(t, tests, TestParams{ 239 extensions: blackfriday.BackslashLineBreak}) 240} 241 242func TestTable(t *testing.T) { 243 var tests = []string{ 244 ` 245| Animal | Color | 246| --------------| --- | 247| elephant | Gray. The elephant is very gray. | 248| wombat | No idea. | 249| zebra | Sometimes black and sometimes white, depending on the stripe. | 250| robin | red. | 251`, 252 `.nh 253 254.TS 255allbox; 256l l 257l l . 258\fB\fCAnimal\fR \fB\fCColor\fR 259elephant T{ 260Gray. The elephant is very gray. 261T} 262wombat No idea. 263zebra T{ 264Sometimes black and sometimes white, depending on the stripe. 265T} 266robin red. 267.TE 268`, 269 } 270 doTestsInlineParam(t, tests, TestParams{blackfriday.Tables}) 271} 272 273func TestLinks(t *testing.T) { 274 var tests = []string{ 275 "See [docs](https://docs.docker.com/) for\nmore", 276 ".nh\n\n.PP\nSee docs\n\\[la]https://docs.docker.com/\\[ra] for\nmore\n", 277 } 278 doTestsInline(t, tests) 279} 280 281func execRecoverableTestSuite(t *testing.T, tests []string, params TestParams, suite func(candidate *string)) { 282 // Catch and report panics. This is useful when running 'go test -v' on 283 // the integration server. When developing, though, crash dump is often 284 // preferable, so recovery can be easily turned off with doRecover = false. 285 var candidate string 286 const doRecover = true 287 if doRecover { 288 defer func() { 289 if err := recover(); err != nil { 290 t.Errorf("\npanic while processing [%#v]: %s\n", candidate, err) 291 } 292 }() 293 } 294 suite(&candidate) 295} 296 297func runMarkdown(input string, params TestParams) string { 298 renderer := NewRoffRenderer() 299 return string(blackfriday.Run([]byte(input), blackfriday.WithRenderer(renderer), 300 blackfriday.WithExtensions(params.extensions))) 301} 302 303func doTestsParam(t *testing.T, tests []string, params TestParams) { 304 execRecoverableTestSuite(t, tests, params, func(candidate *string) { 305 for i := 0; i+1 < len(tests); i += 2 { 306 input := tests[i] 307 *candidate = input 308 expected := tests[i+1] 309 actual := runMarkdown(*candidate, params) 310 if actual != expected { 311 t.Errorf("\nInput [%#v]\nExpected[%#v]\nActual [%#v]", 312 *candidate, expected, actual) 313 } 314 315 // now test every substring to stress test bounds checking 316 if !testing.Short() { 317 for start := 0; start < len(input); start++ { 318 for end := start + 1; end <= len(input); end++ { 319 *candidate = input[start:end] 320 runMarkdown(*candidate, params) 321 } 322 } 323 } 324 } 325 }) 326} 327 328func doTestsInline(t *testing.T, tests []string) { 329 doTestsInlineParam(t, tests, TestParams{}) 330} 331 332func doTestsInlineParam(t *testing.T, tests []string, params TestParams) { 333 params.extensions |= blackfriday.Strikethrough 334 doTestsParam(t, tests, params) 335} 336