From b1590a4fb0c28fdb6af866ea79c186ea57284493 Mon Sep 17 00:00:00 2001 From: Titus Wormer Date: Wed, 31 Aug 2022 16:50:20 +0200 Subject: Add support for GFM tables --- tests/gfm_table.rs | 1782 +++++++++++++++++++++++++++++++++++++++++++++++ tests/heading_setext.rs | 12 + 2 files changed, 1794 insertions(+) create mode 100644 tests/gfm_table.rs (limited to 'tests') diff --git a/tests/gfm_table.rs b/tests/gfm_table.rs new file mode 100644 index 0000000..a265549 --- /dev/null +++ b/tests/gfm_table.rs @@ -0,0 +1,1782 @@ +extern crate micromark; +use micromark::{micromark, micromark_with_options, Constructs, Options}; +use pretty_assertions::assert_eq; + +#[test] +fn gfm_table() { + let gfm = Options { + constructs: Constructs::gfm(), + ..Options::default() + }; + + assert_eq!( + micromark("| a |\n| - |\n| b |"), + "

| a |\n| - |\n| b |

", + "should ignore tables by default" + ); + + assert_eq!( + micromark_with_options("| a |\n| - |\n| b |", &gfm), + "\n\n\n\n\n\n\n\n\n\n\n
a
b
", + "should support tables" + ); + + assert_eq!( + micromark_with_options("| a |", &gfm), + "

| a |

", + "should not support a table w/ the head row ending in an eof (1)" + ); + + assert_eq!( + micromark_with_options("| a", &gfm), + "

| a

", + "should not support a table w/ the head row ending in an eof (2)" + ); + + assert_eq!( + micromark_with_options("a |", &gfm), + "

a |

", + "should not support a table w/ the head row ending in an eof (3)" + ); + + assert_eq!( + micromark_with_options("| a |\n| - |", &gfm), + "\n\n\n\n\n\n
a
", + "should support a table w/ a delimiter row ending in an eof (1)" + ); + + assert_eq!( + micromark_with_options("| a\n| -", &gfm), + "\n\n\n\n\n\n
a
", + "should support a table w/ a delimiter row ending in an eof (2)" + ); + + assert_eq!( + micromark_with_options("| a |\n| - |\n| b |", &gfm), + "\n\n\n\n\n\n\n\n\n\n\n
a
b
", + "should support a table w/ a body row ending in an eof (1)" + ); + + assert_eq!( + micromark_with_options("| a\n| -\n| b", &gfm), + "\n\n\n\n\n\n\n\n\n\n\n
a
b
", + "should support a table w/ a body row ending in an eof (2)" + ); + + assert_eq!( + micromark_with_options("a|b\n-|-\nc|d", &gfm), + "\n\n\n\n\n\n\n\n\n\n\n\n\n
ab
cd
", + "should support a table w/ a body row ending in an eof (3)" + ); + + assert_eq!( + micromark_with_options("| a \n| -\t\n| b | ", &gfm), + "\n\n\n\n\n\n\n\n\n\n\n
a
b
", + "should support rows w/ trailing whitespace (1)" + ); + + assert_eq!( + micromark_with_options("| a | \n| - |", &gfm), + "\n\n\n\n\n\n
a
", + "should support rows w/ trailing whitespace (2)" + ); + + assert_eq!( + micromark_with_options("| a |\n| - | ", &gfm), + "\n\n\n\n\n\n
a
", + "should support rows w/ trailing whitespace (3)" + ); + + assert_eq!( + micromark_with_options("| a |\n| - |\n| b | ", &gfm), + "\n\n\n\n\n\n\n\n\n\n\n
a
b
", + "should support rows w/ trailing whitespace (4)" + ); + + assert_eq!( + micromark_with_options("||a|\n|-|-|", &gfm), + "\n\n\n\n\n\n\n
a
", + "should support empty first header cells" + ); + + assert_eq!( + micromark_with_options("|a||\n|-|-|", &gfm), + "\n\n\n\n\n\n\n
a
", + "should support empty last header cells" + ); + + assert_eq!( + micromark_with_options("a||b\n-|-|-", &gfm), + "\n\n\n\n\n\n\n\n
ab
", + "should support empty header cells" + ); + + assert_eq!( + micromark_with_options("|a|b|\n|-|-|\n||c|", &gfm), + "\n\n\n\n\n\n\n\n\n\n\n\n\n
ab
c
", + "should support empty first body cells" + ); + + assert_eq!( + micromark_with_options("|a|b|\n|-|-|\n|c||", &gfm), + "\n\n\n\n\n\n\n\n\n\n\n\n\n
ab
c
", + "should support empty last body cells" + ); + + assert_eq!( + micromark_with_options("a|b|c\n-|-|-\nd||e", &gfm), + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n
abc
de
", + "should support empty body cells" + ); + + assert_eq!( + micromark_with_options("| a |\n| - |\n- b", &gfm), + "\n\n\n\n\n\n
a
\n", + "should support a list after a table" + ); + + assert_eq!( + micromark_with_options("> | a |\n| - |", &gfm), + "
\n

