aboutsummaryrefslogtreecommitdiff
path: root/internal/calendar/oracle_ef_test.go
diff options
context:
space:
mode:
Diffstat (limited to 'internal/calendar/oracle_ef_test.go')
-rw-r--r--internal/calendar/oracle_ef_test.go62
1 files changed, 62 insertions, 0 deletions
diff --git a/internal/calendar/oracle_ef_test.go b/internal/calendar/oracle_ef_test.go
index 6d63220..a2bb6a5 100644
--- a/internal/calendar/oracle_ef_test.go
+++ b/internal/calendar/oracle_ef_test.go
@@ -339,3 +339,65 @@ func TestOracleEF(t *testing.T) {
t.Fatalf("%d/%d EF colour mismatches vs missalemeum (not allow-listed)", colourMiss, total)
}
}
+
+// TestEFLectionaryKeysAreReachableSlugs asserts that every section name in the
+// EF temporal lectionary is a slug the calendar can actually compute. A key
+// nothing ever matches is dead data: the reading sits in the file, the lookup
+// misses it, and the day silently falls back to the preceding Sunday's Mass —
+// which looks like a plausible answer, so nothing downstream notices.
+//
+// This is not hypothetical. Three sections were filed as ef-lent-1-{wednesday,
+// friday,saturday} while temporal_ef.go's efEmberSlug computes
+// ef-lent-ember-{wed,fri,sat}, so the Lenten Ember days served Lent I Sunday's
+// Mass for as long as the data existed. The keys were stale: they predate Lent
+// being added to efEmberSlug, and scripts/genlect.go — which keys off
+// day.Observed.Slug — would already write the correct names if re-run.
+//
+// It survived every existing test because the wrong answer is a real Mass, and
+// it survived cross-checking against colitur (the sibling OCaml engine)
+// because colitur had bootstrapped the same wrong keys from this very file.
+// Two engines agreeing is not evidence when one was seeded from the other.
+func TestEFLectionaryKeysAreReachableSlugs(t *testing.T) {
+ raw, err := os.ReadFile("../caldata/tridentine-lectionary.ini")
+ if err != nil {
+ t.Fatalf("read lectionary: %v", err)
+ }
+
+ keys := map[string]bool{}
+ for _, line := range strings.Split(string(raw), "\n") {
+ line = strings.TrimSpace(line)
+ if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
+ keys[line[1:len(line)-1]] = true
+ }
+ }
+ if len(keys) == 0 {
+ t.Fatal("no sections parsed from the lectionary")
+ }
+
+ sel := calendar.DefaultSelection()
+ sel.Form = "old"
+ layers := []calendar.Layer{caldata.Tridentine()}
+
+ // Twelve years. Every key in the shipped file is reached within five (the
+ // movable ones recur annually; the Ember and vigil days are the only
+ // awkward cases and they occur every year too), so this is a bit over
+ // double the margin actually needed. Widening it costs test time linearly
+ // and buys nothing measurable — 46 years took 91s, this takes a quarter of
+ // that — but narrowing below five would start reporting live keys as dead.
+ seen := map[string]bool{}
+ for d := time.Date(2005, 1, 1, 0, 0, 0, 0, time.UTC); d.Year() <= 2016; d = d.AddDate(0, 0, 1) {
+ seen[calendar.Compute(d, sel, layers).Observed.Slug] = true
+ }
+
+ var dead []string
+ for k := range keys {
+ if !seen[k] {
+ dead = append(dead, k)
+ }
+ }
+ sort.Strings(dead)
+ if len(dead) > 0 {
+ t.Errorf("lectionary keys no computed slug ever matches (dead data, the day "+
+ "silently falls back to the preceding Sunday): %v", dead)
+ }
+}