package classes_test import ( "os" "path/filepath" "strings" "testing" "time" "git.golem15.com/golem15/sm-sitemap-plugin/classes" ) // TestManifest pins the updates manifest reader: it fails safe (a missing, // empty-path, directory, oversized, non-object or invalid file is no // manifest, so lastmod is omitted), normalizes keys, ignores non-string // values, and parses the ISO dates strtotime reads, a date without a zone // as UTC. func TestManifest(t *testing.T) { dir := t.TempDir() write := func(name, body string) string { t.Helper() path := filepath.Join(dir, name) if err := os.WriteFile(path, []byte(body), 0o644); err != nil { t.Fatal(err) } return path } for name, path := range map[string]string{ "empty path": "", "spaces": " ", "missing": filepath.Join(dir, "missing.json"), "directory": dir, "list": write("list.json", `["/a"]`), "string": write("string.json", `"x"`), "invalid": write("invalid.json", `{"/a": `), "empty file": write("empty.json", ""), "oversized": write("big.json", `{"/a":"2026-01-01","pad":"`+strings.Repeat("x", classes.ManifestMaxBytes)+`"}`), "null": write("null.json", "null"), "leading space": write("space.json", " \n"), } { if m := classes.LoadManifest(path); m != nil { t.Errorf("%s: manifest = %v, want none", name, m) } } if fifo := filepath.Join(dir, "link.json"); os.Symlink(dir, fifo) == nil { if m := classes.LoadManifest(fifo); m != nil { t.Error("a symlink to a directory is not a manifest") } } path := write("updates.json", ` {"blog/a/":"2026-01-02T03:04:05+02:00","/b":"2026-02-03","c":"2026-03-04 05:06:07","/":"2026-04-05T06:07","/num":12,"/bad":"yesterday","/epoch":"1970-01-01T00:00:00Z","/nested":{"x":1}}`) m := classes.LoadManifest(path) if m == nil { t.Fatal("valid manifest not read") } if _, ok := m["/num"]; ok { t.Fatal("a non-string value was kept") } for url, want := range map[string]string{ "https://h/blog/a": "2026-01-02T01:04:05Z", "https://h/blog/a/": "2026-01-02T01:04:05Z", "https://h/b?x=1": "2026-02-03T00:00:00Z", "/c": "2026-03-04T05:06:07Z", "https://h": "2026-04-05T06:07:00Z", "https://h/": "2026-04-05T06:07:00Z", } { got, ok := m.Lastmod(url) if !ok || got.UTC().Format(time.RFC3339) != want { t.Errorf("Lastmod(%s) = %v %v, want %s", url, got, ok, want) } } for _, url := range []string{"https://h/bad", "https://h/epoch", "https://h/unlisted", "https://h/num"} { if got, ok := m.Lastmod(url); ok { t.Errorf("Lastmod(%s) = %v, want none", url, got) } } var none classes.Manifest if _, ok := none.Lastmod("https://h/b"); ok { t.Fatal("a nil manifest answered") } }