{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE StandaloneDeriving #-}

module Hedgehog.Extras.Test.MonadAssertion
  ( MonadAssertion(..)
  ) where

import           Control.Monad
import           Control.Monad.Trans.Class
import           Data.Either
import           Data.Function
import           Data.Monoid (mempty)

import qualified Control.Monad.Trans.Except as E
import qualified Control.Monad.Trans.Resource as IO
import qualified Control.Monad.Trans.Resource.Internal as IO
import qualified Hedgehog as H
import qualified Hedgehog.Internal.Property 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 :: forall a. Failure -> TestT m a
throwAssertion Failure
f = forall (m :: * -> *) a. MonadTest m => Test a -> m a
H.liftTest forall a b. (a -> b) -> a -> b
$ forall a. (Either Failure a, Journal) -> Test a
H.mkTest (forall a b. a -> Either a b
Left Failure
f, forall a. Monoid a => a
mempty)
  catchAssertion :: forall a. TestT m a -> (Failure -> TestT m a) -> TestT m a
catchAssertion TestT m a
g Failure -> TestT m a
h = forall (m :: * -> *) a.
ExceptT Failure (WriterT Journal m) a -> TestT m a
H.TestT forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) e a e'.
Monad m =>
ExceptT e m a -> (e -> ExceptT e' m a) -> ExceptT e' m a
E.catchE (forall (m :: * -> *) a.
TestT m a -> ExceptT Failure (WriterT Journal m) a
H.unTest TestT m a
g) (forall (m :: * -> *) a.
TestT m a -> ExceptT Failure (WriterT Journal m) a
H.unTest forall b c a. (b -> c) -> (a -> b) -> a -> c
. Failure -> TestT m a
h)

instance MonadAssertion m => MonadAssertion (IO.ResourceT m) where
  throwAssertion :: forall a. Failure -> ResourceT m a
throwAssertion = forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. MonadAssertion m => Failure -> m a
throwAssertion
  catchAssertion :: forall a.
ResourceT m a -> (Failure -> ResourceT m a) -> ResourceT m a
catchAssertion ResourceT m a
r Failure -> ResourceT m a
h = forall (m :: * -> *) a. (IORef ReleaseMap -> m a) -> ResourceT m a
IO.ResourceT forall a b. (a -> b) -> a -> b
$ \IORef ReleaseMap
i -> forall (m :: * -> *) a. ResourceT m a -> IORef ReleaseMap -> m a
IO.unResourceT ResourceT m a
r IORef ReleaseMap
i forall (m :: * -> *) a.
MonadAssertion m =>
m a -> (Failure -> m a) -> m a
`catchAssertion` \Failure
e -> forall (m :: * -> *) a. ResourceT m a -> IORef ReleaseMap -> m a
IO.unResourceT (Failure -> ResourceT m a
h Failure
e) IORef ReleaseMap
i

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