summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
Diffstat (limited to 'test')
-rw-r--r--test/test_calendar.ml13
-rw-r--r--test/test_differential.ml10
-rw-r--r--test/test_golden.ml12
-rw-r--r--test/test_lectionary_ef.ml59
-rw-r--r--test/test_oracle.ml10
-rw-r--r--test/test_rite_ef.ml21
-rw-r--r--test/test_validate.ml12
7 files changed, 124 insertions, 13 deletions
diff --git a/test/test_calendar.ml b/test/test_calendar.ml
index 2f6df6d..aeaeea0 100644
--- a/test/test_calendar.ml
+++ b/test/test_calendar.ml
@@ -464,6 +464,13 @@ let real_ef_layer_for_transfer_probes =
if diagnostics <> [] then failwith "unexpected overlay diagnostics loading the real EF layer";
layer)
+(* [Rite_ef.context] takes [~lectionary] (fix round 1, coordinator review) --
+ caller-supplied, same as the sanctoral layer above. *)
+let real_ef_lectionary_for_transfer_probes =
+ match Colitur_kernel.Lectionary.load "../data/ef/lectionary.sexp" with
+ | Error e -> failwith ("../data/ef/lectionary.sexp: " ^ e)
+ | Ok l -> l
+
let test_transferred_commemoration_only_capped_out_at_target_settles_cleanly () =
let probe_date =
match Colitur_kernel.Date_spec.fixed ~month:4 ~day:26 with Ok d -> d | Error e -> failwith e
@@ -479,7 +486,11 @@ let test_transferred_commemoration_only_capped_out_at_target_settles_cleanly ()
let augmented_layer = Colitur_kernel.Layer.set real_ef_layer_for_transfer_probes probe in
(* Liturgical year "2010" (Advent 2010 -- eve of Advent 2011) covers both
25 and 26 April 2011. *)
- let year = C.year Rite_ef.context augmented_layer 2010 in
+ let year =
+ C.year
+ (Rite_ef.context ~lectionary:real_ef_lectionary_for_transfer_probes)
+ augmented_layer 2010
+ in
let find_date target =
match Array.to_list year |> List.find_opt (fun d -> D.compare d.LD.date target = 0) with
| Some d -> d
diff --git a/test/test_differential.ml b/test/test_differential.ml
index a4e550d..0b68f90 100644
--- a/test/test_differential.ml
+++ b/test/test_differential.ml
@@ -207,6 +207,13 @@ let real_layer () =
(List.map Overlay.diagnostic_to_string diagnostics);
layer
+(* [Rite_ef.context] takes [~lectionary] (fix round 1, coordinator review) --
+ caller-supplied, same as [real_layer] above. *)
+let real_lectionary () =
+ match Colitur_kernel.Lectionary.load "../data/ef/lectionary.sexp" with
+ | Ok l -> l
+ | Error e -> Alcotest.failf "../data/ef/lectionary.sexp: failed to load: %s" e
+
(* --- The seven-column row both streams share (commemorations excluded, --- *)
(* limit 1 above). *)
type row = {
@@ -255,9 +262,10 @@ let lectio_rows () = List.map row_of_line (read_lines fixture_path)
test_rite_ef.ml already made for [real_layer] above. *)
let colitur_rows_2005_2050 () =
let layer = real_layer () in
+ let rite = Rite_ef.context ~lectionary:(real_lectionary ()) in
let by_rata : (int, (V.season, V.rank) LD.t) Hashtbl.t = Hashtbl.create 20000 in
for y = 2004 to 2050 do
- let days = Cal.year Rite_ef.context layer y in
+ let days = Cal.year rite layer y in
Array.iter (fun (d : (V.season, V.rank) LD.t) -> Hashtbl.replace by_rata (Date.to_rata d.LD.date) d) days
done;
let mk y m d = match Date.make ~year:y ~month:m ~day:d with Ok t -> t | Error e -> failwith e in
diff --git a/test/test_golden.ml b/test/test_golden.ml
index a873738..188e37f 100644
--- a/test/test_golden.ml
+++ b/test/test_golden.ml
@@ -63,6 +63,7 @@ module V = Rite_ef.Vocab_ef
runs from _build/default/test/). *)
let sanctoral_path = "../data/ef/sanctoral.sexp"
let adjustments_path = "../data/ef/adjustments.sexp"
+let lectionary_path = "../data/ef/lectionary.sexp"
(* Loaded once at module init, same convention test_validate.ml's own
[real_ef_layer] uses (not test_oracle.ml/test_differential.ml's
@@ -83,12 +84,21 @@ let real_ef_layer =
(String.concat "; " (List.map Overlay.diagnostic_to_string diagnostics)));
layer)
+(* [Rite_ef.context] takes [~lectionary] (fix round 1, coordinator review) --
+ caller-supplied, same as [real_ef_layer] above. *)
+let real_ef_lectionary =
+ match Colitur_kernel.Lectionary.load lectionary_path with
+ | Error e -> failwith (Printf.sprintf "%s: failed to load: %s" lectionary_path e)
+ | Ok l -> l
+
+let real_ef_rite = Rite_ef.context ~lectionary:real_ef_lectionary
+
let mk y m d = match Date.make ~year:y ~month:m ~day:d with Ok t -> t | Error e -> failwith e
(* [Cal.day] recomputes its whole liturgical year on every call (calendar.mli
-- "pure, no cache"); acceptable here, same as test_rite_ef.ml's own use
of [Cal.year] for a handful of dates, not a hot loop. *)
-let fetch y m d = Cal.day Rite_ef.context real_ef_layer (mk y m d)
+let fetch y m d = Cal.day real_ef_rite real_ef_layer (mk y m d)
let slug_s (c : V.rank Cel.t) = Slug.to_string c.Cel.slug
let rank_s (c : V.rank Cel.t) = V.rank_to_string c.Cel.rank
diff --git a/test/test_lectionary_ef.ml b/test/test_lectionary_ef.ml
index a1a324f..b1c9e7d 100644
--- a/test/test_lectionary_ef.ml
+++ b/test/test_lectionary_ef.ml
@@ -10,6 +10,7 @@ open Rite_ef
declares both as deps. *)
let sanctoral_path = "../data/ef/sanctoral.sexp"
let adjustments_path = "../data/ef/adjustments.sexp"
+let lectionary_path = "../data/ef/lectionary.sexp"
let real_layer () =
let layer =
@@ -27,6 +28,18 @@ let real_layer () =
(List.map Overlay.diagnostic_to_string diagnostics);
layer
+(* [Rite_ef.context] takes [~lectionary] (fix round 1, coordinator review):
+ the module used to load data/ef/lectionary.sexp itself, as a side effect
+ of being linked, which meant a bare `dune build` produced a `colitur`
+ that died at startup on EVERY subcommand -- including ones (`easter`)
+ that touch no lectionary data at all -- the moment that file was absent
+ from the default build target. Caller-supplied now, same as the
+ sanctoral layer above. *)
+let real_lectionary () =
+ match Lectionary.load lectionary_path with
+ | Ok l -> l
+ | Error e -> Alcotest.failf "%s: failed to load: %s" lectionary_path e
+
(* [Calendar.day] (not [year]): the liturgical year "opening in civil year y"
is Advent-anchored (RG 61), so [Calendar.year _ _ 2030] covers Advent 2030
through November 2031 -- it would never contain 13 January 2030, which
@@ -35,7 +48,7 @@ let real_layer () =
let day y m d =
let date = match Date.make ~year:y ~month:m ~day:d with
| Ok x -> x | Error e -> Alcotest.fail e in
- Calendar.day Rite_ef.context (real_layer ()) date
+ Calendar.day (Rite_ef.context ~lectionary:(real_lectionary ())) (real_layer ()) date
let refs (ld : _ Liturgical_day.t) =
List.map (fun c -> c.Citation.reference) ld.citations
@@ -63,6 +76,48 @@ let test_step2_lenten_feria_has_its_own () =
[ "Ezech 34:11-16"; "Matt 25:31-46" ]
(refs (day 2026 2 23))
+(* Fix round 1 (coordinator review, Important finding 2): neither test above
+ actually distinguishes step 1 from step 2 -- both survive swapping the
+ chain order. 13 January 2026's temporal slug (ef-time-after-epiphany-1-
+ tuesday) has no lectionary entry at all, so a swapped chain falls through
+ to the same []-then-sanctoral answer; 23 February 2026's OBSERVED
+ celebration IS the temporal office (ef-lent-1-monday carries no sanctoral
+ entry of its own), so [observed.citations] and the temporal-slug lookup
+ are the same lookup wearing two names -- order is a no-op either way.
+
+ 19 March 2026 (St Joseph) genuinely needs step 1 to run FIRST: the
+ observed celebration (Joseph, Class1, a real sanctoral entry with its own
+ citations) and the day's own temporal slug (ef-lent-4-thursday, ALSO a
+ real lectionary entry, with different citations) disagree. Verified
+ directly against the real data (not transcribed): both value pairs below
+ were read off the actual resolved day and the actual
+ data/ef/lectionary.sexp entry, not assumed. *)
+let test_step1_wins_over_a_competing_step2_entry () =
+ Alcotest.(check (list string))
+ "19 March 2026: Joseph's own proper wins over Lent 4 Thursday's, which the temporal slug also has"
+ [ "Ecclus 45:1-6"; "Matt 1:18-21" ]
+ (refs (day 2026 3 19))
+
+(* Fix round 1 (coordinator review): the mirror-image pin for step 2 -- a day
+ whose OBSERVED celebration carries no citations of its own (Holy Family,
+ synthesised by [Temporal_ef] itself, not sourced from
+ data/ef/sanctoral.sexp, so [Celebration.citations] is empty) falls
+ through to the temporal slug, and the temporal slug's own lectionary
+ entry is genuinely Holy Family's Mass, not the Baptism's -- RG 112(a)
+ (see test_golden.ml's own [test_holy_family_excludes_baptism_2030])
+ excludes the Baptism from this day entirely, so there is no sanctoral
+ citation anywhere to fall back to even in principle. Verified directly
+ against the real data. *)
+let test_step2_holy_family_reached_through_temporal_slug () =
+ Alcotest.(check (list string))
+ "13 January 2030: Holy Family reached via the temporal slug, the Baptism entirely absent"
+ [ "Col 3:12-17"; "Luke 2:42-52" ]
+ (refs (day 2030 1 13))
+
let suite =
[ ("step 1: sanctoral proper", `Quick, test_step1_sanctoral_proper);
- ("step 2: own temporal proper", `Quick, test_step2_lenten_feria_has_its_own) ]
+ ("step 2: own temporal proper", `Quick, test_step2_lenten_feria_has_its_own);
+ ("step 1 wins over a competing step 2 entry", `Quick,
+ test_step1_wins_over_a_competing_step2_entry);
+ ("step 2: Holy Family reached through the temporal slug, Baptism absent", `Quick,
+ test_step2_holy_family_reached_through_temporal_slug) ]
diff --git a/test/test_oracle.ml b/test/test_oracle.ml
index c1d0e6a..e1e4184 100644
--- a/test/test_oracle.ml
+++ b/test/test_oracle.ml
@@ -220,6 +220,13 @@ let real_layer () =
(List.map Overlay.diagnostic_to_string diagnostics);
layer
+(* [Rite_ef.context] takes [~lectionary] (fix round 1, coordinator review) --
+ caller-supplied, same as [real_layer] above. *)
+let real_lectionary () =
+ match Colitur_kernel.Lectionary.load "../data/ef/lectionary.sexp" with
+ | Ok l -> l
+ | Error e -> Alcotest.failf "../data/ef/lectionary.sexp: failed to load: %s" e
+
(* ---------------------------------------------------------------------- *)
(* The oracle side: one line per day, as tools/extract_missalemeum_oracle *)
(* .py's own header documents. *)
@@ -321,9 +328,10 @@ let en = Lang.of_string_exn "en"
let colitur_rows_2026_2027 () =
let layer = real_layer () in
+ let rite = Rite_ef.context ~lectionary:(real_lectionary ()) in
let by_rata : (int, (V.season, V.rank) LD.t) Hashtbl.t = Hashtbl.create 800 in
for y = 2025 to 2027 do
- let days = Cal.year Rite_ef.context layer y in
+ let days = Cal.year rite layer y in
Array.iter (fun (d : (V.season, V.rank) LD.t) -> Hashtbl.replace by_rata (Date.to_rata d.LD.date) d) days
done;
let mk y m d = match Date.make ~year:y ~month:m ~day:d with Ok t -> t | Error e -> failwith e in
diff --git a/test/test_rite_ef.ml b/test/test_rite_ef.ml
index 67b42ce..7680545 100644
--- a/test/test_rite_ef.ml
+++ b/test/test_rite_ef.ml
@@ -49,6 +49,15 @@ let real_layer () =
(List.map Overlay.diagnostic_to_string diagnostics);
layer
+(* [Rite_ef.context] takes [~lectionary] (fix round 1, coordinator review) --
+ caller-supplied, same as [real_layer] above. *)
+let real_lectionary () =
+ match Colitur_kernel.Lectionary.load "../data/ef/lectionary.sexp" with
+ | Ok l -> l
+ | Error e -> Alcotest.failf "../data/ef/lectionary.sexp: failed to load: %s" e
+
+let context () = Rite_ef.context ~lectionary:(real_lectionary ())
+
let slug_of (c : V.rank Cel.t) = Slug.to_string c.Cel.slug
(* Finding 3: the suppression's ONLY observable effect is on 24 December's
@@ -64,7 +73,7 @@ let slug_of (c : V.rank Cel.t) = Slug.to_string c.Cel.slug
alone structurally cannot. *)
let test_vigil_of_christmas_suppressed () =
let layer = real_layer () in
- let days = Cal.year Rite_ef.context layer 2026 in
+ let days = Cal.year (context ()) layer 2026 in
let christmas_eve =
Array.to_list days |> List.find (fun d -> Date.compare d.LD.date (mk 2026 12 24) = 0)
in
@@ -251,7 +260,7 @@ let test_barbara_added () =
Alcotest.(check bool) "barbara: Red (RG124(e), \"Virg. et Mart.\")" true
(e.Layer.cel.Cel.colour = Colour.Red);
Alcotest.(check bool) "barbara: appears as a commemoration on 4 December in real output" true
- (let days = Cal.year Rite_ef.context layer 2026 in
+ (let days = Cal.year (context ()) layer 2026 in
Array.to_list days
|> List.exists (fun d ->
Date.compare d.LD.date (mk 2026 12 4) = 0
@@ -281,7 +290,7 @@ let test_transfer_search_does_not_raise_at_domain_ceiling () =
in
let layer, _diagnostics = Overlay.apply layer overlay in
(* Must not raise -- the whole point of the fix. *)
- let days = Cal.year Rite_ef.context layer 9999 in
+ let days = Cal.year (context ()) layer 9999 in
Alcotest.(check bool) "year 9999 resolves without raising, even with an impeded Christmas Day"
true (Array.length days > 0);
let impeder_placed_or_recorded =
@@ -350,7 +359,7 @@ let test_no_transfer_lands_in_easter_octave () =
let violations = ref [] in
List.iter
(fun y ->
- let days = Cal.year Rite_ef.context layer y in
+ let days = Cal.year (context ()) layer y in
Array.iter
(fun (d : (V.season, V.rank) LD.t) ->
(match d.LD.transferred_in with
@@ -388,7 +397,7 @@ let test_major_litanies_transfers_inside_easter_octave_exactly_when_rg80_require
let landings = ref [] in
List.iter
(fun y ->
- let days = Cal.year Rite_ef.context layer y in
+ let days = Cal.year (context ()) layer y in
Array.iter
(fun (d : (V.season, V.rank) LD.t) ->
List.iter
@@ -491,7 +500,7 @@ let test_maurice_thomas_band_fidelity_end_to_end () =
is reached via [Cal.year ... 2026], not 2027 -- the same
[y-1]/straddling indexing test_oracle.ml's own header comment already
documents for exactly this reason. *)
- let days = Cal.year Rite_ef.context layer 2026 in
+ let days = Cal.year (context ()) layer 2026 in
let day = Array.to_list days |> List.find (fun d -> Date.compare d.LD.date (mk 2027 9 22) = 0) in
Alcotest.(check string) "the September Ember Wednesday office itself is observed (band entry 18)"
"ef-september-ember-wed" (slug_of day.LD.observed);
diff --git a/test/test_validate.ml b/test/test_validate.ml
index 9fa3c5c..8e63a1b 100644
--- a/test/test_validate.ml
+++ b/test/test_validate.ml
@@ -15,6 +15,7 @@ module T = Rite_ef.Temporal_ef
of the (test ...) stanza. *)
let sanctoral_path = "../data/ef/sanctoral.sexp"
let adjustments_path = "../data/ef/adjustments.sexp"
+let lectionary_path = "../data/ef/lectionary.sexp"
(* Loaded once at module init, not per call: [run] below is called by every
test and by the 200-sample property, and Calendar.year's own resolution
@@ -34,7 +35,16 @@ let real_ef_layer =
(String.concat "; " (List.map Overlay.diagnostic_to_string diagnostics)));
layer)
-let run year = Val.run Rite_ef.context real_ef_layer ~year
+(* [Rite_ef.context] takes [~lectionary] (fix round 1, coordinator review) --
+ caller-supplied, same as [real_ef_layer] above. *)
+let real_ef_lectionary =
+ match Colitur_kernel.Lectionary.load lectionary_path with
+ | Error e -> failwith (Printf.sprintf "%s: failed to load: %s" lectionary_path e)
+ | Ok l -> l
+
+let real_ef_rite = Rite_ef.context ~lectionary:real_ef_lectionary
+
+let run year = Val.run real_ef_rite real_ef_layer ~year
let check_year year =
match run year with