summaryrefslogtreecommitdiff
path: root/test/test_temporal_ef.ml
diff options
context:
space:
mode:
Diffstat (limited to 'test/test_temporal_ef.ml')
-rw-r--r--test/test_temporal_ef.ml131
1 files changed, 128 insertions, 3 deletions
diff --git a/test/test_temporal_ef.ml b/test/test_temporal_ef.ml
index 5394173..ff3cc0b 100644
--- a/test/test_temporal_ef.ml
+++ b/test/test_temporal_ef.ml
@@ -296,13 +296,31 @@ let test_holy_name_sunday_shape () =
compared against)"
None (Colitur_kernel.Names.find (office (d 2026 1 4)).Cel.names en);
(* Negative controls: every OTHER day in the 2-5 January window that year
- stays [subject Temporal] -- the override is scoped to exactly the one
- Sunday [T.holy_name_sunday] names, not the whole window. *)
+ is NOT Lord -- RG 17(a)'s own override is scoped to exactly the one
+ Sunday [T.holy_name_sunday] names, not the whole window. 2 and 5 January
+ (Friday, Monday) stay plain [Temporal] ferias, as before. 3 January is a
+ SATURDAY -- an unrelated rubric (RG 78, "De sancta Maria in sabbato",
+ {!bvm_saturday_names}'s own citation in temporal_ef.ml) legitimately
+ retags it [Bvm], not [Temporal]: it is an otherwise-unoccupied IV-class
+ Saturday (Christmastide's "ef-christmas-1-*" ferial branch, [ferial_rank]'s
+ unconditional Class4 there), so RG 78 fires regardless of RG 17(a) being
+ in play the same week -- the two rubrics are independent and this is not
+ a collision. This is deliberately NOT folded into the [Temporal] check
+ above: asserting "stays Temporal" for 3 January would be WRONG once RG
+ 78 is built, not merely incomplete. *)
List.iter
(fun dd ->
Alcotest.(check bool) (Printf.sprintf "2026-01-%02d: NOT Lord (not the Sunday)" dd) true
- (subject_of (d 2026 1 dd) = Sub.Temporal))
+ (subject_of (d 2026 1 dd) <> Sub.Lord))
[ 2; 3; 5 ];
+ Alcotest.(check bool) "2026-01-02: plain Temporal feria (not a Saturday)" true
+ (subject_of (d 2026 1 2) = Sub.Temporal);
+ Alcotest.(check bool) "2026-01-05: plain Temporal feria (not a Saturday)" true
+ (subject_of (d 2026 1 5) = Sub.Temporal);
+ Alcotest.(check bool) "2026-01-03: a Saturday -- RG 78's BVM Saturday office fires here \
+ independently of RG 17(a)"
+ true
+ (subject_of (d 2026 1 3) = Sub.Bvm);
(* 2027: 3 January is the Sunday (`date -d 2027-01-03 +%u` = 7) -- the
oracle window's own second instance of the Sunday shape. missalemeum's
2027-01-03 row independently corroborates: rank 2, white, title "Holy
@@ -489,7 +507,20 @@ let test_colours () =
(6 Jan) is a Tuesday, so the actual first-Sunday-after-Epiphany origin is
11 Jan -- exercising all four sub-stretches of the fix. *)
let test_christmastide_feria_slugs () =
+ (* 26 Dec 2026 and 10 Jan 2026 are both SATURDAYS -- ef-bvm-saturday task
+ (RG 78, "De sancta Maria in sabbato"): every Christmastide feria
+ [christmastide_feria_slug] builds is unconditionally Class4
+ ([ferial_rank]'s own catch-all outside Advent/Lent/Passiontide), so on a
+ Saturday {!Rite_ef.Temporal_ef.bvm_saturday_names}'s own override fires
+ here too -- but per that citation's own "Slug" paragraph, the SLUG is
+ deliberately left UNCHANGED (reused from this same "-0-"/"-2-" naming,
+ not replaced): only colour/subject/name change. So the slug assertions
+ below are unaffected by the fix; what is NEW is the colour/subject
+ override on these two specific dates, asserted alongside them. *)
Alcotest.(check string) "26 Dec (Sat)" "ef-christmas-0-saturday" (slug_of (d 2026 12 26));
+ Alcotest.(check string) "26 Dec (Sat): the BVM Saturday office overrides the season colour (white, RG 120(b))"
+ "white" (colour_of (d 2026 12 26));
+ Alcotest.(check bool) "26 Dec (Sat): subject Bvm" true (subject_of (d 2026 12 26) = Sub.Bvm);
Alcotest.(check string) "28 Dec (Mon)" "ef-christmas-0-monday" (slug_of (d 2026 12 28));
Alcotest.(check string) "2 Jan (Fri)" "ef-christmas-1-friday" (slug_of (d 2026 1 2));
Alcotest.(check string) "5 Jan (Mon)" "ef-christmas-1-monday" (slug_of (d 2026 1 5));
@@ -497,6 +528,7 @@ let test_christmastide_feria_slugs () =
lectio's "week 1" key, precisely to avoid colliding with 12-13 Jan below. *)
Alcotest.(check string) "7 Jan (Wed, before the origin)" "ef-christmas-2-wednesday" (slug_of (d 2026 1 7));
Alcotest.(check string) "10 Jan (Sat, before the origin)" "ef-christmas-2-saturday" (slug_of (d 2026 1 10));
+ Alcotest.(check bool) "10 Jan (Sat): subject Bvm" true (subject_of (d 2026 1 10) = Sub.Bvm);
(* 12-13 Jan are on/after the origin: genuinely week 1, lectio's key. *)
Alcotest.(check string) "12 Jan (Mon, on/after the origin)" "ef-time-after-epiphany-1-monday"
(slug_of (d 2026 1 12));
@@ -813,6 +845,98 @@ let test_sacred_triduum_identity () =
Alcotest.(check bool) "1666-04-22 Holy Thursday: subject Lord" true
(subject_of (d 1666 4 22) = Sub.Lord)
+(* RG 91 entry 27 / RG 78-79 (Caput IX, "De sancta Maria in sabbato") --
+ {!Rite_ef.Temporal_ef.bvm_saturday_names}'s own citation has the full
+ primary-source argument (both photographic scans and the electronic
+ transcription for RG 78/79 themselves; both photographic scans for RG
+ 120(b)'s colour rule and the Missal's own "Missae de sancta Maria in
+ sabbato" heading). This test proves it holds across every season family
+ [ferial_rank] can give Class4 outside a privileged run -- Christmastide,
+ Septuagesima, Time after Epiphany, Time after Pentecost and ordinary
+ Paschaltide -- and that it does NOT fire where RG 78's own protasis is
+ false (Advent/Lent/Passiontide Saturdays, already II/III class; Ember
+ Saturdays, II/I class; a non-Saturday day in the very same week). Every
+ date below was independently checked against `colitur day <year>`'s own
+ real output (data/ef/sanctoral.sexp + adjustments.sexp) before being
+ pinned here, exactly like test_golden.ml's own discipline -- not merely
+ asserted against [T.temporal]'s own predicted shape a second time. *)
+let test_bvm_saturday () =
+ (* Septuagesima, clean (no competing sanctoral candidate that year):
+ 19 February 2028, Septuagesima I Saturday. Colour is the clearest
+ possible witness here -- Septuagesima's own season colour is violet
+ (RG 128(b)), so a white result can only come from RG 120(b)'s override,
+ never from [season_colour] agreeing by coincidence the way
+ Christmastide/Paschaltide do below. *)
+ Alcotest.(check string) "2028-02-19 (Septuagesima I Saturday): slug stays the ordinary ferial key"
+ "ef-septuagesima-1-saturday" (slug_of (d 2028 2 19));
+ Alcotest.(check string) "2028-02-19: class-4, unconditional (RG 91's own IV-class table position)"
+ "class-4" (rank_of (d 2028 2 19));
+ Alcotest.(check string) "2028-02-19: white overrides Septuagesima's own violet (RG 120(b), not RG 128(b))"
+ "white" (colour_of (d 2028 2 19));
+ Alcotest.(check bool) "2028-02-19: subject Bvm" true (subject_of (d 2028 2 19) = Sub.Bvm);
+ Alcotest.(check (option string)) "2028-02-19: Latin name, both photographic scans and the transcription, \
+ word for word"
+ (Some "Officium sanctae Mariae in sabbato") (name_la_of (d 2028 2 19));
+ (* Time after Epiphany, clean: 16 February 2030. Season colour there is
+ green (RG 127), like Time after Pentecost below -- a second,
+ independent witness that the override is season-blind, not merely
+ "true for Septuagesima's violet and Time after Pentecost's green
+ happen to share a fix". *)
+ Alcotest.(check string) "2030-02-16 (Time after Epiphany V Saturday): slug stays the ordinary ferial key"
+ "ef-time-after-epiphany-5-saturday" (slug_of (d 2030 2 16));
+ Alcotest.(check string) "2030-02-16: white overrides Time after Epiphany's own green (RG 127)" "white"
+ (colour_of (d 2030 2 16));
+ Alcotest.(check bool) "2030-02-16: subject Bvm" true (subject_of (d 2030 2 16) = Sub.Bvm);
+ (* Time after Pentecost, clean: 27 June 2026. *)
+ Alcotest.(check string) "2026-06-27 (Time after Pentecost IV Saturday): slug stays the ordinary ferial key"
+ "ef-time-after-pentecost-4-saturday" (slug_of (d 2026 6 27));
+ Alcotest.(check string) "2026-06-27: white overrides Time after Pentecost's own green (RG 127)" "white"
+ (colour_of (d 2026 6 27));
+ Alcotest.(check bool) "2026-06-27: subject Bvm" true (subject_of (d 2026 6 27) = Sub.Bvm);
+ (* Ordinary Paschaltide, clean, outside the privileged Easter octave: 18
+ April 2026. Season colour there is ALREADY white (RG 119) -- colour
+ alone cannot distinguish the override firing from it simply not being
+ needed, so subject/name are the load-bearing assertions on this one,
+ not colour (the SAME reasoning [test_holy_family]'s own "Christmastide
+ already white" gap does not arise for -- this is a genuine, deliberate
+ exception recorded here, not an oversight). *)
+ Alcotest.(check string) "2026-04-18 (Paschaltide II Saturday): slug stays the ordinary ferial key"
+ "ef-easter-2-saturday" (slug_of (d 2026 4 18));
+ Alcotest.(check string) "2026-04-18: white (coincides with Paschaltide's own RG 119 white -- not a \
+ distinguishing witness on its own)"
+ "white" (colour_of (d 2026 4 18));
+ Alcotest.(check bool) "2026-04-18: subject Bvm (the real witness this date proves, since colour alone \
+ cannot)"
+ true (subject_of (d 2026 4 18) = Sub.Bvm);
+ Alcotest.(check (option string)) "2026-04-18: Latin name present too" (Some "Officium sanctae Mariae in sabbato")
+ (name_la_of (d 2026 4 18));
+ (* Negative controls: RG 78's own protasis ("in quibus occurrit Officium
+ de feria IV classis") is false for these -- each is already II or III
+ class, never reaching Class4 at all, so none of them is overridden. *)
+ Alcotest.(check string) "2026-03-14 (an ordinary Lent Saturday): stays III class, violet, Temporal"
+ "class-3" (rank_of (d 2026 3 14));
+ Alcotest.(check string) "2026-03-14: violet, NOT overridden (RG 78 never applies -- already III class)"
+ "violet" (colour_of (d 2026 3 14));
+ Alcotest.(check bool) "2026-03-14: subject stays Temporal" true (subject_of (d 2026 3 14) = Sub.Temporal);
+ Alcotest.(check string) "2026-12-12 (an ordinary Advent Saturday, before 17 Dec): stays III class"
+ "class-3" (rank_of (d 2026 12 12));
+ Alcotest.(check bool) "2026-12-12: subject stays Temporal (not overridden)" true
+ (subject_of (d 2026 12 12) = Sub.Temporal);
+ Alcotest.(check string) "2026-02-28 (Lent Ember Saturday): stays II class, NOT overridden" "class-2"
+ (rank_of (d 2026 2 28));
+ Alcotest.(check bool) "2026-02-28: subject stays Temporal" true (subject_of (d 2026 2 28) = Sub.Temporal);
+ Alcotest.(check string) "2026-09-26 (September Ember Saturday): stays II class, NOT overridden" "class-2"
+ (rank_of (d 2026 9 26));
+ (* A non-Saturday day in the SAME week as a clean BVM Saturday stays an
+ ordinary ferial -- the override is exactly one weekday wide, not the
+ whole week. 26 June 2026 is the Friday immediately before the 27 June
+ Saturday pinned above. *)
+ Alcotest.(check string) "2026-06-26 (Friday, day before a BVM Saturday): plain ferial, not overridden"
+ "ef-time-after-pentecost-4-friday" (slug_of (d 2026 6 26));
+ Alcotest.(check string) "2026-06-26: green, the season's own colour, unaffected" "green"
+ (colour_of (d 2026 6 26));
+ Alcotest.(check bool) "2026-06-26: subject stays Temporal" true (subject_of (d 2026 6 26) = Sub.Temporal)
+
let test_totality () =
(* Every day of 2026 yields an office without raising. Not a slug
re-validation -- Slug.t is a private string validated on construction,
@@ -848,6 +972,7 @@ let suite_extra =
Alcotest.test_case "colours" `Quick test_colours;
Alcotest.test_case "sacred triduum identity (RG 91 entry 2, Gap 1)" `Quick
test_sacred_triduum_identity;
+ Alcotest.test_case "BVM Saturday office (RG 91 entry 27, RG 78-79)" `Quick test_bvm_saturday;
Alcotest.test_case "christmastide feria slugs" `Quick test_christmastide_feria_slugs;
Alcotest.test_case "named days carry their week" `Quick test_named_days_carry_their_week;
Alcotest.test_case "totality" `Quick test_totality;