diff --git a/src/array.mli b/src/array.mli index 907ae3a..0fada86 100644 --- a/src/array.mli +++ b/src/array.mli @@ -12,7 +12,7 @@ include Ppx_compare_lib.Equal.S_local1 with type 'a t := 'a t val globalize : ('a -> 'a) -> 'a t -> 'a t -include Sexplib0.Sexpable.S1 with type 'a t := 'a t +include Sexplib0.Sexpable.S_any1 with type 'a t := 'a t val t_sexp_grammar : 'a Sexplib0.Sexp_grammar.t -> 'a t Sexplib0.Sexp_grammar.t diff --git a/src/bool.mli b/src/bool.mli index 47c7fea..2892958 100644 --- a/src/bool.mli +++ b/src/bool.mli @@ -9,7 +9,7 @@ include Ppx_enumerate_lib.Enumerable.S with type t := t val globalize : t -> t -include Sexplib0.Sexpable.S with type t := t +include Sexplib0.Sexpable.S_any with type t := t val t_sexp_grammar : t Sexplib0.Sexp_grammar.t diff --git a/src/bytes_intf.ml b/src/bytes_intf.ml index 2d19700..b032f32 100644 --- a/src/bytes_intf.ml +++ b/src/bytes_intf.ml @@ -22,7 +22,7 @@ module type Bytes = sig val globalize : t -> t - include Sexplib0.Sexpable.S with type t := t + include Sexplib0.Sexpable.S_any with type t := t val t_sexp_grammar : t Sexplib0.Sexp_grammar.t diff --git a/src/char.mli b/src/char.mli index 75d881e..2c6d939 100644 --- a/src/char.mli +++ b/src/char.mli @@ -9,7 +9,7 @@ include Ppx_enumerate_lib.Enumerable.S with type t := t val globalize : t -> t -include Sexplib0.Sexpable.S with type t := t +include Sexplib0.Sexpable.S_any with type t := t val t_sexp_grammar : t Sexplib0.Sexp_grammar.t @@ -95,7 +95,7 @@ module Caseless : sig type nonrec t = t [@@deriving_inline hash, sexp, sexp_grammar] include Ppx_hash_lib.Hashable.S with type t := t - include Sexplib0.Sexpable.S with type t := t + include Sexplib0.Sexpable.S_any with type t := t val t_sexp_grammar : t Sexplib0.Sexp_grammar.t diff --git a/src/dictionary_mutable_intf.ml b/src/dictionary_mutable_intf.ml index eb7375a..b9e6d94 100644 --- a/src/dictionary_mutable_intf.ml +++ b/src/dictionary_mutable_intf.ml @@ -381,7 +381,10 @@ module Definitions = struct -> ('key, 'c, 'phantom) t * ('key, 'd, 'phantom) t (** Merges two dictionaries by fully traversing both. Not suitable for efficiently - merging lists of dictionaries. See [merge_into] instead. *) + merging lists of dictionaries. See [merge_into] instead. + + If the two dictionaries differ in their implementations, e.g. of [hash] or + [compare] functions, those from the first argument are preferred. *) val merge : ( ('key, 'data1, 'phantom) t -> ('key, 'data2, 'phantom) t diff --git a/src/exn.ml b/src/exn.ml index 3b31f34..7c632c3 100644 --- a/src/exn.ml +++ b/src/exn.ml @@ -34,7 +34,7 @@ let () = [@@@end] -exception Sexp of Sexp.t +exception Sexp of Sexp.t Lazy.t (* We install a custom exn-converter rather than use: @@ -47,13 +47,14 @@ exception Sexp of Sexp.t to eliminate the extra wrapping of [(Sexp ...)]. *) let () = Sexplib0.Sexp_conv.Exn_converter.add [%extension_constructor Sexp] (function - | Sexp t -> t + | Sexp t -> Lazy.force t | _ -> (* Reaching this branch indicates a bug in sexplib. *) assert false) ;; -let create_s sexp = Sexp sexp +let create_s sexp = Sexp (Lazy.from_val sexp) +let create_s_lazy lazy_sexp = Sexp lazy_sexp let raise_with_original_backtrace t backtrace = Stdlib.Printexc.raise_with_backtrace t backtrace diff --git a/src/exn.mli b/src/exn.mli index ef4d087..1ae00bc 100644 --- a/src/exn.mli +++ b/src/exn.mli @@ -27,6 +27,9 @@ exception Reraised of string * t particular exn constructor doesn't matter. *) val create_s : Sexp.t -> t +(** [create_s_lazy lazy_sexp] is like [create_s], but takes a lazily generated sexp. *) +val create_s_lazy : Sexp.t Lazy.t -> t + (** Same as [raise], except that the backtrace is not recorded. *) val raise_without_backtrace : t -> _ diff --git a/src/float.mli b/src/float.mli index 90ee747..8c72f7a 100644 --- a/src/float.mli +++ b/src/float.mli @@ -700,7 +700,7 @@ val ieee_mantissa : t -> Int63.t module Terse : sig type nonrec t = t [@@deriving_inline sexp, sexp_grammar] - include Sexplib0.Sexpable.S with type t := t + include Sexplib0.Sexpable.S_any with type t := t val t_sexp_grammar : t Sexplib0.Sexp_grammar.t diff --git a/src/hash_set_intf.ml b/src/hash_set_intf.ml index 83f3798..9d7e36c 100644 --- a/src/hash_set_intf.ml +++ b/src/hash_set_intf.ml @@ -172,7 +172,7 @@ module type Hash_set = sig module Poly : sig type nonrec 'a t = 'a t [@@deriving_inline sexp, sexp_grammar] - include Sexplib0.Sexpable.S1 with type 'a t := 'a t + include Sexplib0.Sexpable.S_any1 with type 'a t := 'a t val t_sexp_grammar : 'a Sexplib0.Sexp_grammar.t -> 'a t Sexplib0.Sexp_grammar.t diff --git a/src/hashtbl.ml b/src/hashtbl.ml index 63af8a7..4e4a988 100644 --- a/src/hashtbl.ml +++ b/src/hashtbl.ml @@ -638,11 +638,9 @@ let merge = let maybe_set t ~key ~f d = match f ~key d with | None -> () - | Some v -> set t ~key ~data:v + | Some v -> add_exn t ~key ~data:v in fun t_left t_right ~f -> - if not (Hashable.equal t_left.hashable t_right.hashable) - then invalid_arg "Hashtbl.merge: different 'hashable' values"; let new_t = create ~growth_allowed:t_left.growth_allowed diff --git a/src/indexed_container.ml b/src/indexed_container.ml index d216721..cb2e7b7 100644 --- a/src/indexed_container.ml +++ b/src/indexed_container.ml @@ -152,6 +152,27 @@ struct let filteri t ~f = filter_mapi t ~f:(fun i x -> if f i x then Some x else None) [@nontail] ;; + + let partition_mapi t ~f = + let array = Array.mapi (to_array t) ~f in + let xs = + Array.fold_right array ~init:[] ~f:(fun either acc -> + match (either : _ Either0.t) with + | First x -> x :: acc + | Second _ -> acc) + in + let ys = + Array.fold_right array ~init:[] ~f:(fun either acc -> + match (either : _ Either0.t) with + | First _ -> acc + | Second x -> x :: acc) + in + of_list xs, of_list ys + ;; + + let partitioni_tf t ~f = + partition_mapi t ~f:(fun i x -> if f i x then First x else Second x) [@nontail] + ;; end module Make_with_creators (T : Make_with_creators_arg) = struct diff --git a/src/indexed_container_intf.ml b/src/indexed_container_intf.ml index c843130..31ea0a6 100644 --- a/src/indexed_container_intf.ml +++ b/src/indexed_container_intf.ml @@ -71,6 +71,14 @@ module type S0_with_creators = sig (** [concat_mapi t ~f] is like concat_map. Additionally, it passes the index as an argument. *) val concat_mapi : t -> f:(int -> elt -> t) -> t + + (** [partitioni_tf t ~f] is like partition_tf. Additionally, it passes the index as an + argument. *) + val partitioni_tf : t -> f:(int -> elt -> bool) -> t * t + + (** [partition_mapi t ~f] is like partition_map. Additionally, it passes the index as an + argument. *) + val partition_mapi : t -> f:(int -> elt -> (elt, elt) Either0.t) -> t * t end module type S1_with_creators = sig @@ -94,6 +102,14 @@ module type S1_with_creators = sig (** [concat_mapi t ~f] is like concat_map. Additionally, it passes the index as an argument. *) val concat_mapi : 'a t -> f:(int -> 'a -> 'b t) -> 'b t + + (** [partitioni_tf t ~f] is like partition_tf. Additionally, it passes the index as an + argument. *) + val partitioni_tf : 'a t -> f:(int -> 'a -> bool) -> 'a t * 'a t + + (** [partition_mapi t ~f] is like partition_map. Additionally, it passes the index as an + argument. *) + val partition_mapi : 'a t -> f:(int -> 'a -> ('b, 'c) Either0.t) -> 'b t * 'c t end module type Generic_with_creators = sig @@ -117,6 +133,16 @@ module type Generic_with_creators = sig : ('a, 'p1, 'p2) t -> f:(int -> 'a elt -> ('b, 'p1, 'p2) t) -> ('b, 'p1, 'p2) t + + val partitioni_tf + : ('a, 'p1, 'p2) t + -> f:(int -> 'a elt -> bool) + -> ('a, 'p1, 'p2) t * ('a, 'p1, 'p2) t + + val partition_mapi + : ('a, 'p1, 'p2) t + -> f:(int -> 'a elt -> ('b elt, 'c elt) Either0.t) + -> ('b, 'p1, 'p2) t * ('c, 'p1, 'p2) t end module type Make_gen_arg = sig diff --git a/src/lazy.mli b/src/lazy.mli index dbd5575..f584992 100644 --- a/src/lazy.mli +++ b/src/lazy.mli @@ -32,7 +32,7 @@ include Ppx_compare_lib.Equal.S_local1 with type 'a t := 'a t val globalize : ('a -> 'a) -> 'a t -> 'a t include Ppx_hash_lib.Hashable.S1 with type 'a t := 'a t -include Sexplib0.Sexpable.S1 with type 'a t := 'a t +include Sexplib0.Sexpable.S_any1 with type 'a t := 'a t val t_sexp_grammar : 'a Sexplib0.Sexp_grammar.t -> 'a t Sexplib0.Sexp_grammar.t diff --git a/src/list.ml b/src/list.ml index aa15850..14d1e2c 100644 --- a/src/list.ml +++ b/src/list.ml @@ -1181,6 +1181,23 @@ let partition_tf t ~f = let partition_result t = partition_map t ~f:Result.to_either +let partition_mapi t ~f = + let rec loop i t fst snd = + match t with + | [] -> rev fst, rev snd + | x :: t -> + (match (f i x : _ Either0.t) with + | First y -> loop (i + 1) t (y :: fst) snd + | Second y -> loop (i + 1) t fst (y :: snd)) + in + loop 0 t [] [] [@nontail] +;; + +let partitioni_tf t ~f = + let f i x : _ Either.t = if f i x then First x else Second x in + partition_mapi t ~f [@nontail] +;; + module Assoc = struct type 'a key = ('a[@tag Sexplib0.Sexp_grammar.assoc_key_tag = List []]) [@@deriving_inline sexp, sexp_grammar] diff --git a/src/list.mli b/src/list.mli index f4ca91f..2385342 100644 --- a/src/list.mli +++ b/src/list.mli @@ -16,7 +16,7 @@ include Ppx_compare_lib.Equal.S_local1 with type 'a t := 'a t val globalize : ('a -> 'a) -> 'a t -> 'a t include Ppx_hash_lib.Hashable.S1 with type 'a t := 'a t -include Sexplib0.Sexpable.S1 with type 'a t := 'a t +include Sexplib0.Sexpable.S_any1 with type 'a t := 'a t val t_sexp_grammar : 'a Sexplib0.Sexp_grammar.t -> 'a t Sexplib0.Sexp_grammar.t @@ -401,7 +401,7 @@ val filter_opt : 'a option t -> 'a t module Assoc : sig type ('a, 'b) t = ('a * 'b) list [@@deriving_inline sexp, sexp_grammar] - include Sexplib0.Sexpable.S2 with type ('a, 'b) t := ('a, 'b) t + include Sexplib0.Sexpable.S_any2 with type ('a, 'b) t := ('a, 'b) t val t_sexp_grammar : 'a Sexplib0.Sexp_grammar.t diff --git a/src/map_intf.ml b/src/map_intf.ml index 2402d9f..1281c83 100644 --- a/src/map_intf.ml +++ b/src/map_intf.ml @@ -1323,7 +1323,7 @@ module type Map = sig include Ppx_compare_lib.Comparable.S2 with type ('k, 'v) t := ('k, 'v) t include Ppx_compare_lib.Equal.S2 with type ('k, 'v) t := ('k, 'v) t - include Sexplib0.Sexpable.S2 with type ('k, 'v) t := ('k, 'v) t + include Sexplib0.Sexpable.S_any2 with type ('k, 'v) t := ('k, 'v) t val t_sexp_grammar : 'k Sexplib0.Sexp_grammar.t diff --git a/src/option.ml b/src/option.ml index 84b31f3..dbb5ed3 100644 --- a/src/option.ml +++ b/src/option.ml @@ -46,7 +46,7 @@ sig val globalize : ('a -> 'a) -> 'a t -> 'a t include Ppx_hash_lib.Hashable.S1 with type 'a t := 'a t - include Sexplib0.Sexpable.S1 with type 'a t := 'a t + include Sexplib0.Sexpable.S_any1 with type 'a t := 'a t val t_sexp_grammar : 'a Sexplib0.Sexp_grammar.t -> 'a t Sexplib0.Sexp_grammar.t diff --git a/src/or_error.mli b/src/or_error.mli index 36a0d57..3bed53c 100644 --- a/src/or_error.mli +++ b/src/or_error.mli @@ -21,7 +21,7 @@ include Ppx_compare_lib.Equal.S_local1 with type 'a t := 'a t val globalize : ('a -> 'a) -> 'a t -> 'a t include Ppx_hash_lib.Hashable.S1 with type 'a t := 'a t -include Sexplib0.Sexpable.S1 with type 'a t := 'a t +include Sexplib0.Sexpable.S_any1 with type 'a t := 'a t val t_sexp_grammar : 'a Sexplib0.Sexp_grammar.t -> 'a t Sexplib0.Sexp_grammar.t diff --git a/src/ref.ml b/src/ref.ml index bb91513..ef1e787 100644 --- a/src/ref.ml +++ b/src/ref.ml @@ -34,7 +34,7 @@ sig val globalize : ('a -> 'a) -> 'a t -> 'a t - include Sexplib0.Sexpable.S1 with type 'a t := 'a t + include Sexplib0.Sexpable.S_any1 with type 'a t := 'a t val t_sexp_grammar : 'a Sexplib0.Sexp_grammar.t -> 'a t Sexplib0.Sexp_grammar.t diff --git a/src/string.ml b/src/string.ml index ca73bee..0108145 100644 --- a/src/string.ml +++ b/src/string.ml @@ -1261,11 +1261,11 @@ include struct open struct (* partition helpers *) - let partition_map_into src ~fsts ~snds ~f ~len ~src_pos ~fst_pos ~snd_pos = + let partition_mapi_into src ~fsts ~snds ~f ~len ~src_pos ~fst_pos ~snd_pos = let fst_pos = ref fst_pos in let snd_pos = ref snd_pos in for src_pos = src_pos to len - 1 do - match (f (unsafe_get src src_pos) : (_, _) Either.t) with + match (f src_pos (unsafe_get src src_pos) : (_, _) Either.t) with | First c -> Bytes.unsafe_set fsts !fst_pos c; incr fst_pos @@ -1276,7 +1276,7 @@ include struct local_copy_to_string fsts ~pos:!fst_pos, local_copy_to_string snds ~pos:!snd_pos ;; - let partition_map_difference src ~f ~len ~pos:src_pos ~fst_pos ~snd_pos either = + let partition_mapi_difference src ~f ~len ~pos:src_pos ~fst_pos ~snd_pos either = let fsts = local_copy_prefix src ~prefix_len:fst_pos ~buffer_len:len in let snds = local_copy_prefix src ~prefix_len:snd_pos ~buffer_len:len in let fst_pos, snd_pos = @@ -1288,7 +1288,7 @@ include struct Bytes.unsafe_set snds snd_pos c; fst_pos, snd_pos + 1 in - partition_map_into + partition_mapi_into src ~fsts ~snds @@ -1299,16 +1299,16 @@ include struct ~snd_pos [@nontail] ;; - let rec partition_map_first_maybe_id src ~f ~pos ~len = + let rec partition_mapi_first_maybe_id src ~f ~pos ~len = if pos = len then src, "" else ( let c1 = unsafe_get src pos in - match (f c1 : (_, _) Either.t) with + match (f pos c1 : (_, _) Either.t) with | First c2 when Char.equal c1 c2 -> - partition_map_first_maybe_id src ~f ~len ~pos:(pos + 1) + partition_mapi_first_maybe_id src ~f ~len ~pos:(pos + 1) | either -> - partition_map_difference + partition_mapi_difference src ~f ~len @@ -1318,16 +1318,16 @@ include struct either [@nontail]) ;; - let rec partition_map_second_maybe_id src ~f ~pos ~len = + let rec partition_mapi_second_maybe_id src ~f ~pos ~len = if pos = len then "", src else ( let c1 = unsafe_get src pos in - match (f c1 : (_, _) Either.t) with + match (f pos c1 : (_, _) Either.t) with | Second c2 when Char.equal c1 c2 -> - partition_map_second_maybe_id src ~f ~len ~pos:(pos + 1) + partition_mapi_second_maybe_id src ~f ~len ~pos:(pos + 1) | either -> - partition_map_difference + partition_mapi_difference src ~f ~len @@ -1340,18 +1340,18 @@ include struct (* partition functions *) - let partition_map src ~f = + let partition_mapi src ~f = let len = length src in if len = 0 then "", "" else ( let c1 = unsafe_get src 0 in - match (f c1 : (_, _) Either.t) with - | First c2 when Char.equal c1 c2 -> partition_map_first_maybe_id src ~f ~len ~pos:1 + match (f 0 c1 : (_, _) Either.t) with + | First c2 when Char.equal c1 c2 -> partition_mapi_first_maybe_id src ~f ~len ~pos:1 | Second c2 when Char.equal c1 c2 -> - partition_map_second_maybe_id src ~f ~len ~pos:1 + partition_mapi_second_maybe_id src ~f ~len ~pos:1 | either -> - partition_map_difference + partition_mapi_difference src ~f ~len @@ -1361,9 +1361,12 @@ include struct either [@nontail]) ;; - let partition_tf t ~f = - partition_map t ~f:(fun c -> if f c then First c else Second c) [@nontail] + let partitioni_tf t ~f = + partition_mapi t ~f:(fun i c -> if f i c then First c else Second c) [@nontail] ;; + + let partition_tf t ~f = partitioni_tf t ~f:(fun _ c -> f c) [@nontail] + let partition_map t ~f = partition_mapi t ~f:(fun _ c -> f c) [@nontail] end let edit_distance s1 s2 = @@ -2068,7 +2071,9 @@ struct let mem = C.mem let min_elt = C.min_elt let partition_map = C.partition_map + let partition_mapi = C.partition_mapi let partition_tf = C.partition_tf + let partitioni_tf = C.partitioni_tf let sum = C.sum let to_array = C.to_array let to_list = C.to_list diff --git a/src/string_intf.ml b/src/string_intf.ml index bbc2229..d25f465 100644 --- a/src/string_intf.ml +++ b/src/string_intf.ml @@ -88,7 +88,7 @@ module type String = sig val globalize : t -> t - include Sexplib0.Sexpable.S with type t := t + include Sexplib0.Sexpable.S_any with type t := t val t_sexp_grammar : t Sexplib0.Sexp_grammar.t @@ -164,7 +164,7 @@ module type String = sig type nonrec t = t [@@deriving_inline hash, sexp, sexp_grammar] include Ppx_hash_lib.Hashable.S with type t := t - include Sexplib0.Sexpable.S with type t := t + include Sexplib0.Sexpable.S_any with type t := t val t_sexp_grammar : t Sexplib0.Sexp_grammar.t diff --git a/src/uchar_intf.ml b/src/uchar_intf.ml index ed0a9e4..dd7e905 100644 --- a/src/uchar_intf.ml +++ b/src/uchar_intf.ml @@ -29,7 +29,7 @@ module type Uchar = sig type t = Uchar0.t [@@deriving_inline hash, sexp, sexp_grammar] include Ppx_hash_lib.Hashable.S with type t := t - include Sexplib0.Sexpable.S with type t := t + include Sexplib0.Sexpable.S_any with type t := t val t_sexp_grammar : t Sexplib0.Sexp_grammar.t diff --git a/src/unit.mli b/src/unit.mli index d5889dd..de53afd 100644 --- a/src/unit.mli +++ b/src/unit.mli @@ -8,7 +8,7 @@ include Ppx_enumerate_lib.Enumerable.S with type t := t val globalize : t -> t -include Sexplib0.Sexpable.S with type t := t +include Sexplib0.Sexpable.S_any with type t := t val t_sexp_grammar : t Sexplib0.Sexp_grammar.t diff --git a/test/allocation/test_option_allocation.ml b/test/allocation/test_option_allocation.ml index d7866fc..12f2141 100644 --- a/test/allocation/test_option_allocation.ml +++ b/test/allocation/test_option_allocation.ml @@ -2,142 +2,140 @@ open! Base open Base_quickcheck.Export open Expect_test_helpers_core -let%test_module "local mode vs global mode" = - (module struct - module type Input = sig - type t [@@deriving quickcheck, sexp_of] - end +module%test [@name "local mode vs global mode"] _ = struct + module type Input = sig + type t [@@deriving quickcheck, sexp_of] + end - module type Output = sig - type t [@@deriving equal, globalize, sexp_of] - end + module type Output = sig + type t [@@deriving equal, globalize, sexp_of] + end - let test - (type input output) - (module Input : Input with type t = input) - (module Output : Output with type t = output) - ~local:(fn_local : Input.t -> Output.t) - ~global:(fn_global : Input.t -> Output.t) - = - quickcheck_m - (module Input) - ~f:(fun input -> - require_equal - (module struct - type t = Output.t Or_error.t [@@deriving equal, sexp_of] - end) - (Or_error.try_with (fun () -> - [%globalize: Output.t] - (require_no_allocation_local (fun () -> fn_local input)) [@nontail])) - (Or_error.try_with (fun () -> fn_global input))) - ;; + let test + (type input output) + (module Input : Input with type t = input) + (module Output : Output with type t = output) + ~local:(fn_local : Input.t -> Output.t) + ~global:(fn_global : Input.t -> Output.t) + = + quickcheck_m + (module Input) + ~f:(fun input -> + require_equal + (module struct + type t = Output.t Or_error.t [@@deriving equal, sexp_of] + end) + (Or_error.try_with (fun () -> + [%globalize: Output.t] + (require_no_allocation_local (fun () -> fn_local input)) [@nontail])) + (Or_error.try_with (fun () -> fn_global input))) + ;; - let%expect_test "value_local" = - test - ~local:(Option.value_local ~default:0) - ~global:(Option.value ~default:0) - (module struct - type t = int option [@@deriving quickcheck, sexp_of] - end) - (module struct - type t = int [@@deriving equal, globalize, sexp_of] - end) - ;; + let%expect_test "value_local" = + test + ~local:(Option.value_local ~default:0) + ~global:(Option.value ~default:0) + (module struct + type t = int option [@@deriving quickcheck, sexp_of] + end) + (module struct + type t = int [@@deriving equal, globalize, sexp_of] + end) + ;; - let%expect_test "value_local_exn" = - test - ~local:Option.value_local_exn - ~global:Option.value_exn - (module struct - type t = int option [@@deriving quickcheck, sexp_of] - end) - (module struct - type t = int [@@deriving equal, globalize, sexp_of] - end) - ;; + let%expect_test "value_local_exn" = + test + ~local:Option.value_local_exn + ~global:Option.value_exn + (module struct + type t = int option [@@deriving quickcheck, sexp_of] + end) + (module struct + type t = int [@@deriving equal, globalize, sexp_of] + end) + ;; - let%expect_test "value_map_local" = - test - ~local:(Option.value_map_local ~f:(fun x -> x + 1) ~default:0) - ~global:(Option.value_map ~f:(fun x -> x + 1) ~default:0) - (module struct - type t = int option [@@deriving quickcheck, sexp_of] - end) - (module struct - type t = int [@@deriving equal, globalize, sexp_of] - end) - ;; + let%expect_test "value_map_local" = + test + ~local:(Option.value_map_local ~f:(fun x -> x + 1) ~default:0) + ~global:(Option.value_map ~f:(fun x -> x + 1) ~default:0) + (module struct + type t = int option [@@deriving quickcheck, sexp_of] + end) + (module struct + type t = int [@@deriving equal, globalize, sexp_of] + end) + ;; - let%expect_test "value_or_thunk_local" = - test - ~local:(Option.value_or_thunk_local ~default:(fun () -> 0)) - ~global:(Option.value_or_thunk ~default:(fun () -> 0)) - (module struct - type t = int option [@@deriving quickcheck, sexp_of] - end) - (module struct - type t = int [@@deriving equal, globalize, sexp_of] - end) - ;; + let%expect_test "value_or_thunk_local" = + test + ~local:(Option.value_or_thunk_local ~default:(fun () -> 0)) + ~global:(Option.value_or_thunk ~default:(fun () -> 0)) + (module struct + type t = int option [@@deriving quickcheck, sexp_of] + end) + (module struct + type t = int [@@deriving equal, globalize, sexp_of] + end) + ;; - let%expect_test "map_local" = - test - ~local:(Option.map_local ~f:(fun x -> x + 1)) - ~global:(Option.map ~f:(fun x -> x + 1)) - (module struct - type t = int option [@@deriving quickcheck, sexp_of] - end) - (module struct - type t = int option [@@deriving equal, globalize, sexp_of] - end) - ;; + let%expect_test "map_local" = + test + ~local:(Option.map_local ~f:(fun x -> x + 1)) + ~global:(Option.map ~f:(fun x -> x + 1)) + (module struct + type t = int option [@@deriving quickcheck, sexp_of] + end) + (module struct + type t = int option [@@deriving equal, globalize, sexp_of] + end) + ;; - let%expect_test "to_list_local" = - test - ~local:Option.to_list_local - ~global:Option.to_list - (module struct - type t = int option [@@deriving quickcheck, sexp_of] - end) - (module struct - type t = int list [@@deriving equal, globalize, sexp_of] - end) - ;; + let%expect_test "to_list_local" = + test + ~local:Option.to_list_local + ~global:Option.to_list + (module struct + type t = int option [@@deriving quickcheck, sexp_of] + end) + (module struct + type t = int list [@@deriving equal, globalize, sexp_of] + end) + ;; - let%expect_test "some_local" = - test - ~local:Option.some_local - ~global:Option.some - (module struct - type t = int [@@deriving quickcheck, sexp_of] - end) - (module struct - type t = int option [@@deriving equal, globalize, sexp_of] - end) - ;; + let%expect_test "some_local" = + test + ~local:Option.some_local + ~global:Option.some + (module struct + type t = int [@@deriving quickcheck, sexp_of] + end) + (module struct + type t = int option [@@deriving equal, globalize, sexp_of] + end) + ;; - let%expect_test "first_some_local" = - test - ~local:(fun (x, y) -> Option.first_some_local x y) - ~global:(fun (x, y) -> Option.first_some x y) - (module struct - type t = int option * int option [@@deriving quickcheck, sexp_of] - end) - (module struct - type t = int option [@@deriving equal, globalize, sexp_of] - end) - ;; + let%expect_test "first_some_local" = + test + ~local:(fun (x, y) -> Option.first_some_local x y) + ~global:(fun (x, y) -> Option.first_some x y) + (module struct + type t = int option * int option [@@deriving quickcheck, sexp_of] + end) + (module struct + type t = int option [@@deriving equal, globalize, sexp_of] + end) + ;; - let%expect_test "some_if_local" = - test - ~local:(fun (b, i) -> Option.some_if_local b i) - ~global:(fun (b, i) -> Option.some_if b i) - (module struct - type t = bool * int [@@deriving quickcheck, sexp_of] - end) - (module struct - type t = int option [@@deriving equal, globalize, sexp_of] - end) - ;; - end) -;; + let%expect_test "some_if_local" = + test + ~local:(fun (b, i) -> Option.some_if_local b i) + ~global:(fun (b, i) -> Option.some_if b i) + (module struct + type t = bool * int [@@deriving quickcheck, sexp_of] + end) + (module struct + type t = int option [@@deriving equal, globalize, sexp_of] + end) + ;; +end diff --git a/test/allocation/test_string_allocation.ml b/test/allocation/test_string_allocation.ml index 095c0f0..04f9417 100644 --- a/test/allocation/test_string_allocation.ml +++ b/test/allocation/test_string_allocation.ml @@ -46,134 +46,130 @@ let%expect_test "foldi does not allocate" = [%expect {| |}] ;; -let%test_module "common prefix and suffix" = - (module struct - let require_int_equal a b ~message = require_equal (module Int) a b ~message - let require_string_equal a b ~message = require_equal (module String) a b ~message - - let simulate_common_length ~get_common2_length list = - let rec loop acc prev list ~get_common2_length = - match list with - | [] -> acc - | head :: tail -> - loop (Int.min acc (get_common2_length prev head)) head tail ~get_common2_length - in +module%test [@name "common prefix and suffix"] _ = struct + let require_int_equal a b ~message = require_equal (module Int) a b ~message + let require_string_equal a b ~message = require_equal (module String) a b ~message + + let simulate_common_length ~get_common2_length list = + let rec loop acc prev list ~get_common2_length = match list with - | [] -> 0 - | [ head ] -> String.length head - | head :: tail -> loop Int.max_value head tail ~get_common2_length - ;; - - let get_shortest_and_longest list = - let compare_by_length a b = Comparable.lift Int.compare ~f:String.length a b in - Option.both - (List.min_elt list ~compare:compare_by_length) - (List.max_elt list ~compare:compare_by_length) - ;; - - let test_generic get_common get_common2 get_common_length get_common2_length = - Staged.stage (fun list -> - let common = get_common list in - print_s [%sexp (common : string)]; - let len = get_common_length list in - require_int_equal len (String.length common) ~message:"wrong length"; - let common2 = List.reduce list ~f:get_common2 |> Option.value ~default:"" in - require_string_equal common common2 ~message:"pairwise result mismatch"; - let len2 = simulate_common_length ~get_common2_length list in - require_int_equal len len2 ~message:"pairwise length mismatch"; - if not (String.is_empty common || List.mem list common ~equal:String.equal) - then print_endline "(may allocate)" - else ( - ignore (require_no_allocation (fun () -> get_common list) : string); - Option.iter (get_shortest_and_longest list) ~f:(fun (shortest, longest) -> - ignore - (require_no_allocation (fun () -> get_common2 shortest longest) : string); - ignore - (require_no_allocation (fun () -> get_common2 longest shortest) : string)))) - ;; - - let test_prefix = - test_generic - String.common_prefix - String.common_prefix2 - String.common_prefix_length - String.common_prefix2_length - |> Staged.unstage - ;; - - let test_suffix = - test_generic - String.common_suffix - String.common_suffix2 - String.common_suffix_length - String.common_suffix2_length - |> Staged.unstage - ;; - - let%expect_test "empty" = - test_prefix []; - [%expect {| "" |}]; - test_suffix []; - [%expect {| "" |}] - ;; - - let%expect_test "singleton" = - test_prefix [ "abut" ]; - [%expect {| abut |}]; - test_suffix [ "tuba" ]; - [%expect {| tuba |}] - ;; - - let%expect_test "doubleton, alloc" = - test_prefix [ "hello"; "help"; "hex" ]; - [%expect - {| - he - (may allocate) - |}]; - test_suffix [ "crest"; "zest"; "1st" ]; - [%expect - {| - st - (may allocate) - |}] - ;; - - let%expect_test "doubleton, no alloc" = - test_prefix [ "hello"; "help"; "he" ]; - [%expect {| he |}]; - test_suffix [ "crest"; "zest"; "st" ]; - [%expect {| st |}] - ;; - - let%expect_test "many, alloc" = - test_prefix [ "this"; "that"; "the other"; "these"; "those"; "thy"; "thou" ]; - [%expect - {| - th - (may allocate) - |}]; - test_suffix [ "fourth"; "fifth"; "sixth"; "seventh"; "eleventh"; "twelfth" ]; - [%expect - {| - th - (may allocate) - |}] - ;; - - let%expect_test "many, no alloc" = - test_prefix [ "inconsequential"; "invariant"; "in"; "inner"; "increment" ]; - [%expect {| in |}]; - test_suffix [ "fat"; "cat"; "sat"; "at"; "bat" ]; - [%expect {| at |}] - ;; - - let%expect_test "many, nothing in common" = - let lorem_ipsum = [ "lorem"; "ipsum"; "dolor"; "sit"; "amet" ] in - test_prefix lorem_ipsum; - [%expect {| "" |}]; - test_suffix lorem_ipsum; - [%expect {| "" |}] - ;; - end) -;; + | [] -> acc + | head :: tail -> + loop (Int.min acc (get_common2_length prev head)) head tail ~get_common2_length + in + match list with + | [] -> 0 + | [ head ] -> String.length head + | head :: tail -> loop Int.max_value head tail ~get_common2_length + ;; + + let get_shortest_and_longest list = + let compare_by_length a b = Comparable.lift Int.compare ~f:String.length a b in + Option.both + (List.min_elt list ~compare:compare_by_length) + (List.max_elt list ~compare:compare_by_length) + ;; + + let test_generic get_common get_common2 get_common_length get_common2_length = + Staged.stage (fun list -> + let common = get_common list in + print_s [%sexp (common : string)]; + let len = get_common_length list in + require_int_equal len (String.length common) ~message:"wrong length"; + let common2 = List.reduce list ~f:get_common2 |> Option.value ~default:"" in + require_string_equal common common2 ~message:"pairwise result mismatch"; + let len2 = simulate_common_length ~get_common2_length list in + require_int_equal len len2 ~message:"pairwise length mismatch"; + if not (String.is_empty common || List.mem list common ~equal:String.equal) + then print_endline "(may allocate)" + else ( + ignore (require_no_allocation (fun () -> get_common list) : string); + Option.iter (get_shortest_and_longest list) ~f:(fun (shortest, longest) -> + ignore (require_no_allocation (fun () -> get_common2 shortest longest) : string); + ignore (require_no_allocation (fun () -> get_common2 longest shortest) : string)))) + ;; + + let test_prefix = + test_generic + String.common_prefix + String.common_prefix2 + String.common_prefix_length + String.common_prefix2_length + |> Staged.unstage + ;; + + let test_suffix = + test_generic + String.common_suffix + String.common_suffix2 + String.common_suffix_length + String.common_suffix2_length + |> Staged.unstage + ;; + + let%expect_test "empty" = + test_prefix []; + [%expect {| "" |}]; + test_suffix []; + [%expect {| "" |}] + ;; + + let%expect_test "singleton" = + test_prefix [ "abut" ]; + [%expect {| abut |}]; + test_suffix [ "tuba" ]; + [%expect {| tuba |}] + ;; + + let%expect_test "doubleton, alloc" = + test_prefix [ "hello"; "help"; "hex" ]; + [%expect + {| + he + (may allocate) + |}]; + test_suffix [ "crest"; "zest"; "1st" ]; + [%expect + {| + st + (may allocate) + |}] + ;; + + let%expect_test "doubleton, no alloc" = + test_prefix [ "hello"; "help"; "he" ]; + [%expect {| he |}]; + test_suffix [ "crest"; "zest"; "st" ]; + [%expect {| st |}] + ;; + + let%expect_test "many, alloc" = + test_prefix [ "this"; "that"; "the other"; "these"; "those"; "thy"; "thou" ]; + [%expect + {| + th + (may allocate) + |}]; + test_suffix [ "fourth"; "fifth"; "sixth"; "seventh"; "eleventh"; "twelfth" ]; + [%expect + {| + th + (may allocate) + |}] + ;; + + let%expect_test "many, no alloc" = + test_prefix [ "inconsequential"; "invariant"; "in"; "inner"; "increment" ]; + [%expect {| in |}]; + test_suffix [ "fat"; "cat"; "sat"; "at"; "bat" ]; + [%expect {| at |}] + ;; + + let%expect_test "many, nothing in common" = + let lorem_ipsum = [ "lorem"; "ipsum"; "dolor"; "sit"; "amet" ] in + test_prefix lorem_ipsum; + [%expect {| "" |}]; + test_suffix lorem_ipsum; + [%expect {| "" |}] + ;; +end diff --git a/test/avltree_unit_tests.ml b/test/avltree_unit_tests.ml index a7b03f7..f2da4c1 100644 --- a/test/avltree_unit_tests.ml +++ b/test/avltree_unit_tests.ml @@ -1,401 +1,395 @@ open! Import -let%test_module _ = - (module ( - struct - open Avltree - - type ('k, 'v) t = ('k, 'v) Avltree.t = private - | Empty - | Node of - { mutable left : ('k, 'v) t - ; key : 'k - ; mutable value : 'v - ; mutable height : int - ; mutable right : ('k, 'v) t - } - | Leaf of - { key : 'k - ; mutable value : 'v - } - - module For_quickcheck = struct - module Key = struct - include Int - - type t = int [@@deriving quickcheck] - - let quickcheck_generator = Base_quickcheck.Generator.small_positive_or_zero_int - end - - module Data = struct - include String - - type t = string [@@deriving quickcheck] - - let quickcheck_generator = - Base_quickcheck.Generator.string_of Base_quickcheck.Generator.char_lowercase - ;; - end - - let compare = Key.compare - - module Constructor = struct - type t = - | Add of Key.t * Data.t - | Replace of Key.t * Data.t - | Remove of Key.t - [@@deriving quickcheck, sexp_of] +module%test _ : module type of Avltree = struct + open Avltree + + type ('k, 'v) t = ('k, 'v) Avltree.t = private + | Empty + | Node of + { mutable left : ('k, 'v) t + ; key : 'k + ; mutable value : 'v + ; mutable height : int + ; mutable right : ('k, 'v) t + } + | Leaf of + { key : 'k + ; mutable value : 'v + } + + module For_quickcheck = struct + module Key = struct + include Int + + type t = int [@@deriving quickcheck] + + let quickcheck_generator = Base_quickcheck.Generator.small_positive_or_zero_int + end + + module Data = struct + include String + + type t = string [@@deriving quickcheck] - let apply_to_tree t tree = - match t with - | Add (key, data) -> - add tree ~key ~data ~compare ~added:(ref false) ~replace:false - | Replace (key, data) -> - add tree ~key ~data ~compare ~added:(ref false) ~replace:true - | Remove key -> remove tree key ~compare ~removed:(ref false) - ;; - - let apply_to_map t map = - match t with - | Add (key, data) -> if Map.mem map key then map else Map.set map ~key ~data - | Replace (key, data) -> Map.set map ~key ~data - | Remove key -> Map.remove map key - ;; - end - - module Constructors = struct - type t = Constructor.t list [@@deriving quickcheck, sexp_of] - end - - let reify constructors = - List.fold - constructors - ~init:(empty, Map.empty (module Key)) - ~f:(fun (t, map) constructor -> - ( Constructor.apply_to_tree constructor t - , Constructor.apply_to_map constructor map )) + let quickcheck_generator = + Base_quickcheck.Generator.string_of Base_quickcheck.Generator.char_lowercase ;; + end - let merge map1 map2 = - Map.merge map1 map2 ~f:(fun ~key variant -> - match variant with - | `Left data | `Right data -> Some data - | `Both (data1, data2) -> - Error.raise_s - [%message - "duplicate data for key" (key : Key.t) (data1 : Data.t) (data2 : Data.t)]) + let compare = Key.compare + + module Constructor = struct + type t = + | Add of Key.t * Data.t + | Replace of Key.t * Data.t + | Remove of Key.t + [@@deriving quickcheck, sexp_of] + + let apply_to_tree t tree = + match t with + | Add (key, data) -> + add tree ~key ~data ~compare ~added:(ref false) ~replace:false + | Replace (key, data) -> + add tree ~key ~data ~compare ~added:(ref false) ~replace:true + | Remove key -> remove tree key ~compare ~removed:(ref false) ;; - let rec to_map = function - | Empty -> Map.empty (module Key) - | Leaf { key; value = data } -> Map.singleton (module Key) key data - | Node { left; key; value = data; height = _; right } -> - merge (Map.singleton (module Key) key data) (merge (to_map left) (to_map right)) + let apply_to_map t map = + match t with + | Add (key, data) -> if Map.mem map key then map else Map.set map ~key ~data + | Replace (key, data) -> Map.set map ~key ~data + | Remove key -> Map.remove map key ;; end - open For_quickcheck - - let empty = empty + module Constructors = struct + type t = Constructor.t list [@@deriving quickcheck, sexp_of] + end - let%test_unit _ = - match empty with - | Empty -> () - | _ -> assert false + let reify constructors = + List.fold + constructors + ~init:(empty, Map.empty (module Key)) + ~f:(fun (t, map) constructor -> + ( Constructor.apply_to_tree constructor t + , Constructor.apply_to_map constructor map )) ;; - let is_empty = is_empty - let%test _ = is_empty empty - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module Constructors) - ~f:(fun constructors -> - let t, map = reify constructors in - [%test_result: bool] (is_empty t) ~expect:(Map.is_empty map)) + let merge map1 map2 = + Map.merge map1 map2 ~f:(fun ~key variant -> + match variant with + | `Left data | `Right data -> Some data + | `Both (data1, data2) -> + Error.raise_s + [%message + "duplicate data for key" (key : Key.t) (data1 : Data.t) (data2 : Data.t)]) ;; - let invariant = invariant - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module Constructors) - ~f:(fun constructors -> - let t, map = reify constructors in - invariant t ~compare; - [%test_result: Data.t Map.M(Key).t] (to_map t) ~expect:map) + let rec to_map = function + | Empty -> Map.empty (module Key) + | Leaf { key; value = data } -> Map.singleton (module Key) key data + | Node { left; key; value = data; height = _; right } -> + merge (Map.singleton (module Key) key data) (merge (to_map left) (to_map right)) ;; - - let add = add - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module struct - type t = Constructor.t list * Key.t * Data.t * bool - [@@deriving quickcheck, sexp_of] - end) - ~f:(fun (constructors, key, data, replace) -> - let t, map = reify constructors in - (* test [added], other aspects of [add] are tested via [reify] in the + end + + open For_quickcheck + + let empty = empty + + let%test_unit _ = + match empty with + | Empty -> () + | _ -> assert false + ;; + + let is_empty = is_empty + let%test _ = is_empty empty + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module Constructors) + ~f:(fun constructors -> + let t, map = reify constructors in + [%test_result: bool] (is_empty t) ~expect:(Map.is_empty map)) + ;; + + let invariant = invariant + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module Constructors) + ~f:(fun constructors -> + let t, map = reify constructors in + invariant t ~compare; + [%test_result: Data.t Map.M(Key).t] (to_map t) ~expect:map) + ;; + + let add = add + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module struct + type t = Constructor.t list * Key.t * Data.t * bool + [@@deriving quickcheck, sexp_of] + end) + ~f:(fun (constructors, key, data, replace) -> + let t, map = reify constructors in + (* test [added], other aspects of [add] are tested via [reify] in the [invariant] test above *) - let added = ref false in - let (_ : (Key.t, Data.t) t) = add t ~key ~data ~compare ~added ~replace in - [%test_result: bool] !added ~expect:(not (Map.mem map key))) - ;; - - let remove = remove - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module struct - type t = Constructors.t * Key.t [@@deriving quickcheck, sexp_of] - end) - ~f:(fun (constructors, key) -> - let t, map = reify constructors in - (* test [removed], other aspects of [remove] are tested via [reify] in the + let added = ref false in + let (_ : (Key.t, Data.t) t) = add t ~key ~data ~compare ~added ~replace in + [%test_result: bool] !added ~expect:(not (Map.mem map key))) + ;; + + let remove = remove + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module struct + type t = Constructors.t * Key.t [@@deriving quickcheck, sexp_of] + end) + ~f:(fun (constructors, key) -> + let t, map = reify constructors in + (* test [removed], other aspects of [remove] are tested via [reify] in the [invariant] test above *) - let removed = ref false in - let (_ : (Key.t, Data.t) t) = remove t key ~compare ~removed in - [%test_result: bool] !removed ~expect:(Map.mem map key)) - ;; - - let find = find - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module struct - type t = Constructors.t * Key.t [@@deriving quickcheck, sexp_of] - end) - ~f:(fun (constructors, key) -> - let t, map = reify constructors in - [%test_result: Data.t option] (find t key ~compare) ~expect:(Map.find map key)) - ;; - - let mem = mem - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module struct - type t = Constructors.t * Key.t [@@deriving quickcheck, sexp_of] - end) - ~f:(fun (constructors, key) -> - let t, map = reify constructors in - [%test_result: bool] (mem t key ~compare) ~expect:(Map.mem map key)) - ;; - - let first = first - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module Constructors) - ~f:(fun constructors -> - let t, map = reify constructors in - [%test_result: (Key.t * Data.t) option] (first t) ~expect:(Map.min_elt map)) - ;; - - let last = last - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module Constructors) - ~f:(fun constructors -> - let t, map = reify constructors in - [%test_result: (Key.t * Data.t) option] (last t) ~expect:(Map.max_elt map)) - ;; - - let find_and_call = find_and_call - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module struct - type t = Constructors.t * Key.t [@@deriving quickcheck, sexp_of] - end) - ~f:(fun (constructors, key) -> - let t, map = reify constructors in - [%test_result: [ `Found of Data.t | `Not_found of Key.t ]] - (find_and_call - t - key - ~compare - ~if_found:(fun data -> `Found data) - ~if_not_found:(fun key -> `Not_found key)) - ~expect: - (match Map.find map key with - | None -> `Not_found key - | Some data -> `Found data)) - ;; - - let findi_and_call = findi_and_call - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module struct - type t = Constructors.t * Key.t [@@deriving quickcheck, sexp_of] - end) - ~f:(fun (constructors, key) -> - let t, map = reify constructors in - [%test_result: [ `Found of Key.t * Data.t | `Not_found of Key.t ]] - (findi_and_call - t - key - ~compare - ~if_found:(fun ~key ~data -> `Found (key, data)) - ~if_not_found:(fun key -> `Not_found key)) - ~expect: - (match Map.find map key with - | None -> `Not_found key - | Some data -> `Found (key, data))) - ;; - - let find_and_call1 = find_and_call1 - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module struct - type t = Constructors.t * Key.t * int [@@deriving quickcheck, sexp_of] - end) - ~f:(fun (constructors, key, a) -> - let t, map = reify constructors in - [%test_result: [ `Found of Data.t * int | `Not_found of Key.t * int ]] - (find_and_call1 - t - key - ~compare - ~a - ~if_found:(fun data a -> `Found (data, a)) - ~if_not_found:(fun key a -> `Not_found (key, a))) - ~expect: - (match Map.find map key with - | None -> `Not_found (key, a) - | Some data -> `Found (data, a))) - ;; - - let findi_and_call1 = findi_and_call1 - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module struct - type t = Constructors.t * Key.t * int [@@deriving quickcheck, sexp_of] - end) - ~f:(fun (constructors, key, a) -> - let t, map = reify constructors in - [%test_result: [ `Found of Key.t * Data.t * int | `Not_found of Key.t * int ]] - (findi_and_call1 - t - key - ~compare - ~a - ~if_found:(fun ~key ~data a -> `Found (key, data, a)) - ~if_not_found:(fun key a -> `Not_found (key, a))) - ~expect: - (match Map.find map key with - | None -> `Not_found (key, a) - | Some data -> `Found (key, data, a))) - ;; - - let find_and_call2 = find_and_call2 - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module struct - type t = Constructors.t * Key.t * int * string [@@deriving quickcheck, sexp_of] - end) - ~f:(fun (constructors, key, a, b) -> - let t, map = reify constructors in - [%test_result: - [ `Found of Data.t * int * string | `Not_found of Key.t * int * string ]] - (find_and_call2 - t - key - ~compare - ~a - ~b - ~if_found:(fun data a b -> `Found (data, a, b)) - ~if_not_found:(fun key a b -> `Not_found (key, a, b))) - ~expect: - (match Map.find map key with - | None -> `Not_found (key, a, b) - | Some data -> `Found (data, a, b))) - ;; - - let findi_and_call2 = findi_and_call2 - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module struct - type t = Constructors.t * Key.t * int * string [@@deriving quickcheck, sexp_of] - end) - ~f:(fun (constructors, key, a, b) -> - let t, map = reify constructors in - [%test_result: - [ `Found of Key.t * Data.t * int * string - | `Not_found of Key.t * int * string - ]] - (findi_and_call2 - t - key - ~compare - ~a - ~b - ~if_found:(fun ~key ~data a b -> `Found (key, data, a, b)) - ~if_not_found:(fun key a b -> `Not_found (key, a, b))) - ~expect: - (match Map.find map key with - | None -> `Not_found (key, a, b) - | Some data -> `Found (key, data, a, b))) - ;; - - let iter = iter - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module Constructors) - ~f:(fun constructors -> - let t, map = reify constructors in - [%test_result: (Key.t * Data.t) list] - (let q = Queue.create () in - iter t ~f:(fun ~key ~data -> Queue.enqueue q (key, data)); - Queue.to_list q) - ~expect:(Map.to_alist map)) - ;; - - let mapi_inplace = mapi_inplace - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module Constructors) - ~f:(fun constructors -> - let t, map = reify constructors in - [%test_result: (Key.t * Data.t) list] - (mapi_inplace t ~f:(fun ~key:_ ~data -> data ^ data); - fold t ~init:[] ~f:(fun ~key ~data acc -> (key, data) :: acc)) - ~expect:(Map.map map ~f:(fun data -> data ^ data) |> Map.to_alist |> List.rev)) - ;; - - let fold = fold - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module Constructors) - ~f:(fun constructors -> - let t, map = reify constructors in - [%test_result: (Key.t * Data.t) list] - (fold t ~init:[] ~f:(fun ~key ~data acc -> (key, data) :: acc)) - ~expect:(Map.to_alist map |> List.rev)) - ;; - - let choose_exn = choose_exn - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module Constructors) - ~f:(fun constructors -> - let t, map = reify constructors in - [%test_result: bool] - (is_some (Option.try_with (fun () -> choose_exn t))) - ~expect:(not (Map.is_empty map))) - ;; - end : - module type of Avltree)) -;; + let removed = ref false in + let (_ : (Key.t, Data.t) t) = remove t key ~compare ~removed in + [%test_result: bool] !removed ~expect:(Map.mem map key)) + ;; + + let find = find + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module struct + type t = Constructors.t * Key.t [@@deriving quickcheck, sexp_of] + end) + ~f:(fun (constructors, key) -> + let t, map = reify constructors in + [%test_result: Data.t option] (find t key ~compare) ~expect:(Map.find map key)) + ;; + + let mem = mem + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module struct + type t = Constructors.t * Key.t [@@deriving quickcheck, sexp_of] + end) + ~f:(fun (constructors, key) -> + let t, map = reify constructors in + [%test_result: bool] (mem t key ~compare) ~expect:(Map.mem map key)) + ;; + + let first = first + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module Constructors) + ~f:(fun constructors -> + let t, map = reify constructors in + [%test_result: (Key.t * Data.t) option] (first t) ~expect:(Map.min_elt map)) + ;; + + let last = last + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module Constructors) + ~f:(fun constructors -> + let t, map = reify constructors in + [%test_result: (Key.t * Data.t) option] (last t) ~expect:(Map.max_elt map)) + ;; + + let find_and_call = find_and_call + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module struct + type t = Constructors.t * Key.t [@@deriving quickcheck, sexp_of] + end) + ~f:(fun (constructors, key) -> + let t, map = reify constructors in + [%test_result: [ `Found of Data.t | `Not_found of Key.t ]] + (find_and_call + t + key + ~compare + ~if_found:(fun data -> `Found data) + ~if_not_found:(fun key -> `Not_found key)) + ~expect: + (match Map.find map key with + | None -> `Not_found key + | Some data -> `Found data)) + ;; + + let findi_and_call = findi_and_call + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module struct + type t = Constructors.t * Key.t [@@deriving quickcheck, sexp_of] + end) + ~f:(fun (constructors, key) -> + let t, map = reify constructors in + [%test_result: [ `Found of Key.t * Data.t | `Not_found of Key.t ]] + (findi_and_call + t + key + ~compare + ~if_found:(fun ~key ~data -> `Found (key, data)) + ~if_not_found:(fun key -> `Not_found key)) + ~expect: + (match Map.find map key with + | None -> `Not_found key + | Some data -> `Found (key, data))) + ;; + + let find_and_call1 = find_and_call1 + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module struct + type t = Constructors.t * Key.t * int [@@deriving quickcheck, sexp_of] + end) + ~f:(fun (constructors, key, a) -> + let t, map = reify constructors in + [%test_result: [ `Found of Data.t * int | `Not_found of Key.t * int ]] + (find_and_call1 + t + key + ~compare + ~a + ~if_found:(fun data a -> `Found (data, a)) + ~if_not_found:(fun key a -> `Not_found (key, a))) + ~expect: + (match Map.find map key with + | None -> `Not_found (key, a) + | Some data -> `Found (data, a))) + ;; + + let findi_and_call1 = findi_and_call1 + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module struct + type t = Constructors.t * Key.t * int [@@deriving quickcheck, sexp_of] + end) + ~f:(fun (constructors, key, a) -> + let t, map = reify constructors in + [%test_result: [ `Found of Key.t * Data.t * int | `Not_found of Key.t * int ]] + (findi_and_call1 + t + key + ~compare + ~a + ~if_found:(fun ~key ~data a -> `Found (key, data, a)) + ~if_not_found:(fun key a -> `Not_found (key, a))) + ~expect: + (match Map.find map key with + | None -> `Not_found (key, a) + | Some data -> `Found (key, data, a))) + ;; + + let find_and_call2 = find_and_call2 + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module struct + type t = Constructors.t * Key.t * int * string [@@deriving quickcheck, sexp_of] + end) + ~f:(fun (constructors, key, a, b) -> + let t, map = reify constructors in + [%test_result: + [ `Found of Data.t * int * string | `Not_found of Key.t * int * string ]] + (find_and_call2 + t + key + ~compare + ~a + ~b + ~if_found:(fun data a b -> `Found (data, a, b)) + ~if_not_found:(fun key a b -> `Not_found (key, a, b))) + ~expect: + (match Map.find map key with + | None -> `Not_found (key, a, b) + | Some data -> `Found (data, a, b))) + ;; + + let findi_and_call2 = findi_and_call2 + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module struct + type t = Constructors.t * Key.t * int * string [@@deriving quickcheck, sexp_of] + end) + ~f:(fun (constructors, key, a, b) -> + let t, map = reify constructors in + [%test_result: + [ `Found of Key.t * Data.t * int * string | `Not_found of Key.t * int * string ]] + (findi_and_call2 + t + key + ~compare + ~a + ~b + ~if_found:(fun ~key ~data a b -> `Found (key, data, a, b)) + ~if_not_found:(fun key a b -> `Not_found (key, a, b))) + ~expect: + (match Map.find map key with + | None -> `Not_found (key, a, b) + | Some data -> `Found (key, data, a, b))) + ;; + + let iter = iter + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module Constructors) + ~f:(fun constructors -> + let t, map = reify constructors in + [%test_result: (Key.t * Data.t) list] + (let q = Queue.create () in + iter t ~f:(fun ~key ~data -> Queue.enqueue q (key, data)); + Queue.to_list q) + ~expect:(Map.to_alist map)) + ;; + + let mapi_inplace = mapi_inplace + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module Constructors) + ~f:(fun constructors -> + let t, map = reify constructors in + [%test_result: (Key.t * Data.t) list] + (mapi_inplace t ~f:(fun ~key:_ ~data -> data ^ data); + fold t ~init:[] ~f:(fun ~key ~data acc -> (key, data) :: acc)) + ~expect:(Map.map map ~f:(fun data -> data ^ data) |> Map.to_alist |> List.rev)) + ;; + + let fold = fold + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module Constructors) + ~f:(fun constructors -> + let t, map = reify constructors in + [%test_result: (Key.t * Data.t) list] + (fold t ~init:[] ~f:(fun ~key ~data acc -> (key, data) :: acc)) + ~expect:(Map.to_alist map |> List.rev)) + ;; + + let choose_exn = choose_exn + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module Constructors) + ~f:(fun constructors -> + let t, map = reify constructors in + [%test_result: bool] + (is_some (Option.try_with (fun () -> choose_exn t))) + ~expect:(not (Map.is_empty map))) + ;; +end diff --git a/test/coverage/map/constructor.ml b/test/coverage/map/constructor.ml index 85cbed5..82b8b78 100644 --- a/test/coverage/map/constructor.ml +++ b/test/coverage/map/constructor.ml @@ -771,1189 +771,1185 @@ end The number of quickcheck tests on 32-bit architectures is configured to be lower, so we skip the coverage checks there. *) -let%test_module (_ [@tags "64-bits-only"]) = - (module ( - struct - module Types = struct - type 'key key = 'key - type 'cmp cmp = 'cmp - type ('key, 'data, 'cmp) t = ('key, 'data, 'cmp) Map.t - type ('key, 'data, 'cmp) tree = ('key, 'data, 'cmp) Map.Using_comparator.Tree.t - - type ('key, 'cmp, 'fn) create_options = - ('key, 'cmp, 'fn) Map.With_first_class_module.t - - type ('key, 'cmp, 'fn) access_options = ('key, 'cmp, 'fn) Map.Without_comparator.t - end - - open struct - module Int_data = struct - include Int - - type t = int [@@deriving quickcheck] - - let combine_non_commutative a b = (10 * a) + b - end - - module Instance = struct - module Types = Types - module Key = Int_data +module%test [@tags "64-bits-only"] _ : Impl = struct + module Types = struct + type 'key key = 'key + type 'cmp cmp = 'cmp + type ('key, 'data, 'cmp) t = ('key, 'data, 'cmp) Map.t + type ('key, 'data, 'cmp) tree = ('key, 'data, 'cmp) Map.Using_comparator.Tree.t - type 'a t = (int, 'a, Int.comparator_witness) Map.t + type ('key, 'cmp, 'fn) create_options = + ('key, 'cmp, 'fn) Map.With_first_class_module.t - let compare = Map.compare_direct - let equal = Map.equal - let sexp_of_t f t = Map.sexp_of_m__t (module Key) f t - let create f = f ((module Key) : (_, _) Comparator.Module.t) - let access f = f - end - - module Cons = Make (Instance) (Map) (Int_data) + type ('key, 'cmp, 'fn) access_options = ('key, 'cmp, 'fn) Map.Without_comparator.t + end - let sample = Memo.memoize Cons.quickcheck_generator + open struct + module Int_data = struct + include Int - let%expect_test "normalization" = - quickcheck_m - (module struct - include Cons + type t = int [@@deriving quickcheck] - let sample = sample - end) - ~f:(fun t -> - require_equal (module Cons) t (Cons.normalize t); - require_does_not_raise (fun () -> ignore (Cons.value t : int Map.M(Int).t))) - ;; - - let%expect_test "number of constructors" = - let stats = Stats.create () in - List.iter (Lazy.force sample) ~f:(fun t -> - Stats.add stats (Constructor.number_of_constructors t)); - Stats.print stats; - [%expect - {| - % | size | count - ----+------+------ - 0 | 1 | 10000 - 50 | 4 | 5747 - 75 | 11 | 2687 - 90 | 25 | 1057 - 95 | 40 | 523 - 99 | 77 | 101 - 100 | 293 | 1 - |}] - ;; - - let test predicate = - let stats = Stats.create () in - List.iter (force sample) ~f:(fun t -> - if predicate t - then ( - let size = Map.length (Cons.value t) in - Stats.add stats size)); - Stats.print stats - ;; + let combine_non_commutative a b = (10 * a) + b end - (* Accessors only, not covered. *) - - include (Map : Accessors with module Types := Types) - - (* Complicated types, not covered. *) - - let transpose_keys = Map.transpose_keys - let of_tree = Map.of_tree - let combine_errors = Map.combine_errors - let unzip = Map.unzip - let of_alist_multi = Map.of_alist_multi - let of_sequence_multi = Map.of_sequence_multi - let of_list_with_key_multi = Map.of_list_with_key_multi - let add_multi = Map.add_multi - let remove_multi = Map.remove_multi - - (* Tests *) - - let empty = Map.empty - - let%expect_test _ = - test (function - | Empty -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 86 - |}] - ;; - - let singleton = Map.singleton - - let%expect_test _ = - test (function - | Singleton _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - 100 | 1 | 79 - |}] - ;; - - let map_keys = Map.map_keys - - let%expect_test _ = - test (function - | Map_keys _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 117 - ----+------+------ - 0 | 1 | 170 - 50 | 3 | 94 - 75 | 8 | 44 - 90 | 14 | 21 - 95 | 19 | 10 - 99 | 27 | 2 - 100 | 28 | 1 - |}] - ;; - - let map_keys_exn = Map.map_keys_exn - - let%expect_test _ = - test (function - | Map_keys_exn _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 91 - ----+------+------ - 0 | 1 | 192 - 50 | 3 | 100 - 75 | 8 | 50 - 90 | 16 | 20 - 95 | 23 | 11 - 99 | 28 | 2 - 100 | 48 | 1 - |}] - ;; - - let of_sorted_array = Map.of_sorted_array - - let%expect_test _ = - test (function - | Of_sorted_array _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 16 - ----+------+------ - 0 | 1 | 56 - 50 | 11 | 28 - 75 | 21 | 15 - 90 | 25 | 8 - 95 | 28 | 3 - 100 | 31 | 1 - |}] - ;; - - let of_sorted_array_unchecked = Map.of_sorted_array_unchecked - - let%expect_test _ = - test (function - | Of_sorted_array_unchecked _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 9 - ----+------+------ - 0 | 1 | 74 - 50 | 8 | 41 - 75 | 18 | 20 - 90 | 25 | 9 - 100 | 28 | 4 - |}] - ;; - - let of_increasing_iterator_unchecked = Map.of_increasing_iterator_unchecked - - let%expect_test _ = - test (function - | Of_increasing_iterator_unchecked _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 9 - ----+------+------ - 0 | 1 | 82 - 50 | 10 | 41 - 75 | 18 | 21 - 90 | 26 | 9 - 95 | 27 | 7 - 100 | 30 | 2 - |}] - ;; - - let of_alist = Map.of_alist - - let%expect_test _ = - test (function - | Of_alist _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 18 - ----+------+------ - 0 | 1 | 64 - 50 | 13 | 32 - 75 | 22 | 16 - 90 | 26 | 8 - 95 | 29 | 4 - 100 | 31 | 1 - |}] - ;; - - let of_alist_or_error = Map.of_alist_or_error - - let%expect_test _ = - test (function - | Of_alist_or_error _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 18 - ----+------+------ - 0 | 1 | 74 - 50 | 11 | 37 - 75 | 20 | 20 - 90 | 26 | 8 - 95 | 29 | 4 - 100 | 31 | 2 - |}] - ;; - - let of_alist_exn = Map.of_alist_exn + module Instance = struct + module Types = Types + module Key = Int_data - let%expect_test _ = - test (function - | Of_alist_exn _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 9 - ----+------+------ - 0 | 1 | 59 - 50 | 9 | 30 - 75 | 16 | 15 - 90 | 25 | 6 - 95 | 28 | 3 - 100 | 30 | 1 - |}] - ;; + type 'a t = (int, 'a, Int.comparator_witness) Map.t - let of_alist_fold = Map.of_alist_fold - - let%expect_test _ = - test (function - | Of_alist_fold _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 8 - ----+------+------ - 0 | 1 | 76 - 50 | 3 | 55 - 75 | 4 | 32 - 100 | 5 | 8 - |}] - ;; - - let of_alist_reduce = Map.of_alist_reduce - - let%expect_test _ = - test (function - | Of_alist_reduce _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 11 - ----+------+------ - 0 | 1 | 72 - 50 | 3 | 41 - 90 | 4 | 29 - 95 | 5 | 7 - 100 | 6 | 1 - |}] - ;; - - let of_increasing_sequence = Map.of_increasing_sequence - - let%expect_test _ = - test (function - | Of_increasing_sequence _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 9 - ----+------+------ - 0 | 1 | 77 - 50 | 9 | 39 - 75 | 17 | 20 - 90 | 20 | 12 - 95 | 24 | 5 - 100 | 28 | 1 - |}] - ;; - - let of_sequence = Map.of_sequence - - let%expect_test _ = - test (function - | Of_sequence _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 9 - ----+------+------ - 0 | 1 | 79 - 50 | 9 | 44 - 75 | 15 | 20 - 90 | 22 | 9 - 95 | 23 | 7 - 100 | 29 | 1 - |}] - ;; - - let of_sequence_or_error = Map.of_sequence_or_error - - let%expect_test _ = - test (function - | Of_sequence_or_error _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 15 - ----+------+------ - 0 | 1 | 77 - 50 | 9 | 41 - 75 | 18 | 22 - 90 | 24 | 9 - 95 | 26 | 6 - 100 | 31 | 1 - |}] - ;; - - let of_sequence_exn = Map.of_sequence_exn - - let%expect_test _ = - test (function - | Of_sequence_exn _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 11 - ----+------+------ - 0 | 1 | 71 - 50 | 14 | 36 - 75 | 21 | 19 - 90 | 25 | 8 - 95 | 27 | 4 - 100 | 28 | 2 - |}] - ;; - - let of_sequence_fold = Map.of_sequence_fold - - let%expect_test _ = - test (function - | Of_sequence_fold _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 13 - ----+------+------ - 0 | 1 | 71 - 50 | 3 | 48 - 90 | 4 | 32 - 100 | 5 | 7 - |}] - ;; - - let of_sequence_reduce = Map.of_sequence_reduce + let compare = Map.compare_direct + let equal = Map.equal + let sexp_of_t f t = Map.sexp_of_m__t (module Key) f t + let create f = f ((module Key) : (_, _) Comparator.Module.t) + let access f = f + end - let%expect_test _ = - test (function - | Of_sequence_reduce _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 11 - ----+------+------ - 0 | 1 | 68 - 75 | 3 | 45 - 95 | 4 | 14 - 100 | 5 | 3 - |}] - ;; + module Cons = Make (Instance) (Map) (Int_data) - let of_list_with_key = Map.of_list_with_key + let sample = Memo.memoize Cons.quickcheck_generator - let%expect_test _ = - test (function - | Of_list_with_key _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 10 - ----+------+------ - 0 | 1 | 68 - 50 | 12 | 35 - 75 | 19 | 17 - 95 | 25 | 7 - 100 | 27 | 1 - |}] - ;; - - let of_list_with_key_or_error = Map.of_list_with_key_or_error + let%expect_test "normalization" = + quickcheck_m + (module struct + include Cons - let%expect_test _ = - test (function - | Of_list_with_key_or_error _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 14 - ----+------+------ - 0 | 1 | 86 - 50 | 11 | 44 - 75 | 18 | 23 - 90 | 25 | 10 - 95 | 27 | 6 - 100 | 30 | 1 - |}] + let sample = sample + end) + ~f:(fun t -> + require_equal (module Cons) t (Cons.normalize t); + require_does_not_raise (fun () -> ignore (Cons.value t : int Map.M(Int).t))) ;; - let of_list_with_key_exn = Map.of_list_with_key_exn - - let%expect_test _ = - test (function - | Of_list_with_key_exn _ -> true - | _ -> false); + let%expect_test "number of constructors" = + let stats = Stats.create () in + List.iter (Lazy.force sample) ~f:(fun t -> + Stats.add stats (Constructor.number_of_constructors t)); + Stats.print stats; [%expect {| % | size | count ----+------+------ - - | 0 | 10 - ----+------+------ - 0 | 1 | 68 - 50 | 10 | 34 - 75 | 17 | 18 - 90 | 24 | 7 - 95 | 25 | 6 - 100 | 28 | 2 + 0 | 1 | 10000 + 50 | 4 | 5747 + 75 | 11 | 2687 + 90 | 25 | 1057 + 95 | 40 | 523 + 99 | 77 | 101 + 100 | 293 | 1 |}] ;; - let of_list_with_key_fold = Map.of_list_with_key_fold - - let%expect_test _ = - test (function - | Of_list_with_key_fold _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 13 - ----+------+------ - 0 | 1 | 68 - 50 | 2 | 41 - 100 | 3 | 17 - |}] + let test predicate = + let stats = Stats.create () in + List.iter (force sample) ~f:(fun t -> + if predicate t + then ( + let size = Map.length (Cons.value t) in + Stats.add stats size)); + Stats.print stats ;; + end - let of_list_with_key_reduce = Map.of_list_with_key_reduce + (* Accessors only, not covered. *) - let%expect_test _ = - test (function - | Of_list_with_key_reduce _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 12 - ----+------+------ - 0 | 1 | 69 - 50 | 2 | 48 - 95 | 3 | 18 - 100 | 4 | 1 - |}] - ;; + include (Map : Accessors with module Types := Types) - let of_iteri = Map.of_iteri + (* Complicated types, not covered. *) - let%expect_test _ = - test (function - | Of_iteri _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 11 - ----+------+------ - 0 | 1 | 78 - 50 | 11 | 39 - 75 | 20 | 20 - 90 | 27 | 8 - 100 | 30 | 5 - |}] - ;; + let transpose_keys = Map.transpose_keys + let of_tree = Map.of_tree + let combine_errors = Map.combine_errors + let unzip = Map.unzip + let of_alist_multi = Map.of_alist_multi + let of_sequence_multi = Map.of_sequence_multi + let of_list_with_key_multi = Map.of_list_with_key_multi + let add_multi = Map.add_multi + let remove_multi = Map.remove_multi - let of_iteri_exn = Map.of_iteri_exn + (* Tests *) - let%expect_test _ = - test (function - | Of_iteri_exn _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 17 - ----+------+------ - 0 | 1 | 67 - 50 | 10 | 36 - 75 | 18 | 17 - 90 | 26 | 7 - 95 | 29 | 5 - 100 | 31 | 1 - |}] - ;; + let empty = Map.empty - let add = Map.add + let%expect_test _ = + test (function + | Empty -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 86 + |}] + ;; - let%expect_test _ = - test (function - | Add _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - 0 | 1 | 265 - 50 | 3 | 143 - 75 | 7 | 69 - 90 | 17 | 27 - 95 | 21 | 16 - 99 | 27 | 4 - 100 | 38 | 1 - |}] - ;; + let singleton = Map.singleton + + let%expect_test _ = + test (function + | Singleton _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + 100 | 1 | 79 + |}] + ;; - let add_exn = Map.add_exn + let map_keys = Map.map_keys + + let%expect_test _ = + test (function + | Map_keys _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 117 + ----+------+------ + 0 | 1 | 170 + 50 | 3 | 94 + 75 | 8 | 44 + 90 | 14 | 21 + 95 | 19 | 10 + 99 | 27 | 2 + 100 | 28 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Add_exn _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - 0 | 1 | 271 - 50 | 2 | 183 - 75 | 4 | 85 - 90 | 13 | 33 - 95 | 21 | 14 - 99 | 28 | 4 - 100 | 51 | 1 - |}] - ;; + let map_keys_exn = Map.map_keys_exn + + let%expect_test _ = + test (function + | Map_keys_exn _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 91 + ----+------+------ + 0 | 1 | 192 + 50 | 3 | 100 + 75 | 8 | 50 + 90 | 16 | 20 + 95 | 23 | 11 + 99 | 28 | 2 + 100 | 48 | 1 + |}] + ;; - let set = Map.set + let of_sorted_array = Map.of_sorted_array + + let%expect_test _ = + test (function + | Of_sorted_array _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 16 + ----+------+------ + 0 | 1 | 56 + 50 | 11 | 28 + 75 | 21 | 15 + 90 | 25 | 8 + 95 | 28 | 3 + 100 | 31 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Set _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - 0 | 1 | 263 - 50 | 2 | 151 - 75 | 5 | 66 - 90 | 12 | 29 - 95 | 20 | 14 - 99 | 26 | 3 - 100 | 29 | 1 - |}] - ;; + let of_sorted_array_unchecked = Map.of_sorted_array_unchecked + + let%expect_test _ = + test (function + | Of_sorted_array_unchecked _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 9 + ----+------+------ + 0 | 1 | 74 + 50 | 8 | 41 + 75 | 18 | 20 + 90 | 25 | 9 + 100 | 28 | 4 + |}] + ;; - let change = Map.change + let of_increasing_iterator_unchecked = Map.of_increasing_iterator_unchecked + + let%expect_test _ = + test (function + | Of_increasing_iterator_unchecked _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 9 + ----+------+------ + 0 | 1 | 82 + 50 | 10 | 41 + 75 | 18 | 21 + 90 | 26 | 9 + 95 | 27 | 7 + 100 | 30 | 2 + |}] + ;; - let%expect_test _ = - test (function - | Change _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 62 - ----+------+------ - 0 | 1 | 202 - 50 | 3 | 101 - 75 | 8 | 53 - 90 | 16 | 22 - 95 | 21 | 11 - 99 | 28 | 3 - 100 | 41 | 1 - |}] - ;; + let of_alist = Map.of_alist + + let%expect_test _ = + test (function + | Of_alist _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 18 + ----+------+------ + 0 | 1 | 64 + 50 | 13 | 32 + 75 | 22 | 16 + 90 | 26 | 8 + 95 | 29 | 4 + 100 | 31 | 1 + |}] + ;; - let update = Map.update + let of_alist_or_error = Map.of_alist_or_error + + let%expect_test _ = + test (function + | Of_alist_or_error _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 18 + ----+------+------ + 0 | 1 | 74 + 50 | 11 | 37 + 75 | 20 | 20 + 90 | 26 | 8 + 95 | 29 | 4 + 100 | 31 | 2 + |}] + ;; - let%expect_test _ = - test (function - | Update _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - 0 | 1 | 277 - 50 | 2 | 178 - 75 | 7 | 71 - 90 | 18 | 29 - 95 | 23 | 18 - 99 | 30 | 3 - 100 | 48 | 1 - |}] - ;; + let of_alist_exn = Map.of_alist_exn + + let%expect_test _ = + test (function + | Of_alist_exn _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 9 + ----+------+------ + 0 | 1 | 59 + 50 | 9 | 30 + 75 | 16 | 15 + 90 | 25 | 6 + 95 | 28 | 3 + 100 | 30 | 1 + |}] + ;; - let remove = Map.remove + let of_alist_fold = Map.of_alist_fold + + let%expect_test _ = + test (function + | Of_alist_fold _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 8 + ----+------+------ + 0 | 1 | 76 + 50 | 3 | 55 + 75 | 4 | 32 + 100 | 5 | 8 + |}] + ;; - let%expect_test _ = - test (function - | Remove _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 100 - ----+------+------ - 0 | 1 | 190 - 50 | 3 | 113 - 75 | 11 | 48 - 90 | 20 | 20 - 95 | 24 | 10 - 99 | 39 | 2 - 100 | 42 | 1 - |}] - ;; + let of_alist_reduce = Map.of_alist_reduce + + let%expect_test _ = + test (function + | Of_alist_reduce _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 11 + ----+------+------ + 0 | 1 | 72 + 50 | 3 | 41 + 90 | 4 | 29 + 95 | 5 | 7 + 100 | 6 | 1 + |}] + ;; - let map = Map.map + let of_increasing_sequence = Map.of_increasing_sequence + + let%expect_test _ = + test (function + | Of_increasing_sequence _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 9 + ----+------+------ + 0 | 1 | 77 + 50 | 9 | 39 + 75 | 17 | 20 + 90 | 20 | 12 + 95 | 24 | 5 + 100 | 28 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Map _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 110 - ----+------+------ - 0 | 1 | 194 - 50 | 3 | 106 - 75 | 8 | 53 - 90 | 18 | 22 - 95 | 23 | 10 - 99 | 43 | 2 - 100 | 49 | 1 - |}] - ;; + let of_sequence = Map.of_sequence + + let%expect_test _ = + test (function + | Of_sequence _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 9 + ----+------+------ + 0 | 1 | 79 + 50 | 9 | 44 + 75 | 15 | 20 + 90 | 22 | 9 + 95 | 23 | 7 + 100 | 29 | 1 + |}] + ;; - let mapi = Map.mapi + let of_sequence_or_error = Map.of_sequence_or_error + + let%expect_test _ = + test (function + | Of_sequence_or_error _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 15 + ----+------+------ + 0 | 1 | 77 + 50 | 9 | 41 + 75 | 18 | 22 + 90 | 24 | 9 + 95 | 26 | 6 + 100 | 31 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Mapi _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 100 - ----+------+------ - 0 | 1 | 169 - 50 | 2 | 114 - 75 | 8 | 45 - 90 | 18 | 18 - 95 | 21 | 9 - 99 | 29 | 2 - 100 | 30 | 1 - |}] - ;; + let of_sequence_exn = Map.of_sequence_exn + + let%expect_test _ = + test (function + | Of_sequence_exn _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 11 + ----+------+------ + 0 | 1 | 71 + 50 | 14 | 36 + 75 | 21 | 19 + 90 | 25 | 8 + 95 | 27 | 4 + 100 | 28 | 2 + |}] + ;; - let filter_keys = Map.filter_keys + let of_sequence_fold = Map.of_sequence_fold + + let%expect_test _ = + test (function + | Of_sequence_fold _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 13 + ----+------+------ + 0 | 1 | 71 + 50 | 3 | 48 + 90 | 4 | 32 + 100 | 5 | 7 + |}] + ;; - let%expect_test _ = - test (function - | Filter_keys _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 168 - ----+------+------ - 0 | 1 | 133 - 50 | 2 | 76 - 75 | 7 | 34 - 90 | 16 | 18 - 95 | 22 | 7 - 99 | 29 | 2 - 100 | 38 | 1 - |}] - ;; + let of_sequence_reduce = Map.of_sequence_reduce + + let%expect_test _ = + test (function + | Of_sequence_reduce _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 11 + ----+------+------ + 0 | 1 | 68 + 75 | 3 | 45 + 95 | 4 | 14 + 100 | 5 | 3 + |}] + ;; - let filter = Map.filter + let of_list_with_key = Map.of_list_with_key + + let%expect_test _ = + test (function + | Of_list_with_key _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 10 + ----+------+------ + 0 | 1 | 68 + 50 | 12 | 35 + 75 | 19 | 17 + 95 | 25 | 7 + 100 | 27 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Filter _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 163 - ----+------+------ - 0 | 1 | 140 - 50 | 2 | 97 - 75 | 6 | 37 - 90 | 12 | 14 - 95 | 20 | 7 - 100 | 24 | 2 - |}] - ;; + let of_list_with_key_or_error = Map.of_list_with_key_or_error + + let%expect_test _ = + test (function + | Of_list_with_key_or_error _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 14 + ----+------+------ + 0 | 1 | 86 + 50 | 11 | 44 + 75 | 18 | 23 + 90 | 25 | 10 + 95 | 27 | 6 + 100 | 30 | 1 + |}] + ;; - let filteri = Map.filteri + let of_list_with_key_exn = Map.of_list_with_key_exn + + let%expect_test _ = + test (function + | Of_list_with_key_exn _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 10 + ----+------+------ + 0 | 1 | 68 + 50 | 10 | 34 + 75 | 17 | 18 + 90 | 24 | 7 + 95 | 25 | 6 + 100 | 28 | 2 + |}] + ;; - let%expect_test _ = - test (function - | Filteri _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 157 - ----+------+------ - 0 | 1 | 134 - 50 | 2 | 81 - 75 | 4 | 39 - 90 | 10 | 16 - 95 | 14 | 8 - 99 | 23 | 2 - 100 | 24 | 1 - |}] - ;; + let of_list_with_key_fold = Map.of_list_with_key_fold + + let%expect_test _ = + test (function + | Of_list_with_key_fold _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 13 + ----+------+------ + 0 | 1 | 68 + 50 | 2 | 41 + 100 | 3 | 17 + |}] + ;; - let filter_map = Map.filter_map + let of_list_with_key_reduce = Map.of_list_with_key_reduce + + let%expect_test _ = + test (function + | Of_list_with_key_reduce _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 12 + ----+------+------ + 0 | 1 | 69 + 50 | 2 | 48 + 95 | 3 | 18 + 100 | 4 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Filter_map _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 154 - ----+------+------ - 0 | 1 | 109 - 50 | 3 | 64 - 75 | 6 | 30 - 90 | 16 | 11 - 95 | 20 | 8 - 99 | 24 | 2 - 100 | 26 | 1 - |}] - ;; + let of_iteri = Map.of_iteri + + let%expect_test _ = + test (function + | Of_iteri _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 11 + ----+------+------ + 0 | 1 | 78 + 50 | 11 | 39 + 75 | 20 | 20 + 90 | 27 | 8 + 100 | 30 | 5 + |}] + ;; - let filter_mapi = Map.filter_mapi + let of_iteri_exn = Map.of_iteri_exn + + let%expect_test _ = + test (function + | Of_iteri_exn _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 17 + ----+------+------ + 0 | 1 | 67 + 50 | 10 | 36 + 75 | 18 | 17 + 90 | 26 | 7 + 95 | 29 | 5 + 100 | 31 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Filter_mapi _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 184 - ----+------+------ - 0 | 1 | 119 - 50 | 2 | 78 - 75 | 5 | 32 - 90 | 14 | 12 - 95 | 19 | 6 - 99 | 24 | 3 - 100 | 25 | 1 - |}] - ;; + let add = Map.add + + let%expect_test _ = + test (function + | Add _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + 0 | 1 | 265 + 50 | 3 | 143 + 75 | 7 | 69 + 90 | 17 | 27 + 95 | 21 | 16 + 99 | 27 | 4 + 100 | 38 | 1 + |}] + ;; - let partition_mapi = Map.partition_mapi + let add_exn = Map.add_exn + + let%expect_test _ = + test (function + | Add_exn _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + 0 | 1 | 271 + 50 | 2 | 183 + 75 | 4 | 85 + 90 | 13 | 33 + 95 | 21 | 14 + 99 | 28 | 4 + 100 | 51 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Partition_mapi _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 145 - ----+------+------ - 0 | 1 | 105 - 50 | 3 | 53 - 75 | 7 | 27 - 90 | 15 | 11 - 95 | 22 | 6 - 99 | 26 | 3 - 100 | 28 | 1 - |}] - ;; + let set = Map.set + + let%expect_test _ = + test (function + | Set _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + 0 | 1 | 263 + 50 | 2 | 151 + 75 | 5 | 66 + 90 | 12 | 29 + 95 | 20 | 14 + 99 | 26 | 3 + 100 | 29 | 1 + |}] + ;; - let partition_map = Map.partition_map + let change = Map.change + + let%expect_test _ = + test (function + | Change _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 62 + ----+------+------ + 0 | 1 | 202 + 50 | 3 | 101 + 75 | 8 | 53 + 90 | 16 | 22 + 95 | 21 | 11 + 99 | 28 | 3 + 100 | 41 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Partition_map _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 142 - ----+------+------ - 0 | 1 | 128 - 50 | 3 | 64 - 75 | 8 | 32 - 90 | 15 | 13 - 95 | 18 | 8 - 100 | 24 | 2 - |}] - ;; + let update = Map.update + + let%expect_test _ = + test (function + | Update _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + 0 | 1 | 277 + 50 | 2 | 178 + 75 | 7 | 71 + 90 | 18 | 29 + 95 | 23 | 18 + 99 | 30 | 3 + 100 | 48 | 1 + |}] + ;; - let partitioni_tf = Map.partitioni_tf + let remove = Map.remove + + let%expect_test _ = + test (function + | Remove _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 100 + ----+------+------ + 0 | 1 | 190 + 50 | 3 | 113 + 75 | 11 | 48 + 90 | 20 | 20 + 95 | 24 | 10 + 99 | 39 | 2 + 100 | 42 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Partitioni_tf _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 158 - ----+------+------ - 0 | 1 | 132 - 50 | 2 | 77 - 75 | 5 | 33 - 90 | 10 | 15 - 95 | 14 | 7 - 100 | 27 | 2 - |}] - ;; + let map = Map.map + + let%expect_test _ = + test (function + | Map _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 110 + ----+------+------ + 0 | 1 | 194 + 50 | 3 | 106 + 75 | 8 | 53 + 90 | 18 | 22 + 95 | 23 | 10 + 99 | 43 | 2 + 100 | 49 | 1 + |}] + ;; - let partition_tf = Map.partition_tf + let mapi = Map.mapi + + let%expect_test _ = + test (function + | Mapi _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 100 + ----+------+------ + 0 | 1 | 169 + 50 | 2 | 114 + 75 | 8 | 45 + 90 | 18 | 18 + 95 | 21 | 9 + 99 | 29 | 2 + 100 | 30 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Partition_tf _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 142 - ----+------+------ - 0 | 1 | 121 - 50 | 2 | 75 - 75 | 6 | 33 - 90 | 12 | 14 - 95 | 21 | 7 - 99 | 29 | 2 - 100 | 41 | 1 - |}] - ;; + let filter_keys = Map.filter_keys + + let%expect_test _ = + test (function + | Filter_keys _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 168 + ----+------+------ + 0 | 1 | 133 + 50 | 2 | 76 + 75 | 7 | 34 + 90 | 16 | 18 + 95 | 22 | 7 + 99 | 29 | 2 + 100 | 38 | 1 + |}] + ;; - let merge = Map.merge + let filter = Map.filter + + let%expect_test _ = + test (function + | Filter _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 163 + ----+------+------ + 0 | 1 | 140 + 50 | 2 | 97 + 75 | 6 | 37 + 90 | 12 | 14 + 95 | 20 | 7 + 100 | 24 | 2 + |}] + ;; - let%expect_test _ = - test (function - | Merge _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 83 - ----+------+------ - 0 | 1 | 179 - 50 | 2 | 120 - 75 | 5 | 55 - 90 | 9 | 20 - 95 | 11 | 10 - 99 | 24 | 2 - 100 | 53 | 1 - |}] - ;; + let filteri = Map.filteri + + let%expect_test _ = + test (function + | Filteri _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 157 + ----+------+------ + 0 | 1 | 134 + 50 | 2 | 81 + 75 | 4 | 39 + 90 | 10 | 16 + 95 | 14 | 8 + 99 | 23 | 2 + 100 | 24 | 1 + |}] + ;; - let merge_disjoint_exn = Map.merge_disjoint_exn + let filter_map = Map.filter_map + + let%expect_test _ = + test (function + | Filter_map _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 154 + ----+------+------ + 0 | 1 | 109 + 50 | 3 | 64 + 75 | 6 | 30 + 90 | 16 | 11 + 95 | 20 | 8 + 99 | 24 | 2 + 100 | 26 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Merge_disjoint_exn _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 33 - ----+------+------ - 0 | 1 | 249 - 50 | 5 | 126 - 75 | 13 | 67 - 90 | 23 | 31 - 95 | 29 | 13 - 99 | 42 | 3 - 100 | 69 | 1 - |}] - ;; + let filter_mapi = Map.filter_mapi + + let%expect_test _ = + test (function + | Filter_mapi _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 184 + ----+------+------ + 0 | 1 | 119 + 50 | 2 | 78 + 75 | 5 | 32 + 90 | 14 | 12 + 95 | 19 | 6 + 99 | 24 | 3 + 100 | 25 | 1 + |}] + ;; - let merge_skewed = Map.merge_skewed + let partition_mapi = Map.partition_mapi + + let%expect_test _ = + test (function + | Partition_mapi _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 145 + ----+------+------ + 0 | 1 | 105 + 50 | 3 | 53 + 75 | 7 | 27 + 90 | 15 | 11 + 95 | 22 | 6 + 99 | 26 | 3 + 100 | 28 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Merge_skewed _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 37 - ----+------+------ - 0 | 1 | 237 - 50 | 5 | 122 - 75 | 13 | 65 - 90 | 22 | 25 - 95 | 27 | 15 - 99 | 34 | 3 - 100 | 40 | 1 - |}] - ;; + let partition_map = Map.partition_map + + let%expect_test _ = + test (function + | Partition_map _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 142 + ----+------+------ + 0 | 1 | 128 + 50 | 3 | 64 + 75 | 8 | 32 + 90 | 15 | 13 + 95 | 18 | 8 + 100 | 24 | 2 + |}] + ;; - let split = Map.split + let partitioni_tf = Map.partitioni_tf + + let%expect_test _ = + test (function + | Partitioni_tf _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 158 + ----+------+------ + 0 | 1 | 132 + 50 | 2 | 77 + 75 | 5 | 33 + 90 | 10 | 15 + 95 | 14 | 7 + 100 | 27 | 2 + |}] + ;; - let%expect_test _ = - test (function - | Split _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 176 - ----+------+------ - 0 | 1 | 115 - 50 | 2 | 72 - 75 | 6 | 33 - 90 | 10 | 15 - 95 | 14 | 8 - 99 | 18 | 2 - 100 | 27 | 1 - |}] - ;; + let partition_tf = Map.partition_tf + + let%expect_test _ = + test (function + | Partition_tf _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 142 + ----+------+------ + 0 | 1 | 121 + 50 | 2 | 75 + 75 | 6 | 33 + 90 | 12 | 14 + 95 | 21 | 7 + 99 | 29 | 2 + 100 | 41 | 1 + |}] + ;; - let split_le_gt = Map.split_le_gt + let merge = Map.merge + + let%expect_test _ = + test (function + | Merge _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 83 + ----+------+------ + 0 | 1 | 179 + 50 | 2 | 120 + 75 | 5 | 55 + 90 | 9 | 20 + 95 | 11 | 10 + 99 | 24 | 2 + 100 | 53 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Split_le_gt _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 164 - ----+------+------ - 0 | 1 | 115 - 50 | 2 | 67 - 75 | 5 | 30 - 90 | 12 | 13 - 95 | 19 | 7 - 99 | 23 | 4 - 100 | 25 | 1 - |}] - ;; + let merge_disjoint_exn = Map.merge_disjoint_exn + + let%expect_test _ = + test (function + | Merge_disjoint_exn _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 33 + ----+------+------ + 0 | 1 | 249 + 50 | 5 | 126 + 75 | 13 | 67 + 90 | 23 | 31 + 95 | 29 | 13 + 99 | 42 | 3 + 100 | 69 | 1 + |}] + ;; - let split_lt_ge = Map.split_lt_ge + let merge_skewed = Map.merge_skewed + + let%expect_test _ = + test (function + | Merge_skewed _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 37 + ----+------+------ + 0 | 1 | 237 + 50 | 5 | 122 + 75 | 13 | 65 + 90 | 22 | 25 + 95 | 27 | 15 + 99 | 34 | 3 + 100 | 40 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Split_lt_ge _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 132 - ----+------+------ - 0 | 1 | 123 - 50 | 2 | 69 - 75 | 5 | 32 - 90 | 13 | 13 - 95 | 15 | 7 - 99 | 27 | 2 - 100 | 63 | 1 - |}] - ;; + let split = Map.split + + let%expect_test _ = + test (function + | Split _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 176 + ----+------+------ + 0 | 1 | 115 + 50 | 2 | 72 + 75 | 6 | 33 + 90 | 10 | 15 + 95 | 14 | 8 + 99 | 18 | 2 + 100 | 27 | 1 + |}] + ;; - let append = Map.append + let split_le_gt = Map.split_le_gt + + let%expect_test _ = + test (function + | Split_le_gt _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 164 + ----+------+------ + 0 | 1 | 115 + 50 | 2 | 67 + 75 | 5 | 30 + 90 | 12 | 13 + 95 | 19 | 7 + 99 | 23 | 4 + 100 | 25 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Append _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 23 - ----+------+------ - 0 | 1 | 260 - 50 | 5 | 140 - 75 | 12 | 66 - 90 | 22 | 26 - 95 | 28 | 13 - 99 | 41 | 3 - 100 | 43 | 2 - |}] - ;; + let split_lt_ge = Map.split_lt_ge + + let%expect_test _ = + test (function + | Split_lt_ge _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 132 + ----+------+------ + 0 | 1 | 123 + 50 | 2 | 69 + 75 | 5 | 32 + 90 | 13 | 13 + 95 | 15 | 7 + 99 | 27 | 2 + 100 | 63 | 1 + |}] + ;; - let subrange = Map.subrange + let append = Map.append + + let%expect_test _ = + test (function + | Append _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 23 + ----+------+------ + 0 | 1 | 260 + 50 | 5 | 140 + 75 | 12 | 66 + 90 | 22 | 26 + 95 | 28 | 13 + 99 | 41 | 3 + 100 | 43 | 2 + |}] + ;; - let%expect_test _ = - test (function - | Subrange _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 191 - ----+------+------ - 0 | 1 | 84 - 50 | 2 | 51 - 75 | 6 | 23 - 90 | 16 | 9 - 95 | 19 | 5 - 100 | 25 | 1 - |}] - ;; + let subrange = Map.subrange + + let%expect_test _ = + test (function + | Subrange _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 191 + ----+------+------ + 0 | 1 | 84 + 50 | 2 | 51 + 75 | 6 | 23 + 90 | 16 | 9 + 95 | 19 | 5 + 100 | 25 | 1 + |}] + ;; - module Make_applicative_traversals (A : Applicative.Lazy_applicative) = struct - module T = Map.Make_applicative_traversals (A) + module Make_applicative_traversals (A : Applicative.Lazy_applicative) = struct + module T = Map.Make_applicative_traversals (A) - let mapi = T.mapi - let filter_mapi = T.filter_mapi - end + let mapi = T.mapi + let filter_mapi = T.filter_mapi + end - let%expect_test _ = - test (function - | Make_applicative_traversals__mapi _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 94 - ----+------+------ - 0 | 1 | 179 - 50 | 3 | 95 - 75 | 6 | 53 - 90 | 16 | 20 - 95 | 21 | 9 - 99 | 25 | 2 - 100 | 27 | 1 - |}] - ;; + let%expect_test _ = + test (function + | Make_applicative_traversals__mapi _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 94 + ----+------+------ + 0 | 1 | 179 + 50 | 3 | 95 + 75 | 6 | 53 + 90 | 16 | 20 + 95 | 21 | 9 + 99 | 25 | 2 + 100 | 27 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Make_applicative_traversals__filter_mapi _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 159 - ----+------+------ - 0 | 1 | 138 - 50 | 3 | 70 - 75 | 7 | 35 - 90 | 12 | 17 - 95 | 16 | 8 - 99 | 22 | 2 - 100 | 27 | 1 - |}] - ;; - end : - Impl)) -;; + let%expect_test _ = + test (function + | Make_applicative_traversals__filter_mapi _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 159 + ----+------+------ + 0 | 1 | 138 + 50 | 3 | 70 + 75 | 7 | 35 + 90 | 12 | 17 + 95 | 16 | 8 + 99 | 22 | 2 + 100 | 27 | 1 + |}] + ;; +end diff --git a/test/coverage/set/constructor.ml b/test/coverage/set/constructor.ml index 8f30460..da02f83 100644 --- a/test/coverage/set/constructor.ml +++ b/test/coverage/set/constructor.ml @@ -416,577 +416,573 @@ end The number of quickcheck tests on 32-bit architectures is configured to be lower, so we skip the coverage checks there. *) -let%test_module (_ [@tags "64-bits-only"]) = - (module ( - struct - module Types = struct - type 'elt elt = 'elt - type 'cmp cmp = 'cmp - type ('elt, 'cmp) set = ('elt, 'cmp) Set.t - type ('elt, 'cmp) t = ('elt, 'cmp) Set.t - type ('elt, 'cmp) tree = ('elt, 'cmp) Set.Using_comparator.Tree.t - - type ('elt, 'cmp, 'fn) create_options = - ('elt, 'cmp, 'fn) Set.With_first_class_module.t +module%test [@tags "64-bits-only"] _ : Impl = struct + module Types = struct + type 'elt elt = 'elt + type 'cmp cmp = 'cmp + type ('elt, 'cmp) set = ('elt, 'cmp) Set.t + type ('elt, 'cmp) t = ('elt, 'cmp) Set.t + type ('elt, 'cmp) tree = ('elt, 'cmp) Set.Using_comparator.Tree.t + + type ('elt, 'cmp, 'fn) create_options = + ('elt, 'cmp, 'fn) Set.With_first_class_module.t + + type ('elt, 'cmp, 'fn) access_options = ('elt, 'cmp, 'fn) Set.Without_comparator.t + end - type ('elt, 'cmp, 'fn) access_options = ('elt, 'cmp, 'fn) Set.Without_comparator.t - end + open struct + module Elt = struct + include Int - open struct - module Elt = struct - include Int - - type t = int [@@deriving quickcheck] - end - - module Instance = struct - module Types = Types - module Elt = Elt - - type t = (int, Int.comparator_witness) Set.t - - let compare = Set.compare_direct - let equal = Set.equal - let sexp_of_t t = Set.sexp_of_m__t (module Elt) t - let create f = f ((module Elt) : (_, _) Comparator.Module.t) - let access f = f - end - - module Cons = Make (Instance) (Set) - - let sample = Memo.memoize Cons.quickcheck_generator - - let%expect_test "normalization" = - quickcheck_m - (module struct - include Cons - - let sample = sample - end) - ~f:(fun t -> - require_equal (module Cons) t (Cons.normalize t); - require_does_not_raise (fun () -> ignore (Cons.value t : Set.M(Int).t))) - ;; - - let%expect_test "number of constructors" = - let stats = Stats.create () in - List.iter (Lazy.force sample) ~f:(fun t -> - Stats.add stats (Constructor.number_of_constructors t)); - Stats.print stats; - [%expect - {| - % | size | count - ----+------+------ - 0 | 1 | 10000 - 50 | 9 | 5119 - 75 | 38 | 2510 - 90 | 80 | 1004 - 95 | 129 | 505 - 99 | 274 | 100 - 100 | 718 | 1 - |}] - ;; - - let test predicate = - let stats = Stats.create () in - List.iter (force sample) ~f:(fun t -> - if predicate t - then ( - let size = Set.length (Cons.value t) in - Stats.add stats size)); - Stats.print stats - ;; + type t = int [@@deriving quickcheck] end - (* Accessors only, not covered. *) - - include (Set : Accessors with module Types := Types) - - (* Complicated types, not covered. *) - - let of_tree = Set.of_tree - - (* Tests *) - - let empty = Set.empty - - let%expect_test _ = - test (function - | Empty -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 198 - |}] - ;; - - let singleton = Set.singleton - - let%expect_test _ = - test (function - | Singleton _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - 100 | 1 | 181 - |}] - ;; + module Instance = struct + module Types = Types + module Elt = Elt - let of_sorted_array = Set.of_sorted_array + type t = (int, Int.comparator_witness) Set.t - let%expect_test _ = - test (function - | Of_sorted_array _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 25 - ----+------+------ - 0 | 1 | 152 - 50 | 8 | 78 - 75 | 16 | 38 - 90 | 23 | 16 - 95 | 28 | 8 - 99 | 30 | 2 - 100 | 31 | 1 - |}] - ;; - - let of_sorted_array_unchecked = Set.of_sorted_array_unchecked - - let%expect_test _ = - test (function - | Of_sorted_array_unchecked _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 29 - ----+------+------ - 0 | 1 | 172 - 50 | 10 | 86 - 75 | 19 | 47 - 90 | 25 | 20 - 95 | 29 | 9 - 99 | 30 | 7 - 100 | 31 | 1 - |}] - ;; + let compare = Set.compare_direct + let equal = Set.equal + let sexp_of_t t = Set.sexp_of_m__t (module Elt) t + let create f = f ((module Elt) : (_, _) Comparator.Module.t) + let access f = f + end - let of_increasing_iterator_unchecked = Set.of_increasing_iterator_unchecked + module Cons = Make (Instance) (Set) - let%expect_test _ = - test (function - | Of_increasing_iterator_unchecked _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 40 - ----+------+------ - 0 | 1 | 143 - 50 | 9 | 76 - 75 | 19 | 36 - 90 | 25 | 18 - 95 | 27 | 10 - 99 | 29 | 4 - 100 | 31 | 1 - |}] - ;; + let sample = Memo.memoize Cons.quickcheck_generator - let of_list = Set.of_list + let%expect_test "normalization" = + quickcheck_m + (module struct + include Cons - let%expect_test _ = - test (function - | Of_list _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 32 - ----+------+------ - 0 | 1 | 159 - 50 | 4 | 85 - 75 | 6 | 41 - 90 | 16 | 16 - 95 | 24 | 11 - 99 | 29 | 2 - 100 | 31 | 1 - |}] + let sample = sample + end) + ~f:(fun t -> + require_equal (module Cons) t (Cons.normalize t); + require_does_not_raise (fun () -> ignore (Cons.value t : Set.M(Int).t))) ;; - let of_array = Set.of_array - - let%expect_test _ = - test (function - | Of_array _ -> true - | _ -> false); + let%expect_test "number of constructors" = + let stats = Stats.create () in + List.iter (Lazy.force sample) ~f:(fun t -> + Stats.add stats (Constructor.number_of_constructors t)); + Stats.print stats; [%expect {| % | size | count ----+------+------ - - | 0 | 27 - ----+------+------ - 0 | 1 | 165 - 50 | 4 | 86 - 75 | 12 | 42 - 90 | 21 | 17 - 95 | 24 | 9 - 100 | 30 | 2 + 0 | 1 | 10000 + 50 | 9 | 5119 + 75 | 38 | 2510 + 90 | 80 | 1004 + 95 | 129 | 505 + 99 | 274 | 100 + 100 | 718 | 1 |}] ;; - let of_sequence = Set.of_sequence - - let%expect_test _ = - test (function - | Of_sequence _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 34 - ----+------+------ - 0 | 1 | 154 - 50 | 4 | 82 - 75 | 8 | 40 - 90 | 20 | 16 - 95 | 26 | 8 - 99 | 30 | 5 - 100 | 31 | 1 - |}] + let test predicate = + let stats = Stats.create () in + List.iter (force sample) ~f:(fun t -> + if predicate t + then ( + let size = Set.length (Cons.value t) in + Stats.add stats size)); + Stats.print stats ;; + end - let add = Set.add + (* Accessors only, not covered. *) - let%expect_test _ = - test (function - | Add _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - 50 | 1 | 574 - 75 | 3 | 155 - 90 | 8 | 59 - 95 | 12 | 29 - 99 | 25 | 6 - 100 | 29 | 1 - |}] - ;; + include (Set : Accessors with module Types := Types) - let remove = Set.remove + (* Complicated types, not covered. *) - let%expect_test _ = - test (function - | Remove _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 325 - ----+------+------ - 0 | 1 | 238 - 50 | 2 | 146 - 75 | 8 | 62 - 90 | 17 | 25 - 95 | 21 | 12 - 99 | 27 | 3 - 100 | 28 | 1 - |}] - ;; - - let map = Set.map + let of_tree = Set.of_tree - let%expect_test _ = - test (function - | Map _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 295 - ----+------+------ - 0 | 1 | 249 - 50 | 2 | 130 - 75 | 3 | 79 - 90 | 8 | 26 - 95 | 12 | 13 - 99 | 24 | 4 - 100 | 29 | 1 - |}] - ;; + (* Tests *) - let filter = Set.filter + let empty = Set.empty - let%expect_test _ = - test (function - | Filter _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 404 - ----+------+------ - 0 | 1 | 145 - 50 | 2 | 82 - 75 | 5 | 38 - 90 | 14 | 15 - 95 | 19 | 8 - 99 | 23 | 3 - 100 | 25 | 1 - |}] - ;; + let%expect_test _ = + test (function + | Empty -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 198 + |}] + ;; - let filter_map = Set.filter_map + let singleton = Set.singleton + + let%expect_test _ = + test (function + | Singleton _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + 100 | 1 | 181 + |}] + ;; - let%expect_test _ = - test (function - | Filter_map _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 350 - ----+------+------ - 0 | 1 | 207 - 50 | 2 | 107 - 75 | 3 | 63 - 90 | 12 | 21 - 95 | 14 | 14 - 99 | 24 | 4 - 100 | 27 | 1 - |}] - ;; + let of_sorted_array = Set.of_sorted_array + + let%expect_test _ = + test (function + | Of_sorted_array _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 25 + ----+------+------ + 0 | 1 | 152 + 50 | 8 | 78 + 75 | 16 | 38 + 90 | 23 | 16 + 95 | 28 | 8 + 99 | 30 | 2 + 100 | 31 | 1 + |}] + ;; - let partition_tf = Set.partition_tf + let of_sorted_array_unchecked = Set.of_sorted_array_unchecked + + let%expect_test _ = + test (function + | Of_sorted_array_unchecked _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 29 + ----+------+------ + 0 | 1 | 172 + 50 | 10 | 86 + 75 | 19 | 47 + 90 | 25 | 20 + 95 | 29 | 9 + 99 | 30 | 7 + 100 | 31 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Partition_tf _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 411 - ----+------+------ - 0 | 1 | 155 - 50 | 2 | 86 - 75 | 4 | 43 - 90 | 13 | 17 - 95 | 17 | 8 - 99 | 25 | 3 - 100 | 28 | 1 - |}] - ;; + let of_increasing_iterator_unchecked = Set.of_increasing_iterator_unchecked + + let%expect_test _ = + test (function + | Of_increasing_iterator_unchecked _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 40 + ----+------+------ + 0 | 1 | 143 + 50 | 9 | 76 + 75 | 19 | 36 + 90 | 25 | 18 + 95 | 27 | 10 + 99 | 29 | 4 + 100 | 31 | 1 + |}] + ;; - let diff = Set.diff + let of_list = Set.of_list + + let%expect_test _ = + test (function + | Of_list _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 32 + ----+------+------ + 0 | 1 | 159 + 50 | 4 | 85 + 75 | 6 | 41 + 90 | 16 | 16 + 95 | 24 | 11 + 99 | 29 | 2 + 100 | 31 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Diff _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 348 - ----+------+------ - 0 | 1 | 218 - 50 | 2 | 135 - 75 | 7 | 55 - 90 | 14 | 23 - 95 | 18 | 13 - 100 | 29 | 3 - |}] - ;; + let of_array = Set.of_array + + let%expect_test _ = + test (function + | Of_array _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 27 + ----+------+------ + 0 | 1 | 165 + 50 | 4 | 86 + 75 | 12 | 42 + 90 | 21 | 17 + 95 | 24 | 9 + 100 | 30 | 2 + |}] + ;; - let inter = Set.inter + let of_sequence = Set.of_sequence + + let%expect_test _ = + test (function + | Of_sequence _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 34 + ----+------+------ + 0 | 1 | 154 + 50 | 4 | 82 + 75 | 8 | 40 + 90 | 20 | 16 + 95 | 26 | 8 + 99 | 30 | 5 + 100 | 31 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Inter _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 519 - ----+------+------ - 50 | 1 | 63 - 75 | 2 | 30 - 90 | 6 | 7 - 95 | 8 | 4 - 100 | 25 | 1 - |}] - ;; + let add = Set.add + + let%expect_test _ = + test (function + | Add _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + 50 | 1 | 574 + 75 | 3 | 155 + 90 | 8 | 59 + 95 | 12 | 29 + 99 | 25 | 6 + 100 | 29 | 1 + |}] + ;; - let union = Set.union + let remove = Set.remove + + let%expect_test _ = + test (function + | Remove _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 325 + ----+------+------ + 0 | 1 | 238 + 50 | 2 | 146 + 75 | 8 | 62 + 90 | 17 | 25 + 95 | 21 | 12 + 99 | 27 | 3 + 100 | 28 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Union _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 173 - ----+------+------ - 0 | 1 | 395 - 50 | 3 | 229 - 75 | 9 | 104 - 90 | 17 | 45 - 95 | 25 | 22 - 99 | 37 | 4 - 100 | 48 | 2 - |}] - ;; + let map = Set.map + + let%expect_test _ = + test (function + | Map _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 295 + ----+------+------ + 0 | 1 | 249 + 50 | 2 | 130 + 75 | 3 | 79 + 90 | 8 | 26 + 95 | 12 | 13 + 99 | 24 | 4 + 100 | 29 | 1 + |}] + ;; - let union_list = Set.union_list + let filter = Set.filter + + let%expect_test _ = + test (function + | Filter _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 404 + ----+------+------ + 0 | 1 | 145 + 50 | 2 | 82 + 75 | 5 | 38 + 90 | 14 | 15 + 95 | 19 | 8 + 99 | 23 | 3 + 100 | 25 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Union_list _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 88 - ----+------+------ - 0 | 1 | 448 - 50 | 3 | 251 - 75 | 6 | 120 - 90 | 10 | 53 - 95 | 13 | 30 - 99 | 19 | 5 - 100 | 24 | 1 - |}] - ;; + let filter_map = Set.filter_map + + let%expect_test _ = + test (function + | Filter_map _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 350 + ----+------+------ + 0 | 1 | 207 + 50 | 2 | 107 + 75 | 3 | 63 + 90 | 12 | 21 + 95 | 14 | 14 + 99 | 24 | 4 + 100 | 27 | 1 + |}] + ;; - let split = Set.split + let partition_tf = Set.partition_tf + + let%expect_test _ = + test (function + | Partition_tf _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 411 + ----+------+------ + 0 | 1 | 155 + 50 | 2 | 86 + 75 | 4 | 43 + 90 | 13 | 17 + 95 | 17 | 8 + 99 | 25 | 3 + 100 | 28 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Split _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 413 - ----+------+------ - 0 | 1 | 155 - 50 | 2 | 88 - 75 | 5 | 39 - 90 | 13 | 16 - 95 | 16 | 10 - 99 | 26 | 2 - 100 | 27 | 1 - |}] - ;; + let diff = Set.diff + + let%expect_test _ = + test (function + | Diff _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 348 + ----+------+------ + 0 | 1 | 218 + 50 | 2 | 135 + 75 | 7 | 55 + 90 | 14 | 23 + 95 | 18 | 13 + 100 | 29 | 3 + |}] + ;; - let split_le_gt = Set.split_le_gt + let inter = Set.inter + + let%expect_test _ = + test (function + | Inter _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 519 + ----+------+------ + 50 | 1 | 63 + 75 | 2 | 30 + 90 | 6 | 7 + 95 | 8 | 4 + 100 | 25 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Split_le_gt _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 401 - ----+------+------ - 0 | 1 | 160 - 50 | 2 | 91 - 75 | 5 | 44 - 90 | 11 | 16 - 95 | 14 | 9 - 99 | 17 | 4 - 100 | 24 | 1 - |}] - ;; + let union = Set.union + + let%expect_test _ = + test (function + | Union _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 173 + ----+------+------ + 0 | 1 | 395 + 50 | 3 | 229 + 75 | 9 | 104 + 90 | 17 | 45 + 95 | 25 | 22 + 99 | 37 | 4 + 100 | 48 | 2 + |}] + ;; - let split_lt_ge = Set.split_lt_ge + let union_list = Set.union_list + + let%expect_test _ = + test (function + | Union_list _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 88 + ----+------+------ + 0 | 1 | 448 + 50 | 3 | 251 + 75 | 6 | 120 + 90 | 10 | 53 + 95 | 13 | 30 + 99 | 19 | 5 + 100 | 24 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Split_lt_ge _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 427 - ----+------+------ - 0 | 1 | 172 - 50 | 2 | 88 - 75 | 4 | 54 - 90 | 10 | 19 - 95 | 13 | 10 - 99 | 26 | 2 - 100 | 36 | 1 - |}] - ;; + let split = Set.split + + let%expect_test _ = + test (function + | Split _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 413 + ----+------+------ + 0 | 1 | 155 + 50 | 2 | 88 + 75 | 5 | 39 + 90 | 13 | 16 + 95 | 16 | 10 + 99 | 26 | 2 + 100 | 27 | 1 + |}] + ;; - let group_by = (Set.group_by [@alert "-deprecated"]) + let split_le_gt = Set.split_le_gt + + let%expect_test _ = + test (function + | Split_le_gt _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 401 + ----+------+------ + 0 | 1 | 160 + 50 | 2 | 91 + 75 | 5 | 44 + 90 | 11 | 16 + 95 | 14 | 9 + 99 | 17 | 4 + 100 | 24 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Group_by _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 559 - ----+------+------ - 0 | 1 | 9 - 50 | 2 | 5 - 75 | 4 | 3 - 100 | 14 | 1 - |}] - ;; + let split_lt_ge = Set.split_lt_ge + + let%expect_test _ = + test (function + | Split_lt_ge _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 427 + ----+------+------ + 0 | 1 | 172 + 50 | 2 | 88 + 75 | 4 | 54 + 90 | 10 | 19 + 95 | 13 | 10 + 99 | 26 | 2 + 100 | 36 | 1 + |}] + ;; - let remove_index = Set.remove_index + let group_by = (Set.group_by [@alert "-deprecated"]) + + let%expect_test _ = + test (function + | Group_by _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 559 + ----+------+------ + 0 | 1 | 9 + 50 | 2 | 5 + 75 | 4 | 3 + 100 | 14 | 1 + |}] + ;; - let%expect_test _ = - test (function - | Remove_index _ -> true - | _ -> false); - [%expect - {| - % | size | count - ----+------+------ - - | 0 | 304 - ----+------+------ - 0 | 1 | 284 - 50 | 2 | 157 - 75 | 6 | 75 - 90 | 13 | 32 - 95 | 19 | 15 - 99 | 26 | 4 - 100 | 27 | 2 - |}] - ;; - end : - Impl)) -;; + let remove_index = Set.remove_index + + let%expect_test _ = + test (function + | Remove_index _ -> true + | _ -> false); + [%expect + {| + % | size | count + ----+------+------ + - | 0 | 304 + ----+------+------ + 0 | 1 | 284 + 50 | 2 | 157 + 75 | 6 | 75 + 90 | 13 | 32 + 95 | 19 | 15 + 99 | 26 | 4 + 100 | 27 | 2 + |}] + ;; +end diff --git a/test/hashtbl_tests.ml b/test/hashtbl_tests.ml index 27ea255..d257076 100644 --- a/test/hashtbl_tests.ml +++ b/test/hashtbl_tests.ml @@ -96,33 +96,29 @@ module Make (Hashtbl : Hashtbl_for_testing) = struct List.equal String.equal predicted found ;; - let%test_module "of_alist" = - (module struct - let%test "size" = - let predicted = List.length test_data in - let found = Hashtbl.length (Hashtbl.of_alist_poly_exn test_data) in - predicted = found - ;; - - let%test "right keys" = - let predicted = List.map test_data ~f:(fun (k, _) -> k) in - let found = Hashtbl.keys (Hashtbl.of_alist_poly_exn test_data) in - let sp = List.sort ~compare:Poly.ascending predicted in - let sf = List.sort ~compare:Poly.ascending found in - sp = sf - ;; - end) - ;; - - let%test_module "of_alist_or_error" = - (module struct - let%test "unique" = Result.is_ok (Hashtbl.of_alist_poly_or_error test_data) - - let%test "duplicate" = - Result.is_error (Hashtbl.of_alist_poly_or_error (test_data @ test_data)) - ;; - end) - ;; + module%test [@name "of_alist"] _ = struct + let%test "size" = + let predicted = List.length test_data in + let found = Hashtbl.length (Hashtbl.of_alist_poly_exn test_data) in + predicted = found + ;; + + let%test "right keys" = + let predicted = List.map test_data ~f:(fun (k, _) -> k) in + let found = Hashtbl.keys (Hashtbl.of_alist_poly_exn test_data) in + let sp = List.sort ~compare:Poly.ascending predicted in + let sf = List.sort ~compare:Poly.ascending found in + sp = sf + ;; + end + + module%test [@name "of_alist_or_error"] _ = struct + let%test "unique" = Result.is_ok (Hashtbl.of_alist_poly_or_error test_data) + + let%test "duplicate" = + Result.is_error (Hashtbl.of_alist_poly_or_error (test_data @ test_data)) + ;; + end let%test "size and right keys" = let predicted = List.map test_data ~f:(fun (k, _) -> k) in diff --git a/test/test_applicative.ml b/test/test_applicative.ml index 2e8c4d6..c959d6c 100644 --- a/test/test_applicative.ml +++ b/test/test_applicative.ml @@ -191,35 +191,29 @@ module Test_applicative_s (A : Applicative.S with type 'a t := 'a Or_error.t) : module Applicative_infix = A.Applicative_infix end -let%test_module "Make" = - (module Test_applicative_s (Applicative.Make (struct - type 'a t = 'a Or_error.t - - let return = Or_error.return - let apply = Or_error.apply - let map = `Define_using_apply - end))) -;; +module%test Make = Test_applicative_s (Applicative.Make (struct + type 'a t = 'a Or_error.t -let%test_module "Make" = - (module Test_applicative_s (Applicative.Make_using_map2 (struct - type 'a t = 'a Or_error.t + let return = Or_error.return + let apply = Or_error.apply + let map = `Define_using_apply + end)) - let return = Or_error.return - let map2 = Or_error.map2 - let map = `Define_using_map2 - end))) -;; +module%test Make = Test_applicative_s (Applicative.Make_using_map2 (struct + type 'a t = 'a Or_error.t -let%test_module "Make" = - (module Test_applicative_s (Applicative.Make_using_map2_local (struct - type 'a t = 'a Or_error.t + let return = Or_error.return + let map2 = Or_error.map2 + let map = `Define_using_map2 + end)) - let return x = Ok x - let map2 = Or_error.map2 - let map = `Define_using_map2 - end))) -;; +module%test Make = Test_applicative_s (Applicative.Make_using_map2_local (struct + type 'a t = 'a Or_error.t + + let return x = Ok x + let map2 = Or_error.map2 + let map = `Define_using_map2 + end)) (* While law-abiding applicatives shouldn't be relying functions being called the minimal number of times, it is good for performance that things be this diff --git a/test/test_array.ml b/test/test_array.ml index 6c0324a..76614e6 100644 --- a/test/test_array.ml +++ b/test/test_array.ml @@ -3,27 +3,24 @@ open Base_quickcheck open Expect_test_helpers_base open Array -let%test_module "Binary_searchable" = - (module Test_binary_searchable.Test1 (struct - include Array +module%test Binary_searchable = Test_binary_searchable.Test1 (struct + include Array - module For_test = struct - let of_array = Fn.id - end - end)) -;; + module For_test = struct + let of_array = Fn.id + end + end) -let%test_module "Blit" = - (module Test_blit.Test1 - (struct - type 'a z = 'a +module%test Blit = + Test_blit.Test1 + (struct + type 'a z = 'a - include Array + include Array - let create_bool ~len = create ~len false - end) - (Array)) -;; + let create_bool ~len = create ~len false + end) + (Array) module List_helpers = struct let rec sprinkle x xs = @@ -40,58 +37,54 @@ module List_helpers = struct ;; end -let%test_module "Sort" = - (module struct - open Private.Sort +module%test Sort = struct + open Private.Sort - let%test_module "Intro_sort.five_element_sort" = - (module struct - (* run [five_element_sort] on all permutations of an array of five elements *) - - let all_perms = List_helpers.permutations [ 1; 2; 3; 4; 5 ] - let%test _ = List.length all_perms = 120 - let%test _ = not (List.contains_dup ~compare:[%compare: int list] all_perms) - - let%test _ = - List.for_all all_perms ~f:(fun l -> - let arr = Array.of_list l in - Intro_sort.five_element_sort arr ~compare:[%compare: int] 0 1 2 3 4; - [%compare.equal: int t] arr [| 1; 2; 3; 4; 5 |]) - ;; - end) + module%test [@name "Intro_sort.five_element_sort"] _ = struct + (* run [five_element_sort] on all permutations of an array of five elements *) + + let all_perms = List_helpers.permutations [ 1; 2; 3; 4; 5 ] + let%test _ = List.length all_perms = 120 + let%test _ = not (List.contains_dup ~compare:[%compare: int list] all_perms) + + let%test _ = + List.for_all all_perms ~f:(fun l -> + let arr = Array.of_list l in + Intro_sort.five_element_sort arr ~compare:[%compare: int] 0 1 2 3 4; + [%compare.equal: int t] arr [| 1; 2; 3; 4; 5 |]) ;; + end - module Test (M : Private.Sort.Sort) = struct - let random_data ~length ~range = - let arr = Array.create ~len:length 0 in - for i = 0 to length - 1 do - arr.(i) <- Random.int range - done; - arr - ;; - - let assert_sorted arr = - M.sort arr ~left:0 ~right:(Array.length arr - 1) ~compare:[%compare: int]; - let len = Array.length arr in - let rec loop i prev = - if i = len then true else if arr.(i) < prev then false else loop (i + 1) arr.(i) - in - loop 0 (-1) - ;; - - let%test _ = assert_sorted (random_data ~length:0 ~range:100) - let%test _ = assert_sorted (random_data ~length:1 ~range:100) - let%test _ = assert_sorted (random_data ~length:100 ~range:1_000) - let%test _ = assert_sorted (random_data ~length:1_000 ~range:1) - let%test _ = assert_sorted (random_data ~length:1_000 ~range:10) - let%test _ = assert_sorted (random_data ~length:1_000 ~range:1_000_000) - end + module Test (M : Private.Sort.Sort) = struct + let random_data ~length ~range = + let arr = Array.create ~len:length 0 in + for i = 0 to length - 1 do + arr.(i) <- Random.int range + done; + arr + ;; - let%test_module _ = (module Test (Insertion_sort)) - let%test_module _ = (module Test (Heap_sort)) - let%test_module _ = (module Test (Intro_sort)) - end) -;; + let assert_sorted arr = + M.sort arr ~left:0 ~right:(Array.length arr - 1) ~compare:[%compare: int]; + let len = Array.length arr in + let rec loop i prev = + if i = len then true else if arr.(i) < prev then false else loop (i + 1) arr.(i) + in + loop 0 (-1) + ;; + + let%test _ = assert_sorted (random_data ~length:0 ~range:100) + let%test _ = assert_sorted (random_data ~length:1 ~range:100) + let%test _ = assert_sorted (random_data ~length:100 ~range:1_000) + let%test _ = assert_sorted (random_data ~length:1_000 ~range:1) + let%test _ = assert_sorted (random_data ~length:1_000 ~range:10) + let%test _ = assert_sorted (random_data ~length:1_000 ~range:1_000_000) + end + + module%test _ = Test (Insertion_sort) + module%test _ = Test (Heap_sort) + module%test _ = Test (Intro_sort) +end let%test _ = is_sorted [||] ~compare:[%compare: int] let%test _ = is_sorted [| 0 |] ~compare:[%compare: int] @@ -201,52 +194,45 @@ let%test _ = foldi [||] ~init:13 ~f:(fun _ _ _ -> failwith "bad") = 13 let%test _ = foldi [| 13 |] ~init:17 ~f:(fun i ac x -> ac + i + x) = 30 let%test _ = foldi [| 13; 17 |] ~init:19 ~f:(fun i ac x -> ac + i + x) = 50 -let%test_module "count{,i}" = - (module struct - let%expect_test "[Array.count{,i} = List.count{,i}]" = - quickcheck_m - (module struct - type t = int list * (int -> bool) [@@deriving quickcheck, sexp_of] - end) - ~f:(fun (list, f) -> - require_equal (module Int) (list |> List.count ~f) (list |> of_list |> count ~f)); - quickcheck_m - (module struct - type t = int list * (int -> int -> bool) [@@deriving quickcheck, sexp_of] - end) - ~f:(fun (list, f) -> - require_equal - (module Int) - (list |> List.counti ~f) - (list |> of_list |> counti ~f)) - ;; +module%test [@name "count{,i}"] _ = struct + let%expect_test "[Array.count{,i} = List.count{,i}]" = + quickcheck_m + (module struct + type t = int list * (int -> bool) [@@deriving quickcheck, sexp_of] + end) + ~f:(fun (list, f) -> + require_equal (module Int) (list |> List.count ~f) (list |> of_list |> count ~f)); + quickcheck_m + (module struct + type t = int list * (int -> int -> bool) [@@deriving quickcheck, sexp_of] + end) + ~f:(fun (list, f) -> + require_equal (module Int) (list |> List.counti ~f) (list |> of_list |> counti ~f)) + ;; - let%test _ = counti [| 0; 1; 2; 3; 4 |] ~f:(fun idx x -> idx = x) = 5 - let%test _ = counti [| 0; 1; 2; 3; 4 |] ~f:(fun idx x -> idx = 4 - x) = 1 - end) -;; + let%test _ = counti [| 0; 1; 2; 3; 4 |] ~f:(fun idx x -> idx = x) = 5 + let%test _ = counti [| 0; 1; 2; 3; 4 |] ~f:(fun idx x -> idx = 4 - x) = 1 +end -let%test_module "{min,max}_elt" = - (module struct - let test_opt_selector arr_fun list_fun = - quickcheck_m - (module struct - type t = int list [@@deriving sexp_of, quickcheck] - end) - ~f:(fun list -> - let arr = of_list list in - require_equal - (module struct - type t = int option [@@deriving sexp_of, equal] - end) - (arr_fun arr ~compare:(fun x y -> Int.compare x y)) - (list_fun list ~compare:(fun x y -> Int.compare x y))) - ;; +module%test [@name "{min,max}_elt"] _ = struct + let test_opt_selector arr_fun list_fun = + quickcheck_m + (module struct + type t = int list [@@deriving sexp_of, quickcheck] + end) + ~f:(fun list -> + let arr = of_list list in + require_equal + (module struct + type t = int option [@@deriving sexp_of, equal] + end) + (arr_fun arr ~compare:(fun x y -> Int.compare x y)) + (list_fun list ~compare:(fun x y -> Int.compare x y))) + ;; - let%expect_test "min_elt" = test_opt_selector min_elt List.min_elt - let%expect_test "max_elt" = test_opt_selector max_elt List.max_elt - end) -;; + let%expect_test "min_elt" = test_opt_selector min_elt List.min_elt + let%expect_test "max_elt" = test_opt_selector max_elt List.max_elt +end let%test_unit _ = for i = 0 to 5 do @@ -506,74 +492,101 @@ let%test_unit _ = ~expect:(0, [||]) ;; -let%test_module "permute" = - (module struct - module Int_list = struct - type t = int list [@@deriving compare, sexp_of] +let test_partition_mapi array ~f ~expect = + [%test_result: int array * int array] (partition_mapi array ~f) ~expect +;; - include (val Comparator.make ~compare ~sexp_of_t) - end +let%test_unit _ = + test_partition_mapi + [||] + ~f:(fun i x -> if i = x then First (i + x) else Second (i - x)) + ~expect:([||], [||]) +;; - let test_permute initial_contents ~pos ~len = - let all_permutations = - let pos, len = - Ordered_collection_common.get_pos_len_exn - ?pos - ?len - ~total_length:(List.length initial_contents) - () - in - let left = List.take initial_contents pos in - let middle = List.sub initial_contents ~pos ~len in - let right = List.drop initial_contents (pos + len) in - Set.of_list - (module Int_list) - (List_helpers.permutations middle - |> List.map ~f:(fun middle -> left @ middle @ right)) - in - let not_yet_seen = ref all_permutations in - while not (Set.is_empty !not_yet_seen) do - let array = of_list initial_contents in - permute ?pos ?len array; - let permutation = to_list array in - if not (Set.mem all_permutations permutation) - then - raise_s - [%sexp - "invalid permutation" - , { array_length = (List.length initial_contents : int) - ; permutation : int list - ; pos : int option - ; len : int option - }]; - not_yet_seen := Set.remove !not_yet_seen permutation - done - ;; +let%test_unit _ = + test_partition_mapi + [| 3; 5; 2; 1; 4 |] + ~f:(fun i x -> if i = x then First (i + x) else Second (i - x)) + ~expect:([| 4; 8 |], [| -3; -4; 2 |]) +;; - let%expect_test "permute different array lengths and subranges" = - let indices = None :: List.map [ 0; 1; 2; 3; 4 ] ~f:Option.some in - for array_length = 0 to 4 do - let initial_contents = List.init array_length ~f:Int.succ in - List.iter indices ~f:(fun pos -> - List.iter indices ~f:(fun len -> - match - Ordered_collection_common.get_pos_len - ?pos - ?len - ~total_length:array_length - () - with - | Ok _ -> test_permute initial_contents ~pos ~len - | Error _ -> - require - (Exn.does_raise (fun () -> - permute ?pos ?len (Array.of_list initial_contents))))) - done; - [%expect {| |}] - ;; - end) +let test_partitioni_tf list ~f ~expect = + [%test_result: int array * int array] (partitioni_tf list ~f) ~expect ;; +let%test_unit _ = + test_partitioni_tf [||] ~f:(fun i x -> i = x && x > 2) ~expect:([||], [||]) +;; + +let%test_unit _ = + test_partitioni_tf + [| 3; 5; 2; 1; 4 |] + ~f:(fun i x -> i = x && x > 2) + ~expect:([| 4 |], [| 3; 5; 2; 1 |]) +;; + +module%test [@name "permute"] _ = struct + module Int_list = struct + type t = int list [@@deriving compare, sexp_of] + + include (val Comparator.make ~compare ~sexp_of_t) + end + + let test_permute initial_contents ~pos ~len = + let all_permutations = + let pos, len = + Ordered_collection_common.get_pos_len_exn + ?pos + ?len + ~total_length:(List.length initial_contents) + () + in + let left = List.take initial_contents pos in + let middle = List.sub initial_contents ~pos ~len in + let right = List.drop initial_contents (pos + len) in + Set.of_list + (module Int_list) + (List_helpers.permutations middle + |> List.map ~f:(fun middle -> left @ middle @ right)) + in + let not_yet_seen = ref all_permutations in + while not (Set.is_empty !not_yet_seen) do + let array = of_list initial_contents in + permute ?pos ?len array; + let permutation = to_list array in + if not (Set.mem all_permutations permutation) + then + raise_s + [%sexp + "invalid permutation" + , { array_length = (List.length initial_contents : int) + ; permutation : int list + ; pos : int option + ; len : int option + }]; + not_yet_seen := Set.remove !not_yet_seen permutation + done + ;; + + let%expect_test "permute different array lengths and subranges" = + let indices = None :: List.map [ 0; 1; 2; 3; 4 ] ~f:Option.some in + for array_length = 0 to 4 do + let initial_contents = List.init array_length ~f:Int.succ in + List.iter indices ~f:(fun pos -> + List.iter indices ~f:(fun len -> + match + Ordered_collection_common.get_pos_len ?pos ?len ~total_length:array_length () + with + | Ok _ -> test_permute initial_contents ~pos ~len + | Error _ -> + require + (Exn.does_raise (fun () -> + permute ?pos ?len (Array.of_list initial_contents))))) + done; + [%expect {| |}] + ;; +end + let%expect_test "create_float_uninitialized" = let array = create_float_uninitialized ~len:10 in (* make sure reading/writing the array is safe *) diff --git a/test/test_base.ml b/test/test_base.ml index 17fcd2e..43a8f4f 100644 --- a/test/test_base.ml +++ b/test/test_base.ml @@ -20,64 +20,61 @@ let%expect_test "exp is present at the toplevel" = [ignore]. We use ppx_template as a convenient way to bind functions of different layouts to mangled identifiers that we can access with [@kind] syntax. This prevents some code duplication, and makes it obvious which layout(s) we're testing. *) -let%test_module "layout polymorphism" = - (module [%template - include ( - struct - type t = int [@@kind immediate] - and t = nativeint [@@kind word] - and t = int32 [@@kind bits32] - and t = int64 [@@kind bits64] - and t = float [@@kind float64] +module%test [@name "layout polymorphism"] _ = + [%template + include ( + struct + type t = int [@@kind immediate] + and t = nativeint [@@kind word] + and t = int32 [@@kind bits32] + and t = int64 [@@kind bits64] + and t = float [@@kind float64] - let[@kind immediate] zero () = 0 - and[@kind word] zero () = 0n - and[@kind bits32] zero () = 0l - and[@kind bits64] zero () = 0L - and[@kind float64] zero () = 0. + let[@kind immediate] zero () = 0 + and[@kind word] zero () = 0n + and[@kind bits32] zero () = 0l + and[@kind bits64] zero () = 0L + and[@kind float64] zero () = 0. - let[@kind immediate] is_zero = function - | 0 -> true - | _ -> false + let[@kind immediate] is_zero = function + | 0 -> true + | _ -> false - and[@kind word] is_zero = function - | 0n -> true - | _ -> false + and[@kind word] is_zero = function + | 0n -> true + | _ -> false - and[@kind bits32] is_zero = function - | 0l -> true - | _ -> false + and[@kind bits32] is_zero = function + | 0l -> true + | _ -> false - and[@kind bits64] is_zero = function - | 0L -> true - | _ -> false + and[@kind bits64] is_zero = function + | 0L -> true + | _ -> false - and[@kind float64] is_zero = function - | 0. -> true - | _ -> false - ;; - end : - sig - [@@@kind k = (immediate, word, bits32, bits64, float64)] + and[@kind float64] is_zero = function + | 0. -> true + | _ -> false + ;; + end : + sig + [@@@kind k = (immediate, word, bits32, bits64, float64)] - type t [@@kind k] + type t [@@kind k] - val zero : unit -> (t[@kind k]) [@@kind k] - val is_zero : (t[@kind k]) -> bool [@@kind k] - end) + val zero : unit -> (t[@kind k]) [@@kind k] + val is_zero : (t[@kind k]) -> bool [@@kind k] + end) - [@@@kind k = (immediate, word, bits32, bits64, float64)] + [@@@kind k = (immediate, word, bits32, bits64, float64)] - (* Ignore a value with each of the specified layouts. *) - let%test_unit "ignore" = ignore ((zero [@kind k]) () : (t[@kind k])) + (* Ignore a value with each of the specified layouts. *) + let%test_unit "ignore" = ignore ((zero [@kind k]) () : (t[@kind k])) - (* Apply [Fn.id >> is_zero] to a value with each of the specified layouts. *) - let%test "apply/revapply identity" = - Fn.id @@ (zero [@kind k]) () |> (is_zero [@kind k]) - ;; + (* Apply [Fn.id >> is_zero] to a value with each of the specified layouts. *) + let%test "apply/revapply identity" = Fn.id @@ (zero [@kind k]) () |> (is_zero [@kind k]) - (* As above but testing %opaque rather than %identity. *) - let%test "apply/revapply opaque" = - Sys.opaque_identity @@ (zero [@kind k]) () |> (is_zero [@kind k]) - ;;]) -;; + (* As above but testing %opaque rather than %identity. *) + let%test "apply/revapply opaque" = + Sys.opaque_identity @@ (zero [@kind k]) () |> (is_zero [@kind k]) + ;;] diff --git a/test/test_base_containers_mono.ml b/test/test_base_containers_mono.ml index 94cb9fb..35b2aa6 100644 --- a/test/test_base_containers_mono.ml +++ b/test/test_base_containers_mono.ml @@ -138,5 +138,7 @@ let%expect_test "String" = Container: testing [filteri] Container: testing [filter_mapi] Container: testing [concat_mapi] + Container: testing [partitioni_tf] + Container: testing [partition_mapi] |}] ;; diff --git a/test/test_base_containers_poly.ml b/test/test_base_containers_poly.ml index 77b007e..c707f32 100644 --- a/test/test_base_containers_poly.ml +++ b/test/test_base_containers_poly.ml @@ -60,6 +60,8 @@ let%expect_test "Array" = Container: testing [filteri] Container: testing [filter_mapi] Container: testing [concat_mapi] + Container: testing [partitioni_tf] + Container: testing [partition_mapi] |}] ;; @@ -111,6 +113,8 @@ let%expect_test "List" = Container: testing [filteri] Container: testing [filter_mapi] Container: testing [concat_mapi] + Container: testing [partitioni_tf] + Container: testing [partition_mapi] |}] ;; diff --git a/test/test_blit.ml b/test/test_blit.ml index e1b7e8c..af518c1 100644 --- a/test/test_blit.ml +++ b/test/test_blit.ml @@ -3,87 +3,84 @@ open! Blit (* This unit test checks that when [blit] calls [unsafe_blit], the slices are valid. It also checks that [blit] doesn't call [unsafe_blit] when there is a range error. *) -let%test_module _ = - (module struct - let blit_was_called = ref false - let slices_are_valid = ref (Ok ()) +module%test _ = struct + let blit_was_called = ref false + let slices_are_valid = ref (Ok ()) - module B = Make (struct - type t = bool array + module B = Make (struct + type t = bool array - let create ~len = Array.create false ~len - let length = Array.length + let create ~len = Array.create false ~len + let length = Array.length - let unsafe_blit ~src ~src_pos ~dst ~dst_pos ~len = - blit_was_called := true; - slices_are_valid - := Or_error.try_with (fun () -> - assert (len >= 0); - assert (src_pos >= 0); - assert (src_pos + len <= Array.length src); - assert (dst_pos >= 0); - assert (dst_pos + len <= Array.length dst)); - Array.blit ~src ~src_pos ~dst ~dst_pos ~len - ;; - end) + let unsafe_blit ~src ~src_pos ~dst ~dst_pos ~len = + blit_was_called := true; + slices_are_valid + := Or_error.try_with (fun () -> + assert (len >= 0); + assert (src_pos >= 0); + assert (src_pos + len <= Array.length src); + assert (dst_pos >= 0); + assert (dst_pos + len <= Array.length dst)); + Array.blit ~src ~src_pos ~dst ~dst_pos ~len + ;; + end) - let%test_module "Bool" = - (module Test_blit.Test - (struct - type t = bool + module%test Bool = + Test_blit.Test + (struct + type t = bool - let equal = Bool.equal - let of_bool = Fn.id - end) - (struct - type t = bool array [@@deriving sexp_of] + let equal = Bool.equal + let of_bool = Fn.id + end) + (struct + type t = bool array [@@deriving sexp_of] - let create ~len = Array.create false ~len - let length = Array.length - let get = Array.get - let set = Array.set - end) - (B)) - ;; + let create ~len = Array.create false ~len + let length = Array.length + let get = Array.get + let set = Array.set + end) + (B) - let%test_unit _ = - let opts = [ None; Some (-1); Some 0; Some 1; Some 2 ] in - List.iter [ 0; 1; 2 ] ~f:(fun src -> - List.iter [ 0; 1; 2 ] ~f:(fun dst -> - List.iter opts ~f:(fun src_pos -> - List.iter opts ~f:(fun src_len -> - List.iter opts ~f:(fun dst_pos -> - try - let check f = - blit_was_called := false; - slices_are_valid := Ok (); - match Or_error.try_with f with - | Error _ -> assert (not !blit_was_called) - | Ok () -> ok_exn !slices_are_valid - in - check (fun () -> - B.blito - ~src:(Array.create ~len:src false) - ?src_pos - ?src_len - ~dst:(Array.create ~len:dst false) - ?dst_pos - ()); - check (fun () -> - ignore - (B.subo (Array.create ~len:src false) ?pos:src_pos ?len:src_len - : bool array)) - with - | exn -> - raise_s - [%message - "failure" - (exn : exn) - (src : int) - (src_pos : int option) - (src_len : int option) - (dst : int) - (dst_pos : int option)]))))) - ;; - end) -;; + let%test_unit _ = + let opts = [ None; Some (-1); Some 0; Some 1; Some 2 ] in + List.iter [ 0; 1; 2 ] ~f:(fun src -> + List.iter [ 0; 1; 2 ] ~f:(fun dst -> + List.iter opts ~f:(fun src_pos -> + List.iter opts ~f:(fun src_len -> + List.iter opts ~f:(fun dst_pos -> + try + let check f = + blit_was_called := false; + slices_are_valid := Ok (); + match Or_error.try_with f with + | Error _ -> assert (not !blit_was_called) + | Ok () -> ok_exn !slices_are_valid + in + check (fun () -> + B.blito + ~src:(Array.create ~len:src false) + ?src_pos + ?src_len + ~dst:(Array.create ~len:dst false) + ?dst_pos + ()); + check (fun () -> + ignore + (B.subo (Array.create ~len:src false) ?pos:src_pos ?len:src_len + : bool array)) + with + | exn -> + raise_s + [%message + "failure" + (exn : exn) + (src : int) + (src_pos : int option) + (src_len : int option) + (dst : int) + (dst_pos : int option)]))))) + ;; +end diff --git a/test/test_bytes.ml b/test/test_bytes.ml index be95985..af0e4bc 100644 --- a/test/test_bytes.ml +++ b/test/test_bytes.ml @@ -1,21 +1,20 @@ open! Import open! Bytes -let%test_module "Blit" = - (module Test_blit.Test - (struct - include Char +module%test Blit = + Test_blit.Test + (struct + include Char - let of_bool b = if b then 'a' else 'b' - end) - (struct - include Bytes + let of_bool b = if b then 'a' else 'b' + end) + (struct + include Bytes - let get t i = get t i - let create ~len = create len - end) - (Bytes)) -;; + let get t i = get t i + let create ~len = create len + end) + (Bytes) let%expect_test "local" = let bytes = Bytes.create_local 10 in @@ -34,74 +33,72 @@ let%expect_test "local" = [%expect {| (Invalid_argument Bytes.create_local) |}] ;; -let%test_module "Unsafe primitives" = - (module struct - let%expect_test "16-bit primitives" = - let buffer = create 10 in - (* Ensure that writing the biggest possible 16-bit value works. *) - Bytes.unsafe_set_int16 buffer 2 0xFFFF; - printf "0x%04x" (Bytes.unsafe_get_int16 buffer 2); - [%expect {| 0xffff |}]; - (* Ensure that [16-bit] operations are indeed 16-bit, meaning it doesn't affect +module%test [@name "Unsafe primitives"] _ = struct + let%expect_test "16-bit primitives" = + let buffer = create 10 in + (* Ensure that writing the biggest possible 16-bit value works. *) + Bytes.unsafe_set_int16 buffer 2 0xFFFF; + printf "0x%04x" (Bytes.unsafe_get_int16 buffer 2); + [%expect {| 0xffff |}]; + (* Ensure that [16-bit] operations are indeed 16-bit, meaning it doesn't affect anything other than x[pos] and x[pos + 1]. *) - Bytes.unsafe_set_int16 buffer 4 0; - Bytes.unsafe_set_int16 buffer 2 ((1 lsl 16) + 1); - printf "0x%04x" (Bytes.unsafe_get_int16 buffer 2); - [%expect {| 0x0001 |}]; - printf "0x%04x" (Bytes.unsafe_get_int16 buffer 4); - [%expect {| 0x0000 |}] - ;; + Bytes.unsafe_set_int16 buffer 4 0; + Bytes.unsafe_set_int16 buffer 2 ((1 lsl 16) + 1); + printf "0x%04x" (Bytes.unsafe_get_int16 buffer 2); + [%expect {| 0x0001 |}]; + printf "0x%04x" (Bytes.unsafe_get_int16 buffer 4); + [%expect {| 0x0000 |}] + ;; - let%expect_test "32-bit primitives" = - let buffer = create 10 in - Bytes.unsafe_set_int32 buffer 0 0xdeadbeefl; - printf "%lx" (Bytes.unsafe_get_int32 buffer 0); - [%expect {| deadbeef |}]; - (* Ensure that Bytes.get will retrieve the individual positions byte values as + let%expect_test "32-bit primitives" = + let buffer = create 10 in + Bytes.unsafe_set_int32 buffer 0 0xdeadbeefl; + printf "%lx" (Bytes.unsafe_get_int32 buffer 0); + [%expect {| deadbeef |}]; + (* Ensure that Bytes.get will retrieve the individual positions byte values as written by Bytes.unsafe_set_int32. *) - for i = 0 to 3 do - let chr = Bytes.get buffer i in - printf "buffer[%d] = 0x%02x\n" i (Char.to_int chr) - done; - [%expect - {| - buffer[0] = 0xef - buffer[1] = 0xbe - buffer[2] = 0xad - buffer[3] = 0xde - |}]; - (* Ensure that 32-bit writes works on non-word-aligned positions. *) - Bytes.unsafe_set_int32 buffer 1 178293l; - printf "%ld" (Bytes.unsafe_get_int32 buffer 1); - [%expect {| 178293 |}] - ;; + for i = 0 to 3 do + let chr = Bytes.get buffer i in + printf "buffer[%d] = 0x%02x\n" i (Char.to_int chr) + done; + [%expect + {| + buffer[0] = 0xef + buffer[1] = 0xbe + buffer[2] = 0xad + buffer[3] = 0xde + |}]; + (* Ensure that 32-bit writes works on non-word-aligned positions. *) + Bytes.unsafe_set_int32 buffer 1 178293l; + printf "%ld" (Bytes.unsafe_get_int32 buffer 1); + [%expect {| 178293 |}] + ;; - let%expect_test "64-bit primitives" = - let buffer = create 10 in - Bytes.unsafe_set_int64 buffer 0 0x12345678_deadbeefL; - printf "%Lx" (Bytes.unsafe_get_int64 buffer 0); - [%expect {| 12345678deadbeef |}]; - (* Ensure that Bytes.get will retrieve the individual positions byte values as + let%expect_test "64-bit primitives" = + let buffer = create 10 in + Bytes.unsafe_set_int64 buffer 0 0x12345678_deadbeefL; + printf "%Lx" (Bytes.unsafe_get_int64 buffer 0); + [%expect {| 12345678deadbeef |}]; + (* Ensure that Bytes.get will retrieve the individual positions byte values as written by Bytes.unsafe_set_int64. *) - for i = 0 to 7 do - let chr = Bytes.get buffer i in - printf "buffer[%d] = 0x%02x\n" i (Char.to_int chr) - done; - [%expect - {| - buffer[0] = 0xef - buffer[1] = 0xbe - buffer[2] = 0xad - buffer[3] = 0xde - buffer[4] = 0x78 - buffer[5] = 0x56 - buffer[6] = 0x34 - buffer[7] = 0x12 - |}]; - (* Ensure that 64-bit writes works on non-word-aligned positions. *) - Bytes.unsafe_set_int64 buffer 1 0x12345678_deadbeefL; - printf "%Lx" (Bytes.unsafe_get_int64 buffer 1); - [%expect {| 12345678deadbeef |}] - ;; - end) -;; + for i = 0 to 7 do + let chr = Bytes.get buffer i in + printf "buffer[%d] = 0x%02x\n" i (Char.to_int chr) + done; + [%expect + {| + buffer[0] = 0xef + buffer[1] = 0xbe + buffer[2] = 0xad + buffer[3] = 0xde + buffer[4] = 0x78 + buffer[5] = 0x56 + buffer[6] = 0x34 + buffer[7] = 0x12 + |}]; + (* Ensure that 64-bit writes works on non-word-aligned positions. *) + Bytes.unsafe_set_int64 buffer 1 0x12345678_deadbeefL; + printf "%Lx" (Bytes.unsafe_get_int64 buffer 1); + [%expect {| 12345678deadbeef |}] + ;; +end diff --git a/test/test_char.ml b/test/test_char.ml index 2d4e64b..d1dde4a 100644 --- a/test/test_char.ml +++ b/test/test_char.ml @@ -31,34 +31,32 @@ let%expect_test "hash coherence" = [%expect {| |}] ;; -let%test_module "int to char conversion" = - (module struct - let%test_unit "of_int bounds" = - let bounds_check i = - [%test_result: t option] (of_int i) ~expect:None ~message:(Int.to_string i) - in - for i = 1 to 100 do - bounds_check (-i); - bounds_check (255 + i) - done - ;; - - let%test_unit "of_int_exn vs of_int" = - for i = -100 to 300 do - [%test_eq: t option] - (of_int i) - (Option.try_with (fun () -> of_int_exn i)) - ~message:(Int.to_string i) - done - ;; - - let%test_unit "unsafe_of_int vs of_int_exn" = - for i = 0 to 255 do - [%test_eq: t] (unsafe_of_int i) (of_int_exn i) ~message:(Int.to_string i) - done - ;; - end) -;; +module%test [@name "int to char conversion"] _ = struct + let%test_unit "of_int bounds" = + let bounds_check i = + [%test_result: t option] (of_int i) ~expect:None ~message:(Int.to_string i) + in + for i = 1 to 100 do + bounds_check (-i); + bounds_check (255 + i) + done + ;; + + let%test_unit "of_int_exn vs of_int" = + for i = -100 to 300 do + [%test_eq: t option] + (of_int i) + (Option.try_with (fun () -> of_int_exn i)) + ~message:(Int.to_string i) + done + ;; + + let%test_unit "unsafe_of_int vs of_int_exn" = + for i = 0 to 255 do + [%test_eq: t] (unsafe_of_int i) (of_int_exn i) ~message:(Int.to_string i) + done + ;; +end let%expect_test "all" = Ref.set_temporarily sexp_style To_string_hum ~f:(fun () -> @@ -148,12 +146,10 @@ let%expect_test "get_hex_digit" = [%expect {| ("Char.get_hex_digit_exn: not a hexadecimal digit" (char "\000")) |}]) ;; -let%test_module "Caseless Comparable" = - (module struct - (* examples from docs *) - let%test _ = Caseless.equal 'A' 'a' - let%test _ = Caseless.('a' < 'B') - let%test _ = Int.( <> ) (Caseless.compare 'a' 'B') (compare 'a' 'B') - let%test _ = List.is_sorted ~compare:Caseless.compare [ 'A'; 'b'; 'C' ] - end) -;; +module%test [@name "Caseless Comparable"] _ = struct + (* examples from docs *) + let%test _ = Caseless.equal 'A' 'a' + let%test _ = Caseless.('a' < 'B') + let%test _ = Int.( <> ) (Caseless.compare 'a' 'B') (compare 'a' 'B') + let%test _ = List.is_sorted ~compare:Caseless.compare [ 'A'; 'b'; 'C' ] +end diff --git a/test/test_compare.ml b/test/test_compare.ml index daffe30..245a35f 100644 --- a/test/test_compare.ml +++ b/test/test_compare.ml @@ -113,50 +113,48 @@ let%expect_test "Int63" = [%expect {| |}] ;; -let%test_module "lexicographic" = - (module struct - let%expect_test "single" = - Ref.set_temporarily sexp_style To_string_hum ~f:(fun () -> - List.iter - [ 1, 2; 1, 1; 2, 1 ] - ~f:(fun (a, b) -> - let ordering = Ordering.of_int (compare a b) in - print_s [%message (a : int) (b : int) (ordering : Ordering.t)]; - require_equal - (module Ordering) - (Ordering.of_int (compare a b)) - (Ordering.of_int (Comparable.lexicographic [ compare ] a b))); - [%expect - {| - ((a 1) (b 2) (ordering Less)) - ((a 1) (b 1) (ordering Equal)) - ((a 2) (b 1) (ordering Greater)) - |}]) - ;; - - let%expect_test "three comparisons" = - Ref.set_temporarily sexp_style To_string_hum ~f:(fun () -> - let compare_first_three_elts a_1 b_1 = - Comparable.lexicographic - (List.init 3 ~f:(fun i a b -> compare a.(i) b.(i))) - a_1 - b_1 - in - let test a b = - let a = Array.of_list a in - let b = Array.of_list b in - let ordering = Ordering.of_int (compare_first_three_elts a b) in - print_s [%message (a : int array) (b : int array) (ordering : Ordering.t)] - in - test [ 1; 2; 3; 4 ] [ 1; 2; 4; 9 ]; - [%expect {| ((a (1 2 3 4)) (b (1 2 4 9)) (ordering Less)) |}]; - test [ 1; 2; 3; 4 ] [ 1; 2; 3; 9 ]; - [%expect {| ((a (1 2 3 4)) (b (1 2 3 9)) (ordering Equal)) |}]; - test [ 1; 2; 3; 4 ] [ 1; 1; 4; 9 ]; - [%expect {| ((a (1 2 3 4)) (b (1 1 4 9)) (ordering Greater)) |}]) - ;; - end) -;; +module%test [@name "lexicographic"] _ = struct + let%expect_test "single" = + Ref.set_temporarily sexp_style To_string_hum ~f:(fun () -> + List.iter + [ 1, 2; 1, 1; 2, 1 ] + ~f:(fun (a, b) -> + let ordering = Ordering.of_int (compare a b) in + print_s [%message (a : int) (b : int) (ordering : Ordering.t)]; + require_equal + (module Ordering) + (Ordering.of_int (compare a b)) + (Ordering.of_int (Comparable.lexicographic [ compare ] a b))); + [%expect + {| + ((a 1) (b 2) (ordering Less)) + ((a 1) (b 1) (ordering Equal)) + ((a 2) (b 1) (ordering Greater)) + |}]) + ;; + + let%expect_test "three comparisons" = + Ref.set_temporarily sexp_style To_string_hum ~f:(fun () -> + let compare_first_three_elts a_1 b_1 = + Comparable.lexicographic + (List.init 3 ~f:(fun i a b -> compare a.(i) b.(i))) + a_1 + b_1 + in + let test a b = + let a = Array.of_list a in + let b = Array.of_list b in + let ordering = Ordering.of_int (compare_first_three_elts a b) in + print_s [%message (a : int array) (b : int array) (ordering : Ordering.t)] + in + test [ 1; 2; 3; 4 ] [ 1; 2; 4; 9 ]; + [%expect {| ((a (1 2 3 4)) (b (1 2 4 9)) (ordering Less)) |}]; + test [ 1; 2; 3; 4 ] [ 1; 2; 3; 9 ]; + [%expect {| ((a (1 2 3 4)) (b (1 2 3 9)) (ordering Equal)) |}]; + test [ 1; 2; 3; 4 ] [ 1; 1; 4; 9 ]; + [%expect {| ((a (1 2 3 4)) (b (1 1 4 9)) (ordering Greater)) |}]) + ;; +end let%expect_test "reversed" = let list = [ 3; 1; 4; 1; 5; 9; 2; 6; 5; 3; 5; 9 ] in diff --git a/test/test_exn_reraise.ml b/test/test_exn_reraise.ml index 15fb397..3ad0c0f 100644 --- a/test/test_exn_reraise.ml +++ b/test/test_exn_reraise.ml @@ -82,86 +82,84 @@ let really_show_backtrace s = (String.is_substring s ~substring:"handle_uncaught") ;; -let%test_module ("Show native backtraces" [@tags "no-js"]) = - (module struct - (* good *) - let%expect_test "Base.Exn.reraise" = - test_reraiser _Base_Exn_reraise; - really_show_backtrace [%expect.output]; - [%expect - {| - Before re-raise: true - After re-raise: true - |}] - ;; - - (* bad, because the backtrace was clobbered *) - let%expect_test "Base.Exn.reraise" = - test_reraiser _Base_Exn_reraise_after_clobbering_most_recent_backtrace; - really_show_backtrace [%expect.output]; - [%expect - {| - Before re-raise: false - After re-raise: true - |}] - ;; - - (* bad, missing the backtrace before the reraise *) - let%expect_test "%reraise unequal" = - test_reraiser external_reraise_unequal; - really_show_backtrace [%expect.output]; - [%expect - {| - Before re-raise: false - After re-raise: true - |}] - ;; - - (* bad, missing the backtrace before the reraise *) - let%expect_test "raise unequal" = - test_reraiser vanilla_raise_unequal; - really_show_backtrace [%expect.output]; - [%expect - {| - Before re-raise: false - After re-raise: true - |}] - ;; - - (* good, but no additional info attached *) - let%expect_test "raise equal" = - test_reraiser vanilla_raise; - really_show_backtrace [%expect.output]; - [%expect - {| - Before re-raise: true - After re-raise: true - |}] - ;; - - (* good *) - let%expect_test "Caml.Printexc.raise_with_backtrace" = - test_reraiser raise_with_original_backtrace; - really_show_backtrace [%expect.output]; - [%expect - {| - Before re-raise: true - After re-raise: true - |}] - ;; - - (* good *) - let%expect_test "Exn.reraise_uncaught" = - test_reraise_uncaught ~reraise_uncaught:(Exn.reraise_uncaught "reraised"); - really_show_backtrace [%expect.output]; - [%expect - {| - Before re-raise: true - After re-raise: true - |}] - ;; - end) -;; +module%test [@name "Show native backtraces"] [@tags "no-js"] _ = struct + (* good *) + let%expect_test "Base.Exn.reraise" = + test_reraiser _Base_Exn_reraise; + really_show_backtrace [%expect.output]; + [%expect + {| + Before re-raise: true + After re-raise: true + |}] + ;; + + (* bad, because the backtrace was clobbered *) + let%expect_test "Base.Exn.reraise" = + test_reraiser _Base_Exn_reraise_after_clobbering_most_recent_backtrace; + really_show_backtrace [%expect.output]; + [%expect + {| + Before re-raise: false + After re-raise: true + |}] + ;; + + (* bad, missing the backtrace before the reraise *) + let%expect_test "%reraise unequal" = + test_reraiser external_reraise_unequal; + really_show_backtrace [%expect.output]; + [%expect + {| + Before re-raise: false + After re-raise: true + |}] + ;; + + (* bad, missing the backtrace before the reraise *) + let%expect_test "raise unequal" = + test_reraiser vanilla_raise_unequal; + really_show_backtrace [%expect.output]; + [%expect + {| + Before re-raise: false + After re-raise: true + |}] + ;; + + (* good, but no additional info attached *) + let%expect_test "raise equal" = + test_reraiser vanilla_raise; + really_show_backtrace [%expect.output]; + [%expect + {| + Before re-raise: true + After re-raise: true + |}] + ;; + + (* good *) + let%expect_test "Caml.Printexc.raise_with_backtrace" = + test_reraiser raise_with_original_backtrace; + really_show_backtrace [%expect.output]; + [%expect + {| + Before re-raise: true + After re-raise: true + |}] + ;; + + (* good *) + let%expect_test "Exn.reraise_uncaught" = + test_reraise_uncaught ~reraise_uncaught:(Exn.reraise_uncaught "reraised"); + really_show_backtrace [%expect.output]; + [%expect + {| + Before re-raise: true + After re-raise: true + |}] + ;; +end (* An example bad backtrace: {v diff --git a/test/test_float.ml b/test/test_float.ml index 1b7d74c..64fa7dc 100644 --- a/test/test_float.ml +++ b/test/test_float.ml @@ -108,52 +108,47 @@ let%test _ = z () < one_ulp_above_z () let%test _ = one_ulp_above_z () -. z () = 2. *. x () let%test _ = are_one_ulp_apart (z ()) (one_ulp_above_z ()) -let%test_module "clamp" = - (module struct - let%test _ = clamp_exn 1.0 ~min:2. ~max:3. = 2. - let%test _ = clamp_exn 2.5 ~min:2. ~max:3. = 2.5 - let%test _ = clamp_exn 3.5 ~min:2. ~max:3. = 3. - - let%test_unit "clamp" = - [%test_result: float Or_error.t] (clamp 3.5 ~min:2. ~max:3.) ~expect:(Ok 3.) - ;; - - let%test_unit "clamp nan" = - [%test_result: float Or_error.t] (clamp nan ~min:2. ~max:3.) ~expect:(Ok nan) - ;; - - let%test "clamp bad" = Or_error.is_error (clamp 2.5 ~min:3. ~max:2.) - let%test "clamp also bad" = Or_error.is_error (clamp 2.5 ~min:nan ~max:3.) - let%test "clamp also bad 2" = Or_error.is_error (clamp 2.5 ~min:2. ~max:nan) - let%test "clamp also bad 3" = Or_error.is_error (clamp 2.5 ~min:nan ~max:nan) - let%test "clamp also bad 4" = Or_error.is_error (clamp nan ~min:nan ~max:nan) - - let%test_unit "clamp_exn bad" = - Expect_test_helpers_base.require_does_raise (fun () -> - clamp_exn 2.5 ~min:3. ~max:2.) - ;; - - let%test_unit "clamp_exn also bad" = - Expect_test_helpers_base.require_does_raise (fun () -> - clamp_exn 2.5 ~min:nan ~max:3.) - ;; - - let%test_unit "clamp_exn also bad 2" = - Expect_test_helpers_base.require_does_raise (fun () -> - clamp_exn 2.5 ~min:2. ~max:nan) - ;; - - let%test_unit "clamp_exn also bad 3" = - Expect_test_helpers_base.require_does_raise (fun () -> - clamp_exn 2.5 ~min:nan ~max:nan) - ;; - - let%test_unit "clamp_exn also bad 4" = - Expect_test_helpers_base.require_does_raise (fun () -> - clamp_exn nan ~min:nan ~max:nan) - ;; - end) -;; +module%test [@name "clamp"] _ = struct + let%test _ = clamp_exn 1.0 ~min:2. ~max:3. = 2. + let%test _ = clamp_exn 2.5 ~min:2. ~max:3. = 2.5 + let%test _ = clamp_exn 3.5 ~min:2. ~max:3. = 3. + + let%test_unit "clamp" = + [%test_result: float Or_error.t] (clamp 3.5 ~min:2. ~max:3.) ~expect:(Ok 3.) + ;; + + let%test_unit "clamp nan" = + [%test_result: float Or_error.t] (clamp nan ~min:2. ~max:3.) ~expect:(Ok nan) + ;; + + let%test "clamp bad" = Or_error.is_error (clamp 2.5 ~min:3. ~max:2.) + let%test "clamp also bad" = Or_error.is_error (clamp 2.5 ~min:nan ~max:3.) + let%test "clamp also bad 2" = Or_error.is_error (clamp 2.5 ~min:2. ~max:nan) + let%test "clamp also bad 3" = Or_error.is_error (clamp 2.5 ~min:nan ~max:nan) + let%test "clamp also bad 4" = Or_error.is_error (clamp nan ~min:nan ~max:nan) + + let%test_unit "clamp_exn bad" = + Expect_test_helpers_base.require_does_raise (fun () -> clamp_exn 2.5 ~min:3. ~max:2.) + ;; + + let%test_unit "clamp_exn also bad" = + Expect_test_helpers_base.require_does_raise (fun () -> clamp_exn 2.5 ~min:nan ~max:3.) + ;; + + let%test_unit "clamp_exn also bad 2" = + Expect_test_helpers_base.require_does_raise (fun () -> clamp_exn 2.5 ~min:2. ~max:nan) + ;; + + let%test_unit "clamp_exn also bad 3" = + Expect_test_helpers_base.require_does_raise (fun () -> + clamp_exn 2.5 ~min:nan ~max:nan) + ;; + + let%test_unit "clamp_exn also bad 4" = + Expect_test_helpers_base.require_does_raise (fun () -> + clamp_exn nan ~min:nan ~max:nan) + ;; +end let%test_unit _ = [%test_result: Int64.t] @@ -161,96 +156,93 @@ let%test_unit _ = ~expect:0x7fb0000000000000L ;; -let%test_module "IEEE" = - (module struct - (* Note: IEEE 754 defines NaN values to be those where the exponent is all 1s and the +module%test IEEE = struct + (* Note: IEEE 754 defines NaN values to be those where the exponent is all 1s and the mantissa is nonzero. test_result sees nan values as equal because it is based on [compare] rather than [=]. (If [x] and [x'] are nan, [compare x x'] returns 0, whereas [x = x'] returns [false]. This is the case regardless of whether or not [x] and [x'] are bit-identical values of nan.) *) - let f (t : t) (negative : bool) (exponent : int) (mantissa : Int63.t) : unit = - let str = to_string t in - let is_nan = is_nan t in - (* the sign doesn't matter when nan *) - if not is_nan - then - [%test_result: bool] - ~message:("ieee_negative " ^ str) - (ieee_negative t) - ~expect:negative; - [%test_result: int] - ~message:("ieee_exponent " ^ str) - (ieee_exponent t) - ~expect:exponent; - if is_nan - then assert (Int63.(zero <> ieee_mantissa t)) - else - [%test_result: Int63.t] - ~message:("ieee_mantissa " ^ str) - (ieee_mantissa t) - ~expect:mantissa; - [%test_result: t] - ~message: - (Printf.sprintf - !"create_ieee ~negative:%B ~exponent:%d ~mantissa:%{Int63}" - negative - exponent - mantissa) - (create_ieee_exn ~negative ~exponent ~mantissa) - ~expect:t - ;; - - let%test_unit _ = - let ( !! ) x = Int63.of_int x in - f zero false 0 !!0; - f min_positive_subnormal_value false 0 !!1; - f min_positive_normal_value false 1 !!0; - f epsilon_float false Int.(1023 - mantissa_bits) !!0; - f one false 1023 !!0; - f minus_one true 1023 !!0; - f max_finite_value false Int.(exponent_mask - 1) mantissa_mask; - f infinity false exponent_mask !!0; - f neg_infinity true exponent_mask !!0; - f nan false exponent_mask !!1 - ;; - - (* test the normalized case, that is, 1 <= exponent <= 2046 *) - let%test_unit _ = - let g ~negative ~exponent ~mantissa = - assert ( - create_ieee_exn ~negative ~exponent ~mantissa:(Int63.of_int64_exn mantissa) - = (if negative then -1. else 1.) - * (2. **. (Float.of_int exponent - 1023.)) - * (1. + ((2. **. -52.) * Int64.to_float mantissa))) - in - g ~negative:false ~exponent:1 ~mantissa:147L; - g ~negative:true ~exponent:137 ~mantissa:13L; - g ~negative:false ~exponent:1015 ~mantissa:1370001L; - g ~negative:true ~exponent:2046 ~mantissa:137000100945L - ;; - end) -;; + let f (t : t) (negative : bool) (exponent : int) (mantissa : Int63.t) : unit = + let str = to_string t in + let is_nan = is_nan t in + (* the sign doesn't matter when nan *) + if not is_nan + then + [%test_result: bool] + ~message:("ieee_negative " ^ str) + (ieee_negative t) + ~expect:negative; + [%test_result: int] + ~message:("ieee_exponent " ^ str) + (ieee_exponent t) + ~expect:exponent; + if is_nan + then assert (Int63.(zero <> ieee_mantissa t)) + else + [%test_result: Int63.t] + ~message:("ieee_mantissa " ^ str) + (ieee_mantissa t) + ~expect:mantissa; + [%test_result: t] + ~message: + (Printf.sprintf + !"create_ieee ~negative:%B ~exponent:%d ~mantissa:%{Int63}" + negative + exponent + mantissa) + (create_ieee_exn ~negative ~exponent ~mantissa) + ~expect:t + ;; + + let%test_unit _ = + let ( !! ) x = Int63.of_int x in + f zero false 0 !!0; + f min_positive_subnormal_value false 0 !!1; + f min_positive_normal_value false 1 !!0; + f epsilon_float false Int.(1023 - mantissa_bits) !!0; + f one false 1023 !!0; + f minus_one true 1023 !!0; + f max_finite_value false Int.(exponent_mask - 1) mantissa_mask; + f infinity false exponent_mask !!0; + f neg_infinity true exponent_mask !!0; + f nan false exponent_mask !!1 + ;; + + (* test the normalized case, that is, 1 <= exponent <= 2046 *) + let%test_unit _ = + let g ~negative ~exponent ~mantissa = + assert ( + create_ieee_exn ~negative ~exponent ~mantissa:(Int63.of_int64_exn mantissa) + = (if negative then -1. else 1.) + * (2. **. (Float.of_int exponent - 1023.)) + * (1. + ((2. **. -52.) * Int64.to_float mantissa))) + in + g ~negative:false ~exponent:1 ~mantissa:147L; + g ~negative:true ~exponent:137 ~mantissa:13L; + g ~negative:false ~exponent:1015 ~mantissa:1370001L; + g ~negative:true ~exponent:2046 ~mantissa:137000100945L + ;; +end + +module%test _ = struct + let test f expect = + let actual = to_padded_compact_string f in + if String.(actual <> expect) + then raise_s [%message "failure" (f : t) (expect : string) (actual : string)] + ;; -let%test_module _ = - (module struct - let test f expect = - let actual = to_padded_compact_string f in - if String.(actual <> expect) - then raise_s [%message "failure" (f : t) (expect : string) (actual : string)] - ;; - - let both f expect = - assert (f > 0.); - test f expect; - test ~-.f ("-" ^ expect) - ;; - - let decr = one_ulp `Down - let incr = one_ulp `Up - - let boundary f ~closer_to_zero ~at = - assert (f > 0.); - (* If [f] looks like an odd multiple of 0.05, it might be slightly under-represented + let both f expect = + assert (f > 0.); + test f expect; + test ~-.f ("-" ^ expect) + ;; + + let decr = one_ulp `Down + let incr = one_ulp `Up + + let boundary f ~closer_to_zero ~at = + assert (f > 0.); + (* If [f] looks like an odd multiple of 0.05, it might be slightly under-represented as a float, e.g. 1. -. 0.95 = 0.0500000000000000444 @@ -264,109 +256,101 @@ let%test_module _ = # let x = incr 0.95 in sprintf "%.0f / %.1f / %.2f / %.3f / %.20f" x x x x x ;; - : string = "1 / 1.0 / 0.95 / 0.950 / 0.95000000000000006661" - *) - let f = - if f >= 1000. - then f - else ( - let x = Printf.sprintf "%.20f" f in - let spot = String.index_exn x '.' in - (* the following condition is only meant to work for small multiples of 0.05 *) - let ( + ) = Int.( + ) in - let ( = ) = Char.( = ) in - if x.[spot + 2] = '4' && x.[spot + 3] = '9' && x.[spot + 4] = '9' - then (* something like 0.94999999999999995559 *) - incr f - else f) - in - both (decr f) closer_to_zero; - both f at - ;; - - let%test_unit _ = test nan "nan " - let%test_unit _ = test 0.0 "0 " - let%test_unit _ = both min_positive_subnormal_value "0 " - let%test_unit _ = both infinity "inf " - let%test_unit _ = boundary 0.05 ~closer_to_zero:"0 " ~at:"0.1" - let%test_unit _ = boundary 0.15 ~closer_to_zero:"0.1" ~at:"0.2" - - (* glibc printf resolves ties to even, cf. + *) + let f = + if f >= 1000. + then f + else ( + let x = Printf.sprintf "%.20f" f in + let spot = String.index_exn x '.' in + (* the following condition is only meant to work for small multiples of 0.05 *) + let ( + ) = Int.( + ) in + let ( = ) = Char.( = ) in + if x.[spot + 2] = '4' && x.[spot + 3] = '9' && x.[spot + 4] = '9' + then (* something like 0.94999999999999995559 *) + incr f + else f) + in + both (decr f) closer_to_zero; + both f at + ;; + + let%test_unit _ = test nan "nan " + let%test_unit _ = test 0.0 "0 " + let%test_unit _ = both min_positive_subnormal_value "0 " + let%test_unit _ = both infinity "inf " + let%test_unit _ = boundary 0.05 ~closer_to_zero:"0 " ~at:"0.1" + let%test_unit _ = boundary 0.15 ~closer_to_zero:"0.1" ~at:"0.2" + + (* glibc printf resolves ties to even, cf. http://www.exploringbinary.com/inconsistent-rounding-of-printed-floating-point-numbers/ Ties are resolved differently in JavaScript - mark some tests as no running with JavaScript. - *) - let%test_unit (_ [@tags "no-js"]) = - boundary (* tie *) 0.25 ~closer_to_zero:"0.2" ~at:"0.2" - ;; - - let%test_unit (_ [@tags "no-js"]) = - boundary (incr 0.25) ~closer_to_zero:"0.2" ~at:"0.3" - ;; - - let%test_unit _ = boundary 0.35 ~closer_to_zero:"0.3" ~at:"0.4" - let%test_unit _ = boundary 0.45 ~closer_to_zero:"0.4" ~at:"0.5" - let%test_unit _ = both 0.50 "0.5" - let%test_unit _ = boundary 0.55 ~closer_to_zero:"0.5" ~at:"0.6" - let%test_unit _ = boundary 0.65 ~closer_to_zero:"0.6" ~at:"0.7" - - (* this time tie-to-even means round away from 0 *) - let%test_unit _ = boundary (* tie *) 0.75 ~closer_to_zero:"0.7" ~at:"0.8" - let%test_unit _ = boundary 0.85 ~closer_to_zero:"0.8" ~at:"0.9" - let%test_unit _ = boundary 0.95 ~closer_to_zero:"0.9" ~at:"1 " - let%test_unit _ = boundary 1.05 ~closer_to_zero:"1 " ~at:"1.1" - let%test_unit (_ [@tags "no-js"]) = boundary 3.25 ~closer_to_zero:"3.2" ~at:"3.2" - - let%test_unit (_ [@tags "no-js"]) = - boundary (incr 3.25) ~closer_to_zero:"3.2" ~at:"3.3" - ;; - - let%test_unit _ = boundary 3.75 ~closer_to_zero:"3.7" ~at:"3.8" - let%test_unit _ = boundary 9.95 ~closer_to_zero:"9.9" ~at:"10 " - let%test_unit _ = boundary 10.05 ~closer_to_zero:"10 " ~at:"10.1" - let%test_unit _ = boundary 100.05 ~closer_to_zero:"100 " ~at:"100.1" - - let%test_unit (_ [@tags "no-js"]) = - boundary (* tie *) 999.25 ~closer_to_zero:"999.2" ~at:"999.2" - ;; - - let%test_unit (_ [@tags "no-js"]) = - boundary (incr 999.25) ~closer_to_zero:"999.2" ~at:"999.3" - ;; - - let%test_unit _ = boundary 999.75 ~closer_to_zero:"999.7" ~at:"999.8" - let%test_unit _ = boundary 999.95 ~closer_to_zero:"999.9" ~at:"1k " - let%test_unit _ = both 1000. "1k " - - (* some ties which we resolve manually in [iround_ratio_exn] *) - let%test_unit _ = boundary 1050. ~closer_to_zero:"1k " ~at:"1k " - let%test_unit _ = boundary (incr 1050.) ~closer_to_zero:"1k " ~at:"1k1" - let%test_unit _ = boundary 1950. ~closer_to_zero:"1k9" ~at:"2k " - let%test_unit _ = boundary 3250. ~closer_to_zero:"3k2" ~at:"3k2" - let%test_unit _ = boundary (incr 3250.) ~closer_to_zero:"3k2" ~at:"3k3" - let%test_unit _ = boundary 9950. ~closer_to_zero:"9k9" ~at:"10k " - let%test_unit _ = boundary 33_250. ~closer_to_zero:"33k2" ~at:"33k2" - let%test_unit _ = boundary (incr 33_250.) ~closer_to_zero:"33k2" ~at:"33k3" - let%test_unit _ = boundary 33_350. ~closer_to_zero:"33k3" ~at:"33k4" - let%test_unit _ = boundary 33_750. ~closer_to_zero:"33k7" ~at:"33k8" - let%test_unit _ = boundary 333_250. ~closer_to_zero:"333k2" ~at:"333k2" - let%test_unit _ = boundary (incr 333_250.) ~closer_to_zero:"333k2" ~at:"333k3" - let%test_unit _ = boundary 333_750. ~closer_to_zero:"333k7" ~at:"333k8" - let%test_unit _ = boundary 999_850. ~closer_to_zero:"999k8" ~at:"999k8" - let%test_unit _ = boundary (incr 999_850.) ~closer_to_zero:"999k8" ~at:"999k9" - let%test_unit _ = boundary 999_950. ~closer_to_zero:"999k9" ~at:"1m " - let%test_unit _ = boundary 1_050_000. ~closer_to_zero:"1m " ~at:"1m " - let%test_unit _ = boundary (incr 1_050_000.) ~closer_to_zero:"1m " ~at:"1m1" - let%test_unit _ = boundary 999_950_000. ~closer_to_zero:"999m9" ~at:"1g " - let%test_unit _ = boundary 999_950_000_000. ~closer_to_zero:"999g9" ~at:"1t " - let%test_unit _ = boundary 999_950_000_000_000. ~closer_to_zero:"999t9" ~at:"1p " - - let%test_unit _ = - boundary 999_950_000_000_000_000. ~closer_to_zero:"999p9" ~at:"1.0e+18" - ;; - - (* Test the boundary between the subnormals and the normals. *) - let%test_unit _ = boundary min_positive_normal_value ~closer_to_zero:"0 " ~at:"0 " - end) -;; + *) + let%test_unit (_ [@tags "no-js"]) = + boundary (* tie *) 0.25 ~closer_to_zero:"0.2" ~at:"0.2" + ;; + + let%test_unit (_ [@tags "no-js"]) = boundary (incr 0.25) ~closer_to_zero:"0.2" ~at:"0.3" + let%test_unit _ = boundary 0.35 ~closer_to_zero:"0.3" ~at:"0.4" + let%test_unit _ = boundary 0.45 ~closer_to_zero:"0.4" ~at:"0.5" + let%test_unit _ = both 0.50 "0.5" + let%test_unit _ = boundary 0.55 ~closer_to_zero:"0.5" ~at:"0.6" + let%test_unit _ = boundary 0.65 ~closer_to_zero:"0.6" ~at:"0.7" + + (* this time tie-to-even means round away from 0 *) + let%test_unit _ = boundary (* tie *) 0.75 ~closer_to_zero:"0.7" ~at:"0.8" + let%test_unit _ = boundary 0.85 ~closer_to_zero:"0.8" ~at:"0.9" + let%test_unit _ = boundary 0.95 ~closer_to_zero:"0.9" ~at:"1 " + let%test_unit _ = boundary 1.05 ~closer_to_zero:"1 " ~at:"1.1" + let%test_unit (_ [@tags "no-js"]) = boundary 3.25 ~closer_to_zero:"3.2" ~at:"3.2" + let%test_unit (_ [@tags "no-js"]) = boundary (incr 3.25) ~closer_to_zero:"3.2" ~at:"3.3" + let%test_unit _ = boundary 3.75 ~closer_to_zero:"3.7" ~at:"3.8" + let%test_unit _ = boundary 9.95 ~closer_to_zero:"9.9" ~at:"10 " + let%test_unit _ = boundary 10.05 ~closer_to_zero:"10 " ~at:"10.1" + let%test_unit _ = boundary 100.05 ~closer_to_zero:"100 " ~at:"100.1" + + let%test_unit (_ [@tags "no-js"]) = + boundary (* tie *) 999.25 ~closer_to_zero:"999.2" ~at:"999.2" + ;; + + let%test_unit (_ [@tags "no-js"]) = + boundary (incr 999.25) ~closer_to_zero:"999.2" ~at:"999.3" + ;; + + let%test_unit _ = boundary 999.75 ~closer_to_zero:"999.7" ~at:"999.8" + let%test_unit _ = boundary 999.95 ~closer_to_zero:"999.9" ~at:"1k " + let%test_unit _ = both 1000. "1k " + + (* some ties which we resolve manually in [iround_ratio_exn] *) + let%test_unit _ = boundary 1050. ~closer_to_zero:"1k " ~at:"1k " + let%test_unit _ = boundary (incr 1050.) ~closer_to_zero:"1k " ~at:"1k1" + let%test_unit _ = boundary 1950. ~closer_to_zero:"1k9" ~at:"2k " + let%test_unit _ = boundary 3250. ~closer_to_zero:"3k2" ~at:"3k2" + let%test_unit _ = boundary (incr 3250.) ~closer_to_zero:"3k2" ~at:"3k3" + let%test_unit _ = boundary 9950. ~closer_to_zero:"9k9" ~at:"10k " + let%test_unit _ = boundary 33_250. ~closer_to_zero:"33k2" ~at:"33k2" + let%test_unit _ = boundary (incr 33_250.) ~closer_to_zero:"33k2" ~at:"33k3" + let%test_unit _ = boundary 33_350. ~closer_to_zero:"33k3" ~at:"33k4" + let%test_unit _ = boundary 33_750. ~closer_to_zero:"33k7" ~at:"33k8" + let%test_unit _ = boundary 333_250. ~closer_to_zero:"333k2" ~at:"333k2" + let%test_unit _ = boundary (incr 333_250.) ~closer_to_zero:"333k2" ~at:"333k3" + let%test_unit _ = boundary 333_750. ~closer_to_zero:"333k7" ~at:"333k8" + let%test_unit _ = boundary 999_850. ~closer_to_zero:"999k8" ~at:"999k8" + let%test_unit _ = boundary (incr 999_850.) ~closer_to_zero:"999k8" ~at:"999k9" + let%test_unit _ = boundary 999_950. ~closer_to_zero:"999k9" ~at:"1m " + let%test_unit _ = boundary 1_050_000. ~closer_to_zero:"1m " ~at:"1m " + let%test_unit _ = boundary (incr 1_050_000.) ~closer_to_zero:"1m " ~at:"1m1" + let%test_unit _ = boundary 999_950_000. ~closer_to_zero:"999m9" ~at:"1g " + let%test_unit _ = boundary 999_950_000_000. ~closer_to_zero:"999g9" ~at:"1t " + let%test_unit _ = boundary 999_950_000_000_000. ~closer_to_zero:"999t9" ~at:"1p " + + let%test_unit _ = + boundary 999_950_000_000_000_000. ~closer_to_zero:"999p9" ~at:"1.0e+18" + ;; + + (* Test the boundary between the subnormals and the normals. *) + let%test_unit _ = boundary min_positive_normal_value ~closer_to_zero:"0 " ~at:"0 " +end let%test "int_pow" = let tol = 1e-15 in @@ -434,399 +418,381 @@ let%test_unit "sign_or_nan" = [ 1e-30, Sign_or_nan.Pos; -0., Zero; 0., Zero; neg_infinity, Neg; nan, Nan ] ;; -let%test_module _ = - (module struct - (* Some of the following tests used to live in lib_test/core_float_test.ml. *) +module%test _ = struct + (* Some of the following tests used to live in lib_test/core_float_test.ml. *) - let () = Random.init 137 + let () = Random.init 137 - (* round: + (* round: ... <-)[-><-)[-><-)[-><-)[-><-)[-><-)[-> ... ... -+-----+-----+-----+-----+-----+-----+- ... ... -3 -2 -1 0 1 2 3 ... so round x -. x should be in (-0.5,0.5] - *) - let round_test x = - let y = round x in - -0.5 < y -. x && y -. x <= 0.5 - ;; - - let iround_up_vs_down_test x = - let expected_difference = if Parts.fractional (modf x) = 0. then 0 else 1 in - match iround_up x, iround_down x with - | Some x, Some y -> Int.(x - y = expected_difference) - | _, _ -> true - ;; - - let test_all_six + *) + let round_test x = + let y = round x in + -0.5 < y -. x && y -. x <= 0.5 + ;; + + let iround_up_vs_down_test x = + let expected_difference = if Parts.fractional (modf x) = 0. then 0 else 1 in + match iround_up x, iround_down x with + | Some x, Some y -> Int.(x - y = expected_difference) + | _, _ -> true + ;; + + let test_all_six + x + ~specialized_iround + ~specialized_iround_exn + ~float_rounding + ~dir + ~validate + = + let result1 = iround x ~dir in + let result2 = Option.try_with (fun () -> iround_exn x ~dir) in + let result3 = specialized_iround x in + let result4 = Option.try_with (fun () -> specialized_iround_exn x) in + let result5 = Option.try_with (fun () -> Int.of_float (float_rounding x)) in + let result6 = Option.try_with (fun () -> Int.of_float (round ~dir x)) in + let ( = ) = Stdlib.( = ) in + if result1 = result2 + && result2 = result3 + && result3 = result4 + && result4 = result5 + && result5 = result6 + then validate result1 + else false + ;; + + (* iround ~dir:`Nearest built so this should always be true *) + let iround_nearest_test x = + test_all_six x - ~specialized_iround - ~specialized_iround_exn - ~float_rounding - ~dir - ~validate - = - let result1 = iround x ~dir in - let result2 = Option.try_with (fun () -> iround_exn x ~dir) in - let result3 = specialized_iround x in - let result4 = Option.try_with (fun () -> specialized_iround_exn x) in - let result5 = Option.try_with (fun () -> Int.of_float (float_rounding x)) in - let result6 = Option.try_with (fun () -> Int.of_float (round ~dir x)) in - let ( = ) = Stdlib.( = ) in - if result1 = result2 - && result2 = result3 - && result3 = result4 - && result4 = result5 - && result5 = result6 - then validate result1 - else false - ;; - - (* iround ~dir:`Nearest built so this should always be true *) - let iround_nearest_test x = - test_all_six - x - ~specialized_iround:iround_nearest - ~specialized_iround_exn:iround_nearest_exn - ~float_rounding:round_nearest - ~dir:`Nearest - ~validate:(function - | None -> true - | Some y -> - let y = of_int y in - -0.5 < y -. x && y -. x <= 0.5) - ;; - - (* iround_down: + ~specialized_iround:iround_nearest + ~specialized_iround_exn:iround_nearest_exn + ~float_rounding:round_nearest + ~dir:`Nearest + ~validate:(function + | None -> true + | Some y -> + let y = of_int y in + -0.5 < y -. x && y -. x <= 0.5) + ;; + + (* iround_down: ... )[<---)[<---)[<---)[<---)[<---)[<---)[ ... ... -+-----+-----+-----+-----+-----+-----+- ... ... -3 -2 -1 0 1 2 3 ... so x -. iround_down x should be in [0,1) - *) - let iround_down_test x = - test_all_six - x - ~specialized_iround:iround_down - ~specialized_iround_exn:iround_down_exn - ~float_rounding:round_down - ~dir:`Down - ~validate:(function - | None -> true - | Some y -> - let y = of_int y in - 0. <= x -. y && x -. y < 1.) - ;; - - (* iround_up: + *) + let iround_down_test x = + test_all_six + x + ~specialized_iround:iround_down + ~specialized_iround_exn:iround_down_exn + ~float_rounding:round_down + ~dir:`Down + ~validate:(function + | None -> true + | Some y -> + let y = of_int y in + 0. <= x -. y && x -. y < 1.) + ;; + + (* iround_up: ... ](--->](--->](--->](--->](--->](--->]( ... ... -+-----+-----+-----+-----+-----+-----+- ... ... -3 -2 -1 0 1 2 3 ... so iround_up x -. x should be in [0,1) - *) - let iround_up_test x = - test_all_six - x - ~specialized_iround:iround_up - ~specialized_iround_exn:iround_up_exn - ~float_rounding:round_up - ~dir:`Up - ~validate:(function - | None -> true - | Some y -> - let y = of_int y in - 0. <= y -. x && y -. x < 1.) - ;; - - (* iround_towards_zero: + *) + let iround_up_test x = + test_all_six + x + ~specialized_iround:iround_up + ~specialized_iround_exn:iround_up_exn + ~float_rounding:round_up + ~dir:`Up + ~validate:(function + | None -> true + | Some y -> + let y = of_int y in + 0. <= y -. x && y -. x < 1.) + ;; + + (* iround_towards_zero: ... ](--->](--->](---><--->)[<---)[<---)[ ... ... -+-----+-----+-----+-----+-----+-----+- ... ... -3 -2 -1 0 1 2 3 ... so abs x -. abs (iround_towards_zero x) should be in [0,1) - *) - let iround_towards_zero_test x = - test_all_six - x - ~specialized_iround:iround_towards_zero - ~specialized_iround_exn:iround_towards_zero_exn - ~float_rounding:round_towards_zero - ~dir:`Zero - ~validate:(function - | None -> true - | Some y -> - let x = abs x in - let y = abs (of_int y) in - 0. <= x -. y && x -. y < 1. && (Sign.(sign_exn x = sign_exn y) || y = 0.0)) - ;; - - (* Easy cases that used to live inline with the code above. *) - let%test_unit _ = [%test_result: int option] (iround_up (-3.4)) ~expect:(Some (-3)) - let%test_unit _ = [%test_result: int option] (iround_up 0.0) ~expect:(Some 0) - let%test_unit _ = [%test_result: int option] (iround_up 3.4) ~expect:(Some 4) - let%test_unit _ = [%test_result: int] (iround_up_exn (-3.4)) ~expect:(-3) - let%test_unit _ = [%test_result: int] (iround_up_exn 0.0) ~expect:0 - let%test_unit _ = [%test_result: int] (iround_up_exn 3.4) ~expect:4 - let%test_unit _ = [%test_result: int option] (iround_down (-3.4)) ~expect:(Some (-4)) - let%test_unit _ = [%test_result: int option] (iround_down 0.0) ~expect:(Some 0) - let%test_unit _ = [%test_result: int option] (iround_down 3.4) ~expect:(Some 3) - let%test_unit _ = [%test_result: int] (iround_down_exn (-3.4)) ~expect:(-4) - let%test_unit _ = [%test_result: int] (iround_down_exn 0.0) ~expect:0 - let%test_unit _ = [%test_result: int] (iround_down_exn 3.4) ~expect:3 - - let%test_unit _ = - [%test_result: int option] (iround_towards_zero (-3.4)) ~expect:(Some (-3)) - ;; - - let%test_unit _ = - [%test_result: int option] (iround_towards_zero 0.0) ~expect:(Some 0) - ;; - - let%test_unit _ = - [%test_result: int option] (iround_towards_zero 3.4) ~expect:(Some 3) - ;; - - let%test_unit _ = [%test_result: int] (iround_towards_zero_exn (-3.4)) ~expect:(-3) - let%test_unit _ = [%test_result: int] (iround_towards_zero_exn 0.0) ~expect:0 - let%test_unit _ = [%test_result: int] (iround_towards_zero_exn 3.4) ~expect:3 - - let%test_unit _ = - [%test_result: int option] (iround_nearest (-3.6)) ~expect:(Some (-4)) - ;; - - let%test_unit _ = - [%test_result: int option] (iround_nearest (-3.5)) ~expect:(Some (-3)) - ;; - - let%test_unit _ = - [%test_result: int option] (iround_nearest (-3.4)) ~expect:(Some (-3)) - ;; - - let%test_unit _ = [%test_result: int option] (iround_nearest 0.0) ~expect:(Some 0) - let%test_unit _ = [%test_result: int option] (iround_nearest 3.4) ~expect:(Some 3) - let%test_unit _ = [%test_result: int option] (iround_nearest 3.5) ~expect:(Some 4) - let%test_unit _ = [%test_result: int option] (iround_nearest 3.6) ~expect:(Some 4) - let%test_unit _ = [%test_result: int] (iround_nearest_exn (-3.6)) ~expect:(-4) - let%test_unit _ = [%test_result: int] (iround_nearest_exn (-3.5)) ~expect:(-3) - let%test_unit _ = [%test_result: int] (iround_nearest_exn (-3.4)) ~expect:(-3) - let%test_unit _ = [%test_result: int] (iround_nearest_exn 0.0) ~expect:0 - let%test_unit _ = [%test_result: int] (iround_nearest_exn 3.4) ~expect:3 - let%test_unit _ = [%test_result: int] (iround_nearest_exn 3.5) ~expect:4 - let%test_unit _ = [%test_result: int] (iround_nearest_exn 3.6) ~expect:4 - - let special_values_test () = - [%test_result: float] (round (-1.50001)) ~expect:(-2.); - [%test_result: float] (round (-1.5)) ~expect:(-1.); - [%test_result: float] (round (-0.50001)) ~expect:(-1.); - [%test_result: float] (round (-0.5)) ~expect:0.; - [%test_result: float] (round 0.49999) ~expect:0.; - [%test_result: float] (round 0.5) ~expect:1.; - [%test_result: float] (round 1.49999) ~expect:1.; - [%test_result: float] (round 1.5) ~expect:2.; - [%test_result: int] (iround_exn ~dir:`Up (-2.)) ~expect:(-2); - [%test_result: int] (iround_exn ~dir:`Up (-1.9999)) ~expect:(-1); - [%test_result: int] (iround_exn ~dir:`Up (-1.)) ~expect:(-1); - [%test_result: int] (iround_exn ~dir:`Up (-0.9999)) ~expect:0; - [%test_result: int] (iround_exn ~dir:`Up 0.) ~expect:0; - [%test_result: int] (iround_exn ~dir:`Up 0.00001) ~expect:1; - [%test_result: int] (iround_exn ~dir:`Up 1.) ~expect:1; - [%test_result: int] (iround_exn ~dir:`Up 1.00001) ~expect:2; - [%test_result: int] (iround_up_exn (-2.)) ~expect:(-2); - [%test_result: int] (iround_up_exn (-1.9999)) ~expect:(-1); - [%test_result: int] (iround_up_exn (-1.)) ~expect:(-1); - [%test_result: int] (iround_up_exn (-0.9999)) ~expect:0; - [%test_result: int] (iround_up_exn 0.) ~expect:0; - [%test_result: int] (iround_up_exn 0.00001) ~expect:1; - [%test_result: int] (iround_up_exn 1.) ~expect:1; - [%test_result: int] (iround_up_exn 1.00001) ~expect:2; - [%test_result: int] (iround_exn ~dir:`Down (-1.00001)) ~expect:(-2); - [%test_result: int] (iround_exn ~dir:`Down (-1.)) ~expect:(-1); - [%test_result: int] (iround_exn ~dir:`Down (-0.00001)) ~expect:(-1); - [%test_result: int] (iround_exn ~dir:`Down 0.) ~expect:0; - [%test_result: int] (iround_exn ~dir:`Down 0.99999) ~expect:0; - [%test_result: int] (iround_exn ~dir:`Down 1.) ~expect:1; - [%test_result: int] (iround_exn ~dir:`Down 1.99999) ~expect:1; - [%test_result: int] (iround_exn ~dir:`Down 2.) ~expect:2; - [%test_result: int] (iround_down_exn (-1.00001)) ~expect:(-2); - [%test_result: int] (iround_down_exn (-1.)) ~expect:(-1); - [%test_result: int] (iround_down_exn (-0.00001)) ~expect:(-1); - [%test_result: int] (iround_down_exn 0.) ~expect:0; - [%test_result: int] (iround_down_exn 0.99999) ~expect:0; - [%test_result: int] (iround_down_exn 1.) ~expect:1; - [%test_result: int] (iround_down_exn 1.99999) ~expect:1; - [%test_result: int] (iround_down_exn 2.) ~expect:2; - [%test_result: int] (iround_exn ~dir:`Zero (-2.)) ~expect:(-2); - [%test_result: int] (iround_exn ~dir:`Zero (-1.99999)) ~expect:(-1); - [%test_result: int] (iround_exn ~dir:`Zero (-1.)) ~expect:(-1); - [%test_result: int] (iround_exn ~dir:`Zero (-0.99999)) ~expect:0; - [%test_result: int] (iround_exn ~dir:`Zero 0.99999) ~expect:0; - [%test_result: int] (iround_exn ~dir:`Zero 1.) ~expect:1; - [%test_result: int] (iround_exn ~dir:`Zero 1.99999) ~expect:1; - [%test_result: int] (iround_exn ~dir:`Zero 2.) ~expect:2 - ;; - - let is_64_bit_platform = of_int Int.max_value >= 2. **. 60. - - (* Tests for values close to [iround_lbound] and [iround_ubound]. *) - let extremities_test ~round = - let ( + ) = Int.( + ) in - let ( - ) = Int.( - ) in - if is_64_bit_platform - then ( - (* 64 bits *) - [%test_result: int option] - (round ((2.0 **. 62.) -. 512.)) - ~expect:(Some (Int.max_value - 511)); - [%test_result: int option] - (round ((2.0 **. 62.) -. 1024.)) - ~expect:(Some (Int.max_value - 1023)); - [%test_result: int option] (round (-.(2.0 **. 62.))) ~expect:(Some Int.min_value); - [%test_result: int option] - (round (-.((2.0 **. 62.) -. 512.))) - ~expect:(Some (Int.min_value + 512)); - [%test_result: int option] (round (2.0 **. 62.)) ~expect:None; - [%test_result: int option] (round (-.((2.0 **. 62.) +. 1024.))) ~expect:None) + *) + let iround_towards_zero_test x = + test_all_six + x + ~specialized_iround:iround_towards_zero + ~specialized_iround_exn:iround_towards_zero_exn + ~float_rounding:round_towards_zero + ~dir:`Zero + ~validate:(function + | None -> true + | Some y -> + let x = abs x in + let y = abs (of_int y) in + 0. <= x -. y && x -. y < 1. && (Sign.(sign_exn x = sign_exn y) || y = 0.0)) + ;; + + (* Easy cases that used to live inline with the code above. *) + let%test_unit _ = [%test_result: int option] (iround_up (-3.4)) ~expect:(Some (-3)) + let%test_unit _ = [%test_result: int option] (iround_up 0.0) ~expect:(Some 0) + let%test_unit _ = [%test_result: int option] (iround_up 3.4) ~expect:(Some 4) + let%test_unit _ = [%test_result: int] (iround_up_exn (-3.4)) ~expect:(-3) + let%test_unit _ = [%test_result: int] (iround_up_exn 0.0) ~expect:0 + let%test_unit _ = [%test_result: int] (iround_up_exn 3.4) ~expect:4 + let%test_unit _ = [%test_result: int option] (iround_down (-3.4)) ~expect:(Some (-4)) + let%test_unit _ = [%test_result: int option] (iround_down 0.0) ~expect:(Some 0) + let%test_unit _ = [%test_result: int option] (iround_down 3.4) ~expect:(Some 3) + let%test_unit _ = [%test_result: int] (iround_down_exn (-3.4)) ~expect:(-4) + let%test_unit _ = [%test_result: int] (iround_down_exn 0.0) ~expect:0 + let%test_unit _ = [%test_result: int] (iround_down_exn 3.4) ~expect:3 + + let%test_unit _ = + [%test_result: int option] (iround_towards_zero (-3.4)) ~expect:(Some (-3)) + ;; + + let%test_unit _ = [%test_result: int option] (iround_towards_zero 0.0) ~expect:(Some 0) + let%test_unit _ = [%test_result: int option] (iround_towards_zero 3.4) ~expect:(Some 3) + let%test_unit _ = [%test_result: int] (iround_towards_zero_exn (-3.4)) ~expect:(-3) + let%test_unit _ = [%test_result: int] (iround_towards_zero_exn 0.0) ~expect:0 + let%test_unit _ = [%test_result: int] (iround_towards_zero_exn 3.4) ~expect:3 + let%test_unit _ = [%test_result: int option] (iround_nearest (-3.6)) ~expect:(Some (-4)) + let%test_unit _ = [%test_result: int option] (iround_nearest (-3.5)) ~expect:(Some (-3)) + let%test_unit _ = [%test_result: int option] (iround_nearest (-3.4)) ~expect:(Some (-3)) + let%test_unit _ = [%test_result: int option] (iround_nearest 0.0) ~expect:(Some 0) + let%test_unit _ = [%test_result: int option] (iround_nearest 3.4) ~expect:(Some 3) + let%test_unit _ = [%test_result: int option] (iround_nearest 3.5) ~expect:(Some 4) + let%test_unit _ = [%test_result: int option] (iround_nearest 3.6) ~expect:(Some 4) + let%test_unit _ = [%test_result: int] (iround_nearest_exn (-3.6)) ~expect:(-4) + let%test_unit _ = [%test_result: int] (iround_nearest_exn (-3.5)) ~expect:(-3) + let%test_unit _ = [%test_result: int] (iround_nearest_exn (-3.4)) ~expect:(-3) + let%test_unit _ = [%test_result: int] (iround_nearest_exn 0.0) ~expect:0 + let%test_unit _ = [%test_result: int] (iround_nearest_exn 3.4) ~expect:3 + let%test_unit _ = [%test_result: int] (iround_nearest_exn 3.5) ~expect:4 + let%test_unit _ = [%test_result: int] (iround_nearest_exn 3.6) ~expect:4 + + let special_values_test () = + [%test_result: float] (round (-1.50001)) ~expect:(-2.); + [%test_result: float] (round (-1.5)) ~expect:(-1.); + [%test_result: float] (round (-0.50001)) ~expect:(-1.); + [%test_result: float] (round (-0.5)) ~expect:0.; + [%test_result: float] (round 0.49999) ~expect:0.; + [%test_result: float] (round 0.5) ~expect:1.; + [%test_result: float] (round 1.49999) ~expect:1.; + [%test_result: float] (round 1.5) ~expect:2.; + [%test_result: int] (iround_exn ~dir:`Up (-2.)) ~expect:(-2); + [%test_result: int] (iround_exn ~dir:`Up (-1.9999)) ~expect:(-1); + [%test_result: int] (iround_exn ~dir:`Up (-1.)) ~expect:(-1); + [%test_result: int] (iround_exn ~dir:`Up (-0.9999)) ~expect:0; + [%test_result: int] (iround_exn ~dir:`Up 0.) ~expect:0; + [%test_result: int] (iround_exn ~dir:`Up 0.00001) ~expect:1; + [%test_result: int] (iround_exn ~dir:`Up 1.) ~expect:1; + [%test_result: int] (iround_exn ~dir:`Up 1.00001) ~expect:2; + [%test_result: int] (iround_up_exn (-2.)) ~expect:(-2); + [%test_result: int] (iround_up_exn (-1.9999)) ~expect:(-1); + [%test_result: int] (iround_up_exn (-1.)) ~expect:(-1); + [%test_result: int] (iround_up_exn (-0.9999)) ~expect:0; + [%test_result: int] (iround_up_exn 0.) ~expect:0; + [%test_result: int] (iround_up_exn 0.00001) ~expect:1; + [%test_result: int] (iround_up_exn 1.) ~expect:1; + [%test_result: int] (iround_up_exn 1.00001) ~expect:2; + [%test_result: int] (iround_exn ~dir:`Down (-1.00001)) ~expect:(-2); + [%test_result: int] (iround_exn ~dir:`Down (-1.)) ~expect:(-1); + [%test_result: int] (iround_exn ~dir:`Down (-0.00001)) ~expect:(-1); + [%test_result: int] (iround_exn ~dir:`Down 0.) ~expect:0; + [%test_result: int] (iround_exn ~dir:`Down 0.99999) ~expect:0; + [%test_result: int] (iround_exn ~dir:`Down 1.) ~expect:1; + [%test_result: int] (iround_exn ~dir:`Down 1.99999) ~expect:1; + [%test_result: int] (iround_exn ~dir:`Down 2.) ~expect:2; + [%test_result: int] (iround_down_exn (-1.00001)) ~expect:(-2); + [%test_result: int] (iround_down_exn (-1.)) ~expect:(-1); + [%test_result: int] (iround_down_exn (-0.00001)) ~expect:(-1); + [%test_result: int] (iround_down_exn 0.) ~expect:0; + [%test_result: int] (iround_down_exn 0.99999) ~expect:0; + [%test_result: int] (iround_down_exn 1.) ~expect:1; + [%test_result: int] (iround_down_exn 1.99999) ~expect:1; + [%test_result: int] (iround_down_exn 2.) ~expect:2; + [%test_result: int] (iround_exn ~dir:`Zero (-2.)) ~expect:(-2); + [%test_result: int] (iround_exn ~dir:`Zero (-1.99999)) ~expect:(-1); + [%test_result: int] (iround_exn ~dir:`Zero (-1.)) ~expect:(-1); + [%test_result: int] (iround_exn ~dir:`Zero (-0.99999)) ~expect:0; + [%test_result: int] (iround_exn ~dir:`Zero 0.99999) ~expect:0; + [%test_result: int] (iround_exn ~dir:`Zero 1.) ~expect:1; + [%test_result: int] (iround_exn ~dir:`Zero 1.99999) ~expect:1; + [%test_result: int] (iround_exn ~dir:`Zero 2.) ~expect:2 + ;; + + let is_64_bit_platform = of_int Int.max_value >= 2. **. 60. + + (* Tests for values close to [iround_lbound] and [iround_ubound]. *) + let extremities_test ~round = + let ( + ) = Int.( + ) in + let ( - ) = Int.( - ) in + if is_64_bit_platform + then ( + (* 64 bits *) + [%test_result: int option] + (round ((2.0 **. 62.) -. 512.)) + ~expect:(Some (Int.max_value - 511)); + [%test_result: int option] + (round ((2.0 **. 62.) -. 1024.)) + ~expect:(Some (Int.max_value - 1023)); + [%test_result: int option] (round (-.(2.0 **. 62.))) ~expect:(Some Int.min_value); + [%test_result: int option] + (round (-.((2.0 **. 62.) -. 512.))) + ~expect:(Some (Int.min_value + 512)); + [%test_result: int option] (round (2.0 **. 62.)) ~expect:None; + [%test_result: int option] (round (-.((2.0 **. 62.) +. 1024.))) ~expect:None) + else ( + let int_size_minus_one = of_int (Int.num_bits - 1) in + (* 32 bits *) + [%test_result: int option] + (round ((2.0 **. int_size_minus_one) -. 1.)) + ~expect:(Some Int.max_value); + [%test_result: int option] + (round ((2.0 **. int_size_minus_one) -. 2.)) + ~expect:(Some (Int.max_value - 1)); + [%test_result: int option] + (round (-.(2.0 **. int_size_minus_one))) + ~expect:(Some Int.min_value); + [%test_result: int option] + (round (-.((2.0 **. int_size_minus_one) -. 1.))) + ~expect:(Some (Int.min_value + 1)); + [%test_result: int option] (round (2.0 **. int_size_minus_one)) ~expect:None; + [%test_result: int option] + (round (-.((2.0 **. int_size_minus_one) +. 1.))) + ~expect:None) + ;; + + let%test_unit _ = extremities_test ~round:iround_down + let%test_unit _ = extremities_test ~round:iround_up + let%test_unit _ = extremities_test ~round:iround_nearest + let%test_unit _ = extremities_test ~round:iround_towards_zero + + (* test values beyond the integers range *) + let large_value_test x = + [%test_result: int option] (iround_down x) ~expect:None; + [%test_result: int option] (iround ~dir:`Down x) ~expect:None; + [%test_result: int option] (iround_up x) ~expect:None; + [%test_result: int option] (iround ~dir:`Up x) ~expect:None; + [%test_result: int option] (iround_towards_zero x) ~expect:None; + [%test_result: int option] (iround ~dir:`Zero x) ~expect:None; + [%test_result: int option] (iround_nearest x) ~expect:None; + [%test_result: int option] (iround ~dir:`Nearest x) ~expect:None; + assert (Exn.does_raise (fun () -> iround_down_exn x)); + assert (Exn.does_raise (fun () -> iround_exn ~dir:`Down x)); + assert (Exn.does_raise (fun () -> iround_up_exn x)); + assert (Exn.does_raise (fun () -> iround_exn ~dir:`Up x)); + assert (Exn.does_raise (fun () -> iround_towards_zero_exn x)); + assert (Exn.does_raise (fun () -> iround_exn ~dir:`Zero x)); + assert (Exn.does_raise (fun () -> iround_nearest_exn x)); + assert (Exn.does_raise (fun () -> iround_exn ~dir:`Nearest x)); + [%test_result: float] (round_down x) ~expect:x; + [%test_result: float] (round ~dir:`Down x) ~expect:x; + [%test_result: float] (round_up x) ~expect:x; + [%test_result: float] (round ~dir:`Up x) ~expect:x; + [%test_result: float] (round_towards_zero x) ~expect:x; + [%test_result: float] (round ~dir:`Zero x) ~expect:x; + [%test_result: float] (round_nearest x) ~expect:x; + [%test_result: float] (round ~dir:`Nearest x) ~expect:x + ;; + + let large_numbers = + let ( + ) = Int.( + ) in + let ( - ) = Int.( - ) in + List.concat + (List.init (1024 - 64) ~f:(fun x -> + let x = of_int (x + 64) in + let y = + [ 2. **. x + ; (2. **. x) -. (2. **. (x -. 53.)) + ; (* one ulp down *) + (2. **. x) +. (2. **. (x -. 52.)) + ] + (* one ulp up *) + in + y @ List.map y ~f:neg)) + @ [ infinity; neg_infinity ] + ;; + + let%test_unit _ = List.iter large_numbers ~f:large_value_test + + let numbers_near_powers_of_two = + List.concat + (List.init 64 ~f:(fun i -> + let pow2 = 2. **. of_int i in + let x = + [ pow2 + ; one_ulp `Down (pow2 +. 0.5) + ; pow2 +. 0.5 + ; one_ulp `Down (pow2 +. 1.0) + ; pow2 +. 1.0 + ; one_ulp `Down (pow2 +. 1.5) + ; pow2 +. 1.5 + ; one_ulp `Down (pow2 +. 2.0) + ; pow2 +. 2.0 + ; one_ulp `Down ((pow2 *. 2.0) -. 1.0) + ; one_ulp `Down pow2 + ; one_ulp `Up pow2 + ] + in + x @ List.map x ~f:neg)) + ;; + + let%test _ = List.for_all numbers_near_powers_of_two ~f:iround_up_vs_down_test + let%test _ = List.for_all numbers_near_powers_of_two ~f:iround_nearest_test + let%test _ = List.for_all numbers_near_powers_of_two ~f:iround_down_test + let%test _ = List.for_all numbers_near_powers_of_two ~f:iround_up_test + let%test _ = List.for_all numbers_near_powers_of_two ~f:iround_towards_zero_test + let%test _ = List.for_all numbers_near_powers_of_two ~f:round_test + + (* code for generating random floats on which to test functions *) + let rec absirand () = + let open Int.O in + let rec aux acc cnt = + if cnt = 0 + then acc else ( - let int_size_minus_one = of_int (Int.num_bits - 1) in - (* 32 bits *) - [%test_result: int option] - (round ((2.0 **. int_size_minus_one) -. 1.)) - ~expect:(Some Int.max_value); - [%test_result: int option] - (round ((2.0 **. int_size_minus_one) -. 2.)) - ~expect:(Some (Int.max_value - 1)); - [%test_result: int option] - (round (-.(2.0 **. int_size_minus_one))) - ~expect:(Some Int.min_value); - [%test_result: int option] - (round (-.((2.0 **. int_size_minus_one) -. 1.))) - ~expect:(Some (Int.min_value + 1)); - [%test_result: int option] (round (2.0 **. int_size_minus_one)) ~expect:None; - [%test_result: int option] - (round (-.((2.0 **. int_size_minus_one) +. 1.))) - ~expect:None) - ;; - - let%test_unit _ = extremities_test ~round:iround_down - let%test_unit _ = extremities_test ~round:iround_up - let%test_unit _ = extremities_test ~round:iround_nearest - let%test_unit _ = extremities_test ~round:iround_towards_zero - - (* test values beyond the integers range *) - let large_value_test x = - [%test_result: int option] (iround_down x) ~expect:None; - [%test_result: int option] (iround ~dir:`Down x) ~expect:None; - [%test_result: int option] (iround_up x) ~expect:None; - [%test_result: int option] (iround ~dir:`Up x) ~expect:None; - [%test_result: int option] (iround_towards_zero x) ~expect:None; - [%test_result: int option] (iround ~dir:`Zero x) ~expect:None; - [%test_result: int option] (iround_nearest x) ~expect:None; - [%test_result: int option] (iround ~dir:`Nearest x) ~expect:None; - assert (Exn.does_raise (fun () -> iround_down_exn x)); - assert (Exn.does_raise (fun () -> iround_exn ~dir:`Down x)); - assert (Exn.does_raise (fun () -> iround_up_exn x)); - assert (Exn.does_raise (fun () -> iround_exn ~dir:`Up x)); - assert (Exn.does_raise (fun () -> iround_towards_zero_exn x)); - assert (Exn.does_raise (fun () -> iround_exn ~dir:`Zero x)); - assert (Exn.does_raise (fun () -> iround_nearest_exn x)); - assert (Exn.does_raise (fun () -> iround_exn ~dir:`Nearest x)); - [%test_result: float] (round_down x) ~expect:x; - [%test_result: float] (round ~dir:`Down x) ~expect:x; - [%test_result: float] (round_up x) ~expect:x; - [%test_result: float] (round ~dir:`Up x) ~expect:x; - [%test_result: float] (round_towards_zero x) ~expect:x; - [%test_result: float] (round ~dir:`Zero x) ~expect:x; - [%test_result: float] (round_nearest x) ~expect:x; - [%test_result: float] (round ~dir:`Nearest x) ~expect:x - ;; - - let large_numbers = - let ( + ) = Int.( + ) in - let ( - ) = Int.( - ) in - List.concat - (List.init (1024 - 64) ~f:(fun x -> - let x = of_int (x + 64) in - let y = - [ 2. **. x - ; (2. **. x) -. (2. **. (x -. 53.)) - ; (* one ulp down *) - (2. **. x) +. (2. **. (x -. 52.)) - ] - (* one ulp up *) - in - y @ List.map y ~f:neg)) - @ [ infinity; neg_infinity ] - ;; - - let%test_unit _ = List.iter large_numbers ~f:large_value_test - - let numbers_near_powers_of_two = - List.concat - (List.init 64 ~f:(fun i -> - let pow2 = 2. **. of_int i in - let x = - [ pow2 - ; one_ulp `Down (pow2 +. 0.5) - ; pow2 +. 0.5 - ; one_ulp `Down (pow2 +. 1.0) - ; pow2 +. 1.0 - ; one_ulp `Down (pow2 +. 1.5) - ; pow2 +. 1.5 - ; one_ulp `Down (pow2 +. 2.0) - ; pow2 +. 2.0 - ; one_ulp `Down ((pow2 *. 2.0) -. 1.0) - ; one_ulp `Down pow2 - ; one_ulp `Up pow2 - ] - in - x @ List.map x ~f:neg)) - ;; - - let%test _ = List.for_all numbers_near_powers_of_two ~f:iround_up_vs_down_test - let%test _ = List.for_all numbers_near_powers_of_two ~f:iround_nearest_test - let%test _ = List.for_all numbers_near_powers_of_two ~f:iround_down_test - let%test _ = List.for_all numbers_near_powers_of_two ~f:iround_up_test - let%test _ = List.for_all numbers_near_powers_of_two ~f:iround_towards_zero_test - let%test _ = List.for_all numbers_near_powers_of_two ~f:round_test - - (* code for generating random floats on which to test functions *) - let rec absirand () = - let open Int.O in - let rec aux acc cnt = - if cnt = 0 - then acc - else ( - let bit = if Random.bool () then 1 else 0 in - aux ((2 * acc) + bit) (cnt - 1)) - in - let result = aux 0 (if is_64_bit_platform then 62 else 30) in - if result >= Int.max_value - 255 - then - (* On a 64-bit box, [float x > Int.max_value] when [x >= Int.max_value - 255], so + let bit = if Random.bool () then 1 else 0 in + aux ((2 * acc) + bit) (cnt - 1)) + in + let result = aux 0 (if is_64_bit_platform then 62 else 30) in + if result >= Int.max_value - 255 + then + (* On a 64-bit box, [float x > Int.max_value] when [x >= Int.max_value - 255], so [iround (float x)] would be out of bounds. So we try again. This branch of code runs with probability 6e-17 :-) As such, we have some fixed tests in [extremities_test] above, to ensure that we do always check some examples in that range. *) - absirand () - else result - ;; - - (* -Int.max_value <= frand () <= Int.max_value *) - let frand () = - let x = of_int (absirand ()) +. Random.float 1.0 in - if Random.bool () then -1.0 *. x else x - ;; - - let randoms = List.init ~f:(fun _ -> frand ()) 10_000 - let%test _ = List.for_all randoms ~f:iround_up_vs_down_test - let%test _ = List.for_all randoms ~f:iround_nearest_test - let%test _ = List.for_all randoms ~f:iround_down_test - let%test _ = List.for_all randoms ~f:iround_up_test - let%test _ = List.for_all randoms ~f:iround_towards_zero_test - let%test _ = List.for_all randoms ~f:round_test - let%test_unit _ = special_values_test () - let%test _ = iround_nearest_test (of_int Int.max_value) - let%test _ = iround_nearest_test (of_int Int.min_value) - end) -;; + absirand () + else result + ;; + + (* -Int.max_value <= frand () <= Int.max_value *) + let frand () = + let x = of_int (absirand ()) +. Random.float 1.0 in + if Random.bool () then -1.0 *. x else x + ;; + + let randoms = List.init ~f:(fun _ -> frand ()) 10_000 + let%test _ = List.for_all randoms ~f:iround_up_vs_down_test + let%test _ = List.for_all randoms ~f:iround_nearest_test + let%test _ = List.for_all randoms ~f:iround_down_test + let%test _ = List.for_all randoms ~f:iround_up_test + let%test _ = List.for_all randoms ~f:iround_towards_zero_test + let%test _ = List.for_all randoms ~f:round_test + let%test_unit _ = special_values_test () + let%test _ = iround_nearest_test (of_int Int.max_value) + let%test _ = iround_nearest_test (of_int Int.min_value) +end module Test_bounds (I : sig type t @@ -917,12 +883,13 @@ struct ;; end -let%test_module "Int" = (module Test_bounds (Int)) -let%test_module "Int32" = (module Test_bounds (Int32)) -let%test_module "Int63" = (module Test_bounds (Int63)) -let%test_module "Int63_emul" = (module Test_bounds (Base.Int63.Private.Emul)) -let%test_module "Int64" = (module Test_bounds (Int64)) -let%test_module "Nativeint" = (module Test_bounds (Nativeint)) +module%test Int = Test_bounds (Int) +module%test Int32 = Test_bounds (Int32) +module%test Int63 = Test_bounds (Int63) +module%test Int63_emul = Test_bounds (Base.Int63.Private.Emul) +module%test Int64 = Test_bounds (Int64) +module%test Nativeint = Test_bounds (Nativeint) + let%test_unit _ = [%test_result: string] (to_string 3.14) ~expect:"3.14" let%test_unit _ = [%test_result: string] (to_string 3.1400000000000001) ~expect:"3.14" @@ -991,31 +958,25 @@ let%test _ = not (is_integer nan) let%test _ = not (is_integer infinity) let%test _ = not (is_integer neg_infinity) -let%test_module _ = - (module struct - (* check we raise on invalid input *) - let must_fail f x = Exn.does_raise (fun () -> f x) +module%test _ = struct + (* check we raise on invalid input *) + let must_fail f x = Exn.does_raise (fun () -> f x) - let must_succeed f x = - ignore (f x : _); - true - ;; - - let%test _ = must_fail int63_round_nearest_portable_alloc_exn nan - let%test _ = must_fail int63_round_nearest_portable_alloc_exn max_value - let%test _ = must_fail int63_round_nearest_portable_alloc_exn min_value - let%test _ = must_fail int63_round_nearest_portable_alloc_exn (2. **. 63.) - let%test _ = must_fail int63_round_nearest_portable_alloc_exn ~-.(2. **. 63.) - let%test _ = must_succeed int63_round_nearest_portable_alloc_exn ((2. **. 62.) -. 512.) - let%test _ = must_fail int63_round_nearest_portable_alloc_exn (2. **. 62.) - - let%test _ = - must_fail int63_round_nearest_portable_alloc_exn (~-.(2. **. 62.) -. 1024.) - ;; - - let%test _ = must_succeed int63_round_nearest_portable_alloc_exn ~-.(2. **. 62.) - end) -;; + let must_succeed f x = + ignore (f x : _); + true + ;; + + let%test _ = must_fail int63_round_nearest_portable_alloc_exn nan + let%test _ = must_fail int63_round_nearest_portable_alloc_exn max_value + let%test _ = must_fail int63_round_nearest_portable_alloc_exn min_value + let%test _ = must_fail int63_round_nearest_portable_alloc_exn (2. **. 63.) + let%test _ = must_fail int63_round_nearest_portable_alloc_exn ~-.(2. **. 63.) + let%test _ = must_succeed int63_round_nearest_portable_alloc_exn ((2. **. 62.) -. 512.) + let%test _ = must_fail int63_round_nearest_portable_alloc_exn (2. **. 62.) + let%test _ = must_fail int63_round_nearest_portable_alloc_exn (~-.(2. **. 62.) -. 1024.) + let%test _ = must_succeed int63_round_nearest_portable_alloc_exn ~-.(2. **. 62.) +end let%test _ = round_nearest 3.6 = 4. && round_nearest (-3.6) = -4. @@ -1025,85 +986,81 @@ let%test_unit "e vs E" = [%test_result: Sexp.t] [%sexp (1.4e100 : t)] ~expect:(Atom "1.4E+100") ;; -let%test_module _ = - (module struct - let test ?delimiter ~decimals f s s_strip_zero = - let s' = to_string_hum ?delimiter ~decimals ~strip_zero:false f in - if String.(s' <> s) - then - raise_s - [%message - "to_string_hum ~strip_zero:false" - ~input:(f : float) - (decimals : int) - ~got:(s' : string) - ~expected:(s : string)]; - let s_strip_zero' = to_string_hum ?delimiter ~decimals ~strip_zero:true f in - if String.(s_strip_zero' <> s_strip_zero) - then - raise_s - [%message - "to_string_hum ~strip_zero:true" - ~input:(f : float) - (decimals : int) - ~got:(s_strip_zero : string) - ~expected:(s_strip_zero' : string)] - ;; - - let%test_unit _ = test ~decimals:3 0.99999 "1.000" "1" - let%test_unit _ = test ~decimals:3 0.00001 "0.000" "0" - let%test_unit _ = test ~decimals:3 ~-.12345.1 "-12_345.100" "-12_345.1" - let%test_unit _ = test ~delimiter:',' ~decimals:3 ~-.12345.1 "-12,345.100" "-12,345.1" - let%test_unit _ = test ~decimals:0 0.99999 "1" "1" - let%test_unit _ = test ~decimals:0 0.00001 "0" "0" - let%test_unit _ = test ~decimals:0 ~-.12345.1 "-12_345" "-12_345" - let%test_unit _ = test ~decimals:0 (5.0 /. 0.0) "inf" "inf" - let%test_unit _ = test ~decimals:0 (-5.0 /. 0.0) "-inf" "-inf" - let%test_unit _ = test ~decimals:0 (0.0 /. 0.0) "nan" "nan" - let%test_unit _ = test ~decimals:2 (5.0 /. 0.0) "inf" "inf" - let%test_unit _ = test ~decimals:2 (-5.0 /. 0.0) "-inf" "-inf" - let%test_unit _ = test ~decimals:2 (0.0 /. 0.0) "nan" "nan" - let%test_unit _ = test ~decimals:5 (10_000.0 /. 3.0) "3_333.33333" "3_333.33333" - let%test_unit _ = test ~decimals:2 ~-.0.00001 "-0.00" "-0" - - let rand_test n = - let go () = - let f = Random.float 1_000_000.0 -. 500_000.0 in - let repeatable to_str = - let s = to_str f in - if String.( <> ) - (String.split s ~on:',' |> String.concat |> of_string |> to_str) - s - then raise_s [%message "failed" (f : t)] - in - repeatable (to_string_hum ~decimals:3 ~strip_zero:false) +module%test _ = struct + let test ?delimiter ~decimals f s s_strip_zero = + let s' = to_string_hum ?delimiter ~decimals ~strip_zero:false f in + if String.(s' <> s) + then + raise_s + [%message + "to_string_hum ~strip_zero:false" + ~input:(f : float) + (decimals : int) + ~got:(s' : string) + ~expected:(s : string)]; + let s_strip_zero' = to_string_hum ?delimiter ~decimals ~strip_zero:true f in + if String.(s_strip_zero' <> s_strip_zero) + then + raise_s + [%message + "to_string_hum ~strip_zero:true" + ~input:(f : float) + (decimals : int) + ~got:(s_strip_zero : string) + ~expected:(s_strip_zero' : string)] + ;; + + let%test_unit _ = test ~decimals:3 0.99999 "1.000" "1" + let%test_unit _ = test ~decimals:3 0.00001 "0.000" "0" + let%test_unit _ = test ~decimals:3 ~-.12345.1 "-12_345.100" "-12_345.1" + let%test_unit _ = test ~delimiter:',' ~decimals:3 ~-.12345.1 "-12,345.100" "-12,345.1" + let%test_unit _ = test ~decimals:0 0.99999 "1" "1" + let%test_unit _ = test ~decimals:0 0.00001 "0" "0" + let%test_unit _ = test ~decimals:0 ~-.12345.1 "-12_345" "-12_345" + let%test_unit _ = test ~decimals:0 (5.0 /. 0.0) "inf" "inf" + let%test_unit _ = test ~decimals:0 (-5.0 /. 0.0) "-inf" "-inf" + let%test_unit _ = test ~decimals:0 (0.0 /. 0.0) "nan" "nan" + let%test_unit _ = test ~decimals:2 (5.0 /. 0.0) "inf" "inf" + let%test_unit _ = test ~decimals:2 (-5.0 /. 0.0) "-inf" "-inf" + let%test_unit _ = test ~decimals:2 (0.0 /. 0.0) "nan" "nan" + let%test_unit _ = test ~decimals:5 (10_000.0 /. 3.0) "3_333.33333" "3_333.33333" + let%test_unit _ = test ~decimals:2 ~-.0.00001 "-0.00" "-0" + + let rand_test n = + let go () = + let f = Random.float 1_000_000.0 -. 500_000.0 in + let repeatable to_str = + let s = to_str f in + if String.( <> ) + (String.split s ~on:',' |> String.concat |> of_string |> to_str) + s + then raise_s [%message "failed" (f : t)] in - try - for _ = 0 to Int.( - ) n 1 do - go () - done; - true - with - | e -> - eprintf "%s\n%!" (Exn.to_string e); - false - ;; - - let%test _ = rand_test 10_000 - end) -;; + repeatable (to_string_hum ~decimals:3 ~strip_zero:false) + in + try + for _ = 0 to Int.( - ) n 1 do + go () + done; + true + with + | e -> + eprintf "%s\n%!" (Exn.to_string e); + false + ;; -let%test_module "Hexadecimal syntax" = - (module struct - let should_fail str = Exn.does_raise (fun () -> Stdlib.float_of_string str) - let test_equal str g = Stdlib.float_of_string str = g - let%test _ = should_fail "0x" - let%test _ = should_fail "0x.p0" - let%test _ = test_equal "0x0" 0. - let%test _ = test_equal "0x1.b7p-1" 0.857421875 - let%test _ = test_equal "0x1.999999999999ap-4" 0.1 - end) -;; + let%test _ = rand_test 10_000 +end + +module%test [@name "Hexadecimal syntax"] _ = struct + let should_fail str = Exn.does_raise (fun () -> Stdlib.float_of_string str) + let test_equal str g = Stdlib.float_of_string str = g + let%test _ = should_fail "0x" + let%test _ = should_fail "0x.p0" + let%test _ = test_equal "0x0" 0. + let%test _ = test_equal "0x1.b7p-1" 0.857421875 + let%test _ = test_equal "0x1.999999999999ap-4" 0.1 +end let%expect_test "square" = printf "%f\n" (square 1.5); diff --git a/test/test_hash_set.ml b/test/test_hash_set.ml index 3e57e45..03602c4 100644 --- a/test/test_hash_set.ml +++ b/test/test_hash_set.ml @@ -1,41 +1,39 @@ open! Import open! Hash_set -let%test_module "Set Intersection" = - (module struct - let run_test first_contents second_contents ~expect = - let of_list lst = - let s = create (module String) in - List.iter lst ~f:(add s); - s - in - let s1 = of_list first_contents in - let s2 = of_list second_contents in - let expect = of_list expect in - let result = inter s1 s2 in - iter result ~f:(fun x -> assert (mem expect x)); - iter expect ~f:(fun x -> assert (mem result x)); - let equal x y = 0 = String.compare x y in - assert (List.equal equal (to_list result) (to_list expect)); - assert (length result = length expect); - (* Make sure the sets are unmodified by the inter *) - assert (List.length first_contents = length s1); - assert (List.length second_contents = length s2) - ;; +module%test [@name "Set Intersection"] _ = struct + let run_test first_contents second_contents ~expect = + let of_list lst = + let s = create (module String) in + List.iter lst ~f:(add s); + s + in + let s1 = of_list first_contents in + let s2 = of_list second_contents in + let expect = of_list expect in + let result = inter s1 s2 in + iter result ~f:(fun x -> assert (mem expect x)); + iter expect ~f:(fun x -> assert (mem result x)); + let equal x y = 0 = String.compare x y in + assert (List.equal equal (to_list result) (to_list expect)); + assert (length result = length expect); + (* Make sure the sets are unmodified by the inter *) + assert (List.length first_contents = length s1); + assert (List.length second_contents = length s2) + ;; - let%test_unit "First smaller" = - run_test [ "0"; "3"; "99" ] [ "0"; "1"; "2"; "3" ] ~expect:[ "0"; "3" ] - ;; + let%test_unit "First smaller" = + run_test [ "0"; "3"; "99" ] [ "0"; "1"; "2"; "3" ] ~expect:[ "0"; "3" ] + ;; - let%test_unit "Second smaller" = - run_test [ "a"; "b"; "c"; "d" ] [ "b"; "d" ] ~expect:[ "b"; "d" ] - ;; + let%test_unit "Second smaller" = + run_test [ "a"; "b"; "c"; "d" ] [ "b"; "d" ] ~expect:[ "b"; "d" ] + ;; - let%test_unit "No intersection" = - run_test ~expect:[] [ "a"; "b"; "c"; "d" ] [ "1"; "2"; "3"; "4" ] - ;; - end) -;; + let%test_unit "No intersection" = + run_test ~expect:[] [ "a"; "b"; "c"; "d" ] [ "1"; "2"; "3"; "4" ] + ;; +end let%expect_test "sexp" = let ints = List.init 20 ~f:(fun x -> x * x) in diff --git a/test/test_hashtbl.ml b/test/test_hashtbl.ml index 8270e2a..45e4f97 100644 --- a/test/test_hashtbl.ml +++ b/test/test_hashtbl.ml @@ -16,15 +16,13 @@ let%test "Hashtbl.merge succeeds with first-class-module interface" = List.equal Poly.equal result [] ;; -let%test_module _ = - (module Hashtbl_tests.Make (struct - include Hashtbl +module%test _ = 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 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 diff --git a/test/test_int.ml b/test/test_int.ml index 5508ae8..5c1c9fd 100644 --- a/test/test_int.ml +++ b/test/test_int.ml @@ -49,67 +49,65 @@ let%expect_test "hex" = |}] ;; -let%test_module "Hex" = - (module struct - let f (i, s_hum) = - let s = String.filter s_hum ~f:(fun c -> not (Char.equal c '_')) in - let sexp_hum = Sexp.Atom s_hum in - let sexp = Sexp.Atom s in - [%test_result: Sexp.t] ~message:"sexp_of_t" ~expect:sexp (Hex.sexp_of_t i); - [%test_result: int] ~message:"t_of_sexp" ~expect:i (Hex.t_of_sexp sexp); - [%test_result: int] ~message:"t_of_sexp[human]" ~expect:i (Hex.t_of_sexp sexp_hum); - [%test_result: string] ~message:"to_string" ~expect:s (Hex.to_string i); - [%test_result: string] ~message:"to_string_hum" ~expect:s_hum (Hex.to_string_hum i); - [%test_result: int] ~message:"of_string" ~expect:i (Hex.of_string s); - [%test_result: int] ~message:"of_string[human]" ~expect:i (Hex.of_string s_hum) - ;; +module%test Hex = struct + let f (i, s_hum) = + let s = String.filter s_hum ~f:(fun c -> not (Char.equal c '_')) in + let sexp_hum = Sexp.Atom s_hum in + let sexp = Sexp.Atom s in + [%test_result: Sexp.t] ~message:"sexp_of_t" ~expect:sexp (Hex.sexp_of_t i); + [%test_result: int] ~message:"t_of_sexp" ~expect:i (Hex.t_of_sexp sexp); + [%test_result: int] ~message:"t_of_sexp[human]" ~expect:i (Hex.t_of_sexp sexp_hum); + [%test_result: string] ~message:"to_string" ~expect:s (Hex.to_string i); + [%test_result: string] ~message:"to_string_hum" ~expect:s_hum (Hex.to_string_hum i); + [%test_result: int] ~message:"of_string" ~expect:i (Hex.of_string s); + [%test_result: int] ~message:"of_string[human]" ~expect:i (Hex.of_string s_hum) + ;; - let%test_unit _ = - List.iter - ~f - [ 0, "0x0" - ; 1, "0x1" - ; 2, "0x2" - ; 5, "0x5" - ; 10, "0xa" - ; 16, "0x10" - ; 254, "0xfe" - ; 65_535, "0xffff" - ; 65_536, "0x1_0000" - ; 1_000_000, "0xf_4240" - ; -1, "-0x1" - ; -2, "-0x2" - ; -1_000_000, "-0xf_4240" - ; ( max_value - , match num_bits with - | 31 -> "0x3fff_ffff" - | 32 -> "0x7fff_ffff" - | 63 -> "0x3fff_ffff_ffff_ffff" - | _ -> assert false ) - ; ( min_value - , match num_bits with - | 31 -> "-0x4000_0000" - | 32 -> "-0x8000_0000" - | 63 -> "-0x4000_0000_0000_0000" - | _ -> assert false ) - ] - ;; + let%test_unit _ = + List.iter + ~f + [ 0, "0x0" + ; 1, "0x1" + ; 2, "0x2" + ; 5, "0x5" + ; 10, "0xa" + ; 16, "0x10" + ; 254, "0xfe" + ; 65_535, "0xffff" + ; 65_536, "0x1_0000" + ; 1_000_000, "0xf_4240" + ; -1, "-0x1" + ; -2, "-0x2" + ; -1_000_000, "-0xf_4240" + ; ( max_value + , match num_bits with + | 31 -> "0x3fff_ffff" + | 32 -> "0x7fff_ffff" + | 63 -> "0x3fff_ffff_ffff_ffff" + | _ -> assert false ) + ; ( min_value + , match num_bits with + | 31 -> "-0x4000_0000" + | 32 -> "-0x8000_0000" + | 63 -> "-0x4000_0000_0000_0000" + | _ -> assert false ) + ] + ;; - let%test_unit _ = [%test_result: int] (Hex.of_string "0XA") ~expect:10 + let%test_unit _ = [%test_result: int] (Hex.of_string "0XA") ~expect:10 - let%test_unit _ = - match Option.try_with (fun () -> Hex.of_string "0") with - | None -> () - | Some _ -> failwith "Hex must always have a 0x prefix." - ;; + let%test_unit _ = + match Option.try_with (fun () -> Hex.of_string "0") with + | None -> () + | Some _ -> failwith "Hex must always have a 0x prefix." + ;; - let%test_unit _ = - match Option.try_with (fun () -> Hex.of_string "0x_0") with - | None -> () - | Some _ -> failwith "Hex may not have '_' before the first digit." - ;; - end) -;; + let%test_unit _ = + match Option.try_with (fun () -> Hex.of_string "0x_0") with + | None -> () + | Some _ -> failwith "Hex may not have '_' before the first digit." + ;; +end let%expect_test "binary" = quickcheck_m diff --git a/test/test_int32_pow2.ml b/test/test_int32_pow2.ml index 413f9c5..4bbb179 100644 --- a/test/test_int32_pow2.ml +++ b/test/test_int32_pow2.ml @@ -73,29 +73,27 @@ let%expect_test ("[ceil_log2]" [@tags "64-bits-only"]) = |}] ;; -let%test_module "int_math" = - (module struct - let test_cases () = - of_ints - [ 0b10101010 - ; 0b1010101010101010 - ; 0b101010101010101010101010 - ; 0b10000000 - ; 0b1000000000001000 - ; 0b100000000000000000001000 - ] - ;; +module%test [@name "int_math"] _ = struct + let test_cases () = + of_ints + [ 0b10101010 + ; 0b1010101010101010 + ; 0b101010101010101010101010 + ; 0b10000000 + ; 0b1000000000001000 + ; 0b100000000000000000001000 + ] + ;; - let%test_unit "ceil_pow2" = - List.iter (test_cases ()) ~f:(fun x -> - let p2 = ceil_pow2 x in - assert (is_pow2 p2 && p2 >= x && x >= p2 / of_int_exn 2)) - ;; + let%test_unit "ceil_pow2" = + List.iter (test_cases ()) ~f:(fun x -> + let p2 = ceil_pow2 x in + assert (is_pow2 p2 && p2 >= x && x >= p2 / of_int_exn 2)) + ;; - let%test_unit "floor_pow2" = - List.iter (test_cases ()) ~f:(fun x -> - let p2 = floor_pow2 x in - assert (is_pow2 p2 && of_int_exn 2 * p2 >= x && x >= p2)) - ;; - end) -;; + let%test_unit "floor_pow2" = + List.iter (test_cases ()) ~f:(fun x -> + let p2 = floor_pow2 x in + assert (is_pow2 p2 && of_int_exn 2 * p2 >= x && x >= p2)) + ;; +end diff --git a/test/test_int63.ml b/test/test_int63.ml index 1ca065f..92be2e0 100644 --- a/test/test_int63.ml +++ b/test/test_int63.ml @@ -22,74 +22,59 @@ let%test_unit _ = let%test "typical random 0" = Exn.does_raise (fun () -> random zero) -let%test_module "Overflow_exn" = - (module struct - open Overflow_exn - - let%test_module "( + )" = - (module struct - let test t = Exn.does_raise (fun () -> t + t) - let%test "max_value / 2 + 1" = test (succ (max_value / of_int 2)) - let%test "min_value / 2 - 1" = test (pred (min_value / of_int 2)) - let%test "min_value + min_value" = test min_value - let%test "max_value + max_value" = test max_value - end) +module%test Overflow_exn = struct + open Overflow_exn + + module%test [@name "( + )"] _ = struct + let test t = Exn.does_raise (fun () -> t + t) + let%test "max_value / 2 + 1" = test (succ (max_value / of_int 2)) + let%test "min_value / 2 - 1" = test (pred (min_value / of_int 2)) + let%test "min_value + min_value" = test min_value + let%test "max_value + max_value" = test max_value + end + + module%test [@name "( - )"] _ = struct + let%test "min_value - 1" = Exn.does_raise (fun () -> min_value - one) + let%test "max_value - -1" = Exn.does_raise (fun () -> max_value - neg one) + + let%test "min_value / 2 - max_value / 2 - 2" = + Exn.does_raise (fun () -> + (min_value / of_int 2) - (max_value / of_int 2) - of_int 2) ;; - let%test_module "( - )" = - (module struct - let%test "min_value - 1" = Exn.does_raise (fun () -> min_value - one) - let%test "max_value - -1" = Exn.does_raise (fun () -> max_value - neg one) + let%test "min_value - max_value" = Exn.does_raise (fun () -> min_value - max_value) + let%test "max_value - min_value" = Exn.does_raise (fun () -> max_value - min_value) - let%test "min_value / 2 - max_value / 2 - 2" = - Exn.does_raise (fun () -> - (min_value / of_int 2) - (max_value / of_int 2) - of_int 2) - ;; - - let%test "min_value - max_value" = - Exn.does_raise (fun () -> min_value - max_value) - ;; - - let%test "max_value - min_value" = - Exn.does_raise (fun () -> max_value - min_value) - ;; - - let%test "max_value - -max_value" = - Exn.does_raise (fun () -> max_value - neg max_value) - ;; - end) + let%test "max_value - -max_value" = + Exn.does_raise (fun () -> max_value - neg max_value) ;; + end - let is_overflow = Exn.does_raise + let is_overflow = Exn.does_raise - let%test_module "( * )" = - (module struct - let%test "1 * 1" = one * one = one - let%test "1 * 0" = one * zero = zero - let%test "0 * 1" = zero * one = zero - let%test "min_value * -1" = is_overflow (fun () -> min_value * neg one) - let%test "-1 * min_value" = is_overflow (fun () -> neg one * min_value) + module%test [@name "( * )"] _ = struct + let%test "1 * 1" = one * one = one + let%test "1 * 0" = one * zero = zero + let%test "0 * 1" = zero * one = zero + let%test "min_value * -1" = is_overflow (fun () -> min_value * neg one) + let%test "-1 * min_value" = is_overflow (fun () -> neg one * min_value) - let%test "46116860184273879 * 100" = - of_int64_exn 46116860184273879L * of_int 100 = of_int64_exn 4611686018427387900L - ;; - - let%test "46116860184273879 * 101" = - is_overflow (fun () -> of_int64_exn 46116860184273879L * of_int 101) - ;; - end) + let%test "46116860184273879 * 100" = + of_int64_exn 46116860184273879L * of_int 100 = of_int64_exn 4611686018427387900L ;; - let%test_module "( / )" = - (module struct - let%test "1 / 1" = one / one = one - let%test "min_value / -1" = is_overflow (fun () -> min_value / neg one) - let%test "min_value / 1" = min_value / one = min_value - let%test "max_value / -1" = max_value / neg one = min_value + one - end) + let%test "46116860184273879 * 101" = + is_overflow (fun () -> of_int64_exn 46116860184273879L * of_int 101) ;; - end) -;; + end + + module%test [@name "( / )"] _ = struct + let%test "1 / 1" = one / one = one + let%test "min_value / -1" = is_overflow (fun () -> min_value / neg one) + let%test "min_value / 1" = min_value / one = min_value + let%test "max_value / -1" = max_value / neg one = min_value + one + end +end let%expect_test "[floor_log2]" = let floor_log2 t = print_s [%sexp (floor_log2 t : int)] in diff --git a/test/test_int64.ml b/test/test_int64.ml index 4636565..09bb92f 100644 --- a/test/test_int64.ml +++ b/test/test_int64.ml @@ -75,6 +75,47 @@ let%expect_test "bswap64" = |}] ;; +let%expect_test "of_string" = + let test s = + let result = Or_error.try_with (fun () -> of_string s) in + print_s [%sexp (result : t Or_error.t)] + in + test "0"; + [%expect {| (Ok 0) |}]; + test "-1"; + [%expect {| (Ok -1) |}]; + test "0xBEEF"; + [%expect {| (Ok 48_879) |}]; + (* max_value *) + test "9_223_372_036_854_775_807"; + [%expect {| (Ok 9_223_372_036_854_775_807) |}]; + (* max_value + 1 *) + test "9_223_372_036_854_775_808"; + [%expect {| (Error (Failure Int64.of_string)) |}]; + (* min_value *) + test "-9_223_372_036_854_775_808"; + [%expect {| (Ok -9_223_372_036_854_775_808) |}]; + (* min_value - 1 *) + test "-9_223_372_036_854_775_809"; + [%expect {| (Error (Failure Int64.of_string)) |}]; + (* + * Bases other than 10 are more permissive: + *) + (* max_value (hex) *) + test "0x7fff_ffff_ffff_ffff"; + [%expect {| (Ok 9_223_372_036_854_775_807) |}]; + (* max_value + 1 (hex) *) + test "0x8000_0000_0000_0000"; + [%expect {| (Ok -9_223_372_036_854_775_808) |}]; + (* min_value (hex) *) + test "-0x8000_0000_0000_0000"; + [%expect {| (Ok -9_223_372_036_854_775_808) |}]; + (* min_value - 1 (hex) *) + test "-0x8000_0000_0000_0001"; + [%expect {| (Ok 9_223_372_036_854_775_807) |}]; + () +;; + let%expect_test "binary" = quickcheck_m (module struct diff --git a/test/test_int64_pow2.ml b/test/test_int64_pow2.ml index 961d787..2871ff9 100644 --- a/test/test_int64_pow2.ml +++ b/test/test_int64_pow2.ml @@ -76,38 +76,36 @@ let%expect_test ("[ceil_log2]" [@tags "64-bits-only"]) = |}] ;; -let%test_module "int64_math" = - (module struct - let test_cases () = - let cases = - [ 0b10101010L - ; 0b1010101010101010L - ; 0b101010101010101010101010L - ; 0b10000000L - ; 0b1000000000001000L - ; 0b100000000000000000001000L +module%test [@name "int64_math"] _ = struct + let test_cases () = + let cases = + [ 0b10101010L + ; 0b1010101010101010L + ; 0b101010101010101010101010L + ; 0b10000000L + ; 0b1000000000001000L + ; 0b100000000000000000001000L + ] + in + let cases = + cases + @ [ (0b1010101010101010L lsl 16) lor 0b1010101010101010L + ; (0b1000000000000000L lsl 16) lor 0b0000000000001000L ] - in - let cases = - cases - @ [ (0b1010101010101010L lsl 16) lor 0b1010101010101010L - ; (0b1000000000000000L lsl 16) lor 0b0000000000001000L - ] - in - let added_cases = List.map cases ~f:(fun x -> x lsl 16) in - List.concat [ cases; added_cases ] - ;; + in + let added_cases = List.map cases ~f:(fun x -> x lsl 16) in + List.concat [ cases; added_cases ] + ;; - let%test_unit "ceil_pow2" = - List.iter (test_cases ()) ~f:(fun x -> - let p2 = ceil_pow2 x in - assert (is_pow2 p2 && p2 >= x && x >= p2 / 2L)) - ;; + let%test_unit "ceil_pow2" = + List.iter (test_cases ()) ~f:(fun x -> + let p2 = ceil_pow2 x in + assert (is_pow2 p2 && p2 >= x && x >= p2 / 2L)) + ;; - let%test_unit "floor_pow2" = - List.iter (test_cases ()) ~f:(fun x -> - let p2 = floor_pow2 x in - assert (is_pow2 p2 && 2L * p2 >= x && x >= p2)) - ;; - end) -;; + let%test_unit "floor_pow2" = + List.iter (test_cases ()) ~f:(fun x -> + let p2 = floor_pow2 x in + assert (is_pow2 p2 && 2L * p2 >= x && x >= p2)) + ;; +end diff --git a/test/test_int_conversions.ml b/test/test_int_conversions.ml index ead1dc0..e63c760 100644 --- a/test/test_int_conversions.ml +++ b/test/test_int_conversions.ml @@ -1,255 +1,249 @@ open! Import open! Int_conversions -let%test_module "pretty" = - (module struct - let check input output = - List.for_all [ ""; "+"; "-" ] ~f:(fun prefix -> - let input = prefix ^ input in - let output = prefix ^ output in - [%compare.equal: string] output (insert_underscores input)) - ;; - - let%test _ = check "1" "1" - let%test _ = check "12" "12" - let%test _ = check "123" "123" - let%test _ = check "1234" "1_234" - let%test _ = check "12345" "12_345" - let%test _ = check "123456" "123_456" - let%test _ = check "1234567" "1_234_567" - let%test _ = check "12345678" "12_345_678" - let%test _ = check "123456789" "123_456_789" - let%test _ = check "1234567890" "1_234_567_890" - end) -;; - -let%test_module "conversions" = - (module struct - module type S = sig - include Int.S - - val module_name : string - end - - let test_conversion (type a b) loc ma mb a_to_b_or_error a_to_b_trunc b_to_a_trunc = - let (module A : S with type t = a) = ma in - let (module B : S with type t = b) = mb in - let examples = - [ A.min_value - ; A.minus_one - ; A.zero - ; A.one - ; A.max_value - ; B.min_value |> b_to_a_trunc - ; B.max_value |> b_to_a_trunc - ] - |> List.concat_map ~f:(fun a -> [ A.pred a; a; A.succ a ]) - |> List.dedup_and_sort ~compare:A.compare - |> List.sort ~compare:A.compare - in - List.iter examples ~f:(fun a -> - let b' = a_to_b_trunc a in - let a' = b_to_a_trunc b' in - match a_to_b_or_error a with - | Ok b -> - require - ~here:loc - (B.equal b b') - ~if_false_then_print_s: - (lazy - [%message - "conversion produced wrong value" - ~from:(A.module_name : string) - ~to_:(B.module_name : string) - ~input:(a : A.t) - ~output:(b : B.t) - ~expected:(b' : B.t)]); - require - ~here:loc - (A.equal a a') - ~if_false_then_print_s: - (lazy - [%message - "conversion does not round-trip" - ~from:(A.module_name : string) - ~to_:(B.module_name : string) - ~input:(a : A.t) - ~output:(b : B.t) - ~round_trip:(a' : A.t)]) - | Error error -> - require - ~here:loc - (not (A.equal a a')) - ~if_false_then_print_s: - (lazy - [%message - "conversion failed" - ~from:(A.module_name : string) - ~to_:(B.module_name : string) - ~input:(a : A.t) - ~expected_output:(b' : B.t) - ~error:(error : Error.t)])) - ;; - - let test loc ma mb (a_to_b_trunc, a_to_b_or_error) (b_to_a_trunc, b_to_a_or_error) = - test_conversion loc ma mb a_to_b_or_error a_to_b_trunc b_to_a_trunc; - test_conversion loc mb ma b_to_a_or_error b_to_a_trunc a_to_b_trunc - ;; - - module Int = struct - include Int - - let module_name = "Int" - end - - module Int32 = struct - include Int32 - - let module_name = "Int32" - end - - module Int64 = struct - include Int64 - - let module_name = "Int64" - end - - module Nativeint = struct - include Nativeint - - let module_name = "Nativeint" - end - - let with_exn f x = Or_error.try_with (fun () -> f x) - let optional f x = Or_error.try_with (fun () -> Option.value_exn (f x)) - let alwaysok f x = Ok (f x) - - let%expect_test "int <-> int32" = - test - [%here] - (module Int) - (module Int32) - (Stdlib.Int32.of_int, with_exn int_to_int32_exn) - (Stdlib.Int32.to_int, with_exn int32_to_int_exn); - [%expect {| |}]; - test - [%here] - (module Int) - (module Int32) - (Stdlib.Int32.of_int, optional int_to_int32) - (Stdlib.Int32.to_int, optional int32_to_int); - [%expect {| |}] - ;; - - let%expect_test "int <-> int64" = - test - [%here] - (module Int) - (module Int64) - (Stdlib.Int64.of_int, alwaysok int_to_int64) - (Stdlib.Int64.to_int, with_exn int64_to_int_exn); - [%expect {| |}]; - test - [%here] - (module Int) - (module Int64) - (Stdlib.Int64.of_int, alwaysok int_to_int64) - (Stdlib.Int64.to_int, optional int64_to_int); - [%expect {| |}] - ;; - - let%expect_test "int <-> nativeint" = - test - [%here] - (module Int) - (module Nativeint) - (Stdlib.Nativeint.of_int, alwaysok int_to_nativeint) - (Stdlib.Nativeint.to_int, with_exn nativeint_to_int_exn); - [%expect {| |}]; - test - [%here] - (module Int) - (module Nativeint) - (Stdlib.Nativeint.of_int, alwaysok int_to_nativeint) - (Stdlib.Nativeint.to_int, optional nativeint_to_int); - [%expect {| |}] - ;; - - let%expect_test "int32 <-> int64" = - test - [%here] - (module Int32) - (module Int64) - (Stdlib.Int64.of_int32, alwaysok int32_to_int64) - (Stdlib.Int64.to_int32, with_exn int64_to_int32_exn); - [%expect {| |}]; - test - [%here] - (module Int32) - (module Int64) - (Stdlib.Int64.of_int32, alwaysok int32_to_int64) - (Stdlib.Int64.to_int32, optional int64_to_int32); - [%expect {| |}] - ;; - - let%expect_test "int32 <-> nativeint" = - test - [%here] - (module Int32) - (module Nativeint) - (Stdlib.Nativeint.of_int32, alwaysok int32_to_nativeint) - (Stdlib.Nativeint.to_int32, with_exn nativeint_to_int32_exn); - [%expect {| |}]; - test - [%here] - (module Int32) - (module Nativeint) - (Stdlib.Nativeint.of_int32, alwaysok int32_to_nativeint) - (Stdlib.Nativeint.to_int32, optional nativeint_to_int32); - [%expect {| |}] - ;; - - let%expect_test "int64 <-> nativeint" = - test - [%here] - (module Int64) - (module Nativeint) - (Stdlib.Int64.to_nativeint, with_exn int64_to_nativeint_exn) - (Stdlib.Int64.of_nativeint, alwaysok nativeint_to_int64); - [%expect {| |}]; - test - [%here] - (module Int64) - (module Nativeint) - (Stdlib.Int64.to_nativeint, optional int64_to_nativeint) - (Stdlib.Int64.of_nativeint, alwaysok nativeint_to_int64); - [%expect {| |}] - ;; - end) -;; - -let%test_module "Make_hex" = - (module struct - module Hex_int = struct - type t = int [@@deriving quickcheck] - - module M = Make_hex (struct - type nonrec t = int [@@deriving sexp, compare ~localize, hash, quickcheck] - - let to_string = Int.Hex.to_string - let of_string = Int.Hex.of_string - let zero = 0 - let ( < ) = ( < ) - let neg = Int.neg - let module_name = "Hex_int" - end) - - include (M.Hex : module type of M.Hex with type t := t) - end - - let%expect_test "validate sexp grammar" = - require_ok (Sexp_grammar_validation.validate_grammar (module Hex_int)); - [%expect {| String |}] - ;; - end) -;; +module%test [@name "pretty"] _ = struct + let check input output = + List.for_all [ ""; "+"; "-" ] ~f:(fun prefix -> + let input = prefix ^ input in + let output = prefix ^ output in + [%compare.equal: string] output (insert_underscores input)) + ;; + + let%test _ = check "1" "1" + let%test _ = check "12" "12" + let%test _ = check "123" "123" + let%test _ = check "1234" "1_234" + let%test _ = check "12345" "12_345" + let%test _ = check "123456" "123_456" + let%test _ = check "1234567" "1_234_567" + let%test _ = check "12345678" "12_345_678" + let%test _ = check "123456789" "123_456_789" + let%test _ = check "1234567890" "1_234_567_890" +end + +module%test [@name "conversions"] _ = struct + module type S = sig + include Int.S + + val module_name : string + end + + let test_conversion (type a b) loc ma mb a_to_b_or_error a_to_b_trunc b_to_a_trunc = + let (module A : S with type t = a) = ma in + let (module B : S with type t = b) = mb in + let examples = + [ A.min_value + ; A.minus_one + ; A.zero + ; A.one + ; A.max_value + ; B.min_value |> b_to_a_trunc + ; B.max_value |> b_to_a_trunc + ] + |> List.concat_map ~f:(fun a -> [ A.pred a; a; A.succ a ]) + |> List.dedup_and_sort ~compare:A.compare + |> List.sort ~compare:A.compare + in + List.iter examples ~f:(fun a -> + let b' = a_to_b_trunc a in + let a' = b_to_a_trunc b' in + match a_to_b_or_error a with + | Ok b -> + require + ~here:loc + (B.equal b b') + ~if_false_then_print_s: + (lazy + [%message + "conversion produced wrong value" + ~from:(A.module_name : string) + ~to_:(B.module_name : string) + ~input:(a : A.t) + ~output:(b : B.t) + ~expected:(b' : B.t)]); + require + ~here:loc + (A.equal a a') + ~if_false_then_print_s: + (lazy + [%message + "conversion does not round-trip" + ~from:(A.module_name : string) + ~to_:(B.module_name : string) + ~input:(a : A.t) + ~output:(b : B.t) + ~round_trip:(a' : A.t)]) + | Error error -> + require + ~here:loc + (not (A.equal a a')) + ~if_false_then_print_s: + (lazy + [%message + "conversion failed" + ~from:(A.module_name : string) + ~to_:(B.module_name : string) + ~input:(a : A.t) + ~expected_output:(b' : B.t) + ~error:(error : Error.t)])) + ;; + + let test loc ma mb (a_to_b_trunc, a_to_b_or_error) (b_to_a_trunc, b_to_a_or_error) = + test_conversion loc ma mb a_to_b_or_error a_to_b_trunc b_to_a_trunc; + test_conversion loc mb ma b_to_a_or_error b_to_a_trunc a_to_b_trunc + ;; + + module Int = struct + include Int + + let module_name = "Int" + end + + module Int32 = struct + include Int32 + + let module_name = "Int32" + end + + module Int64 = struct + include Int64 + + let module_name = "Int64" + end + + module Nativeint = struct + include Nativeint + + let module_name = "Nativeint" + end + + let with_exn f x = Or_error.try_with (fun () -> f x) + let optional f x = Or_error.try_with (fun () -> Option.value_exn (f x)) + let alwaysok f x = Ok (f x) + + let%expect_test "int <-> int32" = + test + [%here] + (module Int) + (module Int32) + (Stdlib.Int32.of_int, with_exn int_to_int32_exn) + (Stdlib.Int32.to_int, with_exn int32_to_int_exn); + [%expect {| |}]; + test + [%here] + (module Int) + (module Int32) + (Stdlib.Int32.of_int, optional int_to_int32) + (Stdlib.Int32.to_int, optional int32_to_int); + [%expect {| |}] + ;; + + let%expect_test "int <-> int64" = + test + [%here] + (module Int) + (module Int64) + (Stdlib.Int64.of_int, alwaysok int_to_int64) + (Stdlib.Int64.to_int, with_exn int64_to_int_exn); + [%expect {| |}]; + test + [%here] + (module Int) + (module Int64) + (Stdlib.Int64.of_int, alwaysok int_to_int64) + (Stdlib.Int64.to_int, optional int64_to_int); + [%expect {| |}] + ;; + + let%expect_test "int <-> nativeint" = + test + [%here] + (module Int) + (module Nativeint) + (Stdlib.Nativeint.of_int, alwaysok int_to_nativeint) + (Stdlib.Nativeint.to_int, with_exn nativeint_to_int_exn); + [%expect {| |}]; + test + [%here] + (module Int) + (module Nativeint) + (Stdlib.Nativeint.of_int, alwaysok int_to_nativeint) + (Stdlib.Nativeint.to_int, optional nativeint_to_int); + [%expect {| |}] + ;; + + let%expect_test "int32 <-> int64" = + test + [%here] + (module Int32) + (module Int64) + (Stdlib.Int64.of_int32, alwaysok int32_to_int64) + (Stdlib.Int64.to_int32, with_exn int64_to_int32_exn); + [%expect {| |}]; + test + [%here] + (module Int32) + (module Int64) + (Stdlib.Int64.of_int32, alwaysok int32_to_int64) + (Stdlib.Int64.to_int32, optional int64_to_int32); + [%expect {| |}] + ;; + + let%expect_test "int32 <-> nativeint" = + test + [%here] + (module Int32) + (module Nativeint) + (Stdlib.Nativeint.of_int32, alwaysok int32_to_nativeint) + (Stdlib.Nativeint.to_int32, with_exn nativeint_to_int32_exn); + [%expect {| |}]; + test + [%here] + (module Int32) + (module Nativeint) + (Stdlib.Nativeint.of_int32, alwaysok int32_to_nativeint) + (Stdlib.Nativeint.to_int32, optional nativeint_to_int32); + [%expect {| |}] + ;; + + let%expect_test "int64 <-> nativeint" = + test + [%here] + (module Int64) + (module Nativeint) + (Stdlib.Int64.to_nativeint, with_exn int64_to_nativeint_exn) + (Stdlib.Int64.of_nativeint, alwaysok nativeint_to_int64); + [%expect {| |}]; + test + [%here] + (module Int64) + (module Nativeint) + (Stdlib.Int64.to_nativeint, optional int64_to_nativeint) + (Stdlib.Int64.of_nativeint, alwaysok nativeint_to_int64); + [%expect {| |}] + ;; +end + +module%test Make_hex = struct + module Hex_int = struct + type t = int [@@deriving quickcheck] + + module M = Make_hex (struct + type nonrec t = int [@@deriving sexp, compare ~localize, hash, quickcheck] + + let to_string = Int.Hex.to_string + let of_string = Int.Hex.of_string + let zero = 0 + let ( < ) = ( < ) + let neg = Int.neg + let module_name = "Hex_int" + end) + + include (M.Hex : module type of M.Hex with type t := t) + end + + let%expect_test "validate sexp grammar" = + require_ok (Sexp_grammar_validation.validate_grammar (module Hex_int)); + [%expect {| String |}] + ;; +end diff --git a/test/test_int_math.ml b/test/test_int_math.ml index dc649b8..0401fd2 100644 --- a/test/test_int_math.ml +++ b/test/test_int_math.ml @@ -19,118 +19,110 @@ module Test (X : Make_arg) : sig end = struct open X include Make (X) - let%test_module "integer-rounding" = - (module struct - let check dir ~range:(lower, upper) ~modulus expected = - let modulus = of_int_exn modulus in - let expected = of_int_exn expected in - for i = lower to upper do - let observed = round ~dir ~to_multiple_of:modulus (of_int_exn i) in - if observed <> expected then raise_s [%message "invalid result" (i : int)] - done - ;; - - let%test_unit _ = check ~modulus:10 `Down ~range:(10, 19) 10 - let%test_unit _ = check ~modulus:10 `Down ~range:(0, 9) 0 - let%test_unit _ = check ~modulus:10 `Down ~range:(-10, -1) (-10) - let%test_unit _ = check ~modulus:10 `Down ~range:(-20, -11) (-20) - let%test_unit _ = check ~modulus:10 `Up ~range:(11, 20) 20 - let%test_unit _ = check ~modulus:10 `Up ~range:(1, 10) 10 - let%test_unit _ = check ~modulus:10 `Up ~range:(-9, 0) 0 - let%test_unit _ = check ~modulus:10 `Up ~range:(-19, -10) (-10) - let%test_unit _ = check ~modulus:10 `Zero ~range:(10, 19) 10 - let%test_unit _ = check ~modulus:10 `Zero ~range:(-9, 9) 0 - let%test_unit _ = check ~modulus:10 `Zero ~range:(-19, -10) (-10) - let%test_unit _ = check ~modulus:10 `Nearest ~range:(15, 24) 20 - let%test_unit _ = check ~modulus:10 `Nearest ~range:(5, 14) 10 - let%test_unit _ = check ~modulus:10 `Nearest ~range:(-5, 4) 0 - let%test_unit _ = check ~modulus:10 `Nearest ~range:(-15, -6) (-10) - let%test_unit _ = check ~modulus:10 `Nearest ~range:(-25, -16) (-20) - let%test_unit _ = check ~modulus:5 `Nearest ~range:(8, 12) 10 - let%test_unit _ = check ~modulus:5 `Nearest ~range:(3, 7) 5 - let%test_unit _ = check ~modulus:5 `Nearest ~range:(-2, 2) 0 - let%test_unit _ = check ~modulus:5 `Nearest ~range:(-7, -3) (-5) - let%test_unit _ = check ~modulus:5 `Nearest ~range:(-12, -8) (-10) - end) - ;; + module%test [@name "integer-rounding"] _ = struct + let check dir ~range:(lower, upper) ~modulus expected = + let modulus = of_int_exn modulus in + let expected = of_int_exn expected in + for i = lower to upper do + let observed = round ~dir ~to_multiple_of:modulus (of_int_exn i) in + if observed <> expected then raise_s [%message "invalid result" (i : int)] + done + ;; - let%test_module "remainder-and-modulus" = - (module struct - let one = of_int_exn 1 - - let check_integers x y = - let sexp_of_t t = sexp_of_string (to_string t) in - let check_raises f what = - match f () with - | exception _ -> () - | z -> - raise_s - [%message - "produced result instead of raising" - (what : string) - (x : t) - (y : t) - (z : t)] - in - let check_true cond what = - if not cond then raise_s [%message "failed" (what : string) (x : t) (y : t)] - in - if y = zero + let%test_unit _ = check ~modulus:10 `Down ~range:(10, 19) 10 + let%test_unit _ = check ~modulus:10 `Down ~range:(0, 9) 0 + let%test_unit _ = check ~modulus:10 `Down ~range:(-10, -1) (-10) + let%test_unit _ = check ~modulus:10 `Down ~range:(-20, -11) (-20) + let%test_unit _ = check ~modulus:10 `Up ~range:(11, 20) 20 + let%test_unit _ = check ~modulus:10 `Up ~range:(1, 10) 10 + let%test_unit _ = check ~modulus:10 `Up ~range:(-9, 0) 0 + let%test_unit _ = check ~modulus:10 `Up ~range:(-19, -10) (-10) + let%test_unit _ = check ~modulus:10 `Zero ~range:(10, 19) 10 + let%test_unit _ = check ~modulus:10 `Zero ~range:(-9, 9) 0 + let%test_unit _ = check ~modulus:10 `Zero ~range:(-19, -10) (-10) + let%test_unit _ = check ~modulus:10 `Nearest ~range:(15, 24) 20 + let%test_unit _ = check ~modulus:10 `Nearest ~range:(5, 14) 10 + let%test_unit _ = check ~modulus:10 `Nearest ~range:(-5, 4) 0 + let%test_unit _ = check ~modulus:10 `Nearest ~range:(-15, -6) (-10) + let%test_unit _ = check ~modulus:10 `Nearest ~range:(-25, -16) (-20) + let%test_unit _ = check ~modulus:5 `Nearest ~range:(8, 12) 10 + let%test_unit _ = check ~modulus:5 `Nearest ~range:(3, 7) 5 + let%test_unit _ = check ~modulus:5 `Nearest ~range:(-2, 2) 0 + let%test_unit _ = check ~modulus:5 `Nearest ~range:(-7, -3) (-5) + let%test_unit _ = check ~modulus:5 `Nearest ~range:(-12, -8) (-10) + end + + module%test [@name "remainder-and-modulus"] _ = struct + let one = of_int_exn 1 + + let check_integers x y = + let sexp_of_t t = sexp_of_string (to_string t) in + let check_raises f what = + match f () with + | exception _ -> () + | z -> + raise_s + [%message + "produced result instead of raising" (what : string) (x : t) (y : t) (z : t)] + in + let check_true cond what = + if not cond then raise_s [%message "failed" (what : string) (x : t) (y : t)] + in + if y = zero + then ( + check_raises (fun () -> x / y) "division by zero"; + check_raises (fun () -> rem x y) "rem _ zero"; + check_raises (fun () -> x % y) "_ % zero"; + check_raises (fun () -> x /% y) "_ /% zero") + else ( + if x < zero + then check_true (rem x y <= zero) "non-positive remainder" + else check_true (rem x y >= zero) "non-negative remainder"; + check_true (abs (rem x y) <= abs y - one) "range of remainder"; + if y < zero then ( - check_raises (fun () -> x / y) "division by zero"; - check_raises (fun () -> rem x y) "rem _ zero"; - check_raises (fun () -> x % y) "_ % zero"; - check_raises (fun () -> x /% y) "_ /% zero") + check_raises (fun () -> x % y) "_ % negative"; + check_raises (fun () -> x /% y) "_ /% negative") else ( - if x < zero - then check_true (rem x y <= zero) "non-positive remainder" - else check_true (rem x y >= zero) "non-negative remainder"; - check_true (abs (rem x y) <= abs y - one) "range of remainder"; - if y < zero + check_true (x = (x /% y * y) + (x % y)) "(/%) and (%) identity"; + check_true (x = (x / y * y) + rem x y) "(/) and rem identity"; + check_true (x % y >= zero) "non-negative (%)"; + check_true (x % y <= y - one) "range of (%)"; + if x > zero && y > zero then ( - check_raises (fun () -> x % y) "_ % negative"; - check_raises (fun () -> x /% y) "_ /% negative") - else ( - check_true (x = (x /% y * y) + (x % y)) "(/%) and (%) identity"; - check_true (x = (x / y * y) + rem x y) "(/) and rem identity"; - check_true (x % y >= zero) "non-negative (%)"; - check_true (x % y <= y - one) "range of (%)"; - if x > zero && y > zero - then ( - check_true (x /% y = x / y) "(/%) and (/) identity"; - check_true (x % y = rem x y) "(%) and rem identity"))) - ;; - - let check_natural_numbers x y = - List.iter - [ x; -x; x + one; -(x + one) ] - ~f:(fun x -> - List.iter [ y; -y; y + one; -(y + one) ] ~f:(fun y -> check_integers x y)) - ;; - - let%test_unit "deterministic" = - let big1 = of_int_exn 118_310_344 in - let big2 = of_int_exn 828_172_408 in - (* Important to test the case where one value is a multiple of the other. Note that + check_true (x /% y = x / y) "(/%) and (/) identity"; + check_true (x % y = rem x y) "(%) and rem identity"))) + ;; + + let check_natural_numbers x y = + List.iter + [ x; -x; x + one; -(x + one) ] + ~f:(fun x -> + List.iter [ y; -y; y + one; -(y + one) ] ~f:(fun y -> check_integers x y)) + ;; + + let%test_unit "deterministic" = + let big1 = of_int_exn 118_310_344 in + let big2 = of_int_exn 828_172_408 in + (* Important to test the case where one value is a multiple of the other. Note that the [x + one] and [y + one] cases in [check_natural_numbers] ensure that we also test non-multiple cases. *) - assert (big2 = big1 * of_int_exn 7); - let values = [ zero; one; big1; big2 ] in - List.iter values ~f:(fun x -> - List.iter values ~f:(fun y -> check_natural_numbers x y)) - ;; - - let%test_unit "random" = - let rand = Random.State.make [| 8; 67; -5_309 |] in - for _ = 0 to 1_000 do - let max_value = 1_000_000_000 in - let x = of_int_exn (Random.State.int rand max_value) in - let y = of_int_exn (Random.State.int rand max_value) in - check_natural_numbers x y - done - ;; - end) - ;; + assert (big2 = big1 * of_int_exn 7); + let values = [ zero; one; big1; big2 ] in + List.iter values ~f:(fun x -> + List.iter values ~f:(fun y -> check_natural_numbers x y)) + ;; + + let%test_unit "random" = + let rand = Random.State.make [| 8; 67; -5_309 |] in + for _ = 0 to 1_000 do + let max_value = 1_000_000_000 in + let x = of_int_exn (Random.State.int rand max_value) in + let y = of_int_exn (Random.State.int rand max_value) in + check_natural_numbers x y + done + ;; + end end include Test (Int) @@ -139,338 +131,323 @@ include Test (Int63) include Test (Int64) include Test (Nativeint) -let%test_module "int rounding quickcheck tests" = - (module struct - module type With_quickcheck = sig - type t [@@deriving sexp_of] - - include Make_arg with type t := t - - val min_value : t - val max_value : t - val quickcheck_generator_incl : t -> t -> t Base_quickcheck.Generator.t - val quickcheck_generator_log_incl : t -> t -> t Base_quickcheck.Generator.t - end - - module Rounding_direction = struct - type t = - [ `Up - | `Down - | `Zero - | `Nearest - ] - [@@deriving enumerate, sexp_of] - end - - module Rounding_pair (Integer : With_quickcheck) = struct - type t = - { number : Integer.t - ; factor : Integer.t - } - [@@deriving sexp_of] - - let quickcheck_generator = - (* This generator should frequently generate "interesting" numbers for rounding. *) - let open Base_quickcheck.Generator.Let_syntax in - (* First we choose a factor to round to. *) - let%bind factor = - Integer.quickcheck_generator_log_incl (Integer.of_int_exn 1) Integer.max_value - in - (* Then we choose a multiplier for that factor. *) - let%map multiplier = - Integer.quickcheck_generator_incl - (Integer.( / ) Integer.min_value factor) - (Integer.( / ) Integer.max_value factor) - (* Then we choose an offset such that [multiplier * factor] is the nearest value +module%test [@name "int rounding quickcheck tests"] _ = struct + module type With_quickcheck = sig + type t [@@deriving sexp_of] + + include Make_arg with type t := t + + val min_value : t + val max_value : t + val quickcheck_generator_incl : t -> t -> t Base_quickcheck.Generator.t + val quickcheck_generator_log_incl : t -> t -> t Base_quickcheck.Generator.t + end + + module Rounding_direction = struct + type t = + [ `Up + | `Down + | `Zero + | `Nearest + ] + [@@deriving enumerate, sexp_of] + end + + module Rounding_pair (Integer : With_quickcheck) = struct + type t = + { number : Integer.t + ; factor : Integer.t + } + [@@deriving sexp_of] + + let quickcheck_generator = + (* This generator should frequently generate "interesting" numbers for rounding. *) + let open Base_quickcheck.Generator.Let_syntax in + (* First we choose a factor to round to. *) + let%bind factor = + Integer.quickcheck_generator_log_incl (Integer.of_int_exn 1) Integer.max_value + in + (* Then we choose a multiplier for that factor. *) + let%map multiplier = + Integer.quickcheck_generator_incl + (Integer.( / ) Integer.min_value factor) + (Integer.( / ) Integer.max_value factor) + (* Then we choose an offset such that [multiplier * factor] is the nearest value to round to. [quickcheck_generator_incl] puts extra weight on the [-factor/2, factor/2] bounds, and we also weight 0 heavily. *) - and offset = - let half_factor = Integer.( / ) factor (Integer.of_int_exn 2) in - Base_quickcheck.Generator.weighted_union - [ 9., Integer.quickcheck_generator_incl (Integer.neg half_factor) half_factor - ; 1., Base_quickcheck.Generator.return Integer.zero - ] - in - let number = Integer.( + ) offset (Integer.( * ) factor multiplier) in - { number; factor } - ;; - - let quickcheck_shrinker = Base_quickcheck.Shrinker.atomic - end - - let test_direction (module Integer : With_quickcheck) ~dir = - let open Integer in - (* Criterion for correct rounding: must be a multiple of the factor *) - let is_multiple_of number ~factor = factor * (number / factor) = number in - (* Criterion for correct rounding: must not reverse sign *) - let is_compatible_sign number ~rounded = - if number > zero - then rounded >= zero - else if number < zero - then rounded <= zero - else rounded = zero + and offset = + let half_factor = Integer.( / ) factor (Integer.of_int_exn 2) in + Base_quickcheck.Generator.weighted_union + [ 9., Integer.quickcheck_generator_incl (Integer.neg half_factor) half_factor + ; 1., Base_quickcheck.Generator.return Integer.zero + ] in - (* Criterion for correct rounding: must be less than factor away from original *) - let is_close_enough x y ~factor = - if x > y - then x - y > zero && x - y < factor - else if x < y - then y - x > zero && y - x < factor + let number = Integer.( + ) offset (Integer.( * ) factor multiplier) in + { number; factor } + ;; + + let quickcheck_shrinker = Base_quickcheck.Shrinker.atomic + end + + let test_direction (module Integer : With_quickcheck) ~dir = + let open Integer in + (* Criterion for correct rounding: must be a multiple of the factor *) + let is_multiple_of number ~factor = factor * (number / factor) = number in + (* Criterion for correct rounding: must not reverse sign *) + let is_compatible_sign number ~rounded = + if number > zero + then rounded >= zero + else if number < zero + then rounded <= zero + else rounded = zero + in + (* Criterion for correct rounding: must be less than factor away from original *) + let is_close_enough x y ~factor = + if x > y + then x - y > zero && x - y < factor + else if x < y + then y - x > zero && y - x < factor + else true + in + (* Criterion for correct rounding: rounding direction must be respected *) + let is_in_correct_direction number ~dir ~rounded ~factor = + match dir with + | `Down -> rounded <= number + | `Up -> rounded >= number + | `Zero -> + if number < zero + then rounded >= number + else if number > zero + then rounded <= number + else rounded = zero + | `Nearest -> + if rounded > number + then rounded - number <= number - (rounded - factor) + else if rounded < number + then number - rounded < rounded + factor - number else true - in - (* Criterion for correct rounding: rounding direction must be respected *) - let is_in_correct_direction number ~dir ~rounded ~factor = - match dir with - | `Down -> rounded <= number - | `Up -> rounded >= number - | `Zero -> - if number < zero - then rounded >= number - else if number > zero - then rounded <= number - else rounded = zero - | `Nearest -> - if rounded > number - then rounded - number <= number - (rounded - factor) - else if rounded < number - then number - rounded < rounded + factor - number - else true - in - (* Correct rounding obeys all four criteria *) - let is_rounded_correctly number ~dir ~factor ~rounded = - is_multiple_of rounded ~factor - && is_compatible_sign number ~rounded - && is_close_enough number rounded ~factor - && is_in_correct_direction number ~dir ~rounded ~factor - in - (* Round correctly by finding a multiple of the factor, and trying +/-factor away + in + (* Correct rounding obeys all four criteria *) + let is_rounded_correctly number ~dir ~factor ~rounded = + is_multiple_of rounded ~factor + && is_compatible_sign number ~rounded + && is_close_enough number rounded ~factor + && is_in_correct_direction number ~dir ~rounded ~factor + in + (* Round correctly by finding a multiple of the factor, and trying +/-factor away from that. If this returns [None], there should be no correct representable result. *) - let round_correctly number ~dir ~factor = - let rounded0 = factor * (number / factor) in - match - List.filter - [ rounded0 - factor; rounded0; rounded0 + factor ] - ~f:(fun rounded -> is_rounded_correctly number ~dir ~factor ~rounded) - with - | [] -> None - | [ rounded ] -> Some rounded - | multiple -> - raise_s - [%sexp - "test bug: multiple correctly rounded values", (multiple : Integer.t list)] - in - let module Math = Make (Integer) in - let module Pair = Rounding_pair (Integer) in - require_does_not_raise (fun () -> - Base_quickcheck.Test.run_exn - (module Pair) - ~f:(fun ({ number; factor } : Pair.t) -> - let rounded = Math.round number ~dir ~to_multiple_of:factor in - (* Test that if it is possible to round correctly, then we do. *) - match round_correctly number ~dir ~factor with - | None -> - if is_rounded_correctly number ~dir ~factor ~rounded - then - raise_s - [%sexp - "test bug: did not find correctly rounded value" - , { rounded : Integer.t }] - | Some rounded_correctly -> - if rounded <> rounded_correctly - then - raise_s - [%sexp - "rounding failed" - , { rounded : Integer.t; rounded_correctly : Integer.t }])) - ;; + let round_correctly number ~dir ~factor = + let rounded0 = factor * (number / factor) in + match + List.filter + [ rounded0 - factor; rounded0; rounded0 + factor ] + ~f:(fun rounded -> is_rounded_correctly number ~dir ~factor ~rounded) + with + | [] -> None + | [ rounded ] -> Some rounded + | multiple -> + raise_s + [%sexp + "test bug: multiple correctly rounded values", (multiple : Integer.t list)] + in + let module Math = Make (Integer) in + let module Pair = Rounding_pair (Integer) in + require_does_not_raise (fun () -> + Base_quickcheck.Test.run_exn + (module Pair) + ~f:(fun ({ number; factor } : Pair.t) -> + let rounded = Math.round number ~dir ~to_multiple_of:factor in + (* Test that if it is possible to round correctly, then we do. *) + match round_correctly number ~dir ~factor with + | None -> + if is_rounded_correctly number ~dir ~factor ~rounded + then + raise_s + [%sexp + "test bug: did not find correctly rounded value" + , { rounded : Integer.t }] + | Some rounded_correctly -> + if rounded <> rounded_correctly + then + raise_s + [%sexp + "rounding failed" + , { rounded : Integer.t; rounded_correctly : Integer.t }])) + ;; - let test m = - List.iter Rounding_direction.all ~f:(fun dir -> - print_s [%sexp "testing", (dir : Rounding_direction.t)]; - test_direction m ~dir) - ;; + let test m = + List.iter Rounding_direction.all ~f:(fun dir -> + print_s [%sexp "testing", (dir : Rounding_direction.t)]; + test_direction m ~dir) + ;; - let%expect_test ("int" [@tags "no-js", "64-bits-only"]) = - test - (module struct - include Int - - let quickcheck_generator_incl = Base_quickcheck.Generator.int_inclusive - let quickcheck_generator_log_incl = Base_quickcheck.Generator.int_log_inclusive - end); - [%expect - {| - (testing Up) - (testing Down) - (testing Zero) - (testing Nearest) - |}] - ;; + let%expect_test ("int" [@tags "no-js", "64-bits-only"]) = + test + (module struct + include Int + + let quickcheck_generator_incl = Base_quickcheck.Generator.int_inclusive + let quickcheck_generator_log_incl = Base_quickcheck.Generator.int_log_inclusive + end); + [%expect + {| + (testing Up) + (testing Down) + (testing Zero) + (testing Nearest) + |}] + ;; - let%expect_test "int32" = - test - (module struct - include Int32 - - let quickcheck_generator_incl = Base_quickcheck.Generator.int32_inclusive - - let quickcheck_generator_log_incl = - Base_quickcheck.Generator.int32_log_inclusive - ;; - end); - [%expect - {| - (testing Up) - (testing Down) - (testing Zero) - (testing Nearest) - |}] - ;; + let%expect_test "int32" = + test + (module struct + include Int32 + + let quickcheck_generator_incl = Base_quickcheck.Generator.int32_inclusive + let quickcheck_generator_log_incl = Base_quickcheck.Generator.int32_log_inclusive + end); + [%expect + {| + (testing Up) + (testing Down) + (testing Zero) + (testing Nearest) + |}] + ;; - let%expect_test "int63" = - test - (module struct - include Int63 - - let quickcheck_generator_incl = Base_quickcheck.Generator.int63_inclusive - - let quickcheck_generator_log_incl = - Base_quickcheck.Generator.int63_log_inclusive - ;; - end); - [%expect - {| - (testing Up) - (testing Down) - (testing Zero) - (testing Nearest) - |}] - ;; + let%expect_test "int63" = + test + (module struct + include Int63 + + let quickcheck_generator_incl = Base_quickcheck.Generator.int63_inclusive + let quickcheck_generator_log_incl = Base_quickcheck.Generator.int63_log_inclusive + end); + [%expect + {| + (testing Up) + (testing Down) + (testing Zero) + (testing Nearest) + |}] + ;; - let%expect_test "int64" = - test - (module struct - include Int64 - - let quickcheck_generator_incl = Base_quickcheck.Generator.int64_inclusive - - let quickcheck_generator_log_incl = - Base_quickcheck.Generator.int64_log_inclusive - ;; - end); - [%expect - {| - (testing Up) - (testing Down) - (testing Zero) - (testing Nearest) - |}] - ;; + let%expect_test "int64" = + test + (module struct + include Int64 + + let quickcheck_generator_incl = Base_quickcheck.Generator.int64_inclusive + let quickcheck_generator_log_incl = Base_quickcheck.Generator.int64_log_inclusive + end); + [%expect + {| + (testing Up) + (testing Down) + (testing Zero) + (testing Nearest) + |}] + ;; - let%expect_test ("nativeint" [@tags "no-js", "64-bits-only"]) = - test - (module struct - include Nativeint - - let quickcheck_generator_incl = Base_quickcheck.Generator.nativeint_inclusive - - let quickcheck_generator_log_incl = - Base_quickcheck.Generator.nativeint_log_inclusive - ;; - end); - [%expect - {| - (testing Up) - (testing Down) - (testing Zero) - (testing Nearest) - |}] - ;; - end) -;; + let%expect_test ("nativeint" [@tags "no-js", "64-bits-only"]) = + test + (module struct + include Nativeint + + let quickcheck_generator_incl = Base_quickcheck.Generator.nativeint_inclusive + + let quickcheck_generator_log_incl = + Base_quickcheck.Generator.nativeint_log_inclusive + ;; + end); + [%expect + {| + (testing Up) + (testing Down) + (testing Zero) + (testing Nearest) + |}] + ;; +end -let%test_module "pow" = - (module struct - let%test _ = int_pow 0 0 = 1 - let%test _ = int_pow 0 1 = 0 - let%test _ = int_pow 10 1 = 10 - let%test _ = int_pow 10 2 = 100 - let%test _ = int_pow 10 3 = 1_000 - let%test _ = int_pow 10 4 = 10_000 - let%test _ = int_pow 10 5 = 100_000 - let%test _ = int_pow 2 10 = 1024 - let%test _ = int_pow 0 1_000_000 = 0 - let%test _ = int_pow 1 1_000_000 = 1 - let%test _ = int_pow (-1) 1_000_000 = 1 - let%test _ = int_pow (-1) 1_000_001 = -1 - let ( = ) = Int64.( = ) - let%test _ = int64_pow 0L 0L = 1L - let%test _ = int64_pow 0L 1_000_000L = 0L - let%test _ = int64_pow 1L 1_000_000L = 1L - let%test _ = int64_pow (-1L) 1_000_000L = 1L - let%test _ = int64_pow (-1L) 1_000_001L = -1L - let%test _ = int64_pow 10L 1L = 10L - let%test _ = int64_pow 10L 2L = 100L - let%test _ = int64_pow 10L 3L = 1_000L - let%test _ = int64_pow 10L 4L = 10_000L - let%test _ = int64_pow 10L 5L = 100_000L - let%test _ = int64_pow 2L 10L = 1_024L - let%test _ = int64_pow 5L 27L = 7450580596923828125L - let exception_thrown pow b e = Exn.does_raise (fun () -> pow b e) - let%test _ = exception_thrown int_pow 10 60 - let%test _ = exception_thrown int64_pow 10L 60L - let%test _ = exception_thrown int_pow 10 (-1) - let%test _ = exception_thrown int64_pow 10L (-1L) - let%test _ = exception_thrown int64_pow 2L 63L - let%test _ = not (exception_thrown int64_pow 2L 62L) - let%test _ = exception_thrown int64_pow (-2L) 63L - let%test _ = not (exception_thrown int64_pow (-2L) 62L) - end) -;; +module%test [@name "pow"] _ = struct + let%test _ = int_pow 0 0 = 1 + let%test _ = int_pow 0 1 = 0 + let%test _ = int_pow 10 1 = 10 + let%test _ = int_pow 10 2 = 100 + let%test _ = int_pow 10 3 = 1_000 + let%test _ = int_pow 10 4 = 10_000 + let%test _ = int_pow 10 5 = 100_000 + let%test _ = int_pow 2 10 = 1024 + let%test _ = int_pow 0 1_000_000 = 0 + let%test _ = int_pow 1 1_000_000 = 1 + let%test _ = int_pow (-1) 1_000_000 = 1 + let%test _ = int_pow (-1) 1_000_001 = -1 + let ( = ) = Int64.( = ) + let%test _ = int64_pow 0L 0L = 1L + let%test _ = int64_pow 0L 1_000_000L = 0L + let%test _ = int64_pow 1L 1_000_000L = 1L + let%test _ = int64_pow (-1L) 1_000_000L = 1L + let%test _ = int64_pow (-1L) 1_000_001L = -1L + let%test _ = int64_pow 10L 1L = 10L + let%test _ = int64_pow 10L 2L = 100L + let%test _ = int64_pow 10L 3L = 1_000L + let%test _ = int64_pow 10L 4L = 10_000L + let%test _ = int64_pow 10L 5L = 100_000L + let%test _ = int64_pow 2L 10L = 1_024L + let%test _ = int64_pow 5L 27L = 7450580596923828125L + let exception_thrown pow b e = Exn.does_raise (fun () -> pow b e) + let%test _ = exception_thrown int_pow 10 60 + let%test _ = exception_thrown int64_pow 10L 60L + let%test _ = exception_thrown int_pow 10 (-1) + let%test _ = exception_thrown int64_pow 10L (-1L) + let%test _ = exception_thrown int64_pow 2L 63L + let%test _ = not (exception_thrown int64_pow 2L 62L) + let%test _ = exception_thrown int64_pow (-2L) 63L + let%test _ = not (exception_thrown int64_pow (-2L) 62L) +end -let%test_module "overflow_bounds" = - (module struct - module Pow_overflow_bounds = Pow_overflow_bounds +module%test [@name "overflow_bounds"] _ = struct + module Pow_overflow_bounds = Pow_overflow_bounds - let%test _ = Int.equal Pow_overflow_bounds.overflow_bound_max_int_value Int.max_value + let%test _ = Int.equal Pow_overflow_bounds.overflow_bound_max_int_value Int.max_value - let%test _ = - Int64.equal Pow_overflow_bounds.overflow_bound_max_int64_value Int64.max_value - ;; + let%test _ = + Int64.equal Pow_overflow_bounds.overflow_bound_max_int64_value Int64.max_value + ;; - let test_overflow_table tbl conv max_val = - assert (Array.length tbl = 64); - let max_val = conv max_val in - Array.iteri tbl ~f:(fun i max_base -> - let max_base = conv max_base in - let overflows b = Bigint.(b ** of_int i > max_val) in - let is_ok = - if i = 0 - then Bigint.(max_base = max_val) - else (not (overflows max_base)) && overflows Bigint.(max_base + one) - in - if not is_ok - then - Printf.failwithf - "overflow table check failed for %s (index %d)" - (Bigint.to_string max_base) - i - ()) - ;; + let test_overflow_table tbl conv max_val = + assert (Array.length tbl = 64); + let max_val = conv max_val in + Array.iteri tbl ~f:(fun i max_base -> + let max_base = conv max_base in + let overflows b = Bigint.(b ** of_int i > max_val) in + let is_ok = + if i = 0 + then Bigint.(max_base = max_val) + else (not (overflows max_base)) && overflows Bigint.(max_base + one) + in + if not is_ok + then + Printf.failwithf + "overflow table check failed for %s (index %d)" + (Bigint.to_string max_base) + i + ()) + ;; - let%test_unit _ = - test_overflow_table - Pow_overflow_bounds.int_positive_overflow_bounds - Bigint.of_int - Int.max_value - ;; + let%test_unit _ = + test_overflow_table + Pow_overflow_bounds.int_positive_overflow_bounds + Bigint.of_int + Int.max_value + ;; - let%test_unit _ = - test_overflow_table - Pow_overflow_bounds.int64_positive_overflow_bounds - Bigint.of_int64 - Int64.max_value - ;; - end) -;; + let%test_unit _ = + test_overflow_table + Pow_overflow_bounds.int64_positive_overflow_bounds + Bigint.of_int64 + Int64.max_value + ;; +end diff --git a/test/test_int_pow2.ml b/test/test_int_pow2.ml index ac90971..5b88b71 100644 --- a/test/test_int_pow2.ml +++ b/test/test_int_pow2.ml @@ -79,43 +79,41 @@ let%expect_test ("[ceil_log2]" [@tags "64-bits-only"]) = |}] ;; -let%test_module "int_math" = - (module struct - let test_cases () = +module%test [@name "int_math"] _ = struct + let test_cases () = + let cases = + [ 0b10101010 + ; 0b1010101010101010 + ; 0b101010101010101010101010 + ; 0b10000000 + ; 0b1000000000001000 + ; 0b100000000000000000001000 + ] + in + match Word_size.word_size with + | W64 -> + (* create some >32 bit values... *) + (* We can't use literals directly because the compiler complains on 32 bits. *) let cases = - [ 0b10101010 - ; 0b1010101010101010 - ; 0b101010101010101010101010 - ; 0b10000000 - ; 0b1000000000001000 - ; 0b100000000000000000001000 - ] + cases + @ [ (0b1010101010101010 lsl 16) lor 0b1010101010101010 + ; (0b1000000000000000 lsl 16) lor 0b0000000000001000 + ] in - match Word_size.word_size with - | W64 -> - (* create some >32 bit values... *) - (* We can't use literals directly because the compiler complains on 32 bits. *) - let cases = - cases - @ [ (0b1010101010101010 lsl 16) lor 0b1010101010101010 - ; (0b1000000000000000 lsl 16) lor 0b0000000000001000 - ] - in - let added_cases = List.map cases ~f:(fun x -> x lsl 16) in - List.concat [ cases; added_cases ] - | W32 -> cases - ;; + let added_cases = List.map cases ~f:(fun x -> x lsl 16) in + List.concat [ cases; added_cases ] + | W32 -> cases + ;; - let%test_unit "ceil_pow2" = - List.iter (test_cases ()) ~f:(fun x -> - let p2 = ceil_pow2 x in - assert (is_pow2 p2 && p2 >= x && x >= p2 / 2)) - ;; + let%test_unit "ceil_pow2" = + List.iter (test_cases ()) ~f:(fun x -> + let p2 = ceil_pow2 x in + assert (is_pow2 p2 && p2 >= x && x >= p2 / 2)) + ;; - let%test_unit "floor_pow2" = - List.iter (test_cases ()) ~f:(fun x -> - let p2 = floor_pow2 x in - assert (is_pow2 p2 && 2 * p2 >= x && x >= p2)) - ;; - end) -;; + let%test_unit "floor_pow2" = + List.iter (test_cases ()) ~f:(fun x -> + let p2 = floor_pow2 x in + assert (is_pow2 p2 && 2 * p2 >= x && x >= p2)) + ;; +end diff --git a/test/test_lazy.ml b/test/test_lazy.ml index 0a14550..00a5975 100644 --- a/test/test_lazy.ml +++ b/test/test_lazy.ml @@ -40,38 +40,36 @@ let%expect_test "peek" = [%expect {| (forced) |}] ;; -let%test_module _ = - (module struct - module M1 = struct - type nonrec t = { x : int t } [@@deriving sexp_of] - end +module%test _ = struct + module M1 = struct + type nonrec t = { x : int t } [@@deriving sexp_of] + end - module M2 = struct - type t = { x : int T_unforcing.t } [@@deriving sexp_of] - end + module M2 = struct + type t = { x : int T_unforcing.t } [@@deriving sexp_of] + end - let%test_unit _ = - let v = lazy 42 in - let (_ : int) = - (* no needed, but the purpose of this test is not to test this compiler + let%test_unit _ = + let v = lazy 42 in + let (_ : int) = + (* no needed, but the purpose of this test is not to test this compiler optimization *) - force v - in - assert (is_val v); - let t1 = { M1.x = v } in - let t2 = { M2.x = v } in - assert (Sexp.equal (M1.sexp_of_t t1) (M2.sexp_of_t t2)) - ;; + force v + in + assert (is_val v); + let t1 = { M1.x = v } in + let t2 = { M2.x = v } in + assert (Sexp.equal (M1.sexp_of_t t1) (M2.sexp_of_t t2)) + ;; - let%test_unit _ = - let t1 = { M1.x = lazy (40 + 2) } in - let t2 = { M2.x = lazy (40 + 2) } in - assert (not (Sexp.equal (M1.sexp_of_t t1) (M2.sexp_of_t t2))); - assert (is_val t1.x); - assert (not (is_val t2.x)) - ;; - end) -;; + let%test_unit _ = + let t1 = { M1.x = lazy (40 + 2) } in + let t2 = { M2.x = lazy (40 + 2) } in + assert (not (Sexp.equal (M1.sexp_of_t t1) (M2.sexp_of_t t2))); + assert (is_val t1.x); + assert (not (is_val t2.x)) + ;; +end let%expect_test "equal" = let lazy_a = diff --git a/test/test_list.ml b/test/test_list.ml index e4c438f..a142849 100644 --- a/test/test_list.ml +++ b/test/test_list.ml @@ -16,163 +16,159 @@ let%expect_test "find_exn" = [%expect {| (Ok -2) |}] ;; -let%test_module "reduce_balanced" = - (module struct - let test expect list = - [%test_result: string option] - ~expect - (reduce_balanced ~f:(fun a b -> "(" ^ a ^ "+" ^ b ^ ")") list) - ;; +module%test [@name "reduce_balanced"] _ = struct + let test expect list = + [%test_result: string option] + ~expect + (reduce_balanced ~f:(fun a b -> "(" ^ a ^ "+" ^ b ^ ")") list) + ;; - let%test_unit "length 0" = test None [] - let%test_unit "length 1" = test (Some "a") [ "a" ] - let%test_unit "length 2" = test (Some "(a+b)") [ "a"; "b" ] + let%test_unit "length 0" = test None [] + let%test_unit "length 1" = test (Some "a") [ "a" ] + let%test_unit "length 2" = test (Some "(a+b)") [ "a"; "b" ] - let%test_unit "length 6" = - test (Some "(((a+b)+(c+d))+(e+f))") [ "a"; "b"; "c"; "d"; "e"; "f" ] - ;; + let%test_unit "length 6" = + test (Some "(((a+b)+(c+d))+(e+f))") [ "a"; "b"; "c"; "d"; "e"; "f" ] + ;; - let%test_unit "longer" = - (* pairs (index, number of times f called on me) to check: + let%test_unit "longer" = + (* pairs (index, number of times f called on me) to check: 1. f called on results in index order 2. total number of calls on any element is low called on 2^n + 1 to demonstrate lack of balance (most elements are distance 7 from the tree root, but one is distance 1) *) - let data = map (range 0 65) ~f:(fun i -> [ i, 0 ]) in - let f x y = map (x @ y) ~f:(fun (ix, cx) -> ix, cx + 1) in - match reduce_balanced data ~f with - | None -> failwith "None" - | Some l -> - [%test_result: int] ~expect:65 (List.length l); - iteri l ~f:(fun actual_index (computed_index, num_f) -> - let expected_num_f = if actual_index = 64 then 1 else 7 in - [%test_result: int * int] - ~expect:(actual_index, expected_num_f) - (computed_index, num_f)) - ;; - end) -;; + let data = map (range 0 65) ~f:(fun i -> [ i, 0 ]) in + let f x y = map (x @ y) ~f:(fun (ix, cx) -> ix, cx + 1) in + match reduce_balanced data ~f with + | None -> failwith "None" + | Some l -> + [%test_result: int] ~expect:65 (List.length l); + iteri l ~f:(fun actual_index (computed_index, num_f) -> + let expected_num_f = if actual_index = 64 then 1 else 7 in + [%test_result: int * int] + ~expect:(actual_index, expected_num_f) + (computed_index, num_f)) + ;; +end -let%test_module "range symmetries" = - (module struct - let basic ~stride ~start ~stop ~start_n ~stop_n ~result = - [%compare.equal: int t] (range ~stride ~start ~stop start_n stop_n) result - ;; +module%test [@name "range symmetries"] _ = struct + let basic ~stride ~start ~stop ~start_n ~stop_n ~result = + [%compare.equal: int t] (range ~stride ~start ~stop start_n stop_n) result + ;; - let test stride (start_n, start) (stop_n, stop) result = - basic ~stride ~start ~stop ~start_n ~stop_n ~result - && (* works for negative [start] and [stop] *) - basic - ~stride:(-stride) - ~start_n:(-start_n) - ~stop_n:(-stop_n) - ~start - ~stop - ~result:(List.map result ~f:(fun x -> -x)) - ;; + let test stride (start_n, start) (stop_n, stop) result = + basic ~stride ~start ~stop ~start_n ~stop_n ~result + && (* works for negative [start] and [stop] *) + basic + ~stride:(-stride) + ~start_n:(-start_n) + ~stop_n:(-stop_n) + ~start + ~stop + ~result:(List.map result ~f:(fun x -> -x)) + ;; - let%test _ = test 1 (3, `inclusive) (1, `exclusive) [] - let%test _ = test 1 (3, `inclusive) (3, `exclusive) [] - let%test _ = test 1 (3, `inclusive) (4, `exclusive) [ 3 ] - let%test _ = test 1 (3, `inclusive) (8, `exclusive) [ 3; 4; 5; 6; 7 ] - let%test _ = test 3 (4, `inclusive) (10, `exclusive) [ 4; 7 ] - let%test _ = test 3 (4, `inclusive) (11, `exclusive) [ 4; 7; 10 ] - let%test _ = test 3 (4, `inclusive) (12, `exclusive) [ 4; 7; 10 ] - let%test _ = test 3 (4, `inclusive) (13, `exclusive) [ 4; 7; 10 ] - let%test _ = test 3 (4, `inclusive) (14, `exclusive) [ 4; 7; 10; 13 ] - let%test _ = test (-1) (1, `inclusive) (3, `exclusive) [] - let%test _ = test (-1) (3, `inclusive) (3, `exclusive) [] - let%test _ = test (-1) (4, `inclusive) (3, `exclusive) [ 4 ] - let%test _ = test (-1) (8, `inclusive) (3, `exclusive) [ 8; 7; 6; 5; 4 ] - let%test _ = test (-3) (10, `inclusive) (4, `exclusive) [ 10; 7 ] - let%test _ = test (-3) (10, `inclusive) (3, `exclusive) [ 10; 7; 4 ] - let%test _ = test (-3) (10, `inclusive) (2, `exclusive) [ 10; 7; 4 ] - let%test _ = test (-3) (10, `inclusive) (1, `exclusive) [ 10; 7; 4 ] - let%test _ = test (-3) (10, `inclusive) (0, `exclusive) [ 10; 7; 4; 1 ] - let%test _ = test 1 (3, `exclusive) (1, `exclusive) [] - let%test _ = test 1 (3, `exclusive) (3, `exclusive) [] - let%test _ = test 1 (3, `exclusive) (4, `exclusive) [] - let%test _ = test 1 (3, `exclusive) (8, `exclusive) [ 4; 5; 6; 7 ] - let%test _ = test 3 (4, `exclusive) (10, `exclusive) [ 7 ] - let%test _ = test 3 (4, `exclusive) (11, `exclusive) [ 7; 10 ] - let%test _ = test 3 (4, `exclusive) (12, `exclusive) [ 7; 10 ] - let%test _ = test 3 (4, `exclusive) (13, `exclusive) [ 7; 10 ] - let%test _ = test 3 (4, `exclusive) (14, `exclusive) [ 7; 10; 13 ] - let%test _ = test (-1) (1, `exclusive) (3, `exclusive) [] - let%test _ = test (-1) (3, `exclusive) (3, `exclusive) [] - let%test _ = test (-1) (4, `exclusive) (3, `exclusive) [] - let%test _ = test (-1) (8, `exclusive) (3, `exclusive) [ 7; 6; 5; 4 ] - let%test _ = test (-3) (10, `exclusive) (4, `exclusive) [ 7 ] - let%test _ = test (-3) (10, `exclusive) (3, `exclusive) [ 7; 4 ] - let%test _ = test (-3) (10, `exclusive) (2, `exclusive) [ 7; 4 ] - let%test _ = test (-3) (10, `exclusive) (1, `exclusive) [ 7; 4 ] - let%test _ = test (-3) (10, `exclusive) (0, `exclusive) [ 7; 4; 1 ] - let%test _ = test 1 (3, `inclusive) (1, `inclusive) [] - let%test _ = test 1 (3, `inclusive) (3, `inclusive) [ 3 ] - let%test _ = test 1 (3, `inclusive) (4, `inclusive) [ 3; 4 ] - let%test _ = test 1 (3, `inclusive) (8, `inclusive) [ 3; 4; 5; 6; 7; 8 ] - let%test _ = test 3 (4, `inclusive) (10, `inclusive) [ 4; 7; 10 ] - let%test _ = test 3 (4, `inclusive) (11, `inclusive) [ 4; 7; 10 ] - let%test _ = test 3 (4, `inclusive) (12, `inclusive) [ 4; 7; 10 ] - let%test _ = test 3 (4, `inclusive) (13, `inclusive) [ 4; 7; 10; 13 ] - let%test _ = test 3 (4, `inclusive) (14, `inclusive) [ 4; 7; 10; 13 ] - let%test _ = test (-1) (1, `inclusive) (3, `inclusive) [] - let%test _ = test (-1) (3, `inclusive) (3, `inclusive) [ 3 ] - let%test _ = test (-1) (4, `inclusive) (3, `inclusive) [ 4; 3 ] - let%test _ = test (-1) (8, `inclusive) (3, `inclusive) [ 8; 7; 6; 5; 4; 3 ] - let%test _ = test (-3) (10, `inclusive) (4, `inclusive) [ 10; 7; 4 ] - let%test _ = test (-3) (10, `inclusive) (3, `inclusive) [ 10; 7; 4 ] - let%test _ = test (-3) (10, `inclusive) (2, `inclusive) [ 10; 7; 4 ] - let%test _ = test (-3) (10, `inclusive) (1, `inclusive) [ 10; 7; 4; 1 ] - let%test _ = test (-3) (10, `inclusive) (0, `inclusive) [ 10; 7; 4; 1 ] - let%test _ = test 1 (3, `exclusive) (1, `inclusive) [] - let%test _ = test 1 (3, `exclusive) (3, `inclusive) [] - let%test _ = test 1 (3, `exclusive) (4, `inclusive) [ 4 ] - let%test _ = test 1 (3, `exclusive) (8, `inclusive) [ 4; 5; 6; 7; 8 ] - let%test _ = test 3 (4, `exclusive) (10, `inclusive) [ 7; 10 ] - let%test _ = test 3 (4, `exclusive) (11, `inclusive) [ 7; 10 ] - let%test _ = test 3 (4, `exclusive) (12, `inclusive) [ 7; 10 ] - let%test _ = test 3 (4, `exclusive) (13, `inclusive) [ 7; 10; 13 ] - let%test _ = test 3 (4, `exclusive) (14, `inclusive) [ 7; 10; 13 ] - let%test _ = test (-1) (1, `exclusive) (3, `inclusive) [] - let%test _ = test (-1) (3, `exclusive) (3, `inclusive) [] - let%test _ = test (-1) (4, `exclusive) (3, `inclusive) [ 3 ] - let%test _ = test (-1) (8, `exclusive) (3, `inclusive) [ 7; 6; 5; 4; 3 ] - let%test _ = test (-3) (10, `exclusive) (4, `inclusive) [ 7; 4 ] - let%test _ = test (-3) (10, `exclusive) (3, `inclusive) [ 7; 4 ] - let%test _ = test (-3) (10, `exclusive) (2, `inclusive) [ 7; 4 ] - let%test _ = test (-3) (10, `exclusive) (1, `inclusive) [ 7; 4; 1 ] - let%test _ = test (-3) (10, `exclusive) (0, `inclusive) [ 7; 4; 1 ] - - let test_start_inc_exc stride start (stop, stop_inc_exc) result = - test stride (start, `inclusive) (stop, stop_inc_exc) result - && - match result with - | [] -> true - | head :: tail -> - head = start && test stride (start, `exclusive) (stop, stop_inc_exc) tail - ;; + let%test _ = test 1 (3, `inclusive) (1, `exclusive) [] + let%test _ = test 1 (3, `inclusive) (3, `exclusive) [] + let%test _ = test 1 (3, `inclusive) (4, `exclusive) [ 3 ] + let%test _ = test 1 (3, `inclusive) (8, `exclusive) [ 3; 4; 5; 6; 7 ] + let%test _ = test 3 (4, `inclusive) (10, `exclusive) [ 4; 7 ] + let%test _ = test 3 (4, `inclusive) (11, `exclusive) [ 4; 7; 10 ] + let%test _ = test 3 (4, `inclusive) (12, `exclusive) [ 4; 7; 10 ] + let%test _ = test 3 (4, `inclusive) (13, `exclusive) [ 4; 7; 10 ] + let%test _ = test 3 (4, `inclusive) (14, `exclusive) [ 4; 7; 10; 13 ] + let%test _ = test (-1) (1, `inclusive) (3, `exclusive) [] + let%test _ = test (-1) (3, `inclusive) (3, `exclusive) [] + let%test _ = test (-1) (4, `inclusive) (3, `exclusive) [ 4 ] + let%test _ = test (-1) (8, `inclusive) (3, `exclusive) [ 8; 7; 6; 5; 4 ] + let%test _ = test (-3) (10, `inclusive) (4, `exclusive) [ 10; 7 ] + let%test _ = test (-3) (10, `inclusive) (3, `exclusive) [ 10; 7; 4 ] + let%test _ = test (-3) (10, `inclusive) (2, `exclusive) [ 10; 7; 4 ] + let%test _ = test (-3) (10, `inclusive) (1, `exclusive) [ 10; 7; 4 ] + let%test _ = test (-3) (10, `inclusive) (0, `exclusive) [ 10; 7; 4; 1 ] + let%test _ = test 1 (3, `exclusive) (1, `exclusive) [] + let%test _ = test 1 (3, `exclusive) (3, `exclusive) [] + let%test _ = test 1 (3, `exclusive) (4, `exclusive) [] + let%test _ = test 1 (3, `exclusive) (8, `exclusive) [ 4; 5; 6; 7 ] + let%test _ = test 3 (4, `exclusive) (10, `exclusive) [ 7 ] + let%test _ = test 3 (4, `exclusive) (11, `exclusive) [ 7; 10 ] + let%test _ = test 3 (4, `exclusive) (12, `exclusive) [ 7; 10 ] + let%test _ = test 3 (4, `exclusive) (13, `exclusive) [ 7; 10 ] + let%test _ = test 3 (4, `exclusive) (14, `exclusive) [ 7; 10; 13 ] + let%test _ = test (-1) (1, `exclusive) (3, `exclusive) [] + let%test _ = test (-1) (3, `exclusive) (3, `exclusive) [] + let%test _ = test (-1) (4, `exclusive) (3, `exclusive) [] + let%test _ = test (-1) (8, `exclusive) (3, `exclusive) [ 7; 6; 5; 4 ] + let%test _ = test (-3) (10, `exclusive) (4, `exclusive) [ 7 ] + let%test _ = test (-3) (10, `exclusive) (3, `exclusive) [ 7; 4 ] + let%test _ = test (-3) (10, `exclusive) (2, `exclusive) [ 7; 4 ] + let%test _ = test (-3) (10, `exclusive) (1, `exclusive) [ 7; 4 ] + let%test _ = test (-3) (10, `exclusive) (0, `exclusive) [ 7; 4; 1 ] + let%test _ = test 1 (3, `inclusive) (1, `inclusive) [] + let%test _ = test 1 (3, `inclusive) (3, `inclusive) [ 3 ] + let%test _ = test 1 (3, `inclusive) (4, `inclusive) [ 3; 4 ] + let%test _ = test 1 (3, `inclusive) (8, `inclusive) [ 3; 4; 5; 6; 7; 8 ] + let%test _ = test 3 (4, `inclusive) (10, `inclusive) [ 4; 7; 10 ] + let%test _ = test 3 (4, `inclusive) (11, `inclusive) [ 4; 7; 10 ] + let%test _ = test 3 (4, `inclusive) (12, `inclusive) [ 4; 7; 10 ] + let%test _ = test 3 (4, `inclusive) (13, `inclusive) [ 4; 7; 10; 13 ] + let%test _ = test 3 (4, `inclusive) (14, `inclusive) [ 4; 7; 10; 13 ] + let%test _ = test (-1) (1, `inclusive) (3, `inclusive) [] + let%test _ = test (-1) (3, `inclusive) (3, `inclusive) [ 3 ] + let%test _ = test (-1) (4, `inclusive) (3, `inclusive) [ 4; 3 ] + let%test _ = test (-1) (8, `inclusive) (3, `inclusive) [ 8; 7; 6; 5; 4; 3 ] + let%test _ = test (-3) (10, `inclusive) (4, `inclusive) [ 10; 7; 4 ] + let%test _ = test (-3) (10, `inclusive) (3, `inclusive) [ 10; 7; 4 ] + let%test _ = test (-3) (10, `inclusive) (2, `inclusive) [ 10; 7; 4 ] + let%test _ = test (-3) (10, `inclusive) (1, `inclusive) [ 10; 7; 4; 1 ] + let%test _ = test (-3) (10, `inclusive) (0, `inclusive) [ 10; 7; 4; 1 ] + let%test _ = test 1 (3, `exclusive) (1, `inclusive) [] + let%test _ = test 1 (3, `exclusive) (3, `inclusive) [] + let%test _ = test 1 (3, `exclusive) (4, `inclusive) [ 4 ] + let%test _ = test 1 (3, `exclusive) (8, `inclusive) [ 4; 5; 6; 7; 8 ] + let%test _ = test 3 (4, `exclusive) (10, `inclusive) [ 7; 10 ] + let%test _ = test 3 (4, `exclusive) (11, `inclusive) [ 7; 10 ] + let%test _ = test 3 (4, `exclusive) (12, `inclusive) [ 7; 10 ] + let%test _ = test 3 (4, `exclusive) (13, `inclusive) [ 7; 10; 13 ] + let%test _ = test 3 (4, `exclusive) (14, `inclusive) [ 7; 10; 13 ] + let%test _ = test (-1) (1, `exclusive) (3, `inclusive) [] + let%test _ = test (-1) (3, `exclusive) (3, `inclusive) [] + let%test _ = test (-1) (4, `exclusive) (3, `inclusive) [ 3 ] + let%test _ = test (-1) (8, `exclusive) (3, `inclusive) [ 7; 6; 5; 4; 3 ] + let%test _ = test (-3) (10, `exclusive) (4, `inclusive) [ 7; 4 ] + let%test _ = test (-3) (10, `exclusive) (3, `inclusive) [ 7; 4 ] + let%test _ = test (-3) (10, `exclusive) (2, `inclusive) [ 7; 4 ] + let%test _ = test (-3) (10, `exclusive) (1, `inclusive) [ 7; 4; 1 ] + let%test _ = test (-3) (10, `exclusive) (0, `inclusive) [ 7; 4; 1 ] + + let test_start_inc_exc stride start (stop, stop_inc_exc) result = + test stride (start, `inclusive) (stop, stop_inc_exc) result + && + match result with + | [] -> true + | head :: tail -> + head = start && test stride (start, `exclusive) (stop, stop_inc_exc) tail + ;; - let test_inc_exc stride start stop result = - test_start_inc_exc stride start (stop, `inclusive) result - && - match List.rev result with - | [] -> true - | last :: all_but_last -> - let all_but_last = List.rev all_but_last in - if last = stop - then test_start_inc_exc stride start (stop, `exclusive) all_but_last - else true - ;; + let test_inc_exc stride start stop result = + test_start_inc_exc stride start (stop, `inclusive) result + && + match List.rev result with + | [] -> true + | last :: all_but_last -> + let all_but_last = List.rev all_but_last in + if last = stop + then test_start_inc_exc stride start (stop, `exclusive) all_but_last + else true + ;; - let%test _ = test_inc_exc 1 4 10 [ 4; 5; 6; 7; 8; 9; 10 ] - let%test _ = test_inc_exc 3 4 10 [ 4; 7; 10 ] - let%test _ = test_inc_exc 3 4 11 [ 4; 7; 10 ] - let%test _ = test_inc_exc 3 4 12 [ 4; 7; 10 ] - let%test _ = test_inc_exc 3 4 13 [ 4; 7; 10; 13 ] - let%test _ = test_inc_exc 3 4 14 [ 4; 7; 10; 13 ] - end) -;; + let%test _ = test_inc_exc 1 4 10 [ 4; 5; 6; 7; 8; 9; 10 ] + let%test _ = test_inc_exc 3 4 10 [ 4; 7; 10 ] + let%test _ = test_inc_exc 3 4 11 [ 4; 7; 10 ] + let%test _ = test_inc_exc 3 4 12 [ 4; 7; 10 ] + let%test _ = test_inc_exc 3 4 13 [ 4; 7; 10; 13 ] + let%test _ = test_inc_exc 3 4 14 [ 4; 7; 10; 13 ] +end module Test_values = struct let long1 = @@ -426,183 +422,169 @@ let%test_unit _ = let%test_unit _ = [%test_result: (int * _) list] (mapi ~f:(fun i x -> i, x) []) ~expect:[] -let%test_module "group" = - (module struct - let%test_unit _ = - [%test_result: int list list] - (group [ 1; 2; 3; 4 ] ~break:(fun _ x -> x = 3)) - ~expect:[ [ 1; 2 ]; [ 3; 4 ] ] - ;; +module%test [@name "group"] _ = struct + let%test_unit _ = + [%test_result: int list list] + (group [ 1; 2; 3; 4 ] ~break:(fun _ x -> x = 3)) + ~expect:[ [ 1; 2 ]; [ 3; 4 ] ] + ;; - let%test_unit _ = - [%test_result: int list list] (group [] ~break:(fun _ -> assert false)) ~expect:[] - ;; + let%test_unit _ = + [%test_result: int list list] (group [] ~break:(fun _ -> assert false)) ~expect:[] + ;; - let mis = [ 'M'; 'i'; 's'; 's'; 'i'; 's'; 's'; 'i'; 'p'; 'p'; 'i' ] - - let equal_letters = - [ [ 'M' ] - ; [ 'i' ] - ; [ 's'; 's' ] - ; [ 'i' ] - ; [ 's'; 's' ] - ; [ 'i' ] - ; [ 'p'; 'p' ] - ; [ 'i' ] - ] - ;; + let mis = [ 'M'; 'i'; 's'; 's'; 'i'; 's'; 's'; 'i'; 'p'; 'p'; 'i' ] + + let equal_letters = + [ [ 'M' ] + ; [ 'i' ] + ; [ 's'; 's' ] + ; [ 'i' ] + ; [ 's'; 's' ] + ; [ 'i' ] + ; [ 'p'; 'p' ] + ; [ 'i' ] + ] + ;; - let single_letters = [ [ 'M'; 'i'; 's'; 's'; 'i'; 's'; 's'; 'i'; 'p'; 'p'; 'i' ] ] + let single_letters = [ [ 'M'; 'i'; 's'; 's'; 'i'; 's'; 's'; 'i'; 'p'; 'p'; 'i' ] ] - let every_three = - [ [ 'M'; 'i'; 's' ]; [ 's'; 'i'; 's' ]; [ 's'; 'i'; 'p' ]; [ 'p'; 'i' ] ] - ;; + let every_three = + [ [ 'M'; 'i'; 's' ]; [ 's'; 'i'; 's' ]; [ 's'; 'i'; 'p' ]; [ 'p'; 'i' ] ] + ;; - let%test_unit _ = - [%test_result: char list list] (group ~break:Char.( <> ) mis) ~expect:equal_letters - ;; + let%test_unit _ = + [%test_result: char list list] (group ~break:Char.( <> ) mis) ~expect:equal_letters + ;; - let%test_unit _ = - [%test_result: char list list] - (group ~break:(fun _ _ -> false) mis) - ~expect:single_letters - ;; + let%test_unit _ = + [%test_result: char list list] + (group ~break:(fun _ _ -> false) mis) + ~expect:single_letters + ;; - let%test_unit _ = - [%test_result: char list list] - (groupi ~break:(fun i _ _ -> i % 3 = 0) mis) - ~expect:every_three - ;; - end) -;; - -let%test_module "sort_and_group" = - (module struct - let%expect_test _ = - let compare a b = - Comparable.lift - String.compare - ~f:(fun s -> String.rstrip ~drop:Char.is_digit s) - a - b - in - [%test_result: string list list] - (sort_and_group [ "b1"; "c1"; "a1"; "a2"; "b2"; "a3" ] ~compare) - ~expect:[ [ "a1"; "a2"; "a3" ]; [ "b1"; "b2" ]; [ "c1" ] ] - ;; - end) -;; - -let%test_module "Assoc.group" = - (module struct - let%expect_test _ = - let test alist = - let multi = Assoc.group alist ~equal:String.Caseless.equal in - print_s [%sexp (multi : (string * int list) list)]; - let round_trip = - List.concat_map multi ~f:(fun (key, data) -> - List.map data ~f:(fun datum -> key, datum)) - in - require_equal - (module struct - type t = (String.Caseless.t * int) list [@@deriving equal, sexp_of] - end) - alist - round_trip - in - test []; - [%expect {| () |}]; - test [ "a", 1; "A", 2 ]; - [%expect {| ((a (1 2))) |}]; - test [ "a", 1; "b", 2 ]; - [%expect - {| - ((a (1)) - (b (2))) - |}]; - test [ "odd", 1; "even", 2; "Odd", 3; "Even", 4; "ODD", 5; "EVEN", 6 ]; - [%expect - {| - ((odd (1)) - (even (2)) - (Odd (3)) - (Even (4)) - (ODD (5)) - (EVEN (6))) - |}]; - test [ "odd", 1; "Odd", 3; "ODD", 5; "even", 2; "Even", 4; "EVEN", 6 ]; - [%expect - {| - ((odd (1 3 5)) - (even (2 4 6))) - |}] - ;; - end) -;; + let%test_unit _ = + [%test_result: char list list] + (groupi ~break:(fun i _ _ -> i % 3 = 0) mis) + ~expect:every_three + ;; +end -let%test_module "Assoc.sort_and_group" = - (module struct - let%expect_test _ = - let test alist = - let multi = Assoc.sort_and_group alist ~compare:String.Caseless.compare in - print_s [%sexp (multi : (string * int list) list)]; - require_equal - (module struct - type t = (string * int list) list [@@deriving equal, sexp_of] - end) - multi - (Map.to_alist (Map.of_alist_multi (module String.Caseless) alist)) +module%test [@name "sort_and_group"] _ = struct + let%expect_test _ = + let compare a b = + Comparable.lift String.compare ~f:(fun s -> String.rstrip ~drop:Char.is_digit s) a b + in + [%test_result: string list list] + (sort_and_group [ "b1"; "c1"; "a1"; "a2"; "b2"; "a3" ] ~compare) + ~expect:[ [ "a1"; "a2"; "a3" ]; [ "b1"; "b2" ]; [ "c1" ] ] + ;; +end + +module%test [@name "Assoc.group"] _ = struct + let%expect_test _ = + let test alist = + let multi = Assoc.group alist ~equal:String.Caseless.equal in + print_s [%sexp (multi : (string * int list) list)]; + let round_trip = + List.concat_map multi ~f:(fun (key, data) -> + List.map data ~f:(fun datum -> key, datum)) in - test []; - [%expect {| () |}]; - test [ "a", 1; "A", 2 ]; - [%expect {| ((a (1 2))) |}]; - test [ "a", 1; "b", 2 ]; - [%expect - {| - ((a (1)) - (b (2))) - |}]; - test [ "odd", 1; "even", 2; "Odd", 3; "Even", 4; "ODD", 5; "EVEN", 6 ]; - [%expect - {| - ((even (2 4 6)) - (odd (1 3 5))) - |}] - ;; - end) -;; - -let%test_module "chunks_of" = - (module struct - let test length break_every = - let l = List.init length ~f:Fn.id in - let b = chunks_of l ~length:break_every in - [%test_eq: int list] (List.concat b) l; - List.iter - b - ~f:([%test_pred: int list] (fun batch -> List.length batch <= break_every)) - ;; + require_equal + (module struct + type t = (String.Caseless.t * int) list [@@deriving equal, sexp_of] + end) + alist + round_trip + in + test []; + [%expect {| () |}]; + test [ "a", 1; "A", 2 ]; + [%expect {| ((a (1 2))) |}]; + test [ "a", 1; "b", 2 ]; + [%expect + {| + ((a (1)) + (b (2))) + |}]; + test [ "odd", 1; "even", 2; "Odd", 3; "Even", 4; "ODD", 5; "EVEN", 6 ]; + [%expect + {| + ((odd (1)) + (even (2)) + (Odd (3)) + (Even (4)) + (ODD (5)) + (EVEN (6))) + |}]; + test [ "odd", 1; "Odd", 3; "ODD", 5; "even", 2; "Even", 4; "EVEN", 6 ]; + [%expect + {| + ((odd (1 3 5)) + (even (2 4 6))) + |}] + ;; +end - let expect_exn length break_every = - match test length break_every with - | exception _ -> () - | () -> raise_s [%message "Didn't raise." (length : int) (break_every : int)] - ;; +module%test [@name "Assoc.sort_and_group"] _ = struct + let%expect_test _ = + let test alist = + let multi = Assoc.sort_and_group alist ~compare:String.Caseless.compare in + print_s [%sexp (multi : (string * int list) list)]; + require_equal + (module struct + type t = (string * int list) list [@@deriving equal, sexp_of] + end) + multi + (Map.to_alist (Map.of_alist_multi (module String.Caseless) alist)) + in + test []; + [%expect {| () |}]; + test [ "a", 1; "A", 2 ]; + [%expect {| ((a (1 2))) |}]; + test [ "a", 1; "b", 2 ]; + [%expect + {| + ((a (1)) + (b (2))) + |}]; + test [ "odd", 1; "even", 2; "Odd", 3; "Even", 4; "ODD", 5; "EVEN", 6 ]; + [%expect + {| + ((even (2 4 6)) + (odd (1 3 5))) + |}] + ;; +end - let%test_unit _ = - for n = 0 to 10 do - for k = n + 2 downto 1 do - test n k - done - done; - expect_exn 1 0; - expect_exn 1 (-1) - ;; +module%test [@name "chunks_of"] _ = struct + let test length break_every = + let l = List.init length ~f:Fn.id in + let b = chunks_of l ~length:break_every in + [%test_eq: int list] (List.concat b) l; + List.iter + b + ~f:([%test_pred: int list] (fun batch -> List.length batch <= break_every)) + ;; - let%test_unit _ = [%test_result: _ list list] (chunks_of [] ~length:1) ~expect:[] - end) -;; + let expect_exn length break_every = + match test length break_every with + | exception _ -> () + | () -> raise_s [%message "Didn't raise." (length : int) (break_every : int)] + ;; + + let%test_unit _ = + for n = 0 to 10 do + for k = n + 2 downto 1 do + test n k + done + done; + expect_exn 1 0; + expect_exn 1 (-1) + ;; + + let%test_unit _ = [%test_result: _ list list] (chunks_of [] ~length:1) ~expect:[] +end let%test _ = last_exn [ 1; 2; 3 ] = 3 let%test _ = last_exn [ 1 ] = 1 @@ -1065,35 +1047,33 @@ let%test_unit _ = [%test_result: int list] (drop [ 1; 2; 3; 4; 5; 6 ] (-5)) ~expect:[ 1; 2; 3; 4; 5; 6 ] ;; -let%test_module "{take,drop,split}_while" = - (module struct - let pred = function - | '0' .. '9' -> true - | _ -> false - ;; +module%test [@name "{take,drop,split}_while"] _ = struct + let pred = function + | '0' .. '9' -> true + | _ -> false + ;; - let test xs prefix suffix = - let prefix1, suffix1 = split_while ~f:pred xs in - let prefix2 = take_while xs ~f:pred in - let suffix2 = drop_while xs ~f:pred in - [%test_eq: char list] xs (prefix @ suffix); - [%test_result: char list] ~expect:prefix prefix1; - [%test_result: char list] ~expect:prefix prefix2; - [%test_result: char list] ~expect:suffix suffix1; - [%test_result: char list] ~expect:suffix suffix2 - ;; + let test xs prefix suffix = + let prefix1, suffix1 = split_while ~f:pred xs in + let prefix2 = take_while xs ~f:pred in + let suffix2 = drop_while xs ~f:pred in + [%test_eq: char list] xs (prefix @ suffix); + [%test_result: char list] ~expect:prefix prefix1; + [%test_result: char list] ~expect:prefix prefix2; + [%test_result: char list] ~expect:suffix suffix1; + [%test_result: char list] ~expect:suffix suffix2 + ;; - let%test_unit _ = - test [ '1'; '2'; '3'; 'a'; 'b'; 'c' ] [ '1'; '2'; '3' ] [ 'a'; 'b'; 'c' ] - ;; + let%test_unit _ = + test [ '1'; '2'; '3'; 'a'; 'b'; 'c' ] [ '1'; '2'; '3' ] [ 'a'; 'b'; 'c' ] + ;; - let%test_unit _ = test [ '1'; '2'; 'a'; 'b'; 'c' ] [ '1'; '2' ] [ 'a'; 'b'; 'c' ] - let%test_unit _ = test [ '1'; 'a'; 'b'; 'c' ] [ '1' ] [ 'a'; 'b'; 'c' ] - let%test_unit _ = test [ 'a'; 'b'; 'c' ] [] [ 'a'; 'b'; 'c' ] - let%test_unit _ = test [ '1'; '2'; '3' ] [ '1'; '2'; '3' ] [] - let%test_unit _ = test [] [] [] - end) -;; + let%test_unit _ = test [ '1'; '2'; 'a'; 'b'; 'c' ] [ '1'; '2' ] [ 'a'; 'b'; 'c' ] + let%test_unit _ = test [ '1'; 'a'; 'b'; 'c' ] [ '1' ] [ 'a'; 'b'; 'c' ] + let%test_unit _ = test [ 'a'; 'b'; 'c' ] [] [ 'a'; 'b'; 'c' ] + let%test_unit _ = test [ '1'; '2'; '3' ] [ '1'; '2'; '3' ] [] + let%test_unit _ = test [] [] [] +end let%test_unit _ = [%test_result: int list] (concat []) ~expect:[] let%test_unit _ = [%test_result: int list] (concat [ [] ]) ~expect:[] @@ -1142,69 +1122,67 @@ let%test_unit _ = let%test_unit _ = [%test_result: int option] (random_element []) ~expect:None let%test_unit _ = [%test_result: int option] (random_element [ 0 ]) ~expect:(Some 0) -let%test_module "transpose" = - (module struct - let round_trip a b = - [%test_result: int list list option] (transpose a) ~expect:(Some b); - [%test_result: int list list option] (transpose b) ~expect:(Some a) - ;; +module%test [@name "transpose"] _ = struct + let round_trip a b = + [%test_result: int list list option] (transpose a) ~expect:(Some b); + [%test_result: int list list option] (transpose b) ~expect:(Some a) + ;; - let%test_unit _ = round_trip [] [] + let%test_unit _ = round_trip [] [] - let%test_unit _ = - [%test_result: int list list option] (transpose [ [] ]) ~expect:(Some []) - ;; + let%test_unit _ = + [%test_result: int list list option] (transpose [ [] ]) ~expect:(Some []) + ;; - let%test_unit _ = - [%test_result: int list list option] (transpose [ []; [] ]) ~expect:(Some []) - ;; + let%test_unit _ = + [%test_result: int list list option] (transpose [ []; [] ]) ~expect:(Some []) + ;; - let%test_unit _ = - [%test_result: int list list option] (transpose [ []; []; [] ]) ~expect:(Some []) - ;; + let%test_unit _ = + [%test_result: int list list option] (transpose [ []; []; [] ]) ~expect:(Some []) + ;; - let%test_unit _ = round_trip [ [ 1 ] ] [ [ 1 ] ] - let%test_unit _ = round_trip [ [ 1 ]; [ 2 ] ] [ [ 1; 2 ] ] - let%test_unit _ = round_trip [ [ 1 ]; [ 2 ]; [ 3 ] ] [ [ 1; 2; 3 ] ] - let%test_unit _ = round_trip [ [ 1; 2 ]; [ 3; 4 ] ] [ [ 1; 3 ]; [ 2; 4 ] ] + let%test_unit _ = round_trip [ [ 1 ] ] [ [ 1 ] ] + let%test_unit _ = round_trip [ [ 1 ]; [ 2 ] ] [ [ 1; 2 ] ] + let%test_unit _ = round_trip [ [ 1 ]; [ 2 ]; [ 3 ] ] [ [ 1; 2; 3 ] ] + let%test_unit _ = round_trip [ [ 1; 2 ]; [ 3; 4 ] ] [ [ 1; 3 ]; [ 2; 4 ] ] - let%test_unit _ = - round_trip [ [ 1; 2; 3 ]; [ 4; 5; 6 ] ] [ [ 1; 4 ]; [ 2; 5 ]; [ 3; 6 ] ] - ;; + let%test_unit _ = + round_trip [ [ 1; 2; 3 ]; [ 4; 5; 6 ] ] [ [ 1; 4 ]; [ 2; 5 ]; [ 3; 6 ] ] + ;; - let%test_unit _ = - round_trip - [ [ 1; 2; 3 ]; [ 4; 5; 6 ]; [ 7; 8; 9 ] ] - [ [ 1; 4; 7 ]; [ 2; 5; 8 ]; [ 3; 6; 9 ] ] - ;; + let%test_unit _ = + round_trip + [ [ 1; 2; 3 ]; [ 4; 5; 6 ]; [ 7; 8; 9 ] ] + [ [ 1; 4; 7 ]; [ 2; 5; 8 ]; [ 3; 6; 9 ] ] + ;; - let%test_unit _ = - round_trip - [ [ 1; 2; 3; 4 ]; [ 5; 6; 7; 8 ]; [ 9; 10; 11; 12 ] ] - [ [ 1; 5; 9 ]; [ 2; 6; 10 ]; [ 3; 7; 11 ]; [ 4; 8; 12 ] ] - ;; + let%test_unit _ = + round_trip + [ [ 1; 2; 3; 4 ]; [ 5; 6; 7; 8 ]; [ 9; 10; 11; 12 ] ] + [ [ 1; 5; 9 ]; [ 2; 6; 10 ]; [ 3; 7; 11 ]; [ 4; 8; 12 ] ] + ;; - let%test_unit _ = - round_trip - [ [ 1; 2; 3; 4 ]; [ 5; 6; 7; 8 ]; [ 9; 10; 11; 12 ]; [ 13; 14; 15; 16 ] ] - [ [ 1; 5; 9; 13 ]; [ 2; 6; 10; 14 ]; [ 3; 7; 11; 15 ]; [ 4; 8; 12; 16 ] ] - ;; + let%test_unit _ = + round_trip + [ [ 1; 2; 3; 4 ]; [ 5; 6; 7; 8 ]; [ 9; 10; 11; 12 ]; [ 13; 14; 15; 16 ] ] + [ [ 1; 5; 9; 13 ]; [ 2; 6; 10; 14 ]; [ 3; 7; 11; 15 ]; [ 4; 8; 12; 16 ] ] + ;; - let%test_unit _ = - round_trip - [ [ 1; 2; 3 ]; [ 4; 5; 6 ]; [ 7; 8; 9 ]; [ 10; 11; 12 ] ] - [ [ 1; 4; 7; 10 ]; [ 2; 5; 8; 11 ]; [ 3; 6; 9; 12 ] ] - ;; + let%test_unit _ = + round_trip + [ [ 1; 2; 3 ]; [ 4; 5; 6 ]; [ 7; 8; 9 ]; [ 10; 11; 12 ] ] + [ [ 1; 4; 7; 10 ]; [ 2; 5; 8; 11 ]; [ 3; 6; 9; 12 ] ] + ;; - let%test_unit _ = - [%test_result: int list list option] (transpose [ []; [ 1 ] ]) ~expect:None - ;; + let%test_unit _ = + [%test_result: int list list option] (transpose [ []; [ 1 ] ]) ~expect:None + ;; - let%test_unit _ = - [%test_result: int list list option] (transpose [ [ 1; 2 ]; [ 3 ] ]) ~expect:None - ;; - end) -;; + let%test_unit _ = + [%test_result: int list list option] (transpose [ [ 1; 2 ]; [ 3 ] ]) ~expect:None + ;; +end let%test_unit _ = [%test_result: int list] (intersperse [ 1; 2; 3 ] ~sep:0) ~expect:[ 1; 0; 2; 0; 3 ] @@ -1267,6 +1245,37 @@ let%test_unit _ = ~expect:(0, []) ;; +let test_partition_mapi list ~f ~expect = + [%test_result: int list * int list] (partition_mapi list ~f) ~expect +;; + +let%test_unit _ = + test_partition_mapi + [] + ~f:(fun i x -> if i = x then First (i + x) else Second (i - x)) + ~expect:([], []) +;; + +let%test_unit _ = + test_partition_mapi + [ 3; 5; 2; 1; 4 ] + ~f:(fun i x -> if i = x then First (i + x) else Second (i - x)) + ~expect:([ 4; 8 ], [ -3; -4; 2 ]) +;; + +let test_partitioni_tf list ~f ~expect = + [%test_result: int list * int list] (partitioni_tf list ~f) ~expect +;; + +let%test_unit _ = test_partitioni_tf [] ~f:(fun i x -> i = x && x > 2) ~expect:([], []) + +let%test_unit _ = + test_partitioni_tf + [ 3; 5; 2; 1; 4 ] + ~f:(fun i x -> i = x && x > 2) + ~expect:([ 4 ], [ 3; 5; 2; 1 ]) +;; + let%expect_test "drop_last" = let print_drop_last x = print_s [%sexp (List.drop_last x : int list option)] in print_drop_last []; @@ -1590,173 +1599,165 @@ let%expect_test "[concat_mapi]" = [%expect {| (0 1 2 3 1 2 3 4 5 2 3 4 5 6 7) |}] ;; -let%test_module "filter{,i}" = - (module struct - open Base_quickcheck +module%test [@name "filter{,i}"] _ = struct + open Base_quickcheck - module Int_list = struct - type t = int list [@@deriving equal, sexp_of] - end + module Int_list = struct + type t = int list [@@deriving equal, sexp_of] + end - let%expect_test "[filter]" = - quickcheck_m - (module struct - type t = int list * (int -> bool) [@@deriving quickcheck, sexp_of] - end) - ~f:(fun (list, f) -> + let%expect_test "[filter]" = + quickcheck_m + (module struct + type t = int list * (int -> bool) [@@deriving quickcheck, sexp_of] + end) + ~f:(fun (list, f) -> + (* test [f] *) + let pos = List.filter list ~f in + require (List.for_all pos ~f); + (* test [~f] *) + let not_f = Fn.non f in + let neg = List.filter list ~f:not_f in + require (List.for_all neg ~f:not_f); + (* test [f \/ ~f] *) + let sort = sort ~compare:Int.compare in + require_equal (module Int_list) (sort list) (sort (pos @ neg))) + ;; + + let%expect_test "[filteri]" = + quickcheck_m + (module struct + type t = int list * (int -> int -> bool) [@@deriving quickcheck, sexp_of] + end) + ~f:(fun (list, f) -> + let pos, neg = + (* stash the original indices, so that we can retrieve them after filtering *) + let list = mapi list ~f:(fun i x -> i, x) in + let ignore_stash f : _ = fun i (_, x) -> f i x in + let use_orig_index f : _ = fun (i, x) -> f i x in (* test [f] *) - let pos = List.filter list ~f in - require (List.for_all pos ~f); + let pos = List.filteri list ~f:(ignore_stash f) in + require (List.for_all pos ~f:(use_orig_index f)); (* test [~f] *) - let not_f = Fn.non f in - let neg = List.filter list ~f:not_f in - require (List.for_all neg ~f:not_f); - (* test [f \/ ~f] *) - let sort = sort ~compare:Int.compare in - require_equal (module Int_list) (sort list) (sort (pos @ neg))) - ;; - - let%expect_test "[filteri]" = - quickcheck_m - (module struct - type t = int list * (int -> int -> bool) [@@deriving quickcheck, sexp_of] - end) - ~f:(fun (list, f) -> - let pos, neg = - (* stash the original indices, so that we can retrieve them after filtering *) - let list = mapi list ~f:(fun i x -> i, x) in - let ignore_stash f : _ = fun i (_, x) -> f i x in - let use_orig_index f : _ = fun (i, x) -> f i x in - (* test [f] *) - let pos = List.filteri list ~f:(ignore_stash f) in - require (List.for_all pos ~f:(use_orig_index f)); - (* test [~f] *) - let not_f i x = not (f i x) in - let neg = List.filteri list ~f:(ignore_stash not_f) in - require (List.for_all neg ~f:(use_orig_index not_f)); - pos, neg - in - (* test [f \/ ~f] *) - let sort = sort ~compare:[%compare: int * _] in - require_equal (module Int_list) list (sort (pos @ neg) |> map ~f:snd)) - ;; + let not_f i x = not (f i x) in + let neg = List.filteri list ~f:(ignore_stash not_f) in + require (List.for_all neg ~f:(use_orig_index not_f)); + pos, neg + in + (* test [f \/ ~f] *) + let sort = sort ~compare:[%compare: int * _] in + require_equal (module Int_list) list (sort (pos @ neg) |> map ~f:snd)) + ;; - let%expect_test "[filteri ~f:(Fn.const f) = filter ~f]" = - quickcheck_m - (module struct - type t = int list * (int -> bool) [@@deriving quickcheck, sexp_of] - end) - ~f:(fun (list, f) -> - require_equal - (module Int_list) - (filteri list ~f:(fun _ x -> f x)) - (filter list ~f)) - ;; + let%expect_test "[filteri ~f:(Fn.const f) = filter ~f]" = + quickcheck_m + (module struct + type t = int list * (int -> bool) [@@deriving quickcheck, sexp_of] + end) + ~f:(fun (list, f) -> + require_equal + (module Int_list) + (filteri list ~f:(fun _ x -> f x)) + (filter list ~f)) + ;; - let%expect_test "[filter]" = - let test list = - List.filter list ~f:(fun n -> n % 3 > 0) |> [%sexp_of: int list] |> print_s - in - test []; - [%expect {| () |}]; - test [ 1 ]; - [%expect {| (1) |}]; - test [ 1; 2 ]; - [%expect {| (1 2) |}]; - test [ 1; 2; 3 ]; - [%expect {| (1 2) |}]; - test [ 1; 2; 3; 4 ]; - [%expect {| (1 2 4) |}]; - test [ 4; 5; 6 ]; - [%expect {| (4 5) |}] - ;; + let%expect_test "[filter]" = + let test list = + List.filter list ~f:(fun n -> n % 3 > 0) |> [%sexp_of: int list] |> print_s + in + test []; + [%expect {| () |}]; + test [ 1 ]; + [%expect {| (1) |}]; + test [ 1; 2 ]; + [%expect {| (1 2) |}]; + test [ 1; 2; 3 ]; + [%expect {| (1 2) |}]; + test [ 1; 2; 3; 4 ]; + [%expect {| (1 2 4) |}]; + test [ 4; 5; 6 ]; + [%expect {| (4 5) |}] + ;; - let%expect_test "[filteri]" = - let test list = - List.filteri list ~f:(fun i n -> n > i) |> [%sexp_of: int list] |> print_s - in - test []; - [%expect {| () |}]; - test [ 0 ]; - [%expect {| () |}]; - test [ 0; 1 ]; - [%expect {| () |}]; - test [ 0; 1; 2 ]; - [%expect {| () |}]; - test [ 1 ]; - [%expect {| (1) |}]; - test [ 1; 2 ]; - [%expect {| (1 2) |}]; - test [ 1; 2; 3 ]; - [%expect {| (1 2 3) |}]; - test [ 1; 0 ]; - [%expect {| (1) |}]; - test [ 2; 1; 0 ]; - [%expect {| (2) |}]; - test [ 3; 2; 1; 0 ]; - [%expect {| (3 2) |}] - ;; - end) -;; + let%expect_test "[filteri]" = + let test list = + List.filteri list ~f:(fun i n -> n > i) |> [%sexp_of: int list] |> print_s + in + test []; + [%expect {| () |}]; + test [ 0 ]; + [%expect {| () |}]; + test [ 0; 1 ]; + [%expect {| () |}]; + test [ 0; 1; 2 ]; + [%expect {| () |}]; + test [ 1 ]; + [%expect {| (1) |}]; + test [ 1; 2 ]; + [%expect {| (1 2) |}]; + test [ 1; 2; 3 ]; + [%expect {| (1 2 3) |}]; + test [ 1; 0 ]; + [%expect {| (1) |}]; + test [ 2; 1; 0 ]; + [%expect {| (2) |}]; + test [ 3; 2; 1; 0 ]; + [%expect {| (3 2) |}] + ;; +end -let%test_module "count{,i}" = - (module struct - let%expect_test "[count{,i} list ~f = List.length (filter{,i} list ~f)]" = - quickcheck_m - (module struct - type t = int list * (int -> bool) [@@deriving quickcheck, sexp_of] - end) - ~f:(fun (list, f) -> - require_equal (module Int) (count list ~f) (length (filter list ~f))); - quickcheck_m - (module struct - type t = int list * (int -> int -> bool) [@@deriving quickcheck, sexp_of] - end) - ~f:(fun (list, f) -> - require_equal (module Int) (counti list ~f) (length (filteri list ~f))) - ;; +module%test [@name "count{,i}"] _ = struct + let%expect_test "[count{,i} list ~f = List.length (filter{,i} list ~f)]" = + quickcheck_m + (module struct + type t = int list * (int -> bool) [@@deriving quickcheck, sexp_of] + end) + ~f:(fun (list, f) -> + require_equal (module Int) (count list ~f) (length (filter list ~f))); + quickcheck_m + (module struct + type t = int list * (int -> int -> bool) [@@deriving quickcheck, sexp_of] + end) + ~f:(fun (list, f) -> + require_equal (module Int) (counti list ~f) (length (filteri list ~f))) + ;; - let%test_unit _ = - [%test_result: int] (counti [ 0; 1; 2; 3; 4 ] ~f:(fun idx x -> idx = x)) ~expect:5 - ;; + let%test_unit _ = + [%test_result: int] (counti [ 0; 1; 2; 3; 4 ] ~f:(fun idx x -> idx = x)) ~expect:5 + ;; - let%test_unit _ = - [%test_result: int] - (counti [ 0; 1; 2; 3; 4 ] ~f:(fun idx x -> idx = 4 - x)) - ~expect:1 - ;; - end) -;; + let%test_unit _ = + [%test_result: int] (counti [ 0; 1; 2; 3; 4 ] ~f:(fun idx x -> idx = 4 - x)) ~expect:1 + ;; +end -let%test_module "{min,max}_elt" = - (module struct - let test_in_list_and_forall ~tested_f ~holds_for_res_over_all_elem = - quickcheck_m - (module struct - type t = int list [@@deriving quickcheck, sexp_of] - end) - ~f:(fun list -> - let res = tested_f list ~compare:[%compare: int] in - match res with - | None -> require (is_empty list) - | Some res -> - require (mem list res ~equal:Int.equal); - iter list ~f:(fun elem -> require (holds_for_res_over_all_elem ~res ~elem))) - ;; +module%test [@name "{min,max}_elt"] _ = struct + let test_in_list_and_forall ~tested_f ~holds_for_res_over_all_elem = + quickcheck_m + (module struct + type t = int list [@@deriving quickcheck, sexp_of] + end) + ~f:(fun list -> + let res = tested_f list ~compare:[%compare: int] in + match res with + | None -> require (is_empty list) + | Some res -> + require (mem list res ~equal:Int.equal); + iter list ~f:(fun elem -> require (holds_for_res_over_all_elem ~res ~elem))) + ;; - let%expect_test "min_elt" = - test_in_list_and_forall - ~tested_f:min_elt - ~holds_for_res_over_all_elem:(fun ~res ~elem -> res <= elem) - ;; + let%expect_test "min_elt" = + test_in_list_and_forall + ~tested_f:min_elt + ~holds_for_res_over_all_elem:(fun ~res ~elem -> res <= elem) + ;; - let%expect_test "max_elt" = - test_in_list_and_forall - ~tested_f:max_elt - ~holds_for_res_over_all_elem:(fun ~res ~elem -> res >= elem) - ;; - end) -;; + let%expect_test "max_elt" = + test_in_list_and_forall + ~tested_f:max_elt + ~holds_for_res_over_all_elem:(fun ~res ~elem -> res >= elem) + ;; +end let%expect_test "[map2]" = let test xs ys = diff --git a/test/test_map.ml b/test/test_map.ml index a97fbca..ce01ccb 100644 --- a/test/test_map.ml +++ b/test/test_map.ml @@ -158,238 +158,232 @@ let%expect_test "combine_errors" = |}] ;; -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 +module%test Poly = 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 + +module%test [@name "[symmetric_diff]"] _ = 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%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 quickcheck_observer = Observer.map_t Observer.string Observer.int + let quickcheck_shrinker = Shrinker.map_t Shrinker.string Shrinker.int + 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)))) |}] - ;; + 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 + ;; - module String_to_int_map = struct - type t = int Map.M(String).t [@@deriving equal, sexp_of] + 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 + ;; - open Base_quickcheck + (* 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 + type t = int [@@deriving sexp_of] - let quickcheck_generator = - Generator.map_t_m (module String) Generator.string Generator.int + let compare x y = + Int.incr count; + compare_int x y ;; - let quickcheck_observer = Observer.map_t Observer.string Observer.int - let quickcheck_shrinker = Shrinker.map_t Shrinker.string Shrinker.int + include (val Comparator.make ~compare ~sexp_of_t) 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 - type t = int [@@deriving sexp_of] - - let compare x y = - Int.incr count; - compare_int x y - ;; - - include (val Comparator.make ~compare ~sexp_of_t) - end - in - let test size = - let map_pairs = - (* We measure every step of building up a map from one side. This covers + in + let test size = + let map_pairs = + (* We measure every step of building up a map from one side. This covers different stages of rebalancing along the way. *) - List.folding_map - (List.init size ~f:Int.succ) - ~init:(Map.singleton (module Key) 0 0) - ~f:(fun a i -> - let b = Map.add_exn a ~key:i ~data:i in - b, (a, b)) - in - let add_comparisons = !count in - count := 0; - let comparisons = - List.map map_pairs ~f:(fun (a, b) -> - measure_comparisons (fun () -> - Map.fold_symmetric_diff a b ~init:() ~f:(fun () _ -> ()) ~data_equal:( = ))) - |> List.sort ~compare:Int.compare - in - let len = List.length comparisons in - let diff_comparisons = List.sum (module Int) comparisons ~f:Fn.id in - let mean_diff_comparisons = Float.of_int diff_comparisons /. Float.of_int len in - let median_diff_comparisons = List.nth_exn comparisons (len / 2) in - let diff_comparison_buckets = - List.sort_and_group comparisons ~compare:Int.compare - |> List.map ~f:(fun list -> - [%sexp - { comparisons = (List.hd_exn list : int); times = (List.length list : int) }]) - in - print_s - [%message - "" - (size : int) - (add_comparisons : int) - (diff_comparisons : int) - (mean_diff_comparisons : float) - (median_diff_comparisons : int) - (diff_comparison_buckets : Sexp.t list)] + List.folding_map + (List.init size ~f:Int.succ) + ~init:(Map.singleton (module Key) 0 0) + ~f:(fun a i -> + let b = Map.add_exn a ~key:i ~data:i in + b, (a, b)) in - test (1 lsl 20); - [%expect - {| - ((size 1_048_576) - (add_comparisons 20_971_521) - (diff_comparisons 22_020_076) - (mean_diff_comparisons 20.999980926513672) - (median_diff_comparisons 21) - (diff_comparison_buckets ( - ((comparisons 1) (times 1)) - ((comparisons 2) (times 1)) - ((comparisons 3) (times 1)) - ((comparisons 4) (times 2)) - ((comparisons 5) (times 4)) - ((comparisons 6) (times 8)) - ((comparisons 7) (times 16)) - ((comparisons 8) (times 32)) - ((comparisons 9) (times 64)) - ((comparisons 10) (times 128)) - ((comparisons 11) (times 256)) - ((comparisons 12) (times 512)) - ((comparisons 13) (times 1_024)) - ((comparisons 14) (times 2_048)) - ((comparisons 15) (times 4_096)) - ((comparisons 16) (times 8_192)) - ((comparisons 17) (times 16_384)) - ((comparisons 18) (times 32_768)) - ((comparisons 19) (times 65_536)) - ((comparisons 20) (times 131_072)) - ((comparisons 21) (times 262_144)) - ((comparisons 22) (times 524_287))))) - |}] - ;; - - 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 - (module String_to_int_map) - (Sequence.fold diff ~init:map1 ~f:apply_diff_left_to_right) - map2; - require_equal - (module String_to_int_map) - map1 - (Sequence.fold diff ~init:map2 ~f:apply_diff_right_to_left) + let add_comparisons = !count in + count := 0; + let comparisons = + List.map map_pairs ~f:(fun (a, b) -> + measure_comparisons (fun () -> + Map.fold_symmetric_diff a b ~init:() ~f:(fun () _ -> ()) ~data_equal:( = ))) + |> List.sort ~compare:Int.compare 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 - (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)) + let len = List.length comparisons in + let diff_comparisons = List.sum (module Int) comparisons ~f:Fn.id in + let mean_diff_comparisons = Float.of_int diff_comparisons /. Float.of_int len in + let median_diff_comparisons = List.nth_exn comparisons (len / 2) in + let diff_comparison_buckets = + List.sort_and_group comparisons ~compare:Int.compare + |> List.map ~f:(fun list -> + [%sexp + { comparisons = (List.hd_exn list : int); times = (List.length list : int) }]) in - Base_quickcheck.Test.run_exn - ~f:test + print_s + [%message + "" + (size : int) + (add_comparisons : int) + (diff_comparisons : int) + (mean_diff_comparisons : float) + (median_diff_comparisons : int) + (diff_comparison_buckets : Sexp.t list)] + in + test (1 lsl 20); + [%expect + {| + ((size 1_048_576) + (add_comparisons 20_971_521) + (diff_comparisons 22_020_076) + (mean_diff_comparisons 20.999980926513672) + (median_diff_comparisons 21) + (diff_comparison_buckets ( + ((comparisons 1) (times 1)) + ((comparisons 2) (times 1)) + ((comparisons 3) (times 1)) + ((comparisons 4) (times 2)) + ((comparisons 5) (times 4)) + ((comparisons 6) (times 8)) + ((comparisons 7) (times 16)) + ((comparisons 8) (times 32)) + ((comparisons 9) (times 64)) + ((comparisons 10) (times 128)) + ((comparisons 11) (times 256)) + ((comparisons 12) (times 512)) + ((comparisons 13) (times 1_024)) + ((comparisons 14) (times 2_048)) + ((comparisons 15) (times 4_096)) + ((comparisons 16) (times 8_192)) + ((comparisons 17) (times 16_384)) + ((comparisons 18) (times 32_768)) + ((comparisons 19) (times 65_536)) + ((comparisons 20) (times 131_072)) + ((comparisons 21) (times 262_144)) + ((comparisons 22) (times 524_287))))) + |}] + ;; + + 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 + (module String_to_int_map) + (Sequence.fold diff ~init:map1 ~f:apply_diff_left_to_right) + map2; + require_equal + (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 (module struct - type t = String_to_int_map.t * String_to_int_map.t - [@@deriving quickcheck, sexp_of] + type t = (string, int) Symmetric_diff_element.t list + [@@deriving compare, 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) + (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 + +module%test [@name "of_alist_multi key equality"] _ = struct + module Key = struct + module T = struct + type t = string * int [@@deriving sexp_of] + + let compare = [%compare: string * _] end - let alist = [ ("a", 1), 1; ("a", 2), 3; ("b", 0), 0; ("a", 3), 2 ] + include T + include Comparator.Make (T) + end - 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 alist = [ ("a", 1), 1; ("a", 2), 3; ("b", 0), 0; ("a", 3), 2 ] - 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 "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 diff --git a/test/test_maybe_bound.ml b/test/test_maybe_bound.ml index 531ea9a..b56e334 100644 --- a/test/test_maybe_bound.ml +++ b/test/test_maybe_bound.ml @@ -27,97 +27,91 @@ let%test_unit "bounds_crossed" = assert ([%compare.equal: bool] expect actual)) ;; -let%test_module "is_lower_bound" = - (module struct - let compare = Int.compare - let%test _ = is_lower_bound Unbounded ~of_:Int.min_value ~compare - let%test _ = not (is_lower_bound (Incl 2) ~of_:1 ~compare) - let%test _ = is_lower_bound (Incl 2) ~of_:2 ~compare - let%test _ = is_lower_bound (Incl 2) ~of_:3 ~compare - let%test _ = not (is_lower_bound (Excl 2) ~of_:1 ~compare) - let%test _ = not (is_lower_bound (Excl 2) ~of_:2 ~compare) - let%test _ = is_lower_bound (Excl 2) ~of_:3 ~compare - end) -;; +module%test [@name "is_lower_bound"] _ = struct + let compare = Int.compare + let%test _ = is_lower_bound Unbounded ~of_:Int.min_value ~compare + let%test _ = not (is_lower_bound (Incl 2) ~of_:1 ~compare) + let%test _ = is_lower_bound (Incl 2) ~of_:2 ~compare + let%test _ = is_lower_bound (Incl 2) ~of_:3 ~compare + let%test _ = not (is_lower_bound (Excl 2) ~of_:1 ~compare) + let%test _ = not (is_lower_bound (Excl 2) ~of_:2 ~compare) + let%test _ = is_lower_bound (Excl 2) ~of_:3 ~compare +end -let%test_module "is_upper_bound" = - (module struct - let compare = Int.compare - let%test _ = is_upper_bound Unbounded ~of_:Int.max_value ~compare - let%test _ = is_upper_bound (Incl 2) ~of_:1 ~compare - let%test _ = is_upper_bound (Incl 2) ~of_:2 ~compare - let%test _ = not (is_upper_bound (Incl 2) ~of_:3 ~compare) - let%test _ = is_upper_bound (Excl 2) ~of_:1 ~compare - let%test _ = not (is_upper_bound (Excl 2) ~of_:2 ~compare) - let%test _ = not (is_upper_bound (Excl 2) ~of_:3 ~compare) - end) -;; +module%test [@name "is_upper_bound"] _ = struct + let compare = Int.compare + let%test _ = is_upper_bound Unbounded ~of_:Int.max_value ~compare + let%test _ = is_upper_bound (Incl 2) ~of_:1 ~compare + let%test _ = is_upper_bound (Incl 2) ~of_:2 ~compare + let%test _ = not (is_upper_bound (Incl 2) ~of_:3 ~compare) + let%test _ = is_upper_bound (Excl 2) ~of_:1 ~compare + let%test _ = not (is_upper_bound (Excl 2) ~of_:2 ~compare) + let%test _ = not (is_upper_bound (Excl 2) ~of_:3 ~compare) +end -let%test_module "check_range" = - (module struct - let compare = Int.compare +module%test [@name "check_range"] _ = struct + let compare = Int.compare - let tests (lower, upper) cases = - List.iter cases ~f:(fun (n, comparison) -> - [%test_result: interval_comparison] - ~expect:comparison - (compare_to_interval_exn n ~lower ~upper ~compare); - [%test_result: bool] - ~expect: - (match comparison with - | In_range -> true - | _ -> false) - (interval_contains_exn n ~lower ~upper ~compare)) - ;; + let tests (lower, upper) cases = + List.iter cases ~f:(fun (n, comparison) -> + [%test_result: interval_comparison] + ~expect:comparison + (compare_to_interval_exn n ~lower ~upper ~compare); + [%test_result: bool] + ~expect: + (match comparison with + | In_range -> true + | _ -> false) + (interval_contains_exn n ~lower ~upper ~compare)) + ;; - let%test_unit _ = - tests - (Unbounded, Unbounded) - [ Int.min_value, In_range; 0, In_range; Int.max_value, In_range ] - ;; + let%test_unit _ = + tests + (Unbounded, Unbounded) + [ Int.min_value, In_range; 0, In_range; Int.max_value, In_range ] + ;; - let%test_unit _ = - tests - (Incl 2, Incl 4) - [ 1, Below_lower_bound - ; 2, In_range - ; 3, In_range - ; 4, In_range - ; 5, Above_upper_bound - ] - ;; + let%test_unit _ = + tests + (Incl 2, Incl 4) + [ 1, Below_lower_bound + ; 2, In_range + ; 3, In_range + ; 4, In_range + ; 5, Above_upper_bound + ] + ;; - let%test_unit _ = - tests - (Incl 2, Excl 4) - [ 1, Below_lower_bound - ; 2, In_range - ; 3, In_range - ; 4, Above_upper_bound - ; 5, Above_upper_bound - ] - ;; + let%test_unit _ = + tests + (Incl 2, Excl 4) + [ 1, Below_lower_bound + ; 2, In_range + ; 3, In_range + ; 4, Above_upper_bound + ; 5, Above_upper_bound + ] + ;; - let%test_unit _ = - tests - (Excl 2, Incl 4) - [ 1, Below_lower_bound - ; 2, Below_lower_bound - ; 3, In_range - ; 4, In_range - ; 5, Above_upper_bound - ] - ;; + let%test_unit _ = + tests + (Excl 2, Incl 4) + [ 1, Below_lower_bound + ; 2, Below_lower_bound + ; 3, In_range + ; 4, In_range + ; 5, Above_upper_bound + ] + ;; - let%test_unit _ = - tests - (Excl 2, Excl 4) - [ 1, Below_lower_bound - ; 2, Below_lower_bound - ; 3, In_range - ; 4, Above_upper_bound - ; 5, Above_upper_bound - ] - ;; - end) -;; + let%test_unit _ = + tests + (Excl 2, Excl 4) + [ 1, Below_lower_bound + ; 2, Below_lower_bound + ; 3, In_range + ; 4, Above_upper_bound + ; 5, Above_upper_bound + ] + ;; +end diff --git a/test/test_nativeint_pow2.ml b/test/test_nativeint_pow2.ml index b9641e2..3ae538d 100644 --- a/test/test_nativeint_pow2.ml +++ b/test/test_nativeint_pow2.ml @@ -77,43 +77,41 @@ let%expect_test ("[ceil_log2]" [@tags "64-bits-only"]) = |}] ;; -let%test_module "nativeint_math" = - (module struct - let test_cases () = +module%test [@name "nativeint_math"] _ = struct + let test_cases () = + let cases = + [ 0b10101010n + ; 0b1010101010101010n + ; 0b101010101010101010101010n + ; 0b10000000n + ; 0b1000000000001000n + ; 0b100000000000000000001000n + ] + in + match Word_size.word_size with + | W64 -> + (* create some >32 bit values... *) + (* We can't use literals directly because the compiler complains on 32 bits. *) let cases = - [ 0b10101010n - ; 0b1010101010101010n - ; 0b101010101010101010101010n - ; 0b10000000n - ; 0b1000000000001000n - ; 0b100000000000000000001000n - ] + cases + @ [ (0b1010101010101010n lsl 16) lor 0b1010101010101010n + ; (0b1000000000000000n lsl 16) lor 0b0000000000001000n + ] in - match Word_size.word_size with - | W64 -> - (* create some >32 bit values... *) - (* We can't use literals directly because the compiler complains on 32 bits. *) - let cases = - cases - @ [ (0b1010101010101010n lsl 16) lor 0b1010101010101010n - ; (0b1000000000000000n lsl 16) lor 0b0000000000001000n - ] - in - let added_cases = List.map cases ~f:(fun x -> x lsl 16) in - List.concat [ cases; added_cases ] - | W32 -> cases - ;; + let added_cases = List.map cases ~f:(fun x -> x lsl 16) in + List.concat [ cases; added_cases ] + | W32 -> cases + ;; - let%test_unit "ceil_pow2" = - List.iter (test_cases ()) ~f:(fun x -> - let p2 = ceil_pow2 x in - assert (is_pow2 p2 && p2 >= x && x >= p2 / of_int 2)) - ;; + let%test_unit "ceil_pow2" = + List.iter (test_cases ()) ~f:(fun x -> + let p2 = ceil_pow2 x in + assert (is_pow2 p2 && p2 >= x && x >= p2 / of_int 2)) + ;; - let%test_unit "floor_pow2" = - List.iter (test_cases ()) ~f:(fun x -> - let p2 = floor_pow2 x in - assert (is_pow2 p2 && of_int 2 * p2 >= x && x >= p2)) - ;; - end) -;; + let%test_unit "floor_pow2" = + List.iter (test_cases ()) ~f:(fun x -> + let p2 = floor_pow2 x in + assert (is_pow2 p2 && of_int 2 * p2 >= x && x >= p2)) + ;; +end diff --git a/test/test_obj_array.ml b/test/test_obj_array.ml index 86a6cee..dd108be 100644 --- a/test/test_obj_array.ml +++ b/test/test_obj_array.ml @@ -2,79 +2,75 @@ open! Import module Obj_array = Base.Exported_for_specific_uses.Obj_array (* Invariant tests *) -let%test_module (_ [@tags "no-js"]) = - (module ( - struct - type t = Obj_array.t +module%test [@tags "no-js"] _ : module type of struct + include Obj_array +end = struct + type t = Obj_array.t - let invariant = Obj_array.invariant + let invariant = Obj_array.invariant - (* We test that constructors satisfy the invariant, especially when given floats. *) + (* We test that constructors satisfy the invariant, especially when given floats. *) - open struct - let test - ?cr - ?(allow_nonfloat = false) - ?(allow_empty = false) - ?(here = Stdlib.Lexing.dummy_pos) - t - = - (* assertions for calling convention ... *) - if not allow_empty then assert (Obj_array.length t > 0); - if not allow_nonfloat - then - for pos = 0 to Obj_array.length t - 1 do - assert (Stdlib.Obj.tag (Obj_array.get t pos) = Stdlib.Obj.double_tag) - done; - (* ... [require]* for test itself *) - require_does_not_raise ~here ?cr (fun () -> Obj_array.invariant t) - ;; + open struct + let test + ?cr + ?(allow_nonfloat = false) + ?(allow_empty = false) + ?(here = Stdlib.Lexing.dummy_pos) + t + = + (* assertions for calling convention ... *) + if not allow_empty then assert (Obj_array.length t > 0); + if not allow_nonfloat + then + for pos = 0 to Obj_array.length t - 1 do + assert (Stdlib.Obj.tag (Obj_array.get t pos) = Stdlib.Obj.double_tag) + done; + (* ... [require]* for test itself *) + require_does_not_raise ~here ?cr (fun () -> Obj_array.invariant t) + ;; - let obj (float : float) = Stdlib.Obj.repr float - end + let obj (float : float) = Stdlib.Obj.repr float + end - (* creators *) + (* creators *) - let empty = Obj_array.empty - let%expect_test _ = test Obj_array.empty ~allow_empty:true - let singleton = Obj_array.singleton - let%expect_test _ = test (Obj_array.singleton (obj 0.)) - let create_zero = Obj_array.create_zero - let%expect_test _ = test (Obj_array.create_zero ~len:1) ~allow_nonfloat:true - let create = Obj_array.create - let%expect_test _ = test (Obj_array.create (obj 0.) ~len:1) - let copy = Obj_array.copy - let%expect_test _ = test (Obj_array.copy (Obj_array.singleton (obj 0.))) - let sub = Obj_array.sub - let%expect_test _ = test (Obj_array.sub (Obj_array.singleton (obj 0.)) ~pos:0 ~len:1) - let subo = Obj_array.subo - let%expect_test _ = test (Obj_array.subo (Obj_array.singleton (obj 0.))) + let empty = Obj_array.empty + let%expect_test _ = test Obj_array.empty ~allow_empty:true + let singleton = Obj_array.singleton + let%expect_test _ = test (Obj_array.singleton (obj 0.)) + let create_zero = Obj_array.create_zero + let%expect_test _ = test (Obj_array.create_zero ~len:1) ~allow_nonfloat:true + let create = Obj_array.create + let%expect_test _ = test (Obj_array.create (obj 0.) ~len:1) + let copy = Obj_array.copy + let%expect_test _ = test (Obj_array.copy (Obj_array.singleton (obj 0.))) + let sub = Obj_array.sub + let%expect_test _ = test (Obj_array.sub (Obj_array.singleton (obj 0.)) ~pos:0 ~len:1) + let subo = Obj_array.subo + let%expect_test _ = test (Obj_array.subo (Obj_array.singleton (obj 0.))) - (* accessors *) + (* accessors *) - let sexp_of_t = Obj_array.sexp_of_t - let blit = Obj_array.blit - let blito = Obj_array.blito - let unsafe_blit = Obj_array.unsafe_blit - let length = Obj_array.length - let get = Obj_array.get - let unsafe_get = Obj_array.unsafe_get - let set = Obj_array.set - let unsafe_set = Obj_array.unsafe_set - let swap = Obj_array.swap - let set_with_caml_modify = Obj_array.set_with_caml_modify - let unsafe_set_assuming_currently_int = Obj_array.unsafe_set_assuming_currently_int + let sexp_of_t = Obj_array.sexp_of_t + let blit = Obj_array.blit + let blito = Obj_array.blito + let unsafe_blit = Obj_array.unsafe_blit + let length = Obj_array.length + let get = Obj_array.get + let unsafe_get = Obj_array.unsafe_get + let set = Obj_array.set + let unsafe_set = Obj_array.unsafe_set + let swap = Obj_array.swap + let set_with_caml_modify = Obj_array.set_with_caml_modify + let unsafe_set_assuming_currently_int = Obj_array.unsafe_set_assuming_currently_int - let unsafe_set_int_assuming_currently_int = - Obj_array.unsafe_set_int_assuming_currently_int - ;; + let unsafe_set_int_assuming_currently_int = + Obj_array.unsafe_set_int_assuming_currently_int + ;; - let unsafe_set_int = Obj_array.unsafe_set_int - let unsafe_set_omit_phys_equal_check = Obj_array.unsafe_set_omit_phys_equal_check - let unsafe_set_with_caml_modify = Obj_array.unsafe_set_with_caml_modify - let unsafe_clear_if_pointer = Obj_array.unsafe_clear_if_pointer - end : - module type of struct - include Obj_array - end)) -;; + let unsafe_set_int = Obj_array.unsafe_set_int + let unsafe_set_omit_phys_equal_check = Obj_array.unsafe_set_omit_phys_equal_check + let unsafe_set_with_caml_modify = Obj_array.unsafe_set_with_caml_modify + let unsafe_clear_if_pointer = Obj_array.unsafe_clear_if_pointer +end diff --git a/test/test_option_array.ml b/test/test_option_array.ml index e3661a2..c36769c 100644 --- a/test/test_option_array.ml +++ b/test/test_option_array.ml @@ -1,33 +1,31 @@ open! Import open Option_array -let%test_module "Cheap_option" = - (module struct - open For_testing.Unsafe_cheap_option - - let roundtrip_via_cheap_option (type a) (x : a) = - let opt : a t = some x in - assert (is_some opt); - assert (phys_equal (value_exn opt) x) - ;; - - let%test_unit _ = roundtrip_via_cheap_option 0 - let%test_unit _ = roundtrip_via_cheap_option 1 - let%test_unit _ = roundtrip_via_cheap_option (ref 0) - let%test_unit _ = roundtrip_via_cheap_option `x6e8ee3478e1d7449 - let%test_unit _ = roundtrip_via_cheap_option 0.0 - let%test _ = not (is_some none) - - let%test_unit "memory corruption" = - let make_list () = List.init ~f:(fun i -> Some i) 5 in - Stdlib.Gc.minor (); - let x = value_unsafe (some (make_list ())) in - Stdlib.Gc.minor (); - let (_ : int option list) = List.init ~f:(fun i -> Some (i * 100)) 10000 in - [%test_result: Int.t Option.t List.t] ~expect:(make_list ()) x - ;; - end) -;; +module%test Cheap_option = struct + open For_testing.Unsafe_cheap_option + + let roundtrip_via_cheap_option (type a) (x : a) = + let opt : a t = some x in + assert (is_some opt); + assert (phys_equal (value_exn opt) x) + ;; + + let%test_unit _ = roundtrip_via_cheap_option 0 + let%test_unit _ = roundtrip_via_cheap_option 1 + let%test_unit _ = roundtrip_via_cheap_option (ref 0) + let%test_unit _ = roundtrip_via_cheap_option `x6e8ee3478e1d7449 + let%test_unit _ = roundtrip_via_cheap_option 0.0 + let%test _ = not (is_some none) + + let%test_unit "memory corruption" = + let make_list () = List.init ~f:(fun i -> Some i) 5 in + Stdlib.Gc.minor (); + let x = value_unsafe (some (make_list ())) in + Stdlib.Gc.minor (); + let (_ : int option list) = List.init ~f:(fun i -> Some (i * 100)) 10000 in + [%test_result: Int.t Option.t List.t] ~expect:(make_list ()) x + ;; +end module Sequence = struct let length = length diff --git a/test/test_queue.ml b/test/test_queue.ml index 1500a77..376b3f8 100644 --- a/test/test_queue.ml +++ b/test/test_queue.ml @@ -1,1126 +1,1108 @@ open! Base open Base_test_helpers -let%test_module _ = - (module ( - struct - open Queue - - module type S = S - - let does_raise = Exn.does_raise - - type nonrec 'a t = 'a t [@@deriving sexp, sexp_grammar] - - let globalize = globalize - - let%expect_test _ = - let open Expect_test_helpers_base in - let check t = - require_does_not_raise (fun () -> - invariant ignore t; - print_s [%sexp (t : int t)]) - in - let a = of_list [ 1; 2; 3 ] in - check a; - [%expect {| (1 2 3) |}]; - let b = globalize globalize_int a in - check b; - [%expect {| (1 2 3) |}]; - enqueue b 4; - print_s [%sexp (dequeue a : int option)]; - [%expect {| (1) |}]; - check a; - [%expect {| (2 3) |}]; - check b; - [%expect {| (1 2 3 4) |}] - ;; - - let capacity = capacity - let set_capacity = set_capacity - - let%test_unit _ = - let t = create () in - [%test_result: int] (capacity t) ~expect:2; - enqueue t 1; - [%test_result: int] (capacity t) ~expect:2; - enqueue t 2; - [%test_result: int] (capacity t) ~expect:2; - enqueue t 3; - [%test_result: int] (capacity t) ~expect:4; - set_capacity t 0; - [%test_result: int] (capacity t) ~expect:4; - set_capacity t 3; - [%test_result: int] (capacity t) ~expect:4; - set_capacity t 100; - [%test_result: int] (capacity t) ~expect:128; - enqueue t 4; - enqueue t 5; - set_capacity t 0; - [%test_result: int] (capacity t) ~expect:8; - set_capacity t (-1); - [%test_result: int] (capacity t) ~expect:8 +module%test _ : module type of Queue = struct + open Queue + + module type S = S + + let does_raise = Exn.does_raise + + type nonrec 'a t = 'a t [@@deriving sexp, sexp_grammar] + + let globalize = globalize + + let%expect_test _ = + let open Expect_test_helpers_base in + let check t = + require_does_not_raise (fun () -> + invariant ignore t; + print_s [%sexp (t : int t)]) + in + let a = of_list [ 1; 2; 3 ] in + check a; + [%expect {| (1 2 3) |}]; + let b = globalize globalize_int a in + check b; + [%expect {| (1 2 3) |}]; + enqueue b 4; + print_s [%sexp (dequeue a : int option)]; + [%expect {| (1) |}]; + check a; + [%expect {| (2 3) |}]; + check b; + [%expect {| (1 2 3 4) |}] + ;; + + let capacity = capacity + let set_capacity = set_capacity + + let%test_unit _ = + let t = create () in + [%test_result: int] (capacity t) ~expect:2; + enqueue t 1; + [%test_result: int] (capacity t) ~expect:2; + enqueue t 2; + [%test_result: int] (capacity t) ~expect:2; + enqueue t 3; + [%test_result: int] (capacity t) ~expect:4; + set_capacity t 0; + [%test_result: int] (capacity t) ~expect:4; + set_capacity t 3; + [%test_result: int] (capacity t) ~expect:4; + set_capacity t 100; + [%test_result: int] (capacity t) ~expect:128; + enqueue t 4; + enqueue t 5; + set_capacity t 0; + [%test_result: int] (capacity t) ~expect:8; + set_capacity t (-1); + [%test_result: int] (capacity t) ~expect:8 + ;; + + let round_trip_sexp t = + let sexp = sexp_of_t Int.sexp_of_t t in + let t' = t_of_sexp Int.t_of_sexp sexp in + [%test_result: int list] ~expect:(to_list t) (to_list t') + ;; + + let%test_unit _ = round_trip_sexp (of_list [ 1; 2; 3; 4 ]) + let%test_unit _ = round_trip_sexp (create ()) + let%test_unit _ = round_trip_sexp (of_list []) + let invariant = invariant + let create = create + + let%test_unit _ = + let t = create () in + [%test_result: int] (length t) ~expect:0; + [%test_result: int] (capacity t) ~expect:2 + ;; + + let%test_unit _ = + let t = create ~capacity:0 () in + [%test_result: int] (length t) ~expect:0; + [%test_result: int] (capacity t) ~expect:1 + ;; + + let%test_unit _ = + let t = create ~capacity:6 () in + [%test_result: int] (length t) ~expect:0; + [%test_result: int] (capacity t) ~expect:8 + ;; + + let%test_unit _ = assert (does_raise (fun () : _ Queue.t -> create ~capacity:(-1) ())) + let singleton = singleton + + let%test_unit _ = + let t = singleton 7 in + [%test_result: int] (length t) ~expect:1; + [%test_result: int] (capacity t) ~expect:1; + [%test_result: int option] (dequeue t) ~expect:(Some 7); + [%test_result: int option] (dequeue t) ~expect:None + ;; + + let init = init + + let%test_unit _ = + let t = init 0 ~f:(fun _ -> assert false) in + [%test_result: int] (length t) ~expect:0; + [%test_result: int] (capacity t) ~expect:1; + [%test_result: int option] (dequeue t) ~expect:None + ;; + + let%test_unit _ = + let t = init 3 ~f:(fun i -> i * 2) in + [%test_result: int] (length t) ~expect:3; + [%test_result: int] (capacity t) ~expect:4; + [%test_result: int option] (dequeue t) ~expect:(Some 0); + [%test_result: int option] (dequeue t) ~expect:(Some 2); + [%test_result: int option] (dequeue t) ~expect:(Some 4); + [%test_result: int option] (dequeue t) ~expect:None + ;; + + let%test_unit _ = + assert (does_raise (fun () : unit Queue.t -> init (-1) ~f:(fun _ -> ()))) + ;; + + let get = get + let set = set + + let%test_unit _ = + let t = create () in + let get_opt t i = Option.try_with (fun () -> get t i) in + [%test_result: int option] (get_opt t 0) ~expect:None; + [%test_result: int option] (get_opt t (-1)) ~expect:None; + [%test_result: int option] (get_opt t 10) ~expect:None; + List.iter [ -1; 0; 1 ] ~f:(fun i -> assert (does_raise (fun () -> set t i 0))); + enqueue t 0; + enqueue t 1; + enqueue t 2; + [%test_result: int option] (get_opt t 0) ~expect:(Some 0); + [%test_result: int option] (get_opt t 1) ~expect:(Some 1); + [%test_result: int option] (get_opt t 2) ~expect:(Some 2); + [%test_result: int option] (get_opt t 3) ~expect:None; + ignore (dequeue_exn t : int); + [%test_result: int option] (get_opt t 0) ~expect:(Some 1); + [%test_result: int option] (get_opt t 1) ~expect:(Some 2); + [%test_result: int option] (get_opt t 2) ~expect:None; + set t 0 3; + [%test_result: int option] (get_opt t 0) ~expect:(Some 3); + [%test_result: int option] (get_opt t 1) ~expect:(Some 2); + List.iter [ -1; 2 ] ~f:(fun i -> assert (does_raise (fun () -> set t i 0))) + ;; + + let map = map + + let%test_unit _ = + for i = 0 to 5 do + let l = List.init i ~f:Fn.id in + let t = of_list l in + let f x = x * 2 in + let t' = map t ~f in + [%test_result: int list] (to_list t') ~expect:(List.map l ~f) + done + ;; + + let%test_unit _ = + let t = create () in + let t' = map t ~f:(fun x -> x * 2) in + [%test_result: int] (length t') ~expect:(length t); + [%test_result: int] (length t') ~expect:0; + [%test_result: int list] (to_list t') ~expect:[] + ;; + + let mapi = mapi + + let%test_unit _ = + for i = 0 to 5 do + let l = List.init i ~f:Fn.id in + let t = of_list l in + let f i x = i, x * 2 in + let t' = mapi t ~f in + [%test_result: (int * int) list] (to_list t') ~expect:(List.mapi l ~f) + done + ;; + + let%test_unit _ = + let t = create () in + let t' = mapi t ~f:(fun i x -> i, x * 2) in + [%test_result: int] (length t') ~expect:(length t); + [%test_result: int] (length t') ~expect:0; + [%test_result: (int * int) list] (to_list t') ~expect:[] + ;; + + include Test_container.Test_S1 (Queue) + + let dequeue_exn = dequeue_exn + let enqueue = enqueue + let enqueue_front = enqueue_front + let dequeue_back = dequeue_back + let dequeue_back_exn = dequeue_back_exn + let peek = peek + let peek_exn = peek_exn + let peek_back = peek_back + let peek_back_exn = peek_back_exn + let last = last + let last_exn = last_exn + + let%test_unit _ = + let t = create () in + [%test_result: int option] (peek t) ~expect:None; + [%test_result: int option] (last t) ~expect:None; + enqueue t 1; + enqueue t 2; + [%test_result: int option] (peek t) ~expect:(Some 1); + [%test_result: int] (peek_exn t) ~expect:1; + [%test_result: int option] (last t) ~expect:(Some 2); + [%test_result: int] (last_exn t) ~expect:2; + [%test_result: int] (dequeue_exn t) ~expect:1; + [%test_result: int] (dequeue_exn t) ~expect:2; + assert (does_raise (fun () -> dequeue_exn t)); + assert (does_raise (fun () -> peek_exn t)); + assert (does_raise (fun () -> peek_back_exn t)); + assert (does_raise (fun () -> last_exn t)); + enqueue_front t 1; + enqueue t 2; + enqueue_front t 0; + enqueue t 3; + enqueue t 4; + enqueue t 5; + [%test_result: int option] (peek_back t) ~expect:(Some 5); + [%test_result: int] (peek_back_exn t) ~expect:5; + [%test_result: int] (dequeue_exn t) ~expect:0; + [%test_result: int] (dequeue_exn t) ~expect:1; + [%test_result: int] (dequeue_exn t) ~expect:2; + [%test_result: int] (dequeue_back_exn t) ~expect:5; + [%test_result: int] (dequeue_back_exn t) ~expect:4; + [%test_result: int] (dequeue_back_exn t) ~expect:3 + ;; + + let dequeue_and_ignore_exn = dequeue_and_ignore_exn + + let%test_unit _ = + let t = create () in + enqueue t 1; + enqueue t 2; + enqueue t 3; + [%test_result: int] (peek_exn t) ~expect:1; + dequeue_and_ignore_exn t; + [%test_result: int] (peek_exn t) ~expect:2; + dequeue_and_ignore_exn t; + [%test_result: int] (peek_exn t) ~expect:3; + dequeue_and_ignore_exn t; + [%test_result: int option] (peek t) ~expect:None; + assert (does_raise (fun () -> dequeue_and_ignore_exn t)); + assert (does_raise (fun () -> dequeue_and_ignore_exn t)); + [%test_result: int option] (peek t) ~expect:None + ;; + + let drain = drain + + let%test_unit _ = + let t = create () in + for i = 0 to 10 do + enqueue t i + done; + [%test_result: int] (peek_exn t) ~expect:0; + [%test_result: int] (length t) ~expect:11; + let r = ref 0 in + let add i = r := !r + i in + drain t ~f:add ~while_:(fun i -> i < 7); + [%test_result: int] (peek_exn t) ~expect:7; + [%test_result: int] (length t) ~expect:4; + [%test_result: int] !r ~expect:21; + drain t ~f:add ~while_:(fun i -> i > 7); + [%test_result: int] (peek_exn t) ~expect:7; + [%test_result: int] (length t) ~expect:4; + [%test_result: int] !r ~expect:21; + drain t ~f:add ~while_:(fun i -> i > 0); + [%test_result: int option] (peek t) ~expect:None; + [%test_result: int] (length t) ~expect:0; + [%test_result: int] !r ~expect:55 + ;; + + let enqueue_all = enqueue_all + + let%test_unit _ = + let t = create () in + enqueue_all t [ 1; 2; 3 ]; + [%test_result: int] (dequeue_exn t) ~expect:1; + [%test_result: int] (dequeue_exn t) ~expect:2; + [%test_result: int option] (last t) ~expect:(Some 3); + enqueue_all t [ 4; 5 ]; + [%test_result: int option] (last t) ~expect:(Some 5); + [%test_result: int] (dequeue_exn t) ~expect:3; + [%test_result: int] (dequeue_exn t) ~expect:4; + [%test_result: int] (dequeue_exn t) ~expect:5; + assert (does_raise (fun () -> dequeue_exn t)); + enqueue_all t []; + assert (does_raise (fun () -> dequeue_exn t)) + ;; + + let of_list = of_list + let to_list = to_list + + let%test_unit _ = + for i = 0 to 4 do + let list = List.init i ~f:Fn.id in + [%test_result: int list] (to_list (of_list list)) ~expect:list + done + ;; + + let%test _ = + let t = create () in + for i = 1 to 5 do + enqueue t i + done; + [%equal: int list] (to_list t) [ 1; 2; 3; 4; 5 ] + ;; + + let of_array = of_array + let to_array = to_array + + let%test_unit _ = + for len = 0 to 4 do + let array = Array.init len ~f:Fn.id in + [%test_result: int array] (to_array (of_array array)) ~expect:array + done + ;; + + let compare = compare + let compare__local = compare__local + let equal = equal + let equal__local = equal__local + + module%test [@name "comparisons"] _ = struct + let sign x = if x < 0 then ~-1 else if x > 0 then 1 else 0 + + let test t1 t2 = + [%test_result: bool] + (equal Int.equal t1 t2) + ~expect:(List.equal Int.equal (to_list t1) (to_list t2)); + [%test_result: int] + (sign (compare Int.compare t1 t2)) + ~expect:(sign (List.compare Int.compare (to_list t1) (to_list t2))); + [%test_result: bool] + (equal__local Int.equal__local t1 t2) + ~expect:(List.equal__local Int.equal__local (to_list t1) (to_list t2)); + [%test_result: int] + (sign (compare__local Int.compare__local t1 t2)) + ~expect:(sign (List.compare__local Int.compare__local (to_list t1) (to_list t2))) ;; - let round_trip_sexp t = - let sexp = sexp_of_t Int.sexp_of_t t in - let t' = t_of_sexp Int.t_of_sexp sexp in - [%test_result: int list] ~expect:(to_list t) (to_list t') + let lists = + [ [] + ; [ 1 ] + ; [ 2 ] + ; [ 1; 1 ] + ; [ 1; 2 ] + ; [ 2; 1 ] + ; [ 1; 1; 1 ] + ; [ 1; 2; 3 ] + ; [ 1; 2; 4 ] + ; [ 1; 2; 4; 8 ] + ; [ 1; 2; 3; 4; 5 ] + ] ;; - let%test_unit _ = round_trip_sexp (of_list [ 1; 2; 3; 4 ]) - let%test_unit _ = round_trip_sexp (create ()) - let%test_unit _ = round_trip_sexp (of_list []) - let invariant = invariant - let create = create - let%test_unit _ = - let t = create () in - [%test_result: int] (length t) ~expect:0; - [%test_result: int] (capacity t) ~expect:2 + (* [phys_equal] inputs *) + List.iter lists ~f:(fun list -> + let t = of_list list in + test t t) ;; let%test_unit _ = - let t = create ~capacity:0 () in - [%test_result: int] (length t) ~expect:0; - [%test_result: int] (capacity t) ~expect:1 + List.iter lists ~f:(fun list1 -> + List.iter lists ~f:(fun list2 -> test (of_list list1) (of_list list2))) ;; + end - let%test_unit _ = - let t = create ~capacity:6 () in - [%test_result: int] (length t) ~expect:0; - [%test_result: int] (capacity t) ~expect:8 - ;; + let clear = clear + + let%test_unit "clear" = + let q = of_list [ 1; 2; 3; 4 ] in + [%test_result: int] (length q) ~expect:4; + clear q; + [%test_result: int] (length q) ~expect:0 + ;; + + let blit_transfer = blit_transfer + + let%test_unit _ = + let q_list = [ 1; 2; 3; 4 ] in + let q = of_list q_list in + let q' = create () in + blit_transfer ~src:q ~dst:q' (); + [%test_result: int list] (to_list q') ~expect:q_list; + [%test_result: int list] (to_list q) ~expect:[] + ;; + + let%test_unit _ = + let q = of_list [ 1; 2; 3; 4 ] in + let q' = create () in + blit_transfer ~src:q ~dst:q' ~len:2 (); + [%test_result: int list] (to_list q') ~expect:[ 1; 2 ]; + [%test_result: int list] (to_list q) ~expect:[ 3; 4 ] + ;; + + let%test_unit "blit_transfer on wrapped queues" = + let list = [ 1; 2; 3; 4 ] in + let q = of_list list in + let q' = copy q in + ignore (dequeue_exn q : int); + ignore (dequeue_exn q : int); + ignore (dequeue_exn q' : int); + ignore (dequeue_exn q' : int); + ignore (dequeue_exn q' : int); + enqueue q 5; + enqueue q 6; + blit_transfer ~src:q ~dst:q' ~len:3 (); + [%test_result: int list] (to_list q') ~expect:[ 4; 3; 4; 5 ]; + [%test_result: int list] (to_list q) ~expect:[ 6 ] + ;; + + let copy = copy + + let%test_unit "copies behave independently" = + let q = of_list [ 1; 2; 3; 4 ] in + let q' = copy q in + enqueue q 5; + ignore (dequeue_exn q' : int); + [%test_result: int list] (to_list q) ~expect:[ 1; 2; 3; 4; 5 ]; + [%test_result: int list] (to_list q') ~expect:[ 2; 3; 4 ] + ;; + + let dequeue = dequeue + let filter = filter + let filteri = filteri + let filter_inplace = filter_inplace + let filteri_inplace = filteri_inplace + let concat_map = concat_map + let concat_mapi = concat_mapi + let filter_map = filter_map + let filter_mapi = filter_mapi + let counti = counti + let existsi = existsi + let for_alli = for_alli + let iter = iter + let iteri = iteri + let foldi = foldi + let findi = findi + let find_mapi = find_mapi + + module%test [@name "Linked_queue bisimulation"] _ = struct + module type Queue_intf = sig + type 'a t [@@deriving sexp_of] + + val create : unit -> 'a t + val enqueue : 'a t -> 'a -> unit + val dequeue : 'a t -> 'a option + val drain : 'a t -> f:('a -> unit) -> while_:('a -> bool) -> unit + val to_array : 'a t -> 'a array + val fold : 'a t -> init:'b -> f:('b -> 'a -> 'b) -> 'b + val foldi : 'a t -> init:'b -> f:(int -> 'b -> 'a -> 'b) -> 'b + val iter : 'a t -> f:('a -> unit) -> unit + val iteri : 'a t -> f:(int -> 'a -> unit) -> unit + val length : 'a t -> int + val clear : 'a t -> unit + val concat_map : 'a t -> f:('a -> 'b list) -> 'b t + val concat_mapi : 'a t -> f:(int -> 'a -> 'b list) -> 'b t + val filter_map : 'a t -> f:('a -> 'b option) -> 'b t + val filter_mapi : 'a t -> f:(int -> 'a -> 'b option) -> 'b t + val filter : 'a t -> f:('a -> bool) -> 'a t + val filteri : 'a t -> f:(int -> 'a -> bool) -> 'a t + val filter_inplace : 'a t -> f:('a -> bool) -> unit + val filteri_inplace : 'a t -> f:(int -> 'a -> bool) -> unit + val map : 'a t -> f:('a -> 'b) -> 'b t + val mapi : 'a t -> f:(int -> 'a -> 'b) -> 'b t + val counti : 'a t -> f:(int -> 'a -> bool) -> int + val existsi : 'a t -> f:(int -> 'a -> bool) -> bool + val for_alli : 'a t -> f:(int -> 'a -> bool) -> bool + val findi : 'a t -> f:(int -> 'a -> bool) -> (int * 'a) option + val find_mapi : 'a t -> f:(int -> 'a -> 'b option) -> 'b option + val transfer : src:'a t -> dst:'a t -> unit + val copy : 'a t -> 'a t + end - let%test_unit _ = assert (does_raise (fun () : _ Queue.t -> create ~capacity:(-1) ())) - let singleton = singleton + module That_queue : Queue_intf = Linked_queue - let%test_unit _ = - let t = singleton 7 in - [%test_result: int] (length t) ~expect:1; - [%test_result: int] (capacity t) ~expect:1; - [%test_result: int option] (dequeue t) ~expect:(Some 7); - [%test_result: int option] (dequeue t) ~expect:None - ;; + module This_queue : Queue_intf = struct + include Queue - let init = init + let create () = create () + let transfer ~src ~dst = blit_transfer ~src ~dst () + end - let%test_unit _ = - let t = init 0 ~f:(fun _ -> assert false) in - [%test_result: int] (length t) ~expect:0; - [%test_result: int] (capacity t) ~expect:1; - [%test_result: int option] (dequeue t) ~expect:None + let this_to_string this_t = Sexp.to_string (this_t |> [%sexp_of: int This_queue.t]) + let that_to_string that_t = Sexp.to_string (that_t |> [%sexp_of: int That_queue.t]) + let array_string arr = Sexp.to_string (arr |> [%sexp_of: int array]) + let create () = This_queue.create (), That_queue.create () + + let enqueue (t_a, t_b) v = + let start_a = This_queue.to_array t_a in + let start_b = That_queue.to_array t_b in + This_queue.enqueue t_a v; + That_queue.enqueue t_b v; + let end_a = This_queue.to_array t_a in + let end_b = That_queue.to_array t_b in + if not ([%equal: int array] end_a end_b) + then + Printf.failwithf + "enqueue transition failure of: %s -> %s vs. %s -> %s" + (array_string start_a) + (array_string end_a) + (array_string start_b) + (array_string end_b) + () ;; - let%test_unit _ = - let t = init 3 ~f:(fun i -> i * 2) in - [%test_result: int] (length t) ~expect:3; - [%test_result: int] (capacity t) ~expect:4; - [%test_result: int option] (dequeue t) ~expect:(Some 0); - [%test_result: int option] (dequeue t) ~expect:(Some 2); - [%test_result: int option] (dequeue t) ~expect:(Some 4); - [%test_result: int option] (dequeue t) ~expect:None + let iter (t_a, t_b) = + let r_a, r_b = ref 0, ref 0 in + This_queue.iter t_a ~f:(fun x -> r_a := !r_a + x); + That_queue.iter t_b ~f:(fun x -> r_b := !r_b + x); + if !r_a <> !r_b + then + Printf.failwithf + "error in iter: %s (from %s) <> %s (from %s)" + (Int.to_string !r_a) + (this_to_string t_a) + (Int.to_string !r_b) + (that_to_string t_b) + () ;; - let%test_unit _ = - assert (does_raise (fun () : unit Queue.t -> init (-1) ~f:(fun _ -> ()))) + let iteri (t_a, t_b) = + let r_a, r_b = ref 0, ref 0 in + This_queue.iteri t_a ~f:(fun i x -> r_a := !r_a + (x lxor i)); + That_queue.iteri t_b ~f:(fun i x -> r_b := !r_b + (x lxor i)); + if !r_a <> !r_b + then + Printf.failwithf + "error in iteri: %s (from %s) <> %s (from %s)" + (Int.to_string !r_a) + (this_to_string t_a) + (Int.to_string !r_b) + (that_to_string t_b) + () ;; - let get = get - let set = set - - let%test_unit _ = - let t = create () in - let get_opt t i = Option.try_with (fun () -> get t i) in - [%test_result: int option] (get_opt t 0) ~expect:None; - [%test_result: int option] (get_opt t (-1)) ~expect:None; - [%test_result: int option] (get_opt t 10) ~expect:None; - List.iter [ -1; 0; 1 ] ~f:(fun i -> assert (does_raise (fun () -> set t i 0))); - enqueue t 0; - enqueue t 1; - enqueue t 2; - [%test_result: int option] (get_opt t 0) ~expect:(Some 0); - [%test_result: int option] (get_opt t 1) ~expect:(Some 1); - [%test_result: int option] (get_opt t 2) ~expect:(Some 2); - [%test_result: int option] (get_opt t 3) ~expect:None; - ignore (dequeue_exn t : int); - [%test_result: int option] (get_opt t 0) ~expect:(Some 1); - [%test_result: int option] (get_opt t 1) ~expect:(Some 2); - [%test_result: int option] (get_opt t 2) ~expect:None; - set t 0 3; - [%test_result: int option] (get_opt t 0) ~expect:(Some 3); - [%test_result: int option] (get_opt t 1) ~expect:(Some 2); - List.iter [ -1; 2 ] ~f:(fun i -> assert (does_raise (fun () -> set t i 0))) + let dequeue (t_a, t_b) = + let start_a = This_queue.to_array t_a in + let start_b = That_queue.to_array t_b in + let a, b = This_queue.dequeue t_a, That_queue.dequeue t_b in + let end_a = This_queue.to_array t_a in + let end_b = That_queue.to_array t_b in + if (not ([%equal: int option] a b)) || not ([%equal: int array] end_a end_b) + then + Printf.failwithf + "error in dequeue: %s (%s -> %s) <> %s (%s -> %s)" + (Option.value ~default:"None" (Option.map a ~f:Int.to_string)) + (array_string start_a) + (array_string end_a) + (Option.value ~default:"None" (Option.map b ~f:Int.to_string)) + (array_string start_b) + (array_string end_b) + () ;; - let map = map - - let%test_unit _ = - for i = 0 to 5 do - let l = List.init i ~f:Fn.id in - let t = of_list l in - let f x = x * 2 in - let t' = map t ~f in - [%test_result: int list] (to_list t') ~expect:(List.map l ~f) - done + let is_even x = x land 1 = 0 + + let drain (t_a, t_b) = + let orig_a = This_queue.to_array t_a in + let orig_b = That_queue.to_array t_b in + let r_a = ref 0 in + let r_b = ref 0 in + let add r i = r := !r + i in + This_queue.drain t_a ~f:(fun i -> add r_a i) ~while_:is_even; + That_queue.drain t_b ~f:(fun i -> add r_b i) ~while_:is_even; + if not + ([%equal: int array] (This_queue.to_array t_a) (That_queue.to_array t_b) + && !r_a = !r_b) + then + Printf.failwithf + "error in drain: %s -> %s, %d vs. %s -> %s, %d" + (array_string orig_a) + (this_to_string t_a) + !r_a + (array_string orig_b) + (that_to_string t_b) + !r_b + () ;; - let%test_unit _ = - let t = create () in - let t' = map t ~f:(fun x -> x * 2) in - [%test_result: int] (length t') ~expect:(length t); - [%test_result: int] (length t') ~expect:0; - [%test_result: int list] (to_list t') ~expect:[] + let clear (t_a, t_b) = + This_queue.clear t_a; + That_queue.clear t_b ;; - let mapi = mapi - - let%test_unit _ = - for i = 0 to 5 do - let l = List.init i ~f:Fn.id in - let t = of_list l in - let f i x = i, x * 2 in - let t' = mapi t ~f in - [%test_result: (int * int) list] (to_list t') ~expect:(List.mapi l ~f) - done + let filter (t_a, t_b) = + let t_a' = This_queue.filter t_a ~f:is_even in + let t_b' = That_queue.filter t_b ~f:is_even in + if not ([%equal: int array] (This_queue.to_array t_a') (That_queue.to_array t_b')) + then + Printf.failwithf + "error in filter: %s -> %s vs. %s -> %s" + (this_to_string t_a) + (this_to_string t_a') + (that_to_string t_b) + (that_to_string t_b') + () ;; - let%test_unit _ = - let t = create () in - let t' = mapi t ~f:(fun i x -> i, x * 2) in - [%test_result: int] (length t') ~expect:(length t); - [%test_result: int] (length t') ~expect:0; - [%test_result: (int * int) list] (to_list t') ~expect:[] + let filteri (t_a, t_b) = + let t_a' = + This_queue.filteri t_a ~f:(fun i j -> [%equal: bool] (is_even i) (is_even j)) + in + let t_b' = + That_queue.filteri t_b ~f:(fun i j -> [%equal: bool] (is_even i) (is_even j)) + in + if not ([%equal: int array] (This_queue.to_array t_a') (That_queue.to_array t_b')) + then + Printf.failwithf + "error in filteri: %s -> %s vs. %s -> %s" + (this_to_string t_a) + (this_to_string t_a') + (that_to_string t_b) + (that_to_string t_b') + () ;; - include Test_container.Test_S1 (Queue) - - let dequeue_exn = dequeue_exn - let enqueue = enqueue - let enqueue_front = enqueue_front - let dequeue_back = dequeue_back - let dequeue_back_exn = dequeue_back_exn - let peek = peek - let peek_exn = peek_exn - let peek_back = peek_back - let peek_back_exn = peek_back_exn - let last = last - let last_exn = last_exn - - let%test_unit _ = - let t = create () in - [%test_result: int option] (peek t) ~expect:None; - [%test_result: int option] (last t) ~expect:None; - enqueue t 1; - enqueue t 2; - [%test_result: int option] (peek t) ~expect:(Some 1); - [%test_result: int] (peek_exn t) ~expect:1; - [%test_result: int option] (last t) ~expect:(Some 2); - [%test_result: int] (last_exn t) ~expect:2; - [%test_result: int] (dequeue_exn t) ~expect:1; - [%test_result: int] (dequeue_exn t) ~expect:2; - assert (does_raise (fun () -> dequeue_exn t)); - assert (does_raise (fun () -> peek_exn t)); - assert (does_raise (fun () -> peek_back_exn t)); - assert (does_raise (fun () -> last_exn t)); - enqueue_front t 1; - enqueue t 2; - enqueue_front t 0; - enqueue t 3; - enqueue t 4; - enqueue t 5; - [%test_result: int option] (peek_back t) ~expect:(Some 5); - [%test_result: int] (peek_back_exn t) ~expect:5; - [%test_result: int] (dequeue_exn t) ~expect:0; - [%test_result: int] (dequeue_exn t) ~expect:1; - [%test_result: int] (dequeue_exn t) ~expect:2; - [%test_result: int] (dequeue_back_exn t) ~expect:5; - [%test_result: int] (dequeue_back_exn t) ~expect:4; - [%test_result: int] (dequeue_back_exn t) ~expect:3 + let filter_inplace (t_a, t_b) = + let start_a = This_queue.to_array t_a in + let start_b = That_queue.to_array t_b in + This_queue.filter_inplace t_a ~f:is_even; + That_queue.filter_inplace t_b ~f:is_even; + let end_a = This_queue.to_array t_a in + let end_b = That_queue.to_array t_b in + if not ([%equal: int array] end_a end_b) + then + Printf.failwithf + "error in filter_inplace: %s -> %s vs. %s -> %s" + (array_string start_a) + (array_string end_a) + (array_string start_b) + (array_string end_b) + () ;; - let dequeue_and_ignore_exn = dequeue_and_ignore_exn - - let%test_unit _ = - let t = create () in - enqueue t 1; - enqueue t 2; - enqueue t 3; - [%test_result: int] (peek_exn t) ~expect:1; - dequeue_and_ignore_exn t; - [%test_result: int] (peek_exn t) ~expect:2; - dequeue_and_ignore_exn t; - [%test_result: int] (peek_exn t) ~expect:3; - dequeue_and_ignore_exn t; - [%test_result: int option] (peek t) ~expect:None; - assert (does_raise (fun () -> dequeue_and_ignore_exn t)); - assert (does_raise (fun () -> dequeue_and_ignore_exn t)); - [%test_result: int option] (peek t) ~expect:None + let filteri_inplace (t_a, t_b) = + let start_a = This_queue.to_array t_a in + let start_b = That_queue.to_array t_b in + let f i x = [%equal: bool] (is_even i) (is_even x) in + This_queue.filteri_inplace t_a ~f; + That_queue.filteri_inplace t_b ~f; + let end_a = This_queue.to_array t_a in + let end_b = That_queue.to_array t_b in + if not ([%equal: int array] end_a end_b) + then + Printf.failwithf + "error in filteri_inplace: %s -> %s vs. %s -> %s" + (array_string start_a) + (array_string end_a) + (array_string start_b) + (array_string end_b) + () ;; - let drain = drain - - let%test_unit _ = - let t = create () in - for i = 0 to 10 do - enqueue t i - done; - [%test_result: int] (peek_exn t) ~expect:0; - [%test_result: int] (length t) ~expect:11; - let r = ref 0 in - let add i = r := !r + i in - drain t ~f:add ~while_:(fun i -> i < 7); - [%test_result: int] (peek_exn t) ~expect:7; - [%test_result: int] (length t) ~expect:4; - [%test_result: int] !r ~expect:21; - drain t ~f:add ~while_:(fun i -> i > 7); - [%test_result: int] (peek_exn t) ~expect:7; - [%test_result: int] (length t) ~expect:4; - [%test_result: int] !r ~expect:21; - drain t ~f:add ~while_:(fun i -> i > 0); - [%test_result: int option] (peek t) ~expect:None; - [%test_result: int] (length t) ~expect:0; - [%test_result: int] !r ~expect:55 + let concat_map (t_a, t_b) = + let f x = [ x; x + 1; x + 2 ] in + let t_a' = This_queue.concat_map t_a ~f in + let t_b' = That_queue.concat_map t_b ~f in + if not ([%equal: int array] (This_queue.to_array t_a') (That_queue.to_array t_b')) + then + Printf.failwithf + "error in concat_map: %s (for %s) <> %s (for %s)" + (this_to_string t_a') + (this_to_string t_a) + (that_to_string t_b') + (that_to_string t_b) + () ;; - let enqueue_all = enqueue_all - - let%test_unit _ = - let t = create () in - enqueue_all t [ 1; 2; 3 ]; - [%test_result: int] (dequeue_exn t) ~expect:1; - [%test_result: int] (dequeue_exn t) ~expect:2; - [%test_result: int option] (last t) ~expect:(Some 3); - enqueue_all t [ 4; 5 ]; - [%test_result: int option] (last t) ~expect:(Some 5); - [%test_result: int] (dequeue_exn t) ~expect:3; - [%test_result: int] (dequeue_exn t) ~expect:4; - [%test_result: int] (dequeue_exn t) ~expect:5; - assert (does_raise (fun () -> dequeue_exn t)); - enqueue_all t []; - assert (does_raise (fun () -> dequeue_exn t)) + let concat_mapi (t_a, t_b) = + let f i x = [ x; x + 1; x + 2; x + i ] in + let t_a' = This_queue.concat_mapi t_a ~f in + let t_b' = That_queue.concat_mapi t_b ~f in + if not ([%equal: int array] (This_queue.to_array t_a') (That_queue.to_array t_b')) + then + Printf.failwithf + "error in concat_mapi: %s (for %s) <> %s (for %s)" + (this_to_string t_a') + (this_to_string t_a) + (that_to_string t_b') + (that_to_string t_b) + () ;; - let of_list = of_list - let to_list = to_list - - let%test_unit _ = - for i = 0 to 4 do - let list = List.init i ~f:Fn.id in - [%test_result: int list] (to_list (of_list list)) ~expect:list - done + let filter_map (t_a, t_b) = + let f x = if is_even x then None else Some (x + 1) in + let t_a' = This_queue.filter_map t_a ~f in + let t_b' = That_queue.filter_map t_b ~f in + if not ([%equal: int array] (This_queue.to_array t_a') (That_queue.to_array t_b')) + then + Printf.failwithf + "error in filter_map: %s (for %s) <> %s (for %s)" + (this_to_string t_a') + (this_to_string t_a) + (that_to_string t_b') + (that_to_string t_b) + () ;; - let%test _ = - let t = create () in - for i = 1 to 5 do - enqueue t i - done; - [%equal: int list] (to_list t) [ 1; 2; 3; 4; 5 ] + let filter_mapi (t_a, t_b) = + let f i x = + if [%equal: bool] (is_even i) (is_even x) then None else Some (x + 1 + i) + in + let t_a' = This_queue.filter_mapi t_a ~f in + let t_b' = That_queue.filter_mapi t_b ~f in + if not ([%equal: int array] (This_queue.to_array t_a') (That_queue.to_array t_b')) + then + Printf.failwithf + "error in filter_mapi: %s (for %s) <> %s (for %s)" + (this_to_string t_a') + (this_to_string t_a) + (that_to_string t_b') + (that_to_string t_b) + () ;; - let of_array = of_array - let to_array = to_array - - let%test_unit _ = - for len = 0 to 4 do - let array = Array.init len ~f:Fn.id in - [%test_result: int array] (to_array (of_array array)) ~expect:array - done + let map (t_a, t_b) = + let f x = x * 7 in + let t_a' = This_queue.map t_a ~f in + let t_b' = That_queue.map t_b ~f in + if not ([%equal: int array] (This_queue.to_array t_a') (That_queue.to_array t_b')) + then + Printf.failwithf + "error in map: %s (for %s) <> %s (for %s)" + (this_to_string t_a') + (this_to_string t_a) + (that_to_string t_b') + (that_to_string t_b) + () ;; - let compare = compare - let compare__local = compare__local - let equal = equal - let equal__local = equal__local - - let%test_module "comparisons" = - (module struct - let sign x = if x < 0 then ~-1 else if x > 0 then 1 else 0 - - let test t1 t2 = - [%test_result: bool] - (equal Int.equal t1 t2) - ~expect:(List.equal Int.equal (to_list t1) (to_list t2)); - [%test_result: int] - (sign (compare Int.compare t1 t2)) - ~expect:(sign (List.compare Int.compare (to_list t1) (to_list t2))); - [%test_result: bool] - (equal__local Int.equal__local t1 t2) - ~expect:(List.equal__local Int.equal__local (to_list t1) (to_list t2)); - [%test_result: int] - (sign (compare__local Int.compare__local t1 t2)) - ~expect: - (sign (List.compare__local Int.compare__local (to_list t1) (to_list t2))) - ;; - - let lists = - [ [] - ; [ 1 ] - ; [ 2 ] - ; [ 1; 1 ] - ; [ 1; 2 ] - ; [ 2; 1 ] - ; [ 1; 1; 1 ] - ; [ 1; 2; 3 ] - ; [ 1; 2; 4 ] - ; [ 1; 2; 4; 8 ] - ; [ 1; 2; 3; 4; 5 ] - ] - ;; - - let%test_unit _ = - (* [phys_equal] inputs *) - List.iter lists ~f:(fun list -> - let t = of_list list in - test t t) - ;; - - let%test_unit _ = - List.iter lists ~f:(fun list1 -> - List.iter lists ~f:(fun list2 -> test (of_list list1) (of_list list2))) - ;; - end) + let mapi (t_a, t_b) = + let f i x = (x + 3) lxor i in + let t_a' = This_queue.mapi t_a ~f in + let t_b' = That_queue.mapi t_b ~f in + if not ([%equal: int array] (This_queue.to_array t_a') (That_queue.to_array t_b')) + then + Printf.failwithf + "error in mapi: %s (for %s) <> %s (for %s)" + (this_to_string t_a') + (this_to_string t_a) + (that_to_string t_b') + (that_to_string t_b) + () ;; - let clear = clear - - let%test_unit "clear" = - let q = of_list [ 1; 2; 3; 4 ] in - [%test_result: int] (length q) ~expect:4; - clear q; - [%test_result: int] (length q) ~expect:0 + let counti (t_a, t_b) = + let f i x = i < 7 && i % 7 = x % 7 in + let a' = This_queue.counti t_a ~f in + let b' = That_queue.counti t_b ~f in + if a' <> b' + then + Printf.failwithf + "error in counti: %d (for %s) <> %d (for %s)" + a' + (this_to_string t_a) + b' + (that_to_string t_b) + () ;; - let blit_transfer = blit_transfer + let existsi (t_a, t_b) = + let f i x = i < 7 && i % 7 = x % 7 in + let a' = This_queue.existsi t_a ~f in + let b' = That_queue.existsi t_b ~f in + if not ([%equal: bool] a' b') + then + Printf.failwithf + "error in existsi: %b (for %s) <> %b (for %s)" + a' + (this_to_string t_a) + b' + (that_to_string t_b) + () + ;; - let%test_unit _ = - let q_list = [ 1; 2; 3; 4 ] in - let q = of_list q_list in - let q' = create () in - blit_transfer ~src:q ~dst:q' (); - [%test_result: int list] (to_list q') ~expect:q_list; - [%test_result: int list] (to_list q) ~expect:[] + let for_alli (t_a, t_b) = + let f i x = i >= 7 || i % 7 <> x % 7 in + let a' = This_queue.for_alli t_a ~f in + let b' = That_queue.for_alli t_b ~f in + if not ([%equal: bool] a' b') + then + Printf.failwithf + "error in for_alli: %b (for %s) <> %b (for %s)" + a' + (this_to_string t_a) + b' + (that_to_string t_b) + () ;; - let%test_unit _ = - let q = of_list [ 1; 2; 3; 4 ] in - let q' = create () in - blit_transfer ~src:q ~dst:q' ~len:2 (); - [%test_result: int list] (to_list q') ~expect:[ 1; 2 ]; - [%test_result: int list] (to_list q) ~expect:[ 3; 4 ] + let findi (t_a, t_b) = + let f i x = i < 7 && i % 7 = x % 7 in + let a' = This_queue.findi t_a ~f in + let b' = That_queue.findi t_b ~f in + if not ([%equal: (int * int) option] a' b') + then + Printf.failwithf + "error in findi: %s (for %s) <> %s (for %s)" + (Sexp.to_string ([%sexp_of: (int * int) option] a')) + (this_to_string t_a) + (Sexp.to_string ([%sexp_of: (int * int) option] b')) + (that_to_string t_b) + () ;; - let%test_unit "blit_transfer on wrapped queues" = - let list = [ 1; 2; 3; 4 ] in - let q = of_list list in - let q' = copy q in - ignore (dequeue_exn q : int); - ignore (dequeue_exn q : int); - ignore (dequeue_exn q' : int); - ignore (dequeue_exn q' : int); - ignore (dequeue_exn q' : int); - enqueue q 5; - enqueue q 6; - blit_transfer ~src:q ~dst:q' ~len:3 (); - [%test_result: int list] (to_list q') ~expect:[ 4; 3; 4; 5 ]; - [%test_result: int list] (to_list q) ~expect:[ 6 ] + let find_mapi (t_a, t_b) = + let f i x = if i < 7 && i % 7 = x % 7 then Some (i + x) else None in + let a' = This_queue.find_mapi t_a ~f in + let b' = That_queue.find_mapi t_b ~f in + if not ([%equal: int option] a' b') + then + Printf.failwithf + "error in find_mapi: %s (for %s) <> %s (for %s)" + (Sexp.to_string ([%sexp_of: int option] a')) + (this_to_string t_a) + (Sexp.to_string ([%sexp_of: int option] b')) + (that_to_string t_b) + () ;; - let copy = copy + let copy (t_a, t_b) = + let copy_a = This_queue.copy t_a in + let copy_b = That_queue.copy t_b in + let start_a = This_queue.to_array t_a in + let start_b = That_queue.to_array t_b in + let end_a = This_queue.to_array copy_a in + let end_b = That_queue.to_array copy_b in + if not ([%equal: int array] end_a end_b) + then + Printf.failwithf + "error in copy: %s -> %s vs. %s -> %s" + (array_string start_a) + (array_string end_a) + (array_string start_b) + (array_string end_b) + () + ;; - let%test_unit "copies behave independently" = - let q = of_list [ 1; 2; 3; 4 ] in - let q' = copy q in - enqueue q 5; - ignore (dequeue_exn q' : int); - [%test_result: int list] (to_list q) ~expect:[ 1; 2; 3; 4; 5 ]; - [%test_result: int list] (to_list q') ~expect:[ 2; 3; 4 ] + let transfer (t_a, t_b) = + let dst_a = This_queue.create () in + let dst_b = That_queue.create () in + (* sometimes puts some elements in the destination queues *) + if Random.bool () + then + List.iter [ 1; 2; 3; 4; 5 ] ~f:(fun elem -> + This_queue.enqueue dst_a elem; + That_queue.enqueue dst_b elem); + let start_a = This_queue.to_array t_a in + let start_b = That_queue.to_array t_b in + This_queue.transfer ~src:t_a ~dst:dst_a; + That_queue.transfer ~src:t_b ~dst:dst_b; + let end_a = This_queue.to_array t_a in + let end_b = That_queue.to_array t_b in + let end_a' = This_queue.to_array dst_a in + let end_b' = That_queue.to_array dst_b in + if (not ([%equal: int array] end_a' end_b')) + || not ([%equal: int array] end_a end_b) + then + Printf.failwithf + "error in transfer: %s -> (%s, %s) vs. %s -> (%s, %s)" + (array_string start_a) + (array_string end_a) + (array_string end_a') + (array_string start_b) + (array_string end_b) + (array_string end_b) + () ;; - let dequeue = dequeue - let filter = filter - let filteri = filteri - let filter_inplace = filter_inplace - let filteri_inplace = filteri_inplace - let concat_map = concat_map - let concat_mapi = concat_mapi - let filter_map = filter_map - let filter_mapi = filter_mapi - let counti = counti - let existsi = existsi - let for_alli = for_alli - let iter = iter - let iteri = iteri - let foldi = foldi - let findi = findi - let find_mapi = find_mapi - - let%test_module "Linked_queue bisimulation" = - (module struct - module type Queue_intf = sig - type 'a t [@@deriving sexp_of] - - val create : unit -> 'a t - val enqueue : 'a t -> 'a -> unit - val dequeue : 'a t -> 'a option - val drain : 'a t -> f:('a -> unit) -> while_:('a -> bool) -> unit - val to_array : 'a t -> 'a array - val fold : 'a t -> init:'b -> f:('b -> 'a -> 'b) -> 'b - val foldi : 'a t -> init:'b -> f:(int -> 'b -> 'a -> 'b) -> 'b - val iter : 'a t -> f:('a -> unit) -> unit - val iteri : 'a t -> f:(int -> 'a -> unit) -> unit - val length : 'a t -> int - val clear : 'a t -> unit - val concat_map : 'a t -> f:('a -> 'b list) -> 'b t - val concat_mapi : 'a t -> f:(int -> 'a -> 'b list) -> 'b t - val filter_map : 'a t -> f:('a -> 'b option) -> 'b t - val filter_mapi : 'a t -> f:(int -> 'a -> 'b option) -> 'b t - val filter : 'a t -> f:('a -> bool) -> 'a t - val filteri : 'a t -> f:(int -> 'a -> bool) -> 'a t - val filter_inplace : 'a t -> f:('a -> bool) -> unit - val filteri_inplace : 'a t -> f:(int -> 'a -> bool) -> unit - val map : 'a t -> f:('a -> 'b) -> 'b t - val mapi : 'a t -> f:(int -> 'a -> 'b) -> 'b t - val counti : 'a t -> f:(int -> 'a -> bool) -> int - val existsi : 'a t -> f:(int -> 'a -> bool) -> bool - val for_alli : 'a t -> f:(int -> 'a -> bool) -> bool - val findi : 'a t -> f:(int -> 'a -> bool) -> (int * 'a) option - val find_mapi : 'a t -> f:(int -> 'a -> 'b option) -> 'b option - val transfer : src:'a t -> dst:'a t -> unit - val copy : 'a t -> 'a t - end - - module That_queue : Queue_intf = Linked_queue - - module This_queue : Queue_intf = struct - include Queue - - let create () = create () - let transfer ~src ~dst = blit_transfer ~src ~dst () - end - - let this_to_string this_t = Sexp.to_string (this_t |> [%sexp_of: int This_queue.t]) - let that_to_string that_t = Sexp.to_string (that_t |> [%sexp_of: int That_queue.t]) - let array_string arr = Sexp.to_string (arr |> [%sexp_of: int array]) - let create () = This_queue.create (), That_queue.create () - - let enqueue (t_a, t_b) v = - let start_a = This_queue.to_array t_a in - let start_b = That_queue.to_array t_b in - This_queue.enqueue t_a v; - That_queue.enqueue t_b v; - let end_a = This_queue.to_array t_a in - let end_b = That_queue.to_array t_b in - if not ([%equal: int array] end_a end_b) - then - Printf.failwithf - "enqueue transition failure of: %s -> %s vs. %s -> %s" - (array_string start_a) - (array_string end_a) - (array_string start_b) - (array_string end_b) - () - ;; - - let iter (t_a, t_b) = - let r_a, r_b = ref 0, ref 0 in - This_queue.iter t_a ~f:(fun x -> r_a := !r_a + x); - That_queue.iter t_b ~f:(fun x -> r_b := !r_b + x); - if !r_a <> !r_b - then - Printf.failwithf - "error in iter: %s (from %s) <> %s (from %s)" - (Int.to_string !r_a) - (this_to_string t_a) - (Int.to_string !r_b) - (that_to_string t_b) - () - ;; - - let iteri (t_a, t_b) = - let r_a, r_b = ref 0, ref 0 in - This_queue.iteri t_a ~f:(fun i x -> r_a := !r_a + (x lxor i)); - That_queue.iteri t_b ~f:(fun i x -> r_b := !r_b + (x lxor i)); - if !r_a <> !r_b - then - Printf.failwithf - "error in iteri: %s (from %s) <> %s (from %s)" - (Int.to_string !r_a) - (this_to_string t_a) - (Int.to_string !r_b) - (that_to_string t_b) - () - ;; - - let dequeue (t_a, t_b) = - let start_a = This_queue.to_array t_a in - let start_b = That_queue.to_array t_b in - let a, b = This_queue.dequeue t_a, That_queue.dequeue t_b in - let end_a = This_queue.to_array t_a in - let end_b = That_queue.to_array t_b in - if (not ([%equal: int option] a b)) || not ([%equal: int array] end_a end_b) - then - Printf.failwithf - "error in dequeue: %s (%s -> %s) <> %s (%s -> %s)" - (Option.value ~default:"None" (Option.map a ~f:Int.to_string)) - (array_string start_a) - (array_string end_a) - (Option.value ~default:"None" (Option.map b ~f:Int.to_string)) - (array_string start_b) - (array_string end_b) - () - ;; - - let is_even x = x land 1 = 0 - - let drain (t_a, t_b) = - let orig_a = This_queue.to_array t_a in - let orig_b = That_queue.to_array t_b in - let r_a = ref 0 in - let r_b = ref 0 in - let add r i = r := !r + i in - This_queue.drain t_a ~f:(fun i -> add r_a i) ~while_:is_even; - That_queue.drain t_b ~f:(fun i -> add r_b i) ~while_:is_even; - if not - ([%equal: int array] (This_queue.to_array t_a) (That_queue.to_array t_b) - && !r_a = !r_b) - then - Printf.failwithf - "error in drain: %s -> %s, %d vs. %s -> %s, %d" - (array_string orig_a) - (this_to_string t_a) - !r_a - (array_string orig_b) - (that_to_string t_b) - !r_b - () - ;; - - let clear (t_a, t_b) = - This_queue.clear t_a; - That_queue.clear t_b - ;; - - let filter (t_a, t_b) = - let t_a' = This_queue.filter t_a ~f:is_even in - let t_b' = That_queue.filter t_b ~f:is_even in - if not - ([%equal: int array] (This_queue.to_array t_a') (That_queue.to_array t_b')) - then - Printf.failwithf - "error in filter: %s -> %s vs. %s -> %s" - (this_to_string t_a) - (this_to_string t_a') - (that_to_string t_b) - (that_to_string t_b') - () - ;; - - let filteri (t_a, t_b) = - let t_a' = - This_queue.filteri t_a ~f:(fun i j -> [%equal: bool] (is_even i) (is_even j)) - in - let t_b' = - That_queue.filteri t_b ~f:(fun i j -> [%equal: bool] (is_even i) (is_even j)) - in - if not - ([%equal: int array] (This_queue.to_array t_a') (That_queue.to_array t_b')) - then - Printf.failwithf - "error in filteri: %s -> %s vs. %s -> %s" - (this_to_string t_a) - (this_to_string t_a') - (that_to_string t_b) - (that_to_string t_b') - () - ;; - - let filter_inplace (t_a, t_b) = - let start_a = This_queue.to_array t_a in - let start_b = That_queue.to_array t_b in - This_queue.filter_inplace t_a ~f:is_even; - That_queue.filter_inplace t_b ~f:is_even; - let end_a = This_queue.to_array t_a in - let end_b = That_queue.to_array t_b in - if not ([%equal: int array] end_a end_b) - then - Printf.failwithf - "error in filter_inplace: %s -> %s vs. %s -> %s" - (array_string start_a) - (array_string end_a) - (array_string start_b) - (array_string end_b) - () - ;; - - let filteri_inplace (t_a, t_b) = - let start_a = This_queue.to_array t_a in - let start_b = That_queue.to_array t_b in - let f i x = [%equal: bool] (is_even i) (is_even x) in - This_queue.filteri_inplace t_a ~f; - That_queue.filteri_inplace t_b ~f; - let end_a = This_queue.to_array t_a in - let end_b = That_queue.to_array t_b in - if not ([%equal: int array] end_a end_b) - then - Printf.failwithf - "error in filteri_inplace: %s -> %s vs. %s -> %s" - (array_string start_a) - (array_string end_a) - (array_string start_b) - (array_string end_b) - () - ;; - - let concat_map (t_a, t_b) = - let f x = [ x; x + 1; x + 2 ] in - let t_a' = This_queue.concat_map t_a ~f in - let t_b' = That_queue.concat_map t_b ~f in - if not - ([%equal: int array] (This_queue.to_array t_a') (That_queue.to_array t_b')) - then - Printf.failwithf - "error in concat_map: %s (for %s) <> %s (for %s)" - (this_to_string t_a') - (this_to_string t_a) - (that_to_string t_b') - (that_to_string t_b) - () - ;; - - let concat_mapi (t_a, t_b) = - let f i x = [ x; x + 1; x + 2; x + i ] in - let t_a' = This_queue.concat_mapi t_a ~f in - let t_b' = That_queue.concat_mapi t_b ~f in - if not - ([%equal: int array] (This_queue.to_array t_a') (That_queue.to_array t_b')) - then - Printf.failwithf - "error in concat_mapi: %s (for %s) <> %s (for %s)" - (this_to_string t_a') - (this_to_string t_a) - (that_to_string t_b') - (that_to_string t_b) - () - ;; - - let filter_map (t_a, t_b) = - let f x = if is_even x then None else Some (x + 1) in - let t_a' = This_queue.filter_map t_a ~f in - let t_b' = That_queue.filter_map t_b ~f in - if not - ([%equal: int array] (This_queue.to_array t_a') (That_queue.to_array t_b')) - then - Printf.failwithf - "error in filter_map: %s (for %s) <> %s (for %s)" - (this_to_string t_a') - (this_to_string t_a) - (that_to_string t_b') - (that_to_string t_b) - () - ;; - - let filter_mapi (t_a, t_b) = - let f i x = - if [%equal: bool] (is_even i) (is_even x) then None else Some (x + 1 + i) - in - let t_a' = This_queue.filter_mapi t_a ~f in - let t_b' = That_queue.filter_mapi t_b ~f in - if not - ([%equal: int array] (This_queue.to_array t_a') (That_queue.to_array t_b')) - then - Printf.failwithf - "error in filter_mapi: %s (for %s) <> %s (for %s)" - (this_to_string t_a') - (this_to_string t_a) - (that_to_string t_b') - (that_to_string t_b) - () - ;; - - let map (t_a, t_b) = - let f x = x * 7 in - let t_a' = This_queue.map t_a ~f in - let t_b' = That_queue.map t_b ~f in - if not - ([%equal: int array] (This_queue.to_array t_a') (That_queue.to_array t_b')) - then - Printf.failwithf - "error in map: %s (for %s) <> %s (for %s)" - (this_to_string t_a') - (this_to_string t_a) - (that_to_string t_b') - (that_to_string t_b) - () - ;; - - let mapi (t_a, t_b) = - let f i x = (x + 3) lxor i in - let t_a' = This_queue.mapi t_a ~f in - let t_b' = That_queue.mapi t_b ~f in - if not - ([%equal: int array] (This_queue.to_array t_a') (That_queue.to_array t_b')) - then - Printf.failwithf - "error in mapi: %s (for %s) <> %s (for %s)" - (this_to_string t_a') - (this_to_string t_a) - (that_to_string t_b') - (that_to_string t_b) - () - ;; - - let counti (t_a, t_b) = - let f i x = i < 7 && i % 7 = x % 7 in - let a' = This_queue.counti t_a ~f in - let b' = That_queue.counti t_b ~f in - if a' <> b' - then - Printf.failwithf - "error in counti: %d (for %s) <> %d (for %s)" - a' - (this_to_string t_a) - b' - (that_to_string t_b) - () - ;; - - let existsi (t_a, t_b) = - let f i x = i < 7 && i % 7 = x % 7 in - let a' = This_queue.existsi t_a ~f in - let b' = That_queue.existsi t_b ~f in - if not ([%equal: bool] a' b') - then - Printf.failwithf - "error in existsi: %b (for %s) <> %b (for %s)" - a' - (this_to_string t_a) - b' - (that_to_string t_b) - () - ;; - - let for_alli (t_a, t_b) = - let f i x = i >= 7 || i % 7 <> x % 7 in - let a' = This_queue.for_alli t_a ~f in - let b' = That_queue.for_alli t_b ~f in - if not ([%equal: bool] a' b') - then - Printf.failwithf - "error in for_alli: %b (for %s) <> %b (for %s)" - a' - (this_to_string t_a) - b' - (that_to_string t_b) - () - ;; - - let findi (t_a, t_b) = - let f i x = i < 7 && i % 7 = x % 7 in - let a' = This_queue.findi t_a ~f in - let b' = That_queue.findi t_b ~f in - if not ([%equal: (int * int) option] a' b') - then - Printf.failwithf - "error in findi: %s (for %s) <> %s (for %s)" - (Sexp.to_string ([%sexp_of: (int * int) option] a')) - (this_to_string t_a) - (Sexp.to_string ([%sexp_of: (int * int) option] b')) - (that_to_string t_b) - () - ;; - - let find_mapi (t_a, t_b) = - let f i x = if i < 7 && i % 7 = x % 7 then Some (i + x) else None in - let a' = This_queue.find_mapi t_a ~f in - let b' = That_queue.find_mapi t_b ~f in - if not ([%equal: int option] a' b') - then - Printf.failwithf - "error in find_mapi: %s (for %s) <> %s (for %s)" - (Sexp.to_string ([%sexp_of: int option] a')) - (this_to_string t_a) - (Sexp.to_string ([%sexp_of: int option] b')) - (that_to_string t_b) - () - ;; - - let copy (t_a, t_b) = - let copy_a = This_queue.copy t_a in - let copy_b = That_queue.copy t_b in - let start_a = This_queue.to_array t_a in - let start_b = That_queue.to_array t_b in - let end_a = This_queue.to_array copy_a in - let end_b = That_queue.to_array copy_b in - if not ([%equal: int array] end_a end_b) - then - Printf.failwithf - "error in copy: %s -> %s vs. %s -> %s" - (array_string start_a) - (array_string end_a) - (array_string start_b) - (array_string end_b) - () - ;; - - let transfer (t_a, t_b) = - let dst_a = This_queue.create () in - let dst_b = That_queue.create () in - (* sometimes puts some elements in the destination queues *) - if Random.bool () - then - List.iter [ 1; 2; 3; 4; 5 ] ~f:(fun elem -> - This_queue.enqueue dst_a elem; - That_queue.enqueue dst_b elem); - let start_a = This_queue.to_array t_a in - let start_b = That_queue.to_array t_b in - This_queue.transfer ~src:t_a ~dst:dst_a; - That_queue.transfer ~src:t_b ~dst:dst_b; - let end_a = This_queue.to_array t_a in - let end_b = That_queue.to_array t_b in - let end_a' = This_queue.to_array dst_a in - let end_b' = That_queue.to_array dst_b in - if (not ([%equal: int array] end_a' end_b')) - || not ([%equal: int array] end_a end_b) - then - Printf.failwithf - "error in transfer: %s -> (%s, %s) vs. %s -> (%s, %s)" - (array_string start_a) - (array_string end_a) - (array_string end_a') - (array_string start_b) - (array_string end_b) - (array_string end_b) - () - ;; - - let fold_check (t_a, t_b) = - let make_list fold t = fold t ~init:[] ~f:(fun acc x -> x :: acc) in - let this_l = make_list This_queue.fold t_a in - let that_l = make_list That_queue.fold t_b in - if not ([%equal: int list] this_l that_l) - then - Printf.failwithf - "error in fold: %s (from %s) <> %s (from %s)" - (Sexp.to_string (this_l |> [%sexp_of: int list])) - (this_to_string t_a) - (Sexp.to_string (that_l |> [%sexp_of: int list])) - (that_to_string t_b) - () - ;; - - let foldi_check (t_a, t_b) = - let make_list foldi t = foldi t ~init:[] ~f:(fun i acc x -> (i, x) :: acc) in - let this_l = make_list This_queue.foldi t_a in - let that_l = make_list That_queue.foldi t_b in - if not ([%equal: (int * int) list] this_l that_l) - then - Printf.failwithf - "error in foldi: %s (from %s) <> %s (from %s)" - (Sexp.to_string (this_l |> [%sexp_of: (int * int) list])) - (this_to_string t_a) - (Sexp.to_string (that_l |> [%sexp_of: (int * int) list])) - (that_to_string t_b) - () - ;; - - let length_check (t_a, t_b) = - let this_len = This_queue.length t_a in - let that_len = That_queue.length t_b in - if this_len <> that_len - then - Printf.failwithf - "error in length: %i (for %s) <> %i (for %s)" - this_len - (this_to_string t_a) - that_len - (that_to_string t_b) - () - ;; - - let%test_unit _ = - let t = create () in - let rec loop ~all_ops ~non_empty_ops = - if all_ops <= 0 && non_empty_ops <= 0 - then ( - let t_a, t_b = t in - let arr_a = This_queue.to_array t_a in - let arr_b = That_queue.to_array t_b in - if not ([%equal: int array] arr_a arr_b) - then - Printf.failwithf - "queue final states not equal: %s vs. %s" - (array_string arr_a) - (array_string arr_b) - ()) - else ( - let queue_was_empty = This_queue.length (fst t) = 0 in - let r = Random.int 200 in - if r < 60 - then enqueue t (Random.int 10_000) - else if r < 65 - then dequeue t - else if r < 70 - then clear t - else if r < 80 - then iter t - else if r < 85 - then iteri t - else if r < 90 - then fold_check t - else if r < 95 - then foldi_check t - else if r < 100 - then filter t - else if r < 105 - then filteri t - else if r < 110 - then concat_map t - else if r < 115 - then concat_mapi t - else if r < 120 - then transfer t - else if r < 130 - then filter_map t - else if r < 135 - then filter_mapi t - else if r < 140 - then copy t - else if r < 150 - then filter_inplace t - else if r < 155 - then for_alli t - else if r < 160 - then existsi t - else if r < 165 - then counti t - else if r < 170 - then findi t - else if r < 175 - then find_mapi t - else if r < 180 - then map t - else if r < 185 - then mapi t - else if r < 190 - then filteri_inplace t - else if r < 195 - then length_check t - else if r < 200 - then drain t - else failwith "Impossible: We did [Random.int 200] above"; - loop - ~all_ops:(all_ops - 1) - ~non_empty_ops: - (if queue_was_empty then non_empty_ops else non_empty_ops - 1)) - in - loop ~all_ops:30_000 ~non_empty_ops:20_000 - ;; - end) + let fold_check (t_a, t_b) = + let make_list fold t = fold t ~init:[] ~f:(fun acc x -> x :: acc) in + let this_l = make_list This_queue.fold t_a in + let that_l = make_list That_queue.fold t_b in + if not ([%equal: int list] this_l that_l) + then + Printf.failwithf + "error in fold: %s (from %s) <> %s (from %s)" + (Sexp.to_string (this_l |> [%sexp_of: int list])) + (this_to_string t_a) + (Sexp.to_string (that_l |> [%sexp_of: int list])) + (that_to_string t_b) + () ;; - let%test_unit "modification-during-iteration" = - let x = `A 0 in - let t = of_list [ x; x ] in - let f (`A n) = - ignore n; - clear t - in - assert (does_raise (fun () -> iter t ~f)) + let foldi_check (t_a, t_b) = + let make_list foldi t = foldi t ~init:[] ~f:(fun i acc x -> (i, x) :: acc) in + let this_l = make_list This_queue.foldi t_a in + let that_l = make_list That_queue.foldi t_b in + if not ([%equal: (int * int) list] this_l that_l) + then + Printf.failwithf + "error in foldi: %s (from %s) <> %s (from %s)" + (Sexp.to_string (this_l |> [%sexp_of: (int * int) list])) + (this_to_string t_a) + (Sexp.to_string (that_l |> [%sexp_of: (int * int) list])) + (that_to_string t_b) + () ;; - let%test_unit "more-modification-during-iteration" = - let nested_iter_okay = ref false in - let t = of_list [ `iter; `clear ] in - assert ( - does_raise (fun () -> - iter t ~f:(function - | `iter -> - iter t ~f:ignore; - nested_iter_okay := true - | `clear -> clear t))); - assert !nested_iter_okay + let length_check (t_a, t_b) = + let this_len = This_queue.length t_a in + let that_len = That_queue.length t_b in + if this_len <> that_len + then + Printf.failwithf + "error in length: %i (for %s) <> %i (for %s)" + this_len + (this_to_string t_a) + that_len + (that_to_string t_b) + () ;; - let%test_unit "modification-during-filter" = - let reached_unreachable = ref false in - let t = of_list [ `clear; `unreachable ] in - let f x = - match x with - | `clear -> - clear t; - false - | `unreachable -> - reached_unreachable := true; - false + let%test_unit _ = + let t = create () in + let rec loop ~all_ops ~non_empty_ops = + if all_ops <= 0 && non_empty_ops <= 0 + then ( + let t_a, t_b = t in + let arr_a = This_queue.to_array t_a in + let arr_b = That_queue.to_array t_b in + if not ([%equal: int array] arr_a arr_b) + then + Printf.failwithf + "queue final states not equal: %s vs. %s" + (array_string arr_a) + (array_string arr_b) + ()) + else ( + let queue_was_empty = This_queue.length (fst t) = 0 in + let r = Random.int 200 in + if r < 60 + then enqueue t (Random.int 10_000) + else if r < 65 + then dequeue t + else if r < 70 + then clear t + else if r < 80 + then iter t + else if r < 85 + then iteri t + else if r < 90 + then fold_check t + else if r < 95 + then foldi_check t + else if r < 100 + then filter t + else if r < 105 + then filteri t + else if r < 110 + then concat_map t + else if r < 115 + then concat_mapi t + else if r < 120 + then transfer t + else if r < 130 + then filter_map t + else if r < 135 + then filter_mapi t + else if r < 140 + then copy t + else if r < 150 + then filter_inplace t + else if r < 155 + then for_alli t + else if r < 160 + then existsi t + else if r < 165 + then counti t + else if r < 170 + then findi t + else if r < 175 + then find_mapi t + else if r < 180 + then map t + else if r < 185 + then mapi t + else if r < 190 + then filteri_inplace t + else if r < 195 + then length_check t + else if r < 200 + then drain t + else failwith "Impossible: We did [Random.int 200] above"; + loop + ~all_ops:(all_ops - 1) + ~non_empty_ops:(if queue_was_empty then non_empty_ops else non_empty_ops - 1)) in - assert (does_raise (fun () -> filter t ~f)); - assert (not !reached_unreachable) + loop ~all_ops:30_000 ~non_empty_ops:20_000 ;; + end - let%test_unit "modification-during-filter-inplace" = - let reached_unreachable = ref false in - let t = of_list [ `drop_this; `enqueue_new_element; `unreachable ] in - let f x = - (match x with - | `drop_this | `new_element -> () - | `enqueue_new_element -> enqueue t `new_element - | `unreachable -> reached_unreachable := true); + let%test_unit "modification-during-iteration" = + let x = `A 0 in + let t = of_list [ x; x ] in + let f (`A n) = + ignore n; + clear t + in + assert (does_raise (fun () -> iter t ~f)) + ;; + + let%test_unit "more-modification-during-iteration" = + let nested_iter_okay = ref false in + let t = of_list [ `iter; `clear ] in + assert ( + does_raise (fun () -> + iter t ~f:(function + | `iter -> + iter t ~f:ignore; + nested_iter_okay := true + | `clear -> clear t))); + assert !nested_iter_okay + ;; + + let%test_unit "modification-during-filter" = + let reached_unreachable = ref false in + let t = of_list [ `clear; `unreachable ] in + let f x = + match x with + | `clear -> + clear t; false - in - assert (does_raise (fun () -> filter_inplace t ~f)); - (* even though we said to drop the first element, the aborted call to [filter_inplace] + | `unreachable -> + reached_unreachable := true; + false + in + assert (does_raise (fun () -> filter t ~f)); + assert (not !reached_unreachable) + ;; + + let%test_unit "modification-during-filter-inplace" = + let reached_unreachable = ref false in + let t = of_list [ `drop_this; `enqueue_new_element; `unreachable ] in + let f x = + (match x with + | `drop_this | `new_element -> () + | `enqueue_new_element -> enqueue t `new_element + | `unreachable -> reached_unreachable := true); + false + in + assert (does_raise (fun () -> filter_inplace t ~f)); + (* even though we said to drop the first element, the aborted call to [filter_inplace] shouldn't have made that change *) - (match peek_exn t with - | `drop_this -> () - | `new_element | `enqueue_new_element | `unreachable -> - failwith "Expected the first element to be `drop_this"); - assert (not !reached_unreachable) - ;; - - let%test_unit "filter-inplace-during-iteration" = - let reached_unreachable = ref false in - let t = of_list [ `filter_inplace; `unreachable ] in - let f x = - match x with - | `filter_inplace -> filter_inplace t ~f:(fun _ -> false) - | `unreachable -> reached_unreachable := true - in - assert (does_raise (fun () -> iter t ~f)); - assert (not !reached_unreachable) + (match peek_exn t with + | `drop_this -> () + | `new_element | `enqueue_new_element | `unreachable -> + failwith "Expected the first element to be `drop_this"); + assert (not !reached_unreachable) + ;; + + let%test_unit "filter-inplace-during-iteration" = + let reached_unreachable = ref false in + let t = of_list [ `filter_inplace; `unreachable ] in + let f x = + match x with + | `filter_inplace -> filter_inplace t ~f:(fun _ -> false) + | `unreachable -> reached_unreachable := true + in + assert (does_raise (fun () -> iter t ~f)); + assert (not !reached_unreachable) + ;; + + module Iteration = struct + type t = Iteration.t + + let start = Iteration.start + let assert_no_mutation_since_start = Iteration.assert_no_mutation_since_start + + let%expect_test "mutation-detection" = + let open Expect_test_helpers_base in + let t = of_list [ `elt ] in + let token = start t in + let `elt = get t 0 in + require_does_not_raise (fun () -> assert_no_mutation_since_start token t); + [%expect {| |}]; + enqueue t `elt; + require_does_raise (fun () -> assert_no_mutation_since_start token t); + [%expect + {| + ("mutation of queue during iteration" ( + (num_mutations 2) + (front 0) + (mask 1) + (length 2) + (elts ( + (_) + (_))))) + |}] ;; - - module Iteration = struct - type t = Iteration.t - - let start = Iteration.start - let assert_no_mutation_since_start = Iteration.assert_no_mutation_since_start - - let%expect_test "mutation-detection" = - let open Expect_test_helpers_base in - let t = of_list [ `elt ] in - let token = start t in - let `elt = get t 0 in - require_does_not_raise (fun () -> assert_no_mutation_since_start token t); - [%expect {| |}]; - enqueue t `elt; - require_does_raise (fun () -> assert_no_mutation_since_start token t); - [%expect - {| - ("mutation of queue during iteration" ( - (num_mutations 2) - (front 0) - (mask 1) - (length 2) - (elts ( - (_) - (_))))) - |}] - ;; - end end - (* This signature is here to remind us to update the unit tests whenever we - change [Queue]. *) : - module type of Queue)) -;; +end +(* This signature is here to remind us to update the unit tests whenever we + change [Queue]. *) diff --git a/test/test_random.ml b/test/test_random.ml index 728cdd3..33fd5cd 100644 --- a/test/test_random.ml +++ b/test/test_random.ml @@ -1,22 +1,19 @@ open! Import open! Random -let%test_module "State" = - (module struct - include State +module%test State = struct + include State - let%test_unit ("random int above 2^30" [@tags "64-bits-only"]) = - let state = make [| 1; 2; 3; 4; 5 |] in - for _ = 1 to 100 do - let bound = Int.shift_left 1 40 in - let n = int state bound in - if n < 0 || n >= bound - then - failwith (Printf.sprintf "random result %d out of bounds (0,%d)" n (bound - 1)) - done - ;; - end) -;; + let%test_unit ("random int above 2^30" [@tags "64-bits-only"]) = + let state = make [| 1; 2; 3; 4; 5 |] in + for _ = 1 to 100 do + let bound = Int.shift_left 1 40 in + let n = int state bound in + if n < 0 || n >= bound + then failwith (Printf.sprintf "random result %d out of bounds (0,%d)" n (bound - 1)) + done + ;; +end external random_seed : unit -> Stdlib.Obj.t = "caml_sys_random_seed" @@ -324,44 +321,42 @@ let%expect_test "char" = [%expect {| |}] ;; -let%test_module "float upper bound is inclusive despite docs" = - (module struct - (* The fact that this test passes doesn't demonstrate that the bug has gone away, +module%test [@name "float upper bound is inclusive despite docs"] _ = struct + (* The fact that this test passes doesn't demonstrate that the bug has gone away, since the test was explicitly contrived to provoke the bug. *) - (* This bug is more clearly illustrated by copying the implementation of + (* This bug is more clearly illustrated by copying the implementation of [Random.float] from the stdlib (which is just re-exported by Base). Basically, when [r1 /. scale +. r2] requires more than 53 bits of precision, and [bits2] consists of all 1s, rounding causes [rawfloat] to return 1. *) - let rawfloat bits1 bits2 = - let scale = 1073741824.0 - and r1 = Stdlib.float bits1 - and r2 = Stdlib.float bits2 in - ((r1 /. scale) +. r2) /. scale - ;; + let rawfloat bits1 bits2 = + let scale = 1073741824.0 + and r1 = Stdlib.float bits1 + and r2 = Stdlib.float bits2 in + ((r1 /. scale) +. r2) /. scale + ;; - let%expect_test "likelihood of failure" = - (* test 256 states of the random number generator, highest as 60-bit numbers, out of + let%expect_test "likelihood of failure" = + (* test 256 states of the random number generator, highest as 60-bit numbers, out of which 64 would have yield a float exactly equal to 1 if [Random.State.float] was not recursive. *) - let lbound = (1 lsl 30) - (1 lsl 8) in - let ubound = (1 lsl 30) - 1 in - let bits2 = ubound in - let failures = ref 0 in - for bits1 = lbound to ubound do - let open Float.O in - if rawfloat bits1 bits2 >= 1. then Int.incr failures - done; - let prob = Stdlib.float !failures *. 0x1p-60 in - print_s [%message "likelihood of failure" (failures : int ref) (prob : float)]; - [%expect - {| - ("likelihood of failure" - (failures 64) - (prob 5.5511151231257827E-17)) - |}] - ;; - end) -;; + let lbound = (1 lsl 30) - (1 lsl 8) in + let ubound = (1 lsl 30) - 1 in + let bits2 = ubound in + let failures = ref 0 in + for bits1 = lbound to ubound do + let open Float.O in + if rawfloat bits1 bits2 >= 1. then Int.incr failures + done; + let prob = Stdlib.float !failures *. 0x1p-60 in + print_s [%message "likelihood of failure" (failures : int ref) (prob : float)]; + [%expect + {| + ("likelihood of failure" + (failures 64) + (prob 5.5511151231257827E-17)) + |}] + ;; +end diff --git a/test/test_result.ml b/test/test_result.ml index e49115c..6f2fb17 100644 --- a/test/test_result.ml +++ b/test/test_result.ml @@ -1,60 +1,58 @@ open! Base open! Import -let%test_module "Result.Error" = - (module struct - open Result.Error.Let_syntax - - module Int_or_string = struct - type t = (int, string) Result.t [@@deriving equal, sexp_of] - end - - let%expect_test "return" = - require_equal (module Int_or_string) (return "error") (Error "error"); - [%expect {| |}] - ;; - - let%expect_test "bind Error" = - let result = - let%bind e1 = Error "e1" in - let%bind e2 = Error "e2" in - let%bind e3 = Error "e3" in - return (String.concat ~sep:"," [ e1; e2; e3 ]) - in - require_equal (module Int_or_string) result (Error "e1,e2,e3"); - [%expect {| |}] - ;; - - let%expect_test "bind Ok" = - let result = - let%bind e1 = Error "e1" in - let%bind e2 = Ok 1 in - let%bind e3 = Error "e3" in - return (String.concat ~sep:"," [ e1; e2; e3 ]) - in - require_equal (module Int_or_string) result (Ok 1); - [%expect {| |}] - ;; - - let%expect_test "map Error" = - let result = - let%map e1 = Error "e1" in - e1 ^ "!" - in - require_equal (module Int_or_string) result (Error "e1!"); - [%expect {| |}] - ;; - - let%expect_test "map Ok" = - let result = - let%map e1 = Ok 1 in - e1 ^ "!" - in - require_equal (module Int_or_string) result (Ok 1); - [%expect {| |}] - ;; - - (* The rest of the Monad functions are derived using the Monad.Make functor, which is +module%test [@name "Result.Error"] _ = struct + open Result.Error.Let_syntax + + module Int_or_string = struct + type t = (int, string) Result.t [@@deriving equal, sexp_of] + end + + let%expect_test "return" = + require_equal (module Int_or_string) (return "error") (Error "error"); + [%expect {| |}] + ;; + + let%expect_test "bind Error" = + let result = + let%bind e1 = Error "e1" in + let%bind e2 = Error "e2" in + let%bind e3 = Error "e3" in + return (String.concat ~sep:"," [ e1; e2; e3 ]) + in + require_equal (module Int_or_string) result (Error "e1,e2,e3"); + [%expect {| |}] + ;; + + let%expect_test "bind Ok" = + let result = + let%bind e1 = Error "e1" in + let%bind e2 = Ok 1 in + let%bind e3 = Error "e3" in + return (String.concat ~sep:"," [ e1; e2; e3 ]) + in + require_equal (module Int_or_string) result (Ok 1); + [%expect {| |}] + ;; + + let%expect_test "map Error" = + let result = + let%map e1 = Error "e1" in + e1 ^ "!" + in + require_equal (module Int_or_string) result (Error "e1!"); + [%expect {| |}] + ;; + + let%expect_test "map Ok" = + let result = + let%map e1 = Ok 1 in + e1 ^ "!" + in + require_equal (module Int_or_string) result (Ok 1); + [%expect {| |}] + ;; + + (* The rest of the Monad functions are derived using the Monad.Make functor, which is well-tested. *) - end) -;; +end diff --git a/test/test_sequence.ml b/test/test_sequence.ml index 91f87fd..6c74588 100644 --- a/test/test_sequence.ml +++ b/test/test_sequence.ml @@ -35,67 +35,65 @@ let%test_unit _ = [ 0, 'a'; 0, 'e'; 2, 'a'; 0, 'i'; 2, 'e'; 4, 'a'; 0, 'o'; 2, 'i'; 4, 'e'; 6, 'a' ] ;; -let%test_module "Sequence.merge*" = - (module struct - let%test_unit _ = - [%test_eq: (int, int) Merge_with_duplicates_element.t list] - (to_list - (merge_with_duplicates - (of_list [ 1; 2 ]) - (of_list [ 2; 3 ]) - (* Can't use Core_int.compare because it would be a dependency cycle. *) - ~compare:Int.compare)) - [ Left 1; Both (2, 2); Right 3 ] - ;; +module%test [@name "Sequence.merge*"] _ = struct + let%test_unit _ = + [%test_eq: (int, int) Merge_with_duplicates_element.t list] + (to_list + (merge_with_duplicates + (of_list [ 1; 2 ]) + (of_list [ 2; 3 ]) + (* Can't use Core_int.compare because it would be a dependency cycle. *) + ~compare:Int.compare)) + [ Left 1; Both (2, 2); Right 3 ] + ;; + + let%test_unit _ = + [%test_eq: (int, int) Merge_with_duplicates_element.t list] + (to_list + (merge_with_duplicates + (of_list [ 2; 1 ]) + (of_list [ 2; 3 ]) + ~compare:Int.compare)) + [ Both (2, 2); Left 1; Right 3 ] + ;; + + let test_merge_semantics ~merge ~(normalize_list : _ -> compare:(_ -> _ -> _) -> _) = + Base_quickcheck.Test.run_exn + (module struct + module Deduped_and_sorted_int_list = struct + type t = int list [@@deriving quickcheck, sexp_of] - let%test_unit _ = - [%test_eq: (int, int) Merge_with_duplicates_element.t list] - (to_list - (merge_with_duplicates - (of_list [ 2; 1 ]) - (of_list [ 2; 3 ]) - ~compare:Int.compare)) - [ Both (2, 2); Left 1; Right 3 ] - ;; + let sort t = normalize_list t ~compare:Int.compare - let test_merge_semantics ~merge ~(normalize_list : _ -> compare:(_ -> _ -> _) -> _) = - Base_quickcheck.Test.run_exn - (module struct - module Deduped_and_sorted_int_list = struct - type t = int list [@@deriving quickcheck, sexp_of] - - let sort t = normalize_list t ~compare:Int.compare - - let quickcheck_generator = - Base_quickcheck.Generator.map quickcheck_generator ~f:sort - ;; - - let quickcheck_shrinker = - Base_quickcheck.Shrinker.map quickcheck_shrinker ~f:sort ~f_inverse:sort - ;; - end - - type t = Deduped_and_sorted_int_list.t * Deduped_and_sorted_int_list.t - [@@deriving quickcheck, sexp_of] - end) - ~f:(fun (xs, ys) -> - [%test_result: int list] - (Sequence.to_list - (merge (Sequence.of_list xs) (Sequence.of_list ys) ~compare:Int.compare)) - ~expect:(normalize_list (xs @ ys) ~compare:Int.compare)) - ;; + let quickcheck_generator = + Base_quickcheck.Generator.map quickcheck_generator ~f:sort + ;; - let%test_unit "merge_deduped_and_sorted" = - test_merge_semantics - ~merge:Sequence.merge_deduped_and_sorted - ~normalize_list:List.dedup_and_sort - ;; + let quickcheck_shrinker = + Base_quickcheck.Shrinker.map quickcheck_shrinker ~f:sort ~f_inverse:sort + ;; + end - let%test_unit "merge_sorted" = - test_merge_semantics ~merge:Sequence.merge_sorted ~normalize_list:List.sort - ;; - end) -;; + type t = Deduped_and_sorted_int_list.t * Deduped_and_sorted_int_list.t + [@@deriving quickcheck, sexp_of] + end) + ~f:(fun (xs, ys) -> + [%test_result: int list] + (Sequence.to_list + (merge (Sequence.of_list xs) (Sequence.of_list ys) ~compare:Int.compare)) + ~expect:(normalize_list (xs @ ys) ~compare:Int.compare)) + ;; + + let%test_unit "merge_deduped_and_sorted" = + test_merge_semantics + ~merge:Sequence.merge_deduped_and_sorted + ~normalize_list:List.dedup_and_sort + ;; + + let%test_unit "merge_sorted" = + test_merge_semantics ~merge:Sequence.merge_sorted ~normalize_list:List.sort + ;; +end let%test _ = fold ~f:( + ) ~init:0 (of_list [ 1; 2; 3; 4; 5 ]) = 15 let%test _ = fold ~f:( + ) ~init:0 (of_list []) = 0 @@ -656,71 +654,65 @@ let%expect_test _ = [%expect {| (0 1 2 0 1 2 0 1 2 0 1 2 0 1 2) |}] ;; -let%test_module "group" = - (module struct - let%test _ = - of_list [ 1; 2; 3; 4 ] - |> group ~break:(fun _ x -> Int.equal x 3) - |> [%compare.equal: int list t] (of_list [ [ 1; 2 ]; [ 3; 4 ] ]) - ;; - - let%test _ = - group empty ~break:(fun _ -> assert false) |> [%compare.equal: unit list t] empty - ;; - - let mis = of_list [ 'M'; 'i'; 's'; 's'; 'i'; 's'; 's'; 'i'; 'p'; 'p'; 'i' ] - - let equal_letters = - of_list - [ [ 'M' ] - ; [ 'i' ] - ; [ 's'; 's' ] - ; [ 'i' ] - ; [ 's'; 's' ] - ; [ 'i' ] - ; [ 'p'; 'p' ] - ; [ 'i' ] - ] - ;; - - let single_letters = - of_list [ [ 'M'; 'i'; 's'; 's'; 'i'; 's'; 's'; 'i'; 'p'; 'p'; 'i' ] ] - ;; - - let%test _ = - group ~break:Char.( <> ) mis |> [%compare.equal: char list t] equal_letters - ;; - - let%test _ = - group ~break:(fun _ _ -> false) mis |> [%compare.equal: char list t] single_letters - ;; - end) -;; - -let%test_module "Caml.Seq" = - (module struct - let list = [ 1; 2; 3; 4 ] - - let%expect_test "of_seq" = - list |> Stdlib.List.to_seq |> Sequence.of_seq |> Sequence.iter ~f:(printf "%d\n"); - [%expect - {| - 1 - 2 - 3 - 4 - |}] - ;; - - let%expect_test "to_seq" = - list |> Sequence.of_list |> Sequence.to_seq |> Stdlib.Seq.iter (printf "%d\n"); - [%expect - {| - 1 - 2 - 3 - 4 - |}] - ;; - end) -;; +module%test [@name "group"] _ = struct + let%test _ = + of_list [ 1; 2; 3; 4 ] + |> group ~break:(fun _ x -> Int.equal x 3) + |> [%compare.equal: int list t] (of_list [ [ 1; 2 ]; [ 3; 4 ] ]) + ;; + + let%test _ = + group empty ~break:(fun _ -> assert false) |> [%compare.equal: unit list t] empty + ;; + + let mis = of_list [ 'M'; 'i'; 's'; 's'; 'i'; 's'; 's'; 'i'; 'p'; 'p'; 'i' ] + + let equal_letters = + of_list + [ [ 'M' ] + ; [ 'i' ] + ; [ 's'; 's' ] + ; [ 'i' ] + ; [ 's'; 's' ] + ; [ 'i' ] + ; [ 'p'; 'p' ] + ; [ 'i' ] + ] + ;; + + let single_letters = + of_list [ [ 'M'; 'i'; 's'; 's'; 'i'; 's'; 's'; 'i'; 'p'; 'p'; 'i' ] ] + ;; + + let%test _ = group ~break:Char.( <> ) mis |> [%compare.equal: char list t] equal_letters + + let%test _ = + group ~break:(fun _ _ -> false) mis |> [%compare.equal: char list t] single_letters + ;; +end + +module%test [@name "Caml.Seq"] _ = struct + let list = [ 1; 2; 3; 4 ] + + let%expect_test "of_seq" = + list |> Stdlib.List.to_seq |> Sequence.of_seq |> Sequence.iter ~f:(printf "%d\n"); + [%expect + {| + 1 + 2 + 3 + 4 + |}] + ;; + + let%expect_test "to_seq" = + list |> Sequence.of_list |> Sequence.to_seq |> Stdlib.Seq.iter (printf "%d\n"); + [%expect + {| + 1 + 2 + 3 + 4 + |}] + ;; +end diff --git a/test/test_set.ml b/test/test_set.ml index 0c84fc0..f7236ab 100644 --- a/test/test_set.ml +++ b/test/test_set.ml @@ -75,18 +75,16 @@ let%expect_test "split_lt_ge" = |}] ;; -let%test_module "Poly" = - (module struct - let%test _ = length Poly.empty = 0 - let%test _ = Poly.equal (Poly.of_list []) Poly.empty +module%test Poly = struct + let%test _ = length Poly.empty = 0 + let%test _ = Poly.equal (Poly.of_list []) Poly.empty - let%test _ = - let a = Poly.of_list [ 1; 1 ] in - let b = Poly.of_list [ "a" ] in - length a = length b - ;; - end) -;; + let%test _ = + let a = Poly.of_list [ 1; 1 ] in + let b = Poly.of_list [ "a" ] in + length a = length b + ;; +end let create_balanced array = Set.of_sorted_array_unchecked (module Int) array @@ -110,177 +108,174 @@ let create_random array = the functions do not, or did not, guarantee which element or which order, so it helps to have a view of their choice and whether it is deterministic based on the elements or whether it depends on the specific "shape" or "balance" of the tree. *) -let%test_module "element selection" = - (module struct - let create ~len = - let array = Array.init len ~f:Int.succ in - [ "balanced", create_balanced array - ; "left-heavy", create_left_to_right array - ; "right-heavy", create_right_to_left array - ] - ;; +module%test [@name "element selection"] _ = struct + let create ~len = + let array = Array.init len ~f:Int.succ in + [ "balanced", create_balanced array + ; "left-heavy", create_left_to_right array + ; "right-heavy", create_right_to_left array + ] + ;; - module type S = sig - type t [@@deriving compare, sexp_of] - end + module type S = sig + type t [@@deriving compare, sexp_of] + end - let test1 (type a) (module M : S with type t = a) fn = - Ref.set_temporarily sexp_style Sexp_style.simple_pretty ~f:(fun () -> - for len = 0 to 8 do - let results = - create ~len |> List.map ~f:(fun (set_name, set) -> fn set, set_name) - in - match results |> List.Assoc.sort_and_group ~compare:[%compare: M.t] with - | [ (singleton, _) ] -> - print_s [%message "" ~_:(len : int) ~_:(singleton : M.t)] - | _ -> - print_s - [%message "" ~_:(len : int) "multiple" ~_:(results : (M.t * string) list)] - done) - ;; + let test1 (type a) (module M : S with type t = a) fn = + Ref.set_temporarily sexp_style Sexp_style.simple_pretty ~f:(fun () -> + for len = 0 to 8 do + let results = + create ~len |> List.map ~f:(fun (set_name, set) -> fn set, set_name) + in + match results |> List.Assoc.sort_and_group ~compare:[%compare: M.t] with + | [ (singleton, _) ] -> print_s [%message "" ~_:(len : int) ~_:(singleton : M.t)] + | _ -> + print_s + [%message "" ~_:(len : int) "multiple" ~_:(results : (M.t * string) list)] + done) + ;; - let test2 fn_opt fn_exn = - test1 - (module struct - type t = int Or_error.t [@@deriving compare, sexp_of] - end) - (fun set -> - let option = fn_opt set in - let result = Or_error.try_with (fun () -> fn_exn set) in - require - ([%equal: int option] option (Or_error.ok result)) - ~if_false_then_print_s: - [%lazy_message - "output mismatch" (option : int option) (result : int Or_error.t)]; - result) - ;; + let test2 fn_opt fn_exn = + test1 + (module struct + type t = int Or_error.t [@@deriving compare, sexp_of] + end) + (fun set -> + let option = fn_opt set in + let result = Or_error.try_with (fun () -> fn_exn set) in + require + ([%equal: int option] option (Or_error.ok result)) + ~if_false_then_print_s: + [%lazy_message + "output mismatch" (option : int option) (result : int Or_error.t)]; + result) + ;; - let%expect_test "min_elt" = - test2 Set.min_elt Set.min_elt_exn; - [%expect - {| - (0 (Error "Set.min_elt_exn: empty set")) - (1 (Ok 1)) - (2 (Ok 1)) - (3 (Ok 1)) - (4 (Ok 1)) - (5 (Ok 1)) - (6 (Ok 1)) - (7 (Ok 1)) - (8 (Ok 1)) - |}] - ;; + let%expect_test "min_elt" = + test2 Set.min_elt Set.min_elt_exn; + [%expect + {| + (0 (Error "Set.min_elt_exn: empty set")) + (1 (Ok 1)) + (2 (Ok 1)) + (3 (Ok 1)) + (4 (Ok 1)) + (5 (Ok 1)) + (6 (Ok 1)) + (7 (Ok 1)) + (8 (Ok 1)) + |}] + ;; - let%expect_test "max_elt" = - test2 Set.max_elt Set.max_elt_exn; - [%expect - {| - (0 (Error "Set.max_elt_exn: empty set")) - (1 (Ok 1)) - (2 (Ok 2)) - (3 (Ok 3)) - (4 (Ok 4)) - (5 (Ok 5)) - (6 (Ok 6)) - (7 (Ok 7)) - (8 (Ok 8)) - |}] - ;; + let%expect_test "max_elt" = + test2 Set.max_elt Set.max_elt_exn; + [%expect + {| + (0 (Error "Set.max_elt_exn: empty set")) + (1 (Ok 1)) + (2 (Ok 2)) + (3 (Ok 3)) + (4 (Ok 4)) + (5 (Ok 5)) + (6 (Ok 6)) + (7 (Ok 7)) + (8 (Ok 8)) + |}] + ;; - let%expect_test "choose" = - test2 Set.choose Set.choose_exn; - [%expect - {| - (0 (Error "Set.choose_exn: empty set")) - (1 (Ok 1)) - (2 multiple (((Ok 2) balanced) ((Ok 1) left-heavy) ((Ok 2) right-heavy))) - (3 multiple (((Ok 2) balanced) ((Ok 1) left-heavy) ((Ok 3) right-heavy))) - (4 multiple (((Ok 3) balanced) ((Ok 2) left-heavy) ((Ok 3) right-heavy))) - (5 multiple (((Ok 3) balanced) ((Ok 2) left-heavy) ((Ok 4) right-heavy))) - (6 multiple (((Ok 4) balanced) ((Ok 2) left-heavy) ((Ok 5) right-heavy))) - (7 (Ok 4)) - (8 multiple (((Ok 5) balanced) ((Ok 4) left-heavy) ((Ok 5) right-heavy))) - |}] - ;; + let%expect_test "choose" = + test2 Set.choose Set.choose_exn; + [%expect + {| + (0 (Error "Set.choose_exn: empty set")) + (1 (Ok 1)) + (2 multiple (((Ok 2) balanced) ((Ok 1) left-heavy) ((Ok 2) right-heavy))) + (3 multiple (((Ok 2) balanced) ((Ok 1) left-heavy) ((Ok 3) right-heavy))) + (4 multiple (((Ok 3) balanced) ((Ok 2) left-heavy) ((Ok 3) right-heavy))) + (5 multiple (((Ok 3) balanced) ((Ok 2) left-heavy) ((Ok 4) right-heavy))) + (6 multiple (((Ok 4) balanced) ((Ok 2) left-heavy) ((Ok 5) right-heavy))) + (7 (Ok 4)) + (8 multiple (((Ok 5) balanced) ((Ok 4) left-heavy) ((Ok 5) right-heavy))) + |}] + ;; - let%expect_test "find" = - let f x = x land 1 = 0 in - test2 (Set.find ~f) (Set.find_exn ~f); - [%expect - {| - (0 (Error "Set.find_exn: failed to find a matching element")) - (1 (Error "Set.find_exn: failed to find a matching element")) - (2 (Ok 2)) - (3 (Ok 2)) - (4 (Ok 2)) - (5 multiple (((Ok 2) balanced) ((Ok 2) left-heavy) ((Ok 4) right-heavy))) - (6 multiple (((Ok 4) balanced) ((Ok 2) left-heavy) ((Ok 2) right-heavy))) - (7 (Ok 4)) - (8 multiple (((Ok 2) balanced) ((Ok 4) left-heavy) ((Ok 2) right-heavy))) - |}] - ;; + let%expect_test "find" = + let f x = x land 1 = 0 in + test2 (Set.find ~f) (Set.find_exn ~f); + [%expect + {| + (0 (Error "Set.find_exn: failed to find a matching element")) + (1 (Error "Set.find_exn: failed to find a matching element")) + (2 (Ok 2)) + (3 (Ok 2)) + (4 (Ok 2)) + (5 multiple (((Ok 2) balanced) ((Ok 2) left-heavy) ((Ok 4) right-heavy))) + (6 multiple (((Ok 4) balanced) ((Ok 2) left-heavy) ((Ok 2) right-heavy))) + (7 (Ok 4)) + (8 multiple (((Ok 2) balanced) ((Ok 4) left-heavy) ((Ok 2) right-heavy))) + |}] + ;; - let%expect_test "find_map" = - let f x = if x land 1 = 0 then Some (x asr 1) else None in - test1 - (module struct - type t = int option [@@deriving compare, sexp_of] - end) - (Set.find_map ~f); - [%expect - {| - (0 ()) - (1 ()) - (2 (1)) - (3 (1)) - (4 (1)) - (5 multiple (((1) balanced) ((1) left-heavy) ((2) right-heavy))) - (6 multiple (((2) balanced) ((1) left-heavy) ((1) right-heavy))) - (7 (2)) - (8 multiple (((1) balanced) ((2) left-heavy) ((1) right-heavy))) - |}] - ;; + let%expect_test "find_map" = + let f x = if x land 1 = 0 then Some (x asr 1) else None in + test1 + (module struct + type t = int option [@@deriving compare, sexp_of] + end) + (Set.find_map ~f); + [%expect + {| + (0 ()) + (1 ()) + (2 (1)) + (3 (1)) + (4 (1)) + (5 multiple (((1) balanced) ((1) left-heavy) ((2) right-heavy))) + (6 multiple (((2) balanced) ((1) left-heavy) ((1) right-heavy))) + (7 (2)) + (8 multiple (((1) balanced) ((2) left-heavy) ((1) right-heavy))) + |}] + ;; - let%expect_test "group_by" = - test1 - (module struct - type t = Set.M(Int).t list [@@deriving compare, sexp_of] - end) - ((Set.group_by [@alert "-deprecated"]) ~equiv:(fun x y -> - Int.popcount x = Int.popcount y)); - [%expect - {| - (0 ()) - (1 ((1))) - (2 ((1 2))) - (3 - multiple - ((((3) (1 2)) balanced) (((3) (1 2)) left-heavy) (((1 2) (3)) right-heavy))) - (4 - multiple - ((((1 2 4) (3)) balanced) - (((3) (1 2 4)) left-heavy) - (((1 2 4) (3)) right-heavy))) - (5 - multiple - ((((1 2 4) (3 5)) balanced) - (((3 5) (1 2 4)) left-heavy) - (((3 5) (1 2 4)) right-heavy))) - (6 - multiple - ((((3 5 6) (1 2 4)) balanced) - (((3 5 6) (1 2 4)) left-heavy) - (((1 2 4) (3 5 6)) right-heavy))) - (7 ((7) (3 5 6) (1 2 4))) - (8 - multiple - ((((7) (1 2 4 8) (3 5 6)) balanced) - (((7) (3 5 6) (1 2 4 8)) left-heavy) - (((7) (1 2 4 8) (3 5 6)) right-heavy))) - |}] - ;; - end) -;; + let%expect_test "group_by" = + test1 + (module struct + type t = Set.M(Int).t list [@@deriving compare, sexp_of] + end) + ((Set.group_by [@alert "-deprecated"]) ~equiv:(fun x y -> + Int.popcount x = Int.popcount y)); + [%expect + {| + (0 ()) + (1 ((1))) + (2 ((1 2))) + (3 + multiple + ((((3) (1 2)) balanced) (((3) (1 2)) left-heavy) (((1 2) (3)) right-heavy))) + (4 + multiple + ((((1 2 4) (3)) balanced) + (((3) (1 2 4)) left-heavy) + (((1 2 4) (3)) right-heavy))) + (5 + multiple + ((((1 2 4) (3 5)) balanced) + (((3 5) (1 2 4)) left-heavy) + (((3 5) (1 2 4)) right-heavy))) + (6 + multiple + ((((3 5 6) (1 2 4)) balanced) + (((3 5 6) (1 2 4)) left-heavy) + (((1 2 4) (3 5 6)) right-heavy))) + (7 ((7) (3 5 6) (1 2 4))) + (8 + multiple + ((((7) (1 2 4 8) (3 5 6)) balanced) + (((7) (3 5 6) (1 2 4 8)) left-heavy) + (((7) (1 2 4 8) (3 5 6)) right-heavy))) + |}] + ;; +end let%expect_test ("space" [@tags "no-js"]) = let create ~length ~construction = diff --git a/test/test_sexpable.ml b/test/test_sexpable.ml index 55d1201..7018ce4 100644 --- a/test/test_sexpable.ml +++ b/test/test_sexpable.ml @@ -1,32 +1,30 @@ open! Import open Sexpable -let%test_module "Of_stringable" = - (module struct - module Doubled_string = struct - (* Example module with a partial [of_string] function *) +module%test Of_stringable = struct + module Doubled_string = struct + (* Example module with a partial [of_string] function *) - type t = Double of string [@@deriving quickcheck] + type t = Double of string [@@deriving quickcheck] - include Of_stringable (struct - type nonrec t = t + include Of_stringable (struct + type nonrec t = t - let to_string (Double x) = x ^ x + let to_string (Double x) = x ^ x - let of_string x = - let length = String.length x in - let first_half = String.drop_suffix x (length / 2) in - let second_half = String.drop_suffix x (length / 2) in - if length % 2 = 0 && String.(first_half = second_half) - then Double first_half - else failwith [%string "Invalid doubled string %{x}"] - ;; - end) - end + let of_string x = + let length = String.length x in + let first_half = String.drop_suffix x (length / 2) in + let second_half = String.drop_suffix x (length / 2) in + if length % 2 = 0 && String.(first_half = second_half) + then Double first_half + else failwith [%string "Invalid doubled string %{x}"] + ;; + end) + end - let%expect_test "validate sexp grammar" = - require_ok (Sexp_grammar_validation.validate_grammar (module Doubled_string)); - [%expect {| String |}] - ;; - end) -;; + let%expect_test "validate sexp grammar" = + require_ok (Sexp_grammar_validation.validate_grammar (module Doubled_string)); + [%expect {| String |}] + ;; +end diff --git a/test/test_string.ml b/test/test_string.ml index 4f72d0c..a2033c7 100644 --- a/test/test_string.ml +++ b/test/test_string.ml @@ -51,36 +51,34 @@ let%expect_test "edit distance" = |}] ;; -let%test_module "concat" = - (module struct - let test ?sep list = - let from_list = concat ?sep list in - let from_array = concat_array ?sep (Array.of_list list) in - require_equal (module String) from_list from_array; - print_s [%sexp (from_list : string)] - ;; - - let%expect_test "empty" = - test [] ~sep:":"; - [%expect {| "" |}] - ;; - - let%expect_test "singleton" = - test [ "a" ]; - [%expect {| a |}] - ;; - - let%expect_test "empty separator" = - test [ "a"; "b" ]; - [%expect {| ab |}] - ;; - - let%expect_test "non-empty separator" = - test [ "a"; "b" ] ~sep:":"; - [%expect {| a:b |}] - ;; - end) -;; +module%test [@name "concat"] _ = struct + let test ?sep list = + let from_list = concat ?sep list in + let from_array = concat_array ?sep (Array.of_list list) in + require_equal (module String) from_list from_array; + print_s [%sexp (from_list : string)] + ;; + + let%expect_test "empty" = + test [] ~sep:":"; + [%expect {| "" |}] + ;; + + let%expect_test "singleton" = + test [ "a" ]; + [%expect {| a |}] + ;; + + let%expect_test "empty separator" = + test [ "a"; "b" ]; + [%expect {| ab |}] + ;; + + let%expect_test "non-empty separator" = + test [ "a"; "b" ] ~sep:":"; + [%expect {| a:b |}] + ;; +end let%expect_test "to_list and to_list_rev" = let test s = @@ -155,307 +153,293 @@ let%expect_test "sub/unsafe_sub" = [%expect {| (Invalid_argument "pos + len past end: 10 + 1 > 10") |}] ;; -let%test_module "Unicode" = - (module struct - let encodings : (module Utf) list = - [ (module Utf8) - ; (module Utf16le) - ; (module Utf16be) - ; (module Utf32le) - ; (module Utf32be) - ] - ;; - - let test_validity (module Utf : Utf) string ~expect = - let actual = (Utf.is_valid string : bool) in - match actual, expect with - | true, true | false, false -> () - | true, false -> print_cr [%message "expected valid result, got invalid"] - | false, true -> print_cr [%message "expected invalid result, got valid"] - ;; - - let%expect_test "valid" = - let test_validity = test_validity ~expect:true in - (* Valid UTF-8 encoding for ASCII 'a' *) - test_validity (module Utf8) "\x61"; - [%expect {| |}]; - (* Valid UTF-16LE encoding for ASCII 'a' *) - test_validity (module Utf16le) "\x61\x00"; - [%expect {| |}]; - (* Valid UTF-16BE encoding for ASCII 'a' *) - test_validity (module Utf16be) "\x00\x61"; - [%expect {| |}]; - (* Valid UTF-32LE encoding for ASCII 'a' *) - test_validity (module Utf32le) "\x61\x00\x00\x00"; - [%expect {| |}]; - (* Valid UTF-32BE encoding for ASCII 'a' *) - test_validity (module Utf32be) "\x00\x00\x00\x61"; - [%expect {| |}]; - (* Valid UTF-8 encoding for 'aö' *) - test_validity (module Utf8) "\x61\xc3\xb6"; - [%expect {| |}]; - (* Valid UTF-16LE encoding for 'aö' *) - test_validity (module Utf16le) "\x61\x00\xf6\x00"; - [%expect {| |}]; - (* Valid UTF-16BE encoding for 'aö' *) - test_validity (module Utf16be) "\x00\x61\x00\xf6"; - [%expect {| |}]; - (* Valid UTF-32LE encoding for 'aö' *) - test_validity (module Utf32le) "\x61\x00\x00\x00\xf6\x00\x00\x00"; - [%expect {| |}]; - (* Valid UTF-32BE encoding for 'aö' *) - test_validity (module Utf32be) "\x00\x00\x00\x61\x00\x00\x00\xf6"; - [%expect {| |}]; - (* Valid UTF-16LE encoding for '𝕬' *) - test_validity (module Utf16le) "\x35\xd8\x6c\xdd"; - [%expect {| |}]; - (* Valid UTF-16LE encoding for '𝕬' *) - test_validity (module Utf16be) "\xd8\x35\xdd\x6c"; - [%expect {| |}] - ;; - - let%expect_test "invalid" = - let test_validity = test_validity ~expect:false in - (* Invalid UTF-8: Premature end-of-string after start of 2-byte sequence *) - test_validity (module Utf8) "\x61\xc3"; - [%expect {| |}]; - (* Invalid UTF-8: second byte does not start with bits '10' *) - test_validity (module Utf8) "\xc3\x28"; - [%expect {| |}]; - (* Invalid UTF-8: surrogate pair encoded in UTF-8 *) - test_validity (module Utf8) "\xed\xa0\x80"; - [%expect {| |}]; - (* Invalid UTF-8: ASCII character "/" (U+002F) is encoded in an overlong form *) - test_validity (module Utf8) "\xc0\xaf"; - [%expect {| |}]; - (* Invalid UTF-8: The encoded value is outside the Unicode code point range *) - test_validity (module Utf8) "\xc0\x28"; - [%expect {| |}]; - (* Invalid UTF-16LE: Single byte is not a complete UTF-16 character *) - test_validity (module Utf16le) "\x61"; - [%expect {| |}]; - (* Invalid UTF-16BE: Single byte is not a complete UTF-16 character *) - test_validity (module Utf16be) "\x61"; - [%expect {| |}]; - (* Invalid UTF-32LE: Only 3 bytes is not a complete UTF-32 character *) - test_validity (module Utf32le) "\x61\x00\x00"; - [%expect {| |}]; - (* Invalid UTF-32BE: Only 3 bytes is not a complete UTF-32 character *) - test_validity (module Utf32be) "\x61\x00\x00"; - [%expect {| |}]; - (* Invalid UTF-16LE: high surrogate not followed by low surrogate *) - test_validity (module Utf16le) "\x00\xd8\x00\x00"; - [%expect {| |}]; - (* Invalid UTF-16BE: high surrogate not followed by low surrogate *) - test_validity (module Utf16be) "\xd8\x00\x00\x00"; - [%expect {| |}]; - (* Invalid UTF-32LE: surrogate pair encoded in UTF-32 *) - test_validity (module Utf32le) "\x00\xD8\x00\x00"; - [%expect {| |}]; - (* Invalid UTF-32BE: surrogate pair encoded in UTF-32 *) - test_validity (module Utf32be) "\x00\x00\xD8\x00"; - [%expect {| |}] - ;; - - let test_conversions utf8 = - let utf8 = - match Utf8.of_string utf8 with - | utf8 -> utf8 - | exception exn -> - print_s [%sexp (exn : exn)]; - Utf8.sanitize utf8 - in - let uchars = Utf8.to_list utf8 in - printf "Appearance: %s\n" (Utf8.of_list uchars :> string); - print_s [%sexp (uchars : Uchar.t list)]; - List.iter encodings ~f:(fun (module Utf : Utf) -> - let codec_name = Utf.codec_name in - let t = Utf.of_list uchars in - print_s [%sexp (codec_name : string), (t : Utf.t)]; - let round_trip = Utf.to_list t in - if not ([%equal: Uchar.t list] uchars round_trip) - then - print_cr - [%message - "encoding does not round trip" - (codec_name : string) - (uchars : Uchar.t list) - ~string:(t : Utf.t) - (round_trip : Uchar.t list)]) - ;; - - let%expect_test "conversions" = - test_conversions "abc"; - [%expect - {| - Appearance: abc - (U+0061 U+0062 U+0063) - (UTF-8 abc) - (UTF-16LE "a\000b\000c\000") - (UTF-16BE "\000a\000b\000c") - (UTF-32LE "a\000\000\000b\000\000\000c\000\000\000") - (UTF-32BE "\000\000\000a\000\000\000b\000\000\000c") - |}]; - test_conversions "\u{0065}\u{0301}"; - [%expect - {| - Appearance: é - (U+0065 U+0301) - (UTF-8 "e\204\129") - (UTF-16LE "e\000\001\003") - (UTF-16BE "\000e\003\001") - (UTF-32LE "e\000\000\000\001\003\000\000") - (UTF-32BE "\000\000\000e\000\000\003\001") - |}]; - test_conversions "\u{0063}\u{030C}"; - [%expect - {| - Appearance: č - (U+0063 U+030C) - (UTF-8 "c\204\140") - (UTF-16LE "c\000\012\003") - (UTF-16BE "\000c\003\012") - (UTF-32LE "c\000\000\000\012\003\000\000") - (UTF-32BE "\000\000\000c\000\000\003\012") - |}]; - test_conversions "\u{0E28}\u{0E34}"; - [%expect - {| - Appearance: ศิ - (U+0E28 U+0E34) - (UTF-8 "\224\184\168\224\184\180") - (UTF-16LE "(\0144\014") - (UTF-16BE "\014(\0144") - (UTF-32LE "(\014\000\0004\014\000\000") - (UTF-32BE "\000\000\014(\000\000\0144") - |}]; - test_conversions "\u{1D11E}"; - [%expect - {| - Appearance: 𝄞 - (U+1D11E) - (UTF-8 "\240\157\132\158") - (UTF-16LE "4\216\030\221") - (UTF-16BE "\2164\221\030") - (UTF-32LE "\030\209\001\000") - (UTF-32BE "\000\001\209\030") - |}]; - test_conversions "\u{1D56C}"; - [%expect - {| - Appearance: 𝕬 - (U+1D56C) - (UTF-8 "\240\157\149\172") - (UTF-16LE "5\216l\221") - (UTF-16BE "\2165\221l") - (UTF-32LE "l\213\001\000") - (UTF-32BE "\000\001\213l") - |}]; - test_conversions "\xFF\xFF"; - [%expect - {| - ("Base.String.Utf8.of_string: invalid UTF-8" "\255\255") - Appearance: �� - (U+FFFD U+FFFD) - (UTF-8 "\239\191\189\239\191\189") - (UTF-16LE "\253\255\253\255") - (UTF-16BE "\255\253\255\253") - (UTF-32LE "\253\255\000\000\253\255\000\000") - (UTF-32BE "\000\000\255\253\000\000\255\253") - |}] - ;; - - let%expect_test "Test [get] used at an invalid offset" = - let utf8 = Utf8.of_string "αβ" in - printf "%s\n" (utf8 :> string); - [%expect {| αβ |}]; - print_s [%message "" ~_:(utf8 : Utf8.t) ~_:(Utf8.to_list utf8 : Uchar.t list)]; - [%expect {| ("\206\177\206\178" (U+03B1 U+03B2)) |}]; - require_does_raise (fun () -> Utf8.get utf8 ~byte_pos:1); - [%expect - {| - ("Base.String.Utf8.get: invalid UTF-8 encoding at given position" - "\206\177\206\178" - (pos 1)) - |}] - ;; - end) -;; - -let%test_module "Caseless Suffix/Prefix" = - (module struct - let%test _ = Caseless.is_suffix "OCaml" ~suffix:"AmL" - let%test _ = Caseless.is_suffix "OCaml" ~suffix:"ocAmL" - let%test _ = Caseless.is_suffix "a@!$b" ~suffix:"a@!$B" - let%test _ = not (Caseless.is_suffix "a@!$b" ~suffix:"C@!$B") - let%test _ = not (Caseless.is_suffix "aa" ~suffix:"aaa") - let%test _ = Caseless.is_prefix "OCaml" ~prefix:"oc" - let%test _ = Caseless.is_prefix "OCaml" ~prefix:"ocAmL" - let%test _ = Caseless.is_prefix "a@!$b" ~prefix:"a@!$B" - let%test _ = not (Caseless.is_prefix "a@!$b" ~prefix:"a@!$C") - let%test _ = not (Caseless.is_prefix "aa" ~prefix:"aaa") - end) -;; - -let%test_module "Caseless Substring" = - (module struct - let%test _ = Caseless.is_substring "OCaml" ~substring:"AmL" - let%test _ = Caseless.is_substring "OCaml" ~substring:"oc" - let%test _ = Caseless.is_substring "OCaml" ~substring:"ocAmL" - let%test _ = Caseless.is_substring "a@!$b" ~substring:"a@!$B" - let%test _ = not (Caseless.is_substring "a@!$b" ~substring:"C@!$B") - let%test _ = not (Caseless.is_substring "a@!$b" ~substring:"a@!$C") - let%test _ = not (Caseless.is_substring "aa" ~substring:"aaa") - let%test _ = not (Caseless.is_substring "aa" ~substring:"AAA") - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module struct - type t = string * string [@@deriving quickcheck, sexp_of] - end) - ~f:(fun (t, substring) -> - let actual = Caseless.is_substring t ~substring in - let expect = is_substring (lowercase t) ~substring:(lowercase substring) in - [%test_result: bool] actual ~expect) - ;; - end) -;; - -let%test_module "Caseless Comparable" = - (module struct - (* examples from docs *) - let%test _ = Caseless.equal "OCaml" "ocaml" - let%test _ = Caseless.("apple" < "Banana") - let%test _ = Caseless.("aa" < "aaa") - let%test _ = Int.( <> ) (Caseless.compare "apple" "Banana") (compare "apple" "Banana") - let%test _ = Caseless.equal "XxX" "xXx" - let%test _ = Caseless.("XxX" < "xXxX") - let%test _ = Caseless.("XxXx" > "xXx") - - let%test _ = - List.is_sorted ~compare:Caseless.compare [ "Apples"; "bananas"; "Carrots" ] - ;; - end) -;; - -let%test_module "Caseless Hashable" = - (module struct - let%test _ = - Int.( <> ) (hash "x") (hash "X") - && Int.( = ) (Caseless.hash "x") (Caseless.hash "X") - ;; - - let%test _ = Int.( = ) (Caseless.hash "OCaml") (Caseless.hash "ocaml") - let%test _ = Int.( <> ) (Caseless.hash "aaa") (Caseless.hash "aaaa") - let%test _ = Int.( <> ) (Caseless.hash "aaa") (Caseless.hash "aab") - - let%test _ = - let tbl = Hashtbl.create (module Caseless) in - Hashtbl.add_exn tbl ~key:"x" ~data:7; - [%compare.equal: int option] (Hashtbl.find tbl "X") (Some 7) - ;; - end) -;; +module%test Unicode = struct + let encodings : (module Utf) list = + [ (module Utf8) + ; (module Utf16le) + ; (module Utf16be) + ; (module Utf32le) + ; (module Utf32be) + ] + ;; + + let test_validity (module Utf : Utf) string ~expect = + let actual = (Utf.is_valid string : bool) in + match actual, expect with + | true, true | false, false -> () + | true, false -> print_cr [%message "expected valid result, got invalid"] + | false, true -> print_cr [%message "expected invalid result, got valid"] + ;; + + let%expect_test "valid" = + let test_validity = test_validity ~expect:true in + (* Valid UTF-8 encoding for ASCII 'a' *) + test_validity (module Utf8) "\x61"; + [%expect {| |}]; + (* Valid UTF-16LE encoding for ASCII 'a' *) + test_validity (module Utf16le) "\x61\x00"; + [%expect {| |}]; + (* Valid UTF-16BE encoding for ASCII 'a' *) + test_validity (module Utf16be) "\x00\x61"; + [%expect {| |}]; + (* Valid UTF-32LE encoding for ASCII 'a' *) + test_validity (module Utf32le) "\x61\x00\x00\x00"; + [%expect {| |}]; + (* Valid UTF-32BE encoding for ASCII 'a' *) + test_validity (module Utf32be) "\x00\x00\x00\x61"; + [%expect {| |}]; + (* Valid UTF-8 encoding for 'aö' *) + test_validity (module Utf8) "\x61\xc3\xb6"; + [%expect {| |}]; + (* Valid UTF-16LE encoding for 'aö' *) + test_validity (module Utf16le) "\x61\x00\xf6\x00"; + [%expect {| |}]; + (* Valid UTF-16BE encoding for 'aö' *) + test_validity (module Utf16be) "\x00\x61\x00\xf6"; + [%expect {| |}]; + (* Valid UTF-32LE encoding for 'aö' *) + test_validity (module Utf32le) "\x61\x00\x00\x00\xf6\x00\x00\x00"; + [%expect {| |}]; + (* Valid UTF-32BE encoding for 'aö' *) + test_validity (module Utf32be) "\x00\x00\x00\x61\x00\x00\x00\xf6"; + [%expect {| |}]; + (* Valid UTF-16LE encoding for '𝕬' *) + test_validity (module Utf16le) "\x35\xd8\x6c\xdd"; + [%expect {| |}]; + (* Valid UTF-16LE encoding for '𝕬' *) + test_validity (module Utf16be) "\xd8\x35\xdd\x6c"; + [%expect {| |}] + ;; + + let%expect_test "invalid" = + let test_validity = test_validity ~expect:false in + (* Invalid UTF-8: Premature end-of-string after start of 2-byte sequence *) + test_validity (module Utf8) "\x61\xc3"; + [%expect {| |}]; + (* Invalid UTF-8: second byte does not start with bits '10' *) + test_validity (module Utf8) "\xc3\x28"; + [%expect {| |}]; + (* Invalid UTF-8: surrogate pair encoded in UTF-8 *) + test_validity (module Utf8) "\xed\xa0\x80"; + [%expect {| |}]; + (* Invalid UTF-8: ASCII character "/" (U+002F) is encoded in an overlong form *) + test_validity (module Utf8) "\xc0\xaf"; + [%expect {| |}]; + (* Invalid UTF-8: The encoded value is outside the Unicode code point range *) + test_validity (module Utf8) "\xc0\x28"; + [%expect {| |}]; + (* Invalid UTF-16LE: Single byte is not a complete UTF-16 character *) + test_validity (module Utf16le) "\x61"; + [%expect {| |}]; + (* Invalid UTF-16BE: Single byte is not a complete UTF-16 character *) + test_validity (module Utf16be) "\x61"; + [%expect {| |}]; + (* Invalid UTF-32LE: Only 3 bytes is not a complete UTF-32 character *) + test_validity (module Utf32le) "\x61\x00\x00"; + [%expect {| |}]; + (* Invalid UTF-32BE: Only 3 bytes is not a complete UTF-32 character *) + test_validity (module Utf32be) "\x61\x00\x00"; + [%expect {| |}]; + (* Invalid UTF-16LE: high surrogate not followed by low surrogate *) + test_validity (module Utf16le) "\x00\xd8\x00\x00"; + [%expect {| |}]; + (* Invalid UTF-16BE: high surrogate not followed by low surrogate *) + test_validity (module Utf16be) "\xd8\x00\x00\x00"; + [%expect {| |}]; + (* Invalid UTF-32LE: surrogate pair encoded in UTF-32 *) + test_validity (module Utf32le) "\x00\xD8\x00\x00"; + [%expect {| |}]; + (* Invalid UTF-32BE: surrogate pair encoded in UTF-32 *) + test_validity (module Utf32be) "\x00\x00\xD8\x00"; + [%expect {| |}] + ;; + + let test_conversions utf8 = + let utf8 = + match Utf8.of_string utf8 with + | utf8 -> utf8 + | exception exn -> + print_s [%sexp (exn : exn)]; + Utf8.sanitize utf8 + in + let uchars = Utf8.to_list utf8 in + printf "Appearance: %s\n" (Utf8.of_list uchars :> string); + print_s [%sexp (uchars : Uchar.t list)]; + List.iter encodings ~f:(fun (module Utf : Utf) -> + let codec_name = Utf.codec_name in + let t = Utf.of_list uchars in + print_s [%sexp (codec_name : string), (t : Utf.t)]; + let round_trip = Utf.to_list t in + if not ([%equal: Uchar.t list] uchars round_trip) + then + print_cr + [%message + "encoding does not round trip" + (codec_name : string) + (uchars : Uchar.t list) + ~string:(t : Utf.t) + (round_trip : Uchar.t list)]) + ;; + + let%expect_test "conversions" = + test_conversions "abc"; + [%expect + {| + Appearance: abc + (U+0061 U+0062 U+0063) + (UTF-8 abc) + (UTF-16LE "a\000b\000c\000") + (UTF-16BE "\000a\000b\000c") + (UTF-32LE "a\000\000\000b\000\000\000c\000\000\000") + (UTF-32BE "\000\000\000a\000\000\000b\000\000\000c") + |}]; + test_conversions "\u{0065}\u{0301}"; + [%expect + {| + Appearance: é + (U+0065 U+0301) + (UTF-8 "e\204\129") + (UTF-16LE "e\000\001\003") + (UTF-16BE "\000e\003\001") + (UTF-32LE "e\000\000\000\001\003\000\000") + (UTF-32BE "\000\000\000e\000\000\003\001") + |}]; + test_conversions "\u{0063}\u{030C}"; + [%expect + {| + Appearance: č + (U+0063 U+030C) + (UTF-8 "c\204\140") + (UTF-16LE "c\000\012\003") + (UTF-16BE "\000c\003\012") + (UTF-32LE "c\000\000\000\012\003\000\000") + (UTF-32BE "\000\000\000c\000\000\003\012") + |}]; + test_conversions "\u{0E28}\u{0E34}"; + [%expect + {| + Appearance: ศิ + (U+0E28 U+0E34) + (UTF-8 "\224\184\168\224\184\180") + (UTF-16LE "(\0144\014") + (UTF-16BE "\014(\0144") + (UTF-32LE "(\014\000\0004\014\000\000") + (UTF-32BE "\000\000\014(\000\000\0144") + |}]; + test_conversions "\u{1D11E}"; + [%expect + {| + Appearance: 𝄞 + (U+1D11E) + (UTF-8 "\240\157\132\158") + (UTF-16LE "4\216\030\221") + (UTF-16BE "\2164\221\030") + (UTF-32LE "\030\209\001\000") + (UTF-32BE "\000\001\209\030") + |}]; + test_conversions "\u{1D56C}"; + [%expect + {| + Appearance: 𝕬 + (U+1D56C) + (UTF-8 "\240\157\149\172") + (UTF-16LE "5\216l\221") + (UTF-16BE "\2165\221l") + (UTF-32LE "l\213\001\000") + (UTF-32BE "\000\001\213l") + |}]; + test_conversions "\xFF\xFF"; + [%expect + {| + ("Base.String.Utf8.of_string: invalid UTF-8" "\255\255") + Appearance: �� + (U+FFFD U+FFFD) + (UTF-8 "\239\191\189\239\191\189") + (UTF-16LE "\253\255\253\255") + (UTF-16BE "\255\253\255\253") + (UTF-32LE "\253\255\000\000\253\255\000\000") + (UTF-32BE "\000\000\255\253\000\000\255\253") + |}] + ;; + + let%expect_test "Test [get] used at an invalid offset" = + let utf8 = Utf8.of_string "αβ" in + printf "%s\n" (utf8 :> string); + [%expect {| αβ |}]; + print_s [%message "" ~_:(utf8 : Utf8.t) ~_:(Utf8.to_list utf8 : Uchar.t list)]; + [%expect {| ("\206\177\206\178" (U+03B1 U+03B2)) |}]; + require_does_raise (fun () -> Utf8.get utf8 ~byte_pos:1); + [%expect + {| + ("Base.String.Utf8.get: invalid UTF-8 encoding at given position" + "\206\177\206\178" + (pos 1)) + |}] + ;; +end + +module%test [@name "Caseless Suffix/Prefix"] _ = struct + let%test _ = Caseless.is_suffix "OCaml" ~suffix:"AmL" + let%test _ = Caseless.is_suffix "OCaml" ~suffix:"ocAmL" + let%test _ = Caseless.is_suffix "a@!$b" ~suffix:"a@!$B" + let%test _ = not (Caseless.is_suffix "a@!$b" ~suffix:"C@!$B") + let%test _ = not (Caseless.is_suffix "aa" ~suffix:"aaa") + let%test _ = Caseless.is_prefix "OCaml" ~prefix:"oc" + let%test _ = Caseless.is_prefix "OCaml" ~prefix:"ocAmL" + let%test _ = Caseless.is_prefix "a@!$b" ~prefix:"a@!$B" + let%test _ = not (Caseless.is_prefix "a@!$b" ~prefix:"a@!$C") + let%test _ = not (Caseless.is_prefix "aa" ~prefix:"aaa") +end + +module%test [@name "Caseless Substring"] _ = struct + let%test _ = Caseless.is_substring "OCaml" ~substring:"AmL" + let%test _ = Caseless.is_substring "OCaml" ~substring:"oc" + let%test _ = Caseless.is_substring "OCaml" ~substring:"ocAmL" + let%test _ = Caseless.is_substring "a@!$b" ~substring:"a@!$B" + let%test _ = not (Caseless.is_substring "a@!$b" ~substring:"C@!$B") + let%test _ = not (Caseless.is_substring "a@!$b" ~substring:"a@!$C") + let%test _ = not (Caseless.is_substring "aa" ~substring:"aaa") + let%test _ = not (Caseless.is_substring "aa" ~substring:"AAA") + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module struct + type t = string * string [@@deriving quickcheck, sexp_of] + end) + ~f:(fun (t, substring) -> + let actual = Caseless.is_substring t ~substring in + let expect = is_substring (lowercase t) ~substring:(lowercase substring) in + [%test_result: bool] actual ~expect) + ;; +end + +module%test [@name "Caseless Comparable"] _ = struct + (* examples from docs *) + let%test _ = Caseless.equal "OCaml" "ocaml" + let%test _ = Caseless.("apple" < "Banana") + let%test _ = Caseless.("aa" < "aaa") + let%test _ = Int.( <> ) (Caseless.compare "apple" "Banana") (compare "apple" "Banana") + let%test _ = Caseless.equal "XxX" "xXx" + let%test _ = Caseless.("XxX" < "xXxX") + let%test _ = Caseless.("XxXx" > "xXx") + let%test _ = List.is_sorted ~compare:Caseless.compare [ "Apples"; "bananas"; "Carrots" ] +end + +module%test [@name "Caseless Hashable"] _ = struct + let%test _ = + Int.( <> ) (hash "x") (hash "X") && Int.( = ) (Caseless.hash "x") (Caseless.hash "X") + ;; + + let%test _ = Int.( = ) (Caseless.hash "OCaml") (Caseless.hash "ocaml") + let%test _ = Int.( <> ) (Caseless.hash "aaa") (Caseless.hash "aaaa") + let%test _ = Int.( <> ) (Caseless.hash "aaa") (Caseless.hash "aab") + + let%test _ = + let tbl = Hashtbl.create (module Caseless) in + Hashtbl.add_exn tbl ~key:"x" ~data:7; + [%compare.equal: int option] (Hashtbl.find tbl "X") (Some 7) + ;; +end let%test _ = not (contains "" 'a') let%test _ = contains "a" 'a' @@ -470,277 +454,261 @@ let%test _ = not (contains "abcd" 'd' ~pos:1 ~len:2) let%test _ = contains "abcd" 'd' ~pos:1 let%test _ = not (contains "abcd" 'a' ~pos:1) -let%test_module "Search_pattern" = - (module struct - open Search_pattern - - let%test_module "Search_pattern.create" = - (module struct - let prefix s n = sub s ~pos:0 ~len:n - let suffix s n = sub s ~pos:(length s - n) ~len:n - - let slow_create pattern ~case_sensitive = - let string_equal = - if case_sensitive then String.equal else String.Caseless.equal - in - (* Compute the longest prefix-suffix array from definition, O(n^3) *) - let n = length pattern in - let kmp_array = Array.create ~len:n (-1) in - for i = 0 to n - 1 do - let x = prefix pattern (i + 1) in - for j = 0 to i do - if string_equal (prefix x j) (suffix x j) then kmp_array.(i) <- j - done - done; - ({ pattern; kmp_array; case_sensitive } : Private.t) - ;; - - let test_both ({ pattern; case_sensitive; kmp_array = _ } as expected : Private.t) - = - let create_repr = Private.representation (create pattern ~case_sensitive) in - let slow_create_repr = slow_create pattern ~case_sensitive in - require_equal (module Private) create_repr expected; - require_equal (module Private) slow_create_repr expected - ;; - - let cmp_both pattern ~case_sensitive = - let create_repr = Private.representation (create pattern ~case_sensitive) in - let slow_create_repr = slow_create pattern ~case_sensitive in - require_equal (module Private) create_repr slow_create_repr - ;; - - let%expect_test _ = - List.iter [%all: bool] ~f:(fun case_sensitive -> - test_both { pattern = ""; case_sensitive; kmp_array = [||] }) - ;; - - let%expect_test _ = - List.iter [%all: bool] ~f:(fun case_sensitive -> - test_both - { pattern = "ababab"; case_sensitive; kmp_array = [| 0; 0; 1; 2; 3; 4 |] }) - ;; - - let%expect_test _ = - List.iter [%all: bool] ~f:(fun case_sensitive -> - test_both - { pattern = "abaCabaD" - ; case_sensitive - ; kmp_array = [| 0; 0; 1; 0; 1; 2; 3; 0 |] - }) - ;; - - let%expect_test _ = - List.iter [%all: bool] ~f:(fun case_sensitive -> - test_both - { pattern = "abaCabaDabaCabaCabaDabaCabaEabab" - ; case_sensitive - ; kmp_array = - [| 0 - ; 0 - ; 1 - ; 0 - ; 1 - ; 2 - ; 3 - ; 0 - ; 1 - ; 2 - ; 3 - ; 4 - ; 5 - ; 6 - ; 7 - ; 4 - ; 5 - ; 6 - ; 7 - ; 8 - ; 9 - ; 10 - ; 11 - ; 12 - ; 13 - ; 14 - ; 15 - ; 0 - ; 1 - ; 2 - ; 3 - ; 2 - |] - }) - ;; - - let%expect_test _ = - test_both { pattern = "aaA"; case_sensitive = true; kmp_array = [| 0; 1; 0 |] } - ;; - - let%expect_test _ = - test_both { pattern = "aaA"; case_sensitive = false; kmp_array = [| 0; 1; 2 |] } - ;; - - let%expect_test _ = - test_both - { pattern = "aAaAaA" - ; case_sensitive = true - ; kmp_array = [| 0; 0; 1; 2; 3; 4 |] - } - ;; - - let%expect_test _ = - test_both - { pattern = "aAaAaA" - ; case_sensitive = false - ; kmp_array = [| 0; 1; 2; 3; 4; 5 |] - } - ;; - - let rec x k = - if Int.( < ) k 0 - then "" - else ( - let b = x (k - 1) in - b ^ make 1 (Stdlib.Char.unsafe_chr (65 + k)) ^ b) - ;; - - let%expect_test _ = - List.iter [%all: bool] ~f:(fun case_sensitive -> - cmp_both ~case_sensitive (x 10)) - ;; - - let%expect_test _ = - List.iter [%all: bool] ~f:(fun case_sensitive -> - cmp_both ~case_sensitive (x 5 ^ "E" ^ x 4 ^ "D" ^ x 3 ^ "B" ^ x 2 ^ "C" ^ x 3)) - ;; - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module struct - type t = string [@@deriving quickcheck, sexp_of] - end) - ~f:(fun pattern -> - let case_insensitive = - Private.representation (create pattern ~case_sensitive:false) - in - let case_sensitive_but_lowercase = - Private.representation (create (lowercase pattern) ~case_sensitive:true) - in - [%test_result: String.Caseless.t] - case_insensitive.pattern - ~expect:case_sensitive_but_lowercase.pattern; - [%test_result: int array] - case_insensitive.kmp_array - ~expect:case_sensitive_but_lowercase.kmp_array) - ;; - end) +module%test Search_pattern = struct + open Search_pattern + + module%test [@name "Search_pattern.create"] _ = struct + let prefix s n = sub s ~pos:0 ~len:n + let suffix s n = sub s ~pos:(length s - n) ~len:n + + let slow_create pattern ~case_sensitive = + let string_equal = if case_sensitive then String.equal else String.Caseless.equal in + (* Compute the longest prefix-suffix array from definition, O(n^3) *) + let n = length pattern in + let kmp_array = Array.create ~len:n (-1) in + for i = 0 to n - 1 do + let x = prefix pattern (i + 1) in + for j = 0 to i do + if string_equal (prefix x j) (suffix x j) then kmp_array.(i) <- j + done + done; + ({ pattern; kmp_array; case_sensitive } : Private.t) + ;; + + let test_both ({ pattern; case_sensitive; kmp_array = _ } as expected : Private.t) = + let create_repr = Private.representation (create pattern ~case_sensitive) in + let slow_create_repr = slow_create pattern ~case_sensitive in + require_equal (module Private) create_repr expected; + require_equal (module Private) slow_create_repr expected + ;; + + let cmp_both pattern ~case_sensitive = + let create_repr = Private.representation (create pattern ~case_sensitive) in + let slow_create_repr = slow_create pattern ~case_sensitive in + require_equal (module Private) create_repr slow_create_repr ;; - let ( = ) = [%compare.equal: int option] - let%test _ = index (create "") ~in_:"abababac" = Some 0 - let%test _ = index ~pos:(-1) (create "") ~in_:"abababac" = None - let%test _ = index ~pos:1 (create "") ~in_:"abababac" = Some 1 - let%test _ = index ~pos:7 (create "") ~in_:"abababac" = Some 7 - let%test _ = index ~pos:8 (create "") ~in_:"abababac" = Some 8 - let%test _ = index ~pos:9 (create "") ~in_:"abababac" = None - let%test _ = index (create "abababaca") ~in_:"abababac" = None - let%test _ = index (create "abababac") ~in_:"abababac" = Some 0 - let%test _ = index ~pos:0 (create "abababac") ~in_:"abababac" = Some 0 - let%test _ = index (create "abac") ~in_:"abababac" = Some 4 - let%test _ = index ~pos:4 (create "abac") ~in_:"abababac" = Some 4 - let%test _ = index ~pos:5 (create "abac") ~in_:"abababac" = None - let%test _ = index ~pos:5 (create "abac") ~in_:"abababaca" = None - let%test _ = index ~pos:5 (create "baca") ~in_:"abababaca" = Some 5 - let%test _ = index ~pos:(-1) (create "a") ~in_:"abc" = None - let%test _ = index ~pos:2 (create "a") ~in_:"abc" = None - let%test _ = index ~pos:2 (create "c") ~in_:"abc" = Some 2 - let%test _ = index ~pos:3 (create "c") ~in_:"abc" = None - let ( = ) = [%compare.equal: bool] - let%test _ = matches (create "") "abababac" = true - let%test _ = matches (create "abababaca") "abababac" = false - let%test _ = matches (create "abababac") "abababac" = true - let%test _ = matches (create "abac") "abababac" = true - let%test _ = matches (create "abac") "abababaca" = true - let%test _ = matches (create "baca") "abababaca" = true - let%test _ = matches (create "a") "abc" = true - let%test _ = matches (create "c") "abc" = true - let ( = ) = [%compare.equal: int list] - let%test _ = index_all (create "") ~may_overlap:false ~in_:"abcd" = [ 0; 1; 2; 3; 4 ] - let%test _ = index_all (create "") ~may_overlap:true ~in_:"abcd" = [ 0; 1; 2; 3; 4 ] - let%test _ = index_all (create "abab") ~may_overlap:false ~in_:"abababab" = [ 0; 4 ] - let%test _ = index_all (create "abab") ~may_overlap:true ~in_:"abababab" = [ 0; 2; 4 ] - let%test _ = index_all (create "abab") ~may_overlap:false ~in_:"ababababab" = [ 0; 4 ] - - let%test _ = - index_all (create "abab") ~may_overlap:true ~in_:"ababababab" = [ 0; 2; 4; 6 ] + let%expect_test _ = + List.iter [%all: bool] ~f:(fun case_sensitive -> + test_both { pattern = ""; case_sensitive; kmp_array = [||] }) ;; - let%test _ = - index_all (create "aaa") ~may_overlap:false ~in_:"aaaaBaaaaaa" = [ 0; 5; 8 ] + let%expect_test _ = + List.iter [%all: bool] ~f:(fun case_sensitive -> + test_both + { pattern = "ababab"; case_sensitive; kmp_array = [| 0; 0; 1; 2; 3; 4 |] }) ;; - let%test _ = - index_all (create "aaa") ~may_overlap:true ~in_:"aaaaBaaaaaa" = [ 0; 1; 5; 6; 7; 8 ] + let%expect_test _ = + List.iter [%all: bool] ~f:(fun case_sensitive -> + test_both + { pattern = "abaCabaD" + ; case_sensitive + ; kmp_array = [| 0; 0; 1; 0; 1; 2; 3; 0 |] + }) ;; - let ( = ) = [%compare.equal: string] - let%test _ = replace_first (create "abab") ~in_:"abababab" ~with_:"" = "abab" - let%test _ = replace_first (create "abab") ~in_:"abacabab" ~with_:"" = "abac" - let%test _ = replace_first (create "abab") ~in_:"ababacab" ~with_:"A" = "Aacab" - let%test _ = replace_first (create "abab") ~in_:"acabababab" ~with_:"A" = "acAabab" - let%test _ = replace_first (create "ababab") ~in_:"acabababab" ~with_:"A" = "acAab" - - let%test _ = - replace_first (create "abab") ~in_:"abababab" ~with_:"abababab" = "abababababab" + let%expect_test _ = + List.iter [%all: bool] ~f:(fun case_sensitive -> + test_both + { pattern = "abaCabaDabaCabaCabaDabaCabaEabab" + ; case_sensitive + ; kmp_array = + [| 0 + ; 0 + ; 1 + ; 0 + ; 1 + ; 2 + ; 3 + ; 0 + ; 1 + ; 2 + ; 3 + ; 4 + ; 5 + ; 6 + ; 7 + ; 4 + ; 5 + ; 6 + ; 7 + ; 8 + ; 9 + ; 10 + ; 11 + ; 12 + ; 13 + ; 14 + ; 15 + ; 0 + ; 1 + ; 2 + ; 3 + ; 2 + |] + }) ;; - let%test _ = replace_all (create "abab") ~in_:"abababab" ~with_:"" = "" - let%test _ = replace_all (create "abab") ~in_:"abacabab" ~with_:"" = "abac" - let%test _ = replace_all (create "abab") ~in_:"acabababab" ~with_:"A" = "acAA" - let%test _ = replace_all (create "ababab") ~in_:"acabababab" ~with_:"A" = "acAab" - - let%test _ = - replace_all (create "abaC") ~in_:"abaCabaDCababaCabaCaba" ~with_:"x" - = "xabaDCabxxaba" + let%expect_test _ = + test_both { pattern = "aaA"; case_sensitive = true; kmp_array = [| 0; 1; 0 |] } ;; - let%test _ = replace_all (create "a") ~in_:"aa" ~with_:"aaa" = "aaaaaa" + let%expect_test _ = + test_both { pattern = "aaA"; case_sensitive = false; kmp_array = [| 0; 1; 2 |] } + ;; - let%test _ = - replace_all (create "") ~in_:"abcdeefff" ~with_:"X1" - = "X1aX1bX1cX1dX1eX1eX1fX1fX1fX1" + let%expect_test _ = + test_both + { pattern = "aAaAaA"; case_sensitive = true; kmp_array = [| 0; 0; 1; 2; 3; 4 |] } ;; - (* a doc comment in core_string.mli gives this as an example *) - let%test _ = replace_all (create "bc") ~in_:"aabbcc" ~with_:"cb" = "aabcbc" + let%expect_test _ = + test_both + { pattern = "aAaAaA"; case_sensitive = false; kmp_array = [| 0; 1; 2; 3; 4; 5 |] } + ;; - let%test _ = - [%compare.equal: string list] - (split_on (create "====") "aa====bbb====c=====d======e========fff") - [ "aa"; "bbb"; "c"; "=d"; "==e"; ""; "fff" ] + let rec x k = + if Int.( < ) k 0 + then "" + else ( + let b = x (k - 1) in + b ^ make 1 (Stdlib.Char.unsafe_chr (65 + k)) ^ b) + ;; + + let%expect_test _ = + List.iter [%all: bool] ~f:(fun case_sensitive -> cmp_both ~case_sensitive (x 10)) ;; - let%test _ = - [%compare.equal: string list] - (split_on (create "XYXYX") "XYXYXaaXYXYXYXbbXYXYXYXYXYX") - [ ""; "aa"; "YXbb"; "Y"; "" ] + let%expect_test _ = + List.iter [%all: bool] ~f:(fun case_sensitive -> + cmp_both ~case_sensitive (x 5 ^ "E" ^ x 4 ^ "D" ^ x 3 ^ "B" ^ x 2 ^ "C" ^ x 3)) ;; - let%test _ = - [%compare.equal: string list] - (split_on (create "") "abcd") - (* [index_all (create "")] includes the occurrences at index 0 and at the end of + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module struct + type t = string [@@deriving quickcheck, sexp_of] + end) + ~f:(fun pattern -> + let case_insensitive = + Private.representation (create pattern ~case_sensitive:false) + in + let case_sensitive_but_lowercase = + Private.representation (create (lowercase pattern) ~case_sensitive:true) + in + [%test_result: String.Caseless.t] + case_insensitive.pattern + ~expect:case_sensitive_but_lowercase.pattern; + [%test_result: int array] + case_insensitive.kmp_array + ~expect:case_sensitive_but_lowercase.kmp_array) + ;; + end + + let ( = ) = [%compare.equal: int option] + let%test _ = index (create "") ~in_:"abababac" = Some 0 + let%test _ = index ~pos:(-1) (create "") ~in_:"abababac" = None + let%test _ = index ~pos:1 (create "") ~in_:"abababac" = Some 1 + let%test _ = index ~pos:7 (create "") ~in_:"abababac" = Some 7 + let%test _ = index ~pos:8 (create "") ~in_:"abababac" = Some 8 + let%test _ = index ~pos:9 (create "") ~in_:"abababac" = None + let%test _ = index (create "abababaca") ~in_:"abababac" = None + let%test _ = index (create "abababac") ~in_:"abababac" = Some 0 + let%test _ = index ~pos:0 (create "abababac") ~in_:"abababac" = Some 0 + let%test _ = index (create "abac") ~in_:"abababac" = Some 4 + let%test _ = index ~pos:4 (create "abac") ~in_:"abababac" = Some 4 + let%test _ = index ~pos:5 (create "abac") ~in_:"abababac" = None + let%test _ = index ~pos:5 (create "abac") ~in_:"abababaca" = None + let%test _ = index ~pos:5 (create "baca") ~in_:"abababaca" = Some 5 + let%test _ = index ~pos:(-1) (create "a") ~in_:"abc" = None + let%test _ = index ~pos:2 (create "a") ~in_:"abc" = None + let%test _ = index ~pos:2 (create "c") ~in_:"abc" = Some 2 + let%test _ = index ~pos:3 (create "c") ~in_:"abc" = None + let ( = ) = [%compare.equal: bool] + let%test _ = matches (create "") "abababac" = true + let%test _ = matches (create "abababaca") "abababac" = false + let%test _ = matches (create "abababac") "abababac" = true + let%test _ = matches (create "abac") "abababac" = true + let%test _ = matches (create "abac") "abababaca" = true + let%test _ = matches (create "baca") "abababaca" = true + let%test _ = matches (create "a") "abc" = true + let%test _ = matches (create "c") "abc" = true + let ( = ) = [%compare.equal: int list] + let%test _ = index_all (create "") ~may_overlap:false ~in_:"abcd" = [ 0; 1; 2; 3; 4 ] + let%test _ = index_all (create "") ~may_overlap:true ~in_:"abcd" = [ 0; 1; 2; 3; 4 ] + let%test _ = index_all (create "abab") ~may_overlap:false ~in_:"abababab" = [ 0; 4 ] + let%test _ = index_all (create "abab") ~may_overlap:true ~in_:"abababab" = [ 0; 2; 4 ] + let%test _ = index_all (create "abab") ~may_overlap:false ~in_:"ababababab" = [ 0; 4 ] + + let%test _ = + index_all (create "abab") ~may_overlap:true ~in_:"ababababab" = [ 0; 2; 4; 6 ] + ;; + + let%test _ = + index_all (create "aaa") ~may_overlap:false ~in_:"aaaaBaaaaaa" = [ 0; 5; 8 ] + ;; + + let%test _ = + index_all (create "aaa") ~may_overlap:true ~in_:"aaaaBaaaaaa" = [ 0; 1; 5; 6; 7; 8 ] + ;; + + let ( = ) = [%compare.equal: string] + let%test _ = replace_first (create "abab") ~in_:"abababab" ~with_:"" = "abab" + let%test _ = replace_first (create "abab") ~in_:"abacabab" ~with_:"" = "abac" + let%test _ = replace_first (create "abab") ~in_:"ababacab" ~with_:"A" = "Aacab" + let%test _ = replace_first (create "abab") ~in_:"acabababab" ~with_:"A" = "acAabab" + let%test _ = replace_first (create "ababab") ~in_:"acabababab" ~with_:"A" = "acAab" + + let%test _ = + replace_first (create "abab") ~in_:"abababab" ~with_:"abababab" = "abababababab" + ;; + + let%test _ = replace_all (create "abab") ~in_:"abababab" ~with_:"" = "" + let%test _ = replace_all (create "abab") ~in_:"abacabab" ~with_:"" = "abac" + let%test _ = replace_all (create "abab") ~in_:"acabababab" ~with_:"A" = "acAA" + let%test _ = replace_all (create "ababab") ~in_:"acabababab" ~with_:"A" = "acAab" + + let%test _ = + replace_all (create "abaC") ~in_:"abaCabaDCababaCabaCaba" ~with_:"x" = "xabaDCabxxaba" + ;; + + let%test _ = replace_all (create "a") ~in_:"aa" ~with_:"aaa" = "aaaaaa" + + let%test _ = + replace_all (create "") ~in_:"abcdeefff" ~with_:"X1" = "X1aX1bX1cX1dX1eX1eX1fX1fX1fX1" + ;; + + (* a doc comment in core_string.mli gives this as an example *) + let%test _ = replace_all (create "bc") ~in_:"aabbcc" ~with_:"cb" = "aabcbc" + + let%test _ = + [%compare.equal: string list] + (split_on (create "====") "aa====bbb====c=====d======e========fff") + [ "aa"; "bbb"; "c"; "=d"; "==e"; ""; "fff" ] + ;; + + let%test _ = + [%compare.equal: string list] + (split_on (create "XYXYX") "XYXYXaaXYXYXYXbbXYXYXYXYXYX") + [ ""; "aa"; "YXbb"; "Y"; "" ] + ;; + + let%test _ = + [%compare.equal: string list] + (split_on (create "") "abcd") + (* [index_all (create "")] includes the occurrences at index 0 and at the end of the string, and the result of [split_on (create "")] is a consequence of this - *) - [ ""; "a"; "b"; "c"; "d"; "" ] - ;; + *) + [ ""; "a"; "b"; "c"; "d"; "" ] + ;; - let%test _ = - [%compare.equal: string list] - (split_on (create "not present") "here is a string with no matches") - [ "here is a string with no matches" ] - ;; - end) -;; + let%test _ = + [%compare.equal: string list] + (split_on (create "not present") "here is a string with no matches") + [ "here is a string with no matches" ] + ;; +end let%test _ = rev "" = "" let%test _ = rev "a" = "a" @@ -797,72 +765,70 @@ let%test_unit _ = assert (phys_equal s (tr s ~target:'\255' ~replacement:'\000')) ;; -let%test_module "tr_multi" = - (module struct - let gold_standard ~target ~replacement string = - map string ~f:(fun char -> - match rindex target char with - | None -> char - | Some i -> get replacement (Int.min i (length replacement - 1))) - ;; - - module Test = struct - type nonrec t = - { target : t - ; replacement : t - ; string : t - ; expected : t option [@sexp.option] - } - [@@deriving sexp_of] - - let quickcheck_generator = - let open Base_quickcheck.Generator in - let open Base_quickcheck.Generator.Let_syntax in - let%bind size in - let%bind target_len = int_log_uniform_inclusive 1 255 in - let%bind target = string_with_length ~length:target_len in - let%bind replacement_len = int_inclusive 1 target_len in - let%bind replacement = string_with_length ~length:replacement_len in - let%bind string_length = int_inclusive 0 size in - let%map string = string_with_length ~length:string_length in - { target; replacement; string; expected = None } - ;; - - let quickcheck_shrinker = Base_quickcheck.Shrinker.atomic - end - - let examples = - [ "", "", "abcdefg", "abcdefg" - ; "", "a", "abcdefg", "abcdefg" - ; "aaaa", "abcd", "abcdefg", "dbcdefg" - ; "abcd", "bcde", "abcdefg", "bcdeefg" - ; "abcd", "bcde", "", "" - ; "abcd", "_", "abcdefg", "____efg" - ; "abcd", "b_", "abcdefg", "b___efg" - ; "a", "dcba", "abcdefg", "dbcdefg" - ; "ab", "dcba", "abcdefg", "dccdefg" - ] - |> List.map ~f:(fun (target, replacement, string, expected) -> - { Test.target; replacement; string; expected = Some expected }) - ;; - - let%test_unit _ = - Base_quickcheck.Test.run_exn - (module Test) - ~examples - ~f:(fun ({ target; replacement; string; expected } : Test.t) -> - (* test implementation behavior against gold standard *) - let impl_result = unstage (tr_multi ~target ~replacement) string in - let gold_result = gold_standard ~target ~replacement string in - [%test_result: t] ~expect:gold_result impl_result; - (* test against expected result, if one is provided (non-random examples) *) - Option.iter expected ~f:(fun expected -> - [%test_result: t] ~expect:expected impl_result); - (* test for returning input if the string is unchanged *) - if equal string impl_result then assert (phys_equal string impl_result)) - ;; - end) -;; +module%test [@name "tr_multi"] _ = struct + let gold_standard ~target ~replacement string = + map string ~f:(fun char -> + match rindex target char with + | None -> char + | Some i -> get replacement (Int.min i (length replacement - 1))) + ;; + + module Test = struct + type nonrec t = + { target : t + ; replacement : t + ; string : t + ; expected : t option [@sexp.option] + } + [@@deriving sexp_of] + + let quickcheck_generator = + let open Base_quickcheck.Generator in + let open Base_quickcheck.Generator.Let_syntax in + let%bind size in + let%bind target_len = int_log_uniform_inclusive 1 255 in + let%bind target = string_with_length ~length:target_len in + let%bind replacement_len = int_inclusive 1 target_len in + let%bind replacement = string_with_length ~length:replacement_len in + let%bind string_length = int_inclusive 0 size in + let%map string = string_with_length ~length:string_length in + { target; replacement; string; expected = None } + ;; + + let quickcheck_shrinker = Base_quickcheck.Shrinker.atomic + end + + let examples = + [ "", "", "abcdefg", "abcdefg" + ; "", "a", "abcdefg", "abcdefg" + ; "aaaa", "abcd", "abcdefg", "dbcdefg" + ; "abcd", "bcde", "abcdefg", "bcdeefg" + ; "abcd", "bcde", "", "" + ; "abcd", "_", "abcdefg", "____efg" + ; "abcd", "b_", "abcdefg", "b___efg" + ; "a", "dcba", "abcdefg", "dbcdefg" + ; "ab", "dcba", "abcdefg", "dccdefg" + ] + |> List.map ~f:(fun (target, replacement, string, expected) -> + { Test.target; replacement; string; expected = Some expected }) + ;; + + let%test_unit _ = + Base_quickcheck.Test.run_exn + (module Test) + ~examples + ~f:(fun ({ target; replacement; string; expected } : Test.t) -> + (* test implementation behavior against gold standard *) + let impl_result = unstage (tr_multi ~target ~replacement) string in + let gold_result = gold_standard ~target ~replacement string in + [%test_result: t] ~expect:gold_result impl_result; + (* test against expected result, if one is provided (non-random examples) *) + Option.iter expected ~f:(fun expected -> + [%test_result: t] ~expect:expected impl_result); + (* test for returning input if the string is unchanged *) + if equal string impl_result then assert (phys_equal string impl_result)) + ;; +end let%test_unit _ = [%test_result: int option] (index "bob" 'b') ~expect:(Some 0) let%test_unit _ = [%test_result: int option] (rindex "bob" 'b') ~expect:(Some 2) @@ -925,102 +891,94 @@ let%test_unit _ = [%test_result: int option] (rfindi "bob" ~f:(fun _ -> Char.( = ) 'x')) ~expect:None ;; -let%test_module "strip" = - (module struct - let test ?drop s = print_s [%sexp (strip ?drop s : string)] - - let%expect_test "whitespace on both ends" = - test " foo bar \n"; - [%expect {| "foo bar" |}] - ;; - - let%expect_test "custom drop, present on end" = - test ~drop:(Char.( = ) '"') "\" foo bar "; - [%expect {| " foo bar " |}] - ;; - - let%expect_test "custom drop, absent from end" = - test ~drop:(Char.( = ) '"') " \" foo bar "; - [%expect {| " \" foo bar " |}] - ;; - - let%expect_test "all whitespace" = - test "\n\t \n"; - [%expect {| "" |}] - ;; - - let%expect_test "no whitespace on ends" = - test "as \t\ndf"; - [%expect {| "as \t\ndf" |}] - ;; - - let%expect_test "just one side" = - test " a"; - [%expect {| a |}]; - test "a "; - [%expect {| a |}] - ;; - end) -;; - -let%test_module "lstrip" = - (module struct - let test ?drop s = print_s [%sexp (lstrip ?drop s : string)] - - let%expect_test "whitespace on left" = - test " \t\r\n123 \t\n"; - [%expect {| "123 \t\n" |}] - ;; - - let%expect_test "all whitespace" = - test " \t \n\n\r "; - [%expect {| "" |}] - ;; - - let%expect_test "no whitespace on left" = - test "foo Bar \n "; - [%expect {| "foo Bar \n " |}] - ;; - end) -;; - -let%test_module "rstrip" = - (module struct - let test ?drop s = print_s [%sexp (rstrip ?drop s : string)] - - let%expect_test "whitespace on right" = - test " \t\r\n123 \t\n\r"; - [%expect {| " \t\r\n123" |}] - ;; - - let%expect_test "all whitespace" = - test " \t \n\n\r "; - [%expect {| "" |}] - ;; - - let%expect_test "no whitespace on right" = - test " \n foo Bar"; - [%expect {| " \n foo Bar" |}] - ;; - end) -;; - -let%test_module "map" = - (module struct - let%expect_test "empty" = require_equal (module String) (map "" ~f:Fn.id) "" - - let%expect_test "non-empty" = - let s = "faboo" in - require_equal - (module String) - (map s ~f:(function - | 'a' -> 'b' - | 'b' -> 'a' - | x -> x)) - "fbaoo" - ;; - end) -;; +module%test [@name "strip"] _ = struct + let test ?drop s = print_s [%sexp (strip ?drop s : string)] + + let%expect_test "whitespace on both ends" = + test " foo bar \n"; + [%expect {| "foo bar" |}] + ;; + + let%expect_test "custom drop, present on end" = + test ~drop:(Char.( = ) '"') "\" foo bar "; + [%expect {| " foo bar " |}] + ;; + + let%expect_test "custom drop, absent from end" = + test ~drop:(Char.( = ) '"') " \" foo bar "; + [%expect {| " \" foo bar " |}] + ;; + + let%expect_test "all whitespace" = + test "\n\t \n"; + [%expect {| "" |}] + ;; + + let%expect_test "no whitespace on ends" = + test "as \t\ndf"; + [%expect {| "as \t\ndf" |}] + ;; + + let%expect_test "just one side" = + test " a"; + [%expect {| a |}]; + test "a "; + [%expect {| a |}] + ;; +end + +module%test [@name "lstrip"] _ = struct + let test ?drop s = print_s [%sexp (lstrip ?drop s : string)] + + let%expect_test "whitespace on left" = + test " \t\r\n123 \t\n"; + [%expect {| "123 \t\n" |}] + ;; + + let%expect_test "all whitespace" = + test " \t \n\n\r "; + [%expect {| "" |}] + ;; + + let%expect_test "no whitespace on left" = + test "foo Bar \n "; + [%expect {| "foo Bar \n " |}] + ;; +end + +module%test [@name "rstrip"] _ = struct + let test ?drop s = print_s [%sexp (rstrip ?drop s : string)] + + let%expect_test "whitespace on right" = + test " \t\r\n123 \t\n\r"; + [%expect {| " \t\r\n123" |}] + ;; + + let%expect_test "all whitespace" = + test " \t \n\n\r "; + [%expect {| "" |}] + ;; + + let%expect_test "no whitespace on right" = + test " \n foo Bar"; + [%expect {| " \n foo Bar" |}] + ;; +end + +module%test [@name "map"] _ = struct + let%expect_test "empty" = require_equal (module String) (map "" ~f:Fn.id) "" + + let%expect_test "non-empty" = + let s = "faboo" in + require_equal + (module String) + (map s ~f:(function + | 'a' -> 'b' + | 'b' -> 'a' + | x -> x)) + "fbaoo" + ;; +end let%expect_test "split" = let test s = print_s [%sexp (split s ~on:'c' : string list)] in @@ -1106,6 +1064,19 @@ let%expect_test "iteri" = [%expect {| 0h 1e 2l 3l 4o |}] ;; +let%test_unit _ = + [%test_result: string * string] + (partition_mapi "hello" ~f:(fun i ch -> + if Int.(i % 2 = 0) then First ch else Second ch)) + ~expect:("hlo", "el") +;; + +let%test_unit _ = + [%test_result: string * string] + (partitioni_tf "hello" ~f:(fun i ch -> Int.(i % 2 = 0) && Char.(ch > 'h'))) + ~expect:("lo", "hel") +;; + let%test_unit _ = [%test_result: t] (filter "hello" ~f:(Char.( <> ) 'h')) ~expect:"ello" let%test_unit _ = [%test_result: t] (filter "hello" ~f:(Char.( <> ) 'l')) ~expect:"heo" let%test_unit _ = [%test_result: t] (filter "hello" ~f:(fun _ -> false)) ~expect:"" @@ -1132,25 +1103,23 @@ let%test_unit _ = assert (Int.( = ) !r (String.length s)) ;; -let%test_module "Hash" = - (module struct - external hash : string -> int = "Base_hash_string" [@@noalloc] +module%test Hash = struct + external hash : string -> int = "Base_hash_string" [@@noalloc] - let%test_unit _ = - List.iter - ~f:(fun string -> - assert (Int.( = ) (hash string) (Stdlib.Hashtbl.hash string)); - (* with 31-bit integers, the hash computed by ppx_hash overflows so it doesn't match + let%test_unit _ = + List.iter + ~f:(fun string -> + assert (Int.( = ) (hash string) (Stdlib.Hashtbl.hash string)); + (* with 31-bit integers, the hash computed by ppx_hash overflows so it doesn't match polymorphic hash exactly. *) - if Int.( > ) Int.num_bits 31 - then assert (Int.( = ) (hash string) ([%hash: string] string))) - [ "Oh Gloria inmarcesible! Oh jubilo inmortal!" - ; "Oh say can you see, by the dawn's early light" - ; "Hahahaha\200" - ] - ;; - end) -;; + if Int.( > ) Int.num_bits 31 + then assert (Int.( = ) (hash string) ([%hash: string] string))) + [ "Oh Gloria inmarcesible! Oh jubilo inmortal!" + ; "Oh say can you see, by the dawn's early light" + ; "Hahahaha\200" + ] + ;; +end let%test _ = of_char_list [ 'a'; 'b'; 'c' ] = "abc" let%test _ = of_char_list [] = "" @@ -1406,546 +1375,480 @@ let%expect_test "pad_left and pad_right" = |}] ;; -let%test_module "functions that raise Not_found_s" = - (module struct - let show f sexp_of_ok = print_s [%sexp (Result.try_with f : (ok, exn) Result.t)] - - let%expect_test "index_exn" = - let test s = show (fun () -> index_exn s ':') [%sexp_of: int] in - test ""; - [%expect {| (Error (Not_found_s "String.index_exn: not found")) |}]; - test "abc"; - [%expect {| (Error (Not_found_s "String.index_exn: not found")) |}]; - test ":abc"; - [%expect {| (Ok 0) |}]; - test "abc:"; - [%expect {| (Ok 3) |}]; - test "ab:cd:ef"; - [%expect {| (Ok 2) |}] - ;; - - let%expect_test "index_from_exn" = - let test_at s i = show (fun () -> index_from_exn s i ':') [%sexp_of: int] in - let test s = - for i = 0 to length s do - test_at s i - done +module%test [@name "functions that raise Not_found_s"] _ = struct + let show f sexp_of_ok = print_s [%sexp (Result.try_with f : (ok, exn) Result.t)] + + let%expect_test "index_exn" = + let test s = show (fun () -> index_exn s ':') [%sexp_of: int] in + test ""; + [%expect {| (Error (Not_found_s "String.index_exn: not found")) |}]; + test "abc"; + [%expect {| (Error (Not_found_s "String.index_exn: not found")) |}]; + test ":abc"; + [%expect {| (Ok 0) |}]; + test "abc:"; + [%expect {| (Ok 3) |}]; + test "ab:cd:ef"; + [%expect {| (Ok 2) |}] + ;; + + let%expect_test "index_from_exn" = + let test_at s i = show (fun () -> index_from_exn s i ':') [%sexp_of: int] in + let test s = + for i = 0 to length s do + test_at s i + done + in + test ""; + [%expect {| (Error (Not_found_s "String.index_from_exn: not found")) |}]; + test "abc"; + [%expect + {| + (Error (Not_found_s "String.index_from_exn: not found")) + (Error (Not_found_s "String.index_from_exn: not found")) + (Error (Not_found_s "String.index_from_exn: not found")) + (Error (Not_found_s "String.index_from_exn: not found")) + |}]; + test "a:b:c"; + [%expect + {| + (Ok 1) + (Ok 1) + (Ok 3) + (Ok 3) + (Error (Not_found_s "String.index_from_exn: not found")) + (Error (Not_found_s "String.index_from_exn: not found")) + |}]; + let test_bounds s = + test_at s (-1); + test_at s (length s + 1) + in + test_bounds "abc"; + [%expect + {| + (Error (Invalid_argument String.index_from_exn)) + (Error (Invalid_argument String.index_from_exn)) + |}] + ;; + + let%expect_test "rindex_exn" = + let test s = show (fun () -> rindex_exn s ':') [%sexp_of: int] in + test ""; + [%expect {| (Error (Not_found_s "String.rindex_exn: not found")) |}]; + test "abc"; + [%expect {| (Error (Not_found_s "String.rindex_exn: not found")) |}]; + test ":abc"; + [%expect {| (Ok 0) |}]; + test "abc:"; + [%expect {| (Ok 3) |}]; + test "ab:cd:ef"; + [%expect {| (Ok 5) |}] + ;; + + let%expect_test "rindex_from_exn" = + let test_at s i = show (fun () -> rindex_from_exn s i ':') [%sexp_of: int] in + let test s = + for i = length s - 1 downto -1 do + test_at s i + done + in + test ""; + [%expect {| (Error (Not_found_s "String.rindex_from_exn: not found")) |}]; + test "abc"; + [%expect + {| + (Error (Not_found_s "String.rindex_from_exn: not found")) + (Error (Not_found_s "String.rindex_from_exn: not found")) + (Error (Not_found_s "String.rindex_from_exn: not found")) + (Error (Not_found_s "String.rindex_from_exn: not found")) + |}]; + test "a:b:c"; + [%expect + {| + (Ok 3) + (Ok 3) + (Ok 1) + (Ok 1) + (Error (Not_found_s "String.rindex_from_exn: not found")) + (Error (Not_found_s "String.rindex_from_exn: not found")) + |}]; + let test_bounds s = + test_at s (-2); + test_at s (length s) + in + test_bounds "abc"; + [%expect + {| + (Error (Invalid_argument String.rindex_from_exn)) + (Error (Invalid_argument String.rindex_from_exn)) + |}] + ;; + + let%expect_test "lsplit2_exn" = + let test s = + let option_result = lsplit2 s ~on:':' in + let exn_result = Or_error.try_with (fun () -> lsplit2_exn s ~on:':') in + require_equal + (module struct + type t = (string * string) option [@@deriving equal, sexp_of] + end) + option_result + (Or_error.ok exn_result); + print_s [%sexp (exn_result : (string * string) Or_error.t)] + in + test ""; + [%expect {| (Error (Not_found_s "String.lsplit2_exn: not found")) |}]; + test "abc"; + [%expect {| (Error (Not_found_s "String.lsplit2_exn: not found")) |}]; + test ":abc"; + [%expect {| (Ok ("" abc)) |}]; + test "abc:"; + [%expect {| (Ok (abc "")) |}]; + test "ab:cd:ef"; + [%expect {| (Ok (ab cd:ef)) |}] + ;; + + let%expect_test "rsplit2_exn" = + let test s = + let option_result = rsplit2 s ~on:':' in + let exn_result = Or_error.try_with (fun () -> rsplit2_exn s ~on:':') in + require_equal + (module struct + type t = (string * string) option [@@deriving equal, sexp_of] + end) + option_result + (Or_error.ok exn_result); + print_s [%sexp (exn_result : (string * string) Or_error.t)] + in + test ""; + [%expect {| (Error (Not_found_s "String.rsplit2_exn: not found")) |}]; + test "abc"; + [%expect {| (Error (Not_found_s "String.rsplit2_exn: not found")) |}]; + test ":abc"; + [%expect {| (Ok ("" abc)) |}]; + test "abc:"; + [%expect {| (Ok (abc "")) |}]; + test "ab:cd:ef"; + [%expect {| (Ok (ab:cd ef)) |}] + ;; +end + +module%test Escaping = struct + open Escaping + + module%test [@name "escape_gen"] _ = struct + let escape = + unstage (escape_gen_exn ~escapeworthy_map:[ '%', 'p'; '^', 'c' ] ~escape_char:'_') + ;; + + let%test _ = escape "" = "" + let%test _ = escape "foo" = "foo" + let%test _ = escape "_" = "__" + let%test _ = escape "foo%bar" = "foo_pbar" + let%test _ = escape "^foo%" = "_cfoo_p" + + let escape2 = + unstage + (escape_gen_exn + ~escapeworthy_map:[ '_', '.'; '%', 'p'; '^', 'c' ] + ~escape_char:'_') + ;; + + let%test _ = escape2 "_." = "_.." + let%test _ = escape2 "_" = "_." + let%test _ = escape2 "foo%_bar" = "foo_p_.bar" + let%test _ = escape2 "_foo%" = "_.foo_p" + + let checks_for_one_to_one escapeworthy_map = + Exn.does_raise (fun () -> escape_gen_exn ~escapeworthy_map ~escape_char:'_') + ;; + + let%test _ = checks_for_one_to_one [ '%', 'p'; '^', 'c'; '$', 'c' ] + let%test _ = checks_for_one_to_one [ '%', 'p'; '^', 'c'; '%', 'd' ] + end + + module%test [@name "unescape_gen"] _ = struct + let unescape = + unstage (unescape_gen_exn ~escapeworthy_map:[ '%', 'p'; '^', 'c' ] ~escape_char:'_') + ;; + + let%test _ = unescape "__" = "_" + let%test _ = unescape "foo" = "foo" + let%test _ = unescape "__" = "_" + let%test _ = unescape "foo_pbar" = "foo%bar" + let%test _ = unescape "_cfoo_p" = "^foo%" + + let unescape2 = + unstage + (unescape_gen_exn + ~escapeworthy_map:[ '_', '.'; '%', 'p'; '^', 'c' ] + ~escape_char:'_') + ;; + + (* this one is ill-formed, just ignore the escape_char without escaped char *) + let%test _ = unescape2 "_" = "" + let%test _ = unescape2 "a_" = "a" + let%test _ = unescape2 "__" = "_" + let%test _ = unescape2 "_.." = "_." + let%test _ = unescape2 "_." = "_" + let%test _ = unescape2 "foo_p_.bar" = "foo%_bar" + let%test _ = unescape2 "_.foo_p" = "_foo%" + + (* generate [n] random string and check if escaping and unescaping are consistent *) + let random_test ~escapeworthy_map ~escape_char n = + let escape = unstage (escape_gen_exn ~escapeworthy_map ~escape_char) in + let unescape = unstage (unescape_gen_exn ~escapeworthy_map ~escape_char) in + let test str = + let escaped = escape str in + let unescaped = unescape escaped in + if str <> unescaped + then + failwith + (Printf.sprintf + "string: %s\nescaped string: %s\nunescaped string: %s" + str + escaped + unescaped) in - test ""; - [%expect {| (Error (Not_found_s "String.index_from_exn: not found")) |}]; - test "abc"; - [%expect - {| - (Error (Not_found_s "String.index_from_exn: not found")) - (Error (Not_found_s "String.index_from_exn: not found")) - (Error (Not_found_s "String.index_from_exn: not found")) - (Error (Not_found_s "String.index_from_exn: not found")) - |}]; - test "a:b:c"; - [%expect - {| - (Ok 1) - (Ok 1) - (Ok 3) - (Ok 3) - (Error (Not_found_s "String.index_from_exn: not found")) - (Error (Not_found_s "String.index_from_exn: not found")) - |}]; - let test_bounds s = - test_at s (-1); - test_at s (length s + 1) + let random_char = + let print_chars = + List.range (Char.to_int Char.min_value) (Char.to_int Char.max_value + 1) + |> List.filter_map ~f:Char.of_int + |> List.filter ~f:Char.is_print + |> Array.of_list + in + fun () -> Array.random_element_exn print_chars in - test_bounds "abc"; - [%expect - {| - (Error (Invalid_argument String.index_from_exn)) - (Error (Invalid_argument String.index_from_exn)) - |}] + let escapeworthy_chars = List.map escapeworthy_map ~f:fst |> Array.of_list in + try + for _ = 0 to n - 1 do + let str = + List.init (Random.int 50) ~f:(fun _ -> + let p = Random.int 100 in + if Int.(p < 10) + then escape_char + else if Int.(p < 25) + then Array.random_element_exn escapeworthy_chars + else random_char ()) + |> of_char_list + in + test str + done; + true + with + | e -> raise e ;; - let%expect_test "rindex_exn" = - let test s = show (fun () -> rindex_exn s ':') [%sexp_of: int] in - test ""; - [%expect {| (Error (Not_found_s "String.rindex_exn: not found")) |}]; - test "abc"; - [%expect {| (Error (Not_found_s "String.rindex_exn: not found")) |}]; - test ":abc"; - [%expect {| (Ok 0) |}]; - test "abc:"; - [%expect {| (Ok 3) |}]; - test "ab:cd:ef"; - [%expect {| (Ok 5) |}] + let%test _ = + random_test 1000 ~escapeworthy_map:[ '%', 'p'; '^', 'c' ] ~escape_char:'_' ;; - let%expect_test "rindex_from_exn" = - let test_at s i = show (fun () -> rindex_from_exn s i ':') [%sexp_of: int] in - let test s = - for i = length s - 1 downto -1 do - test_at s i - done - in - test ""; - [%expect {| (Error (Not_found_s "String.rindex_from_exn: not found")) |}]; - test "abc"; - [%expect - {| - (Error (Not_found_s "String.rindex_from_exn: not found")) - (Error (Not_found_s "String.rindex_from_exn: not found")) - (Error (Not_found_s "String.rindex_from_exn: not found")) - (Error (Not_found_s "String.rindex_from_exn: not found")) - |}]; - test "a:b:c"; - [%expect - {| - (Ok 3) - (Ok 3) - (Ok 1) - (Ok 1) - (Error (Not_found_s "String.rindex_from_exn: not found")) - (Error (Not_found_s "String.rindex_from_exn: not found")) - |}]; - let test_bounds s = - test_at s (-2); - test_at s (length s) - in - test_bounds "abc"; - [%expect - {| - (Error (Invalid_argument String.rindex_from_exn)) - (Error (Invalid_argument String.rindex_from_exn)) - |}] - ;; + let%test _ = + random_test 1000 ~escapeworthy_map:[ '_', '.'; '%', 'p'; '^', 'c' ] ~escape_char:'_' + ;; + end + + module%test [@name "escape"] _ = struct + let escape = unstage (escape ~escape_char:'_' ~escapeworthy:[ '_'; '%'; '^' ]) + let%test _ = escape "foo" = "foo" + let%test _ = escape "_" = "__" + let%test _ = escape "foo%bar" = "foo_%bar" + let%test _ = escape "^foo%" = "_^foo_%" + end + + module%test [@name "unescape"] _ = struct + let unescape = unstage (unescape ~escape_char:'_') + let%test _ = unescape "foo" = "foo" + let%test _ = unescape "__" = "_" + let%test _ = unescape "foo_%bar" = "foo%bar" + let%test _ = unescape "_^foo_%" = "^foo%" + end + + module%test [@name "is_char_escaping"] _ = struct + let is = is_char_escaping ~escape_char:'_' + let%test_unit _ = [%test_result: bool] (is "___" 0) ~expect:true + let%test_unit _ = [%test_result: bool] (is "___" 1) ~expect:false + let%test_unit _ = [%test_result: bool] (is "___" 2) ~expect:true + + (* considered escaping, though there's nothing to escape *) + let%test_unit _ = [%test_result: bool] (is "a_b__c" 0) ~expect:false + let%test_unit _ = [%test_result: bool] (is "a_b__c" 1) ~expect:true + let%test_unit _ = [%test_result: bool] (is "a_b__c" 2) ~expect:false + let%test_unit _ = [%test_result: bool] (is "a_b__c" 3) ~expect:true + let%test_unit _ = [%test_result: bool] (is "a_b__c" 4) ~expect:false + let%test_unit _ = [%test_result: bool] (is "a_b__c" 5) ~expect:false + end + + module%test [@name "is_char_escaped"] _ = struct + let is = is_char_escaped ~escape_char:'_' + let%test_unit _ = [%test_result: bool] (is "___" 2) ~expect:false + let%test_unit _ = [%test_result: bool] (is "x" 0) ~expect:false + let%test_unit _ = [%test_result: bool] (is "_x" 1) ~expect:true + let%test_unit _ = [%test_result: bool] (is "sadflkas____sfff" 12) ~expect:false + let%test_unit _ = [%test_result: bool] (is "s_____s" 6) ~expect:true + end + + module%test [@name "is_char_literal"] _ = struct + let is_char_literal = is_char_literal ~escape_char:'_' + let%test_unit _ = [%test_result: bool] (is_char_literal "123456" 4) ~expect:true + let%test_unit _ = [%test_result: bool] (is_char_literal "12345_6" 6) ~expect:false + let%test_unit _ = [%test_result: bool] (is_char_literal "12345_6" 5) ~expect:false + let%test_unit _ = [%test_result: bool] (is_char_literal "123__456" 4) ~expect:false + let%test_unit _ = [%test_result: bool] (is_char_literal "123456__" 7) ~expect:false + let%test_unit _ = [%test_result: bool] (is_char_literal "__123456" 1) ~expect:false + let%test_unit _ = [%test_result: bool] (is_char_literal "__123456" 0) ~expect:false + let%test_unit _ = [%test_result: bool] (is_char_literal "__123456" 2) ~expect:true + end + + module%test [@name "index_from"] _ = struct + let f = index_from ~escape_char:'_' + let%test_unit _ = [%test_result: int option] (f "__" 0 '_') ~expect:None + let%test_unit _ = [%test_result: int option] (f "_.." 0 '.') ~expect:(Some 2) + let%test_unit _ = [%test_result: int option] (f "1273456_7789" 3 '7') ~expect:(Some 9) - let%expect_test "lsplit2_exn" = - let test s = - let option_result = lsplit2 s ~on:':' in - let exn_result = Or_error.try_with (fun () -> lsplit2_exn s ~on:':') in - require_equal - (module struct - type t = (string * string) option [@@deriving equal, sexp_of] - end) - option_result - (Or_error.ok exn_result); - print_s [%sexp (exn_result : (string * string) Or_error.t)] - in - test ""; - [%expect {| (Error (Not_found_s "String.lsplit2_exn: not found")) |}]; - test "abc"; - [%expect {| (Error (Not_found_s "String.lsplit2_exn: not found")) |}]; - test ":abc"; - [%expect {| (Ok ("" abc)) |}]; - test "abc:"; - [%expect {| (Ok (abc "")) |}]; - test "ab:cd:ef"; - [%expect {| (Ok (ab cd:ef)) |}] + let%test_unit _ = + [%test_result: int option] (f "1273_7456_7789" 3 '7') ~expect:(Some 11) ;; - let%expect_test "rsplit2_exn" = - let test s = - let option_result = rsplit2 s ~on:':' in - let exn_result = Or_error.try_with (fun () -> rsplit2_exn s ~on:':') in - require_equal - (module struct - type t = (string * string) option [@@deriving equal, sexp_of] - end) - option_result - (Or_error.ok exn_result); - print_s [%sexp (exn_result : (string * string) Or_error.t)] - in - test ""; - [%expect {| (Error (Not_found_s "String.rsplit2_exn: not found")) |}]; - test "abc"; - [%expect {| (Error (Not_found_s "String.rsplit2_exn: not found")) |}]; - test ":abc"; - [%expect {| (Ok ("" abc)) |}]; - test "abc:"; - [%expect {| (Ok (abc "")) |}]; - test "ab:cd:ef"; - [%expect {| (Ok (ab:cd ef)) |}] - ;; - end) -;; + let%test_unit _ = [%test_result: int option] (f "1273_7456_7789" 3 'z') ~expect:None + end -let%test_module "Escaping" = - (module struct - open Escaping + module%test [@name "rindex"] _ = struct + let f = rindex_from ~escape_char:'_' + let%test_unit _ = [%test_result: int option] (f "__" 0 '_') ~expect:None + let%test_unit _ = [%test_result: int option] (f "123456_37839" 9 '3') ~expect:(Some 2) + let%test_unit _ = [%test_result: int option] (f "123_2321" 6 '2') ~expect:(Some 6) + let%test_unit _ = [%test_result: int option] (f "123_2321" 5 '2') ~expect:(Some 1) - let%test_module "escape_gen" = - (module struct - let escape = - unstage - (escape_gen_exn ~escapeworthy_map:[ '%', 'p'; '^', 'c' ] ~escape_char:'_') - ;; - - let%test _ = escape "" = "" - let%test _ = escape "foo" = "foo" - let%test _ = escape "_" = "__" - let%test _ = escape "foo%bar" = "foo_pbar" - let%test _ = escape "^foo%" = "_cfoo_p" - - let escape2 = - unstage - (escape_gen_exn - ~escapeworthy_map:[ '_', '.'; '%', 'p'; '^', 'c' ] - ~escape_char:'_') - ;; - - let%test _ = escape2 "_." = "_.." - let%test _ = escape2 "_" = "_." - let%test _ = escape2 "foo%_bar" = "foo_p_.bar" - let%test _ = escape2 "_foo%" = "_.foo_p" - - let checks_for_one_to_one escapeworthy_map = - Exn.does_raise (fun () -> escape_gen_exn ~escapeworthy_map ~escape_char:'_') - ;; - - let%test _ = checks_for_one_to_one [ '%', 'p'; '^', 'c'; '$', 'c' ] - let%test _ = checks_for_one_to_one [ '%', 'p'; '^', 'c'; '%', 'd' ] - end) + let%test_unit _ = + [%test_result: int option] (rindex "" ~escape_char:'_' 'x') ~expect:None ;; - let%test_module "unescape_gen" = - (module struct - let unescape = - unstage - (unescape_gen_exn ~escapeworthy_map:[ '%', 'p'; '^', 'c' ] ~escape_char:'_') - ;; - - let%test _ = unescape "__" = "_" - let%test _ = unescape "foo" = "foo" - let%test _ = unescape "__" = "_" - let%test _ = unescape "foo_pbar" = "foo%bar" - let%test _ = unescape "_cfoo_p" = "^foo%" - - let unescape2 = - unstage - (unescape_gen_exn - ~escapeworthy_map:[ '_', '.'; '%', 'p'; '^', 'c' ] - ~escape_char:'_') - ;; - - (* this one is ill-formed, just ignore the escape_char without escaped char *) - let%test _ = unescape2 "_" = "" - let%test _ = unescape2 "a_" = "a" - let%test _ = unescape2 "__" = "_" - let%test _ = unescape2 "_.." = "_." - let%test _ = unescape2 "_." = "_" - let%test _ = unescape2 "foo_p_.bar" = "foo%_bar" - let%test _ = unescape2 "_.foo_p" = "_foo%" - - (* generate [n] random string and check if escaping and unescaping are consistent *) - let random_test ~escapeworthy_map ~escape_char n = - let escape = unstage (escape_gen_exn ~escapeworthy_map ~escape_char) in - let unescape = unstage (unescape_gen_exn ~escapeworthy_map ~escape_char) in - let test str = - let escaped = escape str in - let unescaped = unescape escaped in - if str <> unescaped - then - failwith - (Printf.sprintf - "string: %s\nescaped string: %s\nunescaped string: %s" - str - escaped - unescaped) - in - let random_char = - let print_chars = - List.range (Char.to_int Char.min_value) (Char.to_int Char.max_value + 1) - |> List.filter_map ~f:Char.of_int - |> List.filter ~f:Char.is_print - |> Array.of_list - in - fun () -> Array.random_element_exn print_chars - in - let escapeworthy_chars = List.map escapeworthy_map ~f:fst |> Array.of_list in - try - for _ = 0 to n - 1 do - let str = - List.init (Random.int 50) ~f:(fun _ -> - let p = Random.int 100 in - if Int.(p < 10) - then escape_char - else if Int.(p < 25) - then Array.random_element_exn escapeworthy_chars - else random_char ()) - |> of_char_list - in - test str - done; - true - with - | e -> raise e - ;; - - let%test _ = - random_test 1000 ~escapeworthy_map:[ '%', 'p'; '^', 'c' ] ~escape_char:'_' - ;; - - let%test _ = - random_test - 1000 - ~escapeworthy_map:[ '_', '.'; '%', 'p'; '^', 'c' ] - ~escape_char:'_' - ;; - end) + let%test_unit _ = + [%test_result: int option] (rindex "a_a" ~escape_char:'_' 'a') ~expect:(Some 0) ;; + end - let%test_module "escape" = - (module struct - let escape = unstage (escape ~escape_char:'_' ~escapeworthy:[ '_'; '%'; '^' ]) - let%test _ = escape "foo" = "foo" - let%test _ = escape "_" = "__" - let%test _ = escape "foo%bar" = "foo_%bar" - let%test _ = escape "^foo%" = "_^foo_%" - end) - ;; + module%test [@name "split"] _ = struct + let split = split ~escape_char:'_' ~on:',' - let%test_module "unescape" = - (module struct - let unescape = unstage (unescape ~escape_char:'_') - let%test _ = unescape "foo" = "foo" - let%test _ = unescape "__" = "_" - let%test _ = unescape "foo_%bar" = "foo%bar" - let%test _ = unescape "_^foo_%" = "^foo%" - end) + let%test_unit _ = + [%test_result: string list] (split "foo,bar,baz") ~expect:[ "foo"; "bar"; "baz" ] ;; - let%test_module "is_char_escaping" = - (module struct - let is = is_char_escaping ~escape_char:'_' - let%test_unit _ = [%test_result: bool] (is "___" 0) ~expect:true - let%test_unit _ = [%test_result: bool] (is "___" 1) ~expect:false - let%test_unit _ = [%test_result: bool] (is "___" 2) ~expect:true - - (* considered escaping, though there's nothing to escape *) - let%test_unit _ = [%test_result: bool] (is "a_b__c" 0) ~expect:false - let%test_unit _ = [%test_result: bool] (is "a_b__c" 1) ~expect:true - let%test_unit _ = [%test_result: bool] (is "a_b__c" 2) ~expect:false - let%test_unit _ = [%test_result: bool] (is "a_b__c" 3) ~expect:true - let%test_unit _ = [%test_result: bool] (is "a_b__c" 4) ~expect:false - let%test_unit _ = [%test_result: bool] (is "a_b__c" 5) ~expect:false - end) + let%test_unit _ = + [%test_result: string list] (split "foo_,bar,baz") ~expect:[ "foo_,bar"; "baz" ] ;; - let%test_module "is_char_escaped" = - (module struct - let is = is_char_escaped ~escape_char:'_' - let%test_unit _ = [%test_result: bool] (is "___" 2) ~expect:false - let%test_unit _ = [%test_result: bool] (is "x" 0) ~expect:false - let%test_unit _ = [%test_result: bool] (is "_x" 1) ~expect:true - let%test_unit _ = [%test_result: bool] (is "sadflkas____sfff" 12) ~expect:false - let%test_unit _ = [%test_result: bool] (is "s_____s" 6) ~expect:true - end) + let%test_unit _ = + [%test_result: string list] (split "foo_,bar_,baz") ~expect:[ "foo_,bar_,baz" ] ;; - let%test_module "is_char_literal" = - (module struct - let is_char_literal = is_char_literal ~escape_char:'_' - let%test_unit _ = [%test_result: bool] (is_char_literal "123456" 4) ~expect:true - let%test_unit _ = [%test_result: bool] (is_char_literal "12345_6" 6) ~expect:false - let%test_unit _ = [%test_result: bool] (is_char_literal "12345_6" 5) ~expect:false - - let%test_unit _ = - [%test_result: bool] (is_char_literal "123__456" 4) ~expect:false - ;; - - let%test_unit _ = - [%test_result: bool] (is_char_literal "123456__" 7) ~expect:false - ;; - - let%test_unit _ = - [%test_result: bool] (is_char_literal "__123456" 1) ~expect:false - ;; - - let%test_unit _ = - [%test_result: bool] (is_char_literal "__123456" 0) ~expect:false - ;; - - let%test_unit _ = [%test_result: bool] (is_char_literal "__123456" 2) ~expect:true - end) + let%test_unit _ = + [%test_result: string list] + (split "foo__,bar,baz") + ~expect:[ "foo__"; "bar"; "baz" ] ;; - let%test_module "index_from" = - (module struct - let f = index_from ~escape_char:'_' - let%test_unit _ = [%test_result: int option] (f "__" 0 '_') ~expect:None - let%test_unit _ = [%test_result: int option] (f "_.." 0 '.') ~expect:(Some 2) - - let%test_unit _ = - [%test_result: int option] (f "1273456_7789" 3 '7') ~expect:(Some 9) - ;; - - let%test_unit _ = - [%test_result: int option] (f "1273_7456_7789" 3 '7') ~expect:(Some 11) - ;; + let%test_unit _ = + [%test_result: string list] + (split "foo,bar,baz_,") + ~expect:[ "foo"; "bar"; "baz_," ] + ;; - let%test_unit _ = - [%test_result: int option] (f "1273_7456_7789" 3 'z') ~expect:None - ;; - end) + let%test_unit _ = + [%test_result: string list] + (split "foo,bar_,baz_,,") + ~expect:[ "foo"; "bar_,baz_,"; "" ] ;; + end - let%test_module "rindex" = - (module struct - let f = rindex_from ~escape_char:'_' - let%test_unit _ = [%test_result: int option] (f "__" 0 '_') ~expect:None + module%test [@name "split_on_chars"] _ = struct + let split = split_on_chars ~escape_char:'_' ~on:[ ','; ':' ] - let%test_unit _ = - [%test_result: int option] (f "123456_37839" 9 '3') ~expect:(Some 2) - ;; + let%test_unit _ = + [%test_result: string list] (split "foo,bar:baz") ~expect:[ "foo"; "bar"; "baz" ] + ;; - let%test_unit _ = [%test_result: int option] (f "123_2321" 6 '2') ~expect:(Some 6) - let%test_unit _ = [%test_result: int option] (f "123_2321" 5 '2') ~expect:(Some 1) + let%test_unit _ = + [%test_result: string list] (split "foo_,bar,baz") ~expect:[ "foo_,bar"; "baz" ] + ;; - let%test_unit _ = - [%test_result: int option] (rindex "" ~escape_char:'_' 'x') ~expect:None - ;; + let%test_unit _ = + [%test_result: string list] (split "foo_:bar_,baz") ~expect:[ "foo_:bar_,baz" ] + ;; - let%test_unit _ = - [%test_result: int option] (rindex "a_a" ~escape_char:'_' 'a') ~expect:(Some 0) - ;; - end) + let%test_unit _ = + [%test_result: string list] + (split "foo,bar,baz_,") + ~expect:[ "foo"; "bar"; "baz_," ] ;; - let%test_module "split" = - (module struct - let split = split ~escape_char:'_' ~on:',' - - let%test_unit _ = - [%test_result: string list] - (split "foo,bar,baz") - ~expect:[ "foo"; "bar"; "baz" ] - ;; - - let%test_unit _ = - [%test_result: string list] (split "foo_,bar,baz") ~expect:[ "foo_,bar"; "baz" ] - ;; - - let%test_unit _ = - [%test_result: string list] (split "foo_,bar_,baz") ~expect:[ "foo_,bar_,baz" ] - ;; - - let%test_unit _ = - [%test_result: string list] - (split "foo__,bar,baz") - ~expect:[ "foo__"; "bar"; "baz" ] - ;; - - let%test_unit _ = - [%test_result: string list] - (split "foo,bar,baz_,") - ~expect:[ "foo"; "bar"; "baz_," ] - ;; - - let%test_unit _ = - [%test_result: string list] - (split "foo,bar_,baz_,,") - ~expect:[ "foo"; "bar_,baz_,"; "" ] - ;; - end) + let%test_unit _ = + [%test_result: string list] + (split "foo:bar_,baz_,,") + ~expect:[ "foo"; "bar_,baz_,"; "" ] ;; + end - let%test_module "split_on_chars" = - (module struct - let split = split_on_chars ~escape_char:'_' ~on:[ ','; ':' ] - - let%test_unit _ = - [%test_result: string list] - (split "foo,bar:baz") - ~expect:[ "foo"; "bar"; "baz" ] - ;; - - let%test_unit _ = - [%test_result: string list] (split "foo_,bar,baz") ~expect:[ "foo_,bar"; "baz" ] - ;; - - let%test_unit _ = - [%test_result: string list] (split "foo_:bar_,baz") ~expect:[ "foo_:bar_,baz" ] - ;; - - let%test_unit _ = - [%test_result: string list] - (split "foo,bar,baz_,") - ~expect:[ "foo"; "bar"; "baz_," ] - ;; - - let%test_unit _ = - [%test_result: string list] - (split "foo:bar_,baz_,,") - ~expect:[ "foo"; "bar_,baz_,"; "" ] - ;; - end) + module%test [@name "split2"] _ = struct + let escape_char = '_' + let on = ',' + + let%test_unit _ = + [%test_result: (string * string) option] + (lsplit2 ~escape_char ~on "foo_,bar,baz_,0") + ~expect:(Some ("foo_,bar", "baz_,0")) ;; - let%test_module "split2" = - (module struct - let escape_char = '_' - let on = ',' - - let%test_unit _ = - [%test_result: (string * string) option] - (lsplit2 ~escape_char ~on "foo_,bar,baz_,0") - ~expect:(Some ("foo_,bar", "baz_,0")) - ;; - - let%test_unit _ = - [%test_result: (string * string) option] - (rsplit2 ~escape_char ~on "foo_,bar,baz_,0") - ~expect:(Some ("foo_,bar", "baz_,0")) - ;; - - let%test_unit _ = - [%test_result: string * string] - (lsplit2_exn ~escape_char ~on "foo_,bar,baz_,0") - ~expect:("foo_,bar", "baz_,0") - ;; - - let%test_unit _ = - [%test_result: string * string] - (rsplit2_exn ~escape_char ~on "foo_,bar,baz_,0") - ~expect:("foo_,bar", "baz_,0") - ;; - - let%test_unit _ = - [%test_result: (string * string) option] - (lsplit2 ~escape_char ~on "foo_,bar") - ~expect:None - ;; - - let%test_unit _ = - [%test_result: (string * string) option] - (rsplit2 ~escape_char ~on "foo_,bar") - ~expect:None - ;; - - let%test _ = Exn.does_raise (fun () -> lsplit2_exn ~escape_char ~on "foo_,bar") - let%test _ = Exn.does_raise (fun () -> rsplit2_exn ~escape_char ~on "foo_,bar") - end) + let%test_unit _ = + [%test_result: (string * string) option] + (rsplit2 ~escape_char ~on "foo_,bar,baz_,0") + ~expect:(Some ("foo_,bar", "baz_,0")) ;; - let%test _ = strip_literal ~escape_char:' ' " foo bar \n" = " foo bar \n" - let%test _ = strip_literal ~escape_char:' ' " foo bar \n\n" = " foo bar \n" - let%test _ = strip_literal ~escape_char:'\n' " foo bar \n" = "foo bar \n" - let%test _ = lstrip_literal ~escape_char:' ' " foo bar \n\n" = " foo bar \n\n" - let%test _ = rstrip_literal ~escape_char:' ' " foo bar \n\n" = " foo bar \n" - let%test _ = lstrip_literal ~escape_char:'\n' " foo bar \n" = "foo bar \n" - let%test _ = rstrip_literal ~escape_char:'\n' " foo bar \n" = " foo bar \n" - let%test _ = strip_literal ~drop:Char.is_alpha ~escape_char:'\\' "foo boar" = " " - let%test _ = strip_literal ~drop:Char.is_alpha ~escape_char:'\\' "fooboar" = "" - let%test _ = strip_literal ~drop:Char.is_alpha ~escape_char:'o' "foo boar" = "oo boa" - let%test _ = strip_literal ~drop:Char.is_alpha ~escape_char:'a' "foo boar" = " boar" - let%test _ = strip_literal ~drop:Char.is_alpha ~escape_char:'b' "foo boar" = " bo" + let%test_unit _ = + [%test_result: string * string] + (lsplit2_exn ~escape_char ~on "foo_,bar,baz_,0") + ~expect:("foo_,bar", "baz_,0") + ;; - let%test _ = - lstrip_literal ~drop:Char.is_alpha ~escape_char:'o' "foo boar" = "oo boar" + let%test_unit _ = + [%test_result: string * string] + (rsplit2_exn ~escape_char ~on "foo_,bar,baz_,0") + ~expect:("foo_,bar", "baz_,0") ;; - let%test _ = - rstrip_literal ~drop:Char.is_alpha ~escape_char:'o' "foo boar" = "foo boa" + let%test_unit _ = + [%test_result: (string * string) option] + (lsplit2 ~escape_char ~on "foo_,bar") + ~expect:None ;; - let%test _ = lstrip_literal ~drop:Char.is_alpha ~escape_char:'b' "foo boar" = " boar" - let%test _ = rstrip_literal ~drop:Char.is_alpha ~escape_char:'b' "foo boar" = "foo bo" - end) -;; + let%test_unit _ = + [%test_result: (string * string) option] + (rsplit2 ~escape_char ~on "foo_,bar") + ~expect:None + ;; + + let%test _ = Exn.does_raise (fun () -> lsplit2_exn ~escape_char ~on "foo_,bar") + let%test _ = Exn.does_raise (fun () -> rsplit2_exn ~escape_char ~on "foo_,bar") + end + + let%test _ = strip_literal ~escape_char:' ' " foo bar \n" = " foo bar \n" + let%test _ = strip_literal ~escape_char:' ' " foo bar \n\n" = " foo bar \n" + let%test _ = strip_literal ~escape_char:'\n' " foo bar \n" = "foo bar \n" + let%test _ = lstrip_literal ~escape_char:' ' " foo bar \n\n" = " foo bar \n\n" + let%test _ = rstrip_literal ~escape_char:' ' " foo bar \n\n" = " foo bar \n" + let%test _ = lstrip_literal ~escape_char:'\n' " foo bar \n" = "foo bar \n" + let%test _ = rstrip_literal ~escape_char:'\n' " foo bar \n" = " foo bar \n" + let%test _ = strip_literal ~drop:Char.is_alpha ~escape_char:'\\' "foo boar" = " " + let%test _ = strip_literal ~drop:Char.is_alpha ~escape_char:'\\' "fooboar" = "" + let%test _ = strip_literal ~drop:Char.is_alpha ~escape_char:'o' "foo boar" = "oo boa" + let%test _ = strip_literal ~drop:Char.is_alpha ~escape_char:'a' "foo boar" = " boar" + let%test _ = strip_literal ~drop:Char.is_alpha ~escape_char:'b' "foo boar" = " bo" + let%test _ = lstrip_literal ~drop:Char.is_alpha ~escape_char:'o' "foo boar" = "oo boar" + let%test _ = rstrip_literal ~drop:Char.is_alpha ~escape_char:'o' "foo boar" = "foo boa" + let%test _ = lstrip_literal ~drop:Char.is_alpha ~escape_char:'b' "foo boar" = " boar" + let%test _ = rstrip_literal ~drop:Char.is_alpha ~escape_char:'b' "foo boar" = "foo bo" +end diff --git a/test/test_type_equal.ml b/test/test_type_equal.ml index 049253d..0fca578 100644 --- a/test/test_type_equal.ml +++ b/test/test_type_equal.ml @@ -6,71 +6,67 @@ let%expect_test "[Id.sexp_of_t]" = [%expect {| some-type-id |}] ;; -let%test_module "Type_equal.Id" = - (module struct - open Type_equal.Id +module%test [@name "Type_equal.Id"] _ = struct + open Type_equal.Id - let t1 = create ~name:"t1" [%sexp_of: _] - let t2 = create ~name:"t2" [%sexp_of: _] - let%test _ = same t1 t1 - let%test _ = not (same t1 t2) - let%test _ = Option.is_some (same_witness t1 t1) - let%test _ = Option.is_none (same_witness t1 t2) - let%test_unit _ = ignore (same_witness_exn t1 t1 : (_, _) Type_equal.t) - let%test _ = Result.is_error (Result.try_with (fun () -> same_witness_exn t1 t2)) - end) -;; + let t1 = create ~name:"t1" [%sexp_of: _] + let t2 = create ~name:"t2" [%sexp_of: _] + let%test _ = same t1 t1 + let%test _ = not (same t1 t2) + let%test _ = Option.is_some (same_witness t1 t1) + let%test _ = Option.is_none (same_witness t1 t2) + let%test_unit _ = ignore (same_witness_exn t1 t1 : (_, _) Type_equal.t) + let%test _ = Result.is_error (Result.try_with (fun () -> same_witness_exn t1 t2)) +end (* This test shows that we need [conv] even though [Type_equal.T] is exposed. *) -let%test_module "Type_equal" = - (module struct - open Type_equal +module%test Type_equal = struct + open Type_equal - let id = Id.create ~name:"int" [%sexp_of: int] + let id = Id.create ~name:"int" [%sexp_of: int] - module A : sig - type t + module A : sig + type t - val id : t Id.t - end = struct - type t = int + val id : t Id.t + end = struct + type t = int - let id = id - end + let id = id + end - module B : sig - type t + module B : sig + type t - val id : t Id.t - end = struct - type t = int + val id : t Id.t + end = struct + type t = int - let id = id - end + let id = id + end - let _a_to_b (a : A.t) = - let eq = Id.same_witness_exn A.id B.id in - (conv eq a : B.t) - ;; + let _a_to_b (a : A.t) = + let eq = Id.same_witness_exn A.id B.id in + (conv eq a : B.t) + ;; - (* the following is rejected by the compiler *) - (* let _a_to_b (a : A.t) = + (* the following is rejected by the compiler *) + (* let _a_to_b (a : A.t) = * let T = Id.same_witness_exn A.id B.id in * (a : B.t) *) - module C = struct - type 'a t - end + module C = struct + type 'a t + end - module Liftc = Lift (C) + module Liftc = Lift (C) - let _ac_to_bc (ac : A.t C.t) = - let eq = Liftc.lift (Id.same_witness_exn A.id B.id) in - (conv eq ac : B.t C.t) - ;; - end) -;; + let _ac_to_bc (ac : A.t C.t) = + let eq = Liftc.lift (Id.same_witness_exn A.id B.id) in + (conv eq ac : B.t C.t) + ;; +end let%expect_test "Create*" = let test id1 id2 = diff --git a/test/test_uchar.ml b/test/test_uchar.ml index fa89632..4b0bc17 100644 --- a/test/test_uchar.ml +++ b/test/test_uchar.ml @@ -4,86 +4,68 @@ let min_int = Int.min_value let max_int = Int.max_value let raises f v = Exn.does_raise (fun () -> f v) -let%test_module "test_constants" = - (module struct - let%test _ = Uchar.(to_scalar min_value) = 0x0000 - let%test _ = Uchar.(to_scalar max_value) = 0x10FFFF - end) -;; +module%test [@name "test_constants"] _ = struct + let%test _ = Uchar.(to_scalar min_value) = 0x0000 + let%test _ = Uchar.(to_scalar max_value) = 0x10FFFF +end -let%test_module "test_succ_exn" = - (module struct - let%test _ = raises Uchar.succ_exn Uchar.max_value - let%test _ = Uchar.(to_scalar (succ_exn min_value)) = 0x0001 - let%test _ = Uchar.(to_scalar (succ_exn (of_scalar_exn 0xD7FF))) = 0xE000 - let%test _ = Uchar.(to_scalar (succ_exn (of_scalar_exn 0xE000))) = 0xE001 - end) -;; +module%test [@name "test_succ_exn"] _ = struct + let%test _ = raises Uchar.succ_exn Uchar.max_value + let%test _ = Uchar.(to_scalar (succ_exn min_value)) = 0x0001 + let%test _ = Uchar.(to_scalar (succ_exn (of_scalar_exn 0xD7FF))) = 0xE000 + let%test _ = Uchar.(to_scalar (succ_exn (of_scalar_exn 0xE000))) = 0xE001 +end -let%test_module "test_pred_exn" = - (module struct - let%test _ = raises Uchar.pred_exn Uchar.min_value - let%test _ = Uchar.(to_scalar (pred_exn (of_scalar_exn 0xD7FF))) = 0xD7FE - let%test _ = Uchar.(to_scalar (pred_exn (of_scalar_exn 0xE000))) = 0xD7FF - let%test _ = Uchar.(to_scalar (pred_exn max_value)) = 0x10FFFE - end) -;; +module%test [@name "test_pred_exn"] _ = struct + let%test _ = raises Uchar.pred_exn Uchar.min_value + let%test _ = Uchar.(to_scalar (pred_exn (of_scalar_exn 0xD7FF))) = 0xD7FE + let%test _ = Uchar.(to_scalar (pred_exn (of_scalar_exn 0xE000))) = 0xD7FF + let%test _ = Uchar.(to_scalar (pred_exn max_value)) = 0x10FFFE +end -let%test_module "test_int_is_scalar" = - (module struct - let%test _ = not (Uchar.int_is_scalar (-1)) - let%test _ = Uchar.int_is_scalar 0x0000 - let%test _ = Uchar.int_is_scalar 0xD7FF - let%test _ = not (Uchar.int_is_scalar 0xD800) - let%test _ = not (Uchar.int_is_scalar 0xDFFF) - let%test _ = Uchar.int_is_scalar 0xE000 - let%test _ = Uchar.int_is_scalar 0x10FFFF - let%test _ = not (Uchar.int_is_scalar 0x110000) - let%test _ = not (Uchar.int_is_scalar min_int) - let%test _ = not (Uchar.int_is_scalar max_int) - end) -;; +module%test [@name "test_int_is_scalar"] _ = struct + let%test _ = not (Uchar.int_is_scalar (-1)) + let%test _ = Uchar.int_is_scalar 0x0000 + let%test _ = Uchar.int_is_scalar 0xD7FF + let%test _ = not (Uchar.int_is_scalar 0xD800) + let%test _ = not (Uchar.int_is_scalar 0xDFFF) + let%test _ = Uchar.int_is_scalar 0xE000 + let%test _ = Uchar.int_is_scalar 0x10FFFF + let%test _ = not (Uchar.int_is_scalar 0x110000) + let%test _ = not (Uchar.int_is_scalar min_int) + let%test _ = not (Uchar.int_is_scalar max_int) +end let char_max = Uchar.of_scalar_exn 0x00FF -let%test_module "test_is_char" = - (module struct - let%test _ = Uchar.(is_char Uchar.min_value) - let%test _ = Uchar.(is_char char_max) - let%test _ = Uchar.(not (is_char (of_scalar_exn 0x0100))) - let%test _ = not (Uchar.is_char Uchar.max_value) - end) -;; +module%test [@name "test_is_char"] _ = struct + let%test _ = Uchar.(is_char Uchar.min_value) + let%test _ = Uchar.(is_char char_max) + let%test _ = Uchar.(not (is_char (of_scalar_exn 0x0100))) + let%test _ = not (Uchar.is_char Uchar.max_value) +end -let%test_module "test_of_char" = - (module struct - let%test _ = Uchar.(equal (of_char '\xFF') char_max) - let%test _ = Uchar.(equal (of_char '\x00') min_value) - end) -;; +module%test [@name "test_of_char"] _ = struct + let%test _ = Uchar.(equal (of_char '\xFF') char_max) + let%test _ = Uchar.(equal (of_char '\x00') min_value) +end -let%test_module "test_to_char_exn" = - (module struct - let%test _ = Char.equal Uchar.(to_char_exn min_value) '\x00' - let%test _ = Char.equal Uchar.(to_char_exn char_max) '\xFF' - let%test _ = raises Uchar.to_char_exn (Uchar.succ_exn char_max) - let%test _ = raises Uchar.to_char_exn Uchar.max_value - end) -;; +module%test [@name "test_to_char_exn"] _ = struct + let%test _ = Char.equal Uchar.(to_char_exn min_value) '\x00' + let%test _ = Char.equal Uchar.(to_char_exn char_max) '\xFF' + let%test _ = raises Uchar.to_char_exn (Uchar.succ_exn char_max) + let%test _ = raises Uchar.to_char_exn Uchar.max_value +end -let%test_module "test_equal" = - (module struct - let%test _ = Uchar.(equal min_value min_value) - let%test _ = Uchar.(equal max_value max_value) - let%test _ = not Uchar.(equal min_value max_value) - end) -;; +module%test [@name "test_equal"] _ = struct + let%test _ = Uchar.(equal min_value min_value) + let%test _ = Uchar.(equal max_value max_value) + let%test _ = not Uchar.(equal min_value max_value) +end -let%test_module "test_compare" = - (module struct - let%test _ = Uchar.(compare min_value min_value) = 0 - let%test _ = Uchar.(compare max_value max_value) = 0 - let%test _ = Uchar.(compare min_value max_value) = -1 - let%test _ = Uchar.(compare max_value min_value) = 1 - end) -;; +module%test [@name "test_compare"] _ = struct + let%test _ = Uchar.(compare min_value min_value) = 0 + let%test _ = Uchar.(compare max_value max_value) = 0 + let%test _ = Uchar.(compare min_value max_value) = -1 + let%test _ = Uchar.(compare max_value min_value) = 1 +end diff --git a/test/test_uniform_array.ml b/test/test_uniform_array.ml index f2f4a94..d9cb045 100644 --- a/test/test_uniform_array.ml +++ b/test/test_uniform_array.ml @@ -335,146 +335,137 @@ let%expect_test "unsafe_to_array_inplace__promise_not_a_float" = ;; (* Invariant tests *) -let%test_module (_ [@tags "no-js"]) = - (module ( - struct - type 'a t = 'a Uniform_array.t [@@deriving compare ~localize, sexp_of, sexp_grammar] - - let invariant = Uniform_array.invariant - - (* We test that constructors satisfy the invariant, especially when given floats. *) - - open struct - let test_poly ?(allow_empty = false) ?cr ?(here = Stdlib.Lexing.dummy_pos) t = - assert (allow_empty || length t > 0); - require_does_not_raise ~here ?cr (fun () -> invariant t) - ;; - - let test ?allow_empty ?cr ?(here = Stdlib.Lexing.dummy_pos) (t : float t) = - test_poly ?allow_empty ?cr ~here t - ;; - end - - let t_of_sexp = Uniform_array.t_of_sexp - let%expect_test _ = test (t_of_sexp Float.t_of_sexp (List [ Atom "0" ])) - let empty = Uniform_array.empty - let%expect_test _ = test empty ~allow_empty:true - let create = Uniform_array.create - let%expect_test _ = test (create ~len:1 0.) - let singleton = Uniform_array.singleton - let%expect_test _ = test (singleton 0.) - let init = Uniform_array.init - let%expect_test _ = test (init 1 ~f:(fun _ -> 0.)) - let map = Uniform_array.map - let%expect_test _ = test (map (singleton 0) ~f:(fun _ -> 0.)) - let mapi = Uniform_array.mapi - let%expect_test _ = test (mapi (singleton 0) ~f:(fun _ _ -> 0.)) - let of_array = Uniform_array.of_array - let%expect_test _ = test (of_array [| 0. |]) - let of_list = Uniform_array.of_list - let%expect_test _ = test (of_list [ 0. ]) - let of_list_rev = Uniform_array.of_list_rev - let%expect_test _ = test (of_list_rev [ 0. ]) - let sub = Uniform_array.sub - let%expect_test _ = test (sub (singleton 0.) ~pos:0 ~len:1) - let subo = Uniform_array.subo - let%expect_test _ = test (subo (singleton 0.)) - let copy = Uniform_array.copy - let%expect_test _ = test (copy (singleton 0.)) - let concat = Uniform_array.concat - let%expect_test _ = test (concat [ singleton 0. ]) - let concat_map = Uniform_array.concat_map - let%expect_test _ = test (concat_map (singleton 0) ~f:(fun _ -> singleton 0.)) - let concat_mapi = Uniform_array.concat_mapi - let%expect_test _ = test (concat_mapi (singleton 0) ~f:(fun _ _ -> singleton 0.)) - let partition_map = Uniform_array.partition_map - - let%expect_test _ = - let ts, fs = - partition_map (of_list [ Either.First 0.; Either.Second 0. ]) ~f:Fn.id - in - test ts; - test fs - ;; +module%test [@tags "no-js"] _ : module type of struct + include Uniform_array +end = struct + type 'a t = 'a Uniform_array.t [@@deriving compare ~localize, sexp_of, sexp_grammar] - let filter = Uniform_array.filter - let%expect_test _ = test (filter (singleton 0.) ~f:(fun _ -> true)) - let filteri = Uniform_array.filteri - let%expect_test _ = test (filteri (singleton 0.) ~f:(fun _ _ -> true)) - let filter_map = Uniform_array.filter_map - let%expect_test _ = test (filter_map (singleton 0) ~f:(fun _ -> Some 0.)) - let filter_mapi = Uniform_array.filter_mapi - let%expect_test _ = test (filter_mapi (singleton 0) ~f:(fun _ _ -> Some 0.)) - let map2_exn = Uniform_array.map2_exn - let%expect_test _ = test (map2_exn (singleton 0) (singleton 0) ~f:(fun _ _ -> 0.)) - let unsafe_create_uninitialized = Uniform_array.unsafe_create_uninitialized - - let%expect_test _ = - let t = unsafe_create_uninitialized ~len:1 in - set t 0 0.; - test t - ;; + let invariant = Uniform_array.invariant - let create_obj_array = Uniform_array.create_obj_array + (* We test that constructors satisfy the invariant, especially when given floats. *) - let%expect_test _ = - let t = create_obj_array ~len:1 in - set t 0 (Stdlib.Obj.repr 0.); - test_poly t + open struct + let test_poly ?(allow_empty = false) ?cr ?(here = Stdlib.Lexing.dummy_pos) t = + assert (allow_empty || length t > 0); + require_does_not_raise ~here ?cr (fun () -> invariant t) ;; - (* Accessors, no invariant to test here *) - - let length = Uniform_array.length - let get = Uniform_array.get - let unsafe_get = Uniform_array.unsafe_get - let set = Uniform_array.set - let unsafe_set = Uniform_array.unsafe_set - let swap = Uniform_array.swap - let unsafe_set_omit_phys_equal_check = Uniform_array.unsafe_set_omit_phys_equal_check - let unsafe_set_with_caml_modify = Uniform_array.unsafe_set_with_caml_modify - let set_with_caml_modify = Uniform_array.set_with_caml_modify - let iter = Uniform_array.iter - let iteri = Uniform_array.iteri - let fold = Uniform_array.fold - let foldi = Uniform_array.foldi - - let unsafe_to_array_inplace__promise_not_a_float = - Uniform_array.unsafe_to_array_inplace__promise_not_a_float + let test ?allow_empty ?cr ?(here = Stdlib.Lexing.dummy_pos) (t : float t) = + test_poly ?allow_empty ?cr ~here t ;; - - let to_array = Uniform_array.to_array - let to_list = Uniform_array.to_list - let blit = Uniform_array.blit - let blito = Uniform_array.blito - let unsafe_blit = Uniform_array.unsafe_blit - let exists = Uniform_array.exists - let existsi = Uniform_array.existsi - let for_all = Uniform_array.for_all - let for_alli = Uniform_array.for_alli - let find = Uniform_array.find - let findi = Uniform_array.findi - let find_map = Uniform_array.find_map - let find_mapi = Uniform_array.find_mapi - let fold2_exn = Uniform_array.fold2_exn - let min_elt = Uniform_array.min_elt - let max_elt = Uniform_array.max_elt - let sort = Uniform_array.sort - let binary_search = Uniform_array.binary_search - let binary_search_segmented = Uniform_array.binary_search_segmented - - let unsafe_set_assuming_currently_int = - Uniform_array.unsafe_set_assuming_currently_int - ;; - - let unsafe_set_int_assuming_currently_int = - Uniform_array.unsafe_set_int_assuming_currently_int - ;; - - let unsafe_set_int = Uniform_array.unsafe_set_int - let unsafe_clear_if_pointer = Uniform_array.unsafe_clear_if_pointer - end : - module type of struct - include Uniform_array - end)) -;; + end + + let t_of_sexp = Uniform_array.t_of_sexp + let%expect_test _ = test (t_of_sexp Float.t_of_sexp (List [ Atom "0" ])) + let empty = Uniform_array.empty + let%expect_test _ = test empty ~allow_empty:true + let create = Uniform_array.create + let%expect_test _ = test (create ~len:1 0.) + let singleton = Uniform_array.singleton + let%expect_test _ = test (singleton 0.) + let init = Uniform_array.init + let%expect_test _ = test (init 1 ~f:(fun _ -> 0.)) + let map = Uniform_array.map + let%expect_test _ = test (map (singleton 0) ~f:(fun _ -> 0.)) + let mapi = Uniform_array.mapi + let%expect_test _ = test (mapi (singleton 0) ~f:(fun _ _ -> 0.)) + let of_array = Uniform_array.of_array + let%expect_test _ = test (of_array [| 0. |]) + let of_list = Uniform_array.of_list + let%expect_test _ = test (of_list [ 0. ]) + let of_list_rev = Uniform_array.of_list_rev + let%expect_test _ = test (of_list_rev [ 0. ]) + let sub = Uniform_array.sub + let%expect_test _ = test (sub (singleton 0.) ~pos:0 ~len:1) + let subo = Uniform_array.subo + let%expect_test _ = test (subo (singleton 0.)) + let copy = Uniform_array.copy + let%expect_test _ = test (copy (singleton 0.)) + let concat = Uniform_array.concat + let%expect_test _ = test (concat [ singleton 0. ]) + let concat_map = Uniform_array.concat_map + let%expect_test _ = test (concat_map (singleton 0) ~f:(fun _ -> singleton 0.)) + let concat_mapi = Uniform_array.concat_mapi + let%expect_test _ = test (concat_mapi (singleton 0) ~f:(fun _ _ -> singleton 0.)) + let partition_map = Uniform_array.partition_map + + let%expect_test _ = + let ts, fs = partition_map (of_list [ Either.First 0.; Either.Second 0. ]) ~f:Fn.id in + test ts; + test fs + ;; + + let filter = Uniform_array.filter + let%expect_test _ = test (filter (singleton 0.) ~f:(fun _ -> true)) + let filteri = Uniform_array.filteri + let%expect_test _ = test (filteri (singleton 0.) ~f:(fun _ _ -> true)) + let filter_map = Uniform_array.filter_map + let%expect_test _ = test (filter_map (singleton 0) ~f:(fun _ -> Some 0.)) + let filter_mapi = Uniform_array.filter_mapi + let%expect_test _ = test (filter_mapi (singleton 0) ~f:(fun _ _ -> Some 0.)) + let map2_exn = Uniform_array.map2_exn + let%expect_test _ = test (map2_exn (singleton 0) (singleton 0) ~f:(fun _ _ -> 0.)) + let unsafe_create_uninitialized = Uniform_array.unsafe_create_uninitialized + + let%expect_test _ = + let t = unsafe_create_uninitialized ~len:1 in + set t 0 0.; + test t + ;; + + let create_obj_array = Uniform_array.create_obj_array + + let%expect_test _ = + let t = create_obj_array ~len:1 in + set t 0 (Stdlib.Obj.repr 0.); + test_poly t + ;; + + (* Accessors, no invariant to test here *) + + let length = Uniform_array.length + let get = Uniform_array.get + let unsafe_get = Uniform_array.unsafe_get + let set = Uniform_array.set + let unsafe_set = Uniform_array.unsafe_set + let swap = Uniform_array.swap + let unsafe_set_omit_phys_equal_check = Uniform_array.unsafe_set_omit_phys_equal_check + let unsafe_set_with_caml_modify = Uniform_array.unsafe_set_with_caml_modify + let set_with_caml_modify = Uniform_array.set_with_caml_modify + let iter = Uniform_array.iter + let iteri = Uniform_array.iteri + let fold = Uniform_array.fold + let foldi = Uniform_array.foldi + + let unsafe_to_array_inplace__promise_not_a_float = + Uniform_array.unsafe_to_array_inplace__promise_not_a_float + ;; + + let to_array = Uniform_array.to_array + let to_list = Uniform_array.to_list + let blit = Uniform_array.blit + let blito = Uniform_array.blito + let unsafe_blit = Uniform_array.unsafe_blit + let exists = Uniform_array.exists + let existsi = Uniform_array.existsi + let for_all = Uniform_array.for_all + let for_alli = Uniform_array.for_alli + let find = Uniform_array.find + let findi = Uniform_array.findi + let find_map = Uniform_array.find_map + let find_mapi = Uniform_array.find_mapi + let fold2_exn = Uniform_array.fold2_exn + let min_elt = Uniform_array.min_elt + let max_elt = Uniform_array.max_elt + let sort = Uniform_array.sort + let binary_search = Uniform_array.binary_search + let binary_search_segmented = Uniform_array.binary_search_segmented + let unsafe_set_assuming_currently_int = Uniform_array.unsafe_set_assuming_currently_int + + let unsafe_set_int_assuming_currently_int = + Uniform_array.unsafe_set_int_assuming_currently_int + ;; + + let unsafe_set_int = Uniform_array.unsafe_set_int + let unsafe_clear_if_pointer = Uniform_array.unsafe_clear_if_pointer +end