aboutsummaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-11 11:25:56 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-11 11:25:56 +0200
commitca289b2f43a5b097c4ec20308c1661a0c404399c (patch)
tree09b34b4516ef299fcf6e3689cf7bcd69fa83c640 /test
parente444ae5b03a9113fc6b2fc3fa3e2fd6b71bf8d4b (diff)
downloadcolitur-ca289b2f43a5b097c4ec20308c1661a0c404399c.tar.gz
colitur-ca289b2f43a5b097c4ec20308c1661a0c404399c.zip
kernel: Slug and Lang validated private strings
Both parse through a smart constructor returning result, and both hand-write t_of_sexp so a malformed value in a data file is rejected at load rather than silently accepted -- deriving the converter would have bypassed validation.
Diffstat (limited to 'test')
-rw-r--r--test/test_colitur.ml4
-rw-r--r--test/test_slug.ml39
2 files changed, 42 insertions, 1 deletions
diff --git a/test/test_colitur.ml b/test/test_colitur.ml
index c6c5b91..3341c36 100644
--- a/test/test_colitur.ml
+++ b/test/test_colitur.ml
@@ -1,2 +1,4 @@
(* Aggregating test runner. Per-module suites live in test_<module>.ml. *)
-let () = Alcotest.run "colitur" [ Test_date.suite; Test_computus.suite; Test_colour.suite ]
+let () =
+ Alcotest.run "colitur"
+ [ Test_date.suite; Test_computus.suite; Test_colour.suite; Test_slug.suite ]
diff --git a/test/test_slug.ml b/test/test_slug.ml
new file mode 100644
index 0000000..af70e9a
--- /dev/null
+++ b/test/test_slug.ml
@@ -0,0 +1,39 @@
+module S = Colitur_kernel.Slug
+module L = Colitur_kernel.Lang
+
+let ok_slug s = match S.of_string s with
+ | Ok t -> t | Error e -> Alcotest.failf "slug %S: %s" s e
+
+let test_slug_accepts () =
+ Alcotest.(check string) "plain" "ef-advent-sunday-1" (S.to_string (ok_slug "ef-advent-sunday-1"));
+ Alcotest.(check string) "digits" "ef-lent-3-monday" (S.to_string (ok_slug "ef-lent-3-monday"))
+
+let test_slug_rejects () =
+ List.iter
+ (fun bad ->
+ Alcotest.(check bool) (Printf.sprintf "reject %S" bad) true (Result.is_error (S.of_string bad)))
+ [ ""; "Ef-Advent"; "ef advent"; "ef_advent"; "-leading"; "trailing-"; "ef/advent" ]
+
+let test_slug_sexp () =
+ let s = ok_slug "ef-easter-sunday" in
+ Alcotest.(check bool) "roundtrip" true (S.equal (S.t_of_sexp (S.sexp_of_t s)) s);
+ (* A malformed slug in a data file must be rejected, not silently accepted. *)
+ Alcotest.check_raises "bad slug in sexp"
+ (Sexplib0.Sexp_conv_error.Of_sexp_error
+ (Failure "slug \"Bad Slug\": only [a-z0-9-] allowed", Sexplib0.Sexp.Atom "Bad Slug"))
+ (fun () -> ignore (S.t_of_sexp (Sexplib0.Sexp.Atom "Bad Slug")))
+
+let test_lang () =
+ Alcotest.(check string) "la" "la" (L.to_string (match L.of_string "la" with
+ | Ok t -> t | Error e -> Alcotest.failf "%s" e));
+ List.iter
+ (fun bad ->
+ Alcotest.(check bool) (Printf.sprintf "reject %S" bad) true (Result.is_error (L.of_string bad)))
+ [ ""; "e"; "eng"; "EN"; "e1" ]
+
+let suite =
+ ( "Slug/Lang",
+ [ Alcotest.test_case "slug accepts" `Quick test_slug_accepts;
+ Alcotest.test_case "slug rejects" `Quick test_slug_rejects;
+ Alcotest.test_case "slug sexp validates" `Quick test_slug_sexp;
+ Alcotest.test_case "lang" `Quick test_lang ] )