module Test.QuickCheck.Variant where
import Test.QuickCheck.Arbitrary
import Test.QuickCheck.Exception
import Test.QuickCheck.Gen
import Test.QuickCheck.Property
import Test.QuickCheck.State
import Test.QuickCheck.Text
class Variant a where
valid :: Gen a
invalid :: Gen a
class VarTestable prop where
propertyValid::prop -> Property
propertyInvalid::prop -> Property
instance VarTestable Bool where
propertyValid = property
propertyInvalid = property
mapTotalResultValid :: VarTestable prop => (Result -> Result) -> prop -> Property
mapTotalResultValid f = mapRoseResultValid (fmap f)
mapRoseResultValid :: VarTestable prop => (Rose Result -> Rose Result) -> prop -> Property
mapRoseResultValid f = mapPropValid (\(MkProp t) -> MkProp (f t))
mapPropValid :: VarTestable prop => (Prop -> Prop) -> prop -> Property
mapPropValid f = MkProperty . fmap f . unProperty . propertyValid
callbackValid :: VarTestable prop => Callback -> prop -> Property
callbackValid cb = mapTotalResultValid (\res -> res{ callbacks = cb : callbacks res })
counterexampleValid :: VarTestable prop => String -> prop -> Property
counterexampleValid s =
mapTotalResult (\res -> res{ testCase = s:testCase res }) .
callbackValid (PostFinalFailure Counterexample $ \st _res -> do
s <- showCounterexampleValid s
putLine (terminal st) s)
showCounterexampleValid :: String -> IO String
showCounterexampleValid s = do
let force [] = return ()
force (x:xs) = x `seq` force xs
res <- tryEvaluateIO (force s)
return $
case res of
Left err ->
formatException "Exception thrown while showing test case" err
Right () ->
s
forAllShrinkValid :: (Show a, VarTestable prop)
=> Gen a -> (a -> [a]) -> (a -> prop) -> Property
forAllShrinkValid gen shrinker pf =
again $
MkProperty $
gen >>= \x ->
unProperty $
shrinking shrinker x $ \x' ->
counterexampleValid (show x') (pf x')
mapTotalResultInvalid :: VarTestable prop => (Result -> Result) -> prop -> Property
mapTotalResultInvalid f = mapRoseResultInvalid (fmap f)
mapRoseResultInvalid :: VarTestable prop => (Rose Result -> Rose Result) -> prop -> Property
mapRoseResultInvalid f = mapPropInvalid (\(MkProp t) -> MkProp (f t))
mapPropInvalid :: VarTestable prop => (Prop -> Prop) -> prop -> Property
mapPropInvalid f = MkProperty . fmap f . unProperty . propertyInvalid
callbackInvalid :: VarTestable prop => Callback -> prop -> Property
callbackInvalid cb = mapTotalResultInvalid (\res -> res{ callbacks = cb : callbacks res })
counterexampleInvalid :: VarTestable prop => String -> prop -> Property
counterexampleInvalid s =
mapTotalResult (\res -> res{ testCase = s:testCase res }) .
callbackInvalid (PostFinalFailure Counterexample $ \st _res -> do
s <- showCounterexampleInvalid s
putLine (terminal st) s)
showCounterexampleInvalid :: String -> IO String
showCounterexampleInvalid s = do
let force [] = return ()
force (x:xs) = x `seq` force xs
res <- tryEvaluateIO (force s)
return $
case res of
Left err ->
formatException "Exception thrown while showing test case" err
Right () ->
s
forAllShrinkInvalid :: (Show a, VarTestable prop)
=> Gen a -> (a -> [a]) -> (a -> prop) -> Property
forAllShrinkInvalid gen shrinker pf =
again $
MkProperty $
gen >>= \x ->
unProperty $
shrinking shrinker x $ \x' ->
counterexampleInvalid (show x') (pf x')
instance (Arbitrary a, Variant a, Show a, VarTestable prop) => VarTestable (a->prop) where
propertyValid = forAllShrinkValid valid shrink
propertyInvalid = forAllShrinkInvalid invalid shrink