freer-simple-catching-0.1.0.0: test/Control/Monad/Freer/CatchingSpec.hs
module Control.Monad.Freer.CatchingSpec where
import Control.Monad
import Control.Exception
import Control.Monad.Freer
import Control.Monad.Freer.Catching
import Test.Hspec
data Div a where
Div :: Int -> Int -> Div Int
runDiv :: forall r v . Eff (Div ': r) v -> Eff r v
runDiv = interpret handler
where
handler :: Div a -> Eff r a
handler (Div x y) = return $ x `div` y
data Test a where
Succeed :: Test Int
Fail :: Test Bool
data TestException = TestException deriving (Show, Exception, Eq)
runTest :: forall r v . (Member IO r)
=> Eff (Test ': r) v
-> Eff r v
runTest = interpret handler
where
handler :: Test a -> Eff r a
handler Succeed = return 3
handler Fail = throw TestException
spec :: Spec
spec = do
describe "div" $ do
it "divides" $ do
(run . runDiv . send $ Div 4 2) `shouldBe` 2
describe "catching" $ do
it "lets unexceptional values through from pure code" $ do
result <- runM . runCatching @ArithException runDiv $
catching @ArithException @Div (send $ Div 2 1)
result `shouldBe` Right 2
it "catches exceptions from pure code" $ do
result <- runM . runCatching @ArithException runDiv $
catching @ArithException @Div (send $ Div 2 0)
result `shouldBe` Left DivideByZero
it "lets unexceptional io values through" $ do
result <- runM . runCatching @TestException runTest $
catching @TestException @Test (send Succeed)
result `shouldBe` Right 3
it "catches io exceptions" $ do
result <- runM . runCatching @TestException runTest $
catching @TestException @Test (send Fail)
result `shouldBe` Left TestException
it "catches inside forM" $ do
result <- runM . runCatching @TestException runTest $
forM [1,2,3] $ \i -> do
x <- catching @TestException @Test (send Fail)
y <- case x of
Left e -> return i
Right v -> if v then return 1 else return 2
z <- send Succeed
return $ y + z
result `shouldBe` [4,5,6]