packages feed

quickcheck-property-comb (empty) → 0.1.0.0

raw patch · 4 files changed

+152/−0 lines, 4 filesdep +QuickCheckdep +basedep +mtl

Dependencies added: QuickCheck, base, mtl

Files

+ LICENSE view
@@ -0,0 +1,1 @@+DWTFYWWI
+ README.md view
@@ -0,0 +1,82 @@+quickcheck-property-comb+--------+This is collection of combinators built on the Reader and Writer+Monads to allow for fast and painless Quickcheck property/invariant construction.++Why?+----+[Quickcheck](http://hackage.haskell.org/package/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.: ++```haskell+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:+  - A clean separation of composition of invariants and the creation +    and documenting of those invariants for determining cause of failure.+  - Effective diagnostics for invariants with changing post-conditions,+    leading to <b>faster cause-of-failure diagnosis</b>.++Example use+-----------+```haskell+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+```
+ Test/QuickCheck/Property/Comb.hs view
@@ -0,0 +1,41 @@+-- TODO in some cases it may be useful to indent  messages+-- based on an invariant category above them++{-# LANGUAGE TupleSections,  ScopedTypeVariables, GeneralizedNewtypeDeriving #-}+module Test.QuickCheck.Property.Comb where+import Test.QuickCheck+import Control.Monad.Writer+import Control.Monad.Reader++--A Monad which collects related invariants on the input+type InvM i r = ReaderT i (Writer String) r+type Inv i = InvM i Bool++cause :: (Monad m) => ReaderT i m i+cause = ask++--A Monad which collects distinct invariants on the input+type Invariants i = ReaderT i (Writer [Inv i]) ()++doc :: String -> InvM r ()+doc = lift . tell++sat :: Inv i -> Invariants i+sat p = lift . tell $ (p:[])++satcomp :: forall i i'. (i' -> i) -> Invariants i -> Invariants i'+satcomp f = mapReaderT toWriter . withReaderT f where+  toWriter :: Writer [Inv i] () -> Writer [Inv i'] ()+  toWriter orig = mapWriter (((),) . map toPredicate . snd) orig+  toPredicate :: Inv i -> Inv i'+  toPredicate orig = withReaderT f orig++runInv :: (Show i) => i -> Inv i -> Property+runInv cause' rdr =+  let (effect, msg) = runWriter . (runReaderT rdr) $ cause' in+    printTestCase ("inv: " ++ if null msg then "unknown" else msg)+      . property $ effect++runInvariants :: forall i. (Show i) => i -> Invariants i -> Property+runInvariants cause' preds =+  conjoin . map (runInv cause') . execWriter . runReaderT preds $ cause'
+ quickcheck-property-comb.cabal view
@@ -0,0 +1,28 @@+-- Initial quickcheck-property-comb.cabal generated by cabal init.  For +-- further documentation, see http://haskell.org/cabal/users-guide/++name:                quickcheck-property-comb+version:             0.1.0.0+synopsis:            Combinators for Quickcheck Property construction and Property diagnostics+description:         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.++homepage:            http://www.github.com/jfeltz/quickcheck-property-comb+license:             PublicDomain+license-file:        LICENSE+author:              John Feltz+maintainer:          jfeltz@gmail.com+category:            Testing+build-type:          Simple+cabal-version:       >=1.10++library+  exposed-modules:     Test.QuickCheck.Property.Comb+  -- other-modules:       +  other-extensions:    TupleSections, ScopedTypeVariables, GeneralizedNewtypeDeriving+  build-depends:       base >=4.5 && <4.6, QuickCheck >=2.5 && <2.6, mtl >=2.1 && <2.2+  hs-source-dirs:      ./ +  default-language:    Haskell2010