open! Base
open! Import

type 'a t = 'a Generator.t

let create = Generator.create
let generate = Generator.generate

let%expect_test "create & generate" =
  let int_up_to_size =
    Generator.create (fun ~size ~random -> Splittable_random.int random ~lo:0 ~hi:size)
  in
  let random = Splittable_random.create Random.State.default in
  List.init 30 ~f:(fun size -> Generator.generate int_up_to_size ~size ~random)
  |> [%sexp_of: int list]
  |> print_s;
  [%expect {| (0 1 1 1 1 1 3 0 8 7 1 8 11 13 12 7 6 6 0 8 16 4 15 2 6 14 4 24 16 11) |}];
  require_does_raise [%here] (fun () ->
    Generator.generate int_up_to_size ~size:(-1) ~random:(Splittable_random.of_int 0));
  [%expect {| ("Base_quickcheck.Generator.generate: size < 0" (size -1)) |}]
;;

include (Generator : Applicative.S with type 'a t := 'a t)
include (Generator : Monad.S with type 'a t := 'a t)

open struct
  (* We want to use a consistent test count on 32- and 64-bit targets since these tests
     reflect on the actual trials and distributions. *)
  let config = { Test.default_config with test_count = 10_000 }
  let test_generator ?mode ?cr t m = test_generator ~config ?mode ?cr t m
  let show_distribution ?show t m = show_distribution ~config ?show t m
end

let%expect_test "return" =
  test_generator (Generator.return ()) m_unit;
  [%expect {| (generator exhaustive) |}];
  test_generator ~mode:`inexhaustive (Generator.return false) m_bool;
  [%expect
    {|
    (generator
     ("generated 1 distinct values in 10_000 iterations"
      ("did not generate these values" (true))))
    |}]
;;

let%expect_test "map" =
  test_generator (Generator.map Generator.char ~f:Char.is_print) m_bool;
  [%expect {| (generator exhaustive) |}]
;;

let%expect_test "both" =
  test_generator (Generator.both Generator.bool Generator.bool) (m_pair m_bool m_bool);
  [%expect {| (generator exhaustive) |}]
;;

let%expect_test "bind" =
  test_generator
    ~mode:`inexhaustive
    (Generator.bind Generator.bool ~f:(fun bool ->
       let gen = Generator.return bool in
       Generator.both gen gen))
    (m_pair m_bool m_bool);
  [%expect
    {|
    (generator
     ("generated 2 distinct values in 10_000 iterations"
      ("did not generate these values" ((false true) (true false)))))
    |}]
;;

let perturb = Generator.perturb

let%expect_test "perturb" =
  let gen =
    Generator.create (fun ~size:_ ~random -> Splittable_random.int random ~lo:0 ~hi:9)
  in
  let size = 0 in
  List.init 10 ~f:(fun salt ->
    let random = Splittable_random.of_int 0 in
    let gen = Generator.perturb gen salt in
    List.init 10 ~f:(fun _ -> Generator.generate gen ~size ~random))
  |> [%sexp_of: int list list]
  |> print_s;
  [%expect
    {|
    ((0 4 0 6 0 1 4 9 1 6)
     (2 4 9 9 1 2 5 0 8 5)
     (7 3 6 0 5 0 0 2 5 5)
     (8 5 6 5 4 2 1 9 1 2)
     (8 0 7 4 9 0 5 8 4 5)
     (0 1 5 1 5 9 4 7 4 7)
     (3 8 6 8 5 6 9 9 6 5)
     (0 4 1 3 5 6 6 6 3 5)
     (5 0 9 7 6 5 9 1 6 0)
     (0 6 8 8 1 7 7 9 4 0))
    |}]
;;

let size = Generator.size

let%expect_test "size" =
  test_generator Generator.size (m_nat ~up_to:30);
  [%expect {| (generator exhaustive) |}]
;;

let sizes = Generator.sizes

let%expect_test "sizes" =
  test_generator ~mode:`inexhaustive (Generator.sizes ()) (m_list (m_nat ~up_to:10));
  [%expect
    {|
    (generator
     ("generated 3_724 distinct values in 10_000 iterations"
      ("did not generate these values" ((0 10) (10 0)))))
    |}];
  (* The most common size lists: *)
  show_distribution
    (Generator.sizes ())
    (module struct
      type t = int list [@@deriving compare, sexp_of]
    end);
  [%expect
    {|
    ((24.63% ())
     (1.65% (0))
     (1.12% (2))
     (1.06% (1))
     (91bp (0 0))
     (87bp (6))
     (83bp (0 0 0 0))
     (77bp (8))
     (73bp (5))
     (73bp (4))
     (72bp (7))
     (68bp (3))
     (64bp (15))
     (62bp (25))
     (61bp (0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0))
     (60bp (14))
     (60bp (10))
     (60bp (0 0 0 0 0 0 0 0))
     (59bp (11))
     (58bp (13)))
    |}];
  (* The most common lengths of a size list: *)
  show_distribution
    (Generator.sizes () |> Generator.map ~f:(List.length :> _ -> _))
    (module Int);
  [%expect
    {|
    ((24.63% 0)
     (19.39% 1)
     (9.58% 2)
     (8.72% 3)
     (4.96% 4)
     (4.13% 5)
     (3.77% 6)
     (3.52% 7)
     (2.63% 8)
     (2.15% 9)
     (1.75% 16)
     (1.67% 10)
     (1.61% 12)
     (1.37% 13)
     (1.32% 11)
     (1.27% 17)
     (1.25% 15)
     (1.18% 14)
     (1.06% 18)
     (76bp 21))
    |}];
  (* The most common number of non-zero sizes in a size list: *)
  show_distribution
    (Generator.sizes () |> Generator.map ~f:(List.count ~f:(Int.( <> ) 0)))
    (module Int);
  [%expect
    {|
    ((32.65% 0)
     (23.74% 1)
     (12.01% 2)
     (10.74% 3)
     (6.18% 4)
     (5.22% 5)
     (4.64% 6)
     (2.69% 7)
     (1.38% 8)
     (56bp 9)
     (13bp 10)
     (6bp 11))
    |}]
;;

let with_size = Generator.with_size

let%expect_test "with_size" =
  test_generator
    ~mode:`inexhaustive
    (Generator.with_size ~size:0 Generator.size)
    (m_nat ~up_to:10);
  [%expect
    {|
    (generator
     ("generated 1 distinct values in 10_000 iterations"
      ("did not generate these values" (1 2 3 4 5 6 7 8 9 10))))
    |}]
;;

let filter = Generator.filter

let%expect_test "filter" =
  let is_even int = int % 2 = 0 in
  test_generator
    ~mode:`inexhaustive
    (Generator.filter ~f:is_even Generator.size)
    (m_nat ~up_to:30);
  [%expect
    {|
    (generator
     ("generated 16 distinct values in 10_000 iterations"
      ("did not generate these values" (1 3 5 7 9 11 13 15 17 19 21 23 25 27 29))))
    |}]
;;

let filter_map = Generator.filter_map

let%expect_test "filter_map" =
  let exactly_half int = if int % 2 = 0 then Some (int / 2) else None in
  test_generator (Generator.filter_map ~f:exactly_half Generator.size) (m_nat ~up_to:15);
  [%expect {| (generator exhaustive) |}]
;;

let of_list = Generator.of_list

let%expect_test "of_list" =
  test_generator (Generator.of_list Bool.all) m_bool;
  [%expect {| (generator exhaustive) |}]
;;

let of_weighted_list = Generator.of_weighted_list

let%expect_test "of_weighted_list" =
  test_generator
    ~mode:`inexhaustive
    (Generator.of_weighted_list (List.init 31 ~f:(fun size -> Float.of_int size, size)))
    (m_nat ~up_to:30);
  [%expect
    {|
    (generator
     ("generated 30 distinct values in 10_000 iterations"
      ("did not generate these values" (0))))
    |}]
;;

let union = Generator.union

let%expect_test "union" =
  test_generator
    (Generator.union (List.init 31 ~f:(fun size -> Generator.return size)))
    (m_nat ~up_to:30);
  [%expect {| (generator exhaustive) |}]
;;

let weighted_union = Generator.weighted_union

