Single-binary Go server that fetches markdown from Gitea (mc org), renders to HTML with goldmark (GFM, chroma syntax highlighting, heading anchors), and serves a navigable read-only documentation site. Features: - Boot fetch with retry, webhook refresh, 15-minute poll fallback - In-memory cache with atomic per-repo swap - chi router with htmx partial responses for SPA-like navigation - HMAC-SHA256 webhook validation - Responsive CSS, TOC generation, priority doc ordering - $PORT env var support for MCP agent port assignment 33 tests across config, cache, render, and server packages. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
100 lines
2.4 KiB
Go
100 lines
2.4 KiB
Go
package render
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestRenderBasicMarkdown(t *testing.T) {
|
|
r := New()
|
|
result, err := r.Render([]byte("# Hello\n\nThis is a paragraph."))
|
|
if err != nil {
|
|
t.Fatalf("render: %v", err)
|
|
}
|
|
if !strings.Contains(result.HTML, "<h1") {
|
|
t.Fatalf("expected h1 tag, got: %s", result.HTML)
|
|
}
|
|
if !strings.Contains(result.HTML, "Hello") {
|
|
t.Fatalf("expected heading text, got: %s", result.HTML)
|
|
}
|
|
if !strings.Contains(result.HTML, "<p>This is a paragraph.</p>") {
|
|
t.Fatalf("expected paragraph, got: %s", result.HTML)
|
|
}
|
|
}
|
|
|
|
func TestRenderGFMTable(t *testing.T) {
|
|
md := "| A | B |\n|---|---|\n| 1 | 2 |"
|
|
r := New()
|
|
result, err := r.Render([]byte(md))
|
|
if err != nil {
|
|
t.Fatalf("render: %v", err)
|
|
}
|
|
if !strings.Contains(result.HTML, "<table>") {
|
|
t.Fatalf("expected table, got: %s", result.HTML)
|
|
}
|
|
}
|
|
|
|
func TestRenderCodeHighlighting(t *testing.T) {
|
|
md := "```go\nfunc main() {}\n```"
|
|
r := New()
|
|
result, err := r.Render([]byte(md))
|
|
if err != nil {
|
|
t.Fatalf("render: %v", err)
|
|
}
|
|
// chroma with classes should produce class attributes
|
|
if !strings.Contains(result.HTML, "class=") {
|
|
t.Fatalf("expected syntax highlighting classes, got: %s", result.HTML)
|
|
}
|
|
}
|
|
|
|
func TestExtractHeadings(t *testing.T) {
|
|
md := "# Title\n## Section\n### Subsection"
|
|
r := New()
|
|
result, err := r.Render([]byte(md))
|
|
if err != nil {
|
|
t.Fatalf("render: %v", err)
|
|
}
|
|
if len(result.Headings) != 3 {
|
|
t.Fatalf("expected 3 headings, got %d", len(result.Headings))
|
|
}
|
|
if result.Headings[0].Level != 1 || result.Headings[0].Text != "Title" {
|
|
t.Fatalf("unexpected first heading: %+v", result.Headings[0])
|
|
}
|
|
if result.Headings[1].Level != 2 || result.Headings[1].Text != "Section" {
|
|
t.Fatalf("unexpected second heading: %+v", result.Headings[1])
|
|
}
|
|
}
|
|
|
|
func TestHeadingAnchors(t *testing.T) {
|
|
md := "# Hello World"
|
|
r := New()
|
|
result, err := r.Render([]byte(md))
|
|
if err != nil {
|
|
t.Fatalf("render: %v", err)
|
|
}
|
|
if len(result.Headings) == 0 {
|
|
t.Fatal("no headings extracted")
|
|
}
|
|
if result.Headings[0].ID == "" {
|
|
t.Fatal("expected heading ID to be set")
|
|
}
|
|
}
|
|
|
|
func TestSlugify(t *testing.T) {
|
|
tests := []struct {
|
|
input string
|
|
want string
|
|
}{
|
|
{"Hello World", "hello-world"},
|
|
{"API Design", "api-design"},
|
|
{"foo--bar", "foo-bar"},
|
|
{" leading spaces ", "leading-spaces"},
|
|
}
|
|
for _, tt := range tests {
|
|
got := Slugify(tt.input)
|
|
if got != tt.want {
|
|
t.Errorf("Slugify(%q) = %q, want %q", tt.input, got, tt.want)
|
|
}
|
|
}
|
|
}
|