polysemy/test/ErrorSpec.hs

57 lines
1.9 KiB
Haskell

module ErrorSpec where
import qualified Control.Exception as X
import Polysemy
import Polysemy.Async
import Polysemy.Error
import Polysemy.Resource
import Test.Hspec
newtype MyExc = MyExc String
deriving (Show, Eq)
instance X.Exception MyExc
spec :: Spec
spec = parallel $ do
describe "fromException" $ do
it "should catch exceptions" $ do
a <-
runM $ runError $ fromException @MyExc $ do
_ <- X.throwIO $ MyExc "hello"
pure ()
a `shouldBe` (Left $ MyExc "hello")
it "should not catch non-exceptions" $ do
a <-
runM $ runError @MyExc $ fromException @MyExc $ pure ()
a `shouldBe` Right ()
it "should happen before Resource" $ do
a <-
runFinal $ embedToFinal @IO $ resourceToIOFinal $ runError @MyExc $ do
onException
(fromException @MyExc $ do
_ <- X.throwIO $ MyExc "hello"
pure ()
) $ pure $ error "this exception shouldn't happen"
a `shouldBe` (Left $ MyExc "hello")
describe "errorToIOFinal" $ do
it "should catch errors only for the interpreted Error" $ do
res1 <- runFinal $ errorToIOFinal @() $ errorToIOFinal @() $ do
raise $ throw () `catch` \() -> return ()
res1 `shouldBe` Right (Right ())
res2 <- runFinal $ errorToIOFinal @() $ errorToIOFinal @() $ do
raise (throw ()) `catch` \() -> return ()
res2 `shouldBe` Left ()
it "should propagate errors thrown in 'async'" $ do
res1 <- runFinal $ errorToIOFinal @() $ asyncToIOFinal $ do
a <- async $ throw ()
await a
res1 `shouldBe` (Left () :: Either () (Maybe ()))
res2 <- runFinal $ errorToIOFinal @() $ asyncToIOFinal $ do
a <- async $ throw ()
await a `catch` \() -> return $ Just ()
res2 `shouldBe` Right (Just ())