aboutsummaryrefslogtreecommitdiff
path: root/test/test_rubrics_ef.ml
diff options
context:
space:
mode:
Diffstat (limited to 'test/test_rubrics_ef.ml')
-rw-r--r--test/test_rubrics_ef.ml88
1 files changed, 88 insertions, 0 deletions
diff --git a/test/test_rubrics_ef.ml b/test/test_rubrics_ef.ml
index 5109c69..a778a5a 100644
--- a/test/test_rubrics_ef.ml
+++ b/test/test_rubrics_ef.ml
@@ -26,6 +26,7 @@ module Colour = Colitur_kernel.Colour
module Subject = Colitur_kernel.Subject
module Slug = Colitur_kernel.Slug
module Temporal = Colitur_kernel.Temporal
+module Computus = Colitur_kernel.Computus
module V = Rite_ef.Vocab_ef
module RE = Rite_ef.Rubrics_ef
module TE = Rite_ef.Temporal_ef
@@ -175,6 +176,87 @@ let test_holy_saturday_easter_vigil_no_creed () =
by 476(a) ("in Missa Vigiliae paschalis"). *)
check "RG 23(b)/476(a): Holy Saturday (the Easter Vigil Mass)" 2026 4 4 false
+(* ---- RG 476(f): "in Missis defunctorum" -- the Creed is never said at a
+ Requiem Mass. Whole-branch review finding 1: colitur used to say [true]
+ here on rank alone (475(b), Class1) -- the LMS Ordo layer's own former
+ allow-list entry L1, now closed, was this exact day. See rubrics_ef.ml's
+ own header for why {!Colour.Black} is a sound RG 117 proxy for "this Mass
+ is a Requiem" on the shipped data. ---- *)
+
+let test_476f_all_souls_no_creed () =
+ (* 2025-11-03: All Souls' Day (2 November, a Sunday that year, transferred
+ to the next open day, RG's own Class1/black office unchanged by the
+ transfer) -- `colitur day 2025` confirms class-1/black/
+ commemoration-of-all-souls on this date. Before this fix [creed] here
+ was [true] via 475(b); the Ordo's own text ("No Cr") says otherwise. *)
+ check "RG 476(f): All Souls' Day (transferred), a Requiem, says no Creed" 2025 11 3 false
+
+let test_476f_good_friday_no_creed () =
+ (* 2026-04-03: Good Friday, [colour = Black] (temporal_ef.ml's own
+ [days_between easter d = -2] branch) -- already [false] via the RG
+ 23(b) feria-I-classis exclusion checked earlier in [creed], so this is
+ a belt-and-braces witness that the 476(f) guard, were it ever reached
+ first, would agree rather than a case that depends on it: Good Friday
+ has no Mass in the 1955-restored Holy Week to begin with. *)
+ check "RG 476(f)/RG 23(b): Good Friday, black, says no Creed" 2026 4 3 false
+
+(* Whole-branch review finding 1's own instruction: a test that FAILS if a
+ third {!Colour.Black} celebration is ever introduced, so the RG 476(f)
+ guard's colour proxy cannot silently rot into covering the wrong
+ population. Two independent checks, matching the two places a black
+ celebration could be added:
+
+ DATA: every entry the shipped sanctoral layer (sanctoral.sexp, with
+ adjustments.sexp merged on top -- the same [layer] every other test in
+ this file resolves against) carries directly, fixed AND movable alike
+ ({!Colitur_kernel.Layer.entries} holds the raw [Date_spec.t], not a
+ resolved index, so this needs no date walk at all to cover every civil
+ year).
+
+ CODE: {!Rite_ef.Temporal_ef.temporal}'s own colour logic, which
+ sanctoral.sexp cannot see (Good Friday's black is computed, not data) --
+ swept across a century the same span and for the same coverage reason
+ {!test_ferial_origin_never_carries_lord_bvm_or_apostle_slug} above
+ already uses, since a Colour.Black bug introduced into a rare branch
+ (an Ember day, Rogation Wednesday...) would not show up in one year. *)
+let test_colour_black_population_is_exactly_two () =
+ let black_data_entries =
+ List.filter
+ (fun (e : V.rank Colitur_kernel.Layer.entry) -> e.Colitur_kernel.Layer.cel.Cel.colour = Colour.Black)
+ layer.Colitur_kernel.Layer.entries
+ in
+ Alcotest.(check int) "exactly one Colour.Black entry in the shipped data" 1
+ (List.length black_data_entries);
+ (match black_data_entries with
+ | [ e ] ->
+ Alcotest.(check string) "the one Colour.Black data entry is All Souls" "commemoration-of-all-souls"
+ (Slug.to_string e.Colitur_kernel.Layer.cel.Cel.slug)
+ | _ -> ());
+ let code_black = ref [] in
+ for y = 1583 to 1682 do
+ let dec31 = mk y 12 31 in
+ let d = ref (mk y 1 1) in
+ while Date.compare !d dec31 <= 0 do
+ let t = TE.temporal !d in
+ if t.Temporal.office.Cel.colour = Colour.Black then code_black := (y, !d, t) :: !code_black;
+ d := Date.add_days !d 1
+ done
+ done;
+ Alcotest.(check bool) "the century sweep found at least 100 Colour.Black temporal days" true
+ (List.length !code_black >= 100);
+ List.iter
+ (fun (_, d, (t : (V.season, V.rank) Temporal.t)) ->
+ let easter = Computus.gregorian_easter (Date.year d) in
+ Alcotest.(check int)
+ (Printf.sprintf "%s: the only code-side Colour.Black day is Good Friday (Easter-2)"
+ (Date.to_iso8601 d))
+ (-2) (Date.to_rata d - Date.to_rata easter);
+ Alcotest.(check string)
+ (Printf.sprintf "%s: Good Friday's own slug" (Date.to_iso8601 d))
+ "ef-passiontide-2-friday"
+ (Slug.to_string t.Temporal.office.Cel.slug))
+ !code_black
+
(* ---- RG 476(b) negative: a plain II-class saint, not Domini/BVM, not an
Apostle/Evangelist ---- *)
@@ -381,6 +463,12 @@ let suite =
Alcotest.test_case "RG 23/476(a): Holy Thursday" `Quick test_holy_thursday_no_creed;
Alcotest.test_case "RG 23/476(a): Holy Saturday / Easter Vigil" `Quick
test_holy_saturday_easter_vigil_no_creed;
+ Alcotest.test_case "476(f): All Souls' Day (transferred), a Requiem, no Creed" `Quick
+ test_476f_all_souls_no_creed;
+ Alcotest.test_case "476(f)/RG 23(b): Good Friday, black, no Creed" `Quick
+ test_476f_good_friday_no_creed;
+ Alcotest.test_case "Colour.Black population is exactly two (data + code)" `Quick
+ test_colour_black_population_is_exactly_two;
Alcotest.test_case "476(b): plain II-class saint (negative)" `Quick
test_476b_plain_class2_saint;
Alcotest.test_case "vigils excluded even when Class2 and Marian" `Quick