Module QCheck
Quickcheck inspired property-based testing
val (==>) : bool -> bool -> bool
b1 ==> b2
is the logical implicationb1 => b2
ienot b1 || b2
(except that it is strict and will interact better withTest.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
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, bothb1
andb2
are always evaluated; ifb2
should only be evaluated whenb1
holds, seeassume
.
val assume : bool -> unit
assume cond
checks the preconditioncond
, and does nothing ifcond=true
. Ifcond=false
, it interrupts the current test.WARNING This function, like
(==>)
, 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)
- since
- 0.5.1
val assume_fail : unit -> 'a
assume_fail ()
is likeassume false
, but can take any type since we know it always fails (likeassert false
). This is useful to ignore some branches inif
ormatch
.Example:
Test.make (list int) (function | [] -> assume_fail () | _::_ as l -> List.hd l :: List.tl l = l)
- since
- 0.5.1
module Gen : sig ... end
Pretty printing
module Print : sig ... end
module Iter : sig ... end
module Shrink : sig ... end
Observe Values
module Observable : sig ... end
Arbitrary
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 Test
).
type 'a stat
= string * ('a -> int)
A statistic on a distribution of values of type
'a
. The function MUST return a positive integer.
type 'a arbitrary
= private
{
gen : 'a Gen.t;
print : ('a -> string) option;
print values
small : ('a -> int) option;
size of example
shrink : 'a Shrink.t option;
shrink to smaller examples
collect : ('a -> string) option;
map value to tag, and group by tag
stats : 'a stat list;
statistics to collect and print
}
A value of type
'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
Test
.Made private since 0.8
val make : ?print:'a Print.t -> ?small:('a -> int) -> ?shrink:'a Shrink.t -> ?collect:('a -> string) -> ?stats:'a stat list -> 'a Gen.t -> 'a arbitrary
Builder for arbitrary. Default is to only have a generator, but other arguments can be added.
- parameter print
printer for values (counter-examples)
- parameter collect
for statistics
- parameter shrink
to shrink counter-examples
val 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 arbitrary
- since
- 0.6
val add_shrink_invariant : ('a -> bool) -> 'a arbitrary -> 'a arbitrary
Update shrinker by only keeping smaller values satisfying the given invariant.
- since
- 0.8
Tests
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 Test.make
to build a test, and 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
Result of running a test
module Test : sig ... end
Sub-tests
val find_example : ?name:string -> ?count:int -> f:('a -> bool) -> 'a Gen.t -> 'a Gen.t
find_example ~f gen
usesgen
to generate some values of type'a
, and checks them againstf
. If such a value is found, it is returned. Otherwise an exception is raised. NOTE this should only be used from within a property inTest.make
.- parameter count
number of attempts.
- parameter name
description of the example to find (used in the exception).
- parameter f
the property that the example must satisfy.
- raises No_example_found
if no example is found within
count
tries.
- since
- 0.6
val find_example_gen : ?rand:Stdlib.Random.State.t -> ?name:string -> ?count:int -> f:('a -> bool) -> 'a Gen.t -> 'a
Toplevel version of
find_example
.find_example_gen ~f arb ~n
is roughly the same asGen.generate1 (find_example ~f arb |> gen)
.- parameter rand
the random state to use to generate inputs.
- raises No_example_found
if no example was found within
count
tries.
- since
- 0.6
Combinators for arbitrary
val choose : 'a arbitrary list -> 'a arbitrary
Choose among the given list of generators. The list must not be empty; if it is Invalid_argument is raised.
val unit : unit arbitrary
Always generates
()
, obviously.
val bool : bool arbitrary
Uniform boolean generator.
val float : float arbitrary
Generates regular floats (no nan and no infinities).
val pos_float : float arbitrary
Positive float generator (no nan and no infinities).
val neg_float : float arbitrary
Negative float generator (no nan and no infinities).
val float_bound_inclusive : float -> float arbitrary
float_bound_inclusive n
is uniform between0
andn
included. Ifbound
is negative, the result is negative or zero. Ifbound
is 0, the result is 0.- since
- 0.11
val float_bound_exclusive : float -> float arbitrary
float_bound_exclusive n
is uniform between0
included andn
excluded. Ifbound
is negative, the result is negative or zero.- raises Invalid_argument
if
bound
is zero.
- since
- 0.11
val float_range : float -> float -> float arbitrary
float_range low high
is uniform betweenlow
included andhigh
included.- raises Invalid_argument
if
low > high
or if the range is larger thanmax_float
.
- since
- 0.11
val int : int arbitrary
Int generator. Uniformly distributed.
val int_bound : int -> int arbitrary
int_bound n
is uniform between0
andn
included.
val int_range : int -> int -> int arbitrary
int_range a b
is uniform betweena
andb
included.b
must be larger thana
.
val small_nat : int arbitrary
Small unsigned integers.
- since
- 0.5.1
val small_int : int arbitrary
Small unsigned integers. See
Gen.small_int
.- deprecated
use
small_signed_int
.
val small_signed_int : int arbitrary
Small signed integers.
- since
- 0.5.2
val int32 : int32 arbitrary
Int32 generator. Uniformly distributed.
val int64 : int64 arbitrary
Int64 generator. Uniformly distributed.
val small_int_corners : unit -> int arbitrary
As
small_int
, but each newly created generator starts with a list of corner cases before falling back on random generation.
val neg_int : int arbitrary
Negative int generator (0 included, see
Gen.neg_int
). The distribution is similar to that ofsmall_int
, not ofpos_int
.
val char : char arbitrary
Uniformly distributed on all the chars (not just ascii or valid latin-1).
val printable_char : char arbitrary
Uniformly distributed over a subset of chars.
val numeral_char : char arbitrary
Uniformly distributed over
'0'..'9'
.
val string_gen_of_size : int Gen.t -> char Gen.t -> string arbitrary
val string_gen : char Gen.t -> string arbitrary
Generates strings with a distribution of length of
small_nat
.
val string : string arbitrary
Generates strings with a distribution of length of
small_nat
and distribution of characters ofchar
.
val small_string : string arbitrary
Same as
string
but with a small length (ieGen.small_nat
).
val small_list : 'a arbitrary -> 'a list arbitrary
Generates lists of small size (see
Gen.small_nat
).- since
- 0.5.3
val string_of_size : int Gen.t -> string arbitrary
Generates strings with distribution of characters if
char
.
val printable_string : string arbitrary
Generates strings with a distribution of length of
small_nat
and distribution of characters ofprintable_char
.
val printable_string_of_size : int Gen.t -> string arbitrary
Generates strings with distribution of characters of
printable_char
.
val small_printable_string : string arbitrary
val numeral_string : string arbitrary
Generates strings with a distribution of length of
small_nat
and distribution of characters ofnumeral_char
.
val numeral_string_of_size : int Gen.t -> string arbitrary
Generates strings with a distribution of characters of
numeral_char
.
val list_of_size : int Gen.t -> 'a arbitrary -> 'a list arbitrary
Generates lists with length from the given distribution.
val array_of_size : int Gen.t -> 'a arbitrary -> 'a array arbitrary
Generates arrays with length from the given distribution.
val pair : 'a arbitrary -> 'b arbitrary -> ('a * 'b) arbitrary
Combines two generators into a generator of pairs. Order of elements can matter (w.r.t shrinking, see
Shrink.pair
)
val triple : 'a arbitrary -> 'b arbitrary -> 'c arbitrary -> ('a * 'b * 'c) arbitrary
Combines three generators into a generator of 3-tuples. Order matters for shrinking, see
Shrink.pair
and the likes
val quad : 'a arbitrary -> 'b arbitrary -> 'c arbitrary -> 'd arbitrary -> ('a * 'b * 'c * 'd) arbitrary
Combines four generators into a generator of 4-tuples. Order matters for shrinking, see
Shrink.pair
and the likes
val option : 'a arbitrary -> 'a option arbitrary
Choose between returning Some random value, or None.
val fun1_unsafe : 'a arbitrary -> 'b arbitrary -> ('a -> 'b) arbitrary
Generator of functions of arity 1. The functions are always pure and total functions:
- when given the same argument (as decided by Pervasives.(=)), it returns the same value
- it never does side effects, like printing or never raise exceptions etc. The functions generated are really printable.
renamed from
fun1
since 0.6- deprecated
use
fun_
instead.
- since
- 0.6
val fun2_unsafe : 'a arbitrary -> 'b arbitrary -> 'c arbitrary -> ('a -> 'b -> 'c) arbitrary
Generator of functions of arity 2. The remark about
fun1
also apply here. renamed fromfun2
since 0.6- deprecated
use
fun_
instead since 0.6
type _ fun_
=
|
Fun : 'f fun_repr * 'f -> 'f fun_
A function packed with the data required to print/shrink it. See
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
Utils on functions
val fun1 : 'a Observable.t -> 'b arbitrary -> ('a -> 'b) fun_ arbitrary
fun1 o ret
makes random functions that take an argument observable viao
and map to random values generated fromret
. To write functions with multiple arguments, it's better to useTuple
orObservable.pair
rather than applyingfun_
several times (shrinking will be faster).- since
- 0.6
module Tuple : sig ... end
val fun_nary : 'a Tuple.obs -> 'b arbitrary -> ('a Tuple.t -> 'b) fun_ arbitrary
fun_nary
makes random n-ary functions. Example:let module O = Observable in fun_nary Tuple.(O.int @-> O.float @-> O.string @-> o_nil) bool)
- since
- 0.6
val fun2 : 'a Observable.t -> 'b Observable.t -> 'c arbitrary -> ('a -> 'b -> 'c) fun_ arbitrary
- since
- 0.6
val fun3 : 'a Observable.t -> 'b Observable.t -> 'c Observable.t -> 'd arbitrary -> ('a -> 'b -> 'c -> 'd) fun_ arbitrary
- since
- 0.6
val fun4 : 'a Observable.t -> 'b Observable.t -> 'c Observable.t -> 'd Observable.t -> 'e arbitrary -> ('a -> 'b -> 'c -> 'd -> 'e) fun_ arbitrary
- since
- 0.6
val oneofl : ?print:'a Print.t -> ?collect:('a -> string) -> 'a list -> 'a arbitrary
Pick an element randomly in the list.
val oneofa : ?print:'a Print.t -> ?collect:('a -> string) -> 'a array -> 'a arbitrary
Pick an element randomly in the array.
val frequency : ?print:'a Print.t -> ?small:('a -> int) -> ?shrink:'a Shrink.t -> ?collect:('a -> string) -> (int * 'a arbitrary) list -> 'a arbitrary
Similar to
oneof
but with frequencies.
val frequencyl : ?print:'a Print.t -> ?small:('a -> int) -> (int * 'a) list -> 'a arbitrary
Same as
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 arbitrary
Same as
frequencyl
, but with an array.
val map : ?rev:('b -> 'a) -> ('a -> 'b) -> 'a arbitrary -> 'b arbitrary
map f a
returns a new arbitrary instance that generates values usinga#gen
and then transforms them throughf
.- parameter rev
if provided, maps values back to type
'a
so that the printer, shrinker, etc. ofa
can be used. We assumef
is monotonic in this case (that is, smaller inputs are transformed into smaller outputs).
val map_same_type : ('a -> 'a) -> 'a arbitrary -> 'a arbitrary
Specialization of
map
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) arbitrary
map_keep_input f a
generates random values froma
, and maps them into values of type'b
using the functionf
, but it also keeps the original value. For shrinking, it is assumed thatf
is monotonic and that smaller input values will map into smaller values.- parameter print
optional printer for the
f
's output.