# Announcing SmallCheck 1.0

Published on

I am glad to announce a new major release of SmallCheck (hackage).

## What is SmallCheck?

SmallCheck is a property-based testing library for Haskell.

If you are familiar with QuickCheck, you can think of SmallCheck as a better QuickCheck. The main way in which it is better is that it is non-random: whether your tests pass does not depend on the roll of the dice.

If you are not familiar with QuickCheck, the idea of SmallCheck is to
check certain *properties* of your functions, as opposed to unit
testing, where you just check the expected outcome of some particular
tests.

For an introduction to property-based testing, check out Chapter 11 of Real World Haskell. It should be straightforward to translate all the examples there to SmallCheck.

## What’s new in 1.0

### Monadic properties

Properties are now parameterised on the monad they work in.

The two main ways a property can use the monad are:

- generating test cases monadically
- verifying the condition monadically

Monadic test cases generation can be used to read test cases from files. A well-known problem when testing compilers is that it is hard to enumerate or randomly generate valid programs. So here you go — just put some examples in the file system, and use them to verify some properties of your compiler.

An example of monadic verification is when you want to verify your code against an external (or otherwise impure) reference implementation.

### Quantifiers

The semantics of quantifiers has changed. Previously, all variables
were quantified universally by default, and a quantifier (like
`exists`

) changed the quantification of the next
variable.

So, for example, `exists $ \x y -> p x y`

was
interpreted as \(\exists x: \forall y. p\ x\
y\), which is probably not what one would expect.

Now the quantification operators (`forAll`

,
`exists`

and `existsUnique`

) set the
quantification context for all subsequent variables, so the above
property means \(\exists x, y: p\ x\
y\).

#### Uniqueness quantification

There’s an interesting effect related to the uniqueness quantifier
`existsUnique`

(which was previously called
`exists1`

).

There are two ways to interpret
`existsUnique $ \x y -> p x y`

, “curried” and
“uncurried”:

- \(\exists ! x: \exists ! y: p\ x\ y\)
- \(\exists ! (x,y): p\ x\ y\)

These two actually have different meaning. Suppose that \(p\ x\ y=(|x|=|y|)\), where \(|x|\) denotes the absolute value of an integer \(x\). Then the first property above is true, and the second is false (be sure to check this yourself).

When mathematicians write \(\exists ! x,y:p\ x\ y\), they really mean the second interpretation, so this is what SmallCheck implements (although the first interpretation would be much easier to implement).

### Higher-order properties

Both SmallCheck and QuickCheck have a `==>`

operator,
which tests an implication. The left argument of `==>`

has
type `Bool`

, and it’s usually a statement that the generated
arguments satisfy some side condition (e.g. generated programs are
valid).

In this new version of SmallCheck, the left argument of
`==>`

can be an arbitrary property, with its own
quantifiers etc. Here’s how we could test an `isPrime`

function:

```
import Test.SmallCheck
import Test.SmallCheck.Series
isPrime :: Integer -> Bool
= True
isPrime _
=
main 5 {- 5 is the testing depth -} $
smallCheck Positive n) ->
\($ \(Positive d) -> d /= 1 && d /= n && n `mod` d == 0) ==> not (isPrime n) (exists
```

Unsurprisingly, the result will be

```
Failed test no. 4.
there exists 4 such that
condition is false
```

### Ordered testing

SmallCheck has just got more efficient and less annoying!

Previously, if you wanted to get the *minimal* counterexample,
you used the function `smallCheck`

which tested the property
first with depth 0, then with depth 1 and so on — up to the limit that
you told it.

The reason was that the `Serial`

instance of
e.g. `Integer`

generated the following integers for depth
`3`

:

`[-3,-2,-1,0,1,2,3]`

They are tried in exactly this order, and, if all of them were
counterexamples, the user would be presented with `-3`

as the
first one.

Now the instances generate examples in the order of increasing depth, e.g.

`[0,1,-1,2,-2,3,-3]`

so there’s no need to try multiple depths.

### Better reporting

The way SmallCheck reports its findings is now greatly improved, especially in some complex cases.

For example, consider the following property:

`5 $ existsUnique $ \x -> (forAll $ \y -> x * y >= 0) ==> (forAll $ \y -> x * y == (0 :: Integer)) smallCheck `

Here’s what SmallCheck 0.6.2 reports (or, to be precise,
*would* report if it supported higher-order properties):

```
Depth 0:
Completed 1 test(s) without failure.
Depth 1:
Failed test no. 12. Test values follow.
non-uniqueness
-1
0
```

And this is the output of SmallCheck 1.0:

```
Failed test no. 12.
there are at least two arguments satisfying the property:
for 0
condition is true
for 1
property is vacuously true because
there exists -1 such that
condition is false
```

### Required type annotations

Because the `Testable`

class is now multi-parameter
(parameterised on the type and the monad), ambiguous types that involve
this class do not get defaulted. To put it simply, most non-trivial
properties now require some type annotations.

This turned out to be a very good thing for SmallCheck (which I couldn’t envision). Defaulting for properties often works in an unexpected way. For example, here’s what an older SmallCheck would tell you if you asked it whether all things are the equal:

```
> depthCheck 5 $ \x y -> x == y
Depth 5:
Completed 1 test(s) without failure.
```

The result is unexpected, but at least we get some clue from the fact
that there was just one test: the type of the variables got defaulted to
`()`

!

Alas, QuickCheck doesn’t give us even this hint:

```
> quickCheck $ \x y -> x == y
+++ OK, passed 100 tests.
```

Luckily, with the new SmallCheck you actually get a type error:

```
<interactive>:10:26:
No instance for (Eq a0) arising from a use of `=='
The type variable `a0' is ambiguous
Possible fix: add a type signature that fixes these type variable(s)
```

And indeed, the problem is easy to fix once you know it’s there:

```
> smallCheck 5 $ \x y -> x == (y :: Integer)
Failed test no. 2.
there exist 0 1 such that
condition is false
```

### Simpler interface

I took this chance to clean the API and make it more orthogonal.

Previously SmallCheck had functions like

`forAllElem :: (Show a, Testable b) => [a] -> (a -> b) -> Property`

which did three things at once:

- made the variable universally quantified
- converted the list to a depth-independent series
- quantified the variable over that series

No wonder the API suffered from the combinatorial explosion. Now these things are all done separately:

`generate :: (Depth -> [a]) -> Series m a`

can be used to turn a list into a series;

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

sets the domain of quantification; and

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

sets the quantification context.