Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/rudymatela/extrapolate

generalize counter-examples of property-based testing
https://github.com/rudymatela/extrapolate

counter-example-generalization debugging enumerative-testing generalization haskell leancheck property-based-testing property-testing testing testing-tools

Last synced: about 2 months ago
JSON representation

generalize counter-examples of property-based testing

Awesome Lists containing this project

README

        

Extrapolate
===========

[![Extrapolate Build Status][build-status]][build-log]
[![Extrapolate on Hackage][hackage-version]][extrapolate-on-hackage]
[![Extrapolate on Stackage LTS][stackage-lts-badge]][extrapolate-on-stackage-lts]
[![Extrapolate on Stackage Nightly][stackage-nightly-badge]][extrapolate-on-stackage-nightly]

![Extrapolate logo][extrapolate-logo]

Extrapolate is a [property-based testing] library for [Haskell]
capable of reporting generalized counter-examples.

Installing Extrapolate
----------------------

To install the latest version of [Extrapolate from Hackage] using [cabal], just:

$ cabal update
$ cabal install extrapolate

To test if it installed correctly, follow through the next section.

Starting from Cabal v3, you need to pass `--lib` to `cabal install`:

$ cabal install extrapolate --lib

Using Extrapolate
-----------------

To use Extrapolate, you first import the [`Test.Extrapolate`] module,
then pass any properties you with to test to the function [`check`]:

$ ghci
> import Test.Extrapolate
> check $ \x y -> x + y == y + (x :: Int)
+++ OK, passed 360 tests.

> import Data.List (nub)
> check $ \xs -> nub xs == (xs :: [Int])
*** Failed! Falsifiable (after 3 tests):
[0,0]

Generalization:
x:x:_

The operator [`+`] is commutative. The function [`nub`] is not an identity.

### Configuring the number of tests

To increase the number of tests, use the [`for`] combinator:

$ ghci
> import Test.Extrapolate
> check `for` 1000 $ \x y -> x + y == y + (x :: Int)
+++ OK, passed 1000 tests.

### Customizing the background functions (allowed in side-conditions)

To customize the background functions, use the [`withBackground`] combinator:

$ ghci
> import Test.Extrapolate
> import Data.List (nub)
> let hasDups xs = nub xs /= (xs :: [Int])
> check `withBackground` [constant "hasDups" hasDups] $ \xs -> nub xs == (xs :: [Int])
*** Failed! Falsifiable (after 3 tests):
[0,0]

Generalization:
x:x:_

Conditional Generalization:
xs when hasDups xs

Perhaps the example above is silly (`hasDups` is the negation of the property
itself!), but it illustrates the use of [`withBackground`].

The combinators [`for`] and [`withBackground`] can be used in conjunction:

> check `for` 100 `withBackground` [...] $ property

Don't forget the dollar sign [`$`].

Another Example
---------------

Consider the following (faulty) sort function and a property about it:

sort :: Ord a => [a] -> [a]
sort [] = []
sort (x:xs) = sort (filter (< x) xs)
++ [x]
++ sort (filter (> x) xs)

prop_sortCount :: Ord a => a -> [a] -> Bool
prop_sortCount x xs = count x (sort xs) == count x xs
where
count x = length . filter (== x)

After testing the property, Extrapolate returns a fully defined counter-example
along with a generalization:

> import Test.Extrapolate
> check (prop_sortCount :: Int -> [Int] -> Bool)
*** Failed! Falsifiable (after 4 tests):
0 [0,0]

Generalization:
x (x:x:_)

This hopefully makes it easier to find the source of the bug. In this case,
the faulty sort function discards repeated elements.

Further reading
---------------

For more examples, see the [eg](eg) folder.
For type signatures, other options and uses,
see [Extrapolate's API documentation].

There are two other tools for [Haskell] capable of producing generalized
counter-examples: [SmartCheck] and [Lazy SmallCheck 2012].

Extrapolate was presented at [IFL 2017] and was subject to a paper titled
[Extrapolate: generalizing counterexamples of functional test properties](https://matela.com.br/extrapolate.pdf).
Extrapolate is also subject to a chapter in a [PhD Thesis (2017)].

[extrapolate-on-hackage]: https://hackage.haskell.org/package/extrapolate
[Extrapolate from Hackage]: https://hackage.haskell.org/package/extrapolate
[Extrapolate's API documentation]: https://hackage.haskell.org/package/extrapolate/docs/Test-Extrapolate.html
[`Test.Extrapolate`]: https://hackage.haskell.org/package/extrapolate/docs/Test-Extrapolate.html
[`check`]: https://hackage.haskell.org/package/extrapolate/docs/Test-Extrapolate.html#v:check
[`for`]: https://hackage.haskell.org/package/extrapolate/docs/Test-Extrapolate.html#v:for
[`withBackground`]: https://hackage.haskell.org/package/extrapolate/docs/Test-Extrapolate.html#v:withBackground
[`$`]: https://hackage.haskell.org/package/base-4.10.0.0/docs/Prelude.html#v:-36-
[`+`]: https://hackage.haskell.org/package/base/docs/Prelude.html#v:-43-
[`nub`]: https://hackage.haskell.org/package/base/docs/Data-List.html#v:nub
[Haskell]: https://www.haskell.org/
[cabal]: https://www.haskell.org/cabal/
[property-based testing]: https://github.com/rudymatela/leancheck/blob/master/doc/tutorial.md

[IFL 2017]: http://iflconference.org/
[SmartCheck]: https://github.com/leepike/SmartCheck
[Lazy SmallCheck 2012]: https://github.com/UoYCS-plasma/lazysmallcheck2012
[PhD Thesis (2017)]: https://matela.com.br/thesis-rudy.pdf

[extrapolate-logo]: https://github.com/rudymatela/extrapolate/raw/master/doc/extrapolate.svg?sanitize=true

[build-log]: https://github.com/rudymatela/extrapolate/actions/workflows/build.yml
[build-status]: https://github.com/rudymatela/extrapolate/actions/workflows/build.yml/badge.svg
[hackage-version]: https://img.shields.io/hackage/v/extrapolate.svg
[stackage-lts-badge]: https://stackage.org/package/extrapolate/badge/lts
[stackage-nightly-badge]: https://stackage.org/package/extrapolate/badge/nightly
[extrapolate-on-stackage]: https://stackage.org/package/extrapolate
[extrapolate-on-stackage-lts]: https://stackage.org/lts/package/extrapolate
[extrapolate-on-stackage-nightly]: https://stackage.org/nightly/package/extrapolate