| a |\n| - |

\n
", + "should not support a lazy delimiter row (1)" + ); + + assert_eq!( + micromark_with_options("> a\n> | b |\n| - |", &gfm), + "
\n

a\n| b |\n| - |

\n
", + "should not support a lazy delimiter row (2)" + ); + + assert_eq!( + micromark_with_options("| a |\n> | - |", &gfm), + "

| a |

\n
\n

| - |

\n
", + "should not support a piercing delimiter row" + ); + + assert_eq!( + micromark_with_options("> a\n> | b |\n|-", &gfm), + "
\n

a\n| b |\n|-

\n
", + "should not support a lazy body row (2)" + ); + + assert_eq!( + micromark_with_options("> | a |\n> | - |\n| b |", &gfm), + "
\n\n\n\n\n\n\n
a
\n
\n

| b |

", + "should not support a lazy body row (1)" + ); + + assert_eq!( + micromark_with_options("> a\n> | b |\n> | - |\n| c |", &gfm), + "
\n

a

\n\n\n\n\n\n\n
b
\n
\n

| c |

", + "should not support a lazy body row (2)" + ); + + assert_eq!( + micromark_with_options("> | A |\n> | - |\n> | 1 |\n| 2 |", &gfm), + "
\n\n\n\n\n\n\n\n\n\n\n\n
A
1
\n
\n

| 2 |

", + "should not support a lazy body row (3)" + ); + + assert_eq!( + micromark_with_options(" - d\n - e", &gfm), + micromark(" - d\n - e"), + "should not change how lists and lazyness work" + ); + + assert_eq!( + micromark_with_options("| a |\n | - |", &gfm), + "\n\n\n\n\n\n
a
", + "should form a table if the delimiter row is indented w/ 3 spaces" + ); + + assert_eq!( + micromark_with_options("| a |\n | - |", &gfm), + "

| a |\n| - |

", + "should not form a table if the delimiter row is indented w/ 4 spaces" + ); + + assert_eq!( + micromark_with_options("| a |\n | - |", &Options { + constructs: Constructs { + code_indented: false, + ..Constructs::gfm() + }, + ..Options::default() + }), + "\n\n\n\n\n\n
a
", + "should form a table if the delimiter row is indented w/ 4 spaces and indented code is turned off" + ); + + assert_eq!( + micromark_with_options("| a |\n| - |\n> block quote?", &gfm), + "\n\n\n\n\n\n
a
\n
\n

block quote?

\n
", + "should be interrupted by a block quote" + ); + + assert_eq!( + micromark_with_options("| a |\n| - |\n>", &gfm), + "\n\n\n\n\n\n
a
\n
\n
", + "should be interrupted by a block quote (empty)" + ); + + assert_eq!( + micromark_with_options("| a |\n| - |\n- list?", &gfm), + "\n\n\n\n\n\n
a
\n", + "should be interrupted by a list" + ); + + assert_eq!( + micromark_with_options("| a |\n| - |\n-", &gfm), + "\n\n\n\n\n\n
a
\n", + "should be interrupted by a list (empty)" + ); + + assert_eq!( + micromark_with_options( + "| a |\n| - |\n", + &Options { + allow_dangerous_html: true, + constructs: Constructs::gfm(), + ..Options::default() + } + ), + "\n\n\n\n\n\n
a
\n", + "should be interrupted by HTML (flow)" + ); + + assert_eq!( + micromark_with_options("| a |\n| - |\n\tcode?", &Options { + allow_dangerous_html: true, + constructs: Constructs::gfm(), + ..Options::default() + }), + "\n\n\n\n\n\n
a
\n
code?\n
", + "should be interrupted by code (indented)" + ); + + assert_eq!( + micromark_with_options("| a |\n| - |\n```js\ncode?", &Options { + allow_dangerous_html: true, + constructs: Constructs::gfm(), + ..Options::default() + }), + "\n\n\n\n\n\n
a
\n
code?\n
\n", + "should be interrupted by code (fenced)" + ); + + assert_eq!( + micromark_with_options( + "| a |\n| - |\n***", + &Options { + allow_dangerous_html: true, + constructs: Constructs::gfm(), + ..Options::default() + } + ), + "\n\n\n\n\n\n
a
\n
", + "should be interrupted by a thematic break" + ); + + assert_eq!( + micromark_with_options("| a |\n| - |\n# heading?", &gfm), + "\n\n\n\n\n\n
a
\n

heading?

", + "should be interrupted by a heading (ATX)" + ); + + assert_eq!( + micromark_with_options("| a |\n| - |\nheading\n=", &gfm), + "\n\n\n\n\n\n\n\n\n\n\n\n\n\n
a
heading
=
", + "should *not* be interrupted by a heading (setext)" + ); + + assert_eq!( + micromark_with_options("| a |\n| - |\nheading\n---", &gfm), + "\n\n\n\n\n\n\n\n\n\n\n
a
heading
\n
", + "should *not* be interrupted by a heading (setext), but interrupt if the underline is also a thematic break" + ); + + assert_eq!( + micromark_with_options("| a |\n| - |\nheading\n-", &gfm), + "\n\n\n\n\n\n\n\n\n\n\n
a
heading
\n", + "should *not* be interrupted by a heading (setext), but interrupt if the underline is also an empty list item bullet" + ); + + assert_eq!( + micromark_with_options("a\nb\n-:", &gfm), + "

a

\n\n\n\n\n\n\n
b
", + "should support a single head row" + ); + + assert_eq!( + micromark_with_options("> | a |\n> | - |", &gfm), + "
\n\n\n\n\n\n\n
a
\n
", + "should support a table in a container" + ); + + assert_eq!( + micromark_with_options("> | a |\n| - |", &gfm), + "
\n

| a |\n| - |

\n
", + "should not support a lazy delimiter row if the head row is in a container" + ); + + assert_eq!( + micromark_with_options("| a |\n> | - |", &gfm), + "

| a |

\n
\n

| - |

\n
", + "should not support a “piercing” container for the delimiter row, if the head row was not in that container" + ); + + assert_eq!( + micromark_with_options("> | a |\n> | - |\n| c |", &gfm), + "
\n\n\n\n\n\n\n
a
\n
\n

| c |

", + "should not support a lazy body row if the head row and delimiter row are in a container" + ); + + assert_eq!( + micromark_with_options("> | a |\n| - |\n> | c |", &gfm), + "
\n

| a |\n| - |\n| c |

\n
", + "should not support a lazy delimiter row if the head row and a further body row are in a container" + ); + + assert_eq!(micromark_with_options("", &gfm), "", "should support"); + + assert_eq!(micromark_with_options("", &gfm), "", "should support"); + + assert_eq!( + micromark_with_options( + r###"# Align + +## An empty initial cell + +| | a|c| +|--|:----:|:---| +|a|b|c| +|a|b|c| + +## Missing alignment characters + +| a | b | c | +| |---|---| +| d | e | f | + +* * * + +| a | b | c | +|---|---| | +| d | e | f | + +## Incorrect characters + +| a | b | c | +|---|-*-|---| +| d | e | f | + +## Two alignments + +|a| +|::| + +|a| +|:-:| + +## Two at the start or end + +|a| +|::-| + +|a| +|-::| + +## In the middle + +|a| +|-:-| + +## A space in the middle + +|a| +|- -| + +## No pipe + +a +:-: + +a +:- + +a +-: + +## A single colon + +|a| +|:| + +a +: + +## Alignment on empty cells + +| a | b | c | d | e | +| - | - | :- | -: | :-: | +| f | +"###, + &gfm + ), + r###"

Align

+

An empty initial cell

+ + + + + + + + + + + + + + + + + + + + +
ac
abc
abc
+

Missing alignment characters

+

| a | b | c | +| |---|---| +| d | e | f |

+
+

| a | b | c | +|---|---| | +| d | e | f |

+

Incorrect characters

+

| a | b | c | +|---|-*-|---| +| d | e | f |

+

Two alignments

+

|a| +|::|

+ + + + + + +
a
+

Two at the start or end

+

|a| +|::-|

+

|a| +|-::|

+

In the middle

+

|a| +|-:-|

+

A space in the middle

+

|a| +|- -|

+

No pipe

+ + + + + + +
a
+ + + + + + +
a
+ + + + + + +
a
+

A single colon

+

|a| +|:|

+

a +:

+

Alignment on empty cells

+ + + + + + + + + + + + + + + + + + + +
abcde
f
+"###, + "should match alignment like GitHub" + ); + + assert_eq!( + micromark_with_options( + r###"# Tables + +| a | b | c | +| - | - | - | +| d | e | f | + +## No body + +| a | b | c | +| - | - | - | + +## One column + +| a | +| - | +| b | +"###, + &gfm + ), + r###"

Tables

+ + + + + + + + + + + + + + + +
abc
def
+

No body

+ + + + + + + + +
abc
+

One column

+ + + + + + + + + + + +
a
b
+"###, + "should match basic like GitHub" + ); + + assert_eq!( + micromark_with_options( + r###"# Tables in things + +## In lists + +* Unordered: + + | A | B | + | - | - | + | 1 | 2 | + +1. Ordered: + + | A | B | + | - | - | + | 1 | 2 | + +* Lazy? + | A | B | + | - | - | + | 1 | 2 | + | 3 | 4 | + | 5 | 6 | +| 7 | 8 | + +## In block quotes + +> W/ space: +> | A | B | +> | - | - | +> | 1 | 2 | + +>W/o space: +>| A | B | +>| - | - | +>| 1 | 2 | + +> Lazy? +> | A | B | +> | - | - | +> | 1 | 2 | +>| 3 | 4 | +| 5 | 6 | + +### List interrupting delimiters + +a | +- | + +a +-| + +a +|- +"###, + &gfm + ), + r###"

Tables in things

+

In lists

+ +
    +
  1. +

    Ordered:

    + + + + + + + + + + + + + +
    AB
    12
    +
  2. +
+ +

| 1 | 2 | +| 3 | 4 | +| 5 | 6 | +| 7 | 8 |

+

In block quotes

+
+

W/ space:

+ + + + + + + + + + + + + +
AB
12
+
+
+

W/o space:

+ + + + + + + + + + + + + +
AB
12
+
+
+

Lazy?

+ + + + + + + + + + + + + + + + + +
AB
12
34
+
+

| 5 | 6 |

+

List interrupting delimiters

+

a |

+ + + + + + + +
a
+ + + + + + +
a
+"###, + "should match containers like GitHub" + ); + + assert_eq!( + micromark_with_options( + r###"| a | +| - | +| - | +| 1 | +"###, + &gfm + ), + r###" + + + + + + + + + + + + + +
a
-
1
+"###, + "should match a double delimiter row like GitHub" + ); + + assert_eq!( + micromark_with_options( + r###"# Examples from GFM + +## A + +| foo | bar | +| --- | --- | +| baz | bim | + +## B + +| abc | defghi | +:-: | -----------: +bar | baz + +## C + +| f\|oo | +| ------ | +| b `\|` az | +| b **\|** im | + +## D + +| abc | def | +| --- | --- | +| bar | baz | +> bar + +## E + +| abc | def | +| --- | --- | +| bar | baz | +bar + +bar + +## F + +| abc | def | +| --- | +| bar | + +## G + +| abc | def | +| --- | --- | +| bar | +| bar | baz | boo | + +## H + +| abc | def | +| --- | --- | +"###, + &gfm + ), + r###"

Examples from GFM

+

A

+ + + + + + + + + + + + + +
foobar
bazbim
+

B

+ + + + + + + + + + + + + +
abcdefghi
barbaz
+

C

+ + + + + + + + + + + + + + +
f|oo
b | az
b | im
+

D

+ + + + + + + + + + + + + +
abcdef
barbaz
+
+

bar

+
+

E

+ + + + + + + + + + + + + + + + + +
abcdef
barbaz
bar
+

bar

+

F

+

| abc | def | +| --- | +| bar |

+

G

+ + + + + + + + + + + + + + + + + +
abcdef
bar
barbaz
+

H

+ + + + + + + +
abcdef
+"###, + "should match examples from the GFM spec like GitHub" + ); + + assert_eq!( + micromark_with_options( + r###"# Grave accents + +## Grave accent in cell + +| A | B | +|--------------|---| +| ` | C | + +## Escaped grave accent in “inline code” in cell + +| A | +|-----| +| `\` | + +## “Empty” inline code + +| 1 | 2 | 3 | +|---|------|----| +| a | `` | | +| b | `` | `` | +| c | ` | ` | +| d | `|` | +| e | `\|` | | +| f | \| | | + +## Escaped pipes in code in cells + +| `\|\\` | +| --- | +| `\|\\` | + +`\|\\` +"###, + &Options { + allow_dangerous_html: true, + ..gfm.clone() + } + ), + r###"

Grave accents

+

Grave accent in cell

+ + + + + + + + + + + + + +
AB
`C
+

Escaped grave accent in “inline code” in cell

+ + + + + + + + + + + +
A
\
+

“Empty” inline code

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
123
a``
b````
c``
d``
e|
f|
+

Escaped pipes in code in cells

+ + + + + + + + + + + +
|\\
|\\
+

\|\\

+"###, + "should match grave accent like GitHub" + ); + + assert_eq!( + micromark_with_options( + r###"# Code + +## Indented delimiter row + +a + |- + +a + |- + +## Indented body + +| a | + | - | + | C | + | D | + | E | +"###, + &gfm + ), + r###"

Code

+

Indented delimiter row

+ + + + + + +
a
+

a +|-

+

Indented body

+ + + + + + + + + + + + + + +
a
C
D
+
| E |
+
+"###, + "should match indent like GitHub" + ); + + assert_eq!( + micromark_with_options( + r###"## Blank line + +a +:- +b + +c + +## Block quote + +a +:- +b +> c + +## Code (fenced) + +a +:- +b +``` +c +``` + +## Code (indented) + +a +:- +b + c + +## Definition + +a +:- +b +[c]: d + +## Heading (atx) + +a +:- +b +# c + + +## Heading (setext) (rank 1) + +a +:- +b +== +c + +## Heading (setext) (rank 2) + +a +:- +b +-- +c + +## HTML (flow, kind 1: raw) + +a +:- +b +
+  a
+
+ +## HTML (flow, kind 2: comment) + +a +:- +b + + +## HTML (flow, kind 3: instruction) + +a +:- +b + + +## HTML (flow, kind 4: declaration) + +a +:- +b + + +## HTML (flow, kind 5: cdata) + +a +:- +b + + +## HTML (flow, kind 6: basic) + +a +:- +b +
+ +## HTML (flow, kind 7: complete) + +a +:- +b + + +## List (ordered, 1) + +a +:- +b +1. c + +## List (ordered, other) + +a +:- +b +2. c + +## List (unordered) + +a +:- +b +* c + +## List (unordered, blank) + +a +:- +b +* +c + +## List (unordered, blank start) + +a +:- +b +* + c + +## Thematic break + +a +:- +b +*** +"###, + &Options { + allow_dangerous_html: true, + ..gfm.clone() + } + ), + r###"

Blank line

+ + + + + + + + + + + +
a
b
+

c

+

Block quote

+ + + + + + + + + + + +
a
b
+
+

c

+
+

Code (fenced)

+ + + + + + + + + + + +
a
b
+
c
+
+

Code (indented)

+ + + + + + + + + + + +
a
b
+
c
+
+

Definition

+ + + + + + + + + + + + + + +
a
b
[c]: d
+

Heading (atx)

+ + + + + + + + + + + +
a
b
+

c

+

Heading (setext) (rank 1)

+ + + + + + + + + + + + + + + + + +
a
b
==
c
+

Heading (setext) (rank 2)

+ + + + + + + + + + + + + + + + + +
a
b
--
c
+

HTML (flow, kind 1: raw)

+ + + + + + + + + + + +
a
b
+
+  a
+
+

HTML (flow, kind 2: comment)

+ + + + + + + + + + + +
a
b
+ +

HTML (flow, kind 3: instruction)

+ + + + + + + + + + + +
a
b
+ +

HTML (flow, kind 4: declaration)

+ + + + + + + + + + + +
a
b
+ +

HTML (flow, kind 5: cdata)

+ + + + + + + + + + + +
a
b
+ +

HTML (flow, kind 6: basic)

+ + + + + + + + + + + +
a
b
+
+

HTML (flow, kind 7: complete)

+ + + + + + + + + + + +
a
b
+ +

List (ordered, 1)

+ + + + + + + + + + + +
a
b
+
    +
  1. c
  2. +
+

List (ordered, other)

+ + + + + + + + + + + +
a
b
+
    +
  1. c
  2. +
+

List (unordered)

+ + + + + + + + + + + +
a
b
+
    +
  • c
  • +
+

List (unordered, blank)

+ + + + + + + + + + + +
a
b
+
    +
  • +
+

c

+

List (unordered, blank start)

+ + + + + + + + + + + +
a
b
+
    +
  • c
  • +
+

Thematic break

+ + + + + + + + + + + +
a
b
+
+"###, + "should match interrupt like GitHub" + ); + + assert_eq!( + micromark_with_options( + r###"# Loose + +## Loose + +Header 1 | Header 2 +-------- | -------- +Cell 1 | Cell 2 +Cell 3 | Cell 4 + +## One “column”, loose + +a +- +b + +## No pipe in first row + +a +| - | +"###, + &gfm + ), + r###"

Loose

+

Loose

+ + + + + + + + + + + + + + + + + +
Header 1Header 2
Cell 1Cell 2
Cell 3Cell 4
+

One “column”, loose

+

a

+

b

+

No pipe in first row

+ + + + + + +
a
+"###, + "should match loose tables like GitHub" + ); + + assert_eq!( + micromark_with_options( + r###"# Some more escapes + +| Head | +| ------------- | +| A | Alpha | +| B \| Bravo | +| C \\| Charlie | +| D \\\| Delta | +| E \\\\| Echo | + +Note: GH has a bug where in case C and E, the escaped escape is treated as a +normal escape: . +"###, + &gfm + ), + r###"

Some more escapes

+ + + + + + + + + + + + + + + + + + + + + + + +
Head
A
B | Bravo
C \
D \| Delta
E \\
+

Note: GH has a bug where in case C and E, the escaped escape is treated as a +normal escape: https://github.com/github/cmark-gfm/issues/277.

+"###, + "should match loose escapes like GitHub" + ); +} diff --git a/tests/heading_setext.rs b/tests/heading_setext.rs index 22155f0..fa979be 100644 --- a/tests/heading_setext.rs +++ b/tests/heading_setext.rs @@ -257,6 +257,18 @@ fn heading_setext() { "should not support lazyness (2)" ); + assert_eq!( + micromark("a\n- ==="), + "

a

\n
    \n
  • ===
  • \n
", + "should not support piercing (1)" + ); + + assert_eq!( + micromark("a\n* ---"), + "

a

\n
    \n
  • \n
    \n
  • \n
", + "should not support piercing (2)" + ); + assert_eq!( micromark_with_options( "a\n-", -- cgit