module Gen:sig..end
A generator is responsible for generating pseudo-random values and provide shrinks (smaller values) when a test fails.
This module provides some of the most important features of QCheck:
type 'a t
A random generator for values of type 'a.
type'asized =int -> 'a t
Random generator with a size bound.
val unit : unit tThe unit generator.
Does not shrink.
val bool : bool tThe boolean generator.
Shrinks towards false.
val int : int tGenerates integers uniformly.
Shrinks towards 0.
val pint : ?origin:int -> int tGenerates non-strictly positive integers uniformly (0 included).
Shrinks towards origin if specified, otherwise towards 0.
val small_nat : int tSmall positive integers (< 100, 0 included).
Non-uniform: smaller numbers are more likely than bigger numbers.
Shrinks towards 0.
val nat : int tGenerates natural numbers (< 10_000).
Non-uniform: smaller numbers are more likely than bigger numbers.
Shrinks towards 0.
val big_nat : int tGenerates natural numbers, possibly large (< 1_000_000).
Non-uniform: smaller numbers are more likely than bigger numbers.
Shrinks towards 0.
val neg_int : int tGenerates non-strictly negative integers (0 included).
Non-uniform: smaller numbers (in absolute value) are more likely than bigger numbers.
Shrinks towards 0.
val small_int : int tQCheck2.Gen.small_nat.Small UNSIGNED integers, for retrocompatibility.
Shrinks towards 0.
val small_signed_int : int tSmall SIGNED integers, based on QCheck2.Gen.small_nat.
Non-uniform: smaller numbers (in absolute value) are more likely than bigger numbers.
Shrinks towards 0.
val small_int_corners : unit -> int tAs QCheck2.Gen.small_int, but each newly created generator starts with
a list of corner cases before falling back on random generation.
val int32 : int32 tGenerates uniform QCheck2.Gen.int32 values.
Shrinks towards 0l.
val ui32 : int32 tQCheck2.Gen.int32 instead, the name is wrong, values are signed.Generates QCheck2.Gen.int32 values.
Shrinks towards 0l.
val int64 : int64 tGenerates uniform QCheck2.Gen.int64 values.
Shrinks towards 0L.
val ui64 : int64 tQCheck2.Gen.int64 instead, the name is wrong, values are signed.Generates QCheck2.Gen.int64 values.
Shrinks towards 0L.
val float : float tGenerates floating point numbers.
Shrinks towards 0..
val pfloat : float tGenerates positive floating point numbers (0. included).
Shrinks towards 0..
val nfloat : float tGenerates negative floating point numbers. (-0. included).
Shrinks towards -0..
val char : char tGenerates characters in the 0..255 range.
Shrinks towards 'a'.
val printable : char tGenerates printable characters.
The exhaustive list of character codes is:
32 to 126, inclusive'\n'Shrinks towards 'a' or lower character codes.
val numeral : char tGenerates numeral characters '0'..'9'.
Shrinks towards '0'.
val bytes_size : ?gen:char t -> int t -> bytes tBuilds a bytes generator from a (non-negative) size generator.
Accepts an optional character generator (the default is QCheck2.Gen.char).
Shrinks on the number of characters first, then on the characters.
val bytes : bytes tBytes generator using the QCheck2.Gen.char character generator. Bytes size is generated by QCheck2.Gen.nat.
See also QCheck2.Gen.bytes_of and QCheck2.Gen.bytes_printable for versions with
custom char generator.
Shrinks on the number of characters first, then on the characters.
val bytes_of : char t -> bytes tBuilds a bytes generator using the given character generator.
Shrinks on the number of characters first, then on the characters.
val bytes_printable : bytes tGenerator using the QCheck2.Gen.printable character generator.
Shrinks on the number of characters first, then on the characters.
val bytes_small : bytes tBuilds a bytes generator using the QCheck2.Gen.char character generator, length is QCheck2.Gen.small_nat.
Shrinks on the number of characters first, then on the characters.
val bytes_small_of : char t -> bytes tBuilds a bytes generator using the given character generator, length is QCheck2.Gen.small_nat.
Shrinks on the number of characters first, then on the characters.
val string_size : ?gen:char t -> int t -> string tBuilds a string generator from a (non-negative) size generator.
Accepts an optional character generator (the default is QCheck2.Gen.char).
Shrinks on the number of characters first, then on the characters.
val string : string tBuilds a string generator. String size is generated by QCheck2.Gen.nat.
The default character generator is QCheck2.Gen.char.
See also QCheck2.Gen.string_of and QCheck2.Gen.string_printable for versions with
custom char generator.
Shrinks on the number of characters first, then on the characters.
val string_of : char t -> string tBuilds a string generator using the given character generator.
Shrinks on the number of characters first, then on the characters.
val string_printable : string tBuilds a string generator using the QCheck2.Gen.printable character generator.
Shrinks on the number of characters first, then on the characters.
val string_small : string tBuilds a string generator using the QCheck2.Gen.char characher generator, length is QCheck2.Gen.small_nat.
Shrinks on the number of characters first, then on the characters.
val string_small_of : char t -> string tBuilds a string generator using the given characher generator, length is QCheck2.Gen.small_nat.
Shrinks on the number of characters first, then on the characters.
val small_string : ?gen:char t -> string tBuilds a string generator, length is QCheck2.Gen.small_nat.
Accepts an optional character generator (the default is QCheck2.Gen.char).
Shrinks on the number of characters first, then on the characters.
This function is kept for backward compatibility:
The optional argument is in fact a mandatory option, see c-cube/qcheck#162.
Use QCheck2.Gen.string_small instead.
val pure : 'a -> 'a tpure a creates a generator that always returns a.
Does not shrink.
val return : 'a -> 'a tSynonym for QCheck2.Gen.pure
val make_primitive : gen:(Stdlib.Random.State.t -> 'a) ->
shrink:('a -> 'a Stdlib.Seq.t) -> 'a tmake_primitive ~gen ~shrink creates a generator from a function gen that creates
a random value (this function must only use the given Random.State.t for randomness)
and a function shrink that, given a value a, returns a lazy list of
"smaller" values (used when a test fails).
This lower-level function is meant to build generators for "primitive" types that can neither be built with other primitive generators nor through composition, or to have more control on the shrinking steps.
shrink must obey the following rules (for your own definition of "small"):
shrink a = Seq.empty when a is the smallest possible valueshrink a must return values strictly smaller than a, ideally from smallest to largest (for
faster shrinking)let rec loop a = match shrink a () with | Nil -> () | Cons (smaller_a, _) -> loop smaller_a
must end for all values a of type 'a (i.e. there must not be an infinite number of shrinking
steps).⚠️ This is an unstable API as it partially exposes the implementation. In particular, the type of
Random.State.t may very well change in a future version, e.g. if QCheck switches to another
randomness library.
val add_shrink_invariant : ('a -> bool) -> 'a t -> 'a tQCheck2.Gen.t being an Alternative (not implemented yet). For now we
keep it and wait for users feedback (hence deprecation to raise attention).add_shrink_invariant f gen returns a generator similar to gen except all shrinks satisfy f.
This way it's easy to preserve invariants that are enforced by
generators, when shrinking values
val set_shrink : ('a -> 'a Stdlib.Seq.t) -> 'a t -> 'a tset_shrink shrink gen sets the shrinker to shrink for gen.
val no_shrink : 'a t -> 'a tno_shrink gen returns a generator using gen but with shrinking
disabled
val int_bound : int -> int tUniform integer generator producing integers within 0..bound.
Shrinks towards 0.
Invalid_argument if the argument is negative.val int_range : ?origin:int -> int -> int -> int tint_range ?origin low high is an uniform integer generator producing integers within low..high (inclusive).
Shrinks towards origin if specified, otherwise towards 0 (but always stays within the range).
Examples:
int_range ~origin:6 (-5) 15 will shrink towards 6int_range (-5) 15 will shrink towards 0int_range 8 20 will shrink towards 8 (closest to 0 within range)int_range (-20) (-8) will shrink towards -8 (closest to 0 within range)Invalid_argument if any of the following holds:low > highorigin < loworigin > highval (--) : int -> int -> int ta -- b is an alias for int_range a b. See QCheck2.Gen.int_range for more information.
val float_bound_inclusive : ?origin:float -> float -> float tfloat_bound_inclusive ?origin bound returns a random floating-point number between 0. and
bound (inclusive). If bound is negative, the result is negative or zero. If
bound is 0., the result is 0..
Shrinks towards origin if given, otherwise towards 0..
val float_bound_exclusive : ?origin:float -> float -> float tfloat_bound_exclusive origin bound returns a random floating-point number between 0. and
bound (exclusive). If bound is negative, the result is negative or zero.
Shrinks towards origin if given, otherwise towards 0..
Invalid_argument if bound is 0..val float_range : ?origin:float -> float -> float -> float tfloat_range ?origin low high generates floating-point numbers within low and high (inclusive).
Shrinks towards origin if specified, otherwise towards 0. (but always stays within the range).
Examples:
float_range ~origin:6.2 (-5.8) 15.1 will shrink towards 6.2float_range (-5.8) 15.1 will shrink towards 0.float_range 8.5 20.1 will shrink towards 8.5 (closest to 0. within range)float_range (-20.1) (-8.5) will shrink towards -8.5 (closest to 0. within range)Invalid_argument if any of the following holds:low > highhigh -. low > max_floatorigin < loworigin > highval (--.) : float -> float -> float ta --. b is an alias for float_range ~origin:a a b. See QCheck2.Gen.float_range for more information.
val char_range : ?origin:char -> char -> char -> char tchar_range ?origin low high generates chars between low and high, inclusive.
Example: char_range 'a' 'z' for all lower case ASCII letters.
Shrinks towards origin if specified, otherwise towards low.
Invalid_argument if low > high.val oneof : 'a t list -> 'a toneof l constructs a generator that selects among the given list of generators l.
Shrinks towards the first generator of the list.
Invalid_argument or Failure if l is emptyval oneofl : 'a list -> 'a toneofl l constructs a generator that selects among the given list of values l.
Shrinks towards the first element of the list.
Invalid_argument or Failure if l is emptyval oneofa : 'a array -> 'a toneofa a constructs a generator that selects among the given array of values a.
Shrinks towards the first element of the array.
Invalid_argument or Failure if l is emptyval frequency : (int * 'a t) list -> 'a tConstructs a generator that selects among a given list of generators. Each of the given generators are chosen based on a positive integer weight.
Shrinks towards the first element of the list.
val frequencyl : (int * 'a) list -> 'a tConstructs a generator that selects among a given list of values. Each of the given values are chosen based on a positive integer weight.
Shrinks towards the first element of the list.
val frequencya : (int * 'a) array -> 'a tConstructs a generator that selects among a given array of values. Each of the array entries are chosen based on a positive integer weight.
Shrinks towards the first element of the array.
val shuffle_a : 'a array -> 'a array tReturns a copy of the array with its elements shuffled.
val shuffle_l : 'a list -> 'a list tCreates a generator of shuffled lists.
val shuffle_w_l : (int * 'a) list -> 'a list tCreates a generator of weighted shuffled lists. A given list is shuffled on each generation according to the weights of its elements. An element with a larger weight is more likely to be at the front of the list than an element with a smaller weight. If we want to pick random elements from the (head of) list but need to prioritize some elements over others, this generator can be useful.
Example: given a weighted list [1, "one"; 5, "five"; 10, "ten"], the generator is
more likely to generate ["ten"; "five"; "one"] or ["five"; "ten"; "one"] than
["one"; "ten"; "five"] because "ten" and "five" have larger weights than "one".
val graft_corners : 'a t -> 'a list -> unit -> 'a tgraft_corners gen l () makes a new generator that enumerates
the corner cases in l and then behaves like g.
Does not shrink if the test fails on a grafted value.
Shrinks towards gen otherwise.
val int_pos_corners : int listNon-negative corner cases for int.
val int_corners : int listAll corner cases for int.
val list : 'a t -> 'a list tBuilds a list generator from an element generator. List size is generated by QCheck2.Gen.nat.
Shrinks on the number of elements first, then on elements.
val small_list : 'a t -> 'a list tGenerates lists of small size (see QCheck2.Gen.small_nat).
Shrinks on the number of elements first, then on elements.
val list_size : int t -> 'a t -> 'a list tBuilds a list generator from a (non-negative) size generator and an element generator.
Shrinks on the number of elements first, then on elements.
val list_repeat : int -> 'a t -> 'a list tlist_repeat i g builds a list generator from exactly i elements generated by g.
Shrinks on elements only.
val array : 'a t -> 'a array tBuilds an array generator from an element generator. Array size is generated by QCheck2.Gen.nat.
Shrinks on the number of elements first, then on elements.
val array_size : int t -> 'a t -> 'a array tBuilds an array generator from a (non-negative) size generator and an element generator.
Shrinks on the number of elements first, then on elements.
val small_array : 'a t -> 'a array tGenerates arrays of small size (see QCheck2.Gen.small_nat).
Shrinks on the number of elements first, then on elements.
val array_repeat : int -> 'a t -> 'a array tarray_repeat i g builds an array generator from exactly i elements generated by g.
Shrinks on elements only.
val option : ?ratio:float -> 'a t -> 'a option toption gen is an option generator that uses gen when generating Some values.
Shrinks towards None then towards shrinks of gen.
ratio : a float between 0. and 1. indicating the probability of a sample to be Some _
rather than None (value is 0.85).val opt : ?ratio:float -> 'a t -> 'a option topt is an alias of QCheck2.Gen.option for backward compatibility.
val pair : 'a t -> 'b t -> ('a * 'b) tpair gen1 gen2 generates pairs.
Shrinks on gen1 and then gen2.
val triple : 'a t ->
'b t -> 'c t -> ('a * 'b * 'c) ttriple gen1 gen2 gen3 generates triples.
Shrinks on gen1, then gen2 and then gen3.
val quad : 'a t ->
'b t ->
'c t -> 'd t -> ('a * 'b * 'c * 'd) tquad gen1 gen2 gen3 gen4 generates quadruples.
Shrinks on gen1, then gen2, then gen3 and then gen4.
gen1, then gen2, then ... val tup2 : 'a t -> 'b t -> ('a * 'b) t
val tup3 : 'a t ->
'b t -> 'c t -> ('a * 'b * 'c) t
val tup4 : 'a t ->
'b t ->
'c t -> 'd t -> ('a * 'b * 'c * 'd) t
val tup5 : 'a t ->
'b t ->
'c t ->
'd t ->
'e t -> ('a * 'b * 'c * 'd * 'e) t
val tup6 : 'a t ->
'b t ->
'c t ->
'd t ->
'e t ->
'f t -> ('a * 'b * 'c * 'd * 'e * 'f) t
val tup7 : 'a t ->
'b t ->
'c t ->
'd t ->
'e t ->
'f t ->
'g t -> ('a * 'b * 'c * 'd * 'e * 'f * 'g) t
val tup8 : 'a t ->
'b t ->
'c t ->
'd t ->
'e t ->
'f t ->
'g t ->
'h t -> ('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h) t
val tup9 : 'a t ->
'b t ->
'c t ->
'd t ->
'e t ->
'f t ->
'g t ->
'h t ->
'i t ->
('a * 'b * 'c * 'd * 'e * 'f * 'g * 'h * 'i) tval flatten_l : 'a t list -> 'a list tGenerate a list of elements from individual generators.
Shrinks on the elements of the list, in the list order.
val flatten_a : 'a t array -> 'a array tGenerate an array of elements from individual generators.
Shrinks on the elements of the array, in the array order.
val flatten_opt : 'a t option -> 'a option tGenerate an option from an optional generator.
Shrinks towards None then shrinks on the value.
val flatten_res : ('a t, 'e) Stdlib.result -> ('a, 'e) Stdlib.result tGenerate a result from Ok gen, an error from Error e.
Shrinks on gen if Ok gen.
Does not shrink if Error e.
val join : 'a t t -> 'a tCollapses a generator of generators to a generator.
Shrinks on the generated generators.
val sized : 'a sized -> 'a tCreates a generator from a size-bounded generator by first
generating a size using QCheck2.Gen.nat and passing the result to the size-bounded generator.
Shrinks on the size first, then on the generator.
val sized_size : int t -> 'a sized -> 'a tCreates a generator from a size-bounded generator by first generating a size using the integer generator and passing the result to the size-bounded generator.
Shrinks on the size first, then on the generator.
val fix : (('a -> 'b t) -> 'a -> 'b t) ->
'a -> 'b tParametrized fixpoint combinator for generating recursive values.
The fixpoint is parametrized over an generator state 'a, and the
fixpoint computation may change the value of this state in the recursive
calls.
In particular, this can be used for size-bounded generators (with 'a as int).
The passed size-parameter should decrease to ensure termination.
Example:
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))]
))
fix f shrinks on the generators returned by f.
val delay : (unit -> 'a t) -> 'a tDelay execution of some code until the generator is actually called. This can be used to manually implement recursion or control flow in a generator.
QCheck generators compose well: it means one can easily craft generators for new values or types from existing generators.
Part of the following documentation is greatly inspired by Gabriel Scherer's excellent Generator module documentation.
Gen.t is a functor (in the Haskell sense of "mappable"): it has a map function to transform a generator of 'a into a generator of 'b,
given a simple function 'a -> 'b.
let even_gen : int Gen.t = Gen.map (fun n -> n * 2) Gen.int
let odd_gen : int Gen.t = Gen.map (fun n -> n * 2 + 1) Gen.int
let lower_case_string_gen : string Gen.t = Gen.map String.lowercase Gen.string_printable
type foo = Foo of string * int
let foo_gen : foo Gen.t =
Gen.map (fun (s, n) -> Foo (s, n)) Gen.(pair string_printable int)
Gen.t is applicative: it has a map2 function to apply a function of 2 (or more) arguments to 2 (or more) generators.
Another equivalent way to look at it is that it has an ap function to apply a generator of
functions to a generator of values. While at first sight this may look almost useless, it actually
permits a nice syntax (using the operator alias <*>) for functions of any number of arguments.
(* Notice that this looks suspiciously like the [foo] example above:
this is no coincidence! [pair] is a special case of [map2] where
the function wraps arguments in a tuple. *)
type foo = Foo of string * int
let foo_gen : foo Gen.t =
Gen.map2 (fun s n -> Foo (s, n)) Gen.string_printable Gen.int
let string_prefixed_with_keyword_gen : string Gen.t =
Gen.map2 (fun prefix s -> prefix ^ s)
(Gen.oneofl ["foo"; "bar"; "baz"])
Gen.string_printable
Applicatives are useful when you need several random values to build a new generator, and the values are unrelated. A good rule of thumb is: if the values could be generated in parallel, then you can use an applicative function to combine those generators.
Note that while map2 and map3 are provided, you can use functions with more than 3
arguments (and that is where the <*> operator alias really shines):
val complex_function : bool -> string -> int -> string -> int64 -> some_big_type
(* Verbose version, using map3 and ap *)
let big_type_gen : some_big_type Gen.t = Gen.(
ap (
ap (
map3 complex_function
bool
string_printable
int)
string_printable)
int64)
(* Sleeker syntax, using operators aliases for map and ap *)
let big_type_gen : some_big_type Gen.t = Gen.(
complex_function
<$> bool
<*> string_printable
<*> int
<*> string_printable
<*> int64)
Gen.t is a monad: it has a bind function to return a generator (not a value)
based on another generated value.
As an example, imagine you want to create a generator of (int, string) result that is
an Ok 90% of the time and an Error 10% of the time. You can generate a number between
0 and 9 and return a generator of int (wrapped in an Ok using map) if the generated number is
lower than 9, otherwise return a generator of string (wrapped in an Error using map):
let int_string_result : (int, string) result Gen.t = Gen.(
bind (int_range 0 9) (fun n ->
if n < 9
then map Result.ok int
else map Result.error string_printable))
(* Alternative syntax with operators *)
let int_string_result : (int, string) result Gen.t = Gen.(
int_range 0 9 >>= fun n ->
if n < 9
then int >|= Result.ok
else string_printable >|= Result.error)
(* Another allternative syntax with OCaml 4.08+ binding operators *)
let int_string_result : (int, string) result Gen.t = Gen.(
let* n = int_range 0 9 in
if n < 9
then int >|= Result.ok
else string_printable >|= Result.error)
Note that this particular use case can be simplified by using frequency:
let int_string_result : (int, string) result Gen.t = Gen.(
frequency [
(9, int >|= Result.ok);
(1, string_printable >|= Result.error)
])
val map : ('a -> 'b) -> 'a t -> 'b tmap f gen transforms a generator gen by applying f to each generated element.
Shrinks towards the shrinks of gen with f applied to them.
val (>|=) : 'a t -> ('a -> 'b) -> 'b tAn infix synonym for QCheck2.Gen.map. Note the order of arguments is reversed (usually more
convenient for composing).
val (<$>) : ('a -> 'b) -> 'a t -> 'b tAn infix synonym for QCheck2.Gen.map
val map2 : ('a -> 'b -> 'c) -> 'a t -> 'b t -> 'c tmap2 f gen1 gen2 transforms two generators gen1 and gen2 by applying f to each
pair of generated elements.
Shrinks on gen1 and then gen2.
val map3 : ('a -> 'b -> 'c -> 'd) ->
'a t -> 'b t -> 'c t -> 'd tmap3 f gen1 gen2 gen3 transforms three generators gen1, gen2, and gen3 by applying f
to each triple of generated elements.
Shrinks on gen1, then gen2, and then gen3.
val ap : ('a -> 'b) t -> 'a t -> 'b tap fgen gen composes a function generator and an argument generator
into a result generator.
Shrinks on fgen and then gen.
val (<*>) : ('a -> 'b) t -> 'a t -> 'b tSynonym for QCheck2.Gen.ap
val bind : 'a t -> ('a -> 'b t) -> 'b tbind gen f first generates a value of type 'a with gen and then
passes it to f to generate a value of type 'b. This is typically
useful when a generator depends on the value generated by another
generator.
Shrinks on gen and then on the resulting generator.
val (>>=) : 'a t -> ('a -> 'b t) -> 'b tSynonym for QCheck2.Gen.bind
val let+ : 'a t -> ('a -> 'b) -> 'b t Binding operator alias for QCheck2.Gen.map.
Example:
let+ n = int_range 0 10 in
string_of_int n
(* is equivalent to *)
map (fun n -> string_of_int n) (int_range 0 10)
val and+ : 'a t -> 'b t -> ('a * 'b) t Binding operator alias for QCheck2.Gen.pair.
Example:
let+ n = int_range 0 10
and+ b = bool in
if b then string_of_int n else "Not a number"
(* is equivalent to *)
map
(fun (n, b) -> if b then string_of_int n else "Not a number")
(pair (int_range 0 10) bool)
val ( let* ) : 'a t -> ('a -> 'b t) -> 'b t Binding operator alias for QCheck2.Gen.bind.
Example:
let* n = int_range 0 9 in
if n < 9
then int >|= Result.ok
else string_printable >|= Result.error
(* is equivalent to *)
bind (int_range 0 9) (fun n ->
if n < 9
then map Result.ok int
else map Result.error string_printable)
val ( and* ) : 'a t -> 'b t -> ('a * 'b) t Binding operator alias for QCheck2.Gen.pair.
Example:
let* n = int_range 0 9
and* b = bool in
if n < 9 then int >|= Result.ok
else if b then pure (Error "Some specific error")
else string_printable >|= Result.error
(* is equivalent to *)
bind (pair (int_range 0 9) bool) (fun (n, b) ->
if n < 9 then map Result.ok int
else if b then pure (Error "Some specific error")
else map Result.error string_printable)
These functions should not be used in tests: they are provided for convenience to debug/investigate what values and shrinks a generator produces.
val generate : ?rand:Stdlib.Random.State.t -> n:int -> 'a t -> 'a listgenerate ~n gen generates n values using gen (shrinks are discarded).
val generate1 : ?rand:Stdlib.Random.State.t -> 'a t -> 'agenerate1 gen generates one instance of gen (shrinks are discarded).
val generate_tree : ?rand:Stdlib.Random.State.t -> 'a t -> 'a QCheck2.Tree.tgenerate_tree ?rand gen generates a random value and its shrinks using gen.