packages feed

effectful-zoo-0.0.3.0: components/hedgehog/Effectful/Zoo/Hedgehog/Api/MonadAssertion.hs

module Effectful.Zoo.Hedgehog.Api.MonadAssertion
  ( MonadAssertion(..),
    tryAssertion,
    tryExceptAssertion,
  ) where

import Control.Monad.Catch (MonadCatch(..))
import Control.Monad.Catch qualified as C
import Control.Monad.Trans.Class
import Control.Monad.Trans.Except qualified as E
import Control.Monad.Trans.Resource qualified as IO
import Control.Monad.Trans.Resource.Internal qualified as IO
import Effectful.Zoo.Hedgehog.Data.TestResult
import HaskellWorks.Prelude
import Hedgehog.Internal.Property qualified as H

class Monad m => MonadAssertion m where
  throwAssertion :: H.Failure -> m a
  catchAssertion :: m a -> (H.Failure -> m a) -> m a

instance Monad m => MonadAssertion (H.TestT m) where
  throwAssertion f = H.liftTest $ H.mkTest (Left f, mempty)
  catchAssertion g h = H.TestT $ E.catchE (H.unTest g) (H.unTest . h)

instance MonadAssertion m => MonadAssertion (IO.ResourceT m) where
  throwAssertion = lift . throwAssertion
  catchAssertion r h = IO.ResourceT $ \i -> IO.unResourceT r i `catchAssertion` \e -> IO.unResourceT (h e) i

deriving newtype instance Monad m => MonadAssertion (H.PropertyT m)

tryAssertion :: ()
  => MonadAssertion m
  => m a
  -> m (Either H.Failure a)
tryAssertion m =
  catchAssertion (Right <$> m) (pure . Left)

tryExceptAssertion :: ()
  => MonadAssertion m
  => MonadCatch m
  => m a
  -> m (TestResult a)
tryExceptAssertion m =
  tryAssertion (C.try m) >>= \case
    Right (Right a) -> pure $ TestResult a
    Right (Left e) -> pure $ TestError e
    Left f -> pure $ TestFailure f