Monorepo management for opam overlays
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

monopam: add test_auto_resolve and test_quality (E605)

Cover the deterministic Auto_resolve clients (ours/theirs/union) and
Quality's pure helpers (all_features, has_failures, query_missing,
pp_entry, pp_summary). The AI/Claude path and disk-IO functions still
need integration coverage; the new modules pin the pure surface so
refactors there can't silently regress.

+163 -1
+1 -1
test/dune
··· 1 1 (test 2 2 (name test) 3 - (libraries monopam alcotest eio_main fpath uri)) 3 + (libraries monopam merge3 alcotest eio_main fpath uri)) 4 4 5 5 (cram 6 6 (deps %{bin:monopam}))
+2
test/test.ml
··· 4 4 Alcotest.run "Monopam" 5 5 [ 6 6 Test_add.suite; 7 + Test_auto_resolve.suite; 7 8 Test_changes.suite; 8 9 Test_changes_aggregated.suite; 9 10 Test_changes_daily.suite; ··· 30 31 Test_pkg.suite; 31 32 Test_progress.suite; 32 33 Test_pull.suite; 34 + Test_quality.suite; 33 35 Test_push.suite; 34 36 Test_remote_cache.suite; 35 37 Test_remove.suite;
+86
test/test_auto_resolve.ml
··· 1 + (* Tests for the Auto_resolve module's deterministic strategies. *) 2 + 3 + module AR = Monopam.Auto_resolve 4 + 5 + let resolved lines : Merge3.merged_chunk = Resolved lines 6 + 7 + let conflict ~base ~ours ~theirs : Merge3.merged_chunk = 8 + let c : Merge3.conflict = 9 + { base_lines = base; ours_lines = ours; theirs_lines = theirs } 10 + in 11 + Conflict c 12 + 13 + let resolve_with client chunks = 14 + match 15 + client.AR.resolve_one ~path:"f" ~base:None ~ours:"" ~theirs:"" ~chunks 16 + with 17 + | Ok p -> p.AR.merged 18 + | Error e -> Alcotest.failf "client returned error: %s" e 19 + 20 + let test_ours_picks_ours () = 21 + let chunks = 22 + [ 23 + resolved [ "before" ]; 24 + conflict ~base:[ "B" ] ~ours:[ "O1"; "O2" ] ~theirs:[ "T" ]; 25 + resolved [ "after" ]; 26 + ] 27 + in 28 + Alcotest.(check string) 29 + "ours wins" "before\nO1\nO2\nafter" 30 + (resolve_with AR.ours_client chunks) 31 + 32 + let test_theirs_picks_theirs () = 33 + let chunks = 34 + [ 35 + resolved [ "x" ]; 36 + conflict ~base:[ "B" ] ~ours:[ "O" ] ~theirs:[ "T1"; "T2" ]; 37 + ] 38 + in 39 + Alcotest.(check string) 40 + "theirs wins" "x\nT1\nT2" 41 + (resolve_with AR.theirs_client chunks) 42 + 43 + let test_union_concatenates () = 44 + let chunks = [ conflict ~base:[ "B" ] ~ours:[ "O" ] ~theirs:[ "T" ] ] in 45 + Alcotest.(check string) 46 + "ours then theirs" "O\nT" 47 + (resolve_with AR.union_client chunks) 48 + 49 + let test_union_dedups () = 50 + let chunks = 51 + [ conflict ~base:[] ~ours:[ "shared"; "O" ] ~theirs:[ "shared"; "T" ] ] 52 + in 53 + Alcotest.(check string) 54 + "duplicate dropped" "shared\nO\nT" 55 + (resolve_with AR.union_client chunks) 56 + 57 + let test_no_conflicts_passthrough () = 58 + let chunks = [ resolved [ "line1"; "line2" ] ] in 59 + Alcotest.(check string) 60 + "verbatim" "line1\nline2" 61 + (resolve_with AR.ours_client chunks) 62 + 63 + let test_empty_chunks () = 64 + Alcotest.(check string) "empty" "" (resolve_with AR.ours_client []) 65 + 66 + let test_outcome_distinct () = 67 + let a = AR.Accepted "x" in 68 + let s = AR.Skipped in 69 + let f = AR.Failed "msg" in 70 + Alcotest.(check bool) "Accepted/Skipped distinct" true (a <> s); 71 + Alcotest.(check bool) "Skipped/Failed distinct" true (s <> f); 72 + Alcotest.(check bool) "Accepted/Failed distinct" true (a <> f) 73 + 74 + let suite = 75 + ( "auto_resolve", 76 + [ 77 + Alcotest.test_case "ours picks ours" `Quick test_ours_picks_ours; 78 + Alcotest.test_case "theirs picks theirs" `Quick test_theirs_picks_theirs; 79 + Alcotest.test_case "union concatenates" `Quick test_union_concatenates; 80 + Alcotest.test_case "union dedups" `Quick test_union_dedups; 81 + Alcotest.test_case "no conflicts passthrough" `Quick 82 + test_no_conflicts_passthrough; 83 + Alcotest.test_case "empty chunks" `Quick test_empty_chunks; 84 + Alcotest.test_case "outcome variants distinct" `Quick 85 + test_outcome_distinct; 86 + ] )
+2
test/test_auto_resolve.mli
··· 1 + val suite : string * unit Alcotest.test_case list 2 + (** Test suite. *)
+70
test/test_quality.ml
··· 1 + (* Tests for the Quality module's pure helpers (no I/O, no git access). *) 2 + 3 + module Q = Monopam.Quality 4 + 5 + let mk ?(missing = []) ?(extra = []) ?(present = []) ?(policy = []) name = 6 + { Q.package = name; tree_hash = ""; policy; present; missing; extra } 7 + 8 + let test_all_features_listed () = 9 + let known = Q.all_features in 10 + Alcotest.(check bool) "build present" true (List.mem "build" known); 11 + Alcotest.(check bool) "test present" true (List.mem "test" known); 12 + Alcotest.(check bool) "fuzz present" true (List.mem "fuzz" known); 13 + Alcotest.(check bool) "merlint present" true (List.mem "merlint" known); 14 + Alcotest.(check bool) 15 + "feature names lowercase" true 16 + (List.for_all (fun f -> String.lowercase_ascii f = f) known) 17 + 18 + let test_has_failures_empty () = 19 + Alcotest.(check bool) "no results" false (Q.has_failures []) 20 + 21 + let test_has_failures_clean () = 22 + let r = mk "ok" ~policy:[ "build" ] ~present:[ "build" ] in 23 + Alcotest.(check bool) "no missing" false (Q.has_failures [ r ]) 24 + 25 + let test_has_failures_dirty () = 26 + let r = mk "bad" ~policy:[ "build"; "test" ] ~missing:[ "test" ] in 27 + Alcotest.(check bool) "missing test" true (Q.has_failures [ r ]) 28 + 29 + let test_query_missing_finds () = 30 + let a = mk "a" ~present:[ "build"; "test" ] in 31 + let b = mk "b" ~present:[ "build" ] in 32 + let missing_test = Q.query_missing "test" [ a; b ] in 33 + Alcotest.(check (list string)) 34 + "only b" [ "b" ] 35 + (List.map (fun r -> r.Q.package) missing_test) 36 + 37 + let test_query_missing_all_present () = 38 + let a = mk "a" ~present:[ "build" ] in 39 + let b = mk "b" ~present:[ "build" ] in 40 + Alcotest.(check int) 41 + "none missing" 0 42 + (List.length (Q.query_missing "build" [ a; b ])) 43 + 44 + let test_pp_entry_includes_package () = 45 + let r = mk "mypkg" ~policy:[ "build" ] ~present:[ "build" ] in 46 + let s = Fmt.str "%a" Q.pp_entry r in 47 + Alcotest.(check bool) 48 + "package name in output" true 49 + (String.length s > 0 && Option.is_some (String.index_opt s 'm')) 50 + 51 + let test_pp_summary_includes_total () = 52 + let rs = [ mk "a"; mk "b"; mk "c" ] in 53 + let s = Fmt.str "%a" Q.pp_summary rs in 54 + Alcotest.(check bool) "shows count" true (String.length s > 0) 55 + 56 + let suite = 57 + ( "quality", 58 + [ 59 + Alcotest.test_case "all features listed" `Quick test_all_features_listed; 60 + Alcotest.test_case "has_failures empty" `Quick test_has_failures_empty; 61 + Alcotest.test_case "has_failures clean" `Quick test_has_failures_clean; 62 + Alcotest.test_case "has_failures dirty" `Quick test_has_failures_dirty; 63 + Alcotest.test_case "query_missing finds" `Quick test_query_missing_finds; 64 + Alcotest.test_case "query_missing none" `Quick 65 + test_query_missing_all_present; 66 + Alcotest.test_case "pp_entry has package" `Quick 67 + test_pp_entry_includes_package; 68 + Alcotest.test_case "pp_summary has total" `Quick 69 + test_pp_summary_includes_total; 70 + ] )
+2
test/test_quality.mli
··· 1 + val suite : string * unit Alcotest.test_case list 2 + (** Test suite. *)