ZDDC/zddc/internal/handler/converttemplate_test.go
2026-06-11 13:32:31 -05:00

95 lines
3.3 KiB
Go

package handler
import (
"os"
"path/filepath"
"testing"
)
func TestTemplateNameFromFrontMatter(t *testing.T) {
cases := []struct {
name string
src string
want string
}{
{"plain", "---\ntemplate: specification\n---\n\n# H\n", "specification"},
{"quoted", "---\ntemplate: \"letter\"\n---\n", "letter"},
{"absent", "---\ntitle: X\n---\n", ""},
{"no-frontmatter", "# Just a heading\n", ""},
{"traversal-rejected", "---\ntemplate: ../../etc/passwd\n---\n", ""},
{"slash-rejected", "---\ntemplate: a/b\n---\n", ""},
{"crlf", "---\r\ntemplate: report\r\n---\r\n", "report"},
{"dots-terminator", "---\ntemplate: letter\n...\nbody", "letter"},
}
for _, c := range cases {
t.Run(c.name, func(t *testing.T) {
if got := templateNameFromFrontMatter([]byte(c.src)); got != c.want {
t.Errorf("templateNameFromFrontMatter(%q) = %q, want %q", c.src, got, c.want)
}
})
}
}
func TestResolveTemplateSet_DefaultsAndCascade(t *testing.T) {
root := t.TempDir()
party := filepath.Join(root, "working", "AcmeCo")
if err := os.MkdirAll(party, 0o755); err != nil {
t.Fatal(err)
}
// No overrides, no front matter → embedded report, partials present.
ts := resolveTemplateSet(root, party, []byte("# Hi\n"))
if ts.Name != "report.html" {
t.Fatalf("default doctype: got %q, want report.html", ts.Name)
}
if ts.Files["_head.html"] == nil {
t.Errorf("partial _head.html missing from default set")
}
embeddedReport := string(ts.Files["report.html"])
// Front matter selects a doctype.
if ts := resolveTemplateSet(root, party, []byte("---\ntemplate: letter\n---\n")); ts.Name != "letter.html" {
t.Errorf("front-matter doctype: got %q, want letter.html", ts.Name)
}
// Project-global override at <root>/.zddc.d/templates/report.html.
projDir := filepath.Join(root, ".zddc.d", "templates")
if err := os.MkdirAll(projDir, 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(projDir, "report.html"), []byte("PROJECT-REPORT"), 0o644); err != nil {
t.Fatal(err)
}
ts = resolveTemplateSet(root, party, []byte("# Hi\n"))
if string(ts.Files["report.html"]) != "PROJECT-REPORT" {
t.Errorf("project override not applied: %q", ts.Files["report.html"])
}
if string(ts.Files["report.html"]) == embeddedReport {
t.Errorf("override identical to embedded — overlay didn't happen")
}
// Party override wins over project-global.
partyDir := filepath.Join(party, ".zddc.d", "templates")
if err := os.MkdirAll(partyDir, 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(partyDir, "report.html"), []byte("PARTY-REPORT"), 0o644); err != nil {
t.Fatal(err)
}
ts = resolveTemplateSet(root, party, []byte("# Hi\n"))
if string(ts.Files["report.html"]) != "PARTY-REPORT" {
t.Errorf("party override should win: got %q", ts.Files["report.html"])
}
// A brand-new doctype provided only as an override is adopted as primary.
if err := os.WriteFile(filepath.Join(partyDir, "memo.html"), []byte("MEMO-TEMPLATE"), 0o644); err != nil {
t.Fatal(err)
}
ts = resolveTemplateSet(root, party, []byte("---\ntemplate: memo\n---\n"))
if ts.Name != "memo.html" || string(ts.Files["memo.html"]) != "MEMO-TEMPLATE" {
t.Errorf("custom doctype override: name=%q bytes=%q", ts.Name, ts.Files["memo.html"])
}
if ts.Files["_head.html"] == nil {
t.Errorf("partials should still ride along with a custom doctype override")
}
}