Overview
Generators of test values that draw through a recorder, so that a failing case shrinks by replaying fewer and smaller draws.
(import (std prelude))
(import (std test gen))
(type (: Suit (Union Hearts Spades Clubs Diamonds)))
(type (: Card (Record (: rank int) (: suit Suit))))
(: gen-card (Gen Card))
(def gen-card
(gen-let ((rank (gen-int-range 1 13))
(suit (gen-element (list Hearts Spades Clubs Diamonds))))
(Card (rank rank) (suit suit))))
(impl (Arbitrary Card) (defun (arbitrary) gen-card))
(gen-sample gen-card) ; one card
(gen-samples (gen-list gen-int) 5) ; five lists, small ones first
A (Gen T) makes values of type T. Property tests in
(std test prop) use generators, but this module does not import
(std test). A program can use the generators without the test
runner, for example to make fixtures.
The recorder. A generator does not read a RandomSource
itself. It asks a Choices for numbers with draw. A
Choices has one of two modes:
- Recording (
recording-choices): it draws each number from a random source and records it. - Replaying (
replaying-choices): it answers the numbers of a vector, in order. When the vector is used up, each further draw answers 0.
draw records the number after it puts it into its bound, not the
raw random number. So a recorded vector replays to the same value, and a
changed vector replays to a value that is still in range.
Smaller draws give simpler values. (std test prop)
shrinks a failing case: it makes the recorded vector smaller and replays
it. This gives a simpler value only when each generator obeys this rule:
0 is the simplest choice at every draw, and a larger draw gives a value
farther from the simplest. Because a used-up vector answers 0, a shorter
vector also gives a simpler value. Thus no generator needs a shrinker of
its own. Every generator in this module obeys the rule:
- A number generator gives the value nearest 0 at a draw of 0: the lower bound of a range above 0, the upper bound of a range below 0, and 0 itself otherwise.
gen-listdraws “one more element?” before each element, and 0 means “no more”. So deleting draws makes the list shorter.gen-one-of,gen-frequencyandgen-elementtake their first alternative at 0. Put the simplest alternative first.gen-recursivetakes the base case at 0.gen-boolgives #f,gen-optionNone,gen-resultOk,gen-char#\a,gen-stringthe empty string, andgen-shufflethe order it was given.
A generator made from these with gen-map, gen-bind,
gen-let and the other combinators obeys the rule too.
A generator of your own. Build it from the generators above
when you can: it then obeys the rule without more work. A generator
made with make-gen that calls draw itself must obey the
rule on its own:
- Map a draw of 0 to the simplest value: the origin or identity
of the domain, such as 0, the empty list or the base case. A range
that does not hold 0 starts at its end nearest 0, so add the draw to
the lower bound,
(+ lo (draw c n)), for a range above 0. - Make a larger draw give a value farther from the simplest. For
a range across 0, draw the sign first, positive at 0, and then the
distance from 0, as
gen-int-rangedoes. A draw over the whole range, added tolo, makes the most negative value the simplest, and shrinking then goes to it. - When a draw chooses between kinds of value, put the simplest kind at 0, and make a kind that is a shortcut to a value, such as an edge value, cost at least as many draws as the other way to the same value. Shrinking prefers fewer draws, and would otherwise keep the shortcut.
- Draw a “one more?” choice, 0 for no, before each element of a collection, so that deleting draws removes elements.
A generator that breaks the rule still works: its values are as random as before. Only its failing cases shrink less well.
Sizes. A Choices has a size, which choices-size
gives. Numbers, lists and recursive values grow with it. A property’s
first runs have small sizes and its last runs large ones, so small
cases are tried first. gen-sized reads the size, and
gen-resize changes it.
Edge values. The number and text generators give values that
often find bugs: int-max, -1, NaN when asked for, surrogate
pairs, combining characters. An edge of an integer is recorded as the
draws that the full-range way to the same value would record. So
shrinking can change the draw that chose the edge, keep the value, and
then make the value smaller.
Discarded runs. A generator can give up: gen-such-that
after 100 tries, and any generator after 10000 draws. It then calls
discard!, which marks the Choices and raises an exception.
(std test prop) does not count a discarded run.
Gen is not a Monad. The callback of the bind of a
Monad can be a bjoroutine, but a generator runs inside an
ordinary function. Use gen-let to draw values in order, or
gen-bind.
Defaults by type. The trait Arbitrary gives a generator
for a type. (for-all ((: xs (List int))) ...) uses it. An
instance is only a generator, because shrinking needs nothing more.
See also: Gen, draw, gen-let, Arbitrary, gen-sample
Reference
arbitrarychoices-discarded?choices-drawschoices-sizediscard!drawgen-arraygen-bindgen-doublegen-elementgen-frequencygen-hashsetgen-int-rangegen-listgen-list-of-lengthgen-long-rangegen-mapgen-map-ofgen-one-ofgen-optiongen-orderedmapgen-orderedsetgen-puregen-recursivegen-resizegen-resultgen-rungen-samplegen-samplesgen-shufflegen-sizedgen-string-ofgen-such-thatgen-tuple2gen-tuple3gen-tuple4gen-vecmake-genrecording-choicesreplaying-choices
Types
Choices
record ↑ Types
Where a generator gets its numbers: from a random source, recorded, or from a recorded vector, replayed.
A Choices records every number that it answers, in both modes.
After a replay, the record is the part of the vector that the replay
used, followed by the zeros it answered after the vector was used up.
A Choices also holds the size of the run, and whether the run
was discarded.
A Choices is for one run of a generator. Make a new one for each
run.
See also: recording-choices, replaying-choices, draw, choices-draws
Gen
record ↑ Types
A generator of values of type %a.
%a- The type of the values.
A generator is a function from a Choices to a value. Make one
from the generators and combinators of this module, or with
make-gen.
Arbitrary
trait ↑ Types
The generator that a type has when a property names no generator.
%a- The type that the generator makes.
(impl (Arbitrary Card) (defun (arbitrary) gen-card))
;; In (std test prop): (: xs (List Card)) uses it.
(for-all ((: xs (List Card)))
(check (= (list-length (list-sort xs)) (list-length xs))))
This module has instances for bool, int, long, ulong, bigint, double
(without NaN and the infinities), char, string, void, Option,
Result, tuples of two and three, List, Vec,
Map, HashSet, OrderedMap and OrderedSet.
An instance for a container needs instances for the types in it.
An instance is only a generator. It has no shrinker, because shrinking replays smaller draws. A generator in an instance must obey the rule that smaller draws give simpler values.
Functions
recording-choices
function ↑ Functions
(: recording-choices (-> RandomSource int Choices))
(recording-choices rng size)
A Choices that draws from a random source and records each number.
rng- The source to draw from.
size- The size of the run. Numbers, lists and recursive values grow with it.
- returns
- A new Choices, with nothing recorded.
(def c (recording-choices (make-random/seed64 3UL) 60))
(def v (gen-run (gen-list gen-int) c))
(choices-draws c) ; the draws that replay to v
See also: replaying-choices, choices-draws
replaying-choices
function ↑ Functions
(: replaying-choices (-> (Vec ulong) int Choices))
(replaying-choices draws size)
A Choices that answers the numbers of a vector in order, and 0 after the vector is used up.
draws- The numbers to answer, usually from
choices-draws. size- The size of the run. Give the size of the recording, or a replay can give a different value.
- returns
- A new Choices, with nothing recorded.
(gen-run g (replaying-choices (choices-draws c) 60)) ; the value again
(gen-run g (replaying-choices (vec-empty) 60)) ; the simplest value of g
A number of the vector is put into the bound of its draw. So a vector that was changed, for example by shrinking, still gives a value in range.
See also: recording-choices, choices-draws
draw
function ↑ Functions
(: draw (-> Choices ulong ulong))
(draw c bound)
A number from 0, included, to bound, not included. Every generator is made from this.
c- The choices to draw from.
bound- The bound. 0 means every ulong.
- returns
- A number in [0, bound). A replay answers the next number of its vector, put into the bound, or 0 when the vector is used up.
- raises
ArgumentException - When the run drew 10000 numbers before. The run is then discarded: see
discard!.
;; A die. A draw of 0 gives 1, the simplest value.
(def gen-die (make-gen (fun (c) (+ 1 (cast System.Int32 (draw c 6UL))))))
The number is recorded after it is put into the bound. Map 0 to the simplest value, and larger numbers to values farther from it, so that shrinking makes values simpler.
A recording puts a random number into the bound with a remainder, so a bound that is not a power of 2 makes small numbers slightly more likely.
See also: choices-size, discard!
choices-size
function ↑ Functions
(: choices-size (-> Choices int))
(choices-size c)
The size of the run.
c- The choices.
- returns
- The size given when the choices were made, or the size that
gen-resizeset.
See also: gen-sized, gen-resize
choices-draws
function ↑ Functions
(: choices-draws (-> Choices (Vec ulong)))
(choices-draws c)
Every number that the choices answered, in order.
c- The choices.
- returns
- The record. Replayed with
replaying-choices, at the same size, it gives the same value.
After a replay, the record is the part of the vector that was used, and a 0 for each draw after the vector was used up.
See also: replaying-choices
choices-discarded?
function ↑ Functions
(: choices-discarded? (-> Choices bool))
(choices-discarded? c)
Whether the run was discarded.
c- The choices.
- returns
- #t after
discard!.
A discarded run ends with an exception. The code that ran the generator examines this flag, not the exception, to tell a discard from a failure.
See also: discard!
discard!
function ↑ Functions
(: discard! (-> Choices string %a))
(discard! c why)
Marks the run as discarded and leaves it with an exception.
c- The choices of the run.
why- Why the run is discarded. It is the message of the exception, after
discarded:. - returns
- Nothing: it always raises. The result type fits any position.
- raises
ArgumentException - Always.
Use it in a generator that can not make a good value from its draws.
(std test prop) does not count a discarded run, and fails a
property when more than 10 times its runs are discarded.
See also: choices-discarded?, gen-such-that
make-gen
function ↑ Functions
(: make-gen (-> (-> Choices %a) (Gen %a)))
(make-gen f)
A generator from a function that draws from a Choices.
f- The function. It gets the choices of the run, and answers a value.
- returns
- The generator.
(: gen-even (Gen int))
(def gen-even
(make-gen (fun (c) (* 2 (cast System.Int32 (draw c 1000UL))))))
The function must get all its numbers from the choices, through
draw or other generators. It must map a draw of 0 to the
simplest value, or shrinking does not make its values simpler.
gen-run
function ↑ Functions
(: gen-run (-> (Gen %a) Choices %a))
(gen-run g c)
Runs a generator with the choices of a run.
g- The generator.
c- The choices.
- returns
- The value that g makes from the draws of c.
(gen-run gen-int (replaying-choices (vec-empty) 50)) ; 0
See also: make-gen, gen-sample
gen-sample
function ↑ Functions
(: gen-sample (-> (Gen %a) (#:size int) (#:rng RandomSource) %a))
(gen-sample g #:size 30 #:rng (make-random))
One value of a generator.
g- The generator.
#:size- The size of the run.
#:rng- The source to draw from. A new source each call when not given.
- returns
- A value that g makes.
(gen-sample (gen-list gen-int))
(gen-sample gen-string #:size 5 #:rng (make-random/seed64 1UL))
See also: gen-samples
gen-samples
function ↑ Functions
(: gen-samples (-> (Gen %a) int (#:size int) (#:rng RandomSource) (List %a)))
(gen-samples g n #:size 100 #:rng (make-random))
Values of a generator, at sizes that grow as the runs of a property do.
g- The generator.
n- How many values.
#:size- The size of the last value.
#:rng- The source to draw from. A new source each call when not given.
- returns
- n values. The first is made at size 1 and the last at size, with sizes evenly between.
(gen-samples (gen-list gen-int) 20 #:rng (make-random/seed64 1UL))
Each value draws from its own source, split from rng. The same seed gives the same values.
See also: gen-sample
gen-pure
function ↑ Functions
(: gen-pure (-> %a (Gen %a)))
(gen-pure x)
A generator that always makes x and draws nothing.
x- The value.
- returns
- The generator.
See also: gen-element
gen-map
function ↑ Functions
(: gen-map (-> (-> %a %b) (Gen %a) (Gen %b)))
(gen-map f g)
A generator whose values are those of another, with a function applied.
f- The function.
g- The generator.
- returns
- A generator of the results of f.
(def gen-even (gen-map (fun (n) (* 2 n)) gen-int))
gen-map applies a function to values. The generator of a prelude
Map is gen-map-of.
gen-bind
function ↑ Functions
(: gen-bind (-> (Gen %a) (-> %a (Gen %b)) (Gen %b)))
(gen-bind g f)
A generator that draws a value, and then draws from the generator that a function makes from it.
g- The first generator.
f- A function from the first value to the next generator. It must be an ordinary function, not a bjoroutine.
- returns
- The generator.
;; A list and an index into it.
(gen-bind (gen-such-that (fun (xs) (not (list-empty? xs))) (gen-list gen-int))
(fun (xs) (gen-map (fun (i) (Tuple xs i))
(gen-int-range 0 (- (list-length xs) 1)))))
Both generators draw from the same choices, so shrinking makes both
values simpler. gen-let writes the same thing with names.
gen-such-that
function ↑ Functions
(: gen-such-that (-> (-> %a bool) (Gen %a) (Gen %a)))
(gen-such-that pred g)
A generator of the values of g for which pred holds.
pred- The condition.
g- The generator.
- returns
- A generator that runs g until pred holds.
(gen-such-that even? gen-int)
After 100 values for which pred does not hold, the run is discarded.
A condition that few values satisfy tests little, so a property whose
runs are discarded too often fails. Prefer a generator that makes good
values directly, for example (gen-map (fun (n) (* 2 n)) gen-int)
instead of (gen-such-that even? gen-int).
See also: discard!
gen-one-of
function ↑ Functions
(: gen-one-of (-> (List (Gen %a)) (Gen %a)))
(gen-one-of gens)
A generator that makes a value with one of the generators, each equally likely.
gens- The generators. The first is the simplest: a draw of 0 chooses it.
- returns
- The generator.
- raises
ArgumentException - When gens is empty.
(gen-one-of (list (gen-pure 0) (gen-int-range 1 9) gen-int))
See also: gen-frequency, gen-element
gen-frequency
function ↑ Functions
(: gen-frequency (-> (List (Tuple int (Gen %a))) (Gen %a)))
(gen-frequency choices)
A generator that makes a value with one of the generators, chosen by weight.
choices- Pairs of a weight and a generator. A generator is chosen with a probability of its weight divided by the sum of the weights. The first is the simplest.
- returns
- The generator.
- raises
ArgumentException - When the sum of the weights is not above 0.
(gen-frequency (list (Tuple 1 (gen-pure None))
(Tuple 3 (gen-map Some gen-int))))
A generator with a weight of 0 is never chosen. Give no weight less than 0.
See also: gen-one-of
gen-element
function ↑ Functions
(: gen-element (-> (List %a) (Gen %a)))
(gen-element xs)
A generator that makes one of the values, each equally likely.
xs- The values. The first is the simplest: a draw of 0 chooses it.
- returns
- The generator.
- raises
ArgumentException - When xs is empty.
(gen-element (list Hearts Spades Clubs Diamonds))
See also: gen-one-of, gen-shuffle
gen-sized
function ↑ Functions
(: gen-sized (-> (-> int (Gen %a)) (Gen %a)))
(gen-sized f)
A generator that a function makes from the size of the run.
f- A function from the size to a generator.
- returns
- The generator.
;; A list of exactly size elements.
(gen-sized (fun (n) (gen-list-of-length n gen-int)))
See also: choices-size, gen-resize
gen-resize
function ↑ Functions
(: gen-resize (-> int (Gen %a) (Gen %a)))
(gen-resize n g)
A generator that runs g at another size.
n- The size for g.
g- The generator.
- returns
- The generator. After g, the size is again what it was.
(gen-resize 5 (gen-list gen-int)) ; short lists at every size
See also: gen-sized
gen-recursive
function ↑ Functions
(: gen-recursive (-> (Gen %a) (-> (Gen %a) (Gen %a)) (Gen %a)))
(gen-recursive base step)
A generator of a recursive type, which halves the size at each level so that its values end.
base- The generator of the base case, such as a leaf.
step- A function from a generator of the smaller parts to a generator of one level.
- returns
- The generator.
(type (: Tree (Union Leaf (: Node Tree int Tree))))
(: gen-tree (Gen Tree))
(def gen-tree
(gen-recursive (gen-pure Leaf)
(fun (self) (gen-let ((l self) (x gen-int) (r self))
(Node l x r)))))
At size 0 or less, it makes the base case. At a larger size, a draw chooses: a draw of 0 makes the base case, and the others call step with this generator at half the size. Thus a case shrinks toward the base case. The base case comes at one draw in four, and always when the size reaches 0.
See also: gen-sized
gen-int-range
function ↑ Functions
(: gen-int-range (-> int int (Gen int)))
(gen-int-range lo hi)
An int from lo to hi, both included, each equally likely.
lo- The smallest value.
hi- The largest value. Not less than lo.
- returns
- The generator.
- raises
ArgumentException - When lo is above hi.
(gen-int-range 1 6) ; a die
The simplest value is the one nearest 0: lo when the range is above 0, hi when it is below 0, and 0 when the range contains 0. A range that contains 0 draws the sign first, then the distance from 0. So a value shrinks toward 0.
See also: gen-int, gen-long-range
gen-long-range
function ↑ Functions
(: gen-long-range (-> long long (Gen long)))
(gen-long-range lo hi)
A long from lo to hi, both included, each equally likely.
lo- The smallest value.
hi- The largest value. Not less than lo.
- returns
- The generator.
- raises
ArgumentException - When lo is above hi.
The simplest value is the one nearest 0, as for gen-int-range.
The range can be all the longs.
See also: gen-long, gen-int-range
gen-double
function ↑ Functions
(: gen-double (-> (#:special bool) (Gen double)))
(gen-double #:special #f)
A double that grows with the size, with edge values now and then. 0.0 is the simplest.
#:special- #t to add NaN, positive infinity and negative infinity to the edges.
- returns
- The generator.
(gen-double)
(gen-double #:special #t) ; also NaN and the infinities
9 times in 10, a whole part from -size² to size², with a fraction of 53
bits added away from 0. 1 time in 10, an edge: 0.0, 1.0, -1.0, the
largest and the smallest doubles, the smallest double above 0, and
-0.0. NaN and the infinities find bugs, but many properties do not hold
for them, so they come only with #:special #t.
See also: gen-int
gen-string-of
function ↑ Functions
(: gen-string-of (-> (Gen char) (Gen string)))
(gen-string-of g)
A string of the characters of a generator, whose length grows with the size.
g- The generator of the characters.
- returns
- The generator. The empty string is the simplest.
(gen-string-of (gen-element (string->list "ACGT"))) ; DNA
See also: gen-string, gen-list
gen-option
function ↑ Functions
(: gen-option (-> (Gen %a) (Gen (Option %a))))
(gen-option g)
None, or Some value of g. None is the simplest.
g- The generator of the value.
- returns
- The generator. It makes None 1 time in 4.
See also: gen-result
gen-result
function ↑ Functions
(: gen-result (-> (Gen %e) (Gen %a) (Gen (Result %e %a))))
(gen-result ge ga)
Ok with a value of ga, or Err with a value of ge, equally likely. Ok is the simplest.
ge- The generator of the error.
ga- The generator of the value.
- returns
- The generator.
See also: gen-option
gen-tuple2
function ↑ Functions
(: gen-tuple2 (-> (Gen %a) (Gen %b) (Gen (Tuple %a %b))))
(gen-tuple2 ga gb)
A pair of values, the first drawn first.
ga- The generator of the first value.
gb- The generator of the second value.
- returns
- The generator.
See also: gen-tuple3, gen-tuple4, gen-let
gen-tuple3
function ↑ Functions
(: gen-tuple3 (-> (Gen %a) (Gen %b) (Gen %c) (Gen (Tuple %a %b %c))))
(gen-tuple3 ga gb gc)
A tuple of three values, drawn in order.
ga- The generator of the first value.
gb- The generator of the second value.
gc- The generator of the third value.
- returns
- The generator.
See also: gen-tuple2, gen-tuple4
gen-tuple4
function ↑ Functions
(: gen-tuple4 (-> (Gen %a) (Gen %b) (Gen %c) (Gen %d) (Gen (Tuple %a %b %c %d))))
(gen-tuple4 ga gb gc gd)
A tuple of four values, drawn in order.
ga- The generator of the first value.
gb- The generator of the second value.
gc- The generator of the third value.
gd- The generator of the fourth value.
- returns
- The generator.
Arbitrary has no instance for tuples of four. Name this
generator in the binding.
See also: gen-tuple2, gen-tuple3
gen-list
function ↑ Functions
(: gen-list (-> (Gen %a) (Gen (List %a))))
(gen-list g)
A list of values of g, whose length grows with the size. The empty list is the simplest.
g- The generator of the elements.
- returns
- The generator.
(gen-list gen-int)
(gen-list (gen-int-range 0 20))
Before each element, a draw tells whether there is one more element, and 0 tells that there is not. So shrinking makes a list shorter when it deletes draws, and ends it when it sets such a draw to 0.
The length is 1 + size / 5 on average: 1 at size 0, and 21 at size 100. A list has at most 1000 elements, at any size.
See also: gen-list-of-length, gen-vec, gen-array
gen-list-of-length
function ↑ Functions
(: gen-list-of-length (-> int (Gen %a) (Gen (List %a))))
(gen-list-of-length n g)
A list of exactly n values of g.
n- The length.
g- The generator of the elements.
- returns
- The generator.
The length does not shrink. Use gen-list when the length is part
of what to test.
See also: gen-list
gen-vec
function ↑ Functions
(: gen-vec (-> (Gen %a) (Gen (Vec %a))))
(gen-vec g)
A vec of values of g, as gen-list makes.
g- The generator of the elements.
- returns
- The generator. The empty vec is the simplest.
gen-array
function ↑ Functions
(: gen-array (-> (Gen %a) (Gen (Array %a))))
(gen-array g)
A new array of values of g, as gen-list makes.
g- The generator of the elements.
- returns
- The generator. The empty array is the simplest. Each value is a new array.
gen-shuffle
function ↑ Functions
(: gen-shuffle (-> (List %a) (Gen (List %a))))
(gen-shuffle xs)
A permutation of the values. The order of xs is the simplest.
xs- The values.
- returns
- The generator.
Fisher-Yates from the front: element i changes places with an element at i or after it, and a draw of 0 keeps it at i. So a case shrinks toward the order of xs.
See also: gen-element
gen-map-of
function ↑ Functions
(: gen-map-of (-> (Gen %k) (Gen %v) (Gen (Map %k %v))))
(gen-map-of gk gv)
A prelude Map, made from a gen-list of keys and values.
gk- The generator of the keys.
gv- The generator of the values.
- returns
- The generator. The empty map is the simplest.
The map shrinks as its list of entries does. When the list has a key more than once, the last value wins. So the map can have fewer entries than the list.
See also: gen-orderedmap, gen-list
gen-hashset
function ↑ Functions
(: gen-hashset (-> (Gen %a) (Gen (HashSet %a))))
(gen-hashset g)
A HashSet, made from a gen-list of its elements.
g- The generator of the elements.
- returns
- The generator. The empty set is the simplest.
See also: gen-orderedset, gen-list
gen-orderedmap
function ↑ Functions
(: gen-orderedmap (-> (Gen %k) (Gen %v) (Gen (OrderedMap %k %v))))
(gen-orderedmap gk gv)
An OrderedMap, made from a gen-list of keys and values.
gk- The generator of the keys.
gv- The generator of the values.
- returns
- The generator. The empty map is the simplest.
When the list has a key more than once, the last value wins.
See also: gen-map-of, gen-list
gen-orderedset
function ↑ Functions
(: gen-orderedset (-> (Gen %a) (Gen (OrderedSet %a))))
(gen-orderedset g)
An OrderedSet, made from a gen-list of its elements.
g- The generator of the elements.
- returns
- The generator. The empty set is the simplest.
See also: gen-hashset, gen-list
arbitrary
function ↑ Functions
(: arbitrary (-> (Gen %a)))
The generator of a type. The type of the result chooses the instance.
- returns
- The generator of the instance for that type.
(def (: g (Gen (List int))) (arbitrary))
(def (: cards (List Card)) (gen-samples (arbitrary) 10))
It takes no arguments. Write the type where the result goes, for
example with (def (: name Type) ...).
See also: Arbitrary
Values
gen-bool
value ↑ Values
(: gen-bool (Gen bool))
#t or #f, equally likely. #f is the simplest.
See also: gen-element
gen-int
value ↑ Values
(: gen-int (Gen int))
An int that grows with the size, with edge values now and then. 0 is the simplest.
A first draw chooses the kind of value:
- 8 times in 10, a value from -size² to size². So a size of 100 reaches 10000.
- 1 time in 10, any int.
- 1 time in 10, an edge: 0, 1, -1,
int-max,int-min, 255, 256 or 65535.
An edge is recorded as the draws for “any int” that give it. So shrinking changes the kind of an edge to “any int”, keeps the value, and can then make the value smaller.
See also: gen-int-range, gen-long
gen-long
value ↑ Values
(: gen-long (Gen long))
A long that grows with the size, with edge values now and then. 0 is the simplest.
As gen-int, but over the longs. The edges are 0, 1, -1,
long-max, long-min, int-max, int-min and
2³².
See also: gen-long-range, gen-int
gen-ulong
value ↑ Values
(: gen-ulong (Gen ulong))
A ulong that grows with the size, with edge values now and then. 0 is the simplest.
8 times in 10, a value from 0 to size². 1 time in 10, any ulong. 1
time in 10, an edge: 0, 1, the largest ulong, 2⁶³ or 2³². An edge is
recorded as the draws for “any ulong” that give it, as for
gen-int.
See also: gen-long
gen-bigint
value ↑ Values
(: gen-bigint (Gen bigint))
A bigint: usually a long, and sometimes a value beyond the range of a long. 0 is the simplest.
3 times in 4, a value of gen-long. 1 time in 4, that value
multiplied by a number from 0 to 2⁶⁴, so most such values are beyond
the range of a long.
See also: gen-long
gen-char
value ↑ Values
(: gen-char (Gen char))
Any Unicode scalar value, mostly printable ASCII, with characters that find bugs now and then. #\a is the simplest.
A first draw chooses the kind of character:
- 8 times in 10, a printable ASCII character, as
gen-ascii-charmakes. - 1 time in 10, a character that often finds bugs in text code: the NUL character, a combining acute accent, an emoji outside the BMP (two UTF-16 units), the Hebrew letter alef (right to left), the replacement character, a non-breaking space, the final sigma, or the capital I with a dot.
- 1 time in 10, any scalar value: 0 to 0x10FFFF, without the surrogates.
See also: gen-ascii-char, gen-string
gen-ascii-char
value ↑ Values
(: gen-ascii-char (Gen char))
A printable ASCII character, from space to ~. #\a is the simplest.
The 95 characters are put in an order that starts at #\a: the letters come before the digits and the punctuation. A case shrinks toward a letter, which is easy to read.
See also: gen-char, gen-ascii-string
gen-string
value ↑ Values
(: gen-string (Gen string))
A string of gen-char characters, whose length grows with the size. The empty string is the simplest.
The length is as for gen-list. Because of gen-char, it
sometimes has surrogate pairs, combining characters and other
characters that find bugs.
See also: gen-ascii-string, gen-string-of, gen-char
gen-ascii-string
value ↑ Values
(: gen-ascii-string (Gen string))
A string of printable ASCII characters, whose length grows with the size. The empty string is the simplest.
See also: gen-string, gen-ascii-char
Macros
gen-let
macro ↑ Macros
(gen-let ((name gen) ...) body ...)
A generator that draws each binding in order, as let* binds, and makes the value of the body.
name- The name of the value.
gen- The generator of the value. It can use the names of the bindings before it.
body ...- The forms that make the value from the names. At least one form.
(: gen-card (Gen Card))
(def gen-card
(gen-let ((rank (gen-int-range 1 13))
(suit (gen-element (list Hearts Spades Clubs Diamonds))))
(Card (rank rank) (suit suit))))
;; A later generator uses an earlier value.
(gen-let ((n (gen-int-range 0 10))
(xs (gen-list-of-length n gen-int)))
(Tuple n xs))
Gen is not a Monad, so (do ...) does not make
generators. gen-let is the way to draw values in order. All the
bindings draw from the same choices.