module Test.Hspec.Core where
import System.IO
import System.IO.Silently
import Control.Exception
data Result = Success | Pending String | Fail String
deriving Eq
data Spec = Spec {
name::String,
requirement::String,
result::Result,
depth::Int }
| UnevaluatedSpec {
name::String,
requirement::String,
example::AnyExample,
depth::Int }
data Formatter = Formatter { formatterName :: String,
exampleGroupStarted :: Handle -> Spec -> IO (),
examplePassed :: Handle -> Spec -> [String] -> IO (),
exampleFailed :: Handle -> Spec -> [String] -> IO (),
examplePending :: Handle -> Spec -> [String] -> IO (),
errorsFormatter :: Handle -> [String] -> IO (),
footerFormatter :: Handle -> [Spec] -> Double -> IO (),
usesFormatting :: Bool }
describe :: String -> [[Spec]] -> [Spec]
describe label specs = map desc (concat specs)
where desc spec
| null $ name spec = spec { name = label }
| otherwise = spec { depth = depth spec + 1 }
descriptions :: [[Spec]] -> [Spec]
descriptions = concat
evaluateSpec :: Spec -> IO Spec
evaluateSpec (UnevaluatedSpec name' requirement' example' depth') = do
r <- evaluateExample example' `catches` [
Handler (\e -> throw (e :: AsyncException)),
Handler (\e -> return $ Fail (show (e :: SomeException)))
]
return $ Spec name' requirement' r depth'
evaluateSpec spec = return spec
it :: Example a => String -> a -> [Spec]
it requirement' example' = [UnevaluatedSpec "" requirement' (AnyExample example') 0]
class Example a where
evaluateExample :: a -> IO Result
instance Example Bool where
evaluateExample bool = evaluateExample $ if bool then Success else Fail ""
instance Example Result where
evaluateExample result' = silence $ result' `seq` return result'
data AnyExample = forall a. Example a => AnyExample a
instance Example AnyExample where
evaluateExample (AnyExample a) = evaluateExample a
pending :: String
-> Result
pending = Pending
failedCount :: [Spec] -> Int
failedCount ss = length $ filter (isFailure.result) ss
failure :: [Spec] -> Bool
failure = any (isFailure.result)
success :: [Spec] -> Bool
success = not . failure
isFailure :: Result -> Bool
isFailure (Fail _) = True
isFailure _ = False
quantify :: (Show a, Num a, Eq a) => a -> String -> String
quantify 1 s = "1 " ++ s
quantify n s = show n ++ " " ++ s ++ "s"