module Test.DocTest.Driver (
T,
printLine,
printPrefix,
Count(..),
run,
runWith,
example,
property,
) where
import qualified Test.DocTest.Base as DocTest
import qualified Test.QuickCheck as QC
import System.Exit (exitFailure)
import Text.Printf (printf)
import qualified Control.Monad.Trans.Writer.Strict as MW
import qualified Control.Monad.Trans.Reader as MR
import qualified Control.Monad.Trans.Class as MT
import Control.Monad.IO.Class (liftIO)
import Control.Monad (when, void)
import Data.Monoid (Monoid(mempty,mappend))
import Data.Semigroup (Semigroup((<>)))
type T = MR.ReaderT QC.Args (MW.WriterT Count IO)
data Count = Count {numTotal, numFailures :: !Int}
instance Semigroup Count where
Count t0 f0 <> Count t1 f1 = Count (t0+t1) (f0+f1)
instance Monoid Count where
mempty = Count 0 0
mappend = (<>)
printLine :: String -> T ()
printLine = liftIO . putStrLn
printPrefix :: String -> T ()
printPrefix = liftIO . putStr
run :: T () -> IO ()
run = runWith QC.stdArgs
runWith :: QC.Args -> T () -> IO ()
runWith args act = do
count <- MW.execWriterT $ MR.runReaderT act args
putStrLn ""
void $ printf "Total: %d\n" $ numTotal count
void $ printf "Failures: %d\n" $ numFailures count
when (numFailures count > 0) exitFailure
tell :: Count -> T ()
tell = MT.lift . MW.tell
example :: (Show a) => a -> DocTest.ExpectedResult -> T ()
example actual expected = do
tell $ Count 1 0
case DocTest.checkResult expected (lines $ show actual) of
DocTest.Equal -> printLine "passed"
DocTest.NotEqual ls ->
printPrefix (unlines $ "*** Failed!":ls) >> tell (Count 0 1)
property :: (QC.Testable prop) => prop -> T ()
property prop = do
tell $ Count 1 0
args <- MR.ask
result <- liftIO $ QC.quickCheckWithResult args prop
when (not $ QC.isSuccess result) $ tell (Count 0 1)