diff options
Diffstat (limited to 'test/test_calendar_of_data.ml')
| -rw-r--r-- | test/test_calendar_of_data.ml | 76 |
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 ] ) |
