package liturgy import ( "net/http" "net/http/httptest" "os" "path/filepath" "testing" ) func TestLoadCaches(t *testing.T) { html, _ := os.ReadFile("testdata/2026-06-22.html") hits := 0 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { hits++ w.Write(html) })) defer srv.Close() t.Setenv("XDG_CACHE_HOME", t.TempDir()) baseURL = srv.URL + "/liturgia/%s/Ewangelia" // test hook secs1, err := Load(Options{Date: "2026-06-22"}) if err != nil || len(secs1) == 0 { t.Fatalf("load1: %v", err) } secs2, _ := Load(Options{Date: "2026-06-22"}) // should hit JSON cache if hits != 1 { t.Errorf("server hit %d times, want 1 (cache miss on repeat)", hits) } if len(secs2) != len(secs1) { t.Error("cache returned different section count") } } // TestLoadRejectsInvalidDate is the liturgy-layer defense-in-depth check for // the ?date= path-traversal finding: Load must reject a non-YYYY-MM-DD date // before it ever builds a filesystem path from it, so every caller (web, // cli, tui) is protected even if a future caller forgets to validate. // // The planted "passwd.json" sits one level *above* cacheDir() -- reachable // only via a "../" date -- so if Load ever built jsonPath from the raw date // unchecked, loadJSONCache would read it back and return its section instead // of an error. func TestLoadRejectsInvalidDate(t *testing.T) { dir := t.TempDir() t.Setenv("XDG_CACHE_HOME", dir) evilPath := filepath.Join(dir, "passwd.json") if err := os.WriteFile(evilPath, []byte(`[{"Heading":"SHOULD-NEVER-BE-READ"}]`), 0o644); err != nil { t.Fatal(err) } secs, err := Load(Options{Date: "../passwd"}) if err == nil { t.Fatalf("Load(Date=%q) = (%v, nil), want a non-nil error", "../passwd", secs) } if secs != nil { t.Errorf("Load(Date=%q) sections = %v, want nil", "../passwd", secs) } }