    {-# LANGUAGE CPP #-}
    {-# LANGUAGE FlexibleContexts #-}
    {-# LANGUAGE ConstraintKinds #-}
    -- |
    -- Stability: unstable
    --
    -- This module provides access to Hspec's internals.  It is less stable than
    -- other parts of the API. For most users @Test.Hspec@ is more suitable!
    module Test.Hspec.Core.Spec (

    -- * Defining a spec
      it
    , specify
    , describe
    , context
    , pending
    , pendingWith
    , xit
    , xspecify
    , xdescribe
    , xcontext

    -- * Focused spec items #focus#
    -- |
    -- During a test run, when a spec contains /focused/ spec items, all other spec
    -- items are ignored.
    , focus
    , fit
    , fspecify
    , fdescribe
    , fcontext

    , parallel
    , sequential

    -- * The @SpecM@ monad
    , Test.Hspec.Core.Spec.Monad.Spec
    , Test.Hspec.Core.Spec.Monad.SpecWith
    , Test.Hspec.Core.Spec.Monad.SpecM(..)
    , Test.Hspec.Core.Spec.Monad.runSpecM
    , Test.Hspec.Core.Spec.Monad.fromSpecList
    , Test.Hspec.Core.Spec.Monad.runIO
    , Test.Hspec.Core.Spec.Monad.mapSpecForest
    , Test.Hspec.Core.Spec.Monad.mapSpecItem
    , Test.Hspec.Core.Spec.Monad.mapSpecItem_
    , Test.Hspec.Core.Spec.Monad.modifyParams
    , Test.Hspec.Core.Spec.Monad.modifyConfig
    , getSpecDescriptionPath

    -- * A type class for examples
    , Test.Hspec.Core.Example.Example (..)
    #ifndef ENABLE_SPEC_HOOK_ARGS
    , Test.Hspec.Core.Example.Arg
    #endif
    , Test.Hspec.Core.Example.Params (..)
    , Test.Hspec.Core.Example.defaultParams
    , Test.Hspec.Core.Example.ActionWith
    , Test.Hspec.Core.Example.Progress
    , Test.Hspec.Core.Example.ProgressCallback
    , Test.Hspec.Core.Example.Result(..)
    , Test.Hspec.Core.Example.ResultStatus (..)
    , Test.Hspec.Core.Example.Location (..)
    , Test.Hspec.Core.Example.FailureReason (..)
    , Test.Hspec.Core.Example.safeEvaluate
    , Test.Hspec.Core.Example.safeEvaluateExample

    -- * Internal representation of a spec tree
    , Test.Hspec.Core.Tree.SpecTree
    , Test.Hspec.Core.Tree.Tree (..)
    , Test.Hspec.Core.Tree.Item (..)
    , Test.Hspec.Core.Tree.specGroup
    , Test.Hspec.Core.Tree.specItem
    , Test.Hspec.Core.Tree.bimapTree
    , Test.Hspec.Core.Tree.bimapForest
    , Test.Hspec.Core.Tree.filterTree
    , Test.Hspec.Core.Tree.filterForest
    , Test.Hspec.Core.Tree.filterTreeWithLabels
    , Test.Hspec.Core.Tree.filterForestWithLabels
    , Test.Hspec.Core.Tree.pruneTree -- unused
    , Test.Hspec.Core.Tree.pruneForest -- unused
    , Test.Hspec.Core.Tree.location

    , focusForest

    -- * Re-exports
    , HasCallStack
    , Expectation
    ) where

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

    import           Control.Monad.Trans.Class (lift)
    import           Control.Monad.Trans.Reader (asks)

    import           Test.Hspec.Expectations (Expectation)

    import           Test.Hspec.Core.Example
    #ifdef ENABLE_SPEC_HOOKS
    import           Test.Hspec.Core.Hooks
    #endif
    import           Test.Hspec.Core.Tree
    import           Test.Hspec.Core.Spec.Monad
    import           Test.Hspec.Core.QuickCheck ()

    -- | The @describe@ function combines a list of specs into a larger spec.
    describe :: HasCallStack => String -> SpecWith a -> SpecWith a
    describe :: forall a. HasCallStack => String -> SpecWith a -> SpecWith a
    describe String
    label = (Env -> Env) -> SpecM a () -> SpecM a ()
    forall a r. (Env -> Env) -> SpecM a r -> SpecM a r
    withEnv Env -> Env
    pushLabel (SpecM a () -> SpecM a ())
    -> (SpecM a () -> SpecM a ()) -> SpecM a () -> SpecM a ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . ([SpecTree a] -> [SpecTree a]) -> SpecM a () -> SpecM a ()
    forall a b r.
    ([SpecTree a] -> [SpecTree b]) -> SpecM a r -> SpecM b r
    mapSpecForest (SpecTree a -> [SpecTree a]
    forall a. a -> [a]
    forall (m :: * -> *) a. Monad m => a -> m a
    return (SpecTree a -> [SpecTree a])
    -> ([SpecTree a] -> SpecTree a) -> [SpecTree a] -> [SpecTree a]
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> [SpecTree a] -> SpecTree a
    forall a. HasCallStack => String -> [SpecTree a] -> SpecTree a
    specGroup String
    label)
      where
        pushLabel :: Env -> Env
    pushLabel (Env [String]
    labels) = [String] -> Env
    Env ([String] -> Env) -> [String] -> Env
    forall a b. (a -> b) -> a -> b
    $ String
    label String -> [String] -> [String]
    forall a. a -> [a] -> [a]
    : [String]
    labels

    -- | @context@ is an alias for `describe`.
    context :: HasCallStack => String -> SpecWith a -> SpecWith a
    context :: forall a. HasCallStack => String -> SpecWith a -> SpecWith a
    context = String -> SpecWith a -> SpecWith a
    forall a. HasCallStack => String -> SpecWith a -> SpecWith a
    describe

    -- |
    -- Changing `describe` to `xdescribe` marks all spec items of the corresponding subtree as pending.
    --
    -- This can be used to temporarily disable spec items.
    xdescribe :: HasCallStack => String -> SpecWith a -> SpecWith a
    #ifdef ENABLE_SPEC_HOOKS
    xdescribe :: forall a. HasCallStack => String -> SpecWith a -> SpecWith a
    xdescribe String
    label SpecWith a
    spec = IO () -> SpecWith a -> SpecWith a
    forall a. IO () -> SpecWith a -> SpecWith a
    before_ IO ()
    pending_ (SpecWith a -> SpecWith a) -> SpecWith a -> SpecWith a
    forall a b. (a -> b) -> a -> b
    $ String -> SpecWith a -> SpecWith a
    forall a. HasCallStack => String -> SpecWith a -> SpecWith a
    describe String
    label SpecWith a
    spec
    #else
    xdescribe = describe
    #endif

    -- | @xcontext@ is an alias for `xdescribe`.
    xcontext :: HasCallStack => String -> SpecWith a -> SpecWith a
    xcontext :: forall a. HasCallStack => String -> SpecWith a -> SpecWith a
    xcontext = String -> SpecWith a -> SpecWith a
    forall a. HasCallStack => String -> SpecWith a -> SpecWith a
    xdescribe

    -- | The @it@ function creates a spec item.
    --
    -- A spec item consists of:
    --
    -- * a textual description of a desired behavior
    --
    -- * an example for that behavior
    --
    -- > describe "absolute" $ do
    -- >   it "returns a positive number when given a negative number" $
    -- >     absolute (-1) == 1
    --
    -- @`Example` a@ optionally accepts an argument @`Arg` a@, which is then given
    -- to the test body. This is useful for provisioning resources for a test which
    -- are created and cleaned up outside the test itself. See `Arg` for details.
    --
    -- Note that this function is often on the scene of nasty type errors due to GHC failing
    -- to infer the type of @do@ notation in the test body.
    -- It can be helpful to use
    -- [TypeApplications](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/type_applications.html)
    -- to explicitly specify the intended `Example` type.
    it :: (HasCallStack, Example a) => String -> a -> SpecWith (Arg a)
    it :: forall a.
    (HasCallStack, Example a) =>
    String -> a -> SpecWith (Arg a)
    it String
    label a
    action = [SpecTree (Arg a)] -> SpecM (Arg a) ()
    forall a. [SpecTree a] -> SpecWith a
    fromSpecList [String -> a -> SpecTree (Arg a)
    forall e.
    (HasCallStack, Example e) =>
    String -> e -> SpecTree (Arg e)
    specItem String
    label a
    action]

    -- | @specify@ is an alias for `it`.
    specify :: (HasCallStack, Example a) => String -> a -> SpecWith (Arg a)
    specify :: forall a.
    (HasCallStack, Example a) =>
    String -> a -> SpecWith (Arg a)
    specify = String -> a -> SpecWith (Arg a)
    forall a.
    (HasCallStack, Example a) =>
    String -> a -> SpecWith (Arg a)
    it

    -- |
    -- Changing `it` to `xit` marks the corresponding spec item as pending.
    --
    -- This can be used to temporarily disable a spec item.
    xit :: (HasCallStack, Example a) => String -> a -> SpecWith (Arg a)
    #ifdef ENABLE_SPEC_HOOKS
    xit :: forall a.
    (HasCallStack, Example a) =>
    String -> a -> SpecWith (Arg a)
    xit String
    label a
    action = IO () -> SpecWith (Arg a) -> SpecWith (Arg a)
    forall a. IO () -> SpecWith a -> SpecWith a
    before_ IO ()
    pending_ (SpecWith (Arg a) -> SpecWith (Arg a))
    -> SpecWith (Arg a) -> SpecWith (Arg a)
    forall a b. (a -> b) -> a -> b
    $ String -> a -> SpecWith (Arg a)
    forall a.
    (HasCallStack, Example a) =>
    String -> a -> SpecWith (Arg a)
    it String
    label a
    action
    #else
    xit = it
    #endif

    -- | @xspecify@ is an alias for `xit`.
    xspecify :: (HasCallStack, Example a) => String -> a -> SpecWith (Arg a)
    xspecify :: forall a.
    (HasCallStack, Example a) =>
    String -> a -> SpecWith (Arg a)
    xspecify = String -> a -> SpecWith (Arg a)
    forall a.
    (HasCallStack, Example a) =>
    String -> a -> SpecWith (Arg a)
    xit

    -- | `focus` focuses all spec items of the given spec.
    --
    -- Applying `focus` to a spec with focused spec items has no effect.
    focus :: SpecWith a -> SpecWith a
    focus :: forall a. SpecWith a -> SpecWith a
    focus = ([SpecTree a] -> [SpecTree a]) -> SpecM a () -> SpecM a ()
    forall a b r.
    ([SpecTree a] -> [SpecTree b]) -> SpecM a r -> SpecM b r
    mapSpecForest [SpecTree a] -> [SpecTree a]
    forall a. [SpecTree a] -> [SpecTree a]
    focusForest

    -- | Marks an entire spec forest as focused if nothing in it is already focused.
    focusForest :: [SpecTree a] -> [SpecTree a]
    focusForest :: forall a. [SpecTree a] -> [SpecTree a]
    focusForest [SpecTree a]
    xs
      | (SpecTree a -> Bool) -> [SpecTree a] -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any ((Item a -> Bool) -> SpecTree a -> Bool
    forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Bool
    any Item a -> Bool
    forall a. Item a -> Bool
    itemIsFocused) [SpecTree a]
    xs = [SpecTree a]
    xs
      | Bool
    otherwise = (IO () -> IO ())
    -> (Item a -> Item a) -> [SpecTree a] -> [SpecTree a]
    forall a b c d. (a -> b) -> (c -> d) -> [Tree a c] -> [Tree b d]
    bimapForest IO () -> IO ()
    forall a. a -> a
    id (\ Item a
    item -> Item a
    item {itemIsFocused = True}) [SpecTree a]
    xs

    -- | @fit@ is an alias for @fmap focus . it@
    fit :: (HasCallStack, Example a) => String -> a -> SpecWith (Arg a)
    fit :: forall a.
    (HasCallStack, Example a) =>
    String -> a -> SpecWith (Arg a)
    fit = (SpecM (Arg a) () -> SpecM (Arg a) ())
    -> (a -> SpecM (Arg a) ()) -> a -> SpecM (Arg a) ()
    forall a b. (a -> b) -> (a -> a) -> a -> b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap SpecM (Arg a) () -> SpecM (Arg a) ()
    forall a. SpecWith a -> SpecWith a
    focus ((a -> SpecM (Arg a) ()) -> a -> SpecM (Arg a) ())
    -> (String -> a -> SpecM (Arg a) ())
    -> String
    -> a
    -> SpecM (Arg a) ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> a -> SpecM (Arg a) ()
    forall a.
    (HasCallStack, Example a) =>
    String -> a -> SpecWith (Arg a)
    it

    -- | @fspecify@ is an alias for `fit`.
    fspecify :: (HasCallStack, Example a) => String -> a -> SpecWith (Arg a)
    fspecify :: forall a.
    (HasCallStack, Example a) =>
    String -> a -> SpecWith (Arg a)
    fspecify = String -> a -> SpecWith (Arg a)
    forall a.
    (HasCallStack, Example a) =>
    String -> a -> SpecWith (Arg a)
    fit

    -- | @fdescribe@ is an alias for @fmap focus . describe@
    fdescribe :: HasCallStack => String -> SpecWith a -> SpecWith a
    fdescribe :: forall a. HasCallStack => String -> SpecWith a -> SpecWith a
    fdescribe = (SpecWith a -> SpecWith a)
    -> (SpecWith a -> SpecWith a) -> SpecWith a -> SpecWith a
    forall a b. (a -> b) -> (SpecWith a -> a) -> SpecWith a -> b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap SpecWith a -> SpecWith a
    forall a. SpecWith a -> SpecWith a
    focus ((SpecWith a -> SpecWith a) -> SpecWith a -> SpecWith a)
    -> (String -> SpecWith a -> SpecWith a)
    -> String
    -> SpecWith a
    -> SpecWith a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> SpecWith a -> SpecWith a
    forall a. HasCallStack => String -> SpecWith a -> SpecWith a
    describe

    -- | @fcontext@ is an alias for `fdescribe`.
    fcontext :: HasCallStack => String -> SpecWith a -> SpecWith a
    fcontext :: forall a. HasCallStack => String -> SpecWith a -> SpecWith a
    fcontext = String -> SpecWith a -> SpecWith a
    forall a. HasCallStack => String -> SpecWith a -> SpecWith a
    fdescribe

    -- | `parallel` marks all spec items of the given spec to be safe for parallel
    -- evaluation.
    parallel :: SpecWith a -> SpecWith a
    parallel :: forall a. SpecWith a -> SpecWith a
    parallel = (Item a -> Item a) -> SpecWith a -> SpecWith a
    forall a b. (Item a -> Item b) -> SpecWith a -> SpecWith b
    mapSpecItem_ (Bool -> Item a -> Item a
    forall a. Bool -> Item a -> Item a
    setParallelizable Bool
    True)

    -- | `sequential` marks all spec items of the given spec to be evaluated sequentially.
    sequential :: SpecWith a -> SpecWith a
    sequential :: forall a. SpecWith a -> SpecWith a
    sequential = (Item a -> Item a) -> SpecWith a -> SpecWith a
    forall a b. (Item a -> Item b) -> SpecWith a -> SpecWith b
    mapSpecItem_ (Bool -> Item a -> Item a
    forall a. Bool -> Item a -> Item a
    setParallelizable Bool
    False)

    setParallelizable :: Bool -> Item a -> Item a
    setParallelizable :: forall a. Bool -> Item a -> Item a
    setParallelizable Bool
    value Item a
    item = Item a
    item {itemIsParallelizable = itemIsParallelizable item <|> Just value}

    -- | `pending` can be used to mark a spec item as pending.
    --
    -- If you want to textually specify a behavior but do not have an example yet,
    -- use this:
    --
    -- > describe "fancyFormatter" $ do
    -- >   it "can format text in a way that everyone likes" $
    -- >     pending
    pending :: HasCallStack => Expectation
    pending :: HasCallStack => IO ()
    pending = ResultStatus -> IO ()
    forall e a. (HasCallStack, Exception e) => e -> IO a
    throwIO (Maybe Location -> Maybe String -> ResultStatus
    Pending Maybe Location
    HasCallStack => Maybe Location
    location Maybe String
    forall a. Maybe a
    Nothing)

    #ifdef ENABLE_SPEC_HOOKS
    pending_ :: Expectation
    pending_ :: IO ()
    pending_ = (ResultStatus -> IO ()
    forall e a. (HasCallStack, Exception e) => e -> IO a
    throwIO (Maybe Location -> Maybe String -> ResultStatus
    Pending Maybe Location
    forall a. Maybe a
    Nothing Maybe String
    forall a. Maybe a
    Nothing))
    #endif

    -- |
    -- `pendingWith` is similar to `pending`, but it takes an additional string
    -- argument that can be used to specify the reason for why the spec item is pending.
    pendingWith :: HasCallStack => String -> Expectation
    pendingWith :: HasCallStack => String -> IO ()
    pendingWith = ResultStatus -> IO ()
    forall e a. (HasCallStack, Exception e) => e -> IO a
    throwIO (ResultStatus -> IO ())
    -> (String -> ResultStatus) -> String -> IO ()
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Maybe Location -> Maybe String -> ResultStatus
    Pending Maybe Location
    HasCallStack => Maybe Location
    location (Maybe String -> ResultStatus)
    -> (String -> Maybe String) -> String -> ResultStatus
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . String -> Maybe String
    forall a. a -> Maybe a
    Just

    -- | Get the path of `describe` labels, from the root all the way in to the
    -- call-site of this function.
    --
    -- ==== __Example__
    -- >>> :{
    -- runSpecM $ do
    --   describe "foo" $ do
    --     describe "bar" $ do
    --       getSpecDescriptionPath >>= runIO . print
    -- :}
    -- ["foo","bar"]
    --
    -- @since 2.10.0
    getSpecDescriptionPath :: SpecM a [String]
    getSpecDescriptionPath :: forall a. SpecM a [String]
    getSpecDescriptionPath = WriterT (Endo Config, [SpecTree a]) (ReaderT Env IO) [String]
    -> SpecM a [String]
    forall a r.
    WriterT (Endo Config, [SpecTree a]) (ReaderT Env IO) r -> SpecM a r
    SpecM (WriterT (Endo Config, [SpecTree a]) (ReaderT Env IO) [String]
     -> SpecM a [String])
    -> WriterT (Endo Config, [SpecTree a]) (ReaderT Env IO) [String]
    -> SpecM a [String]
    forall a b. (a -> b) -> a -> b
    $ ReaderT Env IO [String]
    -> WriterT (Endo Config, [SpecTree a]) (ReaderT Env IO) [String]
    forall (m :: * -> *) a.
    Monad m =>
    m a -> WriterT (Endo Config, [SpecTree a]) m a
    forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
    (MonadTrans t, Monad m) =>
    m a -> t m a
    lift (ReaderT Env IO [String]
     -> WriterT (Endo Config, [SpecTree a]) (ReaderT Env IO) [String])
    -> ReaderT Env IO [String]
    -> WriterT (Endo Config, [SpecTree a]) (ReaderT Env IO) [String]
    forall a b. (a -> b) -> a -> b
    $ [String] -> [String]
    forall a. [a] -> [a]
    reverse ([String] -> [String])
    -> ReaderT Env IO [String] -> ReaderT Env IO [String]
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> (Env -> [String]) -> ReaderT Env IO [String]
    forall (m :: * -> *) r a. Monad m => (r -> a) -> ReaderT r m a
    asks Env -> [String]
    envSpecDescriptionPath