aboutsummaryrefslogtreecommitdiff
path: root/test/test_config.ml
diff options
context:
space:
mode:
authorLukasz Kasprzak <lukas@labunix.xyz>2026-08-19 13:38:54 +0200
committerLukasz Kasprzak <lukas@labunix.xyz>2026-08-19 13:38:54 +0200
commitb26089630a61a54060c86ec26be6dc4fe5418b12 (patch)
treecdeb6e17cfcf0a8ecb0bfb59bb2224e04b9a5966 /test/test_config.ml
parent45bcbde502e07ad73b96039fcbb62471a3c94781 (diff)
downloadcolitur-b26089630a61a54060c86ec26be6dc4fe5418b12.tar.gz
colitur-b26089630a61a54060c86ec26be6dc4fe5418b12.zip
feat(naming): the config file
Owns precedence and provenance and nothing else, and never reads the filesystem, so it is as testable as the language table. resolve returns the value AND its source, because a setting that silently comes from a file the user forgot about is worse than no setting at all -- config --show can then say where each effective value came from. overlay accumulates rather than last-wins: a user has more than one. An unknown key is reported, never fatal. A config written for a newer colitur must still work on an older one, but silently dropping a line the user wrote is how a typo becomes invisible.
Diffstat (limited to 'test/test_config.ml')
-rw-r--r--test/test_config.ml62
1 files changed, 62 insertions, 0 deletions
diff --git a/test/test_config.ml b/test/test_config.ml
new file mode 100644
index 0000000..9100380
--- /dev/null
+++ b/test/test_config.ml
@@ -0,0 +1,62 @@
+module C = Colitur_naming.Config
+
+let ok = function Ok x -> x | Error e -> Alcotest.failf "parse: %s" e
+
+let sample =
+ "[defaults]\n\
+ lang = pl\n\
+ overlay = ~/a.ini\n\
+ overlay = ~/b.ini\n\
+ template = ~/my-ordo.tex\n\
+ format = json\n"
+
+let test_reads_defaults () =
+ let c = ok (C.of_string sample) in
+ Alcotest.(check (option string)) "lang" (Some "pl") (C.lang c);
+ Alcotest.(check (option string)) "template" (Some "~/my-ordo.tex") (C.template c);
+ Alcotest.(check (option string)) "format" (Some "json") (C.format c)
+
+(* Repeated keys accumulate for overlay -- a user has more than one. The INI
+ reader keeps every line, so this asserts we do not silently take the last. *)
+let test_overlays_accumulate () =
+ let c = ok (C.of_string sample) in
+ Alcotest.(check (list string)) "both overlays" [ "~/a.ini"; "~/b.ini" ] (C.overlays c)
+
+let test_empty_config_is_all_none () =
+ Alcotest.(check (option string)) "lang" None (C.lang C.empty);
+ Alcotest.(check (list string)) "overlays" [] (C.overlays C.empty)
+
+(* THE precedence rule: flag > config > default, and the SOURCE is reported,
+ because a setting that silently comes from a file the user forgot about is
+ worse than no setting at all. *)
+let test_precedence_and_provenance () =
+ let check ~flag ~config ~default (ev, es) =
+ let v, s = C.resolve ~flag ~config ~default in
+ Alcotest.(check string) "value" ev v;
+ Alcotest.(check string) "source" es s
+ in
+ check ~flag:(Some "en") ~config:(Some "pl") ~default:"la" ("en", "flag");
+ check ~flag:None ~config:(Some "pl") ~default:"la" ("pl", "config");
+ check ~flag:None ~config:None ~default:"la" ("la", "default")
+
+let test_malformed_is_error_not_crash () =
+ match C.of_string "[defaults\nbroken" with
+ | Error _ -> ()
+ | Ok _ -> Alcotest.fail "a malformed config must be an Error, never accepted"
+
+(* An unknown key is a WARNING case, not a hard error: a config written for a
+ newer colitur must still work on an older one. But it must be reportable, so
+ it is not silently dropped either. *)
+let test_unknown_key_is_reported_not_fatal () =
+ match C.of_string "[defaults]\nlang = la\nnonsense = 1\n" with
+ | Error _ -> Alcotest.fail "an unknown key must not be fatal"
+ | Ok c -> Alcotest.(check (option string)) "known key still read" (Some "la") (C.lang c)
+
+let suite =
+ ( "Config",
+ [ Alcotest.test_case "reads defaults" `Quick test_reads_defaults;
+ Alcotest.test_case "overlays accumulate" `Quick test_overlays_accumulate;
+ Alcotest.test_case "empty is all none" `Quick test_empty_config_is_all_none;
+ Alcotest.test_case "precedence and provenance" `Quick test_precedence_and_provenance;
+ Alcotest.test_case "malformed is error" `Quick test_malformed_is_error_not_crash;
+ Alcotest.test_case "unknown key not fatal" `Quick test_unknown_key_is_reported_not_fatal ] )