diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-27 00:24:03 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-27 00:24:03 +0200 |
| commit | bf42e85ed622da5227a69c26ec801d32c767bb32 (patch) | |
| tree | e226fc4dfe25252bd90d706ea415c60c5c9791d9 /test/test_view.ml | |
| parent | 90584d87e763789808329847c46dbaa8e22dca47 (diff) | |
| download | colitur-bf42e85ed622da5227a69c26ec801d32c767bb32.tar.gz colitur-bf42e85ed622da5227a69c26ec801d32c767bb32.zip | |
fix(render): derive citation keys from the day, not a hardcoded pair (W5)
lib/render/view.ml hardcoded exactly two template keys, "first" and
"gospel", regardless of what a day's citations actually contain. The OF
now resolves a third reading, Second, on Sundays and solemnities (OLM
1981 Praenotanda n. 69.1/n. 84(b)(c)) via the rite-supplied
Rite.t.citation_shapes, which the render layer could not express. Latent
today (bin/main.ml's reject_rite_for refuses --rite on every command that
reaches View.of_days, so only EF ever reaches this path), but the wrong
shape to carry forward.
View.citation_fields now derives one key per Citation.part ACTUALLY
PRESENT in a day's own citations, in Citation.all_parts order, using
Citation.part_to_string for the key name. An absent part contributes no
key at all, not a key holding the empty string: Template.render already
treats a missing key and a present Str "" identically in Var, Section and
Inverted position, so nothing is lost, and Emit_json.year dumps the whole
Obj verbatim, so an unconditionally-present-but-empty key for a
still-unbuilt part (Psalm/Tract/Alleluia/Sequence) would sit in every EF
day's JSON forever. Filtering to present parts alone is what makes EF's
output identical byte for byte BY CONSTRUCTION rather than by a rite
check: EF's citations are always exactly [First; Gospel], so the derived
key set is always {"first"; "gospel"}, in that order.
padding_cell keeps its own fixed "first"/"gospel" pair rather than
deriving from a (nonexistent) day: it mirrors the closed set every rite
currently reachable through this render path (EF alone) always carries,
documented as debt for whenever a rite whose citation_shapes includes
Second is admitted here -- test_padding_and_real_share_key_set would
catch the mismatch immediately.
Downstream consumers: Emit_json needed no change (already a verbatim
dump). Emit_xml and Emit_ics gained a third, order-preserving element/line
(a <citation part="second"> element; a "Second ..." DESCRIPTION line
spliced between Epistle and Gospel) since neither is a fixed-column
format. Emit_csv is deliberately left unwidened and commented: RFC 4180's
header-row contract makes a variable column count illegal, and OF cannot
reach `emit` today regardless, so there is nothing to widen for yet;
admitting OF here later needs a disclosed, deliberate format change, not
a silent one.
term_keys (line ~239) is left unchanged, with a comment recording the
judgment call: "epistle" and "lesson" are indeed EF/Roman vocabulary
(Epistola vs. a non-apostolic Lectio, e.g. an Ember day's Old Testament
reading) sitting in an otherwise rite-agnostic list, but nothing forces a
fix yet -- no OF template exists, and every in-repo EF template already
reads term.epistle, so renaming it would break 11 shipped templates and
any user template for zero present benefit. "lesson" already sits unused,
already translated in both lang files, and is the natural neutral term a
future OF ordo template would reach for.
Tests: test_view.ml gains test_ef_days_never_carry_a_second_key (a whole
year, not one day) and test_three_citation_day_exposes_all_three, driving
View.of_days directly with a hand-built Liturgical_day.t since OF cannot
reach this path through the CLI yet -- the only honest way to exercise a
latent path. test_emit.ml/test_ics.ml extend coverage to Emit_xml/Emit_ics
(presence, value, and reading order) and pin Emit_csv's deliberate
16-column non-widening.
EF byte-identity: zero diff in data/ef/ or lib/rites/rite_ef/ against the
pre-change commit. `colitur day`, `readings`, `emit --format csv/xml/json/
ics`, and `table --template templates/ef/ordo.txt` for 2026, all non-empty,
all byte-identical (cmp) against a worktree build of the pre-change commit.
Diffstat (limited to 'test/test_view.ml')
| -rw-r--r-- | test/test_view.ml | 52 |
1 files changed, 52 insertions, 0 deletions
diff --git a/test/test_view.ml b/test/test_view.ml index a542419..bbed8ee 100644 --- a/test/test_view.ml +++ b/test/test_view.ml @@ -140,6 +140,41 @@ let test_day_fields () = Alcotest.(check bool) "first citation present" true (as_str (get [ "first" ] d) <> ""); Alcotest.(check bool) "gospel citation present" true (as_str (get [ "gospel" ] d) <> "") +(* W5's own reason for existing: OF cannot reach [View.of_days] through the + CLI today ([bin/main.ml]'s [reject_rite_for] refuses [--rite] on every + command that would build one), so the only honest way to exercise a + THREE-citation day through this path is to drive [View.of_days] directly + with a hand-built [Liturgical_day.t] -- which rite actually produced the + citations is irrelevant to the render layer; only [citations] itself is. + Reuses a real EF day's [temporal]/[observed]/etc. (record update syntax) + purely as scaffolding, with its own two real citations discarded and + replaced -- nothing here asserts anything EF-specific. Exposed (not + [let () = ...] inline) so [test_emit.ml]/[test_ics.ml] can drive the same + synthetic day through [Emit_xml]/[Emit_ics] without duplicating it. *) +let three_citation_view () = + let module K = Colitur_kernel in + let real = List.hd (days_of_year 2027) in + let synthetic = + { real with + K.Liturgical_day.citations = + [ { K.Citation.part = K.Citation.First; reference = "Rom 1:1-7" }; + { K.Citation.part = K.Citation.Second; reference = "1 Cor 1:3-9" }; + { K.Citation.part = K.Citation.Gospel; reference = "Ioann 1:1-14" } ] } + in + let lang = Lazy.force default_lang in + V.of_days ~lang ~sigla:(Test_support.default_sigla lang) ~vocab:Rite_ef.Vocab_ef.vocab ~rite:"ef" ~year:2027 + [ synthetic ] + +let test_three_citation_day_exposes_all_three () = + let v = three_citation_view () in + let d = List.hd (as_list (get [ "days" ] v)) in + Alcotest.(check string) "first" "Rom 1:1-7" (as_str (get [ "first" ] d)); + Alcotest.(check string) "second" "1 Cor 1:3-9" (as_str (get [ "second" ] d)); + (* "Ioann" -> "John": the stored (Latin) book abbreviation renders through + [sigla] the same as [first]/[gospel] always have -- proving [second] + shares the identical [Sigla.format] path, not a second, divergent one. *) + Alcotest.(check string) "gospel" "John 1:1-14" (as_str (get [ "gospel" ] d)) + (* Exactly one of the six colour booleans is true on every day of a whole year: a template that keys a cell colour off them can never get no colour or two. *) let test_exactly_one_colour_flag () = @@ -164,6 +199,21 @@ let keys_of = function | T.Obj kvs -> List.sort compare (List.map fst kvs) | _ -> Alcotest.fail "expected an object" +(* W5: EF's own citations are always exactly [First; Gospel] + ({!Rite_ef}'s own [citation_shapes]) -- so no EF day's key set should + EVER include "second" (or any of the other still-unbuilt parts: + "psalm"/"tract"/"alleluia"/"sequence"). Confirms the "absent key, not a + present key holding the empty string" half of [View.citation_fields]'s + own design, over a whole year rather than one sampled day. *) +let test_ef_days_never_carry_a_second_key () = + let v = view_of 2027 in + List.iter + (fun d -> + List.iter + (fun k -> if List.mem k (keys_of d) then Alcotest.failf "%s carries an unexpected key %s" (as_str (get [ "iso" ] d)) k) + [ "second"; "psalm"; "tract"; "alleluia"; "sequence" ]) + (as_list (get [ "days" ] v)) + let test_padding_and_real_share_key_set () = let v = view_of 2027 in let jan = List.hd (as_list (get [ "months" ] v)) in @@ -318,6 +368,8 @@ let suite = Alcotest.test_case "padding cells flagged" `Quick test_padding_cells_are_flagged; Alcotest.test_case "first week flagged" `Quick test_first_week_flag; Alcotest.test_case "padding and real days share key set" `Quick test_padding_and_real_share_key_set; + Alcotest.test_case "EF days never carry a second key" `Quick test_ef_days_never_carry_a_second_key; + Alcotest.test_case "three-citation day exposes all three" `Quick test_three_citation_day_exposes_all_three; Alcotest.test_case "week num_roman and month fields" `Quick test_week_num_roman_and_month_fields; Alcotest.test_case "week date span" `Quick test_week_date_span; Alcotest.test_case "single_day agrees with span and cells" `Quick test_single_day_agrees_with_span_and_cells; |
