monadology-0.2: test/Exception.hs
module Exception
( testException
) where
import Control.Applicative
import Control.Monad.Ology
import Data.IORef
import Prelude
import Test.Tasty
import Test.Tasty.HUnit
import Useful
testACatch ::
forall m e. (Eq e, Show e, MonadCatch e m)
=> m --> IO -> e -> TestTree
testACatch runM ex =
testCase "catchExc" $ do
r <- runM $ try @m @e $ throw @e @m @() ex
assertEqual "caught" (FailureResult ex) r
testABracket ::
forall m. (MonadTunnelIO m, MonadException m)
=> m --> IO -> (forall a. m a) -> TestTree
testABracket runM th =
testCase "bracket" $ do
ref <- newIORef False
_ <- tryExc $ runM $ finally @m th (liftIO $ writeIORef ref True)
b <- readIORef ref
assertEqual "finally" True b
testAnException ::
forall m e. (Eq e, Show e, MonadException m, MonadCatch e m, MonadTunnelIO m)
=> String
-> m --> IO -> e -> TestTree
testAnException name runM ex = testGroup name [testACatch runM ex, testABracket runM $ throw ex]
runComposeInner :: ComposeInner Maybe IO --> IO
runComposeInner (MkComposeInner ima) = do
ma <- ima
case ma of
Just a -> return a
Nothing -> fail "Nothing"
runExceptT' :: ExceptT () IO --> IO
runExceptT' eia = do
ea <- runExceptT eia
case ea of
Right a -> return a
Left _ -> fail "Left"
runResultT' :: ResultT () IO --> IO
runResultT' eia = do
ea <- runResultT eia
case ea of
SuccessResult a -> return a
FailureResult _ -> fail "Left"
data Info = forall m e. (MonadCatch e m, MonadIO m, Eq e, Show e) =>
MkInfo
{ iName :: String
, iRun :: m --> IO
, iExc :: Int -> e
}
newtype TestExc =
MkTestExc Int
deriving (Eq, Show)
instance Exception TestExc
ioInfo :: Info
ioInfo = MkInfo {iName = "IO", iRun = \ioa -> ioa, iExc = MkTestExc}
iRunWithT :: WithT IO --> IO
iRunWithT tia = unWithT tia return
transformInfo :: Info
transformInfo = MkInfo {iName = "WithT IO", iRun = iRunWithT, iExc = MkTestExc}
testCatch :: Info -> TestTree
testCatch MkInfo {..} =
testCase iName $
compareTest "ABCE" $ \post -> do
post "A"
found <-
iRun $
try $ do
liftIO $ post "B"
reu <-
try $ do
liftIO $ post "C"
() <- throw $ iExc 52
liftIO $ post "D"
liftIO $ assertEqual "exc1" (FailureResult $ iExc 52) reu
liftIO $ post "E"
() <- throw $ iExc 74
liftIO $ post "F"
assertEqual "exc2" (FailureResult $ iExc 74) found
testCatches :: TestTree
testCatches = testGroup "catch" [testCatch ioInfo, testCatch transformInfo]
testException :: TestTree
testException =
testGroup
"Exception"
[ testAnException "IO" id $ ErrorCall "test"
, testGroup "ExceptT () IO" $ pure $ testABracket @(ExceptT () IO) runExceptT' $ throwE ()
, testGroup "ResultT () IO" $ pure $ testABracket @(ResultT () IO) runResultT' $ throwR ()
, testGroup "ComposeInner Maybe IO" $
pure $ testABracket @(ComposeInner Maybe IO) runComposeInner $ liftInner Nothing
, testCatches
]