feat: render Markdown, mathematics and Mermaid diagrams server-side
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
||||
// SPDX-License-Identifier: MIT
|
||||
|
||||
package markdown
|
||||
|
||||
import "testing"
|
||||
|
||||
// gfmCorpus holds the cases of the GitHub Flavored Markdown extensions:
|
||||
// tables, strikethrough and task lists.
|
||||
var gfmCorpus = []struct {
|
||||
name string
|
||||
input string
|
||||
want string
|
||||
}{
|
||||
// Tables, in the multi-line shape the GFM specification prints.
|
||||
{"table basic", "| foo | bar |\n| --- | --- |\n| baz | bim |",
|
||||
"<table>\n<thead>\n<tr>\n<th>foo</th>\n<th>bar</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>baz</td>\n<td>bim</td>\n</tr>\n</tbody>\n</table>\n"},
|
||||
{"table without boundary pipes", "foo | bar\n--- | ---\nbaz | bim",
|
||||
"<table>\n<thead>\n<tr>\n<th>foo</th>\n<th>bar</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>baz</td>\n<td>bim</td>\n</tr>\n</tbody>\n</table>\n"},
|
||||
{"table alignment", "| a | b | c | d |\n| :- | :-: | -: | - |",
|
||||
"<table>\n<thead>\n<tr>\n<th align=\"left\">a</th>\n<th align=\"center\">b</th>\n<th align=\"right\">c</th>\n<th>d</th>\n</tr>\n</thead>\n</table>\n"},
|
||||
{"table without body", "| abc | def |\n| --- | --- |",
|
||||
"<table>\n<thead>\n<tr>\n<th>abc</th>\n<th>def</th>\n</tr>\n</thead>\n</table>\n"},
|
||||
{"table excess cell ignored", "| a | b |\n| --- | --- |\n| c | d | e |",
|
||||
"<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>c</td>\n<td>d</td>\n</tr>\n</tbody>\n</table>\n"},
|
||||
{"table missing cell empty", "| a | b |\n| --- | --- |\n| c |",
|
||||
"<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>c</td>\n<td></td>\n</tr>\n</tbody>\n</table>\n"},
|
||||
{"table count mismatch stays paragraph", "| a | b |\n| --- |\n| c |",
|
||||
"<p>| a | b |\n| --- |\n| c |</p>\n"},
|
||||
{"table escaped pipe", "| a \\| b | c |\n| --- | --- |",
|
||||
"<table>\n<thead>\n<tr>\n<th>a | b</th>\n<th>c</th>\n</tr>\n</thead>\n</table>\n"},
|
||||
{"table cells hold inline", "| *a* | `b` |\n| --- | --- |",
|
||||
"<table>\n<thead>\n<tr>\n<th><em>a</em></th>\n<th><code>b</code></th>\n</tr>\n</thead>\n</table>\n"},
|
||||
{"table code span escaped pipe", "| f\\|oo |\n| --- |\n| b `\\|` az |",
|
||||
"<table>\n<thead>\n<tr>\n<th>f|oo</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>b <code>|</code> az</td>\n</tr>\n</tbody>\n</table>\n"},
|
||||
{"table breaks at blank", "| a |\n| --- |\n| b |\n\nparagraph",
|
||||
"<table>\n<thead>\n<tr>\n<th>a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>b</td>\n</tr>\n</tbody>\n</table>\n<p>paragraph</p>\n"},
|
||||
{"table interrupted by heading", "| a |\n| --- |\n| b |\n# h",
|
||||
"<table>\n<thead>\n<tr>\n<th>a</th>\n</tr>\n</thead>\n<tbody>\n<tr>\n<td>b</td>\n</tr>\n</tbody>\n</table>\n<h1>h</h1>\n"},
|
||||
{"table interrupts paragraph", "a | b\n--- | ---",
|
||||
"<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n</table>\n"},
|
||||
{"table splits paragraph", "foo\na | b\n--- | ---",
|
||||
"<p>foo</p>\n<table>\n<thead>\n<tr>\n<th>a</th>\n<th>b</th>\n</tr>\n</thead>\n</table>\n"},
|
||||
{"setext without pipes stays", "abc\n---", "<h2>abc</h2>\n"},
|
||||
|
||||
// Strikethrough.
|
||||
{"strikethrough double tilde", "~~foo~~", "<p><del>foo</del></p>\n"},
|
||||
{"strikethrough single tilde", "~foo~", "<p><del>foo</del></p>\n"},
|
||||
{"strikethrough unmatched pair", "~~foo~", "<p>~<del>foo</del></p>\n"},
|
||||
{"strikethrough intraword", "foo~~bar~~baz", "<p>foo<del>bar</del>baz</p>\n"},
|
||||
{"tilde spaced stays literal", "a ~ b", "<p>a ~ b</p>\n"},
|
||||
|
||||
// Task lists.
|
||||
{"task checked", "- [x] foo", "<ul>\n<li><input checked=\"\" disabled=\"\" type=\"checkbox\"> foo</li>\n</ul>\n"},
|
||||
{"task unchecked", "- [ ] foo", "<ul>\n<li><input disabled=\"\" type=\"checkbox\"> foo</li>\n</ul>\n"},
|
||||
{"task uppercase x", "- [X] foo", "<ul>\n<li><input checked=\"\" disabled=\"\" type=\"checkbox\"> foo</li>\n</ul>\n"},
|
||||
{"task needs a space", "- [x]foo", "<ul>\n<li>[x]foo</li>\n</ul>\n"},
|
||||
{"task list of two", "- [x] foo\n- [ ] bar",
|
||||
"<ul>\n<li><input checked=\"\" disabled=\"\" type=\"checkbox\"> foo</li>\n<li><input disabled=\"\" type=\"checkbox\"> bar</li>\n</ul>\n"},
|
||||
{"task nested", "- [x] foo\n - [ ] bar",
|
||||
"<ul>\n<li><input checked=\"\" disabled=\"\" type=\"checkbox\"> foo\n<ul>\n<li><input disabled=\"\" type=\"checkbox\"> bar</li>\n</ul>\n</li>\n</ul>\n"},
|
||||
{"task in loose list", "- [x] foo\n\n- [ ] bar",
|
||||
"<ul>\n<li>\n<p><input checked=\"\" disabled=\"\" type=\"checkbox\"> foo</p>\n</li>\n<li>\n<p><input disabled=\"\" type=\"checkbox\"> bar</p>\n</li>\n</ul>\n"},
|
||||
}
|
||||
|
||||
func TestGFMCorpus(t *testing.T) {
|
||||
for _, tc := range gfmCorpus {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
got := string(RenderHTML([]byte(tc.input)))
|
||||
if got != tc.want {
|
||||
t.Errorf("input %q\ngot: %q\nwant: %q", tc.input, got, tc.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user