let%expect_test "weighted_union" =
  test_generator
    ~mode:`inexhaustive
    (Generator.weighted_union
       (List.init 31 ~f:(fun size -> Float.of_int size, Generator.return size)))
    (m_nat ~up_to:30);
  [%expect
    {|
    (generator
     ("generated 30 distinct values in 10_000 iterations"
      ("did not generate these values" (0))))
    |}]
;;

let fixed_point = Generator.fixed_point

let%expect_test "fixed_point" =
  test_generator
    ~mode:`inexhaustive
    (Generator.fixed_point (fun generator ->
       Generator.bind Generator.bool ~f:(function
         | false -> Generator.return 0
         | true -> Generator.map generator ~f:Int.succ)))
    (m_nat ~up_to:30);
  [%expect
    {|
    (generator
     ("generated 15 distinct values in 10_000 iterations"
      ("did not generate these values"
       (14 15 16 17 19 20 21 22 23 24 25 26 27 28 29 30))))
    |}];
  (* [fixed_point] should only have to call its argument once *)
  let recursive_calls = ref 0 in
  let values_generated = ref 0 in
  Test.with_sample_exn
    ~config
    ~f:(Sequence.iter ~f:(fun () -> Int.incr values_generated))
    (Generator.fixed_point (fun _ ->
       Int.incr recursive_calls;
       Generator.unit));
  print_s [%message "" (recursive_calls : int ref) (values_generated : int ref)];
  require_equal [%here] (module Int) !recursive_calls 1;
  require_equal [%here] (module Int) !values_generated 10_000;
  [%expect {| ((recursive_calls 1) (values_generated 10000)) |}]
;;

let recursive_union = Generator.recursive_union

let%expect_test "recursive_union" =
  test_generator
    ~mode:`inexhaustive
    (Generator.recursive_union
       [ Generator.of_list [ "a"; "bc"; "def" ]
         |> Generator.map ~f:(fun atom -> Sexp.Atom atom)
       ]
       ~f:(fun sexp ->
         [ Generator.list sexp |> Generator.map ~f:(fun list -> Sexp.List list) ]))
    m_sexp;
  [%expect
    {|
    (generator
     ("generated 2_519 distinct values in 10_000 iterations"
      ("did not generate these values" ((a bc def (a) (bc) (def) (a bc def))))))
    |}];
  (* [recursive_union] should only have to call its argument once *)
  let recursive_calls = ref 0 in
  let values_generated = ref 0 in
  Test.with_sample_exn
    ~config
    ~f:(Sequence.iter ~f:(fun () -> Int.incr values_generated))
    (Generator.recursive_union [ Generator.unit ] ~f:(fun _ ->
       Int.incr recursive_calls;
       [ Generator.unit ]));
  print_s [%message "" (recursive_calls : int ref) (values_generated : int ref)];
  require_equal [%here] (module Int) !recursive_calls 1;
  require_equal [%here] (module Int) !values_generated 10_000;
  [%expect {| ((recursive_calls 1) (values_generated 10000)) |}]
;;

let weighted_recursive_union = Generator.weighted_recursive_union

let%expect_test "weighted_recursive_union" =
  test_generator
    ~mode:`inexhaustive
    (Generator.weighted_recursive_union
       [ ( 2.
         , Generator.of_list [ "a"; "bc"; "def" ]
           |> Generator.map ~f:(fun atom -> Sexp.Atom atom) )
       ]
       ~f:(fun sexp ->
         [ 1., Generator.list sexp |> Generator.map ~f:(fun list -> Sexp.List list) ]))
    m_sexp;
  [%expect
    {|
    (generator
     ("generated 1_520 distinct values in 10_000 iterations"
      ("did not generate these values" ((a bc def (a) (bc) (def) (a bc def))))))
    |}];
  (* [weighted_recursive_union] should only have to call its argument once *)
  let recursive_calls = ref 0 in
  let values_generated = ref 0 in
  Test.with_sample_exn
    ~config
    ~f:(Sequence.iter ~f:(fun () -> Int.incr values_generated))
    (Generator.weighted_recursive_union
       [ 1., Generator.unit ]
       ~f:(fun _ ->
         Int.incr recursive_calls;
         [ 2., Generator.unit ]));
  print_s [%message "" (recursive_calls : int ref) (values_generated : int ref)];
  require_equal [%here] (module Int) !recursive_calls 1;
  require_equal [%here] (module Int) !values_generated 10_000;
  [%expect {| ((recursive_calls 1) (values_generated 10000)) |}]
;;

let fn = Generator.fn

let%expect_test "fn" =
  test_generator (Generator.fn Observer.bool Generator.bool) (m_arrow m_bool m_bool);
  [%expect {| (generator exhaustive) |}]
;;

let unit = Generator.unit

let%expect_test "unit" =
  test_generator Generator.unit m_unit;
  [%expect {| (generator exhaustive) |}]
;;

let bool = Generator.bool

let%expect_test "bool" =
  test_generator Generator.bool m_bool;
  [%expect {| (generator exhaustive) |}]
;;

let option = Generator.option

let%expect_test "option" =
  test_generator (Generator.option Generator.bool) (m_option m_bool);
  [%expect {| (generator exhaustive) |}]
;;

let either = Generator.either

let%expect_test "either" =
  test_generator (Generator.either Generator.bool Generator.bool) (m_either m_bool m_bool);
  [%expect {| (generator exhaustive) |}]
;;

let result = Generator.result

let%expect_test "result" =
  test_generator (Generator.result Generator.bool Generator.bool) (m_result m_bool m_bool);
  [%expect {| (generator exhaustive) |}]
;;

let map_t_m = Generator.map_t_m
let map_tree_using_comparator = Generator.map_tree_using_comparator

let%expect_test "map_t_m" =
  test_generator
    (Generator.map_t_m (module Bool) Generator.bool Generator.bool)
    (m_map (module Bool) m_bool m_bool);
  [%expect {| (generator "generated 9 distinct values in 10_000 iterations") |}]
;;

let set_t_m = Generator.set_t_m
let set_tree_using_comparator = Generator.set_tree_using_comparator

let%expect_test "set_t_m" =
  test_generator
    (Generator.set_t_m (module Bool) Generator.bool)
    (m_set (module Bool) m_bool);
  [%expect {| (generator exhaustive) |}]
;;

let small_positive_or_zero_int = Generator.small_positive_or_zero_int

let%expect_test "small_positive_or_zero_int" =
  test_generator Generator.small_positive_or_zero_int (m_nat ~up_to:31);
  [%expect {| (generator exhaustive) |}]
;;

let small_strictly_positive_int = Generator.small_strictly_positive_int

let%expect_test "small_strictly_positive_int" =
  test_generator
    ~mode:`inexhaustive
    Generator.small_strictly_positive_int
    (m_nat ~up_to:31);
  [%expect
    {|
    (generator
     ("generated 31 distinct values in 10_000 iterations"
      ("did not generate these values" (0))))
    |}]
;;

let int = Generator.int

let%expect_test ("int" [@tags "64-bits-only"]) =
  test_generator Generator.int (m_int (module Int));
  [%expect {| (generator "generated 8_006 distinct values in 10_000 iterations") |}]
;;

let int_uniform = Generator.int_uniform

let%expect_test ("int_uniform" [@tags "64-bits-only"]) =
  test_generator ~mode:`inexhaustive Generator.int_uniform (m_int (module Int));
  [%expect
    {|
    (generator
     ("generated 10_000 distinct values in 10_000 iterations"
      ("did not generate these values"
       (-4611686018427387904 -1 0 1 4611686018427387903))))
    |}]
;;

let int_inclusive = Generator.int_inclusive

let%expect_test "int_inclusive" =
  test_generator (Generator.int_inclusive 0 10) (m_nat ~up_to:10);
  [%expect {| (generator exhaustive) |}];
  show_distribution (Generator.int_inclusive 0 10) (module Int);
  [%expect
    {|
    ((12.96% 0)
     (12.63% 10)
     (8.62% 9)
     (8.53% 5)
     (8.46% 1)
     (8.44% 8)
     (8.25% 4)
     (8.21% 2)
     (8.18% 6)
     (8.15% 7)
     (7.57% 3))
    |}]
;;

let int_uniform_inclusive = Generator.int_uniform_inclusive

let%expect_test "int_uniform_inclusive" =
  test_generator (Generator.int_uniform_inclusive 0 10) (m_nat ~up_to:10);
  [%expect {| (generator exhaustive) |}];
  show_distribution (Generator.int_uniform_inclusive 0 10) (module Int);
  [%expect
    {|
    ((9.55% 5)
     (9.54% 0)
     (9.21% 9)
     (9.18% 1)
     (9.14% 4)
     (9.01% 7)
     (8.95% 10)
     (8.89% 8)
     (8.88% 3)
     (8.86% 2)
     (8.79% 6))
    |}]
;;

let int_log_inclusive = Generator.int_log_inclusive

