Module QCheck
Quickcheck inspired property-based testing
val (==>) : bool -> bool -> boolb1 ==> b2is the logical implicationb1 => b2ienot b1 || b2(except that it is strict and will interact better withTest.check_exnand 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, bothb1andb2are always evaluated; ifb2should only be evaluated whenb1holds, seeassume.
val assume : bool -> unitassume condchecks 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 -> 'aassume_fail ()is likeassume false, but can take any type since we know it always fails (likeassert false). This is useful to ignore some branches iniformatch.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 ... endArbitrary
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 arbitraryis 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 arbitraryBuilder 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 arbitraryval set_small : ('a -> int) -> 'a arbitrary -> 'a arbitraryval set_shrink : 'a Shrink.t -> 'a arbitrary -> 'a arbitraryval set_collect : ('a -> string) -> 'a arbitrary -> 'a arbitraryval set_stats : 'a stat list -> 'a arbitrary -> 'a arbitrary- since
- 0.6
val add_shrink_invariant : ('a -> bool) -> 'a arbitrary -> 'a arbitraryUpdate 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 ... endResult of running a test
module Test : sig ... endSub-tests
val find_example : ?name:string -> ?count:int -> f:('a -> bool) -> 'a Gen.t -> 'a Gen.tfind_example ~f genusesgento 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
counttries.
- since
- 0.6
val find_example_gen : ?rand:Stdlib.Random.State.t -> ?name:string -> ?count:int -> f:('a -> bool) -> 'a Gen.t -> 'aToplevel version of
find_example.find_example_gen ~f arb ~nis 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
counttries.
- since
- 0.6
Combinators for arbitrary
val choose : 'a arbitrary list -> 'a arbitraryChoose among the given list of generators. The list must not be empty; if it is Invalid_argument is raised.
val unit : unit arbitraryAlways generates
(), obviously.
val bool : bool arbitraryUniform boolean generator.
val float : float arbitraryGenerates regular floats (no nan and no infinities).
val pos_float : float arbitraryPositive float generator (no nan and no infinities).
val neg_float : float arbitraryNegative float generator (no nan and no infinities).
val float_bound_inclusive : float -> float arbitraryfloat_bound_inclusive nis uniform between0andnincluded. Ifboundis negative, the result is negative or zero. Ifboundis 0, the result is 0.- since
- 0.11
val float_bound_exclusive : float -> float arbitraryfloat_bound_exclusive nis uniform between0included andnexcluded. Ifboundis negative, the result is negative or zero.- raises Invalid_argument
if
boundis zero.
- since
- 0.11
val float_range : float -> float -> float arbitraryfloat_range low highis uniform betweenlowincluded andhighincluded.- raises Invalid_argument
if
low > highor if the range is larger thanmax_float.
- since
- 0.11
val int : int arbitraryInt generator. Uniformly distributed.
val int_bound : int -> int arbitraryint_bound nis uniform between0andnincluded.
val int_range : int -> int -> int arbitraryint_range a bis uniform betweenaandbincluded.bmust be larger thana.
val small_nat : int arbitrarySmall unsigned integers.
- since
- 0.5.1
val small_int : int arbitrarySmall unsigned integers. See
Gen.small_int.- deprecated
use
small_signed_int.
val small_signed_int : int arbitrarySmall signed integers.
- since
- 0.5.2
val int32 : int32 arbitraryInt32 generator. Uniformly distributed.
val int64 : int64 arbitraryInt64 generator. Uniformly distributed.
val small_int_corners : unit -> int arbitraryAs
small_int, but each newly created generator starts with a list of corner cases before falling back on random generation.
val neg_int : int arbitraryNegative int generator (0 included, see
Gen.neg_int). The distribution is similar to that ofsmall_int, not ofpos_int.
val char : char arbitraryUniformly distributed on all the chars (not just ascii or valid latin-1).
val printable_char : char arbitraryUniformly distributed over a subset of chars.
val numeral_char : char arbitraryUniformly distributed over
'0'..'9'.
val string_gen_of_size : int Gen.t -> char Gen.t -> string arbitraryval string_gen : char Gen.t -> string arbitraryGenerates strings with a distribution of length of
small_nat.
val string : string arbitraryGenerates strings with a distribution of length of
small_natand distribution of characters ofchar.
val small_string : string arbitrarySame as
stringbut with a small length (ieGen.small_nat).
val small_list : 'a arbitrary -> 'a list arbitraryGenerates lists of small size (see
Gen.small_nat).- since
- 0.5.3
val string_of_size : int Gen.t -> string arbitraryGenerates strings with distribution of characters if
char.
val printable_string : string arbitraryGenerates strings with a distribution of length of
small_natand distribution of characters ofprintable_char.
val printable_string_of_size : int Gen.t -> string arbitraryGenerates strings with distribution of characters of
printable_char.
val small_printable_string : string arbitraryval numeral_string : string arbitraryGenerates strings with a distribution of length of
small_natand distribution of characters ofnumeral_char.
val numeral_string_of_size : int Gen.t -> string arbitraryGenerates strings with a distribution of characters of
numeral_char.
val list_of_size : int Gen.t -> 'a arbitrary -> 'a list arbitraryGenerates lists with length from the given distribution.
val array_of_size : int Gen.t -> 'a arbitrary -> 'a array arbitraryGenerates arrays with length from the given distribution.
val pair : 'a arbitrary -> 'b arbitrary -> ('a * 'b) arbitraryCombines 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) arbitraryCombines three generators into a generator of 3-tuples. Order matters for shrinking, see
Shrink.pairand the likes
val quad : 'a arbitrary -> 'b arbitrary -> 'c arbitrary -> 'd arbitrary -> ('a * 'b * 'c * 'd) arbitraryCombines four generators into a generator of 4-tuples. Order matters for shrinking, see
Shrink.pairand the likes
val option : 'a arbitrary -> 'a option arbitraryChoose between returning Some random value, or None.
val fun1_unsafe : 'a arbitrary -> 'b arbitrary -> ('a -> 'b) arbitraryGenerator 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
fun1since 0.6- deprecated
use
fun_instead.
- since
- 0.6
val fun2_unsafe : 'a arbitrary -> 'b arbitrary -> 'c arbitrary -> ('a -> 'b -> 'c) arbitraryGenerator of functions of arity 2. The remark about
fun1also apply here. renamed fromfun2since 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
Fnto 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 ... endUtils on functions
val fun1 : 'a Observable.t -> 'b arbitrary -> ('a -> 'b) fun_ arbitraryfun1 o retmakes random functions that take an argument observable viaoand map to random values generated fromret. To write functions with multiple arguments, it's better to useTupleorObservable.pairrather than applyingfun_several times (shrinking will be faster).- since
- 0.6
module Tuple : sig ... endval fun_nary : 'a Tuple.obs -> 'b arbitrary -> ('a Tuple.t -> 'b) fun_ arbitraryfun_narymakes 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 arbitraryPick an element randomly in the list.
val oneofa : ?print:'a Print.t -> ?collect:('a -> string) -> 'a array -> 'a arbitraryPick 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 arbitrarySimilar to
oneofbut with frequencies.
val frequencyl : ?print:'a Print.t -> ?small:('a -> int) -> (int * 'a) list -> 'a arbitrarySame 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 arbitrarySame as
frequencyl, but with an array.
val map : ?rev:('b -> 'a) -> ('a -> 'b) -> 'a arbitrary -> 'b arbitrarymap f areturns a new arbitrary instance that generates values usinga#genand then transforms them throughf.- parameter rev
if provided, maps values back to type
'aso that the printer, shrinker, etc. ofacan be used. We assumefis monotonic in this case (that is, smaller inputs are transformed into smaller outputs).
val map_same_type : ('a -> 'a) -> 'a arbitrary -> 'a arbitrarySpecialization of
mapwhen 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 agenerates random values froma, and maps them into values of type'busing the functionf, but it also keeps the original value. For shrinking, it is assumed thatfis monotonic and that smaller input values will map into smaller values.- parameter print
optional printer for the
f's output.