From 49c06e93fa6dc721c15904d123c9ac8f7f3c4bb8 Mon Sep 17 00:00:00 2001 From: Simon Cruanes Date: Thu, 30 Jun 2022 22:28:19 -0400 Subject: [PATCH] wip: use testlib for tests --- tests/core/dune | 3 +- tests/core/t.ml | 16 +- tests/core/t_array.ml | 166 +++++++++ tests/core/t_bool.ml | 13 + tests/core/t_byte_buffer.ml | 124 +++++++ tests/core/t_canonical_sexp.ml | 49 +++ tests/core/t_char.ml | 10 + tests/core/t_either.ml | 16 + tests/core/t_eq.ml | 8 + tests/core/t_float.ml | 19 ++ tests/core/t_format.ml | 93 +++++ tests/core/t_fun.ml | 22 ++ tests/core/t_hash.ml | 15 + tests/core/t_list.ml | 597 ++++++++++++++++++++++++++------- 14 files changed, 1028 insertions(+), 123 deletions(-) create mode 100644 tests/core/t_array.ml create mode 100644 tests/core/t_bool.ml create mode 100644 tests/core/t_byte_buffer.ml create mode 100644 tests/core/t_canonical_sexp.ml create mode 100644 tests/core/t_char.ml create mode 100644 tests/core/t_either.ml create mode 100644 tests/core/t_eq.ml create mode 100644 tests/core/t_float.ml create mode 100644 tests/core/t_format.ml create mode 100644 tests/core/t_fun.ml create mode 100644 tests/core/t_hash.ml diff --git a/tests/core/dune b/tests/core/dune index b05279c4..44f81944 100644 --- a/tests/core/dune +++ b/tests/core/dune @@ -1,5 +1,4 @@ (test (name t) - (flags :standard -strict-sequence -warn-error -a+8 -open - Containers_testlib.Prelude) + (flags :standard -strict-sequence -warn-error -a+8) (libraries containers containers_testlib)) diff --git a/tests/core/t.ml b/tests/core/t.ml index a42fcdbd..301e80b6 100644 --- a/tests/core/t.ml +++ b/tests/core/t.ml @@ -1,4 +1,16 @@ -include T_list ;; -Containers_testlib.run_all ~descr:"containers" ();; +Containers_testlib.run_all ~descr:"containers" [ + T_list.get(); + T_array.get(); + T_bool.get(); + T_byte_buffer.get(); + T_canonical_sexp.get(); + T_char.get(); + T_either.get(); + T_eq.get(); + T_float.get(); + T_format.get(); + T_fun.get (); + T_hash.get(); +];; diff --git a/tests/core/t_array.ml b/tests/core/t_array.ml new file mode 100644 index 00000000..d6b2da46 --- /dev/null +++ b/tests/core/t_array.ml @@ -0,0 +1,166 @@ + +open CCArray + +module T = (val Containers_testlib.make ~__FILE__ ()) +include T;; + +t @@ fun () -> + let st = Random.State.make [||] in let a = 0--10000 in + let b = Array.copy a in shuffle_with st a; a <> b;; + +eq (Some 1) (get_safe [|1;2;3|] 0);; +eq (Some 2) (get_safe [|1;2;3|] 1);; +eq (Some 3) (get_safe [|1;2;3|] 2);; +eq None (get_safe [|1;2;3|] 4);; +eq None (get_safe [|1;2;3|] max_int);; +eq None (get_safe [|1;2;3|] ~-1);; +eq None (get_safe [|1;2;3|] ~-42);; + +q Q.(array int) (fun a -> + let b = map ((+) 1) a in + map_inplace ((+) 1) a; + b = a);; + +t @@ fun () -> fold_while (fun acc b -> if b then acc+1, `Continue else acc, `Stop) 0 (Array.of_list [true;true;false;true]) = 2;; + +eq (6, [|"1"; "2"; "3"|]) + (fold_map (fun acc x->acc+x, string_of_int x) 0 [|1;2;3|]);; + +q Q.(array int) (fun a -> + fold_map (fun acc x -> x::acc, x) [] a = (List.rev @@ Array.to_list a, a));; + +eq ~printer:Q.Print.(array int) [|0;1;3;6|] (scan_left (+) 0 [|1;2;3|]);; +eq ~printer:Q.Print.(array int) [|0|] (scan_left (+) 0 [||]);; + +t @@ fun () -> reverse_in_place [| |]; true;; +t @@ fun () -> reverse_in_place [| 1 |]; true;; +t @@ fun () -> let a = [| 1; 2; 3; 4; 5 |] in + reverse_in_place a; + a = [| 5;4;3;2;1 |];; +t @@ fun () -> let a = [| 1; 2; 3; 4; 5; 6 |] in + reverse_in_place a; + a = [| 6;5;4;3;2;1 |];; + +eq ~cmp:(=) ~printer:Q.Print.(array int) [||] (sorted Stdlib.compare [||]);; +eq ~cmp:(=) ~printer:Q.Print.(array int) [|0;1;2;3;4|] (sorted Stdlib.compare [|3;2;1;4;0|]);; + +q Q.(array int) (fun a -> + let b = Array.copy a in + Array.sort Stdlib.compare b; b = sorted Stdlib.compare a);; + +eq ~cmp:(=) ~printer:Q.Print.(array int) [||] (sort_indices Stdlib.compare [||]);; +eq ~cmp:(=) ~printer:Q.Print.(array int) [|4;2;1;0;3|] (sort_indices Stdlib.compare [|"d";"c";"b";"e";"a"|]);; + +q Q.(array_of_size Gen.(0 -- 30) printable_string) (fun a -> + let b = sort_indices String.compare a in + sorted String.compare a = Array.map (Array.get a) b);; + +eq ~cmp:(=) ~printer:Q.Print.(array int) [||] (sort_ranking Stdlib.compare [||]);; +eq ~cmp:(=) ~printer:Q.Print.(array int) [|3;2;1;4;0|] (sort_ranking Stdlib.compare [|"d";"c";"b";"e";"a"|]);; + +q Q.(array_of_size Gen.(0--50) printable_string) (fun a -> + let b = sort_ranking String.compare a in + let a_sorted = sorted String.compare a in + a = Array.map (Array.get a_sorted) b);; + +q Q.(array small_int) (fun a -> rev (rev a) = a);; + +t @@ fun () -> rev [| 1; 2; 3 |] = [| 3; 2; 1 |];; +t @@ fun () -> rev [| 1; 2; |] = [| 2; 1 |];; +t @@ fun () -> rev [| |] = [| |];; + +q Q.(array small_int) (fun a -> + mem 1 a = (Array.mem 1 a));; + +t @@ fun () -> filter_map (fun x -> if x mod 2 = 0 then Some (string_of_int x) else None) + [| 1; 2; 3; 4 |] = [| "2"; "4" |];; +t @@ fun () -> filter_map (fun x -> if x mod 2 = 0 then Some (string_of_int x) else None) + [| 1; 2; 3; 4; 5; 6 |] + = [| "2"; "4"; "6" |];; +t @@ fun () -> let a = [| 1; 3; 5 |] in + let a' = flat_map (fun x -> [| x; x+1 |]) a in + a' = [| 1; 2; 3; 4; 5; 6 |];; + +eq ~cmp:(=) ~printer:Q.Print.(array int) [| 11; 12; 21; 22 |] (sorted CCInt.compare @@ monoid_product (+) [| 10; 20 |] [| 1; 2 |]);; +eq ~cmp:(=) ~printer:Q.Print.(array int) [| 11; 12; 13; 14 |] (sorted CCInt.compare @@ monoid_product (+) [| 10 |] [| 1; 2; 3; 4 |]);; + +t @@ fun () -> lookup ~cmp:CCInt.compare 2 [|0;1;2;3;4;5|] = Some 2;; +t @@ fun () -> lookup ~cmp:CCInt.compare 4 [|0;1;2;3;4;5|] = Some 4;; +t @@ fun () -> lookup ~cmp:CCInt.compare 0 [|1;2;3;4;5|] = None;; +t @@ fun () -> lookup ~cmp:CCInt.compare 6 [|1;2;3;4;5|] = None;; +t @@ fun () -> lookup ~cmp:CCInt.compare 3 [| |] = None;; +t @@ fun () -> lookup ~cmp:CCInt.compare 1 [| 1 |] = Some 0;; +t @@ fun () -> lookup ~cmp:CCInt.compare 2 [| 1 |] = None;; + +t @@ fun () -> bsearch ~cmp:CCInt.compare 3 [|1; 2; 2; 3; 4; 10|] = `At 3;; +t @@ fun () -> bsearch ~cmp:CCInt.compare 5 [|1; 2; 2; 3; 4; 10|] = `Just_after 4;; +t @@ fun () -> bsearch ~cmp:CCInt.compare 1 [|1; 2; 5; 5; 11; 12|] = `At 0;; +t @@ fun () -> bsearch ~cmp:CCInt.compare 12 [|1; 2; 5; 5; 11; 12|] = `At 5;; +t @@ fun () -> bsearch ~cmp:CCInt.compare 10 [|1; 2; 2; 3; 4; 9|] = `All_lower;; +t @@ fun () -> bsearch ~cmp:CCInt.compare 0 [|1; 2; 2; 3; 4; 9|] = `All_bigger;; +t @@ fun () -> bsearch ~cmp:CCInt.compare 3 [| |] = `Empty;; + +t @@ fun () -> (1 -- 4) |> Array.to_list = [1;2;3;4];; +t @@ fun () -> (4 -- 1) |> Array.to_list = [4;3;2;1];; +t @@ fun () -> (0 -- 0) |> Array.to_list = [0];; + +q Q.(pair small_int small_int) (fun (a,b) -> + (a -- b) |> Array.to_list = CCList.(a -- b));; +q Q.(pair small_int small_int) (fun (a,b) -> + (a --^ b) |> Array.to_list = CCList.(a --^ b));; +q Q.(pair (array small_int)(array small_int)) (fun (a,b) -> + equal (=) a b = equal (=) b a);; + +t @@ fun () -> equal (=) [|1|] [|1|];; +t @@ fun () -> compare CCOrd.poly [| 1; 2; 3 |] [| 1; 2; 3 |] = 0;; +t @@ fun () -> compare CCOrd.poly [| 1; 2; 3 |] [| 2; 2; 3 |] < 0;; +t @@ fun () -> compare CCOrd.poly [| 1; 2; |] [| 1; 2; 3 |] < 0;; +t @@ fun () -> compare CCOrd.poly [| 1; 2; 3 |] [| 1; 2; |] > 0;; + +t @@ fun () -> let a = [| 1;2;3 |] in + swap a 0 1; + a = [| 2;1;3 |];; +t @@ fun () -> let a = [| 1;2;3 |] in + swap a 0 2; + a = [| 3;2;1 |];; + +q Q.(array_of_size Gen.(0 -- 100) small_int) (fun a -> + let b = Array.copy a in + for i = 0 to Array.length a-1 do + for j = i+1 to Array.length a-1 do + swap a i j; done; done; + for i = 0 to Array.length a-1 do + for j = i+1 to Array.length a-1 do + swap a i j; done; done; + a=b);; + +eq ~printer:(fun s -> s) (to_string string_of_int [|1;2;3;4;5;6|]) "1, 2, 3, 4, 5, 6";; +eq ~printer:(fun s -> s) (to_string string_of_int [||]) "";; +eq ~printer:(fun s -> s) (to_string ~sep:" " string_of_int [|1;2;3;4;5;6|]) "1 2 3 4 5 6";; +eq ~printer:(fun s -> s) (to_string string_of_int [|1|]) "1";; + +eq [] (to_seq [||] |> CCList.of_seq);; +eq [1;2;3] (to_seq [|1;2;3|] |> CCList.of_seq);; +eq CCList.(1 -- 1000) (to_seq (1--1000) |> CCList.of_seq);; + +module IA = struct + let get = Array.get + let set = Array.set + let length = Array.length + type elt = int + type t = int array +end + +let gen_arr = Q.Gen.(array_size (1--100) small_int) +let arr_arbitrary = Q.make + ~print:Q.Print.(array int) + ~small:Array.length + ~shrink:Q.Shrink.(array ?shrink:None) + gen_arr;; + +q ~count:300 + arr_arbitrary (fun a -> + let a1 = Array.copy a and a2 = Array.copy a in + Array.sort CCInt.compare a1; sort_generic (module IA) ~cmp:CCInt.compare a2; + a1 = a2 );; + diff --git a/tests/core/t_bool.ml b/tests/core/t_bool.ml new file mode 100644 index 00000000..5d3e6623 --- /dev/null +++ b/tests/core/t_bool.ml @@ -0,0 +1,13 @@ + +open CCBool + +module T = (val Containers_testlib.make ~__FILE__ ()) +include T;; + +eq 1 (to_int true);; +eq 0 (to_int false);; +eq true (of_int 1);; +eq false (of_int 0);; +eq true (of_int 42);; +eq true (of_int max_int);; +eq true (of_int min_int);; diff --git a/tests/core/t_byte_buffer.ml b/tests/core/t_byte_buffer.ml new file mode 100644 index 00000000..3088349b --- /dev/null +++ b/tests/core/t_byte_buffer.ml @@ -0,0 +1,124 @@ + +module T = (val Containers_testlib.make ~__FILE__ ()) +include T;; + +open CCByte_buffer;; + +t @@ fun () -> (let b = create() in is_empty b);; +t @@ fun () -> (let b = create ~cap:32 () in is_empty b);; +t @@ fun () -> (let b = create() in length b = 0);; +t @@ fun () -> (let b = create ~cap:32 () in length b = 0);; + +let test_count = 2_500 + +open QCheck + +type op = + | Add_char of char + | Add_string of string + | Get_contents + | Get of int + | Clear + | Shrink_to of int + | Set of int * char + +let spf = Printf.sprintf + +let str_op = function + | Add_char c -> spf "add_char %C" c + | Add_string s -> spf "add_string %S" s + | Get_contents -> "contents" + | Get i -> spf "get %d" i + | Clear -> "clear" + | Shrink_to n -> spf "shrink %d" n + | Set (i,c) -> spf "set %d %C" i c + +let gen_op size : (_*_) Gen.t = + let open Gen in + let base = if size>0 then + [1, ((0--size) >|= fun x -> Get x, size); + 1, ((0--size) >>= fun x -> printable >|= fun c -> Set (x,c), size); + 1, ((0--size) >|= fun x -> Shrink_to x, x); + ] + else [] + in + frequency (base @ [ + 1, return (Get_contents, size); + 1, return (Clear, 0); + 3, (printable >|= fun c -> Add_char c, size+1); + 1, (string_size (0 -- 100) ~gen:printable >|= fun s -> + Add_string s, size+String.length s); + ]) + +let rec gen_l acc sz n = + let open Gen in + if n=0 then return (List.rev acc) + else ( + gen_op sz >>= fun (op, sz) -> + gen_l (op::acc) sz (n-1) + ) + +let gen : op list Gen.t = Gen.sized (gen_l [] 0) + +let is_valid ops = + let rec loop sz = function + | [] -> true + | Add_char _ :: tl -> loop (sz+1) tl + | Clear :: tl -> loop 0 tl + | Add_string s :: tl -> loop (sz+String.length s) tl + | (Get n | Set (n,_)) :: tl -> n < sz && loop sz tl + | Get_contents :: tl -> loop sz tl + | Shrink_to x :: tl -> x <= sz && loop x tl + in loop 0 ops + +let shrink_op = Iter.(function + | Get_contents | Clear -> empty + | Get n -> Shrink.int n >|= fun n->Get n + | Add_char c -> Shrink.char c >|= fun c -> Add_char c + | Add_string s -> Shrink.string s >|= fun s -> Add_string s + | Shrink_to n -> Shrink.int n >|= fun n -> Shrink_to n + | Set (n,c) -> + (Shrink.int n >|= fun n-> Set(n,c)) <+> + (Shrink.char c >|= fun c-> Set(n,c)) + ) + +let arb = make gen ~print:(Print.list str_op) + ~shrink:Shrink.(filter is_valid @@ list ~shrink:shrink_op) + +exception Nope of string +let prop_consistent ops = + let buf = ref "" in + let b = create ~cap:32 () in + + let run_op op = + match op with + | Get i -> + assert (String.length !buf = length b); + let c1 = (!buf).[i] in + let c2 = get b i in + if c1<>c2 then raise (Nope (spf "c1=%C, c2=%C" c1 c2)) + + | Get_contents -> + let s1 = !buf in + let s2 = contents b in + if s1<>s2 then raise (Nope (spf "s1=%S, s2=%S" s1 s2)) + + | Add_char c -> buf := !buf ^ String.make 1 c; add_char b c + | Add_string s -> buf := !buf ^ s; append_string b s + | Clear -> buf := ""; clear b + | Shrink_to n -> buf := String.sub !buf 0 n; shrink_to b n + | Set (n,c) -> + ( + let b' = Bytes.of_string !buf in + Bytes.set b' n c; + buf := Bytes.unsafe_to_string b'; + ); + set b n c + in + + assume (is_valid ops); + try List.iter run_op ops; true + with Nope str -> + Test.fail_reportf "consistent ops failed:\n%s" str;; + +q arb (fun ops -> prop_consistent ops);; diff --git a/tests/core/t_canonical_sexp.ml b/tests/core/t_canonical_sexp.ml new file mode 100644 index 00000000..d2049552 --- /dev/null +++ b/tests/core/t_canonical_sexp.ml @@ -0,0 +1,49 @@ + +open CCCanonical_sexp + +module T = (val Containers_testlib.make ~__FILE__ ()) +include T;; + +let csexp_bijective s = to_string s |> parse_string = Ok s;; + +eq ~printer:CCFormat.(to_string (Dump.result pp)) (Ok (`List [`Atom ""])) (parse_string {|(0:)|});; +eq ~printer:CCFormat.(to_string (Dump.result pp)) (Ok (`List [`Atom "a"; `Atom "b "])) (parse_string {|(1:a2:b )|});; + +t @@ fun () -> csexp_bijective (`List [`Atom ""]);; + +let sexp_gen = + let mkatom a = `Atom a and mklist l = `List l in + let atom = Q.Gen.(map mkatom (string_size ~gen:char (1 -- 30))) in + let gen = Q.Gen.( + sized (fix + (fun self n st -> match n with + | 0 -> atom st + | _ -> + frequency + [ 1, atom + ; 2, map mklist (list_size (0 -- 10) (self (n/10))) + ] st + ) + )) in + let rec small = function + | `Atom s -> String.length s + | `List l -> List.fold_left (fun n x->n+small x) 0 l + and print = function + | `Atom s -> Printf.sprintf "`Atom \"%s\"" s + | `List l -> "`List " ^ Q.Print.list print l + and shrink = function + | `Atom s -> Q.Iter.map mkatom (Q.Shrink.string s) + | `List l -> Q.Iter.map mklist (Q.Shrink.list ~shrink l) + in + Q.make ~print ~small ~shrink gen ;; + +q ~count:100 sexp_gen csexp_bijective ;; + +t @@ fun () -> let s1 = + `List (CCList.init 100_000 + (fun i -> `List [`Atom "-"; `Atom (string_of_int i); `Atom ")(\n]"])) in + let str = to_string s1 in + (match parse_string str with + | Ok s2 -> assert_equal s1 s2 + | Error e -> assert_failure e); + true;; diff --git a/tests/core/t_char.ml b/tests/core/t_char.ml new file mode 100644 index 00000000..142a48fd --- /dev/null +++ b/tests/core/t_char.ml @@ -0,0 +1,10 @@ + + +open CCChar + +module T = (val Containers_testlib.make ~__FILE__ ()) +include T;; + +eq (Some 'a') (of_int (to_int 'a'));; +eq None (of_int 257);; +q (Q.string_of_size (Q.Gen.return 1)) (fun s -> CCShims_.Stdlib.(=) (to_string s.[0]) s);; diff --git a/tests/core/t_either.ml b/tests/core/t_either.ml new file mode 100644 index 00000000..0b91e1e1 --- /dev/null +++ b/tests/core/t_either.ml @@ -0,0 +1,16 @@ + +open CCEither + +module T = (val Containers_testlib.make ~__FILE__ ()) +include T;; + +eq (is_left (Left 1)) (true);; +eq (is_left (Right 1)) (false);; +eq (is_left (Left 1)) (true);; +eq (is_left (Right 1)) (false);; +eq (is_right (Left 1)) (false);; +eq (is_right (Right 1)) (true);; +eq (find_left (Left 1)) (Some 1);; +eq (find_left (Right 1)) (None);; +eq (find_right (Left 1)) (None);; +eq (find_right (Right 1)) (Some 1);; diff --git a/tests/core/t_eq.ml b/tests/core/t_eq.ml new file mode 100644 index 00000000..19569565 --- /dev/null +++ b/tests/core/t_eq.ml @@ -0,0 +1,8 @@ + +open CCEqual + +module T = (val Containers_testlib.make ~__FILE__ ()) +include T;; + +q Q.(let p = small_list (pair small_int bool) in pair p p) (fun (l1,l2) -> + CCEqual.(list (pair int bool)) l1 l2 = (l1=l2));; diff --git a/tests/core/t_float.ml b/tests/core/t_float.ml new file mode 100644 index 00000000..13241699 --- /dev/null +++ b/tests/core/t_float.ml @@ -0,0 +1,19 @@ + +open CCFloat + +module T = (val Containers_testlib.make ~__FILE__ ()) +include T;; + +t @@ fun () -> max nan 1. = 1.;; +t @@ fun () -> min nan 1. = 1.;; +t @@ fun () -> max 1. nan = 1.;; +t @@ fun () -> min 1. nan = 1.;; + +q Q.(pair float float) (fun (x,y) -> + is_nan x || is_nan y || (min x y <= x && min x y <= y));; +q Q.(pair float float) (fun (x,y) -> + is_nan x || is_nan y || (max x y >= x && max x y >= y));; + +eq 2. (round 1.6);; +eq 1. (round 1.4);; +eq 0. (round 0.);; diff --git a/tests/core/t_format.ml b/tests/core/t_format.ml new file mode 100644 index 00000000..3e270560 --- /dev/null +++ b/tests/core/t_format.ml @@ -0,0 +1,93 @@ + +open CCFormat + +module T = (val Containers_testlib.make ~__FILE__ ()) +include T;; + +let to_string_test s = CCFormat.sprintf_no_color "@[%a@]%!" s ();; + +eq ~printer:(fun s->CCFormat.sprintf "%S" s) "a b" (to_string_test (return "a@ b"));; +eq ~printer:(fun s->CCFormat.sprintf "%S" s) ", " (to_string_test (return ",@ "));; +eq ~printer:(fun s->CCFormat.sprintf "%S" s) "and then" (to_string_test (return "@{and then@}@,"));; +eq ~printer:(fun s->CCFormat.sprintf "%S" s) "a b" (to_string_test (return "@[a@ b@]"));; + + +eq ~printer:(fun s->CCFormat.sprintf "%S" s) "a\nb\nc" + (sprintf_no_color "@[%a@]%!" text "a b c");; +eq ~printer:(fun s->CCFormat.sprintf "%S" s) "a b\nc" + (sprintf_no_color "@[%a@]%!" text "a b\nc");; + + +eq ~printer:(fun s->CCFormat.sprintf "%S" s) + "(a\n b\n c)" (sprintf_no_color "(@[%a@])" string_lines "a\nb\nc");; + + +eq ~printer:(fun s -> CCFormat.sprintf "%S" s) "foobar" + (to_string_test (append (return "foo") (return "bar")));; +eq ~printer:(fun s -> CCFormat.sprintf "%S" s) "bar" + (to_string_test (append (return "") (return "bar")));; +eq ~printer:(fun s -> CCFormat.sprintf "%S" s) "foo" + (to_string_test (append (return "foo") (return "")));; + + +eq ~printer:(fun s -> CCFormat.sprintf "%S" s) "" (to_string_test @@ append_l []);; +eq ~printer:(fun s -> CCFormat.sprintf "%S" s) "foobarbaz" (to_string_test @@ append_l (List.map return ["foo"; "bar"; "baz"]));; +eq ~printer:(fun s -> CCFormat.sprintf "%S" s) "3141" (to_string_test @@ append_l (List.map (const int) [3; 14; 1]));; + +t @@ fun () -> + let buf1 = Buffer.create 42 in + let buf2 = Buffer.create 42 in + let f1 = Format.formatter_of_buffer buf1 in + let f2 = Format.formatter_of_buffer buf2 in + let fmt = tee f1 f2 in + Format.fprintf fmt "coucou@."; + assert_equal ~printer:CCFun.id "coucou\n" (Buffer.contents buf1); + assert_equal ~printer:CCFun.id "coucou\n" (Buffer.contents buf2); + true;; + +t @@ fun () -> + set_color_default true; + let s = sprintf + "what is your %a? %a! No, %a! Ahhhhhhh@." + (styling [`FG `White; `Bold] string) "favorite color" + (styling [`FG `Blue] string) "blue" + (styling [`FG `Red] string) "red" + in + assert_equal ~printer:CCFun.id + "what is your \027[37;1mfavorite color\027[0m? \027[34mblue\027[0m! No, \027[31mred\027[0m! Ahhhhhhh\n" + s; + true +;; + +t @@ fun () -> + set_color_default true; + let s = sprintf + "what is your @{favorite color@}? @{blue@}! No, @{red@}! Ahhhhhhh@." + in + assert_equal ~printer:CCFun.id + "what is your \027[37;1mfavorite color\027[0m? \027[34mblue\027[0m! No, \027[31mred\027[0m! Ahhhhhhh\n" + s; + true;; + +t @@ fun () -> sprintf "yolo %s %d" "a b" 42 = "yolo a b 42";; +t @@ fun () -> sprintf "%d " 0 = "0 ";; +t @@ fun () -> sprintf_no_color "%d " 0 = "0 ";; + +t @@ fun () -> + set_color_default true; + assert_equal "\027[31myolo\027[0m" (sprintf "@{yolo@}"); + assert_equal "yolo" (sprintf_no_color "@{yolo@}"); + true;; + +eq ~printer:CCFormat.(to_string (opt string)) + (Some "hello world") + (ksprintf ~f:(fun s -> Some s) "hello %a" CCFormat.string "world");; + + +eq ~printer:(fun s->s) "[1;2;3]" (to_string Dump.(list int) [1;2;3]);; +eq ~printer:(fun s->s) "Some 1" (to_string Dump.(option int) (Some 1));; +eq ~printer:(fun s->s) "[None;Some \"a b\"]" (to_string Dump.(list (option string)) [None; Some "a b"]);; +eq ~printer:(fun s->s) "[(Ok \"a b c\");(Error \"nope\")]" + (to_string Dump.(list (result string)) [Ok "a b c"; Error "nope"]);; + +eq ANSI_codes.reset "\x1b[0m";; diff --git a/tests/core/t_fun.ml b/tests/core/t_fun.ml new file mode 100644 index 00000000..f844753e --- /dev/null +++ b/tests/core/t_fun.ml @@ -0,0 +1,22 @@ + +open CCFun + +module T = (val Containers_testlib.make ~__FILE__ ()) +include T;; + + +eq ~printer:Q.Print.int 10 (iterate 0 succ 10);; +eq ~printer:Q.Print.int 11 (iterate 1 succ 10);; +eq ~printer:Q.Print.int 12 (iterate 2 succ 10);; +eq ~printer:Q.Print.int 15 (iterate 5 succ 10);; + +t @@ fun () -> + assert_raises + (function Invalid_argument _ -> true | _ -> false) + (fun () -> iterate (-1) succ 10); + true;; + +t @@ fun () -> CCFun.((succ %> string_of_int) 2 = "3");; +t @@ fun () -> CCFun.((( * ) 3 % succ) 5 = 18);; +t @@ fun () -> CCFun.(succ @@ ( * ) 2 @@ pred @@ 3 = 5);; +t @@ fun () -> CCFun.(3 |> succ |> ( * ) 5 |> pred = 19);; diff --git a/tests/core/t_hash.ml b/tests/core/t_hash.ml new file mode 100644 index 00000000..1a877ea4 --- /dev/null +++ b/tests/core/t_hash.ml @@ -0,0 +1,15 @@ + +open CCHash + +module T = (val Containers_testlib.make ~__FILE__ ()) +include T;; + +t @@ fun () -> int 42 >= 0;; +t @@ fun () -> int max_int >= 0;; +t @@ fun () -> int max_int = int max_int;; +t @@ fun () -> int min_int >= 0;; +t @@ fun () -> int 0 >= 0;; +t @@ fun () -> char 'c' >= 0;; +t @@ fun () -> int 152352 = int 152352;; +t @@ fun () -> list_comm int [1;2] = list_comm int [2;1];; +t @@ fun () -> list_comm int [1;2] <> list_comm int [2;3];; diff --git a/tests/core/t_list.ml b/tests/core/t_list.ml index ef894c6b..cb2328fe 100644 --- a/tests/core/t_list.ml +++ b/tests/core/t_list.ml @@ -1,194 +1,186 @@ open CCList +module T = (val Containers_testlib.make ~__FILE__ ()) +include T;; + let lsort l = CCList.sort Stdlib.compare l;; -q ~__FILE__ ~__LINE__ - Q.(pair small_nat (list int)) (fun (i,l) -> +q Q.(pair small_nat (list int)) (fun (i,l) -> nth_opt l i = get_at_idx i l);; -q ~__FILE__ ~__LINE__ - Q.(pair (list int) (list int)) (fun (l1,l2) -> +q Q.(pair (list int) (list int)) (fun (l1,l2) -> CCOrd.equiv (CCList.compare_lengths l1 l2) (CCInt.compare (length l1)(length l2)));; -q ~__FILE__ ~__LINE__ - Q.(pair (list int) small_int) (fun (l,n) -> +q Q.(pair (list int) small_int) (fun (l,n) -> CCOrd.equiv (CCList.compare_length_with l n) (CCInt.compare (length l) n));; -q ~__FILE__ ~__LINE__ +q (Q.list Q.small_int) (fun l -> let f x = x+1 in List.rev (List.rev_map f l) = map f l);; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> [1;2;3] @ [4;5;6] = [1;2;3;4;5;6];; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> (1-- 10_000) @ (10_001 -- 20_000) = 1 -- 20_000;; -q ~__FILE__ ~__LINE__ - Q.(small_list int)(fun l -> List.rev l = List.fold_left cons' [] l);; +q Q.(small_list int)(fun l -> List.rev l = List.fold_left cons' [] l);; -t ~__FILE__ ~__LINE__ @@ fun () -> - cons_maybe (Some 1) [2;3] = [1;2;3];; +t @@ fun () -> cons_maybe (Some 1) [2;3] = [1;2;3];; -t ~__FILE__ ~__LINE__ @@ fun () -> - cons_maybe None [2;3] = [2;3];; +t @@ fun () -> cons_maybe None [2;3] = [2;3];; -eq ~__FILE__ ~__LINE__ ~printer:CCInt.to_string +eq ~printer:CCInt.to_string 500 (filter (fun x->x mod 2 = 0) (1 -- 1000) |> List.length);; -eq ~__FILE__ ~__LINE__ ~printer:CCInt.to_string +eq ~printer:CCInt.to_string 50_000 (filter (fun x->x mod 2 = 0) (1 -- 100_000) |> List.length);; -eq ~__FILE__ ~__LINE__ ~printer:CCInt.to_string +eq ~printer:CCInt.to_string 500_000 (filter (fun x->x mod 2 = 0) (1 -- 1_000_000) |> List.length);; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> fold_right (+) (1 -- 1_000_000) 0 = List.fold_left (+) 0 (1 -- 1_000_000);; -q ~__FILE__ ~__LINE__ - (Q.list Q.small_int) (fun l -> +q (Q.list Q.small_int) (fun l -> l = fold_right (fun x y->x::y) l []);; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> fold_while (fun acc b -> if b then acc+1, `Continue else acc, `Stop) 0 [true;true;false;true] = 2 ;; -eq ~__FILE__ ~__LINE__ +eq (6, ["1"; "2"; "3"]) (fold_map (fun acc x->acc+x, string_of_int x) 0 [1;2;3]);; -q ~__FILE__ ~__LINE__ - Q.(list int) (fun l -> +q Q.(list int) (fun l -> fold_map (fun acc x -> x::acc, x) [] l = (List.rev l, l));; -eq ~__FILE__ ~__LINE__ - 6 (fold_on_map ~f:int_of_string ~reduce:(+) 0 ["1";"2";"3"]);; +eq 6 (fold_on_map ~f:int_of_string ~reduce:(+) 0 ["1";"2";"3"]);; -eq ~__FILE__ ~__LINE__ - ~printer:Q.Print.(option int) +eq ~printer:Q.Print.(option int) (Some 15) (reduce (+) [1; 2; 3; 4; 5]);; -eq ~__FILE__ ~__LINE__ +eq ~printer:Q.Print.(option int) (Some 3) (reduce CCInt.min [5; 3; 8; 9]);; -eq ~__FILE__ ~__LINE__ +eq ~printer:Q.Print.string "hello world" (reduce_exn (^) ["hello"; " "; "world"]);; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> try ignore (reduce_exn (+.) []); false with Invalid_argument _ -> true;; -eq ~__FILE__ ~__LINE__ +eq ~printer:Q.Print.(list int) [0;1;3;6] (scan_left (+) 0 [1;2;3]);; -eq ~__FILE__ ~__LINE__ +eq ~printer:Q.Print.(list int) [0] (scan_left (+) 0 []);; -q ~__FILE__ ~__LINE__ - Q.(list int) (fun l -> +q + Q.(list int) (fun l -> List.length l + 1 = List.length (scan_left (+) 0 l));; -eq ~__FILE__ ~__LINE__ - (310, ["1 10"; "2 0"; "3 100"]) - (fold_map2 (fun acc x y->acc+x*y, string_of_int x ^ " " ^ string_of_int y) +eq + (310, ["1 10"; "2 0"; "3 100"]) + (fold_map2 (fun acc x y->acc+x*y, string_of_int x ^ " " ^ string_of_int y) 0 [1;2;3] [10;0;100]);; -t ~__FILE__ ~__LINE__ @@ fun () -> - (try ignore (fold_map2 (fun _ _ _ -> assert false) 42 [] [1]); false +t @@ fun () -> + (try ignore (fold_map2 (fun _ _ _ -> assert false) 42 [] [1]); false with Invalid_argument _ -> true);; -eq ~__FILE__ ~__LINE__ +eq ~printer:Q.Print.(pair int (list int)) (List.fold_left (+) 0 (1--10), [2;4;6;8;10]) (fold_filter_map (fun acc x -> acc+x, if x mod 2 = 0 then Some x else None) 0 (1--10));; -eq ~__FILE__ ~__LINE__ - (6, ["1"; "a1"; "2"; "a2"; "3"; "a3"]) - (let pf = Printf.sprintf in +eq + (6, ["1"; "a1"; "2"; "a2"; "3"; "a3"]) + (let pf = Printf.sprintf in fold_flat_map (fun acc x->acc+x, [pf "%d" x; pf "a%d" x]) 0 [1;2;3]);; -q ~__FILE__ ~__LINE__ - Q.(list int) (fun l -> - fold_flat_map (fun acc x -> x::acc, [x;x+10]) [] l = +q + Q.(list int) (fun l -> + fold_flat_map (fun acc x -> x::acc, [x;x+10]) [] l = (List.rev l, flat_map (fun x->[x;x+10]) l) );; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> init 0 (fun _ -> 0) = [];; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> init 1 (fun x->x) = [0];; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> init 1000 (fun x->x) = 0--999;; (* see: #256 *) -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> let r = ref [] in ignore (CCList.init 5 (fun x -> r := x :: !r; ())); assert_equal ~printer:Q.Print.(list int) (List.rev !r) [0;1;2;3;4]; true;; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> let r = ref [] in ignore (CCList.init 200_000 (fun x -> r := x :: !r; ())); assert_equal ~printer:Q.Print.(list int) (List.rev !r) (0--(200_000-1)); true ;; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> equal CCInt.equal (1--1_000_000) (1--1_000_000);; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> flat_map (fun x -> [x+1; x*2]) [10;100] = [11;20;101;200];; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> List.length (flat_map (fun x->[x]) (1--300_000)) = 300_000;; -eq ~__FILE__ ~__LINE__ - [1;2;2;3;3;3] (flat_map_i (fun i x->replicate (i+1) x) [1;2;3]);; +eq [1;2;2;3;3;3] (flat_map_i (fun i x->replicate (i+1) x) [1;2;3]);; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> flatten [[1]; [2;3;4]; []; []; [5;6]] = 1--6;; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> flatten (init 300_001 (fun x->[x])) = 0--300_000;; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> count (fun x -> x mod 2 = 0) [] = 0;; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> count (fun x -> x mod 2 = 0) [0; 0; 2; 4] = 4;; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> count (fun x -> x mod 2 = 0) [1; 3; 5; 7] = 0;; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> count (fun x -> x mod 2 = 0) [2; 6; 9; 4] = 3;; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> count_true_false (fun x -> x mod 2 = 0) [] = (0, 0);; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> count_true_false (fun x -> x mod 2 = 0) [0; 0; 2; 4] = (4, 0);; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> count_true_false (fun x -> x mod 2 = 0) [1; 3; 5; 7] = (0, 4);; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> count_true_false (fun x -> x mod 2 = 0) [2; 6; 9; 4] = (3, 1);; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> diagonal [] = [];; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> diagonal [1] = [];; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> diagonal [1;2] = [1,2];; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> diagonal [1;2;3] |> List.sort Stdlib.compare = [1, 2; 1, 3; 2, 3];; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> let l1, l2 = partition_map_either (function | n when n mod 2 = 0 -> CCEither.Left n @@ -199,7 +191,7 @@ t ~__FILE__ ~__LINE__ @@ fun () -> assert_equal [1;3] l2; true;; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> let l1, l2 = partition_filter_map (function | n when n = 0 -> `Drop @@ -211,97 +203,464 @@ t ~__FILE__ ~__LINE__ @@ fun () -> assert_equal [1;3] l2; true;; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> try ignore (combine [1] []); false with Invalid_argument _ -> true;; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> try ignore (combine (1--1001) (1--1002)); false with Invalid_argument _ -> true;; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> combine [1;2;3] [3;2;1] = List.combine [1;2;3] [3;2;1];; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> combine (1 -- 100_000) (1 -- 100_000) = List.combine (1 -- 100_000) (1 -- 100_000);; -q ~__FILE__ ~__LINE__ - Q.(let p = small_list int in pair p p)(fun (l1,l2) -> - if List.length l1=List.length l2 - then CCList.combine l1 l2 = List.combine l1 l2 +q + Q.(let p = small_list int in pair p p)(fun (l1,l2) -> + if List.length l1=List.length l2 + then CCList.combine l1 l2 = List.combine l1 l2 else Q.assume_fail() );; -q ~__FILE__ ~__LINE__ - Q.(let p = small_list int in pair p p)(fun (l1,l2) -> - let n = min (List.length l1) (List.length l2) in - let res1 = combine (take n l1) (take n l2) in - let res2 = combine_gen l1 l2 |> of_gen in +q + Q.(let p = small_list int in pair p p)(fun (l1,l2) -> + let n = min (List.length l1) (List.length l2) in + let res1 = combine (take n l1) (take n l2) in + let res2 = combine_gen l1 l2 |> of_gen in res1 = res2);; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> (combine_shortest [] []) = [];; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> (combine_shortest [1] []) = [];; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> (combine_shortest [] [1]) = [];; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> (combine_shortest (1--1025) (1--1026)) = List.combine (1--1025) (1--1025);; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> (combine_shortest (1--1026) (1--1025)) = List.combine (1--1025) (1--1025);; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> combine_shortest [1;2;3] [3;2;1] = List.combine [1;2;3] [3;2;1];; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> combine_shortest (1 -- 100_000) (1 -- 100_000) = List.combine (1 -- 100_000) (1 -- 100_000);; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> combine_shortest (1 -- 100_001) (1 -- 100_000) = List.combine (1 -- 100_000) (1 -- 100_000);; -q ~__FILE__ ~__LINE__ - (Q.(list_of_size Gen.(0--10_000) (pair small_int small_string))) (fun l -> - let (l1, l2) = split l in - List.length l1 = List.length l +q + (Q.(list_of_size Gen.(0--10_000) (pair small_int small_string))) (fun l -> + let (l1, l2) = split l in + List.length l1 = List.length l && List.length l2 = List.length l);; -q ~__FILE__ ~__LINE__ - Q.(list_of_size Gen.(0--10_000) (pair small_int small_int)) (fun l -> +q + Q.(list_of_size Gen.(0--10_000) (pair small_int small_int)) (fun l -> split l = List.split l);; let cmp_lii_unord l1 l2 : bool = - List.sort CCOrd.compare l1 = List.sort CCOrd.compare l2;; + List.sort CCOrd.poly l1 = List.sort CCOrd.poly l2;; -eq ~__FILE__ ~__LINE__ +eq ~printer:Q.Print.(list (list int)) ~cmp:cmp_lii_unord - [[1;3;4];[1;3;5];[1;3;6];[2;3;4];[2;3;5];[2;3;6]] + [[1;3;4];[1;3;5];[1;3;6];[2;3;4];[2;3;5];[2;3;6]] (cartesian_product [[1;2];[3];[4;5;6]]);; -eq ~__FILE__ ~__LINE__ +eq ~printer:Q.Print.(list (list int)) ~cmp:cmp_lii_unord [] (cartesian_product [[1;2];[];[4;5;6]]); -eq ~__FILE__ ~__LINE__ +eq ~printer:Q.Print.(list (list int)) ~cmp:cmp_lii_unord [[]] (cartesian_product []);; -eq ~__FILE__ ~__LINE__ +eq ~printer:Q.Print.(list (list int)) ~cmp:cmp_lii_unord - [[1;3;4;5;6];[2;3;4;5;6]] + [[1;3;4;5;6];[2;3;4;5;6]] (cartesian_product [[1;2];[3];[4];[5];[6]]);; -q ~__FILE__ ~__LINE__ - Q.(list_of_size Gen.(1--4) (list_of_size Gen.(0--4) small_int)) (fun l-> +q + Q.(list_of_size Gen.(1--4) (list_of_size Gen.(0--4) small_int)) (fun l-> cmp_lii_unord (cartesian_product l) (map_product_l CCFun.id l));; -q ~__FILE__ ~__LINE__ - Q.(pair small_int (list small_int)) (fun (x,l) -> +q + Q.(pair small_int (list small_int)) (fun (x,l) -> sorted_mem ~cmp:CCInt.compare x (List.sort CCInt.compare l) = mem ~eq:CCInt.equal x l) ;; -t ~__FILE__ ~__LINE__ @@ fun () -> - equal CCInt.equal (List.sort CCInt.compare ([(( * )2); ((+)1)] <*> [10;100])) +t @@ fun () -> + equal CCInt.equal (List.sort CCInt.compare ([(( * )2); ((+)1)] <*> [10;100])) [11; 20; 101; 200] ;; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> equal CCInt.equal (sorted_merge ~cmp:CCInt.compare [1;1;2] [1;2;3]) [1;1;1;2;2;3] ;; -q ~__FILE__ ~__LINE__ - Q.(pair (list int) (list int)) (fun (l1,l2) -> +q + Q.(pair (list int) (list int)) (fun (l1,l2) -> List.length (sorted_merge ~cmp:CCInt.compare l1 l2) = List.length l1 + List.length l2);; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> equal CCInt.equal (sorted_diff ~cmp:CCInt.compare [0;1;1;2;4] [1;2;2;2;3]) [0;1;4];; -t ~__FILE__ ~__LINE__ @@ fun () -> +t @@ fun () -> equal CCInt.equal (sorted_diff ~cmp:CCInt.compare [2] [1;2;2;2;3]) [];; + +q Q.(pair (list small_int) (list small_int)) (fun (l1,l2) -> + List.length (sorted_merge ~cmp:CCInt.compare l1 l2) = List.length l1 + List.length l2) ;; + +q Q.(pair (list small_int) (list small_int)) (fun (l1,l2) -> + let l = sorted_diff ~cmp:CCInt.compare (List.sort CCInt.compare l1) + (List.sort CCInt.compare l2) in + l = sort CCInt.compare l) (* [is_sorted] is after this function *) ;; + +q + Q.(triple small_nat small_nat int) (fun (n1,n2,x) -> + let l = sorted_diff ~cmp:CCInt.compare (CCList.init n1 (fun _ -> x)) + (CCList.init n2 (fun _ -> x)) in + count (CCInt.equal x) l = CCInt.max (n1 - n2) 0) ;; + +q Q.(pair (list small_int) (list small_int)) (fun (l1,l2) -> + let l1 = List.sort CCInt.compare l1 in + let l2 = List.sort CCInt.compare l2 in + l1 = sorted_diff ~cmp:CCInt.compare (sorted_merge ~cmp:CCInt.compare l1 l2) l2) ;; + +t @@ fun () -> sort_uniq ~cmp:CCInt.compare [1;2;5;3;6;1;4;2;3] = [1;2;3;4;5;6] ;; +t @@ fun () -> sort_uniq ~cmp:CCInt.compare [] = [] ;; +t @@ fun () -> sort_uniq ~cmp:CCInt.compare [10;10;10;10;1;10] = [1;10] ;; + + +q Q.(list small_int) (fun l -> + is_sorted ~cmp:CCInt.compare (List.sort Stdlib.compare l)) ;; + +q Q.(pair small_int (list small_int)) (fun (x,l) -> + let l = List.sort Stdlib.compare l in + is_sorted ~cmp:CCInt.compare (sorted_insert ~cmp:CCInt.compare x l));; + +q Q.(pair small_int (list small_int)) (fun (x,l) -> + let l = List.sort Stdlib.compare l in + is_sorted ~cmp:CCInt.compare (sorted_insert ~cmp:CCInt.compare ~uniq:true x l));; + +q Q.(pair small_int (list small_int)) (fun (x,l) -> + let l = List.sort Stdlib.compare l in + is_sorted ~cmp:CCInt.compare (sorted_insert ~cmp:CCInt.compare ~uniq:false x l));; + +q Q.(pair small_int (list small_int)) (fun (x,l) -> + let l = List.sort Stdlib.compare l in + let l' = sorted_insert ~cmp:CCInt.compare ~uniq:false x l in + List.length l' = List.length l + 1);; + +q Q.(pair small_int (list small_int)) (fun (x,l) -> + let l = List.sort Stdlib.compare l in + List.mem x (sorted_insert ~cmp:CCInt.compare x l));; + +q Q.(pair small_int (list small_int)) (fun (x,l) -> + let l = List.sort Stdlib.compare l in + is_sorted ~cmp:CCInt.compare (sorted_remove ~cmp:CCInt.compare x l)) ;; + +q Q.(pair small_int (list small_int)) (fun (x,l) -> + let l = List.sort Stdlib.compare l in + is_sorted ~cmp:CCInt.compare (sorted_remove ~cmp:CCInt.compare ~all:false x l)) ;; + +q Q.(pair small_int (list small_int)) (fun (x,l) -> + let l = List.sort Stdlib.compare l in + is_sorted ~cmp:CCInt.compare (sorted_remove ~cmp:CCInt.compare ~all:true x l)) ;; + +q Q.(pair small_int (list small_int)) (fun (x,l) -> + let l = List.sort Stdlib.compare l in + let l' = sorted_remove ~cmp:CCInt.compare x l in + List.length l' = List.length l - (if List.mem x l then 1 else 0)) ;; + +q Q.(pair small_int (list small_int)) (fun (x,l) -> + let l = List.sort Stdlib.compare l in + let l' = sorted_remove ~cmp:CCInt.compare ~all:true x l in + List.length l' = List.length l - count (CCInt.equal x) l) ;; + +q Q.(pair small_int (list small_int)) (fun (x,l) -> + let l = List.sort Stdlib.compare l in + let l' = sorted_remove ~cmp:CCInt.compare ~all:false x l in + List.length l' = List.length l - (if List.mem x l then 1 else 0)) ;; + +q Q.(pair small_int (list small_int)) (fun (x,l) -> + let l = List.sort Stdlib.compare l in + let l' = sorted_remove ~cmp:CCInt.compare x l in + count (CCInt.equal x) l' = count (CCInt.equal x) l - (if List.mem x l then 1 else 0)) ;; + +q Q.(pair small_int (list small_int)) (fun (x,l) -> + let l = List.sort Stdlib.compare l in + let l' = sorted_remove ~cmp:CCInt.compare ~all:false x l in + count (CCInt.equal x) l' = count (CCInt.equal x) l - (if List.mem x l then 1 else 0)) ;; + +q Q.(pair small_int (list small_int)) (fun (x,l) -> + let l = List.sort Stdlib.compare l in + not (List.mem x (sorted_remove ~cmp:CCInt.compare ~all:true x l))) ;; + +t @@ fun () -> uniq_succ ~eq:CCInt.equal [1;1;2;3;1;6;6;4;6;1] = [1;2;3;1;6;4;6;1] ;; + +t @@ fun () -> group_succ ~eq:CCInt.equal [1;2;3;1;1;2;4] = [[1]; [2]; [3]; [1;1]; [2]; [4]];; +t @@ fun () -> group_succ ~eq:CCInt.equal [] = [];; +t @@ fun () -> group_succ ~eq:CCInt.equal [1;1;1] = [[1;1;1]];; +t @@ fun () -> group_succ ~eq:CCInt.equal [1;2;2;2] = [[1]; [2;2;2]];; +t @@ fun () -> group_succ ~eq:(fun (x,_)(y,_)-> x=y) [1, 1; 1, 2; 1, 3; 2, 0] + = [[1, 1; 1, 2; 1, 3]; [2, 0]];; + +t @@ fun () -> sorted_merge_uniq ~cmp:CCInt.compare + [1; 1; 2; 3; 5; 8] [1; 2; 3; 4; 6; 8; 9; 9] = [1;2;3;4;5;6;8;9];; + +q Q.(list int) (fun l -> + let l = List.sort Stdlib.compare l in + sorted_merge_uniq ~cmp:CCInt.compare l [] = uniq_succ ~eq:CCInt.equal l);; +q Q.(list int) (fun l -> + let l = List.sort Stdlib.compare l in + sorted_merge_uniq ~cmp:CCInt.compare [] l = uniq_succ ~eq:CCInt.equal l);; +q Q.(pair (list int) (list int)) (fun (l1, l2) -> + let l1 = List.sort Stdlib.compare l1 + and l2 = List.sort Stdlib.compare l2 in + let l3 = sorted_merge_uniq ~cmp:CCInt.compare l1 l2 in + uniq_succ ~eq:CCInt.equal l3 = l3);; + +t @@ fun () -> sorted_diff_uniq ~cmp:CCInt.compare [1; 1; 1; 2; 2; 3; 5; 8; 8; 8] [1; 2; 2; 2; 2; 8; 13; 13; 13] = [1;3;5;8];; + +q Q.(pair (list small_int) (list small_int)) (fun (l1, l2) -> + let l1 = List.sort CCInt.compare l1 in + let l2 = List.sort CCInt.compare l2 in + is_sorted ~cmp:CCInt.compare (sorted_diff_uniq ~cmp:CCInt.compare l1 l2)) ;; +q Q.(pair (list small_int) (list small_int)) (fun (l1, l2) -> + let l1 = List.sort CCInt.compare l1 in + let l2 = List.sort CCInt.compare l2 in + sorted_diff_uniq ~cmp:CCInt.compare l1 l2 = uniq_succ ~eq:CCInt.equal (sorted_diff ~cmp:CCInt.compare l1 l2)) ;; + +t @@ fun () -> take 2 [1;2;3;4;5] = [1;2] ;; +t @@ fun () -> take 10_000 (range 0 100_000) |> List.length = 10_000 ;; +t @@ fun () -> take 10_000 (range 0 2_000) = range 0 2_000 ;; +t @@ fun () -> take 300_000 (1 -- 400_000) = 1 -- 300_000 ;; + +q (Q.pair (Q.list Q.small_int) Q.int) (fun (l,i) -> + let i = abs i in + let l1 = take i l in + List.length l1 <= i && ((List.length l1 = i) = (List.length l >= i)));; + +t @@ fun () -> try ignore (hd_tl []); false with Failure _ -> true ;; +t @@ fun () -> hd_tl [1;2;3] = (1, [2;3]) ;; + +q (Q.pair (Q.list Q.small_int) Q.int) (fun (l,i) -> + let i = abs i in + let l1, l2 = take_drop i l in + l1 @ l2 = l ) ;; + +let subs = sublists_of_len ;; +eq ~printer:Q.Print.(list (list int)) [[1;2;3]] (subs 3 [1;2;3;4]) ;; +eq ~printer:Q.Print.(list (list int)) [[1;2]; [3;4]; [5;6]] (subs 2 [1;2;3;4;5;6]) ;; +eq ~printer:Q.Print.(list (list int)) [] (subs 3 [1;2]) ;; +eq ~printer:Q.Print.(list (list int)) [[1;2];[3;4]] (subs ~offset:2 2 [1;2;3;4]) ;; +eq ~printer:Q.Print.(list (list int)) [[1;2];[2;3]] (subs ~offset:1 2 [1;2;3]) ;; +eq ~printer:Q.Print.(list (list int)) [[1;2];[4;5]] (subs ~offset:3 2 [1;2;3;4;5;6]) ;; +eq ~printer:Q.Print.(list (list int)) [[1;2;3];[4]] (subs ~last:CCOption.return 3 [1;2;3;4]) ;; +eq ~printer:Q.Print.(list (list int)) [[1;2]; [3;4]] (subs 2 [1;2;3;4;5]) ;; + +q Q.(small_list small_int) (fun l -> + l = (chunks 3 l |> List.flatten)) ;; +q Q.(small_list small_int) (fun l -> + l = (chunks 5 l |> List.flatten)) ;; +q Q.(small_list small_int) (fun l -> + List.for_all (fun u -> List.length u <= 5) (chunks 5 l)) ;; + +eq [] (intersperse 0 []) ;; +eq [1] (intersperse 0 [1]) ;; +eq [1;0;2;0;3;0;4] (intersperse 0 [1;2;3;4]) ;; + +q Q.(pair int (list int)) (fun (x,l) -> + length (intersperse x l) = (if length l <= 1 then length l else 2 * length l-1)) ;; +q Q.(pair int (list int)) (fun (x,l) -> + rev (intersperse x l) = intersperse x (rev l)) ;; + +eq [1;2;3;4;5] (interleave [1;3] [2;4;5]);; +eq [1;2;3] (interleave [1] [2;3]);; + +q Q.(pair (small_list int)(small_list int)) (fun (l1,l2) -> + length (interleave l1 l2) = length l1 + length l2) ;; +q Q.(small_list int) (fun l -> l = interleave [] l) ;; +q Q.(small_list int) (fun l -> l = interleave l []) ;; + +t @@ fun () -> take_while (fun x->x<10) (1 -- 20) = (1--9) ;; +t @@ fun () -> take_while (fun x->x <> 0) [0;1;2;3] = [] ;; +t @@ fun () -> take_while (fun _ -> true) [] = [] ;; +t @@ fun () -> take_while (fun _ -> true) (1--10) = (1--10) ;; + +q Q.(pair (fun1 Observable.int bool) (list small_int)) (fun (f,l) -> + let l1 = take_while (Q.Fn.apply f) l in + List.for_all (Q.Fn.apply f) l1) ;; +q Q.(pair (fun1 Observable.int bool) (list small_int)) (fun (f,l) -> + take_while (Q.Fn.apply f) l @ drop_while (Q.Fn.apply f) l = l) ;; + +q Q.(pair (fun1 Observable.int bool) (list small_int)) (fun (f,l) -> + let l1,l2 = take_drop_while (Q.Fn.apply f) l in + (l1 = take_while (Q.Fn.apply f) l) && (l2 = drop_while (Q.Fn.apply f) l)) ;; + +eq ~printer:Q.Print.(option (list int)) (Some [2;3]) (tail_opt [1;2;3]);; +eq ~printer:Q.Print.(option (list int)) (Some []) (tail_opt [1]);; +eq ~printer:Q.Print.(option (list int)) None (tail_opt []);; + +eq ~printer:Q.Print.(option int) (Some 1) (head_opt [1;2;3]);; +eq ~printer:Q.Print.(option int) (Some 1) (head_opt [1]);; +eq ~printer:Q.Print.(option int) None (head_opt []);; +eq ~printer:Q.Print.(option int) (Some 3) (last_opt [1;2;3]);; +eq ~printer:Q.Print.(option int) (Some 1) (last_opt [1]);; +eq ~printer:Q.Print.(option int) None (last_opt []);; + +t @@ fun () -> find_pred ((=) 4) [1;2;5;4;3;0] = Some 4 ;; +t @@ fun () -> find_pred (fun _ -> true) [] = None ;; +t @@ fun () -> find_pred (fun _ -> false) (1 -- 10) = None ;; +t @@ fun () -> find_pred (fun x -> x < 10) (1 -- 9) = Some 1 ;; +t @@ fun () -> find_map (fun x -> if x=3 then Some "a" else None) [1;2;3;4] = Some "a" ;; +t @@ fun () -> find_map (fun x -> if x=3 then Some "a" else None) [1;2;4;5] = None ;; +t @@ fun () -> remove ~eq:CCInt.equal ~key:1 [2;1;3;3;2;1] = [2;3;3;2] ;; +t @@ fun () -> remove ~eq:CCInt.equal ~key:10 [1;2;3] = [1;2;3] ;; + +eq ["2"; "4"] + (filter_map (fun x -> if x mod 2 = 0 then Some (string_of_int x) else None) + [1;2;3;4;5]);; +eq [ "2"; "4"; "6" ] + (filter_map (fun x -> if x mod 2 = 0 then Some (string_of_int x) else None) + [ 1; 2; 3; 4; 5; 6 ]);; + +eq (Some []) (all_some []);; +eq (Some [1;2;3]) (all_some [Some 1; Some 2; Some 3]);; +eq None (all_some [Some 1; None; None; Some 4]);; + +t @@ fun () -> + let s1 = (1 -- 3) in + let s2 = ["1"; "2"] in + let join_row i j = + if string_of_int i = j then Some (string_of_int i ^ " = " ^ j) else None + in + let s = join ~join_row s1 s2 in + assert_equal ["1 = 1"; "2 = 2"] s; + true;; + +eq ['a', ["abc"; "attic"]; + 'b', ["barbary"; "boom"; "bop"]; + 'c', []] + (group_join_by (fun s->s.[0]) + (CCString.to_list "abc") + ["abc"; "boom"; "attic"; "deleted"; "barbary"; "bop"] + |> map (fun (c,l)->c,List.sort Stdlib.compare l) + |> sort Stdlib.compare);; + +eq (Ok []) (all_ok []);; +eq (Ok [1;2;3]) (all_ok [Ok 1; Ok 2; Ok 3]);; +eq (Error "e2") (all_ok [Ok 1; Error "e2"; Error "e3"; Ok 4]);; + +q Q.(small_list small_int) (fun l -> + mem 1 l = (List.mem 1 l));; + +q Q.(pair int (list int)) (fun (x,l) -> + remove_one ~eq:CCInt.equal x (add_nodup ~eq:CCInt.equal x l) = l);; +q Q.(pair int (list int)) (fun (x,l) -> + mem ~eq:CCInt.equal x l || List.length (add_nodup ~eq:CCInt.equal x l) = List.length l + 1);; +q Q.(pair int (list int)) (fun (x,l) -> + not (mem ~eq:CCInt.equal x l) || List.length (remove_one ~eq:CCInt.equal x l) = List.length l - 1);; + +t @@ fun () -> uniq ~eq:CCInt.equal [1;2;3] |> List.sort Stdlib.compare = [1;2;3];; +t @@ fun () -> uniq ~eq:CCInt.equal [1;1;2;2;3;4;4;2;4;1;5] |> List.sort Stdlib.compare = [1;2;3;4;5];; + +q Q.(small_list small_int) (fun l -> + sort_uniq ~cmp:CCInt.compare l = (uniq ~eq:CCInt.equal l |> sort Stdlib.compare)) ;; + +t @@ fun () -> union ~eq:CCInt.equal [1;2;4] [2;3;4;5] = [1;2;3;4;5];; +t @@ fun () -> inter ~eq:CCInt.equal [1;2;4] [2;3;4;5] = [2;4];; +t @@ fun () -> mapi (fun i x -> i*x) [10;10;10] = [0;10;20];; +t @@ fun () -> get_at_idx 0 (range 0 10) = Some 0;; +t @@ fun () -> get_at_idx 5 (range 0 10) = Some 5;; +t @@ fun () -> get_at_idx 11 (range 0 10) = None;; +t @@ fun () -> get_at_idx (-1) (range 0 10) = Some 10;; +t @@ fun () -> get_at_idx 0 [] = None;; +t @@ fun () -> get_at_idx (-1) [] = None;; +t @@ fun () -> set_at_idx 0 10 [1;2;3] = [10;2;3];; +t @@ fun () -> set_at_idx 4 10 [1;2;3] = [1;2;3];; +t @@ fun () -> set_at_idx 1 10 [1;2;3] = [1;10;3];; +t @@ fun () -> set_at_idx (-2) 10 [1;2;3] = [1;10;3];; +t @@ fun () -> insert_at_idx 0 10 [1;2;3] = [10;1;2;3];; +t @@ fun () -> insert_at_idx 4 10 [1;2;3] = [1;2;3;10];; +t @@ fun () -> insert_at_idx 1 10 [1;2;3] = [1;10;2;3];; +t @@ fun () -> insert_at_idx (-2) 10 [1;2;3] = [1;10;2;3];; +t @@ fun () -> remove_at_idx 0 [1;2;3;4] = [2;3;4];; +t @@ fun () -> remove_at_idx 3 [1;2;3;4] = [1;2;3];; +t @@ fun () -> remove_at_idx 5 [1;2;3;4] = [1;2;3;4];; +t @@ fun () -> remove_at_idx (-1) [1;2;3;4] = [1;2;3];; +t @@ fun () -> remove_at_idx (-2) [1;2;3;4] = [1;2;4];; +t @@ fun () -> remove_at_idx (-3) [1;2;3;4] = [1;3;4];; +t @@ fun () -> remove_at_idx (-4) [1;2;3;4] = [2;3;4];; + +(* note: the last test checks that no error occurs due to overflows. *) +t @@ fun () -> range_by ~step:1 0 0 = [0];; +t @@ fun () -> range_by ~step:1 5 0 = [];; +t @@ fun () -> range_by ~step:2 1 0 = [];; +t @@ fun () -> range_by ~step:2 0 4 = [0;2;4];; +t @@ fun () -> range_by ~step:2 0 5 = [0;2;4];; +t @@ fun () -> range_by ~step:~-1 0 0 = [0];; +t @@ fun () -> range_by ~step:~-1 0 5 = [];; +t @@ fun () -> range_by ~step:~-2 0 1 = [];; +t @@ fun () -> range_by ~step:~-2 5 1 = [5;3;1];; +t @@ fun () -> range_by ~step:~-2 5 0 = [5;3;1];; +t @@ fun () -> range_by ~step:max_int 0 2 = [0];; + +q Q.(pair small_int small_int) (fun (i,j) -> + let i = min i j and j = max i j in + range_by ~step:1 i j = range i j) ;; + +t @@ fun () -> range 0 5 = [0;1;2;3;4;5];; +t @@ fun () -> range 0 0 = [0];; +t @@ fun () -> range 5 2 = [5;4;3;2];; +t @@ fun () -> range' 0 0 = [];; +t @@ fun () -> range' 0 5 = [0;1;2;3;4];; +t @@ fun () -> range' 5 2 = [5;4;3];; +t @@ fun () -> append (range 0 100) (range 101 1000) = range 0 1000;; +t @@ fun () -> append (range 1000 501) (range 500 0) = range 1000 0;; + +q Q.(pair small_int small_int) (fun (a,b) -> + let l = (a--^b) in not (List.mem b l));; + +t @@ fun () -> repeat 2 [1;2;3] = [1;2;3;1;2;3];; + +q Q.(pair small_int (small_list int)) (fun (n,l) -> + if n>0 then repeat n l = flat_map (fun _ -> l) (1--n) +else Q.assume_fail()) ;; + +t @@ fun () -> Assoc.get ~eq:CCInt.equal 1 [1, "1"; 2, "2"] = Some "1";; +t @@ fun () -> Assoc.get ~eq:CCInt.equal 2 [1, "1"; 2, "2"] = Some "2";; +t @@ fun () -> Assoc.get ~eq:CCInt.equal 3 [1, "1"; 2, "2"] = None;; +t @@ fun () -> Assoc.get ~eq:CCInt.equal 42 [] = None;; +t @@ fun () -> Assoc.set ~eq:CCInt.equal 2 "two" [1,"1"; 2, "2"] |> List.sort Stdlib.compare + = [1, "1"; 2, "two"];; +t @@ fun () -> Assoc.set ~eq:CCInt.equal 3 "3" [1,"1"; 2, "2"] |> List.sort Stdlib.compare += [1, "1"; 2, "2"; 3, "3"];; +t @@ fun () -> Assoc.mem ~eq:CCInt.equal 1 [1,"1"; 2,"2"; 3, "3"];; +t @@ fun () -> not (Assoc.mem ~eq:CCInt.equal 4 [1,"1"; 2,"2"; 3, "3"]);; + +eq [1,"1"; 2,"22"] + (Assoc.update ~eq:CCInt.equal + ~f:(function Some "2" -> Some "22" | _ -> assert false) 2 [1,"1"; 2,"2"] |> lsort);; +eq [1,"1"; 3,"3"] + (Assoc.update ~eq:CCInt.equal + ~f:(function Some "2" -> None | _ -> assert false) 2 [1,"1"; 2,"2"; 3,"3"] |> lsort);; +eq [1,"1"; 2,"2"; 3,"3"] + (Assoc.update ~eq:CCInt.equal + ~f:(function None -> Some "3" | _ -> assert false) 3 [1,"1"; 2,"2"] |> lsort);; +eq [1,"1"] + (Assoc.remove ~eq:CCInt.equal 2 [1,"1"; 2,"2"] |> lsort);; +eq [1,"1"; 3,"3"] + (Assoc.remove ~eq:CCInt.equal 2 [1,"1"; 2,"2"; 3,"3"] |> lsort);; +eq [1,"1"; 2,"2"] + (Assoc.remove ~eq:CCInt.equal 3 [1,"1"; 2,"2"] |> lsort);; + +t @@ fun () -> let l = Ref.create() in Ref.push l 1; Ref.push_list l [2;3]; !l = [3;2;1];; +t @@ fun () -> random_len 10 CCInt.random_small (Random.State.make [||]) |> List.length = 10;; + +eq ~printer:(fun s -> s) (to_string string_of_int []) "";; +eq ~printer:(fun s -> s) (to_string ~start:"[" ~stop:"]" string_of_int []) "[]";; +eq ~printer:(fun s -> s) (to_string ~start:"[" ~stop:"]" string_of_int [1]) "[1]";; +eq ~printer:(fun s -> s) (to_string ~start:"[" ~stop:"]" string_of_int [1;2;3;4]) "[1, 2, 3, 4]";; +eq ~printer:(fun s -> s) (to_string ~sep:" " string_of_int [1;2;3;4]) "1 2 3 4";; + +q Q.(list int) (fun l -> of_iter (to_iter l) = l);; +q Q.(list int) (fun l -> of_gen(to_gen l) = l);; + + +eq ~printer:(fun s->s) "[1, 2, 3]" + (CCFormat.to_string + (CCFormat.hbox(CCList.pp ~pp_start:(fun fmt () -> Format.fprintf fmt "[") + ~pp_stop:(fun fmt () -> Format.fprintf fmt "]") CCFormat.int)) + [1;2;3]);;