diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-14 16:52:29 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-14 16:52:29 +0200 |
| commit | 2c0187f42cc45864932aba2529f876be86ddba39 (patch) | |
| tree | 4f13748309da87763c97a313fa3050c5f0fd63b3 /test | |
| parent | bca1a206589bc41bbcb367a7ae9b217c02f0e892 (diff) | |
| download | colitur-2c0187f42cc45864932aba2529f876be86ddba39.tar.gz colitur-2c0187f42cc45864932aba2529f876be86ddba39.zip | |
kernel(lectionary): fix round 1 -- load never raises
Sexplib.Sexp.load_sexp raises bare Failure for several malformed inputs
(unterminated list/string, empty file, more than one sexp) rather than
Sexplib.Sexp.Parse_error, so those cases escaped Lectionary.load as an
uncaught exception -- breaking the .mli's own promise and the kernel's
never-raises-on-fallible-construction constraint. Mirrors the catch-all
already present in Layer.load and Overlay.load, plus a second catch-all
on the t_of_sexp branch for defence in depth.
Adds test_load_never_raises, covering all of the above plus a missing
file, using Filename.temp_file rather than a hardcoded path. Verified the
new test fails against the pre-fix load (uncaught Failure) and passes
against the fix.
Diffstat (limited to 'test')
| -rw-r--r-- | test/test_lectionary.ml | 27 |
1 files changed, 26 insertions, 1 deletions
diff --git a/test/test_lectionary.ml b/test/test_lectionary.ml index 45a01ab..fba890a 100644 --- a/test/test_lectionary.ml +++ b/test/test_lectionary.ml @@ -53,8 +53,33 @@ let test_sexp_round_trip () = let l' = Lectionary.t_of_sexp (Lectionary.sexp_of_t l) in Alcotest.(check bool) "round trips" true (l = l') +let with_temp_file contents f = + let path = Filename.temp_file "lectionary_test" ".sexp" in + let oc = open_out path in + output_string oc contents; + close_out oc; + Fun.protect ~finally:(fun () -> Sys.remove path) (fun () -> f path) + +let load_is_error contents what = + with_temp_file contents (fun path -> + match Lectionary.load path with + | Error _ -> () + | Ok _ -> Alcotest.fail (what ^ ": expected Error, got Ok")) + +let test_load_never_raises () = + load_is_error "((ef-advent-sunday-1 (" "unterminated list"; + load_is_error "((ef-advent-sunday-1 ((part First) (reference \"x" "unterminated string"; + load_is_error "" "empty file"; + load_is_error "() ()" "more than one sexp"; + load_is_error "not-a-list" "wrong shape"; + load_is_error "((\"NOT A SLUG\" ()))" "invalid slug"; + match Lectionary.load "/nonexistent/path/lectionary.sexp" with + | Error _ -> () + | Ok _ -> Alcotest.fail "missing file: expected Error, got Ok" + let suite = [ ("find present", `Quick, test_find_present); ("find absent", `Quick, test_find_absent); ("duplicate slug rejected", `Quick, test_duplicate_slug_rejected); - ("sexp round-trip", `Quick, test_sexp_round_trip) ] + ("sexp round-trip", `Quick, test_sexp_round_trip); + ("load never raises", `Quick, test_load_never_raises) ] |
