fasttest.plt : FastTest Random Test Case Generation
_fasttest.plt : FastTest Random Test Case Generation_
Written by: Carl Eastlund and Carter Schonwald
Bug reports: Send to Carl Eastlund '(cce @ ccs . neu . edu)
Keywords: _quickcheck_ _randomized_ _testing_
This software is distributed under a BSD-style license (see license.txt).
================================================================================
FastTest is a library for random generation of test cases for unit testing. It
was inspired by the QuickCheck library for Haskell [1]. It includes two
libraries:
random.ss : Randomized generators for sets of data.
schemeunit.ss : SchemeUnit integration for testing based on generators.
[1] http://www.cs.chalmers.se/~rjmh/QuickCheck/
================================================================================
_random.ss : Random data generation_
This module provides tools for constructing random distributions of data. It
introduces one new type: (Generator T), representing a random generator that
produces values of type T. Any non-generator value may be used as a constant
generator which always produces that value.
The functions and macros provided by random.ss are described below. Examples
show valid expressions followed by representative values they may produce. Most
functions have two varieties: random-X, which provides a generator for some X,
and choose-X, which immediately generates an X.
In general, (choose-X ARG ...) = (generate (random-X ARG ...)).
--------------------
> (generator? v) : Boolean
v : Any
Reports whether v is an explicit generator (a generator constructed with the
functions in this module).
Remember that non-generator values may be used as constant generators. The
function nonrandom can be used to convert these to explicit generators.
Example: (generator? 'value) ;; #f
Example: (generator? (nonrandom 'value)) ;; #t
Example: (generator? (random-symbol)) ;; #t
--------------------
> (generate gen) : T
gen : (Generator T)
Constructs a random value from the given generator.
Example: (generate 'value) ;; 'value
Example: (generate (nonrandom 'value)) ;; 'value
Example: (generate (random-symbol)) ;; 'x, 'y
--------------------
> (nonrandom v) : (Generator v)
v : Any
Generates the given value deterministically.
Example: (generate (nonrandom 'value)) ;; 'value
--------------------
> (random-int-between i j) : (Generator Nat)
> (choose-int-between i j) : Nat
i : Integer
j : Integer
Generates a random integer chosen uniformly between i and j, inclusive.
(choose-int-between i j) = (generate (random-int-between i j))
Example: (choose-int-between 1 10) ;; 7, 3, 10, 9, 1, 8
--------------------
> (random-size [minimum average]) : (Generator Nat)
> (choose-size [minimum average]) : Nat
minimum [= 0] : Nat
average [= 4] : Positive-Int
Generates potentially unbounded, but usually small, natural numbers, often
useful for determining the size of other random data.
Produces a geometric distribution with expectation (+ minimum average). The
odds of producing each value (+ minimum k) for non-negative integer k are:
(* (expt (/ average (+ average 1)) k) (/ 1 (+ average 1)))
(choose-size minimum average) = (generate (random-size minimum average))
Example: (choose-size) ;; 0, 7, 1, 5, 13, 0
Example: (choose-size 10 2) ;; 12, 10, 14, 11
--------------------
> (random-boolean [prob]) : (Generator Boolean)
> (choose-boolean [prob]) : Boolean
prob [= 1/2] : Real-in[0,1]
Generates booleans, choosing #t with the given probability and #f otherwise.
Defaults to fair choice.
(choose-boolean prob) = (generate (random-boolean prob))
Example: (choose-boolean) ;; #t, #f
Example: (choose-boolean 1/4) ;; #f, #t, #f, #f
--------------------
> (random-char [code-gen]) : (Generator Char)
> (choose-char [code-gen]) : Char
code-gen [= (random-int-between 32 126)] : (Generator Nat)
Generates characters whose code is chosen from code-gen.
(choose-char code-gen) = (generate (random-char code-gen))
Example: (choose-char) ;; #\c, #\9, #\space, #\A
Example: (choose-char (random-int-between (char->integer #\A)
(char->integer #\Z)))
;; #\G, #\M, #\N, #\B
--------------------
> (random-group-of make elem-gen [len-gen]) : (Generator (Groupof T))
> (choose-group-of make elem-gen [len-gen]) : (Groupof T)
make : T ... -> (Groupof T)
elem-gen : (Generator T)
len-gen [= (random-size)] : (Generator Nat)
Generates a random collection of elements. It chooses a number of elements from
len-gen, generates each from elem-gen, and passes them to the constructor make.
Example: (choose-group-of list (random-symbol)) ;; '(x), '(A b7 -g)
Example: (choose-group-of cons (random-boolean) (nonrandom 2))
;; '(#t . #t), '(#t . #f), '(#f . #t), '(#f . #f)
> (random-list-of elem-gen [len-gen]) : (Generator (Listof T))
> (choose-list-of elem-gen [len-gen]) : (Listof T)
> (random-vector-of elem-gen [len-gen]) : (Generator (Vectorof T))
> (choose-vector-of elem-gen [len-gen]) : (Vectorof T)
> (random-string [char-gen len-gen]) : (Generator String)
> (choose-string [char-gen len-gen]) : String
> (random-bytes [byte-gen len-gen]) : (Generator Bytes)
> (choose-bytes [byte-gen len-gen]) : Bytes
elem-gen : (Generator T)
char-gen [= (random-char)] : (Generator Char)
byte-gen [= (random-int-between 0 255)] : (Generator Byte)
len-gen [= (random-size)] : (Generator Nat)
Generators for lists, vectors, strings, and byte strings, equivalent to
random-group-of or choose-group-of with the added first argument of list,
vector, string, or bytes, respectively.
--------------------
> (random-apply f gen ...) : (Generator B)
> (choose-apply f gen ...) : B
f : A ... -> B
gen ... : (Generator A) ...
Generates the result of applying f to random inputs chosen from each gen.
Example: (choose-apply cons (random-char) (random-string))
;; '(#\c . "+8Y")
> (random-list gen ...) : (Generator (list T ...))
> (random-vector gen ...) : (Generator (vector T ...))
gen : (Generator T) ...
Generators for random heterogenous lists and vectors, equivalent to random-apply
with the added first argument of list or vector, respectively.
--------------------
> (random-symbol [name-gen]) : (Generator Symbol)
> (choose-symbol [name-gen]) : Symbol
name-gen [= (random-string)] : (Generator String)
Generates random interned symbols whose names are chosen from name-gen.
Equivalent to (random-apply string->symbol name-gen).
Example: (choose-symbol) ;; 'x, '|0A-|, 'fY, '@
Example: (choose-symbol (nonrandom "value")) ;; 'value
--------------------
> (random-uniform gen1 ... genK) : (Generator (Or T1 ... TK))
> (choose-uniform gen1 ... genK) : (Or T1 ... TK)
gen1 ... genK : (Generator T1) ... (Generator TK)
Generates a value from a fairly chosen generator out of gen1 ... genK.
Example: (choose-uniform 'bat 'cat 'dog) ;; 'bat, 'cat, 'dog
--------------------
> (random-weighted weight1 gen1 ... weightK genK) : (Generator (Or T1 ... TK))
> (choose-weighted weight1 gen1 ... weightK genK) : (Or T1 ... TK)
weight1 ... weightK : Positive-Rational
gen1 ... genK : (Generator T1) ... (Generator TK)
> (random-weighted* pair1 ... pairK) : (Generator (Or T1 ... TK))
> (choose-weighted* pair1 ... pairK) : (Or T1 ... TK)
pair1 ... pairK = (cons weight1 gen1) ... (cons weight1 genK)
Generates a value from a generator chosen with the associated weight.
Example: (choose-weighted 1 'bat 2 'cat 3 'dog) ;; 'cat, 'dog, 'bat, 'cat, 'dog
(choose-weighted* '((1 . bat) (2 . cat) (3 . dog))) ;; as above
--------------------
> (random-recursive rec-gen [weight1 gen1] ... [weightK genK]) : (Generator T)
> (choose-recursive rec-gen [weight1 gen1] ... [weightK genK]) : T
weight1 ... weightK : Positive-Rational
gen1 ... genK : (Generator T)
This macro creates a generator for a recursive data structure whose clauses are
generated by gen1 ... genK with respective probabilities prob1 ... probK; the
recursive generator is in scope for gen1 ... genK under the name rec-gen.
(choose-recursive r [w g] ...) = (generate (random-recursive r [w g] ...))
Example:
(define-struct leaf () #f)
(define-struct node (left right) #f)
(choose-recursive tree-gen
[2 (nonrandom (make-leaf))]
[1 (random-apply make-node tree-gen tree-gen)])
;; Possible results:
;; (make-leaf),
;; (make-node (make-leaf) (make-leaf)),
;; (make-node (make-node (make-leaf) (make-leaf)) (make-leaf))
--------------------
> (random-function f) : (Generator (A ... -> B))
> (choose-function f) : A ... -> B
f : A ... -> (Generator B)
Generates a function that produces random outputs. For each set of inputs, the
resulting function will get the corresponding generator from f and produce a
value from it. The function will memoize these values to produce consistent
results for any specific set of inputs.
Examples:
(define f
(generate
(random-function
(lambda (n)
(random-list-of (random-boolean) (nonrandom n))))))
;; Notice how (f 5) always produces the same list of 5 booleans:
(f 5) ;; '(#f #f #t #f #t)
(f 2) ;; '(#t #t)
(f 5) ;; '(#f #f #t #f #t)
(f 3) ;; '(#t #f #t)
(f 5) ;; '(#f #f #t #f #t)
================================================================================
_schemeunit.ss : Randomized SchemeUnit testing_
--------------------
> (test-randomly name count ((var gen) ...) body ...) : Test-Suite
name :: (Literal String)
count :: (Literal Nat)
var :: Identifier
gen :: Expression
body :: Expression
Generates a test suite containing count tests, each of which is annotated with
the index of the test and the randomly chosen values, but is otherwise
equivalent to:
(test-case name
(let* ((var (generate gen)) ...)
body ...))
Example:
(test-randomly "list-ref produces a member" 100
([the-list (random-list-of (random-symbol) (random-size 1))]
[the-in dex (random-int-between 0 (- (length the-list) 1))])
(check memq (list-ref the-list the-index) the-list))