serve a bundle at its permalink
-site (or KHOSRA_SITE) opens the site root through content.OpenSite, so every
read keeps the os.Root guarantee. A path is a bundle key: /{section}/{slug}/
serves, the slashless form redirects permanently to it (ADR-0008), anything
unknown is 404. Render failure logs and returns a bare 500 rather than leaking a
template or filesystem detail.
internal/render holds goldmark plus the embedded reference theme (ADR-0026):
base.html with a redefinable "main" block, and one stylesheet inlined through
.Style. Serving it at an asset route would have been a second routing case for no
gain, and static serving belongs to a later entry.
Evidence beyond the tests: the binary against a real site root returns 200 with
<h1>About</h1> and the rendered body, 301 from /pages/about to /pages/about/, and
404 for /nope/. A Bengali variant is scanned but not yet reachable — that is the
next entry.
theme-contract.md gains a "Live today" section listing the six fields and two
named templates a theme may now rely on; the rest stays marked as shape.
This commit is contained in:
@@ -0,0 +1,71 @@
|
||||
package web
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"strings"
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
|
||||
"khosra/internal/content"
|
||||
"khosra/internal/render"
|
||||
)
|
||||
|
||||
func testHandler(t *testing.T) http.Handler {
|
||||
t.Helper()
|
||||
fsys := fstest.MapFS{
|
||||
"content/pages/about.md": {Data: []byte("---\ntitle: About\n---\nAbout me.\n")},
|
||||
"content/posts/hello/index.md": {Data: []byte("---\ntitle: Hello\n---\nFirst post.\n")},
|
||||
}
|
||||
bundles, err := content.Scan(fsys)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
r, err := render.New()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
return Handler(content.NewSite(bundles), r)
|
||||
}
|
||||
|
||||
func TestServeBundleAtItsPermalink(t *testing.T) {
|
||||
h := testHandler(t)
|
||||
for _, path := range []string{"/pages/about/", "/posts/hello/"} {
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, path, nil))
|
||||
if rec.Code != http.StatusOK {
|
||||
t.Fatalf("GET %s = %d, want 200", path, rec.Code)
|
||||
}
|
||||
if ct := rec.Header().Get("Content-Type"); !strings.HasPrefix(ct, "text/html") {
|
||||
t.Errorf("GET %s content-type = %q", path, ct)
|
||||
}
|
||||
}
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/pages/about/", nil))
|
||||
if body := rec.Body.String(); !strings.Contains(body, "<h1>About</h1>") || !strings.Contains(body, "About me.") {
|
||||
t.Errorf("body did not render the bundle:\n%s", body)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSlashlessPathRedirectsPermanently(t *testing.T) {
|
||||
h := testHandler(t)
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, "/pages/about", nil))
|
||||
if rec.Code != http.StatusMovedPermanently {
|
||||
t.Fatalf("got %d, want 301", rec.Code)
|
||||
}
|
||||
if loc := rec.Header().Get("Location"); loc != "/pages/about/" {
|
||||
t.Errorf("Location = %q", loc)
|
||||
}
|
||||
}
|
||||
|
||||
func TestUnknownPathsAre404(t *testing.T) {
|
||||
h := testHandler(t)
|
||||
for _, path := range []string{"/", "/nope/", "/pages/nope", "/pages/about/deeper/"} {
|
||||
rec := httptest.NewRecorder()
|
||||
h.ServeHTTP(rec, httptest.NewRequest(http.MethodGet, path, nil))
|
||||
if rec.Code != http.StatusNotFound {
|
||||
t.Errorf("GET %s = %d, want 404", path, rec.Code)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user