1 package md2man
2
3 import (
4 "testing"
5
6 "github.com/russross/blackfriday/v2"
7 )
8
9 type TestParams struct {
10 extensions blackfriday.Extensions
11 }
12
13 func TestCodeBlocks(t *testing.T) {
14 tests := []string{
15 "```\nsome code\n```\n",
16 ".nh\n\n.EX\nsome code\n.EE\n",
17
18 "```bash\necho foo\n```\n",
19 ".nh\n\n.EX\necho foo\n.EE\n",
20
21
22 "```bash\n\nsome code\n\n```",
23 ".nh\n\n.EX\n\nsome code\n\n.EE\n",
24 }
25 doTestsParam(t, tests, TestParams{blackfriday.FencedCode})
26 }
27
28 func TestEmphasis(t *testing.T) {
29 tests := []string{
30 "nothing inline\n",
31 ".nh\n\n.PP\nnothing inline\n",
32
33 "simple *inline* test\n",
34 ".nh\n\n.PP\nsimple \\fIinline\\fP test\n",
35
36 "*at the* beginning\n",
37 ".nh\n\n.PP\n\\fIat the\\fP beginning\n",
38
39 "at the *end*\n",
40 ".nh\n\n.PP\nat the \\fIend\\fP\n",
41
42 "*try two* in *one line*\n",
43 ".nh\n\n.PP\n\\fItry two\\fP in \\fIone line\\fP\n",
44
45 "over *two\nlines* test\n",
46 ".nh\n\n.PP\nover \\fItwo\nlines\\fP test\n",
47
48 "odd *number of* markers* here\n",
49 ".nh\n\n.PP\nodd \\fInumber of\\fP markers* here\n",
50
51 "odd *number\nof* markers* here\n",
52 ".nh\n\n.PP\nodd \\fInumber\nof\\fP markers* here\n",
53
54 "simple _inline_ test\n",
55 ".nh\n\n.PP\nsimple \\fIinline\\fP test\n",
56
57 "_at the_ beginning\n",
58 ".nh\n\n.PP\n\\fIat the\\fP beginning\n",
59
60 "at the _end_\n",
61 ".nh\n\n.PP\nat the \\fIend\\fP\n",
62
63 "_try two_ in _one line_\n",
64 ".nh\n\n.PP\n\\fItry two\\fP in \\fIone line\\fP\n",
65
66 "over _two\nlines_ test\n",
67 ".nh\n\n.PP\nover \\fItwo\nlines\\fP test\n",
68
69 "odd _number of_ markers_ here\n",
70 ".nh\n\n.PP\nodd \\fInumber of\\fP markers_ here\n",
71
72 "odd _number\nof_ markers_ here\n",
73 ".nh\n\n.PP\nodd \\fInumber\nof\\fP markers_ here\n",
74
75 "mix of *markers_\n",
76 ".nh\n\n.PP\nmix of *markers_\n",
77
78 "*What is A\\* algorithm?*\n",
79 ".nh\n\n.PP\n\\fIWhat is A* algorithm?\\fP\n",
80 }
81 doTestsInline(t, tests)
82 }
83
84 func TestStrong(t *testing.T) {
85 tests := []string{
86 "nothing inline\n",
87 ".nh\n\n.PP\nnothing inline\n",
88
89 "simple **inline** test\n",
90 ".nh\n\n.PP\nsimple \\fBinline\\fP test\n",
91
92 "**at the** beginning\n",
93 ".nh\n\n.PP\n\\fBat the\\fP beginning\n",
94
95 "at the **end**\n",
96 ".nh\n\n.PP\nat the \\fBend\\fP\n",
97
98 "**try two** in **one line**\n",
99 ".nh\n\n.PP\n\\fBtry two\\fP in \\fBone line\\fP\n",
100
101 "over **two\nlines** test\n",
102 ".nh\n\n.PP\nover \\fBtwo\nlines\\fP test\n",
103
104 "odd **number of** markers** here\n",
105 ".nh\n\n.PP\nodd \\fBnumber of\\fP markers** here\n",
106
107 "odd **number\nof** markers** here\n",
108 ".nh\n\n.PP\nodd \\fBnumber\nof\\fP markers** here\n",
109
110 "simple __inline__ test\n",
111 ".nh\n\n.PP\nsimple \\fBinline\\fP test\n",
112
113 "__at the__ beginning\n",
114 ".nh\n\n.PP\n\\fBat the\\fP beginning\n",
115
116 "at the __end__\n",
117 ".nh\n\n.PP\nat the \\fBend\\fP\n",
118
119 "__try two__ in __one line__\n",
120 ".nh\n\n.PP\n\\fBtry two\\fP in \\fBone line\\fP\n",
121
122 "over __two\nlines__ test\n",
123 ".nh\n\n.PP\nover \\fBtwo\nlines\\fP test\n",
124
125 "odd __number of__ markers__ here\n",
126 ".nh\n\n.PP\nodd \\fBnumber of\\fP markers__ here\n",
127
128 "odd __number\nof__ markers__ here\n",
129 ".nh\n\n.PP\nodd \\fBnumber\nof\\fP markers__ here\n",
130
131 "mix of **markers__\n",
132 ".nh\n\n.PP\nmix of **markers__\n",
133
134 "**`/usr`** : this folder is named `usr`\n",
135 ".nh\n\n.PP\n\\fB\\fB/usr\\fR\\fP : this folder is named \\fBusr\\fR\n",
136
137 "**`/usr`** :\n\n this folder is named `usr`\n",
138 ".nh\n\n.PP\n\\fB\\fB/usr\\fR\\fP :\n\n.PP\nthis folder is named \\fBusr\\fR\n",
139 }
140 doTestsInline(t, tests)
141 }
142
143 func TestEmphasisMix(t *testing.T) {
144 tests := []string{
145 "***triple emphasis***\n",
146 ".nh\n\n.PP\n\\fB\\fItriple emphasis\\fP\\fP\n",
147
148 "***triple\nemphasis***\n",
149 ".nh\n\n.PP\n\\fB\\fItriple\nemphasis\\fP\\fP\n",
150
151 "___triple emphasis___\n",
152 ".nh\n\n.PP\n\\fB\\fItriple emphasis\\fP\\fP\n",
153
154 "***triple emphasis___\n",
155 ".nh\n\n.PP\n***triple emphasis___\n",
156
157 "*__triple emphasis__*\n",
158 ".nh\n\n.PP\n\\fI\\fBtriple emphasis\\fP\\fP\n",
159
160 "__*triple emphasis*__\n",
161 ".nh\n\n.PP\n\\fB\\fItriple emphasis\\fP\\fP\n",
162
163 "**improper *nesting** is* bad\n",
164 ".nh\n\n.PP\n\\fBimproper *nesting\\fP is* bad\n",
165
166 "*improper **nesting* is** bad\n",
167 ".nh\n\n.PP\n*improper \\fBnesting* is\\fP bad\n",
168 }
169 doTestsInline(t, tests)
170 }
171
172 func TestCodeSpan(t *testing.T) {
173 tests := []string{
174 "`source code`\n",
175 ".nh\n\n.PP\n\\fBsource code\\fR\n",
176
177 "` source code with spaces `\n",
178 ".nh\n\n.PP\n\\fBsource code with spaces\\fR\n",
179
180 "` source code with spaces `not here\n",
181 ".nh\n\n.PP\n\\fBsource code with spaces\\fRnot here\n",
182
183 "a `single marker\n",
184 ".nh\n\n.PP\na `single marker\n",
185
186 "a single multi-tick marker with ``` no text\n",
187 ".nh\n\n.PP\na single multi-tick marker with ``` no text\n",
188
189 "markers with ` ` a space\n",
190 ".nh\n\n.PP\nmarkers with a space\n",
191
192 "`source code` and a `stray\n",
193 ".nh\n\n.PP\n\\fBsource code\\fR and a `stray\n",
194
195 "`source *with* _awkward characters_ in it`\n",
196 ".nh\n\n.PP\n\\fBsource *with* _awkward characters_ in it\\fR\n",
197
198 "`split over\ntwo lines`\n",
199 ".nh\n\n.PP\n\\fBsplit over\ntwo lines\\fR\n",
200
201 "```multiple ticks``` for the marker\n",
202 ".nh\n\n.PP\n\\fBmultiple ticks\\fR for the marker\n",
203
204 "```multiple ticks `with` ticks inside```\n",
205 ".nh\n\n.PP\n\\fBmultiple ticks `with` ticks inside\\fR\n",
206 }
207 doTestsInline(t, tests)
208 }
209
210 func TestListLists(t *testing.T) {
211 tests := []string{
212 "\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)",
213 ".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",
214 "Definition title\n: Definition description one\n: And two\n: And three\n",
215 ".nh\n\n.TP\nDefinition title\nDefinition description one\n\nAnd two\n\nAnd three\n",
216 }
217 doTestsParam(t, tests, TestParams{blackfriday.DefinitionLists})
218 }
219
220 func TestLineBreak(t *testing.T) {
221 tests := []string{
222 "this line \nhas a break\n",
223 ".nh\n\n.PP\nthis line\n.br\nhas a break\n",
224
225 "this line \ndoes not\n",
226 ".nh\n\n.PP\nthis line\ndoes not\n",
227
228 "this line\\\ndoes not\n",
229 ".nh\n\n.PP\nthis line\\\\\ndoes not\n",
230
231 "this line\\ \ndoes not\n",
232 ".nh\n\n.PP\nthis line\\\\\ndoes not\n",
233
234 "this has an \nextra space\n",
235 ".nh\n\n.PP\nthis has an\n.br\nextra space\n",
236 }
237 doTestsInline(t, tests)
238
239 tests = []string{
240 "this line \nhas a break\n",
241 ".nh\n\n.PP\nthis line\n.br\nhas a break\n",
242
243 "this line \ndoes not\n",
244 ".nh\n\n.PP\nthis line\ndoes not\n",
245
246 "this line\\\nhas a break\n",
247 ".nh\n\n.PP\nthis line\n.br\nhas a break\n",
248
249 "this line\\ \ndoes not\n",
250 ".nh\n\n.PP\nthis line\\\\\ndoes not\n",
251
252 "this has an \nextra space\n",
253 ".nh\n\n.PP\nthis has an\n.br\nextra space\n",
254 }
255 doTestsInlineParam(t, tests, TestParams{
256 extensions: blackfriday.BackslashLineBreak,
257 })
258 }
259
260 func TestTable(t *testing.T) {
261 tests := []string{
262 `
263 | Animal | Color |
264 | --------------| --- |
265 | elephant | Gray. The elephant is very gray. |
266 | wombat | No idea. |
267 | zebra | Sometimes black and sometimes white, depending on the stripe. |
268 | robin | red. |
269 `,
270 `'\" t
271 .nh
272
273 .TS
274 allbox;
275 l l
276 l l .
277 \fBAnimal\fP \fBColor\fP
278 elephant T{
279 Gray. The elephant is very gray.
280 T}
281 wombat No idea.
282 zebra T{
283 Sometimes black and sometimes white, depending on the stripe.
284 T}
285 robin red.
286 .TE
287 `,
288 }
289 doTestsInlineParam(t, tests, TestParams{blackfriday.Tables})
290 }
291
292 func TestTableWithEmptyCell(t *testing.T) {
293 tests := []string{
294 `
295 | Col1 | Col2 | Col3 |
296 |:---------|:-----:|:----:|
297 | row one | | |
298 | row two | x | |
299 `,
300 `'\" t
301 .nh
302
303 .TS
304 allbox;
305 l l l
306 l l l .
307 \fBCol1\fP \fBCol2\fP \fBCol3\fP
308 row one
309 row two x
310 .TE
311 `,
312 }
313 doTestsInlineParam(t, tests, TestParams{blackfriday.Tables})
314 }
315
316 func TestTableWrapping(t *testing.T) {
317 tests := []string{
318 `
319 | Col1 | Col2 |
320 | ----------- | ------------------------------------------------ |
321 | row one | This is a short line. |
322 | row\|two | Col1 should not wrap. |
323 | row three | no\|wrap |
324 | row four | Inline _cursive_ should not wrap. |
325 | row five | Inline ` + "`code markup`" + ` should not wrap. |
326 | row six | A line that's longer than 30 characters with inline ` + "`code markup`" + ` or _cursive_ should not wrap. |
327 | row seven | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent eu ipsum eget tortor aliquam accumsan. Quisque ac turpis convallis, sagittis urna ac, tempor est. Mauris nibh arcu, hendrerit id eros sed, sodales lacinia ex. Suspendisse sed condimentum urna, vitae mattis lectus. Mauris imperdiet magna vel purus pretium, id interdum libero. |
328 `,
329 `'\" t
330 .nh
331
332 .TS
333 allbox;
334 l l
335 l l .
336 \fBCol1\fP \fBCol2\fP
337 row one This is a short line.
338 row|two Col1 should not wrap.
339 row three no|wrap
340 row four Inline \fIcursive\fP should not wrap.
341 row five Inline \fBcode markup\fR should not wrap.
342 row six T{
343 A line that's longer than 30 characters with inline \fBcode markup\fR or \fIcursive\fP should not wrap.
344 T}
345 row seven T{
346 Lorem ipsum dolor sit amet, consectetur adipiscing elit. Praesent eu ipsum eget tortor aliquam accumsan. Quisque ac turpis convallis, sagittis urna ac, tempor est. Mauris nibh arcu, hendrerit id eros sed, sodales lacinia ex. Suspendisse sed condimentum urna, vitae mattis lectus. Mauris imperdiet magna vel purus pretium, id interdum libero.
347 T}
348 .TE
349 `,
350 }
351 doTestsInlineParam(t, tests, TestParams{blackfriday.Tables})
352 }
353
354 func TestLinks(t *testing.T) {
355 tests := []string{
356 "See [docs](https://docs.docker.com/) for\nmore",
357 ".nh\n\n.PP\nSee docs\n\\[la]https://docs.docker.com/\\[ra] for\nmore\n",
358 "See [docs](https://docs-foo.docker.com/) for\nmore",
359 ".nh\n\n.PP\nSee docs\n\\[la]https://docs\\-foo.docker.com/\\[ra] for\nmore\n",
360 "See <https://docs-foo.docker.com/> for\nmore",
361 ".nh\n\n.PP\nSee \n\\[la]https://docs\\-foo.docker.com/\\[ra] for\nmore\n",
362 }
363 doTestsInline(t, tests)
364 }
365
366 func TestEscapeCharacters(t *testing.T) {
367 tests := []string{
368 "Test-one_two&three\\four~five",
369 ".nh\n\n.PP\nTest-one_two&three\\\\four~five\n",
370 "'foo'\n'bar'",
371 ".nh\n\n.PP\n\\&'foo'\n\\&'bar'\n",
372 }
373 doTestsInline(t, tests)
374 }
375
376 func TestSpan(t *testing.T) {
377 tests := []string{
378 "Text containing a <span>html span</span> element\n",
379 ".nh\n\n.PP\nText containing a html span element\n",
380
381 `Text containing an inline <svg width="200" height="200" xmlns="http://www.w3.org/2000/svg"><image href="https://mdn.mozillademos.org/files/6457/mdn_logo_only_color.png" height="200" width="200"/></svg>SVG image`,
382 ".nh\n\n.PP\nText containing an inline SVG image\n",
383
384 "Text containing a <span id=\"e-123\" class=\"foo\">html span</span> element\n",
385 ".nh\n\n.PP\nText containing a html span element\n",
386 }
387 doTestsInline(t, tests)
388 }
389
390 func TestEmails(t *testing.T) {
391 tests := []string{
392 `April 2014, Originally compiled by William Henry (whenry at redhat dot com)
393 based on docker.com source material and internal work.
394 June 2014, updated by Sven Dowideit <SvenDowideit@home.org.au>
395 July 2014, updated by Sven Dowideit (SvenDowideit@home.org.au)
396 `,
397 `.nh
398
399 .PP
400 April 2014, Originally compiled by William Henry (whenry at redhat dot com)
401 based on docker.com source material and internal work.
402 June 2014, updated by Sven Dowideit SvenDowideit@home.org.au
403 \[la]mailto:SvenDowideit@home.org.au\[ra]
404 July 2014, updated by Sven Dowideit (SvenDowideit@home.org.au)
405 `,
406 }
407 doTestsInline(t, tests)
408 }
409
410 func TestComments(t *testing.T) {
411 blockTests := []string{
412 "First paragraph\n\n<!-- Comment, HTML should be separated by blank lines -->\n\nSecond paragraph\n",
413 ".nh\n\n.PP\nFirst paragraph\n\n.PP\nSecond paragraph\n",
414 }
415 doTestsParam(t, blockTests, TestParams{})
416
417 inlineTests := []string{
418 "Text with a com<!--...-->ment in the middle\n",
419 ".nh\n\n.PP\nText with a comment in the middle\n",
420 }
421 doTestsInlineParam(t, inlineTests, TestParams{})
422 }
423
424 func execRecoverableTestSuite(t *testing.T, tests []string, params TestParams, suite func(candidate *string)) {
425
426
427
428 var candidate string
429 const doRecover = true
430 if doRecover {
431 defer func() {
432 if err := recover(); err != nil {
433 t.Errorf("\npanic while processing [%#v]: %s\n", candidate, err)
434 }
435 }()
436 }
437 suite(&candidate)
438 }
439
440 func runMarkdown(input string, params TestParams) string {
441 renderer := NewRoffRenderer()
442 return string(blackfriday.Run([]byte(input), blackfriday.WithRenderer(renderer),
443 blackfriday.WithExtensions(params.extensions)))
444 }
445
446 func doTestsParam(t *testing.T, tests []string, params TestParams) {
447 execRecoverableTestSuite(t, tests, params, func(candidate *string) {
448 for i := 0; i+1 < len(tests); i += 2 {
449 input := tests[i]
450 t.Run(input, func(t *testing.T) {
451 *candidate = input
452 expected := tests[i+1]
453 actual := runMarkdown(*candidate, params)
454 if actual != expected {
455 t.Errorf("\nInput [%#v]\nExpected[%#v]\nActual [%#v]",
456 *candidate, expected, actual)
457 }
458
459
460 if !testing.Short() {
461 for start := 0; start < len(input); start++ {
462 for end := start + 1; end <= len(input); end++ {
463 *candidate = input[start:end]
464 runMarkdown(*candidate, params)
465 }
466 }
467 }
468 })
469 }
470 })
471 }
472
473 func doTestsInline(t *testing.T, tests []string) {
474 doTestsInlineParam(t, tests, TestParams{})
475 }
476
477 func doTestsInlineParam(t *testing.T, tests []string, params TestParams) {
478 params.extensions |= blackfriday.Strikethrough
479 doTestsParam(t, tests, params)
480 }
481
View as plain text