{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Test.Hspec.Core.Spec.Monad (
-- RE-EXPORTED from Test.Hspec.Core.Spec
  Spec
, SpecWith
, SpecM (SpecM)
, runSpecM
, fromSpecList
, runIO

, mapSpecForest
, mapSpecItem
, mapSpecItem_
, modifyParams

, modifyConfig
-- END RE-EXPORTED from Test.Hspec.Core.Spec

, Env(..)
, withEnv
) where

import           Prelude ()
import           Test.Hspec.Core.Compat

import           Control.Monad.IO.Class (liftIO)
import           Control.Monad.Trans.Reader
import           Control.Monad.Trans.Writer

import           Test.Hspec.Core.Example
import           Test.Hspec.Core.Tree

import           Test.Hspec.Core.Config.Definition (Config)

type Spec = SpecWith ()

type SpecWith a = SpecM a ()

-- |
-- @since 2.10.0
modifyConfig :: (Config -> Config) -> SpecWith a
modifyConfig :: forall a. (Config -> Config) -> SpecWith a
modifyConfig Config -> Config
f = forall a r.
WriterT (Endo Config, [SpecTree a]) (ReaderT Env IO) r -> SpecM a r
SpecM forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) w. Monad m => w -> WriterT w m ()
tell (forall a. (a -> a) -> Endo a
Endo Config -> Config
f, forall a. Monoid a => a
mempty)

-- | A writer monad for `SpecTree` forests
newtype SpecM a r = SpecM { forall a r.
SpecM a r -> WriterT (Endo Config, [SpecTree a]) (ReaderT Env IO) r
unSpecM :: WriterT (Endo Config, [SpecTree a]) (ReaderT Env IO) r }
  deriving (forall a b. a -> SpecM a b -> SpecM a a
forall a b. (a -> b) -> SpecM a a -> SpecM a b
forall a a b. a -> SpecM a b -> SpecM a a
forall a a b. (a -> b) -> SpecM a a -> SpecM a b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> SpecM a b -> SpecM a a
$c<$ :: forall a a b. a -> SpecM a b -> SpecM a a
fmap :: forall a b. (a -> b) -> SpecM a a -> SpecM a b
$cfmap :: forall a a b. (a -> b) -> SpecM a a -> SpecM a b
Functor, forall a. Functor (SpecM a)
forall a. a -> SpecM a a
forall a a. a -> SpecM a a
forall a b. SpecM a a -> SpecM a b -> SpecM a a
forall a b. SpecM a a -> SpecM a b -> SpecM a b
forall a b. SpecM a (a -> b) -> SpecM a a -> SpecM a b
forall a a b. SpecM a a -> SpecM a b -> SpecM a a
forall a a b. SpecM a a -> SpecM a b -> SpecM a b
forall a a b. SpecM a (a -> b) -> SpecM a a -> SpecM a b
forall a b c. (a -> b -> c) -> SpecM a a -> SpecM a b -> SpecM a c
forall a a b c.
(a -> b -> c) -> SpecM a a -> SpecM a b -> SpecM a c
forall (f :: * -> *).
Functor f
-> (forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
<* :: forall a b. SpecM a a -> SpecM a b -> SpecM a a
$c<* :: forall a a b. SpecM a a -> SpecM a b -> SpecM a a
*> :: forall a b. SpecM a a -> SpecM a b -> SpecM a b
$c*> :: forall a a b. SpecM a a -> SpecM a b -> SpecM a b
liftA2 :: forall a b c. (a -> b -> c) -> SpecM a a -> SpecM a b -> SpecM a c
$cliftA2 :: forall a a b c.
(a -> b -> c) -> SpecM a a -> SpecM a b -> SpecM a c
<*> :: forall a b. SpecM a (a -> b) -> SpecM a a -> SpecM a b
$c<*> :: forall a a b. SpecM a (a -> b) -> SpecM a a -> SpecM a b
pure :: forall a. a -> SpecM a a
$cpure :: forall a a. a -> SpecM a a
Applicative, forall a. Applicative (SpecM a)
forall a. a -> SpecM a a
forall a a. a -> SpecM a a
forall a b. SpecM a a -> SpecM a b -> SpecM a b
forall a b. SpecM a a -> (a -> SpecM a b) -> SpecM a b
forall a a b. SpecM a a -> SpecM a b -> SpecM a b
forall a a b. SpecM a a -> (a -> SpecM a b) -> SpecM a b
forall (m :: * -> *).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
return :: forall a. a -> SpecM a a
$creturn :: forall a a. a -> SpecM a a
>> :: forall a b. SpecM a a -> SpecM a b -> SpecM a b
$c>> :: forall a a b. SpecM a a -> SpecM a b -> SpecM a b
>>= :: forall a b. SpecM a a -> (a -> SpecM a b) -> SpecM a b
$c>>= :: forall a a b. SpecM a a -> (a -> SpecM a b) -> SpecM a b
Monad)

-- | Convert a `Spec` to a forest of `SpecTree`s.
runSpecM :: SpecWith a -> IO (Endo Config, [SpecTree a])
runSpecM :: forall a. SpecWith a -> IO (Endo Config, [SpecTree a])
runSpecM = forall a b c. (a -> b -> c) -> b -> a -> c
flip forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ([String] -> Env
Env []) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) w a. Monad m => WriterT w m a -> m w
execWriterT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a r.
SpecM a r -> WriterT (Endo Config, [SpecTree a]) (ReaderT Env IO) r
unSpecM

