error-context-0.1.2.0: test/Control/Error/Context/Test.hs
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
module Control.Error.Context.Test (tests) where
import Control.Error.Context
import Control.Exception (Exception (..), throw, throwIO)
import Control.Monad
import Control.Monad.Catch (catch, throwM, try)
import Control.Monad.IO.Class
import Test.Tasty
import Test.Tasty.HUnit
tests :: TestTree
tests =
testGroup
"Tests"
[
testCase "Contextualize IO Exception"
testContextualizeIOException
, testCase "throwM"
testThrow
, testCase "catchAnyWithContext"
testCatchAnyWithContext
, testCase "catchAnyWithContext/pure"
testCatchAnyWithContextPure
, testCase "catchAnyWithoutContext"
testCatchAnyWithoutContext
, testCase "catchAnyWithoutContext/pure"
testCatchAnyWithoutContextPure
, testCase "Catch context-enriched exception without context"
testCatchWithoutContext
, testCase "Contextualize error value"
testContextualizeErrorValue
, testCase "Forgetting error context"
testForgetErrorContext
, testCase "Dumping error context"
testDumpErrorContext
, testCase "Throw and catch"
testThrowAndCatch
, testCase "Catch non-contextualized exception with context"
testNonContextualizedCatchWithContext
, testCase "ensureExceptionContext"
testEnsureExceptionContext
, testCase "catch head exception"
testCatchHeadException
, testCase "tryAnyWithoutContext"
testTryAnyWithoutContext
, testCase "tryAnyWithoutContext/pure"
testTryAnyWithoutContextPure
, testCase "tryAnyWithContext"
testTryAnyWithContext
, testCase "tryAnyWithContext/pure"
testTryAnyWithContextPure
, testCase "tryWithContext"
testTryWithContext
, testCase "tryWithContext/pure"
testTryWithContextPure
, testCase "tryWithoutContext"
testTryWithoutContext
, testCase "tryWithoutContext/pure"
testTryWithoutContextPure
, testCase "Throw and catch"
testThrowAndCatch
]
data TestException = TestException deriving (Show, Eq)
instance Exception TestException
testContextualizeIOException :: Assertion
testContextualizeIOException = do
Left (ErrorWithContext (ErrorContext ctx) TestException) <- try . runErrorContextT $
withErrorContext "A" $
withErrorContext "B" $
liftIO failingIOException
["B", "A"] @=? ctx
where failingIOException :: IO ()
failingIOException =
throwIO TestException
testCatchWithoutContext :: Assertion
testCatchWithoutContext = do
TestException <- runErrorContextT $
withErrorContext "A" $
withErrorContext "B" $
catchWithoutContext (throwM TestException) $ \ (exn :: TestException) -> do
pure exn
pure ()
testContextualizeErrorValue :: Assertion
testContextualizeErrorValue = do
ErrorWithContext (ErrorContext ctx) TestException <- runErrorContextT $
withErrorContext "A" $
withErrorContext "B" $
errorContextualize TestException
["B", "A"] @=? ctx
testForgetErrorContext :: Assertion
testForgetErrorContext = do
errWithCtx @ (ErrorWithContext _ctx TestException) <- runErrorContextT $
withErrorContext "A" $
withErrorContext "B" $
errorContextualize TestException
TestException @=? errorContextForget errWithCtx
testDumpErrorContext :: Assertion
testDumpErrorContext = do
errWithCtx @ (ErrorWithContext _ctx _exn) <- runErrorContextT $
withErrorContext "A" $
withErrorContext "B" $
errorContextualize TestException
errorWithContextDump errWithCtx
testThrowAndCatch :: Assertion
testThrowAndCatch = do
void . runErrorContextT $
catch (throwM TestException) $ \ TestException -> pure ()
testThrow :: Assertion
testThrow = do
catch (runErrorContextT (throwM TestException)) $ \ someExn -> do
let Just (ErrorWithContext _ctx someInnerExn) = fromException someExn
liftIO $ Just TestException @=? fromException someInnerExn
testCatchAnyWithContext :: Assertion
testCatchAnyWithContext = do
catchAnyWithContext (runErrorContextT (throwM TestException)) $
\ (ErrorWithContext _ctx someExn) -> do
Just TestException @=? fromException someExn
testCatchAnyWithContextPure :: Assertion
testCatchAnyWithContextPure = do
catchAnyWithContext (runErrorContextT (throw TestException)) $
\ (ErrorWithContext _ctx someExn) -> do
Just TestException @=? fromException someExn
testCatchAnyWithoutContext :: Assertion
testCatchAnyWithoutContext = do
catchAnyWithoutContext (runErrorContextT (throwM TestException)) $
\ someExn -> do
Just TestException @=? fromException someExn
testCatchAnyWithoutContextPure :: Assertion
testCatchAnyWithoutContextPure = do
catchAnyWithoutContext (runErrorContextT (throw TestException)) $
\ someExn -> do
Just TestException @=? fromException someExn
testNonContextualizedCatchWithContext :: Assertion
testNonContextualizedCatchWithContext = do
ErrorWithContext (ErrorContext ctx) TestException <- runErrorContextT $
withErrorContext "A" $
withErrorContext "B" $ do
catchWithContext throwPureException $ \ (exn :: ErrorWithContext TestException) -> do
pure exn
[] @=? ctx
where throwPureException = throw TestException
testEnsureExceptionContext :: Assertion
testEnsureExceptionContext = do
Left someExn <- try . runErrorContextT $
withErrorContext "A" $
withErrorContext "B" $ do
ensureExceptionContext $ do
throw TestException
let Just (ErrorWithContext ctx someExnWithoutCtx) = fromException someExn
Just TestException @=? fromException someExnWithoutCtx
ErrorContext ["B", "A"] @=? ctx
testCatchHeadException :: Assertion
testCatchHeadException = do
Left errWithCtx <- tryAnyWithContext . runErrorContextT $ do
withErrorContext "Here I am, calling head on an empty list!" $
ensureExceptionContext $ seq (head []) (pure ())
let (ErrorWithContext _ctx _exnWithoutCtx) = errWithCtx
putStrLn . displayException $ errWithCtx
testTryAnyWithContext :: Assertion
testTryAnyWithContext = do
Left (ErrorWithContext _ctx someExn) <- tryAnyWithContext . runErrorContextT $ do
void $ throwM TestException
pure ()
Just TestException @=? fromException someExn
testTryAnyWithContextPure :: Assertion
testTryAnyWithContextPure = do
Left (ErrorWithContext _ctx someExn) <- tryAnyWithContext . runErrorContextT $
seq (throw TestException) (pure ())
Just TestException @=? fromException someExn
testTryAnyWithoutContext :: Assertion
testTryAnyWithoutContext = do
Left someExn <- tryAnyWithoutContext . runErrorContextT $ do
void $ throwM TestException
pure ()
Just TestException @=? fromException someExn
testTryAnyWithoutContextPure :: Assertion
testTryAnyWithoutContextPure = do
Left someExn <- tryAnyWithoutContext . runErrorContextT $
seq (throw TestException) (pure ())
Just TestException @=? fromException someExn
testTryWithContext :: Assertion
testTryWithContext = do
Left (ErrorWithContext _ctx exn) <- tryWithContext . runErrorContextT $ do
void $ throwM TestException
pure ()
TestException @=? exn
testTryWithContextPure :: Assertion
testTryWithContextPure = do
Left (ErrorWithContext _ctx exn) <- tryWithContext . runErrorContextT $
seq (throw TestException) (pure ())
TestException @=? exn
testTryWithoutContext :: Assertion
testTryWithoutContext = do
Left exn <- tryWithoutContext . runErrorContextT $ do
void $ throwM TestException
pure ()
TestException @=? exn
testTryWithoutContextPure :: Assertion
testTryWithoutContextPure = do
Left exn <- tryWithoutContext . runErrorContextT $
seq (throw TestException) (pure ())
TestException @=? exn
-- testTryAnyWithoutContext :: Assertion
-- testTryAnyWithoutContext = do
-- Left someExn <- tryAnyWithoutContext . runErrorContextT $ do
-- void $ throwM TestException
-- pure ()
-- Just TestException @=? fromException someExn