diff options
| author | Lukasz Kasprzak <lukasz@arcofasiagroup.com> | 2026-08-27 12:33:43 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukasz@arcofasiagroup.com> | 2026-08-27 12:33:43 +0200 |
| commit | 32e792a0741f62fc2c0c7dcf9255408b3256fad5 (patch) | |
| tree | 92f0b7b0a289de5251bb18bcc9239becdaee223c /test/test_emit.ml | |
| parent | 85903385f8a32be3de3964f43b3d7831474d0a72 (diff) | |
| download | colitur-32e792a0741f62fc2c0c7dcf9255408b3256fad5.tar.gz colitur-32e792a0741f62fc2c0c7dcf9255408b3256fad5.zip | |
fix(cli): make the flag surface systematic
An audit probed every flag against every command rather than reading --help,
and found three inconsistencies.
--rite reached only `day` and `readings`. main.ml's own comment gave the
reason -- "has not been widened to a second rite in this task" -- a scope note
that had outlived its task and hardened into apparent design. View.of_days was
already polymorphic over the rite's type parameters, so widening was plumbing,
not library work: `temporal`, `rubrics`, `emit`, `table`, `render` and
`publish` now all take it.
`temporal` was the sharpest case. Its refusal said "--rite has no effect on
`temporal`", which was false: the EF has Septuagesima and Passiontide, the OF
neither, and every EF slug is ef-prefixed, so the flag would change nearly
every line. A message claiming no effect where the effect is total is exactly
what the audit set out to find.
Three ways of naming a year (positional, --year, --from/--to) now cross-accept
additively; naming two that disagree is a usage error rather than one silently
winning.
emit --format csv gained a rite-dependent header: EF's 16 columns are
unchanged, OF gets a 17th "second" between "first" and "gospel". An earlier
task had recorded RFC 4180 as permanently blocking this; the rule constrains
one file, not a family of them.
`rubrics` keeps refusing --lang/--raw, now with its reason. An intermediate
version accepted them by adding a name column, which changed the default from
six tab-separated fields to seven and broke both existing consumers and the
byte-identical-EF rule. The asymmetry is real but principled: the row is a
date, a slug, a source keyword, two booleans and a preface key, so there is
nothing to translate and nothing to strip. `easter` refuses --rite for the
same kind of reason -- its six anchors sit at identical Easter offsets in both
rites.
EF output verified byte-identical to 8590338 across day, readings, rubrics,
temporal and easter for 2026, 1583 and 9999, and across all five emit formats.
Diffstat (limited to 'test/test_emit.ml')
| -rw-r--r-- | test/test_emit.ml | 37 |
1 files changed, 37 insertions, 0 deletions
diff --git a/test/test_emit.ml b/test/test_emit.ml index bd9cadc..988e68e 100644 --- a/test/test_emit.ml +++ b/test/test_emit.ml @@ -105,6 +105,42 @@ let test_csv_does_not_widen_for_a_third_citation () = (List.hd lines); Alcotest.(check int) "row still 16 fields" 16 (List.length (parse_csv_row (List.nth lines 1))) +(* Fix 1 (cli-flags-report, 2026-08-27): a NON-"ef" rite DOES widen the CSV + header with a 17th column, "second", between "first" and "gospel" -- + exactly the deliberate, disclosed change [Emit_csv.columns]'s own header + comment predicted the day OF was admitted to `emit` would need. Built + directly against a synthetic [Template.value] rather than a real + [View.of_days] call: [Emit_csv] only ever reads the view's own "rite" + string and per-day string keys, never a [Vocab.t] or a real + [Liturgical_day.t], so this exercises the identical gating + [test_csv_does_not_widen_for_a_third_citation] above proves EF never + takes, in isolation from the calendar/view layers (which carry no real + OF test fixtures in this file). *) +let synthetic_of_day () = + let module T = Colitur_render.Template in + T.Obj + [ ("iso", T.Str "2026-11-29"); ("season", T.Str "advent"); ("season_name", T.Str "Tempus Adventus"); + ("week", T.Str "1"); ("slug", T.Str "of-advent-sunday-1"); ("name", T.Str "of-advent-sunday-1"); + ("weekday", T.Str "Dominica"); ("rank", T.Str "sollemnitas"); ("rank_name", T.Str "sollemnitas"); + ("colour", T.Str "violet"); ("colour_name", T.Str "violaceus"); ("subject", T.Str "temporal"); + ("first", T.Str "Isai 63:16b-17, 19b; 64:2-7"); ("second", T.Str "1 Cor 1:3-9"); + ("gospel", T.Str "Marc 13:33-37"); ("comms", T.List []) ] + +let synthetic_of_view () = + let module T = Colitur_render.Template in + T.Obj [ ("rite", T.Str "of"); ("year", T.Str "2026"); ("days", T.List [ synthetic_of_day () ]) ] + +let test_csv_widens_for_a_non_ef_rite () = + let out = Csv.year (synthetic_of_view ()) in + let lines = String.split_on_char '\n' out |> List.filter (fun l -> l <> "") in + Alcotest.(check string) "header widened with second" + "date,rite,season,season_name,week,slug,name,weekday,rank,rank_name,colour,colour_name,subject,first,second,gospel,comms" + (List.hd lines); + let row = List.nth lines 1 in + Alcotest.(check int) "row has 17 fields" 17 (List.length (parse_csv_row row)); + Alcotest.(check bool) "second reading appears in the row" true + (contains ~needle:"1 Cor 1:3-9" row) + let test_json_parses_back () = let out = Json.year (view_2027 ()) in Alcotest.(check bool) "starts as an object" true (out.[0] = '{'); @@ -149,6 +185,7 @@ let suite = Alcotest.test_case "csv quotes commas" `Quick test_csv_quotes_commas; Alcotest.test_case "csv does not widen for a third citation" `Quick test_csv_does_not_widen_for_a_third_citation; + Alcotest.test_case "csv widens for a non-ef rite" `Quick test_csv_widens_for_a_non_ef_rite; Alcotest.test_case "json parses back" `Quick test_json_parses_back; Alcotest.test_case "json escapes" `Quick test_json_escapes; Alcotest.test_case "json passes utf8 through" `Quick test_utf8_passes_through_json ] ) |
