diff --git a/tests/core/t_heap.ml b/tests/core/t_heap.ml index 6c2ee2ed..9a3e96a0 100644 --- a/tests/core/t_heap.ml +++ b/tests/core/t_heap.ml @@ -2,106 +2,121 @@ open CCHeap module T = (val Containers_testlib.make ~__FILE__ ()) include T +(* A QCheck generator for natural numbers that are not too large (larger than + * [small_nat] but smaller than [big_nat]), with a bias towards smaller numbers. + * This also happens to be what QCheck uses for picking a length for a list + * generated by [QCheck.list]. + * QCheck defines this generator under the name [nat] but does not expose it. *) +let medium_nat = + Q.make ~print:Q.Print.int ~shrink:Q.Shrink.int ~small:(fun _ -> 1) + (fun st -> + let p = Random.State.float st 1. in + if p < 0.5 then Random.State.int st 10 + else if p < 0.75 then Random.State.int st 100 + else if p < 0.95 then Random.State.int st 1_000 + else Random.State.int st 10_000 + ) + module H = CCHeap.Make (struct type t = int - let leq x y = x <= y end) -let rec is_sorted l = - match l with - | [ _ ] | [] -> true - | x :: (y :: _ as l') -> x <= y && is_sorted l' - -let extract_list = H.to_list_sorted;; - -t @@ fun () -> -let h = H.of_list [ 5; 3; 4; 1; 42; 0 ] in -let h, x = H.take_exn h in -assert_equal ~printer:string_of_int 0 x; -let h, x = H.take_exn h in -assert_equal ~printer:string_of_int 1 x; -let h, x = H.take_exn h in -assert_equal ~printer:string_of_int 3 x; -let h, x = H.take_exn h in -assert_equal ~printer:string_of_int 4 x; -let h, x = H.take_exn h in -assert_equal ~printer:string_of_int 5 x; -let h, x = H.take_exn h in -assert_equal ~printer:string_of_int 42 x; -assert_raises - (function - | H.Empty -> true - | _ -> false) - (fun () -> H.take_exn h); -true ;; -q ~count:30 - Q.(list_of_size Gen.(return 1_000) int) +t ~name:"of_list, take_exn" @@ fun () -> + let h = H.of_list [ 5; 4; 3; 4; 1; 42; 0 ] in + let h, x = H.take_exn h in + assert_equal ~printer:string_of_int 0 x; + let h, x = H.take_exn h in + assert_equal ~printer:string_of_int 1 x; + let h, x = H.take_exn h in + assert_equal ~printer:string_of_int 3 x; + let h, x = H.take_exn h in + assert_equal ~printer:string_of_int 4 x; + let h, x = H.take_exn h in + assert_equal ~printer:string_of_int 4 x; + let h, x = H.take_exn h in + assert_equal ~printer:string_of_int 5 x; + let h, x = H.take_exn h in + assert_equal ~printer:string_of_int 42 x; + assert_raises ((=) H.Empty) (fun () -> H.take_exn h); + true +;; + +q ~name:"of_list, to_list" + ~count:30 + Q.(list medium_nat) (fun l -> - (* put elements into a heap *) - let h = H.of_iter (Iter.of_list l) in - assert_equal 1_000 (H.size h); - let l' = extract_list h in - is_sorted l') + (l |> H.of_list |> H.to_list |> List.sort CCInt.compare) + = (l |> List.sort CCInt.compare)) ;; -(* test filter *) -q ~count:30 - Q.(list_of_size Gen.(return 1_000) int) +q ~name:"of_list, to_list_sorted" + ~count:30 + Q.(list medium_nat) (fun l -> - (* put elements into a heap *) - let h = H.of_iter (Iter.of_list l) in - let h = H.filter (fun x -> x mod 2 = 0) h in - assert (H.to_iter h |> Iter.for_all (fun x -> x mod 2 = 0)); - let l' = extract_list h in - is_sorted l') + (l |> H.of_list |> H.to_list_sorted) + = (l |> List.sort CCInt.compare)) ;; -q - Q.(list_of_size Gen.(return 1_000) int) +(* The remaining tests assume the correctness of + [of_list], [to_list], [to_list_sorted]. *) + +q ~name:"size" + ~count:30 + Q.(list_of_size Gen.small_nat medium_nat) (fun l -> - (* put elements into a heap *) - let h = H.of_iter (Iter.of_list l) in - let l' = H.to_iter_sorted h |> Iter.to_list in - is_sorted l') + (l |> H.of_list |> H.size) + = (l |> List.length)) ;; -q - Q.(list int) +q ~name:"filter" + Q.(list medium_nat) (fun l -> - extract_list (H.of_list l) = extract_list (H.of_gen (CCList.to_gen l))) + let p = (fun x -> x mod 2 = 0) in + let l' = l |> H.of_list |> H.filter p |> H.to_list in + List.for_all p l' && List.length l' = List.length (List.filter p l)) ;; -q - Q.(list int) +q ~name:"to_iter_sorted" + Q.(list_of_size Gen.small_nat medium_nat) (fun l -> - let h = H.of_list l in - H.to_gen h |> CCList.of_gen |> List.sort Stdlib.compare - = (H.to_list h |> List.sort Stdlib.compare)) + (l |> H.of_list |> H.to_iter_sorted |> Iter.to_list) + = (l |> List.sort CCInt.compare)) ;; -q - Q.(list int) +q ~name:"of_gen" + Q.(list_of_size Gen.small_nat medium_nat) (fun l -> - let h = H.of_list l in - H.to_string string_of_int h - = (List.sort Stdlib.compare l |> List.map string_of_int |> String.concat ",")) + (l |> CCList.to_gen |> H.of_gen |> H.to_list_sorted) + = (l |> List.sort CCInt.compare)) ;; -q - Q.(list int) +q ~name:"to_gen" + Q.(list_of_size Gen.small_nat medium_nat) (fun l -> - let h = H.of_list l in - H.to_string ~sep:" " string_of_int h - = (List.sort Stdlib.compare l |> List.map string_of_int |> String.concat " ")) + (l |> H.of_list |> H.to_gen |> CCList.of_gen |> List.sort CCInt.compare) + = (l |> List.sort CCInt.compare)) ;; -q - Q.(list_of_size Gen.(return 1_000) int) +q ~name:"to_string with default sep" + Q.(list_of_size Gen.small_nat medium_nat) + (fun l -> + (l |> H.of_list |> H.to_string string_of_int) + = (l |> List.sort CCInt.compare |> List.map string_of_int |> String.concat ",")) +;; + +q ~name:"to_string with space as sep" + Q.(list_of_size Gen.small_nat medium_nat) + (fun l -> + (l |> H.of_list |> H.to_string ~sep:" " string_of_int) + = (l |> List.sort CCInt.compare |> List.map string_of_int |> String.concat " ")) +;; + +q ~name:"Make_from_compare" + Q.(list_of_size Gen.small_nat medium_nat) (fun l -> let module H' = Make_from_compare (CCInt) in - let h = H'.of_list l in - let l' = H'.to_list_sorted h in - is_sorted l') + (l |> H'.of_list |> H'.to_list_sorted) + = (l |> List.sort CCInt.compare))