-- | Create a `Spec` from a forest of `SpecTree`s.
fromSpecForest :: (Endo Config, [SpecTree a]) -> SpecWith a
fromSpecForest :: forall a. (Endo Config, [SpecTree a]) -> SpecWith a
fromSpecForest = forall a r.
WriterT (Endo Config, [SpecTree a]) (ReaderT Env IO) r -> SpecM a r
SpecM forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) w. Monad m => w -> WriterT w m ()
tell

-- | Create a `Spec` from a forest of `SpecTree`s.
fromSpecList :: [SpecTree a] -> SpecWith a
fromSpecList :: forall a. [SpecTree a] -> SpecWith a
fromSpecList = forall a. (Endo Config, [SpecTree a]) -> SpecWith a
fromSpecForest forall b c a. (b -> c) -> (a -> b) -> a -> c
. (,) forall a. Monoid a => a
mempty

-- | Run an IO action while constructing the spec tree.
--
-- `SpecM` is a monad to construct a spec tree, without executing any spec
-- items.  @runIO@ allows you to run IO actions during this construction phase.
-- The IO action is always run when the spec tree is constructed (e.g. even
-- when @--dry-run@ is specified).
-- If you do not need the result of the IO action to construct the spec tree,
-- `Test.Hspec.Core.Hooks.beforeAll` may be more suitable for your use case.
runIO :: IO r -> SpecM a r
runIO :: forall r a. IO r -> SpecM a r
runIO = forall a r.
WriterT (Endo Config, [SpecTree a]) (ReaderT Env IO) r -> SpecM a r
SpecM forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO

mapSpecForest :: ([SpecTree a] -> [SpecTree b]) -> SpecM a r -> SpecM b r
mapSpecForest :: forall a b r.
([SpecTree a] -> [SpecTree b]) -> SpecM a r -> SpecM b r
mapSpecForest [SpecTree a] -> [SpecTree b]
f (SpecM WriterT (Endo Config, [SpecTree a]) (ReaderT Env IO) r
specs) = forall a r.
WriterT (Endo Config, [SpecTree a]) (ReaderT Env IO) r -> SpecM a r
SpecM (forall (m :: * -> *) a w (n :: * -> *) b w'.
(m (a, w) -> n (b, w')) -> WriterT w m a -> WriterT w' n b
mapWriterT (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second [SpecTree a] -> [SpecTree b]
f))) WriterT (Endo Config, [SpecTree a]) (ReaderT Env IO) r
specs)

-- {-# DEPRECATED mapSpecItem "Use `mapSpecItem_` instead." #-}
-- | Deprecated: Use `mapSpecItem_` instead.
mapSpecItem :: (ActionWith a -> ActionWith b) -> (Item a -> Item b) -> SpecWith a -> SpecWith b
mapSpecItem :: forall a b.
(ActionWith a -> ActionWith b)
-> (Item a -> Item b) -> SpecWith a -> SpecWith b
mapSpecItem ActionWith a -> ActionWith b
_ = forall a b. (Item a -> Item b) -> SpecWith a -> SpecWith b
mapSpecItem_

mapSpecItem_ :: (Item a -> Item b) -> SpecWith a -> SpecWith b
mapSpecItem_ :: forall a b. (Item a -> Item b) -> SpecWith a -> SpecWith b
mapSpecItem_ = forall a b r.
([SpecTree a] -> [SpecTree b]) -> SpecM a r -> SpecM b r
mapSpecForest forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b c d. (a -> b) -> (c -> d) -> [Tree a c] -> [Tree b d]
bimapForest forall a. a -> a
id

modifyParams :: (Params -> Params) -> SpecWith a -> SpecWith a
modifyParams :: forall a. (Params -> Params) -> SpecWith a -> SpecWith a
modifyParams Params -> Params
f = forall a b. (Item a -> Item b) -> SpecWith a -> SpecWith b
mapSpecItem_ forall a b. (a -> b) -> a -> b
$ \Item a
item -> Item a
item {itemExample :: Params -> (ActionWith a -> IO ()) -> ProgressCallback -> IO Result
itemExample = \Params
p -> (forall a.
Item a
-> Params
-> (ActionWith a -> IO ())
-> ProgressCallback
-> IO Result
itemExample Item a
item) (Params -> Params
f Params
p)}

newtype Env = Env {
  Env -> [String]
envSpecDescriptionPath :: [String]
}

withEnv :: (Env -> Env) -> SpecM a r -> SpecM a r
withEnv :: forall a r. (Env -> Env) -> SpecM a r -> SpecM a r
withEnv Env -> Env
f = forall a r.
WriterT (Endo Config, [SpecTree a]) (ReaderT Env IO) r -> SpecM a r
SpecM forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall w (m :: * -> *) a. m (a, w) -> WriterT w m a
WriterT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall r (m :: * -> *) a.
(r -> r) -> ReaderT r m a -> ReaderT r m a
local Env -> Env
f forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall w (m :: * -> *) a. WriterT w m a -> m (a, w)
runWriterT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a r.
SpecM a r -> WriterT (Endo Config, [SpecTree a]) (ReaderT Env IO) r
unSpecM