{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE Safe #-}
module Test.SmallCheck.Drivers (
smallCheck, smallCheckM, smallCheckWithHook,
test,
ppFailure,
PropertyFailure(..), PropertySuccess(..), Argument, Reason, TestQuality(..)
) where
import Control.Monad (when)
import Test.SmallCheck.Property
import Test.SmallCheck.Property.Result
import Text.Printf
import Data.IORef (readIORef, writeIORef, IORef, newIORef)
smallCheck :: Testable IO a => Depth -> a -> IO ()
smallCheck d a = do
((good, bad), mbEx) <- runTestWithStats d a
let testsRun = good + bad
case mbEx of
Nothing -> do
printf "Completed %d tests without failure.\n" $ testsRun
when (bad > 0) $
printf "But %d did not meet ==> condition.\n" $ bad
Just x -> do
printf "Failed test no. %d.\n" $ testsRun
putStrLn $ ppFailure x
runTestWithStats :: Testable IO a => Depth -> a -> IO ((Integer, Integer), Maybe PropertyFailure)
runTestWithStats d prop = do
good <- newIORef 0
bad <- newIORef 0
let
hook GoodTest = modifyIORef' good (+1)
hook BadTest = modifyIORef' bad (+1)
r <- smallCheckWithHook d hook prop
goodN <- readIORef good
badN <- readIORef bad
return ((goodN, badN), r)
modifyIORef' :: IORef a -> (a -> a) -> IO ()
modifyIORef' ref f = do
x <- readIORef ref
let x' = f x
x' `seq` writeIORef ref x'
smallCheckM :: Testable m a => Depth -> a -> m (Maybe PropertyFailure)
smallCheckM d a = smallCheckWithHook d (const $ return ()) a
smallCheckWithHook :: Testable m a => Depth -> (TestQuality -> m ()) -> a -> m (Maybe PropertyFailure)
smallCheckWithHook d hook a = runProperty d hook $ test a