fasttest.plt : FastTest Random Test Case Generation
_fasttest.plt : FastTest Random Test Case Generation_
Written by: Carl Eastlund (cce at ccs dot neu dot edu)
and: Carter Schonwald (carter dot schonwald at yale dot edu)
Keywords: _quickcheck_ _randomized_ _testing_
================================================================================
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 support for randomized generation of values based on
user-defined distributions. It provides one new type, described immediately
below, and the values and macros which follow:
A (Generator T) is a source of random values of type T.
--------------------
> (generator? v) : Boolean
v : Any
Reports whether v is a generator.
--------------------
> (generate gen) : T
gen : (Generator T)
Constructs a random value from the given generator.
--------------------
> (nonrandom v) : (Generator v)
v : Any
Generates the given value deterministically.
Example: (generate (nonrandom 'value)) ;; 'value
--------------------
> (random-int-between i j) : (Generator Nat)
i : Integer
j : Integer
Generates a random integer chosen uniformly between i and j, inclusive.
Example: (generate (random-int-between 1 10)) ;; 7, 3, 10, 9, 1, 8
--------------------
> (random-size [min]) : (Generator Nat)
min [= 0] : Nat
Generates potentially unbounded, but usually small, natural numbers, often
useful for determining the size of other random data.
Produces min+k for some natural number k; the chance of k being 0 is 1/4, of 1
is 1/4, and for any larger integer i is 1/2^i.
Example: (generate (random-size)) ;; 1, 3, 2, 0, 4, 2, 0, 1
--------------------
> random-boolean : (Generator Boolean)
Generates fairly-chosen booleans.
Example: (generate random-boolean) ;; #t, #f
--------------------
> (random-char [code-gen]) : (Generator Char)
code-gen [= (random-int-between 32 127)] : (Generator Nat)
Generates characters whose code is chosen from code-gen.
Example: (generate (random-char)) ;; #\c, #\9, #\space, #\A
--------------------
> (random-uniform make elem-gen [len-gen]) : (Generator (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: (random-uniform list* (random-symbol)) ;; 'x, '(A b7 . -g)
> (random-list-of elem-gen [len-gen]) : (Generator (Listof T))
> (random-vector-of elem-gen [len-gen]) : (Generator (Vectorof T))
> (random-string [char-gen len-gen]) : (Generator String)
> (random-bytes [byte-gen len-gen]) : (Generator 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-uniform with the added first argument of list, vector, string, or bytes,
respectively.
--------------------
> (random-apply f gen ...) : (Generator B)
f : A ... -> B
gen ... : (Generator A) ...
Generates the result of applying f to random inputs chosen from each gen.
Example: (generate (random-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)
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: (generate (random-symbol)) ;; 'x, '|0A-|, 'fY, '@
--------------------
> (random-choice gen1 ... genK) : (Generator (Union T1 ... TK))
gen1 ... genK : (Generator T1) ... (Generator TK)
Generates a value from a fairly chosen generator out of gen1 ... genK.
Example: (generate (random-choice (nonrandom 'A) (nonrandom 'B))) ;; 'A, 'B
--------------------
> (random-weighted prob1 gen1 ... probK genK) : (Generator (Union T1 ... TK))
prob1 ... probK : Positive-Rational
gen1 ... genK : (Generator T1) ... (Generator TK)
Generates a value from a generator chosen with the associated weight.
Example: (generate (random-weighted 1 (nonrandom 'A)
3 (nonrandom 'B))) ;; 'B, 'A, 'B, 'B
--------------------
> (random-recursive rec-gen [prob1 gen1] ... [probK genK]) : (Generator T)
prob1 ... probK : 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.
Example:
(define-struct leaf (data))
(define-struct node (left right))
(random-recursive tree-gen
[1 (nonrandom (make-leaf))]
[4 (random-apply make-node tree-gen tree-gen)])
--------------------
> (random-function f) : (Generator (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 (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))]
[the-index (random-int-between 0 (- (length the-list) 1))])
(check-not-false
(member (list-ref the-list the-index) the-list)))