quickcheck-property-comb: Combinators for Quickcheck Property construction and Property diagnostics

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.


This project aims to reduce the pain of composing invariants/properties, and the documenting of those invariants for determining the cause of failure. Additionally, it intends to provide effective diagnostics for invariants with changing post-conditions, leading to faster cause-of-failure diagnosis.

[Skip to ReadMe]


Change logNone available
Dependenciesbase (==4.5.*), mtl (==2.1.*), QuickCheck (==2.5.*) [details]
AuthorJohn Feltz
Home pagehttp://www.github.com/jfeltz/quickcheck-property-comb
UploadedMon Oct 14 23:48:21 UTC 2013 by jfeltz



Maintainers' corner

For package maintainers and hackage trustees

Readme for quickcheck-property-comb-

[back to package description]


This is collection of combinators built on the Reader and Writer Monads to allow for fast and painless Quickcheck property/invariant construction.


Quickcheck is a tool used to test cases based on constructed Properties,or essentially functions taking a data structure and returning a boolean True or False.

However when running tests, the only way to document their failing case is through is through labeling them after binding, e.g.:

inv1, inv2, inv3 :: Foo -> Bool 
fooInvariants :: Foo -> Property 
fooInvariants f = 
    conjoin . map property $ 
      conjoin $ zipWith toLabeled
        ["foo should be even", "foo should contain 3 bar", "all bar should not equal foo"] 
        [inv1 f, inv2 f, inv3 f]

This gets unwieldy fast as the complexity of the data-structure increases, so quickcheck-property-comb provides the following:

Example use

data (Ord l) => QuantityConsumers l =
  QuantityConsumers {
    atQuantity :: S.Set l,
    qcMet :: M.Map (S.Set l) Bool,
    qcDisjoints :: Disjoints l

disjoint_sizes ::  Inv (Disjoints l)
disjoint_sizes = do
  doc . unlines $
     "the intersection of all at quantity and disjoints are the only allowed",
     "singleton sets in disjoints"
  disjoints <- cause 
  -- Do some checking on disjoints 
  return False

disjoints_eq :: Inv (Disjoints l)
disjoints_eq = do
  doc "the solution state domain and sets formed by partition are equal"
  return False

disjoints :: Invariants (Disjoints l)
disjoints = do
  sat disjoints_eq
  sat disjoints_sizes

at_quantity_in_disjoint :: Inv (QuantityConsumers l)
at_quantity_in_disjoint = do
  doc "all at quantity are a singleton subset in disjoints"

  subsets       <- (map S.singleton) . S.toList . atQuantity <$> cause
  disjoint_sets <- fromDisjoints <$>  cause

  return . and . map ((flip S.member) disjoint_sets) $ subsets

inv_quantity_consumers :: Invariants (QuantityConsumers l)
inv_quantity_consumers = do
  satcomp qcDisjoints disjoints
  sat at_quantity_in_disjoint

-- Then to create the final property
prop_quantity_consumers :: QuantityConsumers l -> Property
prop_quantity_consumers q = runInvariants q inv_quantity_consumers