From ebbf88dae0110e9cb00935861fae1857107260cc Mon Sep 17 00:00:00 2001 From: Lukasz Kasprzak Date: Tue, 25 Aug 2026 19:47:52 +0200 Subject: feat(of): disposition per Normae n. 60 An impeded solemnity transfers; every other loser is omitted for that year ('Reliquae celebrationes eo anno omittuntur'). Commemorate is never returned, and that is the rule rather than a gap: the OF has no commemoration of a losing celebration in the EF's sense, and an optional memorial is an election rather than a commemoration. A property over every rank pairing asserts it, so a later edit cannot quietly introduce one. --- test/test_precedence_of.ml | 58 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) (limited to 'test/test_precedence_of.ml') diff --git a/test/test_precedence_of.ml b/test/test_precedence_of.ml index 64b182c..b947d11 100644 --- a/test/test_precedence_of.ml +++ b/test/test_precedence_of.ml @@ -262,10 +262,66 @@ let test_exhaustive_band_total () = Alcotest.skip () else for y = 1583 to 9999 do check_year y done +let disposition_cases = + [ ( "a losing solemnity transfers (Normae n. 60)", + mk ~slug:"of-advent-sunday-2" ~rank:Vocab_of.Sollemnitas ~origin:Precedence.Temporal (), + mk ~slug:"of-immaculate-conception" ~rank:Vocab_of.Sollemnitas ~origin:Precedence.Sanctoral (), + Precedence.Transfer ); + ( "a losing feast is omitted, never commemorated", + mk ~slug:"of-lent-sunday-3" ~rank:Vocab_of.Sollemnitas ~origin:Precedence.Temporal (), + mk ~slug:"of-mark" ~rank:Vocab_of.Festum ~origin:Precedence.Sanctoral (), + Precedence.Omit ); + ( "a losing obligatory memorial is omitted", + mk ~slug:"of-lent-2-monday" ~rank:Vocab_of.Feria ~origin:Precedence.Temporal (), + mk ~slug:"of-agnes" ~rank:Vocab_of.Memoria_obligatoria ~origin:Precedence.Sanctoral (), + Precedence.Omit ); + ( "a losing optional memorial is omitted", + mk ~slug:"of-ordinary-time-15-tuesday" ~rank:Vocab_of.Feria ~origin:Precedence.Temporal (), + mk ~slug:"of-hilary" ~rank:Vocab_of.Memoria_ad_libitum ~origin:Precedence.Sanctoral (), + Precedence.Omit ); + ( "a losing feria is omitted", + mk ~slug:"of-peter-and-paul" ~rank:Vocab_of.Sollemnitas ~origin:Precedence.Sanctoral (), + mk ~slug:"of-ordinary-time-13-monday" ~rank:Vocab_of.Feria ~origin:Precedence.Temporal (), + Precedence.Omit ) ] + +let test_disposition () = + List.iter + (fun (label, winner, loser, expected) -> + Alcotest.(check string) label + (Precedence.sexp_of_disposition expected |> Sexplib0.Sexp.to_string) + (Rite_of.Precedence_of.disposition ~winner ~loser + |> Precedence.sexp_of_disposition |> Sexplib0.Sexp.to_string)) + disposition_cases + +(* The rule stated as a property rather than as five rows: across every + rank/rank pairing, disposition returns Transfer exactly when the loser is a + solemnity, and Omit otherwise -- never Commemorate, never Repose. *) +let test_disposition_never_commemorates () = + List.iter + (fun lr -> + List.iter + (fun wr -> + let winner = mk ~slug:"of-winner" ~rank:wr ~origin:Precedence.Temporal () in + let loser = mk ~slug:"of-loser" ~rank:lr ~origin:Precedence.Sanctoral () in + match Rite_of.Precedence_of.disposition ~winner ~loser with + | Precedence.Transfer -> + Alcotest.(check bool) "only a solemnity transfers" true + (lr = Vocab_of.Sollemnitas) + | Precedence.Omit -> + Alcotest.(check bool) "a solemnity never merely omits" false + (lr = Vocab_of.Sollemnitas) + | Precedence.Commemorate _ -> + Alcotest.fail "OF has no commemorations (Normae n. 60)" + | Precedence.Repose -> Alcotest.fail "OF never reposes a celebration") + Vocab_of.ranks) + Vocab_of.ranks + let suite = ( "precedence-of", [ Alcotest.test_case "Tabula part I (entries 1-4)" `Quick test_part1; Alcotest.test_case "Tabula part II (entries 5-9)" `Quick test_part2; Alcotest.test_case "Tabula part III (entries 10-13)" `Quick test_part3; - Alcotest.test_case "band is total over the domain" `Slow test_exhaustive_band_total ] + Alcotest.test_case "band is total over the domain" `Slow test_exhaustive_band_total; + Alcotest.test_case "disposition (Normae n. 60)" `Quick test_disposition; + Alcotest.test_case "disposition never commemorates" `Quick test_disposition_never_commemorates ] @ List.map QCheck_alcotest.to_alcotest [ prop_band_total ] ) -- cgit v1.3