let%expect_test "int_log_inclusive" =
  test_generator (Generator.int_log_inclusive 0 10) (m_nat ~up_to:10);
  [%expect {| (generator exhaustive) |}];
  show_distribution (Generator.int_log_inclusive 0 10) (module Int);
  [%expect
    {|
    ((22.24% 0)
     (18.67% 1)
     (10.43% 10)
     (9.47% 3)
     (9.12% 2)
     (6.03% 8)
     (6% 9)
     (4.82% 5)
     (4.59% 4)
     (4.37% 7)
     (4.26% 6))
    |}]
;;

let int_log_uniform_inclusive = Generator.int_log_uniform_inclusive

let%expect_test "int_log_uniform_inclusive" =
  test_generator (Generator.int_log_uniform_inclusive 0 10) (m_nat ~up_to:10);
  [%expect {| (generator exhaustive) |}];
  show_distribution (Generator.int_log_uniform_inclusive 0 10) (module Int);
  [%expect
    {|
    ((19.96% 0)
     (19.8% 1)
     (10.19% 3)
     (9.98% 2)
     (6.74% 9)
     (6.64% 8)
     (6.59% 10)
     (5.11% 6)
     (5.08% 5)
     (5.07% 7)
     (4.84% 4))
    |}]
;;

let int_geometric = Generator.int_geometric

let%expect_test "int_geometric" =
  let test n p =
    let gen = Generator.int_geometric n ~p in
    test_generator
      gen
      (m_nat ~up_to:n)
      ~mode:(if n <= 0 then `exhaustive else `inexhaustive);
    show_distribution gen (module Int) ~show:4
  in
  (* check that we stay above the lower bound, test sensible distributions *)
  test 1 0.25;
  [%expect
    {|
    (generator
     ("generated 29 distinct values in 10_000 iterations"
      ("did not generate these values" (0))))
    ((25.65% 1) (18.97% 2) (14.45% 3) (10.34% 4))
    |}];
  test 2 0.5;
  [%expect
    {|
    (generator
     ("generated 14 distinct values in 10_000 iterations"
      ("did not generate these values" (0 1))))
    ((50.77% 2) (25.07% 3) (11.79% 4) (5.78% 5))
    |}];
  test (-3) 0.75;
  [%expect
    {|
    (generator "generated 8 distinct values in 10_000 iterations")
    ((75.84% -3) (17.57% -2) (4.97% -1) (1.2% 0))
    |}];
  (* test a very low [p] *)
  test 1 Float.min_positive_subnormal_value;
  expect_test_output [%here]
  |> replace ~pattern:(Int.to_string Int.max_value) ~with_:"MAX_VALUE"
  |> print_string;
  [%expect
    {|
    (generator
     ("generated 1 distinct values in 10_000 iterations"
      ("did not generate these values" (0 1))))
    ((1x MAX_VALUE))
    |}];
  (* test bounds checking *)
  require_does_raise [%here] (fun () -> Generator.int_geometric 0 ~p:Float.nan);
  [%expect {| ("geometric distribution: p must be between 0 and 1" (p NAN)) |}];
  require_does_raise [%here] (fun () -> Generator.int_geometric 0 ~p:(-1.));
  [%expect {| ("geometric distribution: p must be between 0 and 1" (p -1)) |}];
  require_does_raise [%here] (fun () -> Generator.int_geometric 0 ~p:2.);
  [%expect {| ("geometric distribution: p must be between 0 and 1" (p 2)) |}]
;;

let int32 = Generator.int32

let%expect_test "int32" =
  test_generator Generator.int32 (m_int (module Int32));
  [%expect {| (generator "generated 6_769 distinct values in 10_000 iterations") |}]
;;

let int32_uniform = Generator.int32_uniform

let%expect_test "int32_uniform" =
  test_generator ~mode:`inexhaustive Generator.int32_uniform (m_int (module Int32));
  [%expect
    {|
    (generator
     ("generated 10_000 distinct values in 10_000 iterations"
      ("did not generate these values" (-2147483648 -1 0 1 2147483647))))
    |}]
;;

let int32_inclusive = Generator.int32_inclusive

let%expect_test "int32_inclusive" =
  test_generator (Generator.int32_inclusive 0l 10l) (m_nat' ~up_to:10 (module Int32));
  [%expect {| (generator exhaustive) |}];
  show_distribution (Generator.int32_inclusive 0l 10l) (module Int32);
  [%expect
    {|
    ((12.96% 0)
     (12.63% 10)
     (8.62% 9)
     (8.53% 5)
     (8.46% 1)
     (8.44% 8)
     (8.25% 4)
     (8.21% 2)
     (8.18% 6)
     (8.15% 7)
     (7.57% 3))
    |}]
;;

let int32_uniform_inclusive = Generator.int32_uniform_inclusive

let%expect_test "int32_uniform_inclusive" =
  test_generator
    (Generator.int32_uniform_inclusive 0l 10l)
    (m_nat' ~up_to:10 (module Int32));
  [%expect {| (generator exhaustive) |}];
  show_distribution (Generator.int32_uniform_inclusive 0l 10l) (module Int32);
  [%expect
    {|
    ((9.55% 5)
     (9.54% 0)
     (9.21% 9)
     (9.18% 1)
     (9.14% 4)
     (9.01% 7)
     (8.95% 10)
     (8.89% 8)
     (8.88% 3)
     (8.86% 2)
     (8.79% 6))
    |}]
;;

let int32_log_inclusive = Generator.int32_log_inclusive

let%expect_test "int32_log_inclusive" =
  test_generator (Generator.int32_log_inclusive 0l 10l) (m_nat' ~up_to:10 (module Int32));
  [%expect {| (generator exhaustive) |}];
  show_distribution (Generator.int32_log_inclusive 0l 10l) (module Int32);
  [%expect
    {|
    ((22.24% 0)
     (18.67% 1)
     (10.43% 10)
     (9.47% 3)
     (9.12% 2)
     (6.03% 8)
     (6% 9)
     (4.82% 5)
     (4.59% 4)
     (4.37% 7)
     (4.26% 6))
    |}]
;;

let int32_log_uniform_inclusive = Generator.int32_log_uniform_inclusive

let%expect_test "int32_log_uniform_inclusive" =
  test_generator
    (Generator.int32_log_uniform_inclusive 0l 10l)
    (m_nat' ~up_to:10 (module Int32));
  [%expect {| (generator exhaustive) |}];
  show_distribution (Generator.int32_log_uniform_inclusive 0l 10l) (module Int32);
  [%expect
    {|
    ((19.96% 0)
     (19.8% 1)
     (10.19% 3)
     (9.98% 2)
     (6.74% 9)
     (6.64% 8)
     (6.59% 10)
     (5.11% 6)
     (5.08% 5)
     (5.07% 7)
     (4.84% 4))
    |}]
;;

let int32_geometric = Generator.int32_geometric

let%expect_test "int32_geometric" =
  let test n p =
    let gen = Generator.int32_geometric (Int32.of_int_exn n) ~p in
    test_generator
      gen
      (m_nat' ~up_to:n (module Int32))
      ~mode:(if n <= 0 then `exhaustive else `inexhaustive);
    show_distribution gen (module Int32) ~show:4
  in
  (* check that we stay above the lower bound, test sensible distributions *)
  test 1 0.25;
  [%expect
    {|
    (generator
     ("generated 29 distinct values in 10_000 iterations"
      ("did not generate these values" (0))))
    ((25.65% 1) (18.97% 2) (14.45% 3) (10.34% 4))
    |}];
  test 2 0.5;
  [%expect
    {|
    (generator
     ("generated 14 distinct values in 10_000 iterations"
      ("did not generate these values" (0 1))))
    ((50.77% 2) (25.07% 3) (11.79% 4) (5.78% 5))
    |}];
  test (-3) 0.75;
  [%expect
    {|
    (generator "generated 8 distinct values in 10_000 iterations")
    ((75.84% -3) (17.57% -2) (4.97% -1) (1.2% 0))
    |}];
  (* test a very low [p] *)
  test 1 Float.min_positive_subnormal_value;
  [%expect
    {|
    (generator
     ("generated 1 distinct values in 10_000 iterations"
      ("did not generate these values" (0 1))))
    ((1x 2147483647))
    |}];
  (* test bounds checking *)
  require_does_raise [%here] (fun () -> Generator.int32_geometric 0l ~p:Float.nan);
  [%expect {| ("geometric distribution: p must be between 0 and 1" (p NAN)) |}];
  require_does_raise [%here] (fun () -> Generator.int32_geometric 0l ~p:(-1.));
  [%expect {| ("geometric distribution: p must be between 0 and 1" (p -1)) |}];
  require_does_raise [%here] (fun () -> Generator.int32_geometric 0l ~p:2.);
  [%expect {| ("geometric distribution: p must be between 0 and 1" (p 2)) |}]
;;

let int63 = Generator.int63

let%expect_test "int63" =
  test_generator Generator.int63 (m_int (module Int63));
  [%expect {| (generator "generated 8_006 distinct values in 10_000 iterations") |}]
;;

let int63_uniform = Generator.int63_uniform

let%expect_test "int63_uniform" =
  test_generator ~mode:`inexhaustive Generator.int63_uniform (m_int (module Int63));
  [%expect
    {|
    (generator
     ("generated 10_000 distinct values in 10_000 iterations"
      ("did not generate these values"
       (-4611686018427387904 -1 0 1 4611686018427387903))))
    |}]
