mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-06 11:15:31 -05:00
QCheck easier to use, with printing combinators module
and simpler ('a -> bool) properties
This commit is contained in:
parent
ead09ae349
commit
b4f3925a45
2 changed files with 93 additions and 59 deletions
101
qCheck.ml
101
qCheck.ml
|
|
@ -29,14 +29,16 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
module Arbitrary = struct
|
module Arbitrary = struct
|
||||||
type 'a t = Random.State.t -> 'a
|
type 'a t = Random.State.t -> 'a
|
||||||
|
|
||||||
let int st = Random.State.int st max_int
|
let int n st = Random.State.int st n
|
||||||
|
|
||||||
let int_range ?(start=0) ~stop st =
|
let int_range ~start ~stop st =
|
||||||
let n = stop - start in
|
let n = stop - start in
|
||||||
if n <= 0
|
if n <= 0
|
||||||
then 0
|
then 0
|
||||||
else start + Random.State.int st n
|
else start + Random.State.int st n
|
||||||
|
|
||||||
|
let small_int = int 100
|
||||||
|
|
||||||
let bool = Random.State.bool
|
let bool = Random.State.bool
|
||||||
|
|
||||||
let float f st = Random.State.float st f
|
let float f st = Random.State.float st f
|
||||||
|
|
@ -46,7 +48,7 @@ module Arbitrary = struct
|
||||||
let alpha st =
|
let alpha st =
|
||||||
Char.chr (Char.code 'a' + Random.State.int st (Char.code 'z' - Char.code 'a'))
|
Char.chr (Char.code 'a' + Random.State.int st (Char.code 'z' - Char.code 'a'))
|
||||||
|
|
||||||
let string ~len st =
|
let string_len len st =
|
||||||
let n = len st in
|
let n = len st in
|
||||||
assert (n>=0);
|
assert (n>=0);
|
||||||
let s = String.create n in
|
let s = String.create n in
|
||||||
|
|
@ -55,6 +57,8 @@ module Arbitrary = struct
|
||||||
done;
|
done;
|
||||||
s
|
s
|
||||||
|
|
||||||
|
let string st = string_len (int 10) st
|
||||||
|
|
||||||
let map ar f st = f (ar st)
|
let map ar f st = f (ar st)
|
||||||
|
|
||||||
let rec _make_list ar st acc n =
|
let rec _make_list ar st acc n =
|
||||||
|
|
@ -62,7 +66,7 @@ module Arbitrary = struct
|
||||||
let x = ar st in
|
let x = ar st in
|
||||||
_make_list ar st (x::acc) (n-1)
|
_make_list ar st (x::acc) (n-1)
|
||||||
|
|
||||||
let list ~len ar st =
|
let list ?(len=int 10) ar st =
|
||||||
let n = len st in
|
let n = len st in
|
||||||
_make_list ar st [] n
|
_make_list ar st [] n
|
||||||
|
|
||||||
|
|
@ -74,7 +78,7 @@ module Arbitrary = struct
|
||||||
let list_repeat len ar st =
|
let list_repeat len ar st =
|
||||||
_make_list ar st [] len
|
_make_list ar st [] len
|
||||||
|
|
||||||
let array ~len ar st =
|
let array ?(len=int 10) ar st =
|
||||||
let n = len st in
|
let n = len st in
|
||||||
Array.init n (fun _ -> ar st)
|
Array.init n (fun _ -> ar st)
|
||||||
|
|
||||||
|
|
@ -118,41 +122,57 @@ module Arbitrary = struct
|
||||||
fix ~max ~base f st
|
fix ~max ~base f st
|
||||||
end
|
end
|
||||||
|
|
||||||
|
(** {2 Pretty printing} *)
|
||||||
|
|
||||||
|
module PP = struct
|
||||||
|
type 'a t = 'a -> string
|
||||||
|
|
||||||
|
let int = string_of_int
|
||||||
|
let bool = string_of_bool
|
||||||
|
let float = string_of_float
|
||||||
|
let string s = s
|
||||||
|
let char c =
|
||||||
|
let s = "_" in
|
||||||
|
s.[0] <- c;
|
||||||
|
s
|
||||||
|
|
||||||
|
let list pp l =
|
||||||
|
let b = Buffer.create 25 in
|
||||||
|
Buffer.add_char b '(';
|
||||||
|
List.iteri (fun i x ->
|
||||||
|
if i > 0 then Buffer.add_string b ", ";
|
||||||
|
Buffer.add_string b (pp x))
|
||||||
|
l;
|
||||||
|
Buffer.add_char b ')';
|
||||||
|
Buffer.contents b
|
||||||
|
|
||||||
|
let array pp a =
|
||||||
|
let b = Buffer.create 25 in
|
||||||
|
Buffer.add_char b '[';
|
||||||
|
Array.iteri (fun i x ->
|
||||||
|
if i > 0 then Buffer.add_string b ", ";
|
||||||
|
Buffer.add_string b (pp x))
|
||||||
|
a;
|
||||||
|
Buffer.add_char b ']';
|
||||||
|
Buffer.contents b
|
||||||
|
end
|
||||||
|
|
||||||
(** {2 Testing} *)
|
(** {2 Testing} *)
|
||||||
|
|
||||||
module Prop = struct
|
module Prop = struct
|
||||||
type 'a t = {
|
type 'a t = 'a -> bool
|
||||||
name : string;
|
|
||||||
precond : 'a -> bool;
|
exception PrecondFail
|
||||||
test: 'a -> bool;
|
|
||||||
} (** A simple property on elements of type 'a *)
|
|
||||||
|
|
||||||
let __true _ = true
|
|
||||||
|
|
||||||
let make_prop ?(precond=__true) name test = {
|
|
||||||
precond;
|
|
||||||
name;
|
|
||||||
test;
|
|
||||||
}
|
|
||||||
|
|
||||||
let (>::) name test = make_prop name test
|
|
||||||
|
|
||||||
let (==>) a b =
|
let (==>) a b =
|
||||||
{ b with precond = (fun x -> a x && b.precond x); }
|
fun x ->
|
||||||
|
if not (a x) then raise PrecondFail else b x
|
||||||
|
|
||||||
let (&&&) a b =
|
let (&&&) a b x = a x && b x
|
||||||
{ precond = (fun x -> a.precond x && b.precond x);
|
|
||||||
name = Printf.sprintf "%s and %s" a.name b.name;
|
|
||||||
test = (fun x -> a.test x && b.test x);
|
|
||||||
}
|
|
||||||
|
|
||||||
let (|||) a b =
|
let (|||) a b x = a x || b x
|
||||||
{ precond = (fun x -> a.precond x && b.precond x);
|
|
||||||
name = Printf.sprintf "%s or %s" a.name b.name;
|
|
||||||
test = (fun x -> a.test x || b.test x);
|
|
||||||
}
|
|
||||||
|
|
||||||
let (!!!) a = { a with name = "not " ^ a.name; test = (fun x -> not (a.test x)); }
|
let (!!!) a x = not (a x)
|
||||||
end
|
end
|
||||||
|
|
||||||
type 'a result =
|
type 'a result =
|
||||||
|
|
@ -160,16 +180,17 @@ type 'a result =
|
||||||
| Failed of 'a list
|
| Failed of 'a list
|
||||||
| Error of exn
|
| Error of exn
|
||||||
|
|
||||||
let check ?(rand=Random.State.make_self_init ()) ?(n=100) ~gen ~prop =
|
let check ?(rand=Random.State.make_self_init ()) ?(n=100) gen prop =
|
||||||
let precond_failed = ref 0 in
|
let precond_failed = ref 0 in
|
||||||
let failures = ref [] in
|
let failures = ref [] in
|
||||||
try
|
try
|
||||||
for i = 0 to n - 1 do
|
for i = 0 to n - 1 do
|
||||||
let x = gen rand in
|
let x = gen rand in
|
||||||
if not (prop.Prop.precond x)
|
try
|
||||||
then incr precond_failed
|
if not (prop x)
|
||||||
else if not (prop.Prop.test x)
|
then failures := x :: !failures
|
||||||
then failures := x :: !failures
|
with Prop.PrecondFail ->
|
||||||
|
incr precond_failed
|
||||||
done;
|
done;
|
||||||
match !failures with
|
match !failures with
|
||||||
| [] -> Ok (n, !precond_failed)
|
| [] -> Ok (n, !precond_failed)
|
||||||
|
|
@ -179,9 +200,9 @@ let check ?(rand=Random.State.make_self_init ()) ?(n=100) ~gen ~prop =
|
||||||
|
|
||||||
(** {2 Main} *)
|
(** {2 Main} *)
|
||||||
|
|
||||||
let run ?pp ?n ~rand ~gen ~prop =
|
let run ?pp ?n ?(rand=Random.State.make_self_init()) ?(name="<no name>") gen prop =
|
||||||
Printf.printf "testing property %s...\n" prop.Prop.name;
|
Printf.printf "testing property %s...\n" name;
|
||||||
match check ~rand ?n ~gen ~prop with
|
match check ~rand ?n gen prop with
|
||||||
| Ok (n, prefail) ->
|
| Ok (n, prefail) ->
|
||||||
Printf.printf "passed %d tests (%d preconditions failed)\n" n prefail;
|
Printf.printf "passed %d tests (%d preconditions failed)\n" n prefail;
|
||||||
true
|
true
|
||||||
|
|
|
||||||
51
qCheck.mli
51
qCheck.mli
|
|
@ -32,12 +32,15 @@ module Arbitrary : sig
|
||||||
type 'a t = Random.State.t -> 'a
|
type 'a t = Random.State.t -> 'a
|
||||||
(** A generator of arbitrary values of type 'a *)
|
(** A generator of arbitrary values of type 'a *)
|
||||||
|
|
||||||
val int : int t
|
val int : int -> int t
|
||||||
(** Any integer *)
|
(** Any integer *)
|
||||||
|
|
||||||
val int_range : ?start:int -> stop:int -> int t
|
val int_range : start:int -> stop:int -> int t
|
||||||
(* Integer range *)
|
(* Integer range *)
|
||||||
|
|
||||||
|
val small_int : int t
|
||||||
|
(** Ints lower than 100 *)
|
||||||
|
|
||||||
val bool : bool t
|
val bool : bool t
|
||||||
(** Arbitrary boolean *)
|
(** Arbitrary boolean *)
|
||||||
|
|
||||||
|
|
@ -50,13 +53,16 @@ module Arbitrary : sig
|
||||||
val float : float -> float t
|
val float : float -> float t
|
||||||
(** Random float *)
|
(** Random float *)
|
||||||
|
|
||||||
val string : len:int t -> string t
|
val string : string t
|
||||||
|
(** Random strings of small length *)
|
||||||
|
|
||||||
|
val string_len : int t -> string t
|
||||||
(** String of random length *)
|
(** String of random length *)
|
||||||
|
|
||||||
val map : 'a t -> ('a -> 'b) -> 'b t
|
val map : 'a t -> ('a -> 'b) -> 'b t
|
||||||
(** Transform an arbitrary into another *)
|
(** Transform an arbitrary into another *)
|
||||||
|
|
||||||
val list : len:int t -> 'a t -> 'a list t
|
val list : ?len:int t -> 'a t -> 'a list t
|
||||||
(** List of arbitrary length *)
|
(** List of arbitrary length *)
|
||||||
|
|
||||||
val opt : 'a t -> 'a option t
|
val opt : 'a t -> 'a option t
|
||||||
|
|
@ -65,7 +71,7 @@ module Arbitrary : sig
|
||||||
val list_repeat : int -> 'a t -> 'a list t
|
val list_repeat : int -> 'a t -> 'a list t
|
||||||
(** Lists of given length exactly *)
|
(** Lists of given length exactly *)
|
||||||
|
|
||||||
val array : len:int t -> 'a t -> 'a array t
|
val array : ?len:int t -> 'a t -> 'a array t
|
||||||
(** Random array of random length *)
|
(** Random array of random length *)
|
||||||
|
|
||||||
val array_repeat : int -> 'a t -> 'a array t
|
val array_repeat : int -> 'a t -> 'a array t
|
||||||
|
|
@ -91,19 +97,25 @@ module Arbitrary : sig
|
||||||
(** Recursive values of at most given random depth *)
|
(** Recursive values of at most given random depth *)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
(** {2 Pretty printing} *)
|
||||||
|
|
||||||
|
module PP : sig
|
||||||
|
type 'a t = 'a -> string
|
||||||
|
|
||||||
|
val int : int t
|
||||||
|
val bool : bool t
|
||||||
|
val float : float t
|
||||||
|
val char : char t
|
||||||
|
val string : string t
|
||||||
|
|
||||||
|
val list : 'a t -> 'a list t
|
||||||
|
val array : 'a t -> 'a array t
|
||||||
|
end
|
||||||
|
|
||||||
(** {2 Testing} *)
|
(** {2 Testing} *)
|
||||||
|
|
||||||
module Prop : sig
|
module Prop : sig
|
||||||
type 'a t = {
|
type 'a t = 'a -> bool
|
||||||
name : string;
|
|
||||||
precond : 'a -> bool;
|
|
||||||
test: 'a -> bool;
|
|
||||||
} (** A simple property on elements of type 'a *)
|
|
||||||
|
|
||||||
val (>::) : string -> ('a -> bool) -> 'a t
|
|
||||||
(** Build a test with the given name *)
|
|
||||||
|
|
||||||
val make_prop : ?precond:('a -> bool) -> string -> ('a -> bool) -> 'a t
|
|
||||||
|
|
||||||
val (==>) : ('a -> bool) -> 'a t -> 'a t
|
val (==>) : ('a -> bool) -> 'a t -> 'a t
|
||||||
(** Precondition for a test *)
|
(** Precondition for a test *)
|
||||||
|
|
@ -123,15 +135,16 @@ type 'a result =
|
||||||
| Failed of 'a list
|
| Failed of 'a list
|
||||||
| Error of exn
|
| Error of exn
|
||||||
|
|
||||||
val check : ?rand:Random.State.t -> ?n:int ->
|
val check : ?rand:Random.State.t -> ?n:int ->
|
||||||
gen:'a Arbitrary.t -> prop:'a Prop.t -> 'a result
|
'a Arbitrary.t -> 'a Prop.t -> 'a result
|
||||||
(** Check that the property [prop] holds on [n] random instances of the type
|
(** Check that the property [prop] holds on [n] random instances of the type
|
||||||
'a, as generated by the arbitrary instance [gen] *)
|
'a, as generated by the arbitrary instance [gen] *)
|
||||||
|
|
||||||
(** {2 Main} *)
|
(** {2 Main} *)
|
||||||
|
|
||||||
val run : ?pp:('a -> string) -> ?n:int -> rand:Random.State.t ->
|
val run : ?pp:('a -> string) -> ?n:int ->
|
||||||
gen:'a Arbitrary.t -> prop:'a Prop.t -> bool
|
?rand:Random.State.t -> ?name:string ->
|
||||||
|
'a Arbitrary.t -> 'a Prop.t -> bool
|
||||||
(** Run and print result *)
|
(** Run and print result *)
|
||||||
|
|
||||||
val run_tests : (rand:Random.State.t -> bool) list -> bool
|
val run_tests : (rand:Random.State.t -> bool) list -> bool
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue