Test.SmallCheck

smallcheck-1.1.1: A property-based testing library

Copyright | (c) Colin Runciman et al.
License | BSD3
Maintainer | Roman Cheplyaka <roma@ro-che.info>
Safe Haskell | Safe
Language | Haskell98

Test.SmallCheck

Contents

- Constructing tests
  - Examples
- Running tests
- Main types and classes

Description

This module exports the main pieces of SmallCheck functionality.

To generate test cases for your own types, refer to Test.SmallCheck.Series.

For pointers to other sources of information about SmallCheck, please refer to the README at https://github.com/feuerbach/smallcheck/blob/master/README.md

Synopsis

- forAll :: Testable m a => a -> Property m
- exists :: Testable m a => a -> Property m
- existsUnique :: Testable m a => a -> Property m
- over :: (Show a, Testable m b) => Series m a -> (a -> b) -> Property m
- monadic :: Testable m a => m a -> Property m
- (==>) :: (Testable m c, Testable m a) => c -> a -> Property m
- changeDepth :: Testable m a => (Depth -> Depth) -> a -> Property m
- changeDepth1 :: (Show a, Serial m a, Testable m b) => (Depth -> Depth) -> (a -> b) -> Property m
- type Depth = Int
- smallCheck :: Testable IO a => Depth -> a -> IO ()
- class Monad m => Testable m a
- data Property m
- type Reason = String

# Constructing tests

The simplest kind of test is a function (possibly of many arguments) returning `Bool`. The function arguments are interpreted as being universally, existentially or uniquely quantified, depending on the quantification context.

The default quantification context is universal (`forAll`).

`forAll`, `exists` and `existsUnique` functions set the quantification context for function arguments. Depending on the quantification context, the test `\x y -> p x y` may be equivalent to:

- ∀ x, y. p x y (`forAll`)
- ∃ x, y: p x y (`exists`)
- ∃! x, y: p x y (`existsUnique`)

The quantification context affects all the variables immediately following the quantification operator, also extending past `over`, `changeDepth` and `changeDepth1` functions.

However, it doesn't extend past other functions, like `monadic`, and doesn't affect the operands of `==>`. Such functions start a fresh default quantification context.

## Examples

- `\x y -> p x y` means ∀ x, y. p x y
- ``exists` $ \x y -> p x y` means ∃ x, y: p x y
- ``exists` $ \x -> `forAll` $ \y -> p x y` means ∃ x: ∀ y. p x y
- ``existsUnique` $ \x y -> p x y` means ∃! (x, y): p x y
- ``existsUnique` $ \x -> `over` s $ \y -> p x y` means ∃! (x, y): y ∈ s && p x y
- ``existsUnique` $ \x -> `monadic` $ \y -> p x y` means ∃! x: ∀ y. [p x y]
- ``existsUnique` $ \x -> `existsUnique` $ \y -> p x y` means ∃! x: ∃! y: p x y
- ``exists` $ \x -> (\y -> p y) `==>` (\z -> q z)` means ∃ x: (∀ y. p y) => (∀ z. p z)

forAll :: Testable m a => a -> Property m #

Set the universal quantification context

exists :: Testable m a => a -> Property m #

Set the existential quantification context

existsUnique :: Testable m a => a -> Property m #

Set the uniqueness quantification context.

Bear in mind that ∃! (x, y): p x y is not the same as ∃! x: ∃! y: p x y.

For example, ∃! x: ∃! y: |x| = |y| is true (it holds only when x=0), but ∃! (x,y): |x| = |y| is false (there are many such pairs).

As is customary in mathematics, ``existsUnique` $ \x y -> p x y` is equivalent to ``existsUnique` $ \(x,y) -> p x y` and not to ``existsUnique` $ \x -> `existsUnique` $ \y -> p x y` (the latter, of course, may be explicitly written when desired).

That is, all the variables affected by the same uniqueness context are quantified simultaneously as a tuple.

over :: (Show a, Testable m b) => Series m a -> (a -> b) -> Property m #

``over` s $ \x -> p x` makes `x` range over the `Series` `s` (by default, all variables range over the `series` for their types).

Note that, unlike the quantification operators, this affects only the variable following the operator and not subsequent variables.

`over` does not affect the quantification context.

monadic :: Testable m a => m a -> Property m #

Execute a monadic test

(==>) :: (Testable m c, Testable m a) => c -> a -> Property m infixr 0 #

The `==>` operator can be used to express a restricting condition under which a property should hold. It corresponds to implication in the classical logic.

Note that `==>` resets the quantification context for its operands to the default (universal).

changeDepth :: Testable m a => (Depth -> Depth) -> a -> Property m #

Run property with a modified depth. Affects all quantified variables in the property.

changeDepth1 :: (Show a, Serial m a, Testable m b) => (Depth -> Depth) -> (a -> b) -> Property m #

Quantify the function's argument over its `series`, but adjust the depth. This doesn't affect any subsequent variables.

# Running tests

`smallCheck` is a simple way to run a test.

As an alternative, consider using a testing framework.

The packages http://hackage.haskell.org/package/tasty-smallcheck and http://hackage.haskell.org/package/hspec-smallcheck provide integration with Tasty and HSpec, two popular testing frameworks.

They allow to organize SmallCheck properties into a test suite (possibly together with HUnit or QuickCheck tests) and provide other useful features.

For more ways to run the tests, see Test.SmallCheck.Drivers.

type Depth = Int #

Maximum depth of generated test values.

For data values, it is the depth of nested constructor applications.

For functional values, it is both the depth of nested case analysis and the depth of results.

smallCheck :: Testable IO a => Depth -> a -> IO () #

A simple driver that runs the test in the `IO` monad and prints the results.

# Main types and classes

class Monad m => Testable m a #

Class of tests that can be run in a monad. For pure tests, it is recommended to keep their types polymorphic in `m` rather than specialising it to `Identity`.

Minimal complete definition

test

Instances

Monad m => Testable m Bool # |
Methods test :: Bool -> Property m #
(Monad m, (~) (* -> *) m n) => Testable n (Property m) # |
Methods test :: Property m -> Property n #
(Serial m a, Show a, Testable m b) => Testable m (a -> b) # |
Methods test :: (a -> b) -> Property m #
Monad m => Testable m (Either Reason Reason) # | Works like the `Bool` instance, but includes an explanation of the result. `Left` and `Right` correspond to test failure and success respectively.
Methods test :: Either Reason Reason -> Property m #

data Property m #

The type of properties over the monad `m`

Instances

(Monad m, (~) (* -> *) m n) => Testable n (Property m) # |
Methods test :: Property m -> Property n #

type Reason = String #

An explanation for the test outcome