{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ConstraintKinds #-}
module Test.Hspec.Core.Hooks (
before
, before_
, beforeWith
, beforeAll
, beforeAll_
, beforeAllWith
, after
, after_
, afterAll
, afterAll_
, around
, around_
, aroundWith
, aroundAll
, aroundAll_
, aroundAllWith
, mapSubject
, ignoreSubject
) where
import Prelude ()
import Test.Hspec.Core.Compat
import Data.CallStack
import Control.Exception (SomeException, finally, throwIO, try, catch)
import Control.Concurrent.MVar
import Control.Concurrent.Async
import Test.Hspec.Core.Example
import Test.Hspec.Core.Tree
import Test.Hspec.Core.Spec.Monad
before :: IO a -> SpecWith a -> Spec
before :: forall a. IO a -> SpecWith a -> Spec
before IO a
action = forall a. (ActionWith a -> IO ()) -> SpecWith a -> Spec
around (IO a
action forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>=)
before_ :: IO () -> SpecWith a -> SpecWith a
before_ :: forall a. IO () -> SpecWith a -> SpecWith a
before_ IO ()
action = forall a. (IO () -> IO ()) -> SpecWith a -> SpecWith a
around_ (IO ()
action forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>>)
beforeWith :: (b -> IO a) -> SpecWith a -> SpecWith b
beforeWith :: forall b a. (b -> IO a) -> SpecWith a -> SpecWith b
beforeWith b -> IO a
action = forall a b.
(ActionWith a -> ActionWith b) -> SpecWith a -> SpecWith b
aroundWith forall a b. (a -> b) -> a -> b
$ \ActionWith a
e b
x -> b -> IO a
action b
x forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= ActionWith a
e
beforeAll :: HasCallStack => IO a -> SpecWith a -> Spec
beforeAll :: forall a. HasCallStack => IO a -> SpecWith a -> Spec
beforeAll IO a
action SpecWith a
spec = do
MVar (Memoized a)
mvar <- forall r a. IO r -> SpecM a r
runIO (forall a. a -> IO (MVar a)
newMVar forall a. Memoized a
Empty)
forall a. IO a -> SpecWith a -> Spec
before (forall a. HasCallStack => MVar (Memoized a) -> IO a -> IO a
memoize MVar (Memoized a)
mvar IO a
action) SpecWith a
spec
beforeAll_ :: HasCallStack => IO () -> SpecWith a -> SpecWith a
beforeAll_ :: forall a. HasCallStack => IO () -> SpecWith a -> SpecWith a
beforeAll_ IO ()
action SpecWith a
spec = do
MVar (Memoized ())
mvar <- forall r a. IO r -> SpecM a r
runIO (forall a. a -> IO (MVar a)
newMVar forall a. Memoized a
Empty)
forall a. IO () -> SpecWith a -> SpecWith a
before_ (forall a. HasCallStack => MVar (Memoized a) -> IO a -> IO a
memoize MVar (Memoized ())
mvar IO ()
action) SpecWith a
spec
beforeAllWith :: HasCallStack => (b -> IO a) -> SpecWith a -> SpecWith b
beforeAllWith :: forall b a. HasCallStack => (b -> IO a) -> SpecWith a -> SpecWith b
beforeAllWith b -> IO a
action SpecWith a
spec = do
MVar (Memoized a)
mvar <- forall r a. IO r -> SpecM a r
runIO (forall a. a -> IO (MVar a)
newMVar forall a. Memoized a
Empty)
forall b a. (b -> IO a) -> SpecWith a -> SpecWith b
beforeWith (forall a. HasCallStack => MVar (Memoized a) -> IO a -> IO a
memoize MVar (Memoized a)
mvar forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> IO a
action) SpecWith a
spec
data Memoized a =
Empty
| Memoized a
| Failed SomeException
memoize :: HasCallStack => MVar (Memoized a) -> IO a -> IO a
memoize :: forall a. HasCallStack => MVar (Memoized a) -> IO a -> IO a
memoize MVar (Memoized a)
mvar IO a
action = do
Either SomeException a
result <- forall a b. MVar a -> (a -> IO (a, b)) -> IO b
modifyMVar MVar (Memoized a)
mvar forall a b. (a -> b) -> a -> b
$ \Memoized a
ma -> case Memoized a
ma of
Memoized a
Empty -> do
Either SomeException a
a <- forall e a. Exception e => IO a -> IO (Either e a)
try IO a
action
forall (m :: * -> *) a. Monad m => a -> m a
return (forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall a. SomeException -> Memoized a
Failed forall a. a -> Memoized a
Memoized Either SomeException a
a, Either SomeException a
a)
Memoized a
a -> forall (m :: * -> *) a. Monad m => a -> m a
return (Memoized a
ma, forall a b. b -> Either a b
Right a
a)
Failed SomeException
_ -> forall e a. Exception e => e -> IO a
throwIO (Maybe Location -> Maybe String -> ResultStatus
Pending forall a. Maybe a
Nothing (forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ String
"exception in " forall a. Semigroup a => a -> a -> a
<> forall b a. b -> (a -> b) -> Maybe a -> b
maybe String
"beforeAll" forall a b. (a, b) -> a
fst HasCallStack => Maybe (String, SrcLoc)
callSite forall a. Semigroup a => a -> a -> a
<> String
"-hook (see previous failure)"))
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall e a. Exception e => e -> IO a
throwIO forall (m :: * -> *) a. Monad m => a -> m a
return Either SomeException a
result
after :: ActionWith a -> SpecWith a -> SpecWith a
after :: forall a. ActionWith a -> SpecWith a -> SpecWith a
after ActionWith a
action = forall a b.
(ActionWith a -> ActionWith b) -> SpecWith a -> SpecWith b
aroundWith forall a b. (a -> b) -> a -> b
$ \ActionWith a
e a
x -> ActionWith a
e a
x forall a b. IO a -> IO b -> IO a
`finally` ActionWith a
action a
x
after_ :: IO () -> SpecWith a -> SpecWith a
after_ :: forall a. IO () -> SpecWith a -> SpecWith a
after_ IO ()
action = forall a. ActionWith a -> SpecWith a -> SpecWith a
after forall a b. (a -> b) -> a -> b
$ \a
_ -> IO ()
action
around :: (ActionWith a -> IO ()) -> SpecWith a -> Spec
around :: forall a. (ActionWith a -> IO ()) -> SpecWith a -> Spec
around ActionWith a -> IO ()
action = forall a b.
(ActionWith a -> ActionWith b) -> SpecWith a -> SpecWith b
aroundWith forall a b. (a -> b) -> a -> b
$ \ActionWith a
e () -> ActionWith a -> IO ()
action ActionWith a
e
afterAll :: HasCallStack => ActionWith a -> SpecWith a -> SpecWith a
afterAll :: forall a. HasCallStack => ActionWith a -> SpecWith a -> SpecWith a
afterAll ActionWith a
action = forall a b r.
([SpecTree a] -> [SpecTree b]) -> SpecM a r -> SpecM b r
mapSpecForest (forall (m :: * -> *) a. Monad m => a -> m a
return forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall c a. Maybe Location -> c -> [Tree c a] -> Tree c a
NodeWithCleanup HasCallStack => Maybe Location
location ActionWith a
action)
afterAll_ :: HasCallStack => IO () -> SpecWith a -> SpecWith a
afterAll_ :: forall a. HasCallStack => IO () -> SpecWith a -> SpecWith a
afterAll_ IO ()
action = forall a. HasCallStack => ActionWith a -> SpecWith a -> SpecWith a
afterAll (\a
_ -> IO ()
action)
around_ :: (IO () -> IO ()) -> SpecWith a -> SpecWith a
around_ :: forall a. (IO () -> IO ()) -> SpecWith a -> SpecWith a
around_ IO () -> IO ()
action = forall a b.
(ActionWith a -> ActionWith b) -> SpecWith a -> SpecWith b
aroundWith forall a b. (a -> b) -> a -> b
$ \ActionWith a
e a
a -> IO () -> IO ()
action (ActionWith a
e a
a)
aroundWith :: (ActionWith a -> ActionWith b) -> SpecWith a -> SpecWith b
aroundWith :: forall a b.
(ActionWith a -> ActionWith b) -> SpecWith a -> SpecWith b
aroundWith ActionWith a -> ActionWith b
action = forall a b.
(ActionWith a -> ActionWith b)
-> (Item a -> Item b) -> SpecWith a -> SpecWith b
mapSpecItem ActionWith a -> ActionWith b
action (forall a b. (ActionWith a -> ActionWith b) -> Item a -> Item b
modifyAroundAction ActionWith a -> ActionWith b
action)
modifyAroundAction :: (ActionWith a -> ActionWith b) -> Item a -> Item b
modifyAroundAction :: forall a b. (ActionWith a -> ActionWith b) -> Item a -> Item b
modifyAroundAction ActionWith a -> ActionWith b
action item :: Item a
item@Item{itemExample :: forall a.
Item a
-> Params
-> (ActionWith a -> IO ())
-> ProgressCallback
-> IO Result
itemExample = Params -> (ActionWith a -> IO ()) -> ProgressCallback -> IO Result
e} =
Item a
item{ itemExample :: Params -> (ActionWith b -> IO ()) -> ProgressCallback -> IO Result
itemExample = \Params
params ActionWith b -> IO ()
aroundAction -> Params -> (ActionWith a -> IO ()) -> ProgressCallback -> IO Result
e Params
params (ActionWith b -> IO ()
aroundAction forall b c a. (b -> c) -> (a -> b) -> a -> c
. ActionWith a -> ActionWith b
action) }
aroundAll :: HasCallStack => (ActionWith a -> IO ()) -> SpecWith a -> Spec
aroundAll :: forall a.
HasCallStack =>
(ActionWith a -> IO ()) -> SpecWith a -> Spec
aroundAll ActionWith a -> IO ()
action = forall a b.
HasCallStack =>
(ActionWith a -> ActionWith b) -> SpecWith a -> SpecWith b
aroundAllWith forall a b. (a -> b) -> a -> b
$ \ ActionWith a
e () -> ActionWith a -> IO ()
action ActionWith a
e
aroundAll_ :: HasCallStack => (IO () -> IO ()) -> SpecWith a -> SpecWith a
aroundAll_ :: forall a.
HasCallStack =>
(IO () -> IO ()) -> SpecWith a -> SpecWith a
aroundAll_ IO () -> IO ()
action SpecWith a
spec = do
MVar ()
allSpecItemsDone <- forall r a. IO r -> SpecM a r
runIO forall a. IO (MVar a)
newEmptyMVar
MVar (Async ())
workerRef <- forall r a. IO r -> SpecM a r
runIO forall a. IO (MVar a)
newEmptyMVar
let
acquire :: IO ()
acquire :: IO ()
acquire = do
MVar ()
resource <- forall a. IO (MVar a)
newEmptyMVar
Async ()
worker <- forall a. IO a -> IO (Async a)
async forall a b. (a -> b) -> a -> b
$ do
IO () -> IO ()
action forall a b. (a -> b) -> a -> b
$ do
MVar () -> IO ()
signal MVar ()
resource
MVar () -> IO ()
waitFor MVar ()
allSpecItemsDone
forall a. MVar a -> a -> IO ()
putMVar MVar (Async ())
workerRef Async ()
worker
forall a. IO a -> IO a
unwrapExceptionsFromLinkedThread forall a b. (a -> b) -> a -> b
$ do
forall a. Async a -> IO ()
link Async ()
worker
MVar () -> IO ()
waitFor MVar ()
resource
release :: IO ()
release :: IO ()
release = MVar () -> IO ()
signal MVar ()
allSpecItemsDone forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall a. MVar a -> IO a
takeMVar MVar (Async ())
workerRef forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall a. Async a -> IO a
wait
forall a. HasCallStack => IO () -> SpecWith a -> SpecWith a
beforeAll_ IO ()
acquire forall a b. (a -> b) -> a -> b
$ forall a. HasCallStack => IO () -> SpecWith a -> SpecWith a
afterAll_ IO ()
release SpecWith a
spec
aroundAllWith :: forall a b. HasCallStack => (ActionWith a -> ActionWith b) -> SpecWith a -> SpecWith b
aroundAllWith :: forall a b.
HasCallStack =>
(ActionWith a -> ActionWith b) -> SpecWith a -> SpecWith b
aroundAllWith ActionWith a -> ActionWith b
action SpecWith a
spec = do
MVar ()
allSpecItemsDone <- forall r a. IO r -> SpecM a r
runIO forall a. IO (MVar a)
newEmptyMVar
MVar (Async ())
workerRef <- forall r a. IO r -> SpecM a r
runIO forall a. IO (MVar a)
newEmptyMVar
let
acquire :: b -> IO a
acquire :: b -> IO a
acquire b
b = do
MVar a
resource <- forall a. IO (MVar a)
newEmptyMVar
Async ()
worker <- forall a. IO a -> IO (Async a)
async forall a b. (a -> b) -> a -> b
$ do
forall a b c. (a -> b -> c) -> b -> a -> c
flip ActionWith a -> ActionWith b
action b
b forall a b. (a -> b) -> a -> b
$ \ a
a -> do
forall a. MVar a -> a -> IO ()
putMVar MVar a
resource a
a
MVar () -> IO ()
waitFor MVar ()
allSpecItemsDone
forall a. MVar a -> a -> IO ()
putMVar MVar (Async ())
workerRef Async ()
worker
forall a. IO a -> IO a
unwrapExceptionsFromLinkedThread forall a b. (a -> b) -> a -> b
$ do
forall a. Async a -> IO ()
link Async ()
worker
forall a. MVar a -> IO a
takeMVar MVar a
resource
release :: IO ()
release :: IO ()
release = MVar () -> IO ()
signal MVar ()
allSpecItemsDone forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall a. MVar a -> IO a
takeMVar MVar (Async ())
workerRef forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= forall a. Async a -> IO a
wait
forall b a. HasCallStack => (b -> IO a) -> SpecWith a -> SpecWith b
beforeAllWith b -> IO a
acquire forall a b. (a -> b) -> a -> b
$ forall a. HasCallStack => IO () -> SpecWith a -> SpecWith a
afterAll_ IO ()
release SpecWith a
spec
unwrapExceptionsFromLinkedThread :: IO a -> IO a
unwrapExceptionsFromLinkedThread :: forall a. IO a -> IO a
unwrapExceptionsFromLinkedThread = (forall e a. Exception e => IO a -> (e -> IO a) -> IO a
`catch` \ (ExceptionInLinkedThread Async a
_ SomeException
e) -> forall e a. Exception e => e -> IO a
throwIO SomeException
e)
type BinarySemaphore = MVar ()
signal :: BinarySemaphore -> IO ()
signal :: MVar () -> IO ()
signal = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a. MVar a -> a -> IO ()
putMVar ()
waitFor :: BinarySemaphore -> IO ()
waitFor :: MVar () -> IO ()
waitFor = forall a. MVar a -> IO a
takeMVar
mapSubject :: (b -> a) -> SpecWith a -> SpecWith b
mapSubject :: forall b a. (b -> a) -> SpecWith a -> SpecWith b
mapSubject b -> a
f = forall a b.
(ActionWith a -> ActionWith b) -> SpecWith a -> SpecWith b
aroundWith (forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> a
f)
ignoreSubject :: SpecWith () -> SpecWith a
ignoreSubject :: forall a. Spec -> SpecWith a
ignoreSubject = forall b a. (b -> a) -> SpecWith a -> SpecWith b
mapSubject (forall a b. a -> b -> a
const ())