1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495 | package tui
import (
"strings"
"testing"
"github.com/charmbracelet/x/ansi"
)
func TestMarkdownInline(t *testing.T) {
for in, want := range map[string]string{
"**bold** and *it*": "bold and it",
"snake_case_name": "snake_case_name",
"2 * 3 * 4": "2 * 3 * 4",
"`a*b*c` code": "a*b*c code",
`\*not\*`: "*not*",
"[docs](https://x.y/z)": "docs (https://x.y/z)",
"~~gone~~ **unclosed": "gone **unclosed",
"## Heading": "Heading",
"- item": "• item",
" 3. third": " 3. third",
"> quoted": "│ quoted",
} {
if got := ansi.Strip(markdown(in, 80)); got != want {
t.Errorf("markdown(%q) = %q, want %q", in, got, want)
}
}
}
func TestMarkdownTable(t *testing.T) {
in := "| Name | N |\n|:-----|--:|\n| a `x|y` | 1 |\n| long name | 22 |"
want := strings.Join([]string{
"┌───────────┬────┐",
"│ Name │ N │",
"├───────────┼────┤",
"│ a x|y │ 1 │",
"│ long name │ 22 │",
"└───────────┴────┘",
}, "\n")
if got := ansi.Strip(markdown(in, 80)); got != want {
t.Errorf("table:\n%s\nwant:\n%s", got, want)
}
// Too wide for the screen: cells wrap, and no line is wider than it.
wide := "| a | b |\n|---|---|\n| " + strings.Repeat("word ", 20) + "| " + strings.Repeat("more ", 20) + "|"
for _, l := range strings.Split(markdown(wide, 40), "\n") {
if w := ansi.StringWidth(l); w > 40 {
t.Errorf("line %q is %d wide", ansi.Strip(l), w)
}
}
}
// Every line stands alone: it ends with a reset, so a style cannot run
// into the next one or the interface after it.
func TestMarkdownLinesReset(t *testing.T) {
out := markdown("**"+strings.Repeat("bold ", 30)+"**\n```\ncode\n```", 40)
for _, l := range strings.Split(out, "\n") {
if strings.Contains(l, "\x1b") && !strings.HasSuffix(l, sgrReset) {
t.Errorf("line %q does not end with a reset", l)
}
}
}
// A row with more cells than the header shows them all.
func TestTableExtraCells(t *testing.T) {
out := ansi.Strip(markdown("| a | b |\n|---|---|\n| x | y | HIDDEN |\n", 80))
if !strings.Contains(out, "HIDDEN") {
t.Errorf("lost a cell:\n%s", out)
}
}
// Rendering keeps every word of the text: Markdown syntax goes, but
// nothing the model wrote may vanish from the screen.
func FuzzMarkdownKeepsWords(f *testing.F) {
for _, s := range []string{
"| a | b |\n|---|---|\n| x | y | z |",
"# Title\n\n*em* **strong** `code` [text](https://u.example/path) ~~gone~~",
"```go extra words\nfunc main() {}\n```",
"> quote\n- item\n1. first\n\n---\n",
"a\\*b\\_c <html> &",
} {
f.Add(s)
}
f.Fuzz(func(t *testing.T, s string) {
s = Sanitize(s)
out := ansi.Strip(markdown(s, 10000))
flat := strings.Join(strings.Fields(out), "")
for _, w := range strings.FieldsFunc(s, func(r rune) bool {
return !(r >= 'a' && r <= 'z' || r >= 'A' && r <= 'Z' || r >= '0' && r <= '9')
}) {
if !strings.Contains(flat, w) {
t.Fatalf("markdown(%q) lost %q:\n%s", s, w, out)
}
}
})
}
|