This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
434
unikernel/duniverse/base/test/test_map.ml
Normal file
434
unikernel/duniverse/base/test/test_map.ml
Normal file
|
|
@ -0,0 +1,434 @@
|
|||
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)) |}]
|
||||
;;
|
||||
Loading…
Add table
Add a link
Reference in a new issue