{-# LANGUAGE TypeOperators, TypeFamilies, DeriveFunctor, TemplateHaskell #-}
module Test.QuickCheck.Counterexamples(module Test.QuickCheck.Counterexamples, module Test.QuickCheck) where
import Data.IORef
import Test.QuickCheck hiding
( quickCheck, quickCheckWith, quickCheckResult, quickCheckWithResult
, verboseCheck, verboseCheckWith, verboseCheckResult, verboseCheckWithResult
, labelledExamples, labelledExamplesWith, labelledExamplesResult, labelledExamplesWithResult
, polyQuickCheck, polyVerboseCheck
, Property, Testable(..)
, forAll
, forAllShrink
, forAllShow
, forAllShrinkShow
, forAllBlind
, forAllShrinkBlind
, shrinking
, (==>)
, (===)
, (=/=)
, ioProperty
, idempotentIOProperty
, verbose
, verboseShrinking
, once
, again
, within
, noShrinking
, (.&.)
, (.&&.)
, conjoin
, (.||.)
, disjoin
, counterexample
, printTestCase
, whenFail
, whenFail'
, expectFailure
, label
, collect
, classify
, cover
, tabulate
, coverTable
, checkCoverage
, checkCoverageWith
, mapSize
)
import qualified Test.QuickCheck as QC
import Language.Haskell.TH
import Control.Monad
newtype PropertyOf cex =
MkProperty {
unProperty :: (cex -> IO ()) -> QC.Property }
deriving Functor
type Property = PropertyOf ()
type PropertyFrom prop = PropertyOf (Counterexample prop)
class QC.Testable prop => Testable prop where
type Counterexample prop
property :: prop -> PropertyFrom prop
propertyForAllShrinkShow :: Show a => Gen a -> (a -> [a]) -> (a -> String) -> (a -> prop) -> PropertyOf (a :&: Counterexample prop)
propertyForAllShrinkShow gen shr f =
forAllShrinkShow gen shr f
instance Testable Discard where
type Counterexample Discard = ()
property prop = MkProperty (\_ -> QC.property prop)
instance Testable () where
type Counterexample () = ()
property prop = MkProperty (\f -> QC.whenFail (f ()) prop)
instance Testable prop => Testable (Maybe prop) where
type Counterexample (Maybe prop) = Counterexample prop
property = property . liftMaybe
where
liftMaybe prop@Nothing = MkProperty (\_ -> QC.property prop)
liftMaybe (Just prop) = property prop
instance Testable Bool where
type Counterexample Bool = ()
property prop = MkProperty (\f -> QC.whenFail (f ()) prop)
instance Testable QC.Property where
type Counterexample QC.Property = ()
property prop = MkProperty (\f -> QC.whenFail (f ()) prop)
instance Testable prop => Testable (Gen prop) where
type Counterexample (Gen prop) = Counterexample prop
property prop = MkProperty $ \k ->
QC.property (unProperty . property <$> prop <*> pure k)
instance QC.Testable (PropertyOf cex) where
property prop = unProperty prop (\_ -> return ())
instance Testable (PropertyOf cex) where
type Counterexample (PropertyOf cex) = cex
property = id
instance (Show a, QC.Arbitrary a, Testable b) => Testable (a -> b) where
type Counterexample (a -> b) = a :&: Counterexample b
property prop = propertyForAllShrinkShow arbitrary shrink show prop
propertyForAllShrinkShow gen shr shw f =
fmap (\((x, y) :&: z) -> x :&: y :&: z) $
propertyForAllShrinkShow
(liftM2 (,) gen arbitrary)
(liftShrink2 shr shrink)
(\(x, y) -> shw x ++ "\n" ++ show y)
(uncurry f)
infixr 6 :&:
data a :&: b = a :&: b deriving (Eq, Ord, Show, Read)
typedCounterexample :: Testable prop => a -> prop -> PropertyOf (a :&: Counterexample prop)
typedCounterexample x prop = fmap (x :&:) (property prop)
onProperty :: Testable prop => (QC.Property -> QC.Property) -> prop -> PropertyFrom prop
onProperty f prop =
MkProperty (\k -> f (unProperty (property prop) k))
quickCheck :: Testable prop => prop -> IO (Maybe (Counterexample prop))
quickCheck = quickCheckWith stdArgs
quickCheckWith :: Testable prop => Args -> prop -> IO (Maybe (Counterexample prop))
quickCheckWith args prop = fmap fst (quickCheckWithResult args prop)
quickCheckResult :: Testable prop => prop -> IO (Maybe (Counterexample prop), Result)
quickCheckResult = quickCheckWithResult stdArgs
quickCheckWithResult :: Testable prop => Args -> prop -> IO (Maybe (Counterexample prop), Result)
quickCheckWithResult args prop = do
ref <- newIORef Nothing
let
modify x Nothing = Just x
modify _ (Just _) =
error "Internal error in quickcheck-with-counterexamples: IORef written to twice"
res <- QC.quickCheckWithResult args $
unProperty (property prop) (modifyIORef ref . modify)
cex <- readIORef ref
return (cex, res)
verboseCheck :: Testable prop => prop -> IO (Maybe (Counterexample prop))
verboseCheck p = quickCheck (verbose p)
verboseCheckWith :: Testable prop => Args -> prop -> IO (Maybe (Counterexample prop))
verboseCheckWith args p = quickCheckWith args (verbose p)
verboseCheckResult :: Testable prop => prop -> IO (Maybe (Counterexample prop), Result)
verboseCheckResult p = quickCheckResult (verbose p)
verboseCheckWithResult :: Testable prop => Args -> prop -> IO (Maybe (Counterexample prop), Result)
verboseCheckWithResult a p = quickCheckWithResult a (verbose p)
labelledExamples :: Testable prop => prop -> IO (Maybe (Counterexample prop))
labelledExamples p = quickCheck (verbose p)
labelledExamplesWith :: Testable prop => Args -> prop -> IO (Maybe (Counterexample prop))
labelledExamplesWith args p = quickCheckWith args (verbose p)
labelledExamplesResult :: Testable prop => prop -> IO (Maybe (Counterexample prop), Result)
labelledExamplesResult p = quickCheckResult (verbose p)
labelledExamplesWithResult :: Testable prop => Args -> prop -> IO (Maybe (Counterexample prop), Result)
labelledExamplesWithResult a p = quickCheckWithResult a (verbose p)
polyQuickCheck :: Name -> ExpQ
polyQuickCheck x = [| quickCheck $(monomorphic x) |]
polyVerboseCheck :: Name -> ExpQ
polyVerboseCheck x = [| verboseCheck $(monomorphic x) |]
forAll :: (Testable prop, Show a) => Gen a -> (a -> prop) -> PropertyOf (a :&: Counterexample prop)
forAll arb prop = forAllShrink arb shrinkNothing prop
forAllShrink :: (Testable prop, Show a) => Gen a -> (a -> [a]) -> (a -> prop) -> PropertyOf (a :&: Counterexample prop)
forAllShrink arb shr prop =
forAllShrinkShow arb shr show prop
forAllShow :: Testable prop => Gen a -> (a -> String) -> (a -> prop) -> PropertyOf (a :&: Counterexample prop)
forAllShow arb shw prop = forAllShrinkShow arb shrinkNothing shw prop
forAllShrinkShow :: Testable prop => Gen a -> (a -> [a]) -> (a -> String) -> (a -> prop) -> PropertyOf (a :&: Counterexample prop)
forAllShrinkShow arb shr shw prop =
forAllShrinkBlind arb shr (\x -> counterexample (shw x) (prop x))
forAllBlind :: Testable prop => Gen a -> (a -> prop) -> PropertyOf (a :&: Counterexample prop)
forAllBlind arb prop = forAllShrinkBlind arb shrinkNothing prop
forAllShrinkBlind :: Testable prop => Gen a -> (a -> [a]) -> (a -> prop) -> PropertyOf (a :&: Counterexample prop)
forAllShrinkBlind arb shr prop =
MkProperty $ \f ->
QC.forAllShrinkBlind arb shr $ \x ->
unProperty (property (prop x)) (\y -> f (x :&: y))
shrinking :: Testable prop => (a -> [a]) -> a -> (a -> prop) -> PropertyFrom prop
shrinking shr x prop =
MkProperty $ \k -> QC.shrinking shr x $ \x ->
unProperty (property (prop x)) k
infixr 0 ==>
(==>) :: Testable prop => Bool -> prop -> PropertyFrom prop
x ==> prop = onProperty (x QC.==>) prop
infix 4 ===
(===) :: (Eq a, Show a) => a -> a -> Property
x === y = property (x QC.=== y)
infix 4 =/=
(=/=) :: (Eq a, Show a) => a -> a -> Property
x =/= y = property (x QC.=/= y)
ioProperty :: Testable prop => IO prop -> PropertyFrom prop
ioProperty ioprop =
MkProperty $ \k -> QC.ioProperty $ do
prop <- ioprop
return (unProperty (property prop) k)
idempotentIOProperty :: Testable prop => IO prop -> PropertyFrom prop
idempotentIOProperty ioprop =
MkProperty $ \k -> QC.idempotentIOProperty $ do
prop <- ioprop
return (unProperty (property prop) k)
verbose :: Testable prop => prop -> PropertyFrom prop
verbose = onProperty QC.verbose
verboseShrinking :: Testable prop => prop -> PropertyFrom prop
verboseShrinking = onProperty QC.verboseShrinking
once :: Testable prop => prop -> PropertyFrom prop
once = onProperty QC.once
again :: Testable prop => prop -> PropertyFrom prop
again = onProperty QC.again
within :: Testable prop => Int -> prop -> PropertyFrom prop
within n = onProperty (QC.within n)
noShrinking :: Testable prop => prop -> PropertyFrom prop
noShrinking = onProperty QC.noShrinking
counterexample :: Testable prop => String -> prop -> PropertyFrom prop
counterexample msg = onProperty (QC.counterexample msg)
whenFail :: Testable prop => IO () -> prop -> PropertyFrom prop
whenFail m = onProperty (QC.whenFail m)
whenFail' :: Testable prop => IO () -> prop -> PropertyFrom prop
whenFail' m = onProperty (QC.whenFail' m)
expectFailure :: Testable prop => prop -> PropertyFrom prop
expectFailure = onProperty QC.expectFailure
label :: Testable prop => String -> prop -> PropertyFrom prop
label lab = onProperty (QC.label lab)
collect :: (Show a, Testable prop) => a -> prop -> PropertyFrom prop
collect x = onProperty (QC.collect x)
classify :: Testable prop => Bool -> String -> prop -> PropertyFrom prop
classify cond lab = onProperty (QC.classify cond lab)
cover :: Testable prop => Double -> Bool -> String -> prop -> PropertyFrom prop
cover percent cond lab = onProperty (QC.cover percent cond lab)
tabulate :: Testable prop => String -> [String] -> prop -> PropertyFrom prop
tabulate table values = onProperty (QC.tabulate table values)
coverTables :: Testable prop => String -> [(String, Double)] -> prop -> PropertyFrom prop
coverTables table percents = onProperty (QC.coverTable table percents)
checkCoverage :: Testable prop => prop -> PropertyFrom prop
checkCoverage = onProperty QC.checkCoverage
checkCoverageWith :: Testable prop => Confidence -> prop -> PropertyFrom prop
checkCoverageWith confidence = onProperty (QC.checkCoverageWith confidence)
mapSize :: Testable prop => (Int -> Int) -> prop -> PropertyFrom prop
mapSize f = onProperty (QC.mapSize f)