Module Base_quickcheck__.Generator
Basic Generators
These are good default generators for tests over types from OCaml and Base. They are designed to hit corner cases reasonably often, and also generate reasonably good coverage of common cases and arbitrary values.
val unit : Base.unit tval bool : Base.bool tval char : Base.char tval string : Base.string tval int : Base.int tval int32 : Base.int32 tval int63 : Base.Int63.t tval int64 : Base.int64 tval nativeint : Base.nativeint tval float : Base.float tval sexp : Base.Sexp.t tval option : 'a t -> 'a Base.option tval list : 'a t -> 'a Base.list tval both : 'a t -> 'b t -> ('a * 'b) tval either : 'a t -> 'b t -> ('a, 'b) Base.Either.t tval result : 'a t -> 'b t -> ('a, 'b) Base.Result.t t
val fn : 'a Base_quickcheck__.Observer0.t -> 'b t -> ('a -> 'b) tGenerates random functions that use the given observer to perturb the pseudo-random state that is then used to generate the output value. The resulting functions are therefore deterministic, assuming the observer is deterministic.
val map_t_m : ('key, 'cmp) Base.Set.comparator -> 'key t -> 'data t -> ('key, 'data, 'cmp) Base.Map.t tval set_t_m : ('elt, 'cmp) Base.Set.comparator -> 'elt t -> ('elt, 'cmp) Base.Set.t tval map_tree_using_comparator : comparator:('key, 'cmp) Base.Comparator.t -> 'key t -> 'data t -> ('key, 'data, 'cmp) Base.Map.Using_comparator.Tree.t tval set_tree_using_comparator : comparator:('elt, 'cmp) Base.Comparator.t -> 'elt t -> ('elt, 'cmp) Base.Set.Using_comparator.Tree.t t
Combining and Modifying Generators
val union : 'a t Base.list -> 'a tChooses among the given generators, weighted uniformly; then chooses a value from that generator.
include Base.Applicative.S with type 'a t := 'a t
val apply : ('a -> 'b) t -> 'a t -> 'b tval map2 : 'a t -> 'b t -> f:('a -> 'b -> 'c) -> 'c tval map3 : 'a t -> 'b t -> 'c t -> f:('a -> 'b -> 'c -> 'd) -> 'd tval all : 'a t list -> 'a list tval all_unit : unit t list -> unit tval all_ignore : unit t list -> unit t
module Applicative_infix : Base__.Applicative_intf.Applicative_infix with type 'a t := 'a tinclude Base.Monad.S with type 'a t := 'a t
include Base__.Monad_intf.S_without_syntax with type 'a t := 'a t
module Monad_infix : Base__.Monad_intf.Infix with type 'a t := 'a tval return : 'a -> 'a treturn vreturns the (trivial) computation that returns v.
val ignore_m : 'a t -> unit tignore_m tismap t ~f:(fun _ -> ()).ignore_mused to be calledignore, but we decided that was a bad name, because it shadowed the widely usedCaml.ignore. Some monads still dolet ignore = ignore_mfor historical reasons.
Size of Random Values
Base_quickcheck threads a size parameter through generators to limit the size of unbounded types. Users of Base_quickcheck often do not need to think about the size parameter; the default generators handle it sensibly. Generators of atomic types ignore it, generators of bounded-size containers like both and either thread it through unchanged, and generators of unbounded-size containers like list and set_t_m distribute the size they are given among their constituents.
The bindings below allow direct manipulation of the size parameter in cases where users want a custom treatment of sizes. There is no prescribed meaning of the size parameter for any given type other than that it must be non-negative. As a general guideline, however, the time and space used to generate a value should be proportional to the size parameter at most.
The size parameter should be treated as an upper bound but not as a lower bound, so for example a generator given a size parameter of 2 should have a chance to generate values of size 0 or 1 as well. If the size parameter is treated as a lower bound, then for example members of tuples will always be generated at the same size, and test cases for members of different size will not be covered.
val with_size : 'a t -> size:Base.int -> 'a tProduces a generator that ignores the size parameter passed in by Base_quickcheck and instead uses the given
~sizeargument. Most often used withsizeto reduce the size when dispatching to generators for subparts of a value.For example, here is a use of
with_sizeandsizeto create a generator for optional lists. We are careful to generateNoneeven at non-zero sizes; see the note above about not usingsizeas a lower bound.let optional_list generator = let open Let_syntax in match%bind both size bool with | (0, _) | (_, false) -> return None | k, _ -> let%map elements = with_size ~size:(k-1) (list generator) in Some elements
val sizes : ?min_length:Base.int -> ?max_length:Base.int -> Base.unit -> Base.int Base.list tProduces a list of sizes that distribute the current size among list elements. The
min_lengthandmax_lengthparameters can be used to bound the length of the result.This is the distribution used by generators such as
listto divide up size among elements.This function is designed so that elements of
listare always generated at strictly smaller size than the list itself. The technical invariant is: ifsize_listis generated bywith_size ~size:n (sizes ~min_length ()), then:(List.length size_list - min_length) + (List.sum (module Int) size_list) <= n
Filtering Generators
val filter : 'a t -> f:('a -> Base.bool) -> 'a tProduces values for which
freturnstrue. Iffreturnsfalse, retries withsizeincremented by 1. This avoidsfiltergetting stuck if all values at a given size failf; see the note above about not usingsizeas a lower bound.
val filter_map : 'a t -> f:('a -> 'b Base.option) -> 'b tWhen
fproducesSome x, producesx. IffreturnsNone, retries withsizeincremented by 1, as withfilter.
Generating Recursive Values
val recursive_union : 'a t Base.list -> f:('a t -> 'a t Base.list) -> 'a tTies the recursive knot to produce generators for recursive types that have multiple clauses, separating base cases from recursive cases. At size 0, only base cases are produced; at size
n > 0, the base cases are produced at sizenalong with the recursive cases at sizen-1. Raises if the list of base cases is empty or if the list of recursive cases is empty.For example, here is a use of
recursive_unionto create a generator for an expression datatype.type exp = | Int of int | Bool of bool | If of exp * exp * exp | Add of exp * exp let exp_generator = recursive_union [ map int ~f:(fun i -> Int i); map bool ~f:(fun b -> Bool b); ] ~f:(fun exp -> let open Let_syntax in [ (let%map a = exp and b = exp and c = exp in If (a, b, c)); (let%map a = exp and b = exp in Add (a, b)); ])
val fixed_point : ('a t -> 'a t) -> 'a tLike
recursive_union, without separate clauses or automatic size management. Useful for generating recursive types that don't fit the clause structure ofrecursive_union.For example, here is a use of
fixed_pointto create a generator for N-ary trees. No manual size management is needed, asGenerator.listguarantees to generate list elements at strictly smaller sizes than the list itself.type tree = Node of tree list let tree_generator = fixed_point (fun tree -> map (list tree) ~f:(fun trees -> Node trees))
Custom Random Distributions
val of_weighted_list : (Base.float * 'a) Base.list -> 'a tProduces one of the given values, chosen with the corresponding weight. Weights must be non-negative and must have a strictly positive sum.
val weighted_union : (Base.float * 'a t) Base.list -> 'a tProduces one of the given generators, chosen with the corresponding weight, then chooses a value from that generator. Weights must be non-negative and must have a strictly positive sum.
val weighted_recursive_union : (Base.float * 'a t) Base.list -> f:('a t -> (Base.float * 'a t) Base.list) -> 'a tLike
recursive_union, with explicit weights for each clause. Weights must be non-negative and the recursive case weights must have a strictly positive sum.
Integer Distributions
val small_positive_or_zero_int : Base.int tProduces an integer between 0 and an unspecified upper bound which is proportional to
size. This is a good generator to use for sizes of values like strings which have a variable number of fixed-size elements.
val small_strictly_positive_int : Base.int tLike
small_positive_or_zero_intbut with a minimum of1.
Uniform Unbounded Distributions
These generators produce any value of the relevant integer type with uniform weight. The default generators for these types differ in that they give higher weight to corner cases, e.g. min_value and max_value.
val int_uniform : Base.int tval int32_uniform : Base.int32 tval int63_uniform : Base.Int63.t tval int64_uniform : Base.int64 tval nativeint_uniform : Base.nativeint t
Bounded Distributions
These generators produce any value between the given inclusive bounds, which must be given in nondecreasing order. Higher weight is given to corner cases, e.g. the bounds themselves.
val int_inclusive : Base.int -> Base.int -> Base.int tval int32_inclusive : Base.int32 -> Base.int32 -> Base.int32 tval int63_inclusive : Base.Int63.t -> Base.Int63.t -> Base.Int63.t tval int64_inclusive : Base.int64 -> Base.int64 -> Base.int64 tval nativeint_inclusive : Base.nativeint -> Base.nativeint -> Base.nativeint t
Uniform Bounded Distributions
These generators produce any value between the given inclusive bounds, which must be given in nondecreasing order. All values are given equal weight.
val int_uniform_inclusive : Base.int -> Base.int -> Base.int tval int32_uniform_inclusive : Base.int32 -> Base.int32 -> Base.int32 tval int63_uniform_inclusive : Base.Int63.t -> Base.Int63.t -> Base.Int63.t tval int64_uniform_inclusive : Base.int64 -> Base.int64 -> Base.int64 tval nativeint_uniform_inclusive : Base.nativeint -> Base.nativeint -> Base.nativeint t
Uniform in Log Space Distributions
These generators produce any value between the given inclusive, non-negative bounds, choosing bit-length in that range uniformly and then uniformly among values with that bit-length between the bounds. The bounds must be given in nondecreasing order.
val int_log_uniform_inclusive : Base.int -> Base.int -> Base.int tval int32_log_uniform_inclusive : Base.int32 -> Base.int32 -> Base.int32 tval int63_log_uniform_inclusive : Base.Int63.t -> Base.Int63.t -> Base.Int63.t tval int64_log_uniform_inclusive : Base.int64 -> Base.int64 -> Base.int64 tval nativeint_log_uniform_inclusive : Base.nativeint -> Base.nativeint -> Base.nativeint t
Log Space Distributions
Like the *_log_uniform_inclusive bindings above, but giving additional weight to corner cases, e.g. the given bounds.
val int_log_inclusive : Base.int -> Base.int -> Base.int tval int32_log_inclusive : Base.int32 -> Base.int32 -> Base.int32 tval int63_log_inclusive : Base.Int63.t -> Base.Int63.t -> Base.Int63.t tval int64_log_inclusive : Base.int64 -> Base.int64 -> Base.int64 tval nativeint_log_inclusive : Base.nativeint -> Base.nativeint -> Base.nativeint t
Floating Point Distributions
val float_inclusive : Base.float -> Base.float -> Base.float tGenerates values between the given bounds, inclusive, which must be finite and in nondecreasing order. Weighted toward boundary values.
val float_uniform_exclusive : Base.float -> Base.float -> Base.float tGenerates values between the given bounds, exclusive, which must be finite and in increasing order, with at least one float value between them. Weighted approximately uniformly across the resulting range, rounding error notwithstanding.
val float_without_nan : Base.float tval float_finite : Base.float tval float_strictly_positive : Base.float tval float_strictly_negative : Base.float tval float_positive_or_zero : Base.float tval float_negative_or_zero : Base.float tval float_of_class : Base.Float.Class.t -> Base.float t
Character Distributions
String Distributions
val string_non_empty : Base.string tval string_with_length : length:Base.int -> Base.string tval string_of : Base.char t -> Base.string tval string_non_empty_of : Base.char t -> Base.string tval string_with_length_of : Base.char t -> length:Base.int -> Base.string t
Sexp Distributions
val sexp_of : Base.string t -> Base.Sexp.t tProduces s-expressions whose atoms are chosen from the given string distribution.
List Distrubtions
Low-Level Interface
These functions provide direct access to the pseudo-random state threaded through Base_quickcheck generators. Most users should not need these functions.
val perturb : 'a t -> Base.int -> 'a tPasses in additional "salt" used to perturb the pseudo-random state used to generate random values. Generators' output is intended to be deterministic for any initial pseudorandom state, so
perturbcan be used to generate a new generator with the same distribution that nonetheless produces different values from the original for any given pseudo-random state.
val create : (size:Base.int -> random:Splittable_random.State.t -> 'a) -> 'a tCreates a generator that calls the given function with the current size parameter and pseudorandom state.
val generate : 'a t -> size:Base.int -> random:Splittable_random.State.t -> 'aGenerates a random value using the given size and pseudorandom state. Useful when using
createand dispatching to other existing generators.