<feed xmlns='http://www.w3.org/2005/Atom'>
<title>colitur.git/test/test_overlay.ml, branch v0.1.0</title>
<subtitle>deterministic OCaml engine to compute and validate liturgical calendars for multiple rites, template-driven output to year 9999</subtitle>
<id>https://git.labunix.xyz/colitur.git/atom?h=v0.1.0</id>
<link rel='self' href='https://git.labunix.xyz/colitur.git/atom?h=v0.1.0'/>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/'/>
<updated>2026-08-11T14:21:46Z</updated>
<entry>
<title>kernel: loaders never escape as an exception, date-spec validates on load</title>
<updated>2026-08-11T14:21:46Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-11T14:21:46Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=745ec8f8edb32ee7ef0a8c12ab84833216296f73'/>
<id>urn:sha1:745ec8f8edb32ee7ef0a8c12ab84833216296f73</id>
<content type='text'>
Layer.load narrowed its catch to Sexplib0.Sexp_conv_error.Of_sexp_error,
but rank_of_sexp is caller-supplied and may raise anything -- e.g. a
hand-written rank parser that calls invalid_arg. Overlay.load already
catches every exception from the equivalent call; mirror that here so
layer.mli's "never as an exception" promise actually holds.

Date_spec.t derived its sexp converters with plain ppx_sexp_conv, unlike
Slug and Lang, which hand-write validating parsers specifically so
malformed data is rejected at load. (Fixed (month 13) (day 40)) used to
deserialise cleanly into a spec that simply never resolves -- a saint
quietly vanishing with no diagnostic. t_of_sexp now re-runs the value
through the existing fixed validator, the same shape Slug and Lang
already use.

Covering tests: a Layer.load case where rank_of_sexp raises
Invalid_argument instead of Of_sexp_error (would have escaped
uncaught before this fix); two Date_spec.t_of_sexp cases (month 13,
31 April) that must raise Of_sexp_error rather than silently
constructing an unresolvable spec.
</content>
</entry>
<entry>
<title>test(overlay): close review gaps in the merge-algebra test suite</title>
<updated>2026-08-11T10:54:56Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-11T10:54:56Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=2747e01ca00e3be9b8b94c4eddc2c9a17daedce7'/>
<id>urn:sha1:2747e01ca00e3be9b8b94c4eddc2c9a17daedce7</id>
<content type='text'>
Five review findings, all in the test suite the task designates as the
algebra's specification:

- test_diagnostics's headline assertion was vacuous: it checked slug
  presence after an add-over-existing, but hilary was already present
  before the Add ran, so a broken implementation that recorded the
  diagnostic and skipped applying the entry would still pass. Add now
  carries a rank that genuinely differs from base()'s default, and the
  assertion checks the field actually changed.
- Set_subject, Set_name, Remove_name, Set_citation and Remove_citation
  were implemented but never exercised. Added coverage for all five,
  including the case that matters most for Set_citation: setting a part
  that already exists must replace it, not append a duplicate.
- Replace had zero coverage. Added tests for both its existing-slug path
  (entry swapped, no diagnostic) and its absent-slug path (diagnostic
  recorded, entry still added).
- merge's diagnostic accumulation was untested; test_merge_order discarded
  the diagnostics it got back. Added a test asserting two overlays' each
  producing one diagnostic come back in application order.

Extended the cel/entry test helpers with optional subject/names/citations
so the new tests can build fixtures with those fields populated.
</content>
</entry>
<entry>
<title>kernel(overlay): ordered layer-merge algebra with diagnostics</title>
<updated>2026-08-11T10:37:22Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-11T10:37:22Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=3cb45720f5e2ba7bd8be9a5113d866be22ad07a8'/>
<id>urn:sha1:3cb45720f5e2ba7bd8be9a5113d866be22ad07a8</id>
<content type='text'>
add/suppress/replace/field-edit folded in order, last writer wins per field,
empty the identity. A directive naming an unknown slug, or adding one that
already exists, yields a diagnostic rather than silence or a hard failure:
overlays must survive a shifted base while still surfacing authoring errors.
</content>
</entry>
<entry>
<title>test(layer): cover load's failure modes and same-date index ordering</title>
<updated>2026-08-11T10:27:24Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-11T10:27:24Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=e58cf9920254d7312325cf382b5be24efc175749'/>
<id>urn:sha1:e58cf9920254d7312325cf382b5be24efc175749</id>
<content type='text'>
load previously had zero coverage despite being the module's only fallible-
I/O function and the one place the brief's literal code would have let an
exception escape on this sexplib version (Failure instead of Parse_error).
Add cases for a missing file, a malformed/unterminated sexp, an invalid slug
embedded in an otherwise well-formed layer, and a success round-trip.

Also add a same-date index case with three entries inserted out of slug
order, pinning that the by-date index accumulates rather than overwrites and
returns buckets in canonical order regardless of insertion order -- the
previous two-entry fixture only ever touched bucket sizes 0 and 1.
</content>
</entry>
<entry>
<title>kernel(layer): sanctoral layer with canonical order and date index</title>
<updated>2026-08-11T10:15:44Z</updated>
<author>
<name>Lukasz Kasprzak</name>
<email>lukas@labunix.xyz</email>
</author>
<published>2026-08-11T10:15:44Z</published>
<link rel='alternate' type='text/html' href='https://git.labunix.xyz/colitur.git/commit/?id=2e3697b5ce7338568a67531d07a5528f0de1da22'/>
<id>urn:sha1:2e3697b5ce7338568a67531d07a5528f0de1da22</id>
<content type='text'>
Entries sort by slug so equal layers serialise identically. The by-date index
is built once per layer rather than per year, since fixed dates are
year-independent; a full-domain sweep would otherwise rescan every entry for
every day. load turns parse and validation failures into result.
</content>
</entry>
</feed>