;;

let int63_inclusive = Generator.int63_inclusive

let%expect_test "int63_inclusive" =
  test_generator
    (Generator.int63_inclusive Int63.zero (Int63.of_int_exn 10))
    (m_nat' ~up_to:10 (module Int63));
  [%expect {| (generator exhaustive) |}];
  show_distribution
    (Generator.int63_inclusive Int63.zero (Int63.of_int_exn 10))
    (module Int63);
  [%expect
    {|
    ((12.96% 0)
     (12.63% 10)
     (8.62% 9)
     (8.53% 5)
     (8.46% 1)
     (8.44% 8)
     (8.25% 4)
     (8.21% 2)
     (8.18% 6)
     (8.15% 7)
     (7.57% 3))
    |}]
;;

let int63_uniform_inclusive = Generator.int63_uniform_inclusive

let%expect_test "int63_uniform_inclusive" =
  test_generator
    (Generator.int63_uniform_inclusive Int63.zero (Int63.of_int_exn 10))
    (m_nat' ~up_to:10 (module Int63));
  [%expect {| (generator exhaustive) |}];
  show_distribution
    (Generator.int63_uniform_inclusive Int63.zero (Int63.of_int_exn 10))
    (module Int63);
  [%expect
    {|
    ((9.55% 5)
     (9.54% 0)
     (9.21% 9)
     (9.18% 1)
     (9.14% 4)
     (9.01% 7)
     (8.95% 10)
     (8.89% 8)
     (8.88% 3)
     (8.86% 2)
     (8.79% 6))
    |}]
;;

let int63_log_inclusive = Generator.int63_log_inclusive

let%expect_test "int63_log_inclusive" =
  test_generator
    (Generator.int63_log_inclusive Int63.zero (Int63.of_int_exn 10))
    (m_nat' ~up_to:10 (module Int63));
  [%expect {| (generator exhaustive) |}];
  show_distribution
    (Generator.int63_log_inclusive Int63.zero (Int63.of_int_exn 10))
    (module Int63);
  [%expect
    {|
    ((22.24% 0)
     (18.67% 1)
     (10.43% 10)
     (9.47% 3)
     (9.12% 2)
     (6.03% 8)
     (6% 9)
     (4.82% 5)
     (4.59% 4)
     (4.37% 7)
     (4.26% 6))
    |}]
;;

let int63_log_uniform_inclusive = Generator.int63_log_uniform_inclusive

let%expect_test "int63_log_uniform_inclusive" =
  test_generator
    (Generator.int63_log_uniform_inclusive Int63.zero (Int63.of_int_exn 10))
    (m_nat' ~up_to:10 (module Int63));
  [%expect {| (generator exhaustive) |}];
  show_distribution
    (Generator.int63_log_uniform_inclusive Int63.zero (Int63.of_int_exn 10))
    (module Int63);
  [%expect
    {|
    ((19.96% 0)
     (19.8% 1)
     (10.19% 3)
     (9.98% 2)
     (6.74% 9)
     (6.64% 8)
     (6.59% 10)
     (5.11% 6)
     (5.08% 5)
     (5.07% 7)
     (4.84% 4))
    |}]
;;

let int63_geometric = Generator.int63_geometric

let%expect_test "int63_geometric" =
  let test n p =
    let gen = Generator.int63_geometric (Int63.of_int_exn n) ~p in
    test_generator
      gen
      (m_nat' ~up_to:n (module Int63))
      ~mode:(if n <= 0 then `exhaustive else `inexhaustive);
    show_distribution gen (module Int63) ~show:4
  in
  (* check that we stay above the lower bound, test sensible distributions *)
  test 1 0.25;
  [%expect
    {|
    (generator
     ("generated 29 distinct values in 10_000 iterations"
      ("did not generate these values" (0))))
    ((25.65% 1) (18.97% 2) (14.45% 3) (10.34% 4))
    |}];
  test 2 0.5;
  [%expect
    {|
    (generator
     ("generated 14 distinct values in 10_000 iterations"
      ("did not generate these values" (0 1))))
    ((50.77% 2) (25.07% 3) (11.79% 4) (5.78% 5))
    |}];
  test (-3) 0.75;
  [%expect
    {|
    (generator "generated 8 distinct values in 10_000 iterations")
    ((75.84% -3) (17.57% -2) (4.97% -1) (1.2% 0))
    |}];
  (* test a very low [p] *)
  test 1 Float.min_positive_subnormal_value;
  [%expect
    {|
    (generator
     ("generated 1 distinct values in 10_000 iterations"
      ("did not generate these values" (0 1))))
    ((1x 4611686018427387903))
    |}];
  (* test bounds checking *)
  require_does_raise [%here] (fun () -> Generator.int63_geometric Int63.zero ~p:Float.nan);
  [%expect {| ("geometric distribution: p must be between 0 and 1" (p NAN)) |}];
  require_does_raise [%here] (fun () -> Generator.int63_geometric Int63.zero ~p:(-1.));
  [%expect {| ("geometric distribution: p must be between 0 and 1" (p -1)) |}];
  require_does_raise [%here] (fun () -> Generator.int63_geometric Int63.zero ~p:2.);
  [%expect {| ("geometric distribution: p must be between 0 and 1" (p 2)) |}]
;;

let int64 = Generator.int64

let%expect_test "int64" =
  test_generator Generator.int64 (m_int (module Int64));
  [%expect {| (generator "generated 8_047 distinct values in 10_000 iterations") |}]
;;

let int64_uniform = Generator.int64_uniform

let%expect_test "int64_uniform" =
  test_generator ~mode:`inexhaustive Generator.int64_uniform (m_int (module Int64));
  [%expect
    {|
    (generator
     ("generated 10_000 distinct values in 10_000 iterations"
      ("did not generate these values"
       (-9223372036854775808 -1 0 1 9223372036854775807))))
    |}]
;;

let int64_inclusive = Generator.int64_inclusive

let%expect_test "int64_inclusive" =
  test_generator (Generator.int64_inclusive 0L 10L) (m_nat' ~up_to:10 (module Int64));
  [%expect {| (generator exhaustive) |}];
  show_distribution (Generator.int64_inclusive 0L 10L) (module Int64);
  [%expect
    {|
    ((12.96% 0)
     (12.63% 10)
     (8.62% 9)
     (8.53% 5)
     (8.46% 1)
     (8.44% 8)
     (8.25% 4)
     (8.21% 2)
     (8.18% 6)
     (8.15% 7)
     (7.57% 3))
    |}]
;;

let int64_uniform_inclusive = Generator.int64_uniform_inclusive

let%expect_test "int64_uniform_inclusive" =
  test_generator
    (Generator.int64_uniform_inclusive 0L 10L)
    (m_nat' ~up_to:10 (module Int64));
  [%expect {| (generator exhaustive) |}];
  show_distribution (Generator.int64_uniform_inclusive 0L 10L) (module Int64);
  [%expect
    {|
    ((9.55% 5)
     (9.54% 0)
     (9.21% 9)
     (9.18% 1)
     (9.14% 4)
     (9.01% 7)
     (8.95% 10)
     (8.89% 8)
     (8.88% 3)
     (8.86% 2)
     (8.79% 6))
    |}]
;;

let int64_log_inclusive = Generator.int64_log_inclusive

let%expect_test "int64_log_inclusive" =
  test_generator (Generator.int64_log_inclusive 0L 10L) (m_nat' ~up_to:10 (module Int64));
  [%expect {| (generator exhaustive) |}];
  show_distribution (Generator.int64_log_inclusive 0L 10L) (module Int64);
  [%expect
    {|
    ((22.24% 0)
     (18.67% 1)
     (10.43% 10)
     (9.47% 3)
     (9.12% 2)
     (6.03% 8)
     (6% 9)
     (4.82% 5)
     (4.59% 4)
     (4.37% 7)
     (4.26% 6))
    |}]
;;

let int64_log_uniform_inclusive = Generator.int64_log_uniform_inclusive

let%expect_test "int64_log_uniform_inclusive" =
  test_generator
    (Generator.int64_log_uniform_inclusive 0L 10L)
    (m_nat' ~up_to:10 (module Int64));
  [%expect {| (generator exhaustive) |}];
  show_distribution (Generator.int64_log_uniform_inclusive 0L 10L) (module Int64);
  [%expect
    {|
    ((19.96% 0)
     (19.8% 1)
     (10.19% 3)
     (9.98% 2)
     (6.74% 9)
     (6.64% 8)
     (6.59% 10)
     (5.11% 6)
     (5.08% 5)
     (5.07% 7)
     (4.84% 4))
    |}]
;;

let int64_geometric = Generator.int64_geometric

let%expect_test "int64_geometric" =
  let test n p =
    let gen = Generator.int64_geometric (Int64.of_int_exn n) ~p in
    test_generator
      gen
      (m_nat' ~up_to:n (module Int64))
      ~mode:(if n <= 0 then `exhaustive else `inexhaustive);
    show_distribution gen (module Int64) ~show:4
  in
  (* check that we stay above the lower bound, test sensible distributions *)
  test 1 0.25;
  [%expect
    {|
    (generator
     ("generated 29 distinct values in 10_000 iterations"
      ("did not generate these values" (0))))
    ((25.65% 1) (18.97% 2) (14.45% 3) (10.34% 4))
    |}];
  test 2 0.5;
  [%expect
    {|
    (generator
     ("generated 14 distinct values in 10_000 iterations"
      ("did not generate these values" (0 1))))
    ((50.77% 2) (25.07% 3) (11.79% 4) (5.78% 5))
    |}];
  test (-3) 0.75;
  [%expect
    {|
    (generator "generated 8 distinct values in 10_000 iterations")
    ((75.84% -3) (17.57% -2) (4.97% -1) (1.2% 0))
    |}];
  (* test a very low [p] *)
  test 1 Float.min_positive_subnormal_value;
  [%expect
    {|
    (generator
     ("generated 1 distinct values in 10_000 iterations"
      ("did not generate these values" (0 1))))
    ((1x 9223372036854775807))
    |}];
  (* test bounds checking *)
  require_does_raise [%here] (fun () -> Generator.int64_geometric 0L ~p:Float.nan);
  [%expect {| ("geometric distribution: p must be between 0 and 1" (p NAN)) |}];
  require_does_raise [%here] (fun () -> Generator.int64_geometric 0L ~p:(-1.));
  [%expect {| ("geometric distribution: p must be between 0 and 1" (p -1)) |}];
  require_does_raise [%here] (fun () -> Generator.int64_geometric 0L ~p:2.);
  [%expect {| ("geometric distribution: p must be between 0 and 1" (p 2)) |}]
;;

let nativeint = Generator.nativeint

let%expect_test ("nativeint" [@tags "64-bits-only"]) =
  test_generator Generator.nativeint (m_int (module Nativeint));
  [%expect {| (generator "generated 8_047 distinct values in 10_000 iterations") |}]
;;

let nativeint_uniform = Generator.nativeint_uniform

let%expect_test ("nativeint_uniform" [@tags "64-bits-only"]) =
  test_generator
    ~mode:`inexhaustive
    Generator.nativeint_uniform
    (m_int (module Nativeint));
  [%expect
    {|
    (generator
     ("generated 10_000 distinct values in 10_000 iterations"
      ("did not generate these values"
       (-9223372036854775808 -1 0 1 9223372036854775807))))
    |}]
;;

let nativeint_inclusive = Generator.nativeint_inclusive

let%expect_test "nativeint_inclusive" =
  test_generator
    (Generator.nativeint_inclusive 0n 10n)
    (m_nat' ~up_to:10 (module Nativeint));
  [%expect {| (generator exhaustive) |}];
  show_distribution (Generator.nativeint_inclusive 0n 10n) (module Nativeint);
  [%expect
    {|
    ((12.96% 0)
     (12.63% 10)
     (8.62% 9)
     (8.53% 5)
     (8.46% 1)
     (8.44% 8)
     (8.25% 4)
     (8.21% 2)
     (8.18% 6)
     (8.15% 7)
     (7.57% 3))
    |}]
;;

let nativeint_uniform_inclusive = Generator.nativeint_uniform_inclusive

let%expect_test "nativeint_uniform_inclusive" =
  test_generator
    (Generator.nativeint_uniform_inclusive 0n 10n)
    (m_nat' ~up_to:10 (module Nativeint));
  [%expect {| (generator exhaustive) |}];
  show_distribution (Generator.nativeint_uniform_inclusive 0n 10n) (module Nativeint);
  [%expect
    {|
    ((9.55% 5)
     (9.54% 0)
     (9.21% 9)
     (9.18% 1)
     (9.14% 4)
     (9.01% 7)
     (8.95% 10)
     (8.89% 8)
     (8.88% 3)
     (8.86% 2)
     (8.79% 6))
    |}]
;;

let nativeint_log_inclusive = Generator.nativeint_log_inclusive

let%expect_test "nativeint_log_inclusive" =
  test_generator
    (Generator.nativeint_log_inclusive 0n 10n)
    (m_nat' ~up_to:10 (module Nativeint));
  [%expect {| (generator exhaustive) |}];
  show_distribution (Generator.nativeint_log_inclusive 0n 10n) (module Nativeint);
  [%expect
    {|
    ((22.24% 0)
     (18.67% 1)
     (10.43% 10)
     (9.47% 3)
     (9.12% 2)
     (6.03% 8)
     (6% 9)
     (4.82% 5)
     (4.59% 4)
     (4.37% 7)
     (4.26% 6))
    |}]
;;

let nativeint_log_uniform_inclusive = Generator.nativeint_log_uniform_inclusive

let%expect_test "nativeint_log_uniform_inclusive" =
  test_generator
    (Generator.nativeint_log_uniform_inclusive 0n 10n)
    (m_nat' ~up_to:10 (module Nativeint));
  [%expect {| (generator exhaustive) |}];
  show_distribution (Generator.nativeint_log_uniform_inclusive 0n 10n) (module Nativeint);
  [%expect
    {|
    ((19.96% 0)
     (19.8% 1)
     (10.19% 3)
     (9.98% 2)
     (6.74% 9)
     (6.64% 8)
     (6.59% 10)
     (5.11% 6)
     (5.08% 5)
     (5.07% 7)
     (4.84% 4))
    |}]
;;

let nativeint_geometric = Generator.nativeint_geometric

let%expect_test "nativeint_geometric" =
  let test n p =
    let gen = Generator.nativeint_geometric (Nativeint.of_int n) ~p in
    test_generator
      gen
      (m_nat' ~up_to:n (module Nativeint))
      ~mode:(if n <= 0 then `exhaustive else `inexhaustive);
    show_distribution gen (module Nativeint) ~show:4
  in
  (* check that we stay above the lower bound, test sensible distributions *)
  test 1 0.25;
  [%expect
    {|
    (generator
     ("generated 29 distinct values in 10_000 iterations"
      ("did not generate these values" (0))))
    ((25.65% 1) (18.97% 2) (14.45% 3) (10.34% 4))
    |}];
  test 2 0.5;
  [%expect
    {|
    (generator
     ("generated 14 distinct values in 10_000 iterations"
      ("did not generate these values" (0 1))))
    ((50.77% 2) (25.07% 3) (11.79% 4) (5.78% 5))
    |}];
  test (-3) 0.75;
  [%expect
    {|
    (generator "generated 8 distinct values in 10_000 iterations")
    ((75.84% -3) (17.57% -2) (4.97% -1) (1.2% 0))
    |}];
  (* test a very low [p] *)
  test 1 Float.min_positive_subnormal_value;
  expect_test_output [%here]
  |> replace ~pattern:(Nativeint.to_string Nativeint.max_value) ~with_:"MAX_VALUE"
  |> print_string;
  [%expect
    {|
    (generator
     ("generated 1 distinct values in 10_000 iterations"
      ("did not generate these values" (0 1))))
    ((1x MAX_VALUE))
    |}];
  (* test bounds checking *)
  require_does_raise [%here] (fun () -> Generator.nativeint_geometric 0n ~p:Float.nan);
  [%expect {| ("geometric distribution: p must be between 0 and 1" (p NAN)) |}];
  require_does_raise [%here] (fun () -> Generator.nativeint_geometric 0n ~p:(-1.));
  [%expect {| ("geometric distribution: p must be between 0 and 1" (p -1)) |}];
  require_does_raise [%here] (fun () -> Generator.nativeint_geometric 0n ~p:2.);
  [%expect {| ("geometric distribution: p must be between 0 and 1" (p 2)) |}]
;;

let float = Generator.float

let%expect_test "float" =
  test_generator ~mode:`inexhaustive Generator.float m_float;
  [%expect
    {|
    (generator
     ("generated 9_127 distinct values in 10_000 iterations"
      ("did not generate these values"
       (-1.7976931348623157E+308 1.7976931348623157E+308))))
    |}]
;;

let float_without_nan = Generator.float_without_nan

let%expect_test "float_without_nan" =
  test_generator ~mode:`inexhaustive Generator.float_without_nan m_float;
  [%expect
    {|
    (generator
     ("generated 9_170 distinct values in 10_000 iterations"
      ("did not generate these values"
       (NAN -1.7976931348623157E+308 1.7976931348623157E+308))))
    |}]
;;

let float_finite = Generator.float_finite

let%expect_test "float_finite" =
  test_generator ~mode:`inexhaustive Generator.float_finite m_float;
  [%expect
    {|
    (generator
     ("generated 9_252 distinct values in 10_000 iterations"
      ("did not generate these values"
       (NAN -INF -1.7976931348623157E+308 1.7976931348623157E+308 INF))))
    |}]
;;

let float_strictly_positive = Generator.float_strictly_positive

let%expect_test "float_strictly_positive" =
  test_generator ~mode:`inexhaustive Generator.float_strictly_positive m_float;
  [%expect
    {|
    (generator
     ("generated 9_171 distinct values in 10_000 iterations"
      ("did not generate these values"
       (NAN
        -INF
        -1.7976931348623157E+308
        -2.2250738585072014E-308
        -2.2250738585072009E-308
        -4.94065645841247E-324
        0
        1.7976931348623157E+308
        INF))))
    |}]
;;

let float_strictly_negative = Generator.float_strictly_negative

let%expect_test "float_strictly_negative" =
  test_generator ~mode:`inexhaustive Generator.float_strictly_negative m_float;
  [%expect
    {|
    (generator
     ("generated 9_171 distinct values in 10_000 iterations"
      ("did not generate these values"
       (NAN
        -INF
        -1.7976931348623157E+308
        0
        4.94065645841247E-324
        2.2250738585072009E-308
        2.2250738585072014E-308
        1.7976931348623157E+308
        INF))))
    |}]
;;

let float_positive_or_zero = Generator.float_positive_or_zero

let%expect_test "float_positive_or_zero" =
  test_generator ~mode:`inexhaustive Generator.float_positive_or_zero m_float;
  [%expect
    {|
    (generator
     ("generated 9_095 distinct values in 10_000 iterations"
      ("did not generate these values"
       (NAN
        -INF
        -1.7976931348623157E+308
        -2.2250738585072014E-308
        -2.2250738585072009E-308
        -4.94065645841247E-324
        1.7976931348623157E+308
        INF))))
    |}]
;;

let float_negative_or_zero = Generator.float_negative_or_zero

let%expect_test "float_negative_or_zero" =
  test_generator ~mode:`inexhaustive Generator.float_negative_or_zero m_float;
  [%expect
    {|
    (generator
     ("generated 9_095 distinct values in 10_000 iterations"
      ("did not generate these values"
       (NAN
        -INF
        -1.7976931348623157E+308
        4.94065645841247E-324
        2.2250738585072009E-308
        2.2250738585072014E-308
        1.7976931348623157E+308
        INF))))
    |}]
;;

let float_inclusive = Generator.float_inclusive

let%expect_test "float_inclusive" =
  test_generator ~mode:`inexhaustive (Generator.float_inclusive (-1.) 1.) m_float;
  [%expect
    {|
    (generator
     ("generated 9_075 distinct values in 10_000 iterations"
      ("did not generate these values"
       (NAN
        -INF
        -1.7976931348623157E+308
        -2.2250738585072014E-308
        -2.2250738585072009E-308
        -4.94065645841247E-324
        0
        4.94065645841247E-324
        2.2250738585072009E-308
        2.2250738585072014E-308
        1.7976931348623157E+308
        INF))))
    |}]
;;

let%expect_test "float_inclusive singular range edge case" =
  test_generator ~mode:`inexhaustive (Generator.float_inclusive 1. 1.) m_float;
  [%expect
    {|
    (generator
     ("generated 1 distinct values in 10_000 iterations"
      ("did not generate these values"
       (NAN
        -INF
        -1.7976931348623157E+308
        -2.2250738585072014E-308
        -2.2250738585072009E-308
        -4.94065645841247E-324
        0
        4.94065645841247E-324
        2.2250738585072009E-308
        2.2250738585072014E-308
        1.7976931348623157E+308
        INF))))
    |}]
;;

let%expect_test "float_inclusive two-value range edge case" =
  show_raise (fun () ->
    test_generator
      ~mode:`inexhaustive
      (Generator.float_inclusive 5000000000000000. 5000000000000001.)
      m_float);
  [%expect
    {|
    (generator
     ("generated 2 distinct values in 10_000 iterations"
      ("did not generate these values"
       (NAN
        -INF
        -1.7976931348623157E+308
        -2.2250738585072014E-308
        -2.2250738585072009E-308
        -4.94065645841247E-324
        0
        4.94065645841247E-324
        2.2250738585072009E-308
        2.2250738585072014E-308
        1.7976931348623157E+308
        INF))))
    "did not raise"
    |}]
;;

let float_uniform_exclusive = Generator.float_uniform_exclusive

let%expect_test "float_uniform_exclusive" =
  test_generator ~mode:`inexhaustive (Generator.float_uniform_exclusive (-1.) 1.) m_float;
  [%expect
    {|
    (generator
     ("generated 10_000 distinct values in 10_000 iterations"
      ("did not generate these values"
       (NAN
        -INF
        -1.7976931348623157E+308
        -2.2250738585072014E-308
        -2.2250738585072009E-308
        -4.94065645841247E-324
        0
        4.94065645841247E-324
        2.2250738585072009E-308
        2.2250738585072014E-308
        1.7976931348623157E+308
        INF))))
    |}]
;;

let float_of_class = Generator.float_of_class

let%expect_test "float_of_class" =
  test_generator ~mode:`inexhaustive (Generator.float_of_class Normal) m_float;
  [%expect
    {|
    (generator
     ("generated 9_360 distinct values in 10_000 iterations"
      ("did not generate these values"
       (NAN
        -INF
        -1.7976931348623157E+308
        -2.2250738585072009E-308
        -4.94065645841247E-324
        0
        4.94065645841247E-324
        2.2250738585072009E-308
        1.7976931348623157E+308
        INF))))
    |}];
  test_generator ~mode:`inexhaustive (Generator.float_of_class Subnormal) m_float;
  [%expect
    {|
    (generator
     ("generated 7_852 distinct values in 10_000 iterations"
      ("did not generate these values"
       (NAN
        -INF
        -1.7976931348623157E+308
        -2.2250738585072014E-308
        0
        2.2250738585072014E-308
        1.7976931348623157E+308
        INF))))
    |}]
;;

let char = Generator.char

let%expect_test "char" =
  test_generator Generator.char m_char;
  [%expect {| (generator "generated 249 distinct values in 10_000 iterations") |}]
;;

let char_lowercase = Generator.char_lowercase

let%expect_test "char_lowercase" =
  test_generator ~mode:`inexhaustive Generator.char_lowercase m_char;
  [%expect
    {|
    (generator
     ("generated 26 distinct values in 10_000 iterations"
      ("did not generate these values" ("\000" "\t" " " ! 0 9 A Z ~ "\255"))))
    |}]
;;

let char_uppercase = Generator.char_uppercase

let%expect_test "char_uppercase" =
  test_generator ~mode:`inexhaustive Generator.char_uppercase m_char;
  [%expect
    {|
    (generator
     ("generated 26 distinct values in 10_000 iterations"
      ("did not generate these values" ("\000" "\t" " " ! 0 9 a z ~ "\255"))))
    |}]
;;

let char_digit = Generator.char_digit

let%expect_test "char_digit" =
  test_generator ~mode:`inexhaustive Generator.char_digit m_char;
  [%expect
    {|
    (generator
     ("generated 10 distinct values in 10_000 iterations"
      ("did not generate these values" ("\000" "\t" " " ! A Z a z ~ "\255"))))
    |}]
;;

let char_alpha = Generator.char_alpha

let%expect_test "char_alpha" =
  test_generator ~mode:`inexhaustive Generator.char_alpha m_char;
  [%expect
    {|
    (generator
     ("generated 52 distinct values in 10_000 iterations"
      ("did not generate these values" ("\000" "\t" " " ! 0 9 ~ "\255"))))
    |}]
;;

let char_alphanum = Generator.char_alphanum

let%expect_test "char_alphanum" =
  test_generator ~mode:`inexhaustive Generator.char_alphanum m_char;
  [%expect
    {|
    (generator
     ("generated 62 distinct values in 10_000 iterations"
      ("did not generate these values" ("\000" "\t" " " ! ~ "\255"))))
    |}]
;;

let char_whitespace = Generator.char_whitespace

let%expect_test "char_whitespace" =
  test_generator ~mode:`inexhaustive Generator.char_whitespace m_char;
  [%expect
    {|
    (generator
     ("generated 6 distinct values in 10_000 iterations"
      ("did not generate these values" ("\000" ! 0 9 A Z a z ~ "\255"))))
    |}]
;;

let char_print = Generator.char_print

let%expect_test "char_print" =
  test_generator ~mode:`inexhaustive Generator.char_print m_char;
  [%expect
    {|
    (generator
     ("generated 95 distinct values in 10_000 iterations"
      ("did not generate these values" ("\000" "\t" "\255"))))
    |}]
;;

let char_uniform_inclusive = Generator.char_uniform_inclusive

let%expect_test "char_uniform_inclusive" =
  test_generator ~mode:`inexhaustive (Generator.char_uniform_inclusive 'A' 'Z') m_char;
  [%expect
    {|
    (generator
     ("generated 26 distinct values in 10_000 iterations"
      ("did not generate these values" ("\000" "\t" " " ! 0 9 a z ~ "\255"))))
    |}]
;;

let string = Generator.string

let%expect_test "string" =
  test_generator ~mode:`inexhaustive Generator.string m_string;
  [%expect
    {|
    (generator
     ("generated 8_583 distinct values in 10_000 iterations"
      ("did not generate these values" (" " "\000\000" "  " 00 AA __ zz))))
    |}]
;;

let string_non_empty = Generator.string_non_empty

let%expect_test "string_non_empty" =
  test_generator ~mode:`inexhaustive Generator.string_non_empty m_string;
  [%expect
    {|
    (generator
     ("generated 8_936 distinct values in 10_000 iterations"
      ("did not generate these values" ("" " " "\000\000" "  " 00 AA __ zz))))
    |}]
;;

let string_with_length = Generator.string_with_length

let%expect_test "string_with_length" =
  test_generator ~mode:`inexhaustive (Generator.string_with_length ~length:2) m_string;
  [%expect
    {|
    (generator
     ("generated 5_239 distinct values in 10_000 iterations"
      ("did not generate these values" ("" "\000" " " 0 A _ z "\000\000" "  " __))))
    |}]
;;

let string_of = Generator.string_of

let%expect_test "string_of" =
  test_generator
    ~mode:`inexhaustive
    (Generator.string_of (Generator.filter Generator.char ~f:Char.is_lowercase))
    m_string;
  [%expect
    {|
    (generator
     ("generated 8_320 distinct values in 10_000 iterations"
      ("did not generate these values"
       ("\000" " " 0 A _ "\000\000" "  " 00 AA __))))
    |}]
;;

let string_non_empty_of = Generator.string_non_empty_of

let%expect_test "string_non_empty_of" =
  test_generator
    ~mode:`inexhaustive
    (Generator.string_non_empty_of (Generator.filter Generator.char ~f:Char.is_lowercase))
    m_string;
  [%expect
    {|
    (generator
     ("generated 8_569 distinct values in 10_000 iterations"
      ("did not generate these values"
       ("" "\000" " " 0 A _ "\000\000" "  " 00 AA __ zz))))
    |}]
;;

let string_with_length_of = Generator.string_with_length_of

let%expect_test "string_with_length_of" =
  test_generator
    ~mode:`inexhaustive
    (Generator.string_with_length_of
       ~length:2
       (Generator.filter Generator.char ~f:Char.is_lowercase))
    m_string;
  [%expect
    {|
    (generator
     ("generated 676 distinct values in 10_000 iterations"
      ("did not generate these values"
       ("" "\000" " " 0 A _ z "\000\000" "  " 00 AA __))))
    |}]
;;

let string_like = Generator.string_like

let%expect_test "string_like" =
  test_generator ~mode:`inexhaustive (Generator.string_like "__") m_string;
  [%expect
    {|
    (generator
     ("generated 2_643 distinct values in 10_000 iterations"
      ("did not generate these values" (" " "\000\000" "  " 00))))
    |}];
  Test.with_sample_exn
    (Generator.string_like "The quick brown fox jumps over the lazy dog.")
    ~f:(fun sequence ->
    Sequence.take sequence 30
    |> Sequence.iter ~f:(fun string -> print_s (sexp_of_string string)));
  [%expect
    {|
    "The quick uick brown fox jumps over the lazy dog."
    "The quickdog."
    "The quick brownThe quick brown fox jumps over the lazy dog."
    .
    "The quick brown fmps over the lazy dog."
    "The quick brown fox jumps over the lazy dog./"
    "The quick brown fox jumps over the lazy dog."
    "The quick brown fox jumps over the lazy dog."
    "The quick brown  jumps over the lazy dog."
    "The ThOHQuJyXVs8 TThOHQuXVs8gcTe\255P\000xv\134uV\197p2qysr7fAzjbAWyMdog."
    "The quick brown fox jumps over the lazy dog."
    "The quickL brown fox jdJ=3umps over the lazy dog."
    "The quick brown fox jumps over the lazy dog.brown fox jumps over the lazy dog."
    "The quick brown fox jumps over the lazy dog."
    "The quick brown fox jumps over tox jumps  jumps over tox jumps over the lazy dI7bog."
    "The quick brownzy dog."
    "The quick brown fox jumps over the lazy dog."
    "The quick brown fox jumps over the lazy dog."
    "ThbgX\171e quuick brown fox jumps over the lazy dog."
    "The quick brown fox jumps over the lazy dog."
    "The quick brown fox jumps over the lazy dog."
    "The quick brown fox jumps over the lazy dog."
    "The quick brown fox jumps over the lazy dog."
    "The quick brown fox jumps HjvQyI1e lazy dog."
    "The quick brown fox jumps over the lazy dog."
    "The quick brown fox jumps ov jumps over the lazy dog."
    "TOe quick brown fox jm|tumps over thethe lazy dog."
    "\\\003DuRB9A4O8p~OUoHsP6e\255C44ZQROn4\164ru\03104FN\144wMhD"
    "tg9+W3saM\173ZkL;3KDi\\tmSUMwxY6Y\"PLkM27]fXyN9,'"
    "The quick brown fox jumps over the lazy dog."
    |}]
;;

let bytes = Generator.bytes

let%expect_test "bytes" =
  test_generator ~mode:`inexhaustive Generator.bytes m_bytes;
  [%expect
    {|
    (generator
     ("generated 8_583 distinct values in 10_000 iterations"
      ("did not generate these values" (" " "\000\000" "  " 00 AA __ zz))))
    |}]
;;

let sexp = Generator.sexp

let%expect_test "sexp" =
  test_generator ~mode:`inexhaustive Generator.sexp m_sexp;
  [%expect
    {|
    (generator
     ("generated 7_175 distinct values in 10_000 iterations"
      ("did not generate these values"
       (bc def (a bc def) (a bc def (a) (bc) (def) (a bc def)) (bc) (def)))))
    |}]
;;

let sexp_of = Generator.sexp_of

let%expect_test "sexp_of" =
  test_generator
    ~mode:`inexhaustive
    (Generator.sexp_of (Generator.of_list [ "a"; "bc"; "def" ]))
    m_sexp;
  [%expect
    {|
    (generator
     ("generated 4_917 distinct values in 10_000 iterations"
      ("did not generate these values"
       ((a bc def) (a bc def (a) (bc) (def) (a bc def))))))
    |}]
;;

let list = Generator.list

let%expect_test "list" =
  test_generator (Generator.list Generator.bool) (m_list m_bool);
  [%expect {| (generator "generated 2_248 distinct values in 10_000 iterations") |}]
;;

let list_non_empty = Generator.list_non_empty

let%expect_test "list_non_empty" =
  test_generator
    ~mode:`inexhaustive
    (Generator.list_non_empty Generator.bool)
    (m_list m_bool);
  [%expect
    {|
    (generator
     ("generated 2_672 distinct values in 10_000 iterations"
      ("did not generate these values" (()))))
    |}]
;;

let list_with_length = Generator.list_with_length

let%expect_test "list_with_length" =
  test_generator
    ~mode:`inexhaustive
    (Generator.list_with_length ~length:2 Generator.bool)
    (m_list m_bool);
  [%expect
    {|
    (generator
     ("generated 4 distinct values in 10_000 iterations"
      ("did not generate these values" (() (false) (true)))))
    |}]
;;

let list_filtered = Generator.list_filtered

let%expect_test "list_filtered" =
  let original_list = List.range 1 4 ~start:`inclusive ~stop:`inclusive in
  test_generator
    (Generator.list_filtered original_list)
    (module struct
      type t = int list [@@deriving compare, sexp_of]

      let examples = [ [] ] @ List.map original_list ~f:List.return @ [ original_list ]
    end);
  [%expect {| (generator "generated 16 distinct values in 10_000 iterations") |}]
;;

let list_permutations = Generator.list_permutations

let%expect_test "list_permutations" =
  let original_list = List.range 1 4 ~start:`inclusive ~stop:`inclusive in
  test_generator
    (Generator.list_permutations original_list)
    (module struct
      type t = int list [@@deriving compare, sexp_of]

      let examples = [ original_list; List.rev original_list ]
    end);
  [%expect {| (generator "generated 24 distinct values in 10_000 iterations") |}]
;;

let array = Generator.array

let%expect_test "array" =
  test_generator (Generator.array Generator.bool) (m_array m_bool);
  [%expect {| (generator "generated 2_248 distinct values in 10_000 iterations") |}]
;;

let ref = Generator.ref

let%expect_test "ref" =
  test_generator (Generator.ref Generator.bool) (m_ref m_bool);
  [%expect {| (generator exhaustive) |}]
;;

let lazy_t = Generator.lazy_t

let%expect_test "lazy_t" =
  test_generator (Generator.lazy_t Generator.bool) (m_lazy_t m_bool);
  [%expect {| (generator exhaustive) |}]
;;

let of_lazy = Generator.of_lazy

let%expect_test "of_lazy, forced" =
  test_generator (Generator.of_lazy (lazy Generator.size)) (m_nat ~up_to:30);
  [%expect {| (generator exhaustive) |}]
;;

let%expect_test "of_lazy, unforced" =
  test_generator
    (Generator.weighted_union
       [ Float.max_finite_value, Generator.size
       ; Float.min_positive_subnormal_value, Generator.of_lazy (lazy (assert false))
       ])
    (m_nat ~up_to:30);
  [%expect {| (generator exhaustive) |}]
;;

let bigarray1 = Generator.bigarray1
let bigstring = Generator.bigstring
let float32_vec = Generator.float32_vec
let float64_vec = Generator.float64_vec

let%expect_test "[bigarray1], [bigstring], [float32_vec], [float64_vec]" =
  let test
    (type elt pack layout)
    (t : (elt, pack, layout) Bigarray.Array1.t Generator.t)
    sexp_of_elt
    =
    let module M = struct
      type t = (elt, pack, layout) Bigarray.Array1.t

      let compare = Poly.compare
      let sexp_of_t = [%sexp_of: (elt, _, _) Private.Bigarray_helpers.Array1.t]
      let examples = []
    end
    in
    test_generator t (module M)
  in
  test (bigarray1 float Bigarray.float64 Bigarray.c_layout ~length:None) [%sexp_of: float];
  [%expect {| (generator "generated 7_520 distinct values in 10_000 iterations") |}];
  test
    (bigarray1 float Bigarray.float32 Bigarray.fortran_layout ~length:(Some 3))
    [%sexp_of: float];
  [%expect {| (generator "generated 9_525 distinct values in 10_000 iterations") |}];
  test bigstring [%sexp_of: char];
  [%expect {| (generator "generated 5_751 distinct values in 10_000 iterations") |}];
  test float32_vec [%sexp_of: float];
  [%expect {| (generator "generated 6_670 distinct values in 10_000 iterations") |}];
  test float64_vec [%sexp_of: float];
  [%expect {| (generator "generated 7_520 distinct values in 10_000 iterations") |}]
;;

let bigstring_with_length = Generator.bigstring_with_length
let float32_vec_with_length = Generator.float32_vec_with_length
let float64_vec_with_length = Generator.float64_vec_with_length

let%expect_test "[bigstring_with_length], [float32_vec_with_length], \
                 [float64_vec_with_length]"
  =
  let test t =
    let with_length =
      let open Generator.Let_syntax in
      let%bind length = Generator.small_positive_or_zero_int in
      let%map arr = t ~length in
      arr, length
    in
    Test.with_sample_exn
      with_length
      ~f:
        (Sequence.iter ~f:(fun (sample, expected_length) ->
           Expect_test_helpers_base.require_equal
             [%here]
             (module Int)
             (Bigarray.Array1.dim sample)
             expected_length))
  in
  test bigstring_with_length;
  [%expect {| |}];
  test float32_vec_with_length;
  [%expect {| |}];
  test float64_vec_with_length;
  [%expect {| |}]
;;

let float32_mat = Generator.float32_mat
let float64_mat = Generator.float64_mat

let%expect_test "[float32_mat], [float64_mat]" =
  let test
    (type elt pack layout)
    (t : (elt, pack, layout) Bigarray.Array2.t Generator.t)
    sexp_of_elt
    =
    let module M = struct
      type t = (elt, pack, layout) Bigarray.Array2.t

      let compare = Poly.compare
      let sexp_of_t = [%sexp_of: (elt, _, _) Private.Bigarray_helpers.Array2.t]
      let examples = []
    end
    in
    test_generator t (module M)
  in
  test float32_mat [%sexp_of: float];
  [%expect {| (generator "generated 6_875 distinct values in 10_000 iterations") |}];
  test float64_mat [%sexp_of: float];
  [%expect {| (generator "generated 7_022 distinct values in 10_000 iterations") |}]
;;

module Debug = struct
  let coverage = Generator.Debug.coverage

  let%expect_test "[coverage]" =
    let test config =
      Generator.string_of (Generator.return '.')
      |> Test.with_sample_exn ~config ~f:(fun sample ->
           let counts = coverage (module Int) (Sequence.map sample ~f:String.length) in
           counts |> [%sexp_of: int Map.M(Int).t] |> print_s)
    in
    (* small sample size *)
    test { config with test_count = 3 };
    [%expect {| ((0 1) (1 1) (3 1)) |}];
    (* larger sample size *)
    test { config with test_count = 10 };
    [%expect {| ((0 2) (1 2) (2 1) (3 1) (4 2) (6 1) (10 1)) |}];
    (* nonstandard sizes *)
    test { config with sizes = Sequence.cycle_list_exn [ 1; 2 ] };
    [%expect {| ((0 2466) (1 2534) (2 3304) (3 1696)) |}];
    (* not enough sizes *)
    require_does_raise [%here] (fun () ->
      test { config with sizes = Sequence.init 10 ~f:Fn.id });
    [%expect
      {|
      ("Base_quickcheck.Test.run: insufficient size values for test count"
       (test_count 10000)
       (number_of_size_values 10))
      |}]
  ;;

  let monitor = Generator.Debug.monitor

  let%expect_test "[iter]" =
    let before = Base.ref 0 in
    let after = Base.ref 0 in
    let test n ~f =
      let t =
        bool
        |> monitor ~f:(fun _ -> Int.incr before)
        |> Generator.filter ~f
        |> monitor ~f:(fun _ -> Int.incr after)
      in
      Test.with_sample_exn
        t
        ~config:{ config with test_count = n }
        ~f:(Sequence.iter ~f:ignore);
      print_s [%message "counts" (before : int ref) (after : int ref)]
    in
    let all (_ : bool) = true in
    let half bool = bool in
    test 10 ~f:all;
    [%expect {| (counts (before 10) (after 10)) |}];
    (* state must be reset manually *)
    test 10 ~f:all;
    [%expect {| (counts (before 20) (after 20)) |}];
    before := 0;
    test 0 ~f:all;
    [%expect {| (counts (before 0) (after 20)) |}];
    after := 0;
    test 0 ~f:all;
    [%expect {| (counts (before 0) (after 0)) |}];
    (* [iter] reflects internal behavior such as filtering *)
    test 10 ~f:half;
    [%expect {| (counts (before 16) (after 10)) |}]
  ;;
end
