Skip to content

Commit

Permalink
SmallCheck v0.4
Browse files Browse the repository at this point in the history
  • Loading branch information
UnkindPartition committed Nov 17, 2011
1 parent 25e3244 commit a0cc45f
Show file tree
Hide file tree
Showing 16 changed files with 606 additions and 177 deletions.
97 changes: 74 additions & 23 deletions README
@@ -1,7 +1,7 @@
---------------------------------------------------------------
SmallCheck: another lightweight testing library in Haskell.
Version 0.2, November 2006
Colin Runciman, University of York UK
Version 0.4, 21 May 2008
Colin Runciman, University of York, UK

After QuickCheck, by Koen Claessen and John Hughes (2000-2004).
---------------------------------------------------------------
Expand All @@ -14,7 +14,7 @@ you could:
* write properties using existentials as well as universals?
* establish complete coverage of a defined test-space?
* display counter-examples of functional type?
* guarantee repeatable test results?
* always repeat tests and obtain the same results?

If so, try SmallCheck! This note should be enough to get you started,
assuming some prior experience with QuickCheck.
Expand All @@ -35,8 +35,15 @@ values, depth means depth of construction. For functional values, it
is a measure combining the depth to which arguments may be evaluated
and the depth of possible results.

Generators
----------
QuickCheck's statistics-gathering operators have been omitted from
SmallCheck's property language, as they seem more relevant to the
random-testing approach.

Data Generators
---------------

SmallCheck itself defines data generators for all the data types used
by the Prelude.

Writing SmallCheck generators for application-specific types is
straightforward. Just as the QuickCheck user defines 'arbitrary'
Expand All @@ -62,20 +69,38 @@ instance Serial a => Serial (Light a) where

The depth of Light x is just the depth of x.

Function Generators
-------------------

To generate functions of an application-specific argument type requires a
second method 'coseries' -- cf. 'coarbitrary' in QuickCheck. Again there
is a standard pattern, this time using the alts<N> combinators where
again N is constructor arity. Here are Tree and Light instances:

coseries d = [ \t -> case t of
Null -> z
Fork t1 x t2 -> f t1 x t2
| z <- alts0 d ,
f <- alts3 d ]
coseries rs d = [ \t -> case t of
Null -> z
Fork t1 x t2 -> f t1 x t2
| z <- alts0 rs d ,
f <- alts3 rs d ]

coseries rs d = [ \l -> case l of
Light x -> f x
| f <- (alts1 rs . depth 0) d ]

(NB changed from Version 0.2: 'coseries' and 'alts<N>' family now take a
series argument -- here rs. In the coseries definitions we simply pass
on rs as series argument in each 'alts<N>' application.)

coseries d = [ \l -> case l of
Light x -> f x
| f <- (alts1 . depth 0) d ]
Automated Derivation of Generators
----------------------------------

For small examples, Series instances are easy enough to define by hand,
following the above patterns. But for programs with many or large data
type definitions, automatic derivation using a tool such as 'derive'
is a better option. For example, the following command-line appends to
Prog.hs the Series instances for all data types defined there.

$ derive Prog.hs -d Serial --append

Properties
----------
Expand All @@ -98,7 +123,7 @@ by the function that always returns True! We can test the same property
using SmallCheck. But we can also test the following property, which
involves an existentially quantified variable:

prop_isPrefix2 :: String -> String -> Bool
prop_isPrefix2 :: String -> String -> Property
prop_isPrefix2 xs ys = isPrefix xs ys ==>
exists $ \xs' -> ys == xs++xs'

Expand All @@ -122,9 +147,8 @@ Int->Int function:
prop_append2 :: [Bool] -> [Bool] -> Property
prop_append2 xs ys = existsDeeperBy (*2) $ \zs -> zs == xs++ys

QuickCheck's statistics-gathering operators have been omitted from
SmallCheck's property language, as they seem more relevant to the
random-testing approach.
There are also quantifiers for unique existence. Their names include
a 1 immediately after 'exists': eg. exists1, exists1DeeperBy.

Pragmatics of ==>
-----------------
Expand Down Expand Up @@ -200,6 +224,10 @@ Depth 0:
True
False

When (unique) existential properties are tested, any failure reports
conclude with "non-existence" (or "non-uniqueness" followed by two
witnesses).

Large Test Spaces
-----------------

Expand Down Expand Up @@ -235,23 +263,46 @@ The interactive variant is still available as 'smallCheckI'. All
Prelude numeric types now have Serial instances, including floating-point
types. Serial types Nat and Natural are also defined. Examples extended.

Version 0.3
-----------

Existential quantifiers now have unique variants for which two witnesses
are reported when uniqueness fails. The over-generating coseries method
for functions of functional arguments has been replaced; now 'coseries'
and the 'alts<N>' family take a series argument. Test counters are
now Integers, not Ints. Ord and Eq are now derived for the N types.
Examples extended.

Version 0.4
-----------

The module SmallCheck is now Test.SmallCheck. Packaged with Cabal.

Final Notes
-----------

The name is intended to acknowledge QuickCheck, not to suggest that
SmallCheck is a tool of equal refinement.
SmallCheck replaces it. See also Lazy SmallCheck. Each tool has its
advantages and disadvantages when compared with the others.

SmallCheck is a Haskell 98 module aside from the import of unsafePerformIO
for use in a single instance -- the import and instance can be commented
out if there is no need to test IO computations. I am not aware of any
other portability issues. SmallCheck can be obtained from:
other portability issues. SmallCheck can be obtained from

http://hackage.haskell.org/cgi-bin/hackage-scripts/package/smallcheck

or alternatively from

http://www.cs.york.ac.uk/fp/smallcheck0.2.tar
http://www.cs.york.ac.uk/fp/smallcheck0.4.tar

Comments and suggestions are welcome.

Thanks to Galois Connections, my hosts when I first wrote SmallCheck, and
to users who have mailed me with feedback.
Thanks to Galois Connections, my hosts when I first wrote SmallCheck,
to users who have mailed me with feedback, to Ralf Hinze who suggested
the better method for functional coseries, to Neil Mitchell for
automating the derivation of Serial instances, to Matt Naylor for
the circuit-design examples and to Gwern Branwen for Cabal packaging.

Colin.Runciman@cs.york.ac.uk
6 November 2006
23 May 2008
2 changes: 1 addition & 1 deletion Setup.hs
@@ -1,2 +1,2 @@
import Distribution.Simple
main = defaultMain
main = defaultMain

0 comments on commit a0cc45f

Please sign in to comment.