blas-hs-0.1.1.0: tests/TestUtils.hs
module TestUtils where
import Control.Applicative (Applicative((<*>), pure))
import System.Exit (exitFailure, exitSuccess)
import System.IO (hPutStrLn, stderr)
import Text.Printf (printf)
data TestState
= TestState
{ quiet :: Bool -- ^ Whether success messages should be suppressed
, failCount :: Int
}
initTestState :: TestState
initTestState
= TestState
{ quiet = False
, failCount = 0
}
newtype Test a = Test { runTestM :: TestState -> IO (a, TestState) }
instance Functor Test where
fmap f u = return f <*> u
instance Applicative Test where
pure = return
mf <*> mx = do
f <- mf
x <- mx
return (f x)
instance Monad Test where
return x = Test $ \ s -> return (x, s)
Test f >>= u = Test $ \ s -> do
(x, s') <- f s
runTestM (u x) s'
fail msg = do
failTest "aborted"
liftIO (fail msg)
runTest :: Test () -> IO ()
runTest test = do
((), s) <- runTestM test initTestState
if failCount s > 0 then exitFailure else exitSuccess
passTest :: String -> Test ()
passTest msg = do
s <- get
if quiet s
then return ()
else liftIO (putStrLn msg')
where msg' = "ok" ++ if null msg then "" else printf " (%s)" msg
failTest :: String -> Test ()
failTest msg = do
liftIO (hPutStrLn stderr ("*** FAIL: " ++ msg))
modify $ \ state -> state { failCount = succ (failCount state) }
-- | The test passes only if the boolean argument is true.
expect :: String -> Bool -> Test ()
expect msg False = failTest msg
expect msg True = passTest msg
liftIO :: IO a -> Test a
liftIO m = Test $ \ s -> do
result <- m
return (result, s)
get :: Test TestState
get = Test $ \ s -> return (s, s)
put :: TestState -> Test ()
put s = Test $ \ _ -> return ((), s)
modify :: (TestState -> TestState) -> Test ()
modify f = do
s <- get
put (f s)