packages feed

fitspec-0.2.1: README.md

FitSpec
=======

FitSpec provides automated assistance in the task of refining test properties
for Haskell functions.  FitSpec tests mutant variations of functions under test
against a given property set, recording any surviving mutants that pass all
tests.  FitSpec then reports:

* *surviving mutants:*
  indicating incompleteness of properties,
  prompting the user to amend a property or to add a new one;
* *conjectures:*
  indicating redundancy in the property set,
  prompting the user to remove properties so to reduce the cost of testing.

Installing FitSpec
------------------

To install the latest FitSpec version from Hackage, just:

    $ cabal install fitspec

Pre-requisites are [cmdargs], [pretty] and [leancheck].
They should be automatically resolved and installed by [Cabal].


Using FitSpec
-------------

As an example, consider the following properties describing a `sort` function:

    prop_ordered xs = ordered (sort xs)
    prop_length xs = length (sort xs) == length xs
    prop_elem x xs = elem x (sort xs) == elem x xs
    prop_notElem x xs = notElem x (sort xs) == notElem x xs
    prop_min x xs = head (sort (x:xs)) == minimum (x:xs)

We provide the above properties to FitSpec in the following program:

    import FitSpec
    import Data.List

    properties sort =
      [ property $ \xs -> ordered (sort xs)
      , property $ \xs -> length (sort xs) == length xs
      , property $ \x xs -> elem x (sort xs) == elem x xs
      , property $ \x xs -> notElem x (sort xs) == notElem x xs
      , property $ \x xs -> head (sort (x:xs)) == minimum (x:xs)
      ]
      where
      ordered (x:y:xs) = x <= y && ordered (y:xs)
      ordered _        = True

    main = mainWith args { names = ["sort xs"]
                         , nMutants = 4000
                         , nTests = 4000
                         , timeout = 0
                         }
                    (sort::[Word2]->[Word2])
                    properties

The above program reports, after a few seconds, that our property set is
apparently *neither minimal nor complete*.

    $ ./fitspec-sort
    Apparent incomplete and non-minimal specification based on
    4000 test cases for each of properties 1, 2, 3, 4 and 5
    for each of 4000 mutant variations.

    3 survivors (99% killed), smallest:
      \xs -> case xs of
               [0,0,1] -> [0,1,1]
               _ -> sort xs

    apparent minimal property subsets:  {1,2,3} {1,2,4}
    conjectures:  {3}    =  {4}     96% killed (weak)
                  {1,3} ==> {5}     98% killed (weak)

*Completeness:* Of 4000 mutants, 3 survive testing against our 5 properties.
The surviving mutant is clearly not a valid implementation of `sort`, but
indeed satisfies those properties.  As a specification, the property set is
*incomplete* as it omits to require that sorting preserves the number of
occurrences of each element value: `\x xs -> count x (sort xs) == count x xs`

*Minimality:*
So far as testing has revealed, properties 3 and 4 are equivalent and property
5 follows from 1 and 3 (conjectures).  It is *up to the user* to check whether
these conjectures are true.  Indeed they are, so in future testing we could
safely omit properties 4 and 5.

*Refinement:* If we omit redundant properties, and add a property to kill the
surviving mutant, our refined properties are:

    properties sort =
      [ \xs ->   ordered (sort xs)
      , \xs ->    length (sort xs) == length xs
      , \x xs ->  elem x (sort xs) == elem x xs
      , \x xs -> count x (sort xs) == count x xs
      ]

(The implementation of `count` is left as an exercise to the reader.)

FitSpec now reports:

    Apparent complete but non-minimal specification based on
    4000 test cases for each of properties 1, 2, 3 and 4
    for each of 4000 mutant variations.

    0 survivors (100% killed).

    apparent minimal property subsets:  {1,4}
    conjectures:  {4} ==> {2,3}     99% killed (weak)

As reported, properties 2 and 3 are implied by property 4, since that is true,
we can safely remove properties 2 and 3 to arrive at a minimal and complete
propety set.


### User-defined datatypes

If you want to use FitSpec to analyse functions over user-defined datatypes,
those datatypes should be made instances of the [Listable], [Mutable] and
[ShowMutable] typeclasses.  Check the Haddock documentation of each class for
how to define instances manually.  If datatypes do not follow a data invariant,
instances can be automatically derived using [TH] by:

    deriveMutable ''DataType


More documentation
------------------

For more examples, see the [eg](eg) and [bench](bench) folders.

For further documentation, consult the [doc](doc) folder and [FitSpec API]
documentation on Hackage.

(TODO: link to a possible future FitSpec paper goes here)


[Listable]:    https://hackage.haskell.org/package/leancheck/docs/Test-LeanCheck.html#t:Listable
[Mutable]:     https://hackage.haskell.org/package/fitspec/docs/FitSpec.html#t:Mutable
[ShowMutable]: https://hackage.haskell.org/package/fitspec/docs/FitSpec.html#t:ShowMutable
[FitSpec API]: https://hackage.haskell.org/package/fitspec/docs/FitSpec.html

[leancheck]: https://hackage.haskell.org/package/leancheck
[cmdargs]:   https://hackage.haskell.org/package/cmdargs
[pretty]:    https://hackage.haskell.org/package/pretty

[TH]:    https://wiki.haskell.org/Template_Haskell
[Cabal]: https://www.haskell.org/cabal