module QCheck:sig..end
This explains the organization of this module:
'a arbitrary is used to describe how to generate random values,
shrink them (make counter-examples as small as possible), print
them, etc. Auxiliary modules such as QCheck.Gen, QCheck.Print, and QCheck.Shrink
can be used along with QCheck.make to build one's own arbitrary instances.QCheck.Test is used to describe a single test, that is, a property of
type 'a -> bool combined with an 'a arbitrary that is used to generate
the test cases for this property. Optional parameters
allow to specify the random generator state, number of instances to generate
and test, etc.
let test =
QCheck.(Test.make ~count:1000
(list int) (fun l -> List.rev (List.rev l) = l));;
QCheck.Test.check_exn test;;
let test = QCheck.(
Test.make
~count:10_000 ~max_fail:3
(list small_nat)
(fun l -> l = List.sort compare l));;
QCheck.Test.check_exn test;;
QCheck.Gen.fix :type tree = Leaf of int | Node of tree * tree
let leaf x = Leaf x
let node x y = Node (x,y)
let g = QCheck.Gen.(sized @@ fix
(fun self n -> match n with
| 0 -> map leaf nat
| n ->
frequency
[1, map leaf nat;
2, map2 node (self (n/2)) (self (n/2))]
))
Gen.generate ~n:20 g;;
More complex and powerful combinators can be found in Gabriel Scherer's
Generator module. Its documentation can be found
here.
val (==>) : bool -> bool -> boolb1 ==> b2 is the logical implication b1 => b2
ie not b1 || b2 (except that it is strict and will interact
better with QCheck.Test.check_exn and the likes, because they will know
the precondition was not satisfied.).
WARNING: this function should only be used in a property
(see QCheck.Test.make), because it raises a special exception in case of
failure of the first argument, to distinguish between failed test
and failed precondition. Because of OCaml's evaluation order,
both b1 and b2 are always evaluated; if b2 should only be
evaluated when b1 holds, see QCheck.assume.
val assume : bool -> unitassume cond checks the precondition cond, and does nothing
if cond=true. If cond=false, it interrupts the current test.
WARNING This function, like QCheck.(==>), should only be used in
a test, not outside.
Example:
Test.make (list int) (fun l ->
assume (l <> []);
List.hd l :: List.tl l = l)
val assume_fail : unit -> 'aassume_fail () is like assume false, but can take any type
since we know it always fails (like assert false).
This is useful to ignore some branches in if or match.
Example:
Test.make (list int) (function
| [] -> assume_fail ()
| _::_ as l -> List.hd l :: List.tl l = l)
module Gen:sig..end
module Print:sig..end
module Iter:sig..end
module Shrink:sig..end
Inspired from https://blogs.janestreet.com/quickcheck-for-core/
and Koen Claessen's "Shrinking and Showing functions".
module Observable:sig..end
A value of type 'a arbitrary glues together a random generator,
and optional functions for shrinking, printing, computing the size,
etc. It is the "normal" way of describing how to generate
values of a given type, to be then used in tests (see QCheck.Test).
type'astat =string * ('a -> int)
'a.
The function MUST return a positive integer.type 'a arbitrary = {
|
gen : |
|||
|
print : |
(* |
print values
| *) |
|
small : |
(* |
size of example
| *) |
|
shrink : |
(* |
shrink to smaller examples
| *) |
|
collect : |
(* |
map value to tag, and group by tag
| *) |
|
stats : |
(* |
statistics to collect and print
| *) |
'a arbitrary is an object with a method for generating random
values of type 'a, and additional methods to compute the size of values,
print them, and possibly shrink them into smaller counter-examples.
NOTE the collect field is unstable and might be removed, or
moved into QCheck.Test.
val make : ?print:'a Print.t ->
?small:('a -> int) ->
?shrink:'a Shrink.t ->
?collect:('a -> string) ->
?stats:'a stat list -> 'a Gen.t -> 'a arbitraryval set_print : 'a Print.t -> 'a arbitrary -> 'a arbitrary
val set_small : ('a -> int) -> 'a arbitrary -> 'a arbitrary
val set_shrink : 'a Shrink.t -> 'a arbitrary -> 'a arbitrary
val set_collect : ('a -> string) -> 'a arbitrary -> 'a arbitrary
val set_stats : 'a stat list -> 'a arbitrary -> 'a arbitraryval set_gen : 'a Gen.t -> 'a arbitrary -> 'a arbitraryval add_stat : 'a stat -> 'a arbitrary -> 'a arbitraryval gen : 'a arbitrary -> 'a Gen.t
A test is a universal property of type foo -> bool for some type foo,
with an object of type foo arbitrary used to generate, print, etc. values
of type foo.
See QCheck.Test.make to build a test, and QCheck.Test.check_exn to
run one test simply.
For more serious testing, it is better to create a testsuite
and use QCheck_runner.
module TestResult:sig..end
module Test:sig..end
See https://github.com/c-cube/qcheck/issues/31
exception No_example_found of string
val find_example : ?name:string ->
?count:int -> f:('a -> bool) -> 'a Gen.t -> 'a Gen.tfind_example ~f gen uses gen to generate some values of type 'a,
and checks them against f. If such a value is found, it is returned.
Otherwise an exception is raised.
NOTE this should only be used from within a property in QCheck.Test.make.No_example_found if no example is found within count tries.name : description of the example to find (used in the exception).count : number of attempts.f : the property that the example must satisfy.val find_example_gen : ?rand:Random.State.t ->
?name:string -> ?count:int -> f:('a -> bool) -> 'a Gen.t -> 'aQCheck.find_example.
find_example_gen ~f arb ~n is roughly the same as
Gen.generate1 (find_example ~f arb |> gen).No_example_found if no example was found within count tries.rand : the random state to use to generate inputs.QCheck.arbitraryval choose : 'a arbitrary list -> 'a arbitraryval unit : unit arbitrary(), obviously.val bool : bool arbitraryval float : float arbitraryval pos_float : float arbitraryval neg_float : float arbitraryval int : int arbitraryval int_bound : int -> int arbitraryint_bound n is uniform between 0 and n included.val int_range : int -> int -> int arbitraryint_range a b is uniform between a and b included. b must be
larger than a.val small_nat : int arbitraryval small_int : int arbitrary
val small_signed_int : int arbitraryval (--) : int -> int -> int arbitraryQCheck.int_range.val int32 : int32 arbitraryval int64 : int64 arbitraryval pos_int : int arbitraryval small_int_corners : unit -> int arbitrarysmall_int, but each newly created generator starts with
a list of corner cases before falling back on random generation.val neg_int : int arbitrarysmall_int, not of pos_int.val char : char arbitraryval printable_char : char arbitraryval numeral_char : char arbitrary'0'..'9'.val string_gen_of_size : int Gen.t -> char Gen.t -> string arbitrary
val string_gen : char Gen.t -> string arbitrarysmall_nat.val string : string arbitrarysmall_nat
and distribution of characters of char.val small_string : string arbitrary
val small_list : 'a arbitrary -> 'a list arbitrary0 -- 10).val string_of_size : int Gen.t -> string arbitrarychar.val printable_string : string arbitrarysmall_nat
and distribution of characters of printable_char.val printable_string_of_size : int Gen.t -> string arbitraryprintable_char.val small_printable_string : string arbitrary
val numeral_string : string arbitrarysmall_nat
and distribution of characters of numeral_char.val numeral_string_of_size : int Gen.t -> string arbitrarynumeral_char.val list : 'a arbitrary -> 'a list arbitrarysmall_nat.val list_of_size : int Gen.t -> 'a arbitrary -> 'a list arbitraryval array : 'a arbitrary -> 'a array arbitrarysmall_nat.val array_of_size : int Gen.t -> 'a arbitrary -> 'a array arbitraryval pair : 'a arbitrary -> 'b arbitrary -> ('a * 'b) arbitraryQCheck.Shrink.pair)val triple : 'a arbitrary ->
'b arbitrary -> 'c arbitrary -> ('a * 'b * 'c) arbitraryQCheck.Shrink.pair and the likesval quad : 'a arbitrary ->
'b arbitrary ->
'c arbitrary ->
'd arbitrary -> ('a * 'b * 'c * 'd) arbitraryQCheck.Shrink.pair and the likesval option : 'a arbitrary -> 'a option arbitraryval fun1_unsafe : 'a arbitrary -> 'b arbitrary -> ('a -> 'b) arbitraryQCheck.fun_ instead.QCheck.fun1.val fun2_unsafe : 'a arbitrary ->
'b arbitrary ->
'c arbitrary -> ('a -> 'b -> 'c) arbitraryQCheck.fun_ instead.fun1 also apply
here.
renamed from QCheck.fun2.type '_ fun_repr
'f fun_ is a function
of type 'f, fundamentally.type '_ fun_ =
| |
Fun : |
QCheck.Fn
to see how to apply, print, etc. such a function.
One can also directly pattern match on it to obtain the executable function.
For example:
QCheck.Test.make
QCheck.(pair (fun1 Observable.int bool) (small_list int))
(fun (Fun (_,f), l) -> l=(List.rev_map f l |> List.rev l))
module Fn:sig..end
val fun1 : 'a Observable.t ->
'b arbitrary -> ('a -> 'b) fun_ arbitraryfun1 o ret makes random functions that take an argument observable
via o and map to random values generated from ret.
To write functions with multiple arguments, it's better to use QCheck.Tuple
or QCheck.Observable.pair rather than applying QCheck.fun_ several times
(shrinking will be faster).module Tuple:sig..end
val fun_nary : 'a Tuple.obs ->
'b arbitrary -> ('a Tuple.t -> 'b) fun_ arbitraryfun_nary makes random n-ary functions.
Example:
let module O = Observable in
fun_nary Tuple.(O.int @-> O.float @-> O.string @-> o_nil) bool)
val fun2 : 'a Observable.t ->
'b Observable.t ->
'c arbitrary -> ('a -> 'b -> 'c) fun_ arbitraryval fun3 : 'a Observable.t ->
'b Observable.t ->
'c Observable.t ->
'd arbitrary -> ('a -> 'b -> 'c -> 'd) fun_ arbitraryval fun4 : 'a Observable.t ->
'b Observable.t ->
'c Observable.t ->
'd Observable.t ->
'e arbitrary ->
('a -> 'b -> 'c -> 'd -> 'e) fun_ arbitraryval oneofl : ?print:'a Print.t ->
?collect:('a -> string) -> 'a list -> 'a arbitraryval oneofa : ?print:'a Print.t ->
?collect:('a -> string) -> 'a array -> 'a arbitraryval oneof : 'a arbitrary list -> 'a arbitraryval always : ?print:'a Print.t -> 'a -> 'a arbitraryval frequency : ?print:'a Print.t ->
?small:('a -> int) ->
?shrink:'a Shrink.t ->
?collect:('a -> string) ->
(int * 'a arbitrary) list -> 'a arbitraryQCheck.oneof but with frequencies.val frequencyl : ?print:'a Print.t ->
?small:('a -> int) -> (int * 'a) list -> 'a arbitraryQCheck.oneofl, but each element is paired with its frequency in
the probability distribution (the higher, the more likely).val frequencya : ?print:'a Print.t ->
?small:('a -> int) -> (int * 'a) array -> 'a arbitraryQCheck.frequencyl, but with an array.val map : ?rev:('b -> 'a) -> ('a -> 'b) -> 'a arbitrary -> 'b arbitrarymap f a returns a new arbitrary instance that generates values using
a#gen and then transforms them through f.rev : if provided, maps values back to type 'a so that the printer,
shrinker, etc. of a can be used. We assume f is monotonic in
this case (that is, smaller inputs are transformed into smaller outputs).val map_same_type : ('a -> 'a) -> 'a arbitrary -> 'a arbitrarymap when the transformation preserves the type, which
makes shrinker, printer, etc. still relevant.val map_keep_input : ?print:'b Print.t ->
?small:('b -> int) ->
('a -> 'b) -> 'a arbitrary -> ('a * 'b) arbitrarymap_keep_input f a generates random values from a, and maps them into
values of type 'b using the function f, but it also keeps the
original value.
For shrinking, it is assumed that f is monotonic and that smaller input
values will map into smaller values.print : optional printer for the f's output.