-------------------------------------------------------------------------------
-------------------------------------------------------------------------------
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TupleSections #-}

{- | Free monads for composing Given/When/Then scenarios.

Module    : Test.BDD.LanguageFree
Copyright :  (c) Paolo Veronelli 2017
License   :  BSD-3-Clause
Maintainer:  paolo.veronelli@gmail.com
Stability :  experimental
Portability: non-portable
-}
module Test.BDD.LanguageFree
    ( given
    , givenAndAfter_
    , givenAndAfter
    , then_
    , then__
    , when_
    , GivenFree
    , ThenFree
    , FreeBDD
    , testFreeBDD
    , BDDResult (..)
    )
where

import Control.Monad.Catch
import Control.Monad.Free
import Control.Monad.Reader

-- | Separating the 2 phases by type
data Phase t = Preparing | Testing t

-- | Bare hoare language
data Language m a where
    -- | action to prepare the test
    Given :: m a -> (a -> Language m 'Preparing) -> Language m 'Preparing
    -- | action to prepare the test, and related teardown action
    GivenAndAfter
        :: m (a, r)
        -> (r -> m ())
        -> (a -> Language m 'Preparing)
        -> Language m 'Preparing
    -- | core logic of the test (last preparing action)
    When :: m t -> Language m ('Testing t) -> Language m 'Preparing
    -- | action producing a test
    Then
        :: (t -> m ()) -> Language m ('Testing t) -> Language m ('Testing t)
    -- | final placeholder
    End :: Language m x
    And
        :: Language m 'Preparing
        -> Language m 'Preparing
        -> Language m 'Preparing

-- | A scenario result carrying the recorded teardown action.
data BDDResult m = Failed SomeException (m ()) | Succeded (m ())

type CJR m = ReaderT (m ()) m (BDDResult m)

catchCJR :: (MonadCatch m) => CJR m -> CJR m
catchCJR :: forall (m :: * -> *). MonadCatch m => CJR m -> CJR m
catchCJR CJR m
f = CJR m -> (SomeException -> CJR m) -> CJR m
forall e a.
(HasCallStack, Exception e) =>
ReaderT (m ()) m a
-> (e -> ReaderT (m ()) m a) -> ReaderT (m ()) m a
forall (m :: * -> *) e a.
(MonadCatch m, HasCallStack, Exception e) =>
m a -> (e -> m a) -> m a
catch CJR m
f ((SomeException -> CJR m) -> CJR m)
-> (SomeException -> CJR m) -> CJR m
forall a b. (a -> b) -> a -> b
$ (m () -> BDDResult m) -> CJR m
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks ((m () -> BDDResult m) -> CJR m)
-> (SomeException -> m () -> BDDResult m) -> SomeException -> CJR m
forall b c a. (b -> c) -> (a -> b) -> a -> c
. SomeException -> m () -> BDDResult m
forall (m :: * -> *). SomeException -> m () -> BDDResult m
Failed

stepIn :: (MonadCatch m) => m a -> (a -> CJR m) -> CJR m
stepIn :: forall (m :: * -> *) a.
MonadCatch m =>
m a -> (a -> CJR m) -> CJR m
stepIn m a
g a -> CJR m
q = CJR m -> CJR m
forall (m :: * -> *). MonadCatch m => CJR m -> CJR m
catchCJR (m a -> ReaderT (m ()) m a
forall (m :: * -> *) a. Monad m => m a -> ReaderT (m ()) m a
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift m a
g ReaderT (m ()) m a -> (a -> CJR m) -> CJR m
forall a b.
ReaderT (m ()) m a
-> (a -> ReaderT (m ()) m b) -> ReaderT (m ()) m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= a -> CJR m
q)

{- | Run a teardown, then the remaining ones even when it throws; the
first exception is rethrown once all have run.
-}
releaseThen :: (MonadCatch m) => m () -> m () -> m ()
releaseThen :: forall (m :: * -> *). MonadCatch m => m () -> m () -> m ()
releaseThen m ()
release m ()
rest =
    m () -> m (Either SomeException ())
forall (m :: * -> *) e a.
(HasCallStack, MonadCatch m, Exception e) =>
m a -> m (Either e a)
try m ()
release m (Either SomeException ())
-> (Either SomeException () -> m ()) -> m ()
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
        Right () -> m ()
rest
        Left (SomeException
e :: SomeException) -> do
            (_ :: Either SomeException ()) <- m () -> m (Either SomeException ())
forall (m :: * -> *) e a.
(HasCallStack, MonadCatch m, Exception e) =>
m a -> m (Either e a)
try m ()
rest
            throwM e

interpret
    :: forall m. (MonadCatch m) => Language m 'Preparing -> m (BDDResult m)
interpret :: forall (m :: * -> *).
MonadCatch m =>
Language m 'Preparing -> m (BDDResult m)
interpret Language m 'Preparing
y = ReaderT (m ()) m (BDDResult m) -> m () -> m (BDDResult m)
forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (Language m 'Preparing -> ReaderT (m ()) m (BDDResult m)
interpret' Language m 'Preparing
y) (() -> m ()
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return ())
  where
    interpret' :: Language m 'Preparing -> CJR m
    interpret' :: Language m 'Preparing -> ReaderT (m ()) m (BDDResult m)
interpret' (Given m a
g a -> Language m 'Preparing
p) = m a
-> (a -> ReaderT (m ()) m (BDDResult m))
-> ReaderT (m ()) m (BDDResult m)
forall (m :: * -> *) a.
MonadCatch m =>
m a -> (a -> CJR m) -> CJR m
stepIn m a
g ((a -> ReaderT (m ()) m (BDDResult m))
 -> ReaderT (m ()) m (BDDResult m))
-> (a -> ReaderT (m ()) m (BDDResult m))
-> ReaderT (m ()) m (BDDResult m)
forall a b. (a -> b) -> a -> b
$ Language m 'Preparing -> ReaderT (m ()) m (BDDResult m)
interpret' (Language m 'Preparing -> ReaderT (m ()) m (BDDResult m))
-> (a -> Language m 'Preparing)
-> a
-> ReaderT (m ()) m (BDDResult m)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Language m 'Preparing
p
    interpret' (GivenAndAfter m (a, r)
g r -> m ()
z a -> Language m 'Preparing
p) =
        m (a, r)
-> ((a, r) -> ReaderT (m ()) m (BDDResult m))
-> ReaderT (m ()) m (BDDResult m)
forall (m :: * -> *) a.
MonadCatch m =>
m a -> (a -> CJR m) -> CJR m
stepIn m (a, r)
g (((a, r) -> ReaderT (m ()) m (BDDResult m))
 -> ReaderT (m ()) m (BDDResult m))
-> ((a, r) -> ReaderT (m ()) m (BDDResult m))
-> ReaderT (m ()) m (BDDResult m)
forall a b. (a -> b) -> a -> b
$ \(a
x, r
r) -> (m () -> m ())
-> ReaderT (m ()) m (BDDResult m) -> ReaderT (m ()) m (BDDResult m)
forall a.
(m () -> m ()) -> ReaderT (m ()) m a -> ReaderT (m ()) m a
forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local (m () -> m () -> m ()
forall (m :: * -> *). MonadCatch m => m () -> m () -> m ()
releaseThen (m () -> m () -> m ()) -> m () -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ r -> m ()
z r
r) (ReaderT (m ()) m (BDDResult m) -> ReaderT (m ()) m (BDDResult m))
-> ReaderT (m ()) m (BDDResult m) -> ReaderT (m ()) m (BDDResult m)
forall a b. (a -> b) -> a -> b
$ Language m 'Preparing -> ReaderT (m ()) m (BDDResult m)
interpret' (Language m 'Preparing -> ReaderT (m ()) m (BDDResult m))
-> Language m 'Preparing -> ReaderT (m ()) m (BDDResult m)
forall a b. (a -> b) -> a -> b
$ a -> Language m 'Preparing
p a
x
    interpret' (When m t
fa Language m ('Testing t)
p) =
        m t
-> (t -> ReaderT (m ()) m (BDDResult m))
-> ReaderT (m ()) m (BDDResult m)
forall (m :: * -> *) a.
MonadCatch m =>
m a -> (a -> CJR m) -> CJR m
stepIn m t
fa ((t -> ReaderT (m ()) m (BDDResult m))
 -> ReaderT (m ()) m (BDDResult m))
-> (t -> ReaderT (m ()) m (BDDResult m))
-> ReaderT (m ()) m (BDDResult m)
forall a b. (a -> b) -> a -> b
$ \t
x -> t -> Language m ('Testing t) -> ReaderT (m ()) m (BDDResult m)
forall t.
t -> Language m ('Testing t) -> ReaderT (m ()) m (BDDResult m)
interpretT' t
x Language m ('Testing t)
p
    interpret' (And Language m 'Preparing
f Language m 'Preparing
g) = do
        r <- Language m 'Preparing -> ReaderT (m ()) m (BDDResult m)
interpret' Language m 'Preparing
f
        case r of
            Succeded m ()
_ -> Language m 'Preparing -> ReaderT (m ()) m (BDDResult m)
interpret' Language m 'Preparing
g
            BDDResult m
w -> BDDResult m -> ReaderT (m ()) m (BDDResult m)
forall a. a -> ReaderT (m ()) m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure BDDResult m
w
    interpret' Language m 'Preparing
End = (m () -> BDDResult m) -> ReaderT (m ()) m (BDDResult m)
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks m () -> BDDResult m
forall (m :: * -> *). m () -> BDDResult m
Succeded
    interpretT' :: t -> Language m ('Testing t) -> CJR m
    interpretT' :: forall t.
t -> Language m ('Testing t) -> ReaderT (m ()) m (BDDResult m)
interpretT' t
_ Language m ('Testing t)
End = (m () -> BDDResult m) -> ReaderT (m ()) m (BDDResult m)
forall r (m :: * -> *) a. MonadReader r m => (r -> a) -> m a
asks m () -> BDDResult m
forall (m :: * -> *). m () -> BDDResult m
Succeded
    interpretT' t
x (Then t -> m ()
f Language m ('Testing t)
p) =
        m ()
-> (() -> ReaderT (m ()) m (BDDResult m))
-> ReaderT (m ()) m (BDDResult m)
forall (m :: * -> *) a.
MonadCatch m =>
m a -> (a -> CJR m) -> CJR m
stepIn (t -> m ()
f t
t
x) ((() -> ReaderT (m ()) m (BDDResult m))
 -> ReaderT (m ()) m (BDDResult m))
-> (() -> ReaderT (m ()) m (BDDResult m))
-> ReaderT (m ()) m (BDDResult m)
forall a b. (a -> b) -> a -> b
$ \() -> t -> Language m ('Testing t) -> ReaderT (m ()) m (BDDResult m)
forall t.
t -> Language m ('Testing t) -> ReaderT (m ()) m (BDDResult m)
interpretT' t
x Language m ('Testing t)
Language m ('Testing t)
p

-- | Preparation instructions for the free-monad interface.
data GivenFree m a where
    GivenFree :: m b -> (b -> a) -> GivenFree m a
    GivenAndAfterFree
        :: m (b, r) -> (r -> m ()) -> (b -> a) -> GivenFree m a
    WhenFree :: m t -> Free (ThenFree m t) c -> a -> GivenFree m a

-- | Assertions that consume the result of a scenario action.
data ThenFree m t a
    = ThenFree (t -> m ()) a
    deriving ((forall a b. (a -> b) -> ThenFree m t a -> ThenFree m t b)
-> (forall a b. a -> ThenFree m t b -> ThenFree m t a)
-> Functor (ThenFree m t)
forall a b. a -> ThenFree m t b -> ThenFree m t a
forall a b. (a -> b) -> ThenFree m t a -> ThenFree m t b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
forall (m :: * -> *) t a b. a -> ThenFree m t b -> ThenFree m t a
forall (m :: * -> *) t a b.
(a -> b) -> ThenFree m t a -> ThenFree m t b
$cfmap :: forall (m :: * -> *) t a b.
(a -> b) -> ThenFree m t a -> ThenFree m t b
fmap :: forall a b. (a -> b) -> ThenFree m t a -> ThenFree m t b
$c<$ :: forall (m :: * -> *) t a b. a -> ThenFree m t b -> ThenFree m t a
<$ :: forall a b. a -> ThenFree m t b -> ThenFree m t a
Functor)

instance Functor (GivenFree m) where
    fmap :: forall a b. (a -> b) -> GivenFree m a -> GivenFree m b
fmap a -> b
f (GivenFree m b
m b -> a
x) = m b -> (b -> b) -> GivenFree m b
forall (m :: * -> *) t a. m t -> (t -> a) -> GivenFree m a
GivenFree m b
m ((b -> b) -> GivenFree m b) -> (b -> b) -> GivenFree m b
forall a b. (a -> b) -> a -> b
$ a -> b
f (a -> b) -> (b -> a) -> b -> b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> b -> a
x
    fmap a -> b
f (GivenAndAfterFree m (b, r)
mr r -> m ()
rm b -> a
x) = m (b, r) -> (r -> m ()) -> (b -> b) -> GivenFree m b
forall (m :: * -> *) t r a.
m (t, r) -> (r -> m ()) -> (t -> a) -> GivenFree m a
GivenAndAfterFree m (b, r)
mr r -> m ()
rm ((b -> b) -> GivenFree m b) -> (b -> b) -> GivenFree m b
forall a b. (a -> b) -> a -> b
$ a -> b
f (a -> b) -> (b -> a) -> b -> b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> b -> a
x
    fmap a -> b
f (WhenFree m t
mt Free (ThenFree m t) c
ft a
x) = m t -> Free (ThenFree m t) c -> b -> GivenFree m b
forall (m :: * -> *) t r a.
m t -> Free (ThenFree m t) r -> a -> GivenFree m a
WhenFree m t
mt Free (ThenFree m t) c
ft (b -> GivenFree m b) -> b -> GivenFree m b
forall a b. (a -> b) -> a -> b
$ a -> b
f a
x

-- | A scenario built from preparation instructions.
type FreeBDD m x = Free (GivenFree m) x

-- | Run a preparation action and return its value to subsequent steps.
given :: m a -> Free (GivenFree m) a
given :: forall (m :: * -> *) a. m a -> Free (GivenFree m) a
given m a
m = GivenFree m a -> Free (GivenFree m) a
forall (f :: * -> *) (m :: * -> *) a.
(Functor f, MonadFree f m) =>
f a -> m a
liftF (GivenFree m a -> Free (GivenFree m) a)
-> GivenFree m a -> Free (GivenFree m) a
forall a b. (a -> b) -> a -> b
$ m a -> (a -> a) -> GivenFree m a
forall (m :: * -> *) t a. m t -> (t -> a) -> GivenFree m a
GivenFree m a
m a -> a
forall a. a -> a
id

-- | Acquire a value and resource, recording the resource teardown.
givenAndAfter :: m (b, r) -> (r -> m ()) -> Free (GivenFree m) b
givenAndAfter :: forall (m :: * -> *) b r.
m (b, r) -> (r -> m ()) -> Free (GivenFree m) b
givenAndAfter m (b, r)
g r -> m ()
td = GivenFree m b -> Free (GivenFree m) b
forall (f :: * -> *) (m :: * -> *) a.
(Functor f, MonadFree f m) =>
f a -> m a
liftF (GivenFree m b -> Free (GivenFree m) b)
-> GivenFree m b -> Free (GivenFree m) b
forall a b. (a -> b) -> a -> b
$ m (b, r) -> (r -> m ()) -> (b -> b) -> GivenFree m b
forall (m :: * -> *) t r a.
m (t, r) -> (r -> m ()) -> (t -> a) -> GivenFree m a
GivenAndAfterFree m (b, r)
g r -> m ()
td b -> b
forall a. a -> a
id

-- | Acquire a resource and record its teardown without returning a value.
givenAndAfter_
    :: (Functor m) => m r -> (r -> m ()) -> Free (GivenFree m) ()
givenAndAfter_ :: forall (m :: * -> *) r.
Functor m =>
m r -> (r -> m ()) -> Free (GivenFree m) ()
givenAndAfter_ m r
g r -> m ()
td = GivenFree m () -> Free (GivenFree m) ()
forall (f :: * -> *) (m :: * -> *) a.
(Functor f, MonadFree f m) =>
f a -> m a
liftF (GivenFree m () -> Free (GivenFree m) ())
-> GivenFree m () -> Free (GivenFree m) ()
forall a b. (a -> b) -> a -> b
$ m ((), r) -> (r -> m ()) -> (() -> ()) -> GivenFree m ()
forall (m :: * -> *) t r a.
m (t, r) -> (r -> m ()) -> (t -> a) -> GivenFree m a
GivenAndAfterFree (((),) (r -> ((), r)) -> m r -> m ((), r)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m r
g) r -> m ()
td () -> ()
forall a. a -> a
id

-- | Run the scenario action and feed its result to the assertions.
when_ :: m t -> Free (ThenFree m t) b -> Free (GivenFree m) ()
when_ :: forall (m :: * -> *) t b.
m t -> Free (ThenFree m t) b -> Free (GivenFree m) ()
when_ m t
mt Free (ThenFree m t) b
ts = GivenFree m () -> Free (GivenFree m) ()
forall (f :: * -> *) (m :: * -> *) a.
(Functor f, MonadFree f m) =>
f a -> m a
liftF (GivenFree m () -> Free (GivenFree m) ())
-> GivenFree m () -> Free (GivenFree m) ()
forall a b. (a -> b) -> a -> b
$ m t -> Free (ThenFree m t) b -> () -> GivenFree m ()
forall (m :: * -> *) t r a.
m t -> Free (ThenFree m t) r -> a -> GivenFree m a
WhenFree m t
mt Free (ThenFree m t) b
ts ()

thens :: Free (ThenFree m t) a -> Language m ('Testing t)
thens :: forall (m :: * -> *) t a.
Free (ThenFree m t) a -> Language m ('Testing t)
thens (Free (ThenFree t -> m ()
m Free (ThenFree m t) a
f)) = (t -> m ()) -> Language m ('Testing t) -> Language m ('Testing t)
forall t (m :: * -> *).
(t -> m ()) -> Language m ('Testing t) -> Language m ('Testing t)
Then t -> m ()
m (Language m ('Testing t) -> Language m ('Testing t))
-> Language m ('Testing t) -> Language m ('Testing t)
forall a b. (a -> b) -> a -> b
$ Free (ThenFree m t) a -> Language m ('Testing t)
forall (m :: * -> *) t a.
Free (ThenFree m t) a -> Language m ('Testing t)
thens Free (ThenFree m t) a
f
thens (Pure a
_) = Language m ('Testing t)
forall (m :: * -> *) (x :: Phase (*)). Language m x
End

bddFree :: Free (GivenFree m) x -> Language m 'Preparing
bddFree :: forall (m :: * -> *) x.
Free (GivenFree m) x -> Language m 'Preparing
bddFree (Free (GivenFree m b
m b -> Free (GivenFree m) x
f)) = m b -> (b -> Language m 'Preparing) -> Language m 'Preparing
forall (m :: * -> *) t.
m t -> (t -> Language m 'Preparing) -> Language m 'Preparing
Given m b
m ((b -> Language m 'Preparing) -> Language m 'Preparing)
-> (b -> Language m 'Preparing) -> Language m 'Preparing
forall a b. (a -> b) -> a -> b
$ Free (GivenFree m) x -> Language m 'Preparing
forall (m :: * -> *) x.
Free (GivenFree m) x -> Language m 'Preparing
bddFree (Free (GivenFree m) x -> Language m 'Preparing)
-> (b -> Free (GivenFree m) x) -> b -> Language m 'Preparing
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> b -> Free (GivenFree m) x
f
bddFree (Free (GivenAndAfterFree m (b, r)
mr r -> m ()
rm b -> Free (GivenFree m) x
f)) =
    m (b, r)
-> (r -> m ())
-> (b -> Language m 'Preparing)
-> Language m 'Preparing
forall (m :: * -> *) t r.
m (t, r)
-> (r -> m ())
-> (t -> Language m 'Preparing)
-> Language m 'Preparing
GivenAndAfter m (b, r)
mr r -> m ()
rm ((b -> Language m 'Preparing) -> Language m 'Preparing)
-> (b -> Language m 'Preparing) -> Language m 'Preparing
forall a b. (a -> b) -> a -> b
$ Free (GivenFree m) x -> Language m 'Preparing
forall (m :: * -> *) x.
Free (GivenFree m) x -> Language m 'Preparing
bddFree (Free (GivenFree m) x -> Language m 'Preparing)
-> (b -> Free (GivenFree m) x) -> b -> Language m 'Preparing
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> b -> Free (GivenFree m) x
f
bddFree (Free (WhenFree m t
mt Free (ThenFree m t) c
ts Free (GivenFree m) x
f)) = Language m 'Preparing
-> Language m 'Preparing -> Language m 'Preparing
forall (m :: * -> *).
Language m 'Preparing
-> Language m 'Preparing -> Language m 'Preparing
And (m t -> Language m ('Testing t) -> Language m 'Preparing
forall (m :: * -> *) t.
m t -> Language m ('Testing t) -> Language m 'Preparing
When m t
mt (Language m ('Testing t) -> Language m 'Preparing)
-> Language m ('Testing t) -> Language m 'Preparing
forall a b. (a -> b) -> a -> b
$ Free (ThenFree m t) c -> Language m ('Testing t)
forall (m :: * -> *) t a.
Free (ThenFree m t) a -> Language m ('Testing t)
thens Free (ThenFree m t) c
ts) (Free (GivenFree m) x -> Language m 'Preparing
forall (m :: * -> *) x.
Free (GivenFree m) x -> Language m 'Preparing
bddFree Free (GivenFree m) x
f)
bddFree (Pure x
_) = Language m 'Preparing
forall (m :: * -> *) (x :: Phase (*)). Language m x
End

-- | Add an assertion using the scenario action result.
then_ :: (t -> m ()) -> Free (ThenFree m t) ()
then_ :: forall t (m :: * -> *). (t -> m ()) -> Free (ThenFree m t) ()
then_ t -> m ()
m = ThenFree m t () -> Free (ThenFree m t) ()
forall (f :: * -> *) (m :: * -> *) a.
(Functor f, MonadFree f m) =>
f a -> m a
liftF (ThenFree m t () -> Free (ThenFree m t) ())
-> ThenFree m t () -> Free (ThenFree m t) ()
forall a b. (a -> b) -> a -> b
$ (t -> m ()) -> () -> ThenFree m t ()
forall (m :: * -> *) t a. (t -> m ()) -> a -> ThenFree m t a
ThenFree t -> m ()
m ()

-- | Add an assertion independent of the scenario action result.
then__ :: m () -> Free (ThenFree m t) ()
then__ :: forall (m :: * -> *) t. m () -> Free (ThenFree m t) ()
then__ = (t -> m ()) -> Free (ThenFree m t) ()
forall t (m :: * -> *). (t -> m ()) -> Free (ThenFree m t) ()
then_ ((t -> m ()) -> Free (ThenFree m t) ())
-> (m () -> t -> m ()) -> m () -> Free (ThenFree m t) ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m () -> t -> m ()
forall a b. a -> b -> a
const

-- | Execute a scenario and return its result with recorded teardown.
testFreeBDD
    :: (MonadCatch m)
    => Free (GivenFree m) x
    -> m (BDDResult m)
testFreeBDD :: forall (m :: * -> *) x.
MonadCatch m =>
Free (GivenFree m) x -> m (BDDResult m)
testFreeBDD = Language m 'Preparing -> m (BDDResult m)
forall (m :: * -> *).
MonadCatch m =>
Language m 'Preparing -> m (BDDResult m)
interpret (Language m 'Preparing -> m (BDDResult m))
-> (Free (GivenFree m) x -> Language m 'Preparing)
-> Free (GivenFree m) x
-> m (BDDResult m)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Free (GivenFree m) x -> Language m 'Preparing
forall (m :: * -> *) x.
Free (GivenFree m) x -> Language m 'Preparing
bddFree