aboutsummaryrefslogtreecommitdiff
path: root/test/cli.t
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-17 17:46:31 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-17 17:46:31 +0200
commit0a4bb4e6c3cbcafb302962d9d1e70b5a0bb554b8 (patch)
tree5ad26a80ce3bb0a628ea86f84c28a824c39efb32 /test/cli.t
parent2b9f8133a22ce6dc309644a98bbe61507f574b38 (diff)
downloadcolitur-0a4bb4e6c3cbcafb302962d9d1e70b5a0bb554b8.tar.gz
colitur-0a4bb4e6c3cbcafb302962d9d1e70b5a0bb554b8.zip
feat(cli): --overlay FILE, so a local calendar can be supplied
The Overlay algebra has been built and tested since Plan 2, and Date_spec grew movable variants last commit, but there was still no way to hand colitur a file: bin/main.ml applied exactly one overlay, the shipped data/ef/adjustments.sexp, with the path hardcoded. This is the plumbing. --overlay is repeatable and ordered, and applies ON TOP of the shipped adjustments rather than instead of them. That ordering is the whole point: adjustments.sexp carries RG 110's own 30 June companion, the Major Litanies, St Barbara and Rogation Wednesday, and a user file that replaced it would silently drop all four while appearing merely to add a local feast. Overlay.merge is last-writer-wins, so a local calendar can still override a universal entry deliberately, by naming its slug. The dispatch needed real argument parsing. It matched Sys.argv as an exact array, which does not survive a repeatable flag -- two --overlay arguments are a different array shape from one, and each further flag would multiply the patterns again. Flags are now stripped first and the remaining words matched as command plus year. Hand-rolled, because the dependency list is frozen and this is fifteen lines. One defect found by the cram suite on the first run: the unknown-option guard rejected --help and --version, having excluded only their short forms. Refused, not ignored, on easter and temporal. Neither reads sanctoral data -- temporal deliberately runs the cycle before any layer exists -- so accepting the flag there and silently doing nothing is the failure mode this project refuses everywhere else. A file that fails to load is fatal, exactly as the shipped overlay is; a directive naming a slug that does not exist warns on stderr and the run continues. The second matters more for a user file than for ours: a typo in a diocesan calendar should say so rather than quietly do nothing. test/fixtures/overlay-example-diocesan.sexp is a worked example and is labelled as invented, not calendar data. It carries both shapes a real local calendar needs: a fixed-date patron, and a dedication on "the first Sunday of October" -- which is the case the Date_spec work existed to unlock and which lands on 4 October in 2026, 3 October in 2027, 1 October in 2028. The dedication is I class because a church's own dedication anniversary is I class in that church; at III class it lost to the II-class Sunday every year, which a first draft demonstrated correctly and uselessly. The man page gains an OVERLAYS section saying plainly that an overlay is applied, NOT validated: the five test layers assert things about the shipped calendar and none of them can vouch for a file the user supplies. This is the first feature that lets someone change what colitur computes, and that distinction should not have to be inferred.
Diffstat (limited to 'test/cli.t')
-rw-r--r--test/cli.t65
1 files changed, 65 insertions, 0 deletions
diff --git a/test/cli.t b/test/cli.t
index 419e7f0..9771c56 100644
--- a/test/cli.t
+++ b/test/cli.t
@@ -259,3 +259,68 @@ tree to read dune-project from. It is asserted in the Makefile's release
target instead, which rewrites both and then requires the freshly built
binary to report the version it just wrote -- the point in time where a drift
between the two could actually be introduced.
+
+A user-supplied overlay is applied ON TOP of the shipped universal calendar,
+never instead of it. That ordering is the point: data/ef/adjustments.sexp
+carries RG 110's own 30 June companion, the Major Litanies, St Barbara and
+Rogation Wednesday, and a user file that replaced it would silently drop all
+four while appearing merely to add a local feast.
+
+A fixed-date local patron, observed on its own day:
+
+ $ colitur day 2026 --overlay fixtures/overlay-example-diocesan.sexp | grep '^2026-07-11 '
+ 2026-07-11 saturday time-after-pentecost 6 example-local-patron class-3 white +pius-i
+
+A MOVABLE one -- the capability the Date_spec work existed to unlock. "The
+first Sunday of October" is the shape a patronal or dedication feast usually
+takes, and it lands on a different civil date every year:
+
+ $ for y in 2026 2027 2028; do colitur day $y --overlay fixtures/overlay-example-diocesan.sexp | grep 'example-dedication'; done
+ 2026-10-04 sunday time-after-pentecost 19 example-dedication class-1 white +ef-time-after-pentecost-sunday-19
+ 2027-10-03 sunday time-after-pentecost 20 example-dedication class-1 white +ef-time-after-pentecost-sunday-20
+ 2028-10-01 sunday time-after-pentecost 17 example-dedication class-1 white +ef-time-after-pentecost-sunday-17
+
+The shipped calendar is untouched without the flag -- the same date, no local
+feast, the ordinary Sunday restored:
+
+ $ colitur day 2026 | grep '^2026-10-04 '
+ 2026-10-04 sunday time-after-pentecost 19 ef-time-after-pentecost-sunday-19 class-2 green
+
+And the shipped overlay's own entries survive alongside the user's, which is
+what "on top of, not instead of" means in practice:
+
+ $ colitur day 2024 --overlay fixtures/overlay-example-diocesan.sexp | grep -c 'rogation-wednesday'
+ 1
+
+An unreadable overlay is fatal, not a warning: a calendar that failed to load
+is not something to carry on past.
+
+ $ colitur day 2026 --overlay /nonexistent/diocese.sexp
+ colitur: failed to load /nonexistent/diocese.sexp: /nonexistent/diocese.sexp: No such file or directory
+ [2]
+
+--overlay is refused on the commands it could not affect, rather than accepted
+and silently ignored. `easter` reads no calendar data at all, and `temporal`
+runs the temporal cycle before any sanctoral layer exists:
+
+ $ colitur easter 2026 --overlay fixtures/overlay-example-diocesan.sexp
+ colitur: --overlay has no effect on `easter` (it reads no sanctoral data); refusing rather than ignoring it
+ [2]
+
+ $ colitur temporal 2026 --overlay fixtures/overlay-example-diocesan.sexp
+ colitur: --overlay has no effect on `temporal` (it reads no sanctoral data); refusing rather than ignoring it
+ [2]
+
+A flag needing a value, given none:
+
+ $ colitur day 2026 --overlay
+ colitur: --overlay needs a file path
+ colitur: usage: colitur easter <year> | colitur temporal <year> | colitur day <year> | colitur readings <year> (try: colitur --help)
+ [2]
+
+An unknown option is rejected rather than treated as a positional word:
+
+ $ colitur day 2026 --diocese
+ colitur: unknown option --diocese
+ colitur: usage: colitur easter <year> | colitur temporal <year> | colitur day <year> | colitur readings <year> (try: colitur --help)
+ [2]