LeanCheck
=========
**The API is likely to change in the near future**
LeanCheck is a simple enumerative property-based testing library. It works by
producing *tiers* of test values, which are essentially (possibly infinite)
lists of finite lists of same-and-increasingly-sized values. It is similar to
[Feat] in that regard.
In this README, lines ending with `-- >` indicate expected return values.
Checking if properties are True
-------------------------------
To check if properties are True,
just use the function `holds :: Testable a => Int -> a -> Bool`.
It takes _two arguments_:
the _number of values_ to test
and a _property_ (function returning Bool),
then, it returns a boolean indicating whether the property holds.
See (ghci):
import Test.Check
import Data.List
holds 100 $ \xs -> sort (sort xs) == sort (xs::[Int]) -- > True
holds 100 $ \xs -> [] `union` xs == (xs::[Int]) -- > False
Finding counter examples
------------------------
To find counter examples to properties,
you can use the function `counterExample :: Testable a => Int -> a -> Maybe [String]`.
It takes _two arguments_:
the _number of values_ to test
and a _property_ (function returning Bool).
Then, it returns Nothing if no results are found or Just a list of Strings
representing the offending arguments to the property.
See (ghci):
import Test.Check
import Data.List
counterExample 100 $ \xs -> sort (sort xs) == sort (xs::[Int])
-- > Nothing
counterExample 100 $ \xs -> [] `union` xs == (xs::[Int])
-- > Just ["[0,0]"]
counterExample 100 $ \xs ys -> xs `union` ys == ys `union` (xs::[Int])
-- > Just ["[]","[0,0]"]
Checking properties like in SmallCheck/QuickCheck
-------------------------------------------------
To "check" properties like in [SmallCheck] and [QuickCheck]
automatically printing results on standard output,
you can use the function `check :: Testable a => a -> IO ()`.
import Test.Check
import Data.List
check $ \xs -> sort (sort xs) == sort (xs::[Int])
-- > OK, passed 200 tests.
check $ \xs ys -> xs `union` ys == ys `union` (xs::[Int])
-- > Failed! Falsifiable (after 4 tests):
-- > [] [0,0]
The function `check` tests for a maximum of 200 tests.
To check for a maximum of `n` tests, use `checkFor n`.
To get a boolean result wrapped in `IO`, use `checkResult` or `checkResultFor`.
There is no "quiet" option, just use `holds` or `counterExample` in that case.
Testing for custom types
------------------------
LeanCheck works on properties with `Listable` argument types.
Custom `Listable` instances are created similarly to SmallCheck:
data MyType = MyConsA
| MyConsB Int
| MyConsC Int Char
| MyConsD String
instance Listable MyType where
tiers = cons0 MyConsA
\/ cons1 MyConsB
\/ cons2 MyConsC
\/ cons1 MyConsD
The tiers function return a potentially infinite list of finite sub-lists (tiers).
Each tier has values of increasing size.
tiers :: Listable a => [[a]]
For convenience, there is also the function `list`,
which returns an infinite list of values of the bound type:
list :: Listable a => [a]
So, for example:
take 5 (list :: [(Int,Int)]) -- > [(0,0),(0,1),(1,0),(0,-1),(1,1)]
The `list` function can be used to debug your custom instances.
More information / extra functions
----------------------------------
`Listable` class instances are more customizable than what is described here:
check source comments or haddock documentation for details.
Building / Installing
---------------------
To build:
$ cabal build
To install:
$ cabal install
To reference in a cabal sandbox:
$ cabal sandbox add-source ../path/to/leancheck
To use the files directly in your project:
$ cp -r Test ../path/to/your-project
LeanCheck was tested on GHC 7.10, GHC 7.8, GHC 7.6 and GHC 7.4.
This library does not use any fancy extensions:
if it does not work on previous GHC versions,
probably only *minor* changes are needed.
It optionally depends on Template Haskell
(for automatic derivation of Listable instances).
[Feat]: https://hackage.haskell.org/package/testing-feat
[SmallCheck]: https://hackage.haskell.org/package/smallcheck
[QuickCheck]: https://hackage.haskell.org/package/QuickCheck