doc.txt

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))