module Test.Hspec.Core.Util (
pluralize
, strip
, lineBreaksAt
, Path
, joinPath
, formatRequirement
, filterPredicate
, safeTry
, formatException
) where
import Data.List
import Data.Char (isSpace)
import GHC.IO.Exception
import Control.Exception
import Control.Concurrent.Async
import Test.Hspec.Core.Compat (showType)
pluralize :: Int -> String -> String
pluralize 1 s = "1 " ++ s
pluralize n s = show n ++ " " ++ s ++ "s"
strip :: String -> String
strip = dropWhile isSpace . reverse . dropWhile isSpace . reverse
lineBreaksAt :: Int -> String -> [String]
lineBreaksAt n input = case words input of
[] -> []
x:xs -> go (x, xs)
where
go :: (String, [String]) -> [String]
go c = case c of
(s, []) -> [s]
(s, y:ys) -> let r = s ++ " " ++ y in
if length r <= n
then go (r, ys)
else s : go (y, ys)
type Path = ([String], String)
joinPath :: Path -> String
joinPath (groups, requirement) = "/" ++ intercalate "/" (groups ++ [requirement]) ++ "/"
formatRequirement :: Path -> String
formatRequirement (groups, requirement) = groups_ ++ requirement
where
groups_ = case break (any isSpace) groups of
([], ys) -> join ys
(xs, ys) -> join (intercalate "." xs : ys)
join xs = case xs of
[x] -> x ++ " "
ys -> concatMap (++ ", ") ys
filterPredicate :: String -> Path -> Bool
filterPredicate pattern path =
pattern `isInfixOf` plain
|| pattern `isInfixOf` formatted
where
plain = joinPath path
formatted = formatRequirement path
formatException :: SomeException -> String
formatException err@(SomeException e) = case fromException err of
Just ioe -> showType ioe ++ " of type " ++ showIOErrorType ioe ++ "\n" ++ show ioe
Nothing -> showType e ++ "\n" ++ show e
where
showIOErrorType :: IOException -> String
showIOErrorType ioe = case ioe_type ioe of
AlreadyExists -> "AlreadyExists"
NoSuchThing -> "NoSuchThing"
ResourceBusy -> "ResourceBusy"
ResourceExhausted -> "ResourceExhausted"
EOF -> "EOF"
IllegalOperation -> "IllegalOperation"
PermissionDenied -> "PermissionDenied"
UserError -> "UserError"
UnsatisfiedConstraints -> "UnsatisfiedConstraints"
SystemError -> "SystemError"
ProtocolError -> "ProtocolError"
OtherError -> "OtherError"
InvalidArgument -> "InvalidArgument"
InappropriateType -> "InappropriateType"
HardwareFault -> "HardwareFault"
UnsupportedOperation -> "UnsupportedOperation"
TimeExpired -> "TimeExpired"
ResourceVanished -> "ResourceVanished"
Interrupted -> "Interrupted"
safeTry :: IO a -> IO (Either SomeException a)
safeTry action = withAsync (action >>= evaluate) waitCatch