1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124
|
import json
from pathlib import Path
from _pytest.mark import ParameterSet
import pytest
import mdformat
from mdformat._util import is_md_equal
SPECTESTS_PATH = Path(__file__).parent / "data" / "commonmark_spec_v0.31.2.json"
SPECTESTS_CASES = tuple(
{"name": str(entry["example"]), "md": entry["markdown"]}
for entry in json.loads(SPECTESTS_PATH.read_text(encoding="utf-8"))
)
EXTRA_CASES = (
{
"name": "titles",
"md": "# BIG Title\n"
"## smaller\n"
"### even smaller\n"
"#### 4th level\n"
"##### 5th level\n"
"###### the smallest (6th level)\n",
},
{"name": "emphasis", "md": "*emphasized*\n" "**STRONGLY emphasized**\n"},
{
"name": "simple",
"md": "# BIG Title\n" "> a quote here\n\n" "Paragraph is here.\n",
},
{"name": "strikethrough", "md": "# Testing strikethrough\n" "~~here goes~~\n"},
{"name": "code span", "md": "`print('Hello World!)`\n"},
{
"name": "code span: double spaces",
"md": "` starts and ends with double spaces `\n",
},
{"name": "escape char", "md": "\\*not emphasized\\*\n"},
{
"name": "fenced code",
"md": "## Here's a code block\n"
"```python\n"
"print('Hello world!')\n"
"```\n",
},
{"name": "paragraph line feeds", "md": "first paragraph\n\n" "second one\n"},
{"name": "thematic break", "md": "thematic break\n\n" "---\n" "above\n"},
{"name": "autolink", "md": "<http://foo.bar.baz>\n"},
{"name": "link", "md": '[link](/uri "title")\n' "[link](/uri)\n" "[link]()\n"},
{"name": "image", "md": '\n' "](/url2)\n"},
{"name": "unordered list", "md": "- item1\n" "- item2\n"},
{"name": "unordered loose list", "md": "- item1\n" "\n" "- item2\n"},
{"name": "ordered list", "md": "1. item1\n" "1. item2\n"},
{"name": "ordered list 2", "md": "10021. item1\n" "10021. item2\n"},
{"name": "ordered list zero", "md": "0. item1\n" "0. item2\n"},
{"name": "whitespace preserve", "md": "- foo\n\n\tbar\n"},
{"name": "debug", "md": "> ```\n> a\n> \n> \n> ```\n"},
{"name": "list indentation", "md": "- foo\n\n\t\tbar\n"},
{"name": "list in quote", "md": "> -"},
{"name": "starts with >", "md": "\\>"},
{"name": "reference link", "md": '[foo][bar]\n\n[bar]: /url "title"\n'},
{"name": "empty file", "md": ""},
{"name": "whitespace only", "md": " \n\n \n \n"},
{"name": "starts with em space", "md": " \n"},
{"name": "starts with space", "md": " \n"},
{"name": "trailing space", "md": "trailing space  \n"},
{"name": "soft breaks", "md": "this is\nall one\nparagraph\n"},
{"name": "escape underscore", "md": "# foo _bar_ \\_baz\\_\n"},
{
"name": "extend spectest 300",
"md": "\\_not emphasized_\n"
"1\\) not a list\n"
"\\- not a list\n"
"\\+ not a list\n",
},
{"name": "image link with brackets 1", "md": ">)\n"},
{"name": "image link with brackets 2", "md": ")\n"},
{"name": "image link with brackets 3", "md": "\\:)\n"},
{"name": "image link with brackets 4", "md": "c>)\n"},
{"name": "image link with brackets 5", "md": 'c> "some title")\n'},
{"name": "escaped thematic break (hyphen)", "md": "\\-\\-\\-\n"},
{"name": "escaped thematic break (underscore v1)", "md": "\\_\\_\\_\n"},
{"name": "escaped thematic break (underscore v2)", "md": " _ _ _ \n"},
{"name": "escaped thematic break (asterisk v1)", "md": "\\*\\*\\*\n"},
{"name": "escaped thematic break (asterisk v2)", "md": " * * * \n"},
{"name": "Hard break in setext heading", "md": "line1\\\nline2\n====\n"},
{
"name": "a mix of leading and trailing whitespace",
"md": "	foo\n"
"   foo 	 \n"
"	foo \t\n"
" foo \n"
"\u2005foo\u2005\n"
"foo\n",
},
)
ALL_CASES = EXTRA_CASES + SPECTESTS_CASES
@pytest.mark.parametrize("wrap", ["keep", "no", 60])
@pytest.mark.parametrize("number", [True, False])
@pytest.mark.parametrize(
"entry",
ALL_CASES,
ids=[
(
c.values[0]["name"] # type: ignore[index]
if isinstance(c, ParameterSet)
else c["name"]
)
for c in ALL_CASES
],
)
def test_commonmark_spec(wrap, number, entry):
"""mdformat.text() against the Commonmark spec.
Test that:
1. Markdown AST is the same before and after 1 pass of formatting
2. Markdown after 1st pass and 2nd pass of formatting are equal
"""
options = {"wrap": wrap, "number": number}
md_original = entry["md"]
md_new = mdformat.text(md_original, options=options)
md_2nd_pass = mdformat.text(md_new, options=options)
assert is_md_equal(md_original, md_new, options=options)
assert md_new == md_2nd_pass
|