aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/test_calendar_of_data.ml76
1 files changed, 68 insertions, 8 deletions
diff --git a/test/test_calendar_of_data.ml b/test/test_calendar_of_data.ml
index 01a757e..d4f8a8b 100644
--- a/test/test_calendar_of_data.ml
+++ b/test/test_calendar_of_data.ml
@@ -5,9 +5,20 @@
'(slug', grep -oP rank/status/colour/subject | sort | uniq -c -- see
.superpowers/sdd/2026-08-25-colitur-of-phases-3-5/task-1-report.md), plus
named spot-checks read straight off the Missal's own printed page so a
- passing count can't hide the wrong 206 entries having been transcribed
+ passing count can't hide the wrong entries having been transcribed
(the same "live hazard" test_sanctoral_ef.ml's own header names).
+ Fix round 1 (2026-08-25): 206 -> 208. Two movable universal celebrations
+ -- the Sacred Heart of Jesus and the Immaculate Heart of Mary -- are
+ printed in the SAME 2002 table (as prose headings, not (kalends, day)
+ rows) but were missed by the first pass; both are now produced as
+ Date_spec.Easter_offset entries (68/69) by
+ tools/extract_of_calendar.py's own MOVABLE_ENTRY_HEADINGS, the same
+ mechanism EF's Rogation Wednesday already uses. See
+ test_movable_entries below, which verifies the Easter+68/Easter+69
+ arithmetic against three REAL Easter dates rather than trusting the
+ offset on its own say-so.
+
SOURCE DISCIPLINE, asserted structurally here, not merely stated in the
tool's own header: every entry's rank is one of the four Vocab_of.rank
grades NEVER Feria (that rank is temporal-only, see vocab_of.mli), and
@@ -58,7 +69,7 @@ let sha256_of_file path =
don't transcribe it from output" pinning discipline. *)
let test_sha256 () =
Alcotest.(check string) "data/of/calendar-2002.sexp SHA-256"
- "b2bf3fa9d27f5bc6e47225c477c158f629eaab6c280e0b69fa04c8a55db9f612" (sha256_of_file path)
+ "1b4f2117133dea1c70989708d94e6f292f3ce23fce6221391191d6fcf6042d19" (sha256_of_file path)
(* Counts independently re-derived from the shipped file
(`grep -c '(slug'`; `grep -oP '(?<=\(rank )[A-Za-z_]+' | sort | uniq -c`).
@@ -68,19 +79,19 @@ let test_sha256 () =
asserting the count moved. *)
let test_load_and_counts () =
let l = load () in
- Alcotest.(check int) "206 entries" 206 (List.length l.L.entries);
+ Alcotest.(check int) "208 entries" 208 (List.length l.L.entries);
let count pred = List.length (List.filter pred l.L.entries) in
- Alcotest.(check int) "8 Sollemnitas" 8 (count (fun e -> e.L.cel.Cel.rank = V.Sollemnitas));
+ Alcotest.(check int) "9 Sollemnitas" 9 (count (fun e -> e.L.cel.Cel.rank = V.Sollemnitas));
Alcotest.(check int) "23 Festum" 23 (count (fun e -> e.L.cel.Cel.rank = V.Festum));
- Alcotest.(check int) "67 Memoria_obligatoria" 67
+ Alcotest.(check int) "68 Memoria_obligatoria" 68
(count (fun e -> e.L.cel.Cel.rank = V.Memoria_obligatoria));
Alcotest.(check int) "108 Memoria_ad_libitum" 108
(count (fun e -> e.L.cel.Cel.rank = V.Memoria_ad_libitum));
Alcotest.(check int) "0 Feria (temporal-only rank, never a calendar entry)" 0
(count (fun e -> e.L.cel.Cel.rank = V.Feria));
- Alcotest.(check int) "206 Feast (OF admits no Commemoration_only status)" 206
+ Alcotest.(check int) "208 Feast (OF admits no Commemoration_only status)" 208
(count (fun e -> e.L.cel.Cel.status = Cel.Feast));
- Alcotest.(check int) "every entry tagged Precedence_of.universal_layer" 206
+ Alcotest.(check int) "every entry tagged Precedence_of.universal_layer" 208
(count (fun e -> e.L.cel.Cel.layer = PO.universal_layer))
let test_slugs_unique () =
@@ -183,6 +194,52 @@ let test_excludes_temporal_of_dates () =
| Some (_, _, _, rank) -> Alcotest.(check bool) "25 Dec: Sollemnitas" true (rank = V.Sollemnitas)
| None -> Alcotest.fail "25 Dec: Temporal_of.named returned None"
+(* Fix round 1: the two movable entries (Sacred Heart of Jesus, Immaculate
+ Heart of Mary) resolve to the right weekday AND date in three real
+ years, computed from Colitur_kernel.Computus.gregorian_easter, not
+ hand-typed dates -- so a wrong offset in the data would fail this even
+ if it "looked" plausible. Also independently confirms the coordinator's
+ own +68/+69 derivation (Pentecost = Easter+49, so the Friday/Saturday
+ after the Second Sunday after Pentecost are Easter+68/+69) rather than
+ trusting it. *)
+let test_movable_entries () =
+ let l = load () in
+ let heart = find l "sacred-heart-of-jesus" in
+ Alcotest.(check bool) "Sacred Heart: date spec is Easter_offset 68" true
+ (heart.L.date = DS.Easter_offset 68);
+ Alcotest.(check bool) "Sacred Heart: Sollemnitas" true
+ (heart.L.cel.Cel.rank = V.Sollemnitas);
+ Alcotest.(check bool) "Sacred Heart: white" true (heart.L.cel.Cel.colour = Col.White);
+ Alcotest.(check bool) "Sacred Heart: subject Lord" true (heart.L.cel.Cel.subject = Sub.Lord);
+ let immaculate = find l "immaculate-heart-of-mary" in
+ Alcotest.(check bool) "Immaculate Heart: date spec is Easter_offset 69" true
+ (immaculate.L.date = DS.Easter_offset 69);
+ Alcotest.(check bool) "Immaculate Heart: Memoria_obligatoria" true
+ (immaculate.L.cel.Cel.rank = V.Memoria_obligatoria);
+ Alcotest.(check bool) "Immaculate Heart: white" true (immaculate.L.cel.Cel.colour = Col.White);
+ Alcotest.(check bool) "Immaculate Heart: subject Bvm" true (immaculate.L.cel.Cel.subject = Sub.Bvm);
+ List.iter
+ (fun year ->
+ let easter = Colitur_kernel.Computus.gregorian_easter year in
+ let resolve spec =
+ match DS.resolve spec ~year ~easter with
+ | Some d -> d
+ | None -> Alcotest.failf "year %d: date spec did not resolve" year
+ in
+ let sacred_heart_date = resolve heart.L.date in
+ let immaculate_heart_date = resolve immaculate.L.date in
+ Alcotest.(check bool)
+ (Printf.sprintf "%d: Sacred Heart (Easter+68) falls on a Friday" year)
+ true (D.weekday sacred_heart_date = D.Fri);
+ Alcotest.(check bool)
+ (Printf.sprintf "%d: Immaculate Heart (Easter+69) falls on a Saturday" year)
+ true (D.weekday immaculate_heart_date = D.Sat);
+ (* Immaculate Heart is the day right after Sacred Heart, every year. *)
+ Alcotest.(check bool)
+ (Printf.sprintf "%d: Immaculate Heart is the day after Sacred Heart" year)
+ true (immaculate_heart_date = D.add_days sacred_heart_date 1))
+ [ 2026; 2027; 2035 ]
+
let suite =
( "Calendar_of (data/of/calendar-2002.sexp)",
[ Alcotest.test_case "SHA-256 pinned" `Quick test_sha256;
@@ -204,4 +261,7 @@ let suite =
test_spot_check_angela_merici;
Alcotest.test_case
"1/6 Jan and 25 Dec deliberately excluded -- Temporal_of.named covers them" `Quick
- test_excludes_temporal_of_dates ] )
+ test_excludes_temporal_of_dates;
+ Alcotest.test_case
+ "fix round 1: Sacred Heart of Jesus (Easter+68) and Immaculate Heart of Mary (Easter+69)" `Quick
+ test_movable_entries ] )