open! Import open! Map let%expect_test "Finished_or_unfinished <-> Continue_or_stop" = (* These functions are implemented using [Caml.Obj.magic]. It is important to test them comprehensively. *) List.iter2_exn Continue_or_stop.all Finished_or_unfinished.all ~f:(fun c_or_s f_or_u -> print_s [%sexp (c_or_s : Continue_or_stop.t), (f_or_u : Finished_or_unfinished.t)]; require_equal [%here] (module Continue_or_stop) c_or_s (Finished_or_unfinished.to_continue_or_stop f_or_u); require_equal [%here] (module Finished_or_unfinished) f_or_u (Finished_or_unfinished.of_continue_or_stop c_or_s)); [%expect {| (Continue Finished) (Stop Unfinished) |}] ;; let%test _ = invariants (of_increasing_iterator_unchecked (module Int) ~len:20 ~f:(fun x -> x, x)) ;; let%test _ = invariants (Poly.of_increasing_iterator_unchecked ~len:20 ~f:(fun x -> x, x)) let add12 t = add_exn t ~key:1 ~data:2 type int_map = int Map.M(Int).t [@@deriving compare, hash, sexp] let%expect_test "[add_exn] success" = print_s [%sexp (add12 (empty (module Int)) : int_map)]; [%expect {| ((1 2)) |}] ;; let%expect_test "[add_exn] failure" = show_raise (fun () -> add12 (add12 (empty (module Int)))); [%expect {| (raised ("[Map.add_exn] got key already present" (key 1))) |}] ;; let%expect_test "[add] success" = print_s [%sexp (add (empty (module Int)) ~key:1 ~data:2 : int_map Or_duplicate.t)]; [%expect {| (Ok ((1 2))) |}] ;; let%expect_test "[add] duplicate" = print_s [%sexp (add (add12 (empty (module Int))) ~key:1 ~data:2 : int_map Or_duplicate.t)]; [%expect {| Duplicate |}] ;; let%expect_test "[Map.of_alist_multi] preserves value ordering" = print_s [%sexp (Map.of_alist_multi (module String) [ "a", 1; "a", 2; "b", 1; "b", 3 ] : int list Map.M(String).t)]; [%expect {| ((a (1 2)) (b (1 3))) |}] ;; let%expect_test "find_exn" = let map = Map.of_alist_exn (module String) [ "one", 1; "two", 2; "three", 3 ] in let test_success key = require_does_not_raise [%here] (fun () -> print_s [%sexp (Map.find_exn map key : int)]) in test_success "one"; [%expect {| 1 |}]; test_success "two"; [%expect {| 2 |}]; test_success "three"; [%expect {| 3 |}]; let test_failure key = require_does_raise [%here] (fun () -> Map.find_exn map key) in test_failure "zero"; [%expect {| (Not_found_s ("Map.find_exn: not found" zero)) |}]; test_failure "four"; [%expect {| (Not_found_s ("Map.find_exn: not found" four)) |}] ;; let%expect_test "[t_of_sexp] error on duplicate" = let sexp = Sexplib.Sexp.of_string "((0 a)(1 b)(2 c)(1 d))" in (match [%of_sexp: string Map.M(String).t] sexp with | t -> print_cr [%here] [%message "did not raise" (t : string Map.M(String).t)] | exception (Sexp.Of_sexp_error _ as exn) -> print_s (sexp_of_exn exn) | exception exn -> print_cr [%here] [%message "wrong kind of exception" (exn : exn)]); [%expect {| (Of_sexp_error "Map.t_of_sexp_direct: duplicate key" (invalid_sexp 1)) |}] ;; let%expect_test "combine_errors" = let test list = let input = list |> List.map ~f:(Result.map_error ~f:Error.of_string) |> List.mapi ~f:(fun k x -> Int.succ k, x) |> Map.of_alist_exn (module Int) in let output = Map.combine_errors input in print_s [%sexp (output : string Map.M(Int).t Or_error.t)] in (* empty *) test []; [%expect {| (Ok ()) |}]; (* singletons *) test [ Ok "one" ]; test [ Error "one" ]; [%expect {| (Ok ((1 one))) (Error ((1 one))) |}]; (* multiple ok *) test [ Ok "one"; Ok "two"; Ok "three" ]; [%expect {| (Ok ( (1 one) (2 two) (3 three))) |}]; (* multiple errors *) test [ Error "one"; Error "two"; Error "three" ]; [%expect {| (Error ( (1 one) (2 two) (3 three))) |}]; (* one error among oks *) test [ Error "one"; Ok "two"; Ok "three" ]; test [ Ok "one"; Error "two"; Ok "three" ]; test [ Ok "one"; Ok "two"; Error "three" ]; [%expect {| (Error ((1 one))) (Error ((2 two))) (Error ((3 three))) |}]; (* one ok among errors *) test [ Ok "one"; Error "two"; Error "three" ]; test [ Error "one"; Ok "two"; Error "three" ]; test [ Error "one"; Error "two"; Ok "three" ]; [%expect {| (Error ( (2 two) (3 three))) (Error ( (1 one) (3 three))) (Error ( (1 one) (2 two))) |}] ;; let%test_module "Poly" = (module struct let%test _ = length Poly.empty = 0 let%test _ = let a = Poly.of_alist_exn [] in Poly.equal Base.Poly.equal a Poly.empty ;; let%test _ = let a = Poly.of_alist_exn [ "a", 1 ] in let b = Poly.of_alist_exn [ 1, "b" ] in length a = length b ;; end) ;; let%test_module "[symmetric_diff]" = (module struct let%expect_test "examples" = let test alist1 alist2 = Map.symmetric_diff ~data_equal:Int.equal (Map.of_alist_exn (module String) alist1) (Map.of_alist_exn (module String) alist2) |> Sequence.to_list |> [%sexp_of: (string, int) Symmetric_diff_element.t list] |> print_s in test [] []; [%expect {| () |}]; test [ "one", 1 ] []; [%expect {| ((one (Left 1))) |}]; test [] [ "two", 2 ]; [%expect {| ((two (Right 2))) |}]; test [ "one", 1; "two", 2 ] [ "one", 1; "two", 2 ]; [%expect {| () |}]; test [ "one", 1; "two", 2 ] [ "one", 1; "two", 3 ]; [%expect {| ((two (Unequal (2 3)))) |}] ;; module String_to_int_map = struct type t = int Map.M(String).t [@@deriving equal, sexp_of] open Base_quickcheck let quickcheck_generator = Generator.map_t_m (module String) Generator.string Generator.int ;; let quickcheck_observer = Observer.map_t Observer.string Observer.int let quickcheck_shrinker = Shrinker.map_t Shrinker.string Shrinker.int end let apply_diff_left_to_right map (key, elt) = match elt with | `Right data | `Unequal (_, data) -> Map.set map ~key ~data | `Left _ -> Map.remove map key ;; let apply_diff_right_to_left map (key, elt) = match elt with | `Left data | `Unequal (data, _) -> Map.set map ~key ~data | `Right _ -> Map.remove map key ;; (* This is a deterministic benchmark rather than a test, measuring the number of comparisons made by fold_symmetric_diff. *) let%expect_test "number of key comparisons" = let count = ref 0 in let measure_comparisons f = let c = !count in f (); !count - c in let module Key = struct module T = struct type t = int [@@deriving sexp_of] let compare x y = Int.incr count; compare_int x y ;; end include T include Comparator.Make (T) end in let (_m : unit Map.M(Key).t), map_pairs = List.fold (List.init 1000 ~f:Fn.id) ~init:(Map.empty (module Key), []) ~f:(fun (m, acc) i -> let m' = Map.add_exn m ~key:i ~data:() in m', (m, m') :: acc) in print_s [%sexp (!count : int)]; [%expect {| 9_966 |}]; count := 0; let diffs = ref 0 in let counts = List.map map_pairs ~f:(fun (m, m') -> measure_comparisons (fun () -> diffs := !diffs + Map.fold_symmetric_diff ~init:0 ~f:(fun n _ -> n + 1) ~data_equal:(fun () () -> true) (m : unit Map.M(Key).t) m')) in let worst_counts = List.sort counts ~compare:[%compare: int] |> List.rev |> fun l -> List.take l 20 in (* The smaller these numbers are, the better. *) print_s [%sexp (!diffs : int), (!count : int)]; [%expect {| (1_000 10_955) |}]; print_s [%sexp (worst_counts : int list)]; [%expect {| (12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12) |}] ;; let%expect_test "reconstructing in both directions" = let test (map1, map2) = let diff = Map.symmetric_diff map1 map2 ~data_equal:Int.equal in require_equal [%here] (module String_to_int_map) (Sequence.fold diff ~init:map1 ~f:apply_diff_left_to_right) map2; require_equal [%here] (module String_to_int_map) map1 (Sequence.fold diff ~init:map2 ~f:apply_diff_right_to_left) in Base_quickcheck.Test.run_exn ~f:test (module struct type t = String_to_int_map.t * String_to_int_map.t [@@deriving quickcheck, sexp_of] end) ;; let%expect_test "vs [fold_symmetric_diff]" = let test (map1, map2) = require_compare_equal [%here] (module struct type t = (string, int) Symmetric_diff_element.t list [@@deriving compare, sexp_of] end) (Map.symmetric_diff map1 map2 ~data_equal:Int.equal |> Sequence.fold ~init:[] ~f:(Fn.flip List.cons)) (Map.fold_symmetric_diff map1 map2 ~data_equal:Int.equal ~init:[] ~f:(Fn.flip List.cons)) in Base_quickcheck.Test.run_exn ~f:test (module struct type t = String_to_int_map.t * String_to_int_map.t [@@deriving quickcheck, sexp_of] end) ;; end) ;; let%test_module "of_alist_multi key equality" = (module struct module Key = struct module T = struct type t = string * int [@@deriving sexp_of] let compare = [%compare: string * _] end include T include Comparator.Make (T) end let alist = [ ("a", 1), 1; ("a", 2), 3; ("b", 0), 0; ("a", 3), 2 ] let%expect_test "of_alist_multi chooses the first key" = print_s [%sexp (Map.of_alist_multi (module Key) alist : int list Map.M(Key).t)]; [%expect {| (((a 1) (1 3 2)) ((b 0) (0))) |}] ;; let%test_unit "of_{alist,sequence}_multi have the same behaviour" = [%test_result: int list Map.M(Key).t] ~expect:(Map.of_alist_multi (module Key) alist) (Map.of_sequence_multi (module Key) (Sequence.of_list alist)) ;; end) ;; let%expect_test "remove returns the same object if there's nothing to do" = let map1 = Map.of_alist_exn (module Int) [ 1, "one"; 3, "three" ] in let map2 = Map.remove map1 2 in require [%here] (phys_equal map1 map2) ;; let%expect_test "[map_keys]" = let test m c ~f = print_s [%sexp (Map.map_keys c ~f m : [ `Duplicate_key of string | `Ok of string Map.M(String).t ])] in let map = Map.of_alist_exn (module Int) [ 1, "one"; 2, "two"; 3, "three" ] in test map (module String) ~f:Int.to_string; [%expect {| (Ok ( (1 one) (2 two) (3 three))) |}]; test map (module String) ~f:(fun x -> Int.to_string (x / 2)); [%expect {| (Duplicate_key 1) |}] ;; let%expect_test "[fold_until]" = let test t = print_s [%sexp (Map.fold_until t ~init:0 ~f:(fun ~key ~data acc -> if key > 2 then Stop data else Continue (acc + key)) ~finish:Int.to_string : string)] in let map = Map.of_alist_exn (module Int) [ 1, "one"; 2, "two"; 3, "three" ] in test map; [%expect {| three |}]; let map = Map.of_alist_exn (module Int) [ -1, "minus-one"; 1, "one"; 2, "two" ] in test map; [%expect {| 2 |}] ;; let%expect_test "[sum]" = let test t = print_s [%sexp (Map.sum (module Int) t ~f:(( * ) 2) : int)] in let map = Map.of_alist_exn (module String) [ "A", 1; "B", 2; "C", 3 ] in test map; [%expect {| 12 |}] ;; let%expect_test "[sumi]" = let test t = print_s [%sexp (Map.sumi (module Int) t ~f:(fun ~key ~data -> key * data) : int)] in let map = Map.of_alist_exn (module Int) [ 1, 1; 2, 2; 3, 3 ] in test map; [%expect {| 14 |}] ;; let%expect_test "[merge_disjoint_exn] success" = let map1 = Map.of_alist_exn (module Int) [ 1, "one"; 2, "two" ] in let map2 = Map.of_alist_exn (module Int) [ 3, "three" ] in print_s [%sexp (Map.merge_disjoint_exn map1 map2 : string Map.M(Int).t)]; [%expect {| ((1 one) (2 two) (3 three)) |}] ;; let%expect_test "[merge_disjoint_exn] failure" = let map1 = Map.of_alist_exn (module Int) [ 1, "one"; 2, "two" ] in let map2 = Map.of_alist_exn (module Int) [ 2, "two"; 3, "three" ] in show_raise (fun () -> Map.merge_disjoint_exn map1 map2); [%expect {| (raised ("Map.merge_disjoint_exn: duplicate key" 2)) |}] ;;