diff options
| author | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-11 19:23:06 +0200 |
|---|---|---|
| committer | Lukasz Kasprzak <lukas@labunix.xyz> | 2026-08-11 19:23:06 +0200 |
| commit | 7e29712aadf2436b83de2d5e8d1f98b30d2f6d59 (patch) | |
| tree | 7d883df1b0a412164c49912c414b5fa50645a6d0 /test/test_precedence.ml | |
| parent | 19d5bbaab8fbf40f6fa6de8906169e3bb7144e1f (diff) | |
| download | colitur-7e29712aadf2436b83de2d5e8d1f98b30d2f6d59.tar.gz colitur-7e29712aadf2436b83de2d5e8d1f98b30d2f6d59.zip | |
test(precedence): strengthen accounting test, cover order and empty sanctoral
The accounting test only checked bucket lengths, which a mutant satisfies by
duplicating a candidate across two buckets while dropping another entirely.
Replace it with a sorted slug-set comparison (Alcotest.slist), which a
duplicate-or-missing slug both fail.
Add two cases the brief's three properties call for but nothing exercised:
input-order independence (permuting the sanctoral list must not change the
outcome) and a temporal-only day (empty sanctoral list), the case the
temporal/sanctoral split exists to make safe.
Diffstat (limited to 'test/test_precedence.ml')
| -rw-r--r-- | test/test_precedence.ml | 46 |
1 files changed, 39 insertions, 7 deletions
diff --git a/test/test_precedence.ml b/test/test_precedence.ml index 39be06c..369c490 100644 --- a/test/test_precedence.ml +++ b/test/test_precedence.ml @@ -56,15 +56,45 @@ let test_commemoration_only_never_observed () = Alcotest.(check (list string)) "suppressed commemorated" [ "suppressed" ] (List.map (fun (c, _) -> slug_of c) r.P.commemorations) -(* Anything the admit limit drops is recorded in `omitted`, never dropped silently. *) +(* Anything the admit limit drops is recorded in `omitted`, never dropped silently + -- and each input candidate lands in exactly one bucket, not zero or two. *) let test_nothing_silently_lost () = let r = P.resolve rules ctx ~temporal:(cand ~origin:P.Temporal ~rank:Hi "sunday") ~sanctoral:[ cand ~rank:Lo "a"; cand ~rank:Lo "b"; cand ~rank:Lo "c" ] in - Alcotest.(check int) "two admitted" 2 (List.length r.P.commemorations); - Alcotest.(check int) "one recorded as omitted" 1 (List.length r.P.omitted); - let total = 1 + List.length r.P.commemorations + List.length r.P.deferred - + List.length r.P.omitted in - Alcotest.(check int) "every candidate accounted for" 4 total + let bucketed = + (slug_of r.P.observed + :: List.map (fun (c, _) -> slug_of c) r.P.commemorations) + @ List.map slug_of r.P.deferred + @ List.map (fun (c, _) -> slug_of c) r.P.omitted + in + Alcotest.(check (slist string compare)) "every candidate appears exactly once" + [ "a"; "b"; "c"; "sunday" ] bucketed; + Alcotest.(check int) "two admitted" 2 (List.length r.P.commemorations) + +(* The result must not depend on the order sanctoral candidates arrive in; + ties break on slug, not on list position. *) +let test_order_independent () = + let a = cand ~rank:Lo "a" and b = cand ~rank:Lo "b" and c = cand ~rank:Lo "c" in + let t = cand ~origin:P.Temporal ~rank:Hi "sunday" in + let observed_for sanctoral = slug_of (P.resolve rules ctx ~temporal:t ~sanctoral).P.observed in + let comms_for sanctoral = + List.map (fun (x, _) -> slug_of x) (P.resolve rules ctx ~temporal:t ~sanctoral).P.commemorations + in + List.iter + (fun perm -> + Alcotest.(check string) "same observed" (observed_for [ a; b; c ]) (observed_for perm); + Alcotest.(check (list string)) "same commemorations" (comms_for [ a; b; c ]) (comms_for perm)) + [ [ c; b; a ]; [ b; a; c ]; [ c; a; b ] ] + +(* The case the "pass temporal separately" design exists to make safe: a day + with no sanctoral candidate at all. *) +let test_temporal_only_day () = + let r = P.resolve rules ctx ~temporal:(cand ~origin:P.Temporal ~rank:Lo "feria") + ~sanctoral:[] in + Alcotest.(check string) "feria observed" "feria" (slug_of r.P.observed); + Alcotest.(check int) "no commemorations" 0 (List.length r.P.commemorations); + Alcotest.(check int) "nothing deferred" 0 (List.length r.P.deferred); + Alcotest.(check int) "nothing omitted" 0 (List.length r.P.omitted) let suite = ( "Precedence", @@ -73,4 +103,6 @@ let suite = Alcotest.test_case "loser dispositions" `Quick test_loser_dispositions; Alcotest.test_case "commemoration-only never observed" `Quick test_commemoration_only_never_observed; - Alcotest.test_case "nothing silently lost" `Quick test_nothing_silently_lost ] ) + Alcotest.test_case "nothing silently lost" `Quick test_nothing_silently_lost; + Alcotest.test_case "order independent" `Quick test_order_independent; + Alcotest.test_case "temporal-only day" `Quick test_temporal_only_day ] ) |
