module Test.HUnit.Text
(
PutText(..),
putTextToHandle, putTextToShowS,
runTestText,
showPath, showCounts,
runTestTT,
runTestTTAndExit
)
where
import Test.HUnit.Base
import Data.CallStack
import Control.Monad (when)
import System.IO (Handle, stderr, hPutStr, hPutStrLn)
import System.Exit (exitSuccess, exitFailure)
data PutText st = PutText (String -> Bool -> st -> IO st) st
putTextToHandle
:: Handle
-> Bool
-> PutText Int
putTextToHandle :: Handle -> Bool -> PutText Int
putTextToHandle Handle
handle Bool
showProgress = forall st. (String -> Bool -> st -> IO st) -> st -> PutText st
PutText String -> Bool -> Int -> IO Int
put Int
initCnt
where
initCnt :: Int
initCnt = if Bool
showProgress then Int
0 else -Int
1
put :: String -> Bool -> Int -> IO Int
put String
line Bool
pers (-1) = do forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when Bool
pers (Handle -> String -> IO ()
hPutStrLn Handle
handle String
line); forall (m :: * -> *) a. Monad m => a -> m a
return (-Int
1)
put String
line Bool
True Int
cnt = do Handle -> String -> IO ()
hPutStrLn Handle
handle (Int -> String
erase Int
cnt forall a. [a] -> [a] -> [a]
++ String
line); forall (m :: * -> *) a. Monad m => a -> m a
return Int
0
put String
line Bool
False Int
_ = do Handle -> String -> IO ()
hPutStr Handle
handle (Char
'\r' forall a. a -> [a] -> [a]
: String
line); forall (m :: * -> *) a. Monad m => a -> m a
return (forall (t :: * -> *) a. Foldable t => t a -> Int
length String
line)
erase :: Int -> String
erase Int
cnt = if Int
cnt forall a. Eq a => a -> a -> Bool
== Int
0 then String
"" else String
"\r" forall a. [a] -> [a] -> [a]
++ forall a. Int -> a -> [a]
replicate Int
cnt Char
' ' forall a. [a] -> [a] -> [a]
++ String
"\r"
putTextToShowS :: PutText ShowS
putTextToShowS :: PutText ShowS
putTextToShowS = forall st. (String -> Bool -> st -> IO st) -> st -> PutText st
PutText forall {m :: * -> *} {t}.
Monad m =>
String -> Bool -> (String -> t) -> m (String -> t)
put forall a. a -> a
id
where put :: String -> Bool -> (String -> t) -> m (String -> t)
put String
line Bool
pers String -> t
f = forall (m :: * -> *) a. Monad m => a -> m a
return (if Bool
pers then forall {t}. (String -> t) -> String -> String -> t
acc String -> t
f String
line else String -> t
f)
acc :: (String -> t) -> String -> String -> t
acc String -> t
f String
line String
rest = String -> t
f (String
line forall a. [a] -> [a] -> [a]
++ Char
'\n' forall a. a -> [a] -> [a]
: String
rest)
runTestText :: PutText st -> Test -> IO (Counts, st)
runTestText :: forall st. PutText st -> Test -> IO (Counts, st)
runTestText (PutText String -> Bool -> st -> IO st
put st
us0) Test
t = do
(Counts
counts', st
us1) <- forall us.
ReportStart us
-> ReportProblem us
-> ReportProblem us
-> us
-> Test
-> IO (Counts, us)
performTest State -> st -> IO st
reportStart Maybe SrcLoc -> String -> State -> st -> IO st
reportError Maybe SrcLoc -> String -> State -> st -> IO st
reportFailure st
us0 Test
t
st
us2 <- String -> Bool -> st -> IO st
put (Counts -> String
showCounts Counts
counts') Bool
True st
us1
forall (m :: * -> *) a. Monad m => a -> m a
return (Counts
counts', st
us2)
where
reportStart :: State -> st -> IO st
reportStart State
ss st
us = String -> Bool -> st -> IO st
put (Counts -> String
showCounts (State -> Counts
counts State
ss)) Bool
False st
us
reportError :: Maybe SrcLoc -> String -> State -> st -> IO st
reportError = String -> String -> Maybe SrcLoc -> String -> State -> st -> IO st
reportProblem String
"Error:" String
"Error in: "
reportFailure :: Maybe SrcLoc -> String -> State -> st -> IO st
reportFailure = String -> String -> Maybe SrcLoc -> String -> State -> st -> IO st
reportProblem String
"Failure:" String
"Failure in: "
reportProblem :: String -> String -> Maybe SrcLoc -> String -> State -> st -> IO st
reportProblem String
p0 String
p1 Maybe SrcLoc
loc String
msg State
ss st
us = String -> Bool -> st -> IO st
put String
line Bool
True st
us
where line :: String
line = String
"### " forall a. [a] -> [a] -> [a]
++ String
kind forall a. [a] -> [a] -> [a]
++ String
path' forall a. [a] -> [a] -> [a]
++ String
"\n" forall a. [a] -> [a] -> [a]
++ Maybe SrcLoc -> String
formatLocation Maybe SrcLoc
loc forall a. [a] -> [a] -> [a]
++ String
msg
kind :: String
kind = if forall (t :: * -> *) a. Foldable t => t a -> Bool
null String
path' then String
p0 else String
p1
path' :: String
path' = Path -> String
showPath (State -> Path
path State
ss)
formatLocation :: Maybe SrcLoc -> String
formatLocation :: Maybe SrcLoc -> String
formatLocation Maybe SrcLoc
Nothing = String
""
formatLocation (Just SrcLoc
loc) = SrcLoc -> String
srcLocFile SrcLoc
loc forall a. [a] -> [a] -> [a]
++ String
":" forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show (SrcLoc -> Int
srcLocStartLine SrcLoc
loc) forall a. [a] -> [a] -> [a]
++ String
"\n"
showCounts :: Counts -> String
showCounts :: Counts -> String
showCounts Counts{ cases :: Counts -> Int
cases = Int
cases', tried :: Counts -> Int
tried = Int
tried',
errors :: Counts -> Int
errors = Int
errors', failures :: Counts -> Int
failures = Int
failures' } =
String
"Cases: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
cases' forall a. [a] -> [a] -> [a]
++ String
" Tried: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
tried' forall a. [a] -> [a] -> [a]
++
String
" Errors: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
errors' forall a. [a] -> [a] -> [a]
++ String
" Failures: " forall a. [a] -> [a] -> [a]
++ forall a. Show a => a -> String
show Int
failures'
showPath :: Path -> String
showPath :: Path -> String
showPath [] = String
""
showPath Path
nodes = forall (t :: * -> *) a. Foldable t => (a -> a -> a) -> t a -> a
foldl1 String -> ShowS
f (forall a b. (a -> b) -> [a] -> [b]
map Node -> String
showNode Path
nodes)
where f :: String -> ShowS
f String
b String
a = String
a forall a. [a] -> [a] -> [a]
++ String
":" forall a. [a] -> [a] -> [a]
++ String
b
showNode :: Node -> String
showNode (ListItem Int
n) = forall a. Show a => a -> String
show Int
n
showNode (Label String
label) = String -> ShowS
safe String
label (forall a. Show a => a -> String
show String
label)
safe :: String -> ShowS
safe String
s String
ss = if Char
':' forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
`elem` String
s Bool -> Bool -> Bool
|| String
"\"" forall a. [a] -> [a] -> [a]
++ String
s forall a. [a] -> [a] -> [a]
++ String
"\"" forall a. Eq a => a -> a -> Bool
/= String
ss then String
ss else String
s
runTestTT :: Test -> IO Counts
runTestTT :: Test -> IO Counts
runTestTT Test
t = do (Counts
counts', Int
0) <- forall st. PutText st -> Test -> IO (Counts, st)
runTestText (Handle -> Bool -> PutText Int
putTextToHandle Handle
stderr Bool
True) Test
t
forall (m :: * -> *) a. Monad m => a -> m a
return Counts
counts'
runTestTTAndExit :: Test -> IO ()
runTestTTAndExit :: Test -> IO ()
runTestTTAndExit Test
tests = do
Counts
c <- Test -> IO Counts
runTestTT Test
tests
if (Counts -> Int
errors Counts
c forall a. Eq a => a -> a -> Bool
== Int
0) Bool -> Bool -> Bool
&& (Counts -> Int
failures Counts
c forall a. Eq a => a -> a -> Bool
== Int
0)
then forall a. IO a
exitSuccess
else forall a. IO a
exitFailure