5. Properties
A predicate is just a boolean function over some type. A property
carries some additional data about preconditions and statistics.
 type 'a pred = 'a → bool
type 'a prop
val pred : 'a pred → 'a prop
val pred2 : ('a * 'b) pred → 'b → 'a prop

This function and operator are the same: they construct conditional
properties. Test cases that fail the precondition are not counted.
 val implies : 'a pred * 'a prop → 'a prop
val ==> : 'a pred * 'a pred → 'a prop

5.1 Statistical distribution
One problem with random testcase generation is that we don't know
for sure what we're getting. QCheck provides a way to observe the
distribution of test cases by tagging them based on userdefinable
criteria. For example, suppose we want to test the ListMergeSort
module in the SML/NJ library, by generating random integer lists.
If we generate and pass 100 cases, what does that mean? Sorting a list
with fewer than 2 elements is pretty easy, so how many of our 100 cases
are that trivial? Also, how many of the lists are already ordered? The
following functions are designed to help you answer such questions.
 val trivial : 'a pred → 'a prop → 'a prop
val classify : 'a pred → string → 'a prop → 'a prop
val classify' : ('a → string option) → 'a prop →
'a prop

Here are some examples of how they work.
 fun fewer_than n L = length L < n
val sort_ok = ListMergeSort.sorted op> o
ListMergeSort.sort op>
val sort_test = trivial (fewer_than 2)
(classify (ListMergeSort.sorted op>) "presorted"
(pred sort_ok))
checkGen (Gen.list (Gen.flip'(1,9)) Gen.Int.int, NONE)
("ListMergeSort", sort_test)

Now the test result, if passing, will be accompanied with some
statistics on the distribution of the specified properties.
 › ListMergeSort..........ok (100 passed) 33% presorted
› 28% trivial

The functions classify
and trivial
are specializations of
the more general classify'
(prime), with which we can provide a
function that returns the tag. To see the complete distribution of list
lengths, try this:
 fun sizeTag n =
"length "^ StringCvt.padLeft #" " 3 (Int.toString n)
val sort_test = classify' (SOME o sizeTag o length) (pred sort_ok)
checkGen (Gen.list (Gen.flip'(1,9)) Gen.Int.int, NONE)
("ListMergeSort", sort_test)
› ListMergeSort..........ok (100 passed) 13% length 0
› 7% length 1
› 6% length 2
› 13% length 3
› 8% length 4
› 6% length 5
› 3% length 6
› 2% length 7
› 5% length 8
› 5% length 9
› 2% length 10
› 5% length 11
› 3% length 12

The list goes on: the maximum length list generated in this run was
43.
5.2 Results
 type result = bool option
type stats = { tags : StringBag.bag,
count : int }
val test : 'a prop → 'a * stats → result * stats
val stats : stats
val success : result pred
val failure : result pred

This document was generated by Chris League on April, 14 2008 using texi2html 1.78.