1
2fn run(input: &str, output: &str) {
3 let output = if output.is_empty() { "".to_owned() } else { output.to_owned() + "\n" };
4 let md = &mut markdown_it::MarkdownIt::new();
5 markdown_it::plugins::cmark::add(md);
6 markdown_it::plugins::html::add(md);
7 markdown_it::plugins::extra::typographer::add(md);
8 markdown_it::plugins::extra::tables::add(md);
9 let node = md.parse(&(input.to_owned() + "\n"));
10
11 // make sure we have sourcemaps for everything
12 node.walk(|node, _| assert!(node.srcmap.is_some()));
13
14 let result = node.render();
15 assert_eq!(result, output);
16
17 // make sure it doesn't crash without trailing \n
18 let _ = md.parse(input.trim_end());
19}
20
21///////////////////////////////////////////////////////////////////////////
22// TESTGEN: fixtures/markdown-it/tables.txt
23#[rustfmt::skip]
24mod fixtures_markdown_it_tables_txt {
25use super::run;
26// this part of the file is auto-generated
27// don't edit it, otherwise your changes might be lost
28#[test]
29fn simple() {
30 let input = r#"| Heading 1 | Heading 2
31| --------- | ---------
32| Cell 1 | Cell 2
33| Cell 3 | Cell 4"#;
34 let output = r#"<table>
35<thead>
36<tr>
37<th>Heading 1</th>
38<th>Heading 2</th>
39</tr>
40</thead>
41<tbody>
42<tr>
43<td>Cell 1</td>
44<td>Cell 2</td>
45</tr>
46<tr>
47<td>Cell 3</td>
48<td>Cell 4</td>
49</tr>
50</tbody>
51</table>"#;
52 run(input, output);
53}
54
55#[test]
56fn column_alignment() {
57 let input = r#"| Header 1 | Header 2 | Header 3 | Header 4 |
58| :------: | -------: | :------- | -------- |
59| Cell 1 | Cell 2 | Cell 3 | Cell 4 |
60| Cell 5 | Cell 6 | Cell 7 | Cell 8 |"#;
61 let output = r#"<table>
62<thead>
63<tr>
64<th style="text-align:center">Header 1</th>
65<th style="text-align:right">Header 2</th>
66<th style="text-align:left">Header 3</th>
67<th>Header 4</th>
68</tr>
69</thead>
70<tbody>
71<tr>
72<td style="text-align:center">Cell 1</td>
73<td style="text-align:right">Cell 2</td>
74<td style="text-align:left">Cell 3</td>
75<td>Cell 4</td>
76</tr>
77<tr>
78<td style="text-align:center">Cell 5</td>
79<td style="text-align:right">Cell 6</td>
80<td style="text-align:left">Cell 7</td>
81<td>Cell 8</td>
82</tr>
83</tbody>
84</table>"#;
85 run(input, output);
86}
87
88#[test]
89fn nested_emphases() {
90 let input = r#"Header 1|Header 2|Header 3|Header 4
91:-------|:------:|-------:|--------
92Cell 1 |Cell 2 |Cell 3 |Cell 4
93*Cell 5*|Cell 6 |Cell 7 |Cell 8"#;
94 let output = r#"<table>
95<thead>
96<tr>
97<th style="text-align:left">Header 1</th>
98<th style="text-align:center">Header 2</th>
99<th style="text-align:right">Header 3</th>
100<th>Header 4</th>
101</tr>
102</thead>
103<tbody>
104<tr>
105<td style="text-align:left">Cell 1</td>
106<td style="text-align:center">Cell 2</td>
107<td style="text-align:right">Cell 3</td>
108<td>Cell 4</td>
109</tr>
110<tr>
111<td style="text-align:left"><em>Cell 5</em></td>
112<td style="text-align:center">Cell 6</td>
113<td style="text-align:right">Cell 7</td>
114<td>Cell 8</td>
115</tr>
116</tbody>
117</table>"#;
118 run(input, output);
119}
120
121#[test]
122fn nested_tables_inside_blockquotes() {
123 let input = r#"> foo|foo
124> ---|---
125> bar|bar
126baz|baz"#;
127 let output = r#"<blockquote>
128<table>
129<thead>
130<tr>
131<th>foo</th>
132<th>foo</th>
133</tr>
134</thead>
135<tbody>
136<tr>
137<td>bar</td>
138<td>bar</td>
139</tr>
140</tbody>
141</table>
142</blockquote>
143<p>baz|baz</p>"#;
144 run(input, output);
145}
146
147#[test]
148fn minimal_one_column() {
149 let input = r#"| foo
150|----
151| test2"#;
152 let output = r#"<table>
153<thead>
154<tr>
155<th>foo</th>
156</tr>
157</thead>
158<tbody>
159<tr>
160<td>test2</td>
161</tr>
162</tbody>
163</table>"#;
164 run(input, output);
165}
166
167#[test]
168fn this_is_parsed_as_one_big_table() {
169 let input = r#"- foo|foo
170---|---
171bar|bar"#;
172 let output = r#"<table>
173<thead>
174<tr>
175<th>- foo</th>
176<th>foo</th>
177</tr>
178</thead>
179<tbody>
180<tr>
181<td>bar</td>
182<td>bar</td>
183</tr>
184</tbody>
185</table>"#;
186 run(input, output);
187}
188
189#[test]
190fn second_line_should_not_contain_symbols_except_and() {
191 let input = r#"foo|foo
192-----|-----s
193bar|bar"#;
194 let output = r#"<p>foo|foo
195-----|-----s
196bar|bar</p>"#;
197 run(input, output);
198}
199
200#[test]
201fn second_line_should_contain_symbol() {
202 let input = r#"foo|foo
203-----:-----
204bar|bar"#;
205 let output = r#"<p>foo|foo
206-----:-----
207bar|bar</p>"#;
208 run(input, output);
209}
210
211#[test]
212fn second_line_should_not_have_empty_columns_in_the_middle() {
213 let input = r#"foo|foo
214-----||-----
215bar|bar"#;
216 let output = r#"<p>foo|foo
217-----||-----
218bar|bar</p>"#;
219 run(input, output);
220}
221
222#[test]
223fn wrong_alignment_symbol_position() {
224 let input = r#"foo|foo
225-----|-::-
226bar|bar"#;
227 let output = r#"<p>foo|foo
228-----|-::-
229bar|bar</p>"#;
230 run(input, output);
231}
232
233#[test]
234fn title_line_should_contain_symbol() {
235 let input = r#"foo
236-----|-----
237bar|bar"#;
238 let output = r#"<p>foo
239-----|-----
240bar|bar</p>"#;
241 run(input, output);
242}
243
244#[test]
245fn allow_tabs_as_a_separator_on_2nd_line() {
246 let input = "|\tfoo\t|\tbar\t|
247|\t---\t|\t---\t|
248|\tbaz\t|\tquux\t|";
249 let output = r#"<table>
250<thead>
251<tr>
252<th>foo</th>
253<th>bar</th>
254</tr>
255</thead>
256<tbody>
257<tr>
258<td>baz</td>
259<td>quux</td>
260</tr>
261</tbody>
262</table>"#;
263 run(input, output);
264}
265
266#[test]
267fn should_terminate_paragraph() {
268 let input = r#"paragraph
269foo|foo
270---|---
271bar|bar"#;
272 let output = r#"<p>paragraph</p>
273<table>
274<thead>
275<tr>
276<th>foo</th>
277<th>foo</th>
278</tr>
279</thead>
280<tbody>
281<tr>
282<td>bar</td>
283<td>bar</td>
284</tr>
285</tbody>
286</table>"#;
287 run(input, output);
288}
289
290#[test]
291fn another_complicated_backticks_case() {
292 let input = r#"| Heading 1 | Heading 2
293| --------- | ---------
294| Cell 1 | Cell 2
295| \\\`|\\\`"#;
296 let output = r#"<table>
297<thead>
298<tr>
299<th>Heading 1</th>
300<th>Heading 2</th>
301</tr>
302</thead>
303<tbody>
304<tr>
305<td>Cell 1</td>
306<td>Cell 2</td>
307</tr>
308<tr>
309<td>\`</td>
310<td>\`</td>
311</tr>
312</tbody>
313</table>"#;
314 run(input, output);
315}
316
317#[test]
318fn in_tables_should_not_count_as_escaped_backtick() {
319 let input = r#"# | 1 | 2
320--|--|--
321x | `\` | `x`"#;
322 let output = r#"<table>
323<thead>
324<tr>
325<th>#</th>
326<th>1</th>
327<th>2</th>
328</tr>
329</thead>
330<tbody>
331<tr>
332<td>x</td>
333<td><code>\</code></td>
334<td><code>x</code></td>
335</tr>
336</tbody>
337</table>"#;
338 run(input, output);
339}
340
341#[test]
342fn tables_should_handle_escaped_backticks() {
343 let input = r#"# | 1 | 2
344--|--|--
345x | \`\` | `x`"#;
346 let output = r#"<table>
347<thead>
348<tr>
349<th>#</th>
350<th>1</th>
351<th>2</th>
352</tr>
353</thead>
354<tbody>
355<tr>
356<td>x</td>
357<td>``</td>
358<td><code>x</code></td>
359</tr>
360</tbody>
361</table>"#;
362 run(input, output);
363}
364
365#[test]
366fn an_amount_of_rows_might_be_different_across_the_table_issue_171() {
367 let input = r#"| 1 | 2 |
368| :-----: | :-----: |
369| 3 | 4 | 5 | 6 |"#;
370 let output = r#"<table>
371<thead>
372<tr>
373<th style="text-align:center">1</th>
374<th style="text-align:center">2</th>
375</tr>
376</thead>
377<tbody>
378<tr>
379<td style="text-align:center">3</td>
380<td style="text-align:center">4</td>
381</tr>
382</tbody>
383</table>"#;
384 run(input, output);
385}
386
387#[test]
388fn an_amount_of_rows_might_be_different_across_the_table_2() {
389 let input = r#"| 1 | 2 | 3 | 4 |
390| :-----: | :-----: | :-----: | :-----: |
391| 5 | 6 |"#;
392 let output = r#"<table>
393<thead>
394<tr>
395<th style="text-align:center">1</th>
396<th style="text-align:center">2</th>
397<th style="text-align:center">3</th>
398<th style="text-align:center">4</th>
399</tr>
400</thead>
401<tbody>
402<tr>
403<td style="text-align:center">5</td>
404<td style="text-align:center">6</td>
405<td style="text-align:center"></td>
406<td style="text-align:center"></td>
407</tr>
408</tbody>
409</table>"#;
410 run(input, output);
411}
412
413#[test]
414fn allow_one_column_tables_issue_171() {
415 let input = r#"| foo |
416:-----:
417| bar |"#;
418 let output = r#"<table>
419<thead>
420<tr>
421<th style="text-align:center">foo</th>
422</tr>
423</thead>
424<tbody>
425<tr>
426<td style="text-align:center">bar</td>
427</tr>
428</tbody>
429</table>"#;
430 run(input, output);
431}
432
433#[test]
434fn allow_indented_tables_issue_325() {
435 let input = r#" | Col1a | Col2a |
436 | ----- | ----- |
437 | Col1b | Col2b |"#;
438 let output = r#"<table>
439<thead>
440<tr>
441<th>Col1a</th>
442<th>Col2a</th>
443</tr>
444</thead>
445<tbody>
446<tr>
447<td>Col1b</td>
448<td>Col2b</td>
449</tr>
450</tbody>
451</table>"#;
452 run(input, output);
453}
454
455#[test]
456fn tables_should_not_be_indented_more_than_4_spaces_1st_line() {
457 let input = r#" | Col1a | Col2a |
458 | ----- | ----- |
459 | Col1b | Col2b |"#;
460 let output = r#"<pre><code>| Col1a | Col2a |
461</code></pre>
462<p>| ----- | ----- |
463| Col1b | Col2b |</p>"#;
464 run(input, output);
465}
466
467#[test]
468fn tables_should_not_be_indented_more_than_4_spaces_2nd_line() {
469 let input = r#" | Col1a | Col2a |
470 | ----- | ----- |
471 | Col1b | Col2b |"#;
472 let output = r#"<p>| Col1a | Col2a |
473| ----- | ----- |
474| Col1b | Col2b |</p>"#;
475 run(input, output);
476}
477
478#[test]
479fn tables_should_not_be_indented_more_than_4_spaces_3rd_line() {
480 let input = r#" | Col1a | Col2a |
481 | ----- | ----- |
482 | Col1b | Col2b |"#;
483 let output = r#"<table>
484<thead>
485<tr>
486<th>Col1a</th>
487<th>Col2a</th>
488</tr>
489</thead>
490</table>
491<pre><code>| Col1b | Col2b |
492</code></pre>"#;
493 run(input, output);
494}
495
496#[test]
497fn allow_tables_with_empty_body() {
498 let input = r#" | Col1a | Col2a |
499 | ----- | ----- |"#;
500 let output = r#"<table>
501<thead>
502<tr>
503<th>Col1a</th>
504<th>Col2a</th>
505</tr>
506</thead>
507</table>"#;
508 run(input, output);
509}
510
511#[test]
512fn align_row_should_be_at_least_as_large_as_any_actual_rows() {
513 let input = r#"Col1a | Col1b | Col1c
514----- | -----
515Col2a | Col2b | Col2c"#;
516 let output = r#"<p>Col1a | Col1b | Col1c
517----- | -----
518Col2a | Col2b | Col2c</p>"#;
519 run(input, output);
520}
521
522#[test]
523fn escaped_pipes_inside_backticks_don_t_split_cells() {
524 let input = r#"| Heading 1 | Heading 2
525| --------- | ---------
526| Cell 1 | Cell 2
527| `Cell 3\|` | Cell 4"#;
528 let output = r#"<table>
529<thead>
530<tr>
531<th>Heading 1</th>
532<th>Heading 2</th>
533</tr>
534</thead>
535<tbody>
536<tr>
537<td>Cell 1</td>
538<td>Cell 2</td>
539</tr>
540<tr>
541<td><code>Cell 3|</code></td>
542<td>Cell 4</td>
543</tr>
544</tbody>
545</table>"#;
546 run(input, output);
547}
548
549#[test]
550fn escape_before_escaped_pipes_inside_backticks_don_t_split_cells() {
551 let input = r#"| Heading 1 | Heading 2
552| --------- | ---------
553| Cell 1 | Cell 2
554| `Cell 3\\|` | Cell 4"#;
555 let output = r#"<table>
556<thead>
557<tr>
558<th>Heading 1</th>
559<th>Heading 2</th>
560</tr>
561</thead>
562<tbody>
563<tr>
564<td>Cell 1</td>
565<td>Cell 2</td>
566</tr>
567<tr>
568<td><code>Cell 3\|</code></td>
569<td>Cell 4</td>
570</tr>
571</tbody>
572</table>"#;
573 run(input, output);
574}
575
576#[test]
577fn regression_test_for_721_table_in_a_list_indented_with_tabs() {
578 let input = "- Level 1
579
580\t- Level 2
581
582\t\t| Column 1 | Column 2 |
583\t\t| -------- | -------- |
584\t\t| abcdefgh | ijklmnop |";
585 let output = r#"<ul>
586<li>
587<p>Level 1</p>
588<ul>
589<li>
590<p>Level 2</p>
591<table>
592<thead>
593<tr>
594<th>Column 1</th>
595<th>Column 2</th>
596</tr>
597</thead>
598<tbody>
599<tr>
600<td>abcdefgh</td>
601<td>ijklmnop</td>
602</tr>
603</tbody>
604</table>
605</li>
606</ul>
607</li>
608</ul>"#;
609 run(input, output);
610}
611
612#[test]
613fn table_without_any_columns_is_not_a_table_724() {
614 let input = r#"|
615|
616|"#;
617 let output = r#"<p>|
618|
619|</p>"#;
620 run(input, output);
621}
622
623#[test]
624fn gfm_4_10_tables_extension_example_198() {
625 let input = r#"| foo | bar |
626| --- | --- |
627| baz | bim |"#;
628 let output = r#"<table>
629<thead>
630<tr>
631<th>foo</th>
632<th>bar</th>
633</tr>
634</thead>
635<tbody>
636<tr>
637<td>baz</td>
638<td>bim</td>
639</tr>
640</tbody>
641</table>"#;
642 run(input, output);
643}
644
645#[test]
646fn gfm_4_10_tables_extension_example_199() {
647 let input = r#"| abc | defghi |
648:-: | -----------:
649bar | baz"#;
650 let output = r#"<table>
651<thead>
652<tr>
653<th style="text-align:center">abc</th>
654<th style="text-align:right">defghi</th>
655</tr>
656</thead>
657<tbody>
658<tr>
659<td style="text-align:center">bar</td>
660<td style="text-align:right">baz</td>
661</tr>
662</tbody>
663</table>"#;
664 run(input, output);
665}
666
667#[test]
668fn gfm_4_10_tables_extension_example_200() {
669 let input = r#"| f\|oo |
670| ------ |
671| b `\|` az |
672| b **\|** im |"#;
673 let output = r#"<table>
674<thead>
675<tr>
676<th>f|oo</th>
677</tr>
678</thead>
679<tbody>
680<tr>
681<td>b <code>|</code> az</td>
682</tr>
683<tr>
684<td>b <strong>|</strong> im</td>
685</tr>
686</tbody>
687</table>"#;
688 run(input, output);
689}
690
691#[test]
692fn gfm_4_10_tables_extension_example_201() {
693 let input = r#"| abc | def |
694| --- | --- |
695| bar | baz |
696> bar"#;
697 let output = r#"<table>
698<thead>
699<tr>
700<th>abc</th>
701<th>def</th>
702</tr>
703</thead>
704<tbody>
705<tr>
706<td>bar</td>
707<td>baz</td>
708</tr>
709</tbody>
710</table>
711<blockquote>
712<p>bar</p>
713</blockquote>"#;
714 run(input, output);
715}
716
717#[test]
718fn gfm_4_10_tables_extension_example_202() {
719 let input = r#"| abc | def |
720| --- | --- |
721| bar | baz |
722bar
723
724bar"#;
725 let output = r#"<table>
726<thead>
727<tr>
728<th>abc</th>
729<th>def</th>
730</tr>
731</thead>
732<tbody>
733<tr>
734<td>bar</td>
735<td>baz</td>
736</tr>
737<tr>
738<td>bar</td>
739<td></td>
740</tr>
741</tbody>
742</table>
743<p>bar</p>"#;
744 run(input, output);
745}
746
747#[test]
748fn gfm_4_10_tables_extension_example_203() {
749 let input = r#"| abc | def |
750| --- |
751| bar |"#;
752 let output = r#"<p>| abc | def |
753| — |
754| bar |</p>"#;
755 run(input, output);
756}
757
758#[test]
759fn gfm_4_10_tables_extension_example_204() {
760 let input = r#"| abc | def |
761| --- | --- |
762| bar |
763| bar | baz | boo |"#;
764 let output = r#"<table>
765<thead>
766<tr>
767<th>abc</th>
768<th>def</th>
769</tr>
770</thead>
771<tbody>
772<tr>
773<td>bar</td>
774<td></td>
775</tr>
776<tr>
777<td>bar</td>
778<td>baz</td>
779</tr>
780</tbody>
781</table>"#;
782 run(input, output);
783}
784
785#[test]
786fn gfm_4_10_tables_extension_example_205() {
787 let input = r#"| abc | def |
788| --- | --- |"#;
789 let output = r#"<table>
790<thead>
791<tr>
792<th>abc</th>
793<th>def</th>
794</tr>
795</thead>
796</table>"#;
797 run(input, output);
798}
799
800#[test]
801fn a_list_takes_precedence_in_case_of_ambiguity() {
802 let input = r#"a | b
803- | -
8041 | 2"#;
805 let output = r#"<p>a | b</p>
806<ul>
807<li>| -
8081 | 2</li>
809</ul>"#;
810 run(input, output);
811}
812// end of auto-generated module
813}
814///////////////////////////////////////////////////////////////////////////
815// TESTGEN: fixtures/markdown-it/markdown-it-rs.txt
816#[rustfmt::skip]
817mod fixtures_markdown_it_markdown_it_rs_txt {
818use super::run;
819// this part of the file is auto-generated
820// don't edit it, otherwise your changes might be lost
821#[test]
822fn regression_test_for_panic_in_40() {
823 let input = r#"![hello'"`world](x)\"#;
824 let output = r#"<p><img src="x" alt="hello'&quot;`world">\</p>"#;
825 run(input, output);
826}
827// end of auto-generated module
828}