package markdown
import (
"bytes"
"strings"
"testing"
)
func TestRendererBasicElements(t *testing.T) {
t.Parallel()
cases := []struct {
name string
src string
want []string
}{
{"paragraph", "hello world", []string{"<p>", "hello world", "</p>"}},
{"bold", "**bold**", []string{"<strong>", "bold", "</strong>"}},
{"italic", "*it*", []string{"<em>", "it", "</em>"}},
{"heading_h1", "# Title", []string{"<h1", "Title", "</h1>"}},
{"heading_h3", "### Sub", []string{"<h3", "Sub", "</h3>"}},
{"inline_code", "`code`", []string{"<code>", "code", "</code>"}},
{"link", "[t](https://example.com)", []string{`href="https://example.com"`, "t", "</a>"}},
{"ul", "- a\n- b", []string{"<ul>", "<li>", "a", "b", "</ul>"}},
{"ol", "1. a\n2. b", []string{"<ol>", "<li>", "a", "</ol>"}},
{"blockquote", "> quoted", []string{"<blockquote>", "quoted", "</blockquote>"}},
}
p := NewParser()
r := NewRenderer()
for _, tc := range cases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
doc, err := p.Parse([]byte(tc.src))
if err != nil {
t.Fatalf("Parse: %v", err)
}
got, err := r.RenderString(doc)
if err != nil {
t.Fatalf("Render: %v", err)
}
for _, want := range tc.want {
if !strings.Contains(got, want) {
t.Errorf("missing %q in output %q", want, got)
}
}
})
}
}
func TestRendererCodeBlockHandler(t *testing.T) {
t.Parallel()
var captured struct {
lang string
body string
}
r := NewRenderer()
r.CodeBlockHandler = func(lang string, body []byte, w any) error {
captured.lang = lang
captured.body = string(body)
return nil
}
// Re-wire to the io.Writer-taking signature the renderer expects.
r.CodeBlockHandler = func(lang string, body []byte, w any) error { return nil }
_ = r
}
func TestRendererHeadingPrefix(t *testing.T) {
t.Parallel()
p := NewParser(WithAutoHeadingID())
r := NewRenderer()
r.HeadingPrefix = "note-"
doc, err := p.Parse([]byte("# Hello"))
if err != nil {
t.Fatalf("Parse: %v", err)
}
var buf bytes.Buffer
if err := r.Render(&buf, doc); err != nil {
t.Fatalf("Render: %v", err)
}
if !strings.Contains(buf.String(), `id="note-hello"`) {
t.Errorf("expected heading prefix in %q", buf.String())
}
}
func TestRendererNilDoc(t *testing.T) {
t.Parallel()
r := NewRenderer()
var buf bytes.Buffer
if err := r.Render(&buf, nil); err == nil {
t.Error("expected error on nil document")
}
}
func TestSlug(t *testing.T) {
t.Parallel()
cases := map[string]string{
"Hello World": "hello-world",
" Space Pad ": "space-pad",
"Has_Underscore": "has-underscore",
"Symbols!?": "symbols",
}
for in, want := range cases {
in, want := in, want
t.Run(in, func(t *testing.T) {
t.Parallel()
got := slug(in)
if got != want {
t.Errorf("slug(%q) = %q, want %q", in, got, want)
}
})
}
}