diff options
Diffstat (limited to 'internal/caldata')
| -rw-r--r-- | internal/caldata/caldata.go | 27 | ||||
| -rw-r--r-- | internal/caldata/sanctorale_test.go | 47 |
2 files changed, 73 insertions, 1 deletions
diff --git a/internal/caldata/caldata.go b/internal/caldata/caldata.go index 9c17035..4e54f1f 100644 --- a/internal/caldata/caldata.go +++ b/internal/caldata/caldata.go @@ -77,9 +77,34 @@ func Tridentine() calendar.Layer { return l } +// sanctoraleDir, when set, holds an optional external universal sanctorale that +// overrides the embedded one (of.ini for OF, ef.ini for EF). Set once at startup +// via SetSanctoraleDir; empty means "use the embedded calendar". +var sanctoraleDir string + +// SetSanctoraleDir points caldata at the dir holding an optional external +// universal sanctorale (<dir>/of.ini, <dir>/ef.ini). Empty disables it. +func SetSanctoraleDir(dir string) { sanctoraleDir = dir } + // Base returns the universal base layer for a form: the 1962 calendar for -// "old" (EF), the General Roman Calendar otherwise (OF). +// "old" (EF), the General Roman Calendar otherwise (OF). If an external +// sanctorale file is present and parses, it REPLACES the embedded calendar for +// that form -- so the saints and ranks can be updated without a rebuild. A +// missing or malformed external file falls back to the embedded default, which +// therefore always keeps the tool self-contained and correct out of the box. func Base(form string) calendar.Layer { + if sanctoraleDir != "" { + name := "of.ini" + if form == "old" { + name = "ef.ini" + } + if data, err := os.ReadFile(filepath.Join(sanctoraleDir, name)); err == nil { + if l, err := ParseLayer(data); err == nil { + return l + } + // malformed external file: fall through to the embedded default + } + } if form == "old" { return Tridentine() } diff --git a/internal/caldata/sanctorale_test.go b/internal/caldata/sanctorale_test.go new file mode 100644 index 0000000..610aa33 --- /dev/null +++ b/internal/caldata/sanctorale_test.go @@ -0,0 +1,47 @@ +package caldata + +import ( + "os" + "path/filepath" + "testing" +) + +func TestBaseSanctoraleOverride(t *testing.T) { + dir := t.TempDir() + os.WriteFile(filepath.Join(dir, "of.ini"), []byte( + "[layer]\nid = test-override\ntype = universal\n\n"+ + "[test-saint]\ndate = 06-15\nrank = feast\nname.en = Test Saint\n"), 0o644) + SetSanctoraleDir(dir) + t.Cleanup(func() { SetSanctoraleDir("") }) + + // External file present and valid -> it REPLACES the embedded OF calendar. + l := Base("new") + if l.ID != "test-override" { + t.Fatalf("external of.ini not used: layer id = %q", l.ID) + } + if _, ok := l.Cels["test-saint"]; !ok || len(l.Cels) != 1 { + t.Fatalf("external calendar not loaded verbatim: %d cels", len(l.Cels)) + } + + // EF form has no external file here -> embedded Tridentine still used. + if ef := Base("old"); ef.ID == "test-override" { + t.Fatal("EF wrongly took the OF override") + } +} + +func TestBaseFallsBackToEmbedded(t *testing.T) { + // No dir set -> embedded default. + SetSanctoraleDir("") + if l := Base("new"); l.ID != "universal" || len(l.Cels) < 100 { + t.Fatalf("no-override should give the embedded calendar, got id=%q n=%d", l.ID, len(l.Cels)) + } + + // A malformed external file must not break computation -> embedded fallback. + dir := t.TempDir() + os.WriteFile(filepath.Join(dir, "of.ini"), []byte("[unclosed section\n"), 0o644) + SetSanctoraleDir(dir) + t.Cleanup(func() { SetSanctoraleDir("") }) + if l := Base("new"); l.ID != "universal" || len(l.Cels) < 100 { + t.Fatalf("malformed override should fall back to embedded, got id=%q n=%d", l.ID, len(l.Cels)) + } +} |
