open! Base open Expect_test_helpers_base type int_hashtbl = int Hashtbl.M(Int).t [@@deriving sexp] let%test "Hashtbl.merge succeeds with first-class-module interface" = let t1 = Hashtbl.create (module Int) in let t2 = Hashtbl.create (module Int) in let result = Hashtbl.merge t1 t2 ~f:(fun ~key:_ -> function | `Left x -> x | `Right x -> x | `Both _ -> assert false) |> Hashtbl.to_alist in List.equal Poly.equal result [] ;; let%test_module _ = (module Hashtbl_tests.Make (struct include Hashtbl let create_poly ?size () = Poly.create ?size () let of_alist_poly_exn l = Poly.of_alist_exn l let of_alist_poly_or_error l = Poly.of_alist_or_error l end)) ;; let%expect_test "Hashtbl.find_exn" = let table = Hashtbl.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 (Hashtbl.find_exn table 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 () -> Hashtbl.find_exn table key) in test_failure "zero"; [%expect {| (Not_found_s ("Hashtbl.find_exn: not found" zero)) |}]; test_failure "four"; [%expect {| (Not_found_s ("Hashtbl.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 Hashtbl.M(String).t] sexp with | t -> print_cr [%here] [%message "did not raise" (t : string Hashtbl.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 "Hashtbl.t_of_sexp: duplicate key" (invalid_sexp 1)) |}] ;; let%expect_test "[choose], [choose_exn], [choose_randomly], [choose_randomly_exn]" = let test ?size l = let t = l |> List.map ~f:(fun i -> i, i) |> Hashtbl.of_alist_exn ?size (module Int) in print_s [%message "" ~input:(t : int_hashtbl) ~choose:(Hashtbl.choose t : (_ * _) option) ~choose_exn: (Or_error.try_with (fun () -> Hashtbl.choose_exn t) : (_ * _) Or_error.t) ~choose_randomly:(Hashtbl.choose_randomly t : (_ * _) option) ~choose_randomly_exn: (Or_error.try_with (fun () -> Hashtbl.choose_randomly_exn t) : (_ * _) Or_error.t)] in test []; [%expect {| ((input ()) (choose ()) (choose_exn (Error ("[Hashtbl.choose_exn] of empty hashtbl"))) (choose_randomly ()) (choose_randomly_exn ( Error ("[Hashtbl.choose_randomly_exn] of empty hashtbl")))) |}]; test [] ~size:100; [%expect {| ((input ()) (choose ()) (choose_exn (Error ("[Hashtbl.choose_exn] of empty hashtbl"))) (choose_randomly ()) (choose_randomly_exn ( Error ("[Hashtbl.choose_randomly_exn] of empty hashtbl")))) |}]; test [ 1 ]; [%expect {| ((input ((1 1))) (choose ((_ _))) (choose_exn (Ok (_ _))) (choose_randomly ((_ _))) (choose_randomly_exn (Ok (_ _)))) |}]; test [ 1 ] ~size:100; [%expect {| ((input ((1 1))) (choose ((_ _))) (choose_exn (Ok (_ _))) (choose_randomly ((_ _))) (choose_randomly_exn (Ok (_ _)))) |}]; test [ 1; 2 ]; [%expect {| ((input ( (1 1) (2 2))) (choose ((_ _))) (choose_exn (Ok (_ _))) (choose_randomly ((_ _))) (choose_randomly_exn (Ok (_ _)))) |}]; test [ 1; 2 ] ~size:100; [%expect {| ((input ( (1 1) (2 2))) (choose ((_ _))) (choose_exn (Ok (_ _))) (choose_randomly ((_ _))) (choose_randomly_exn (Ok (_ _)))) |}] ;; let%expect_test "update_and_return" = let t = Hashtbl.create (module String) in let update_and_return str ~f = let x = Hashtbl.update_and_return t str ~f in print_s [%message (t : (string, int) Hashtbl.t) (x : int)] in update_and_return "foo" ~f:(function | None -> 1 | Some _ -> failwith "no"); [%expect {| ((t ((foo 1))) (x 1)) |}]; update_and_return "foo" ~f:(function | Some 1 -> 2 | _ -> failwith "no"); [%expect {| ((t ((foo 2))) (x 2)) |}] ;;