The chosen view is published at /, the other under /timeline/ or /grid/. Page paths, pager links and the cross-links between the views are derived from the setting. The directory named after the default view is removed on build, since it can only be a leftover from before a switch. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
133 lines
3.8 KiB
Go
133 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"image"
|
|
"image/jpeg"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// buildSite builds a site of three photos spread over two days, with a page
|
|
// size of two so both views need a second page, and returns the output dir.
|
|
func buildSite(t *testing.T, output, defaultView string) {
|
|
t.Helper()
|
|
content := t.TempDir()
|
|
|
|
var img bytes.Buffer
|
|
if err := jpeg.Encode(&img, image.NewRGBA(image.Rect(0, 0, 8, 8)), nil); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
for slug, date := range map[string]string{
|
|
"one": "2026-06-14",
|
|
"two": "2026-06-14",
|
|
"three": "2026-06-10",
|
|
} {
|
|
writeFile(t, filepath.Join(content, slug+".jpg"), img.Bytes())
|
|
writeFile(t, filepath.Join(content, slug+".toml"),
|
|
[]byte("caption = \""+slug+"\"\ndate = \""+date+"\"\n"))
|
|
}
|
|
|
|
g := NewGenerator(content, output, "https://photos.example.com",
|
|
"Ada", "", "", "", "", "Crimson Pro", "Manjari", 2, defaultView)
|
|
if err := g.Build(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func writeFile(t *testing.T, path string, data []byte) {
|
|
t.Helper()
|
|
if err := os.WriteFile(path, data, 0644); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
|
|
func readPage(t *testing.T, output, rel string) string {
|
|
t.Helper()
|
|
data, err := os.ReadFile(filepath.Join(output, filepath.FromSlash(rel), "index.html"))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return string(data)
|
|
}
|
|
|
|
// Timeline pages carry day sections, grid pages do not.
|
|
func isTimeline(page string) bool {
|
|
return strings.Contains(page, `class="tl-day"`)
|
|
}
|
|
|
|
func TestDefaultViewOwnsSiteRoot(t *testing.T) {
|
|
tests := []struct {
|
|
defaultView string
|
|
gridAt string // URL of the grid's first page
|
|
timelineAt string // URL of the timeline's first page
|
|
}{
|
|
{viewTimeline, "/grid/", "/"},
|
|
{viewGrid, "/", "/timeline/"},
|
|
{"nonsense", "/grid/", "/"}, // unknown values fall back to the timeline
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.defaultView, func(t *testing.T) {
|
|
output := t.TempDir()
|
|
buildSite(t, output, tt.defaultView)
|
|
|
|
timeline := readPage(t, output, tt.timelineAt)
|
|
grid := readPage(t, output, tt.gridAt)
|
|
if !isTimeline(timeline) {
|
|
t.Errorf("%s is not the timeline", tt.timelineAt)
|
|
}
|
|
if isTimeline(grid) {
|
|
t.Errorf("%s is not the grid", tt.gridAt)
|
|
}
|
|
|
|
// The views link to each other, and to their own second page.
|
|
for page, want := range map[string]string{
|
|
timeline: `href="` + tt.gridAt + `" class="rss-a">Grid`,
|
|
grid: `href="` + tt.timelineAt + `" class="rss-a">Timeline`,
|
|
} {
|
|
if !strings.Contains(page, want) {
|
|
t.Errorf("missing link %q", want)
|
|
}
|
|
}
|
|
for first, base := range map[string]string{
|
|
timeline: strings.TrimSuffix(tt.timelineAt, "/"),
|
|
grid: strings.TrimSuffix(tt.gridAt, "/"),
|
|
} {
|
|
next := base + "/page/2/"
|
|
if !strings.Contains(first, `href="`+next+`" data-load-more`) {
|
|
t.Errorf("first page does not link to %s", next)
|
|
}
|
|
second := readPage(t, output, next)
|
|
if !strings.Contains(second, `class="pager-newer" href="`+base+`/"`) {
|
|
t.Errorf("%s does not link back to %s/", next, base)
|
|
}
|
|
}
|
|
|
|
// Day pages lead back to the timeline, wherever it lives.
|
|
day := readPage(t, output, "/day/2026-06-14/")
|
|
if !strings.Contains(day, `href="`+tt.timelineAt+`" class="rss-a">← Timeline`) {
|
|
t.Errorf("day page does not link to the timeline at %s", tt.timelineAt)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSwitchingDefaultViewDropsOldViewDir(t *testing.T) {
|
|
output := t.TempDir()
|
|
|
|
buildSite(t, output, viewTimeline)
|
|
if _, err := os.Stat(filepath.Join(output, "grid", "index.html")); err != nil {
|
|
t.Fatalf("grid view missing before the switch: %v", err)
|
|
}
|
|
|
|
buildSite(t, output, viewGrid)
|
|
if _, err := os.Stat(filepath.Join(output, "grid")); !os.IsNotExist(err) {
|
|
t.Errorf("stale /grid/ survived the switch to -default-view grid")
|
|
}
|
|
if isTimeline(readPage(t, output, "/")) {
|
|
t.Errorf("site root is still the timeline")
|
|
}
|
|
}
|