112 lines
3.6 KiB
Go
112 lines
3.6 KiB
Go
package handler
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestRecognizeVirtualConvert_MatrixAndPrecedence(t *testing.T) {
|
|
root := t.TempDir()
|
|
write := func(rel string) {
|
|
p := filepath.Join(root, filepath.FromSlash(rel))
|
|
if err := os.MkdirAll(filepath.Dir(p), 0o755); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := os.WriteFile(p, []byte("x"), 0o644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
// Sources on disk: doc.md, only.docx, both.md + both.docx, page.html.
|
|
write("doc.md")
|
|
write("only.docx")
|
|
write("both.md")
|
|
write("both.docx")
|
|
write("page.html")
|
|
|
|
cases := []struct {
|
|
name string
|
|
url string
|
|
wantOK bool
|
|
wantSrcExt string
|
|
wantFormat string
|
|
}{
|
|
{"md→docx", "/doc.docx", true, ".md", "docx"},
|
|
{"md→html", "/doc.html", true, ".md", "html"},
|
|
{"md→pdf", "/doc.pdf", true, ".md", "pdf"},
|
|
{"docx→md (only docx present)", "/only.md", true, ".docx", "md"},
|
|
{"docx→html (only docx present)", "/only.html", true, ".docx", "html"},
|
|
{"docx has no pdf source", "/only.pdf", false, "", ""},
|
|
{"both present, html prefers md source", "/both.html", true, ".md", "html"},
|
|
{"html→md", "/page.md", true, ".html", "md"},
|
|
{"html→docx", "/page.docx", true, ".html", "docx"},
|
|
{"no source at all", "/missing.html", false, "", ""},
|
|
{"directory url ignored", "/doc/", false, "", ""},
|
|
{"non-convertible target", "/doc.txt", false, "", ""},
|
|
}
|
|
for _, c := range cases {
|
|
t.Run(c.name, func(t *testing.T) {
|
|
src, format, ok := RecognizeVirtualConvert(root, c.url)
|
|
if ok != c.wantOK {
|
|
t.Fatalf("ok=%v want %v (src=%q format=%q)", ok, c.wantOK, src, format)
|
|
}
|
|
if !ok {
|
|
return
|
|
}
|
|
if format != c.wantFormat {
|
|
t.Errorf("format=%q want %q", format, c.wantFormat)
|
|
}
|
|
if filepath.Ext(src) != c.wantSrcExt {
|
|
t.Errorf("source ext=%q want %q (src=%q)", filepath.Ext(src), c.wantSrcExt, src)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestServeFrontMatterTemplate(t *testing.T) {
|
|
rec := httptest.NewRecorder()
|
|
ServeFrontMatterTemplate(rec, httptest.NewRequest(http.MethodGet, FrontMatterTemplatePath, nil))
|
|
if rec.Code != http.StatusOK {
|
|
t.Fatalf("status=%d, want 200", rec.Code)
|
|
}
|
|
if ct := rec.Header().Get("Content-Type"); !strings.Contains(ct, "application/json") {
|
|
t.Errorf("Content-Type=%q, want application/json", ct)
|
|
}
|
|
var payload struct {
|
|
Placeholder string `json:"placeholder"`
|
|
Fields []struct {
|
|
Name string `json:"name"`
|
|
Hint string `json:"hint"`
|
|
} `json:"fields"`
|
|
}
|
|
if err := json.Unmarshal(rec.Body.Bytes(), &payload); err != nil {
|
|
t.Fatalf("decode: %v; body=%s", err, rec.Body.String())
|
|
}
|
|
if len(payload.Fields) == 0 {
|
|
t.Fatal("fields empty")
|
|
}
|
|
// doctype/numbering have no other source; revision/status are template
|
|
// fields an author can override here — all must be communicated.
|
|
for _, want := range []string{"doctype", "numbering", "revision", "status", "tracking_number"} {
|
|
if !strings.Contains(payload.Placeholder, want) {
|
|
t.Errorf("placeholder missing %q: %q", want, payload.Placeholder)
|
|
}
|
|
}
|
|
// HEAD returns headers, no body.
|
|
hrec := httptest.NewRecorder()
|
|
ServeFrontMatterTemplate(hrec, httptest.NewRequest(http.MethodHead, FrontMatterTemplatePath, nil))
|
|
if hrec.Code != http.StatusOK || hrec.Body.Len() != 0 {
|
|
t.Errorf("HEAD: status=%d bodylen=%d, want 200 + empty", hrec.Code, hrec.Body.Len())
|
|
}
|
|
// Non-GET/HEAD is rejected.
|
|
prec := httptest.NewRecorder()
|
|
ServeFrontMatterTemplate(prec, httptest.NewRequest(http.MethodPost, FrontMatterTemplatePath, nil))
|
|
if prec.Code != http.StatusMethodNotAllowed {
|
|
t.Errorf("POST: status=%d, want 405", prec.Code)
|
|
}
|
|
}
|