    {-# LANGUAGE FlexibleInstances #-}
    {-# LANGUAGE GeneralizedNewtypeDeriving #-}
    {-# LANGUAGE OverloadedStrings #-}
    {-# LANGUAGE TypeFamilies #-}
    {-# LANGUAGE CPP #-}
    module Test.Hspec.Wai.Internal (
      WaiExpectation
    , WaiSession(..)
    , runWaiSession
    , runWithState
    , withApplication
    , getApp
    , getState
    , formatHeader
    ) where

    import           Control.Monad.IO.Class
    import           Control.Monad.Trans.Class
    import           Control.Monad.Trans.Reader
    import           Network.Wai (Application)
    import           Network.Wai.Test hiding (request)
    import           Test.Hspec.Core.Spec
    import           Test.Hspec.Wai.Util (formatHeader)

    #if MIN_VERSION_base(4,9,0)
    import           Control.Monad.Fail
    #endif

    -- | An expectation in the `WaiSession` monad.  Failing expectations are
    -- communicated through exceptions (similar to `Test.Hspec.Expectations.Expectation` and
    -- `Test.HUnit.Base.Assertion`).
    type WaiExpectation st = WaiSession st ()

    -- | A <http://www.yesodweb.com/book/web-application-interface WAI> test
    -- session that carries the `Application` under test and some client state.
    newtype WaiSession st a = WaiSession {forall st a. WaiSession st a -> ReaderT st Session a
    unWaiSession :: ReaderT st Session a}
      deriving ((forall a b. (a -> b) -> WaiSession st a -> WaiSession st b)
    -> (forall a b. a -> WaiSession st b -> WaiSession st a)
    -> Functor (WaiSession st)
    forall a b. a -> WaiSession st b -> WaiSession st a
    forall a b. (a -> b) -> WaiSession st a -> WaiSession st b
    forall st a b. a -> WaiSession st b -> WaiSession st a
    forall st a b. (a -> b) -> WaiSession st a -> WaiSession st b
    forall (f :: * -> *).
    (forall a b. (a -> b) -> f a -> f b)
    -> (forall a b. a -> f b -> f a) -> Functor f
    $cfmap :: forall st a b. (a -> b) -> WaiSession st a -> WaiSession st b
    fmap :: forall a b. (a -> b) -> WaiSession st a -> WaiSession st b
    $c<$ :: forall st a b. a -> WaiSession st b -> WaiSession st a
    <$ :: forall a b. a -> WaiSession st b -> WaiSession st a
    Functor, Functor (WaiSession st)
    Functor (WaiSession st)
    -> (forall a. a -> WaiSession st a)
    -> (forall a b.
        WaiSession st (a -> b) -> WaiSession st a -> WaiSession st b)
    -> (forall a b c.
        (a -> b -> c)
        -> WaiSession st a -> WaiSession st b -> WaiSession st c)
    -> (forall a b.
        WaiSession st a -> WaiSession st b -> WaiSession st b)
    -> (forall a b.
        WaiSession st a -> WaiSession st b -> WaiSession st a)
    -> Applicative (WaiSession st)
    forall st. Functor (WaiSession st)
    forall a. a -> WaiSession st a
    forall st a. a -> WaiSession st a
    forall a b. WaiSession st a -> WaiSession st b -> WaiSession st a
    forall a b. WaiSession st a -> WaiSession st b -> WaiSession st b
    forall a b.
    WaiSession st (a -> b) -> WaiSession st a -> WaiSession st b
    forall st a b.
    WaiSession st a -> WaiSession st b -> WaiSession st a
    forall st a b.
    WaiSession st a -> WaiSession st b -> WaiSession st b
    forall st a b.
    WaiSession st (a -> b) -> WaiSession st a -> WaiSession st b
    forall a b c.
    (a -> b -> c)
    -> WaiSession st a -> WaiSession st b -> WaiSession st c
    forall st a b c.
    (a -> b -> c)
    -> WaiSession st a -> WaiSession st b -> WaiSession st 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
    $cpure :: forall st a. a -> WaiSession st a
    pure :: forall a. a -> WaiSession st a
    $c<*> :: forall st a b.
    WaiSession st (a -> b) -> WaiSession st a -> WaiSession st b
    <*> :: forall a b.
    WaiSession st (a -> b) -> WaiSession st a -> WaiSession st b
    $cliftA2 :: forall st a b c.
    (a -> b -> c)
    -> WaiSession st a -> WaiSession st b -> WaiSession st c
    liftA2 :: forall a b c.
    (a -> b -> c)
    -> WaiSession st a -> WaiSession st b -> WaiSession st c
    $c*> :: forall st a b.
    WaiSession st a -> WaiSession st b -> WaiSession st b
    *> :: forall a b. WaiSession st a -> WaiSession st b -> WaiSession st b
    $c<* :: forall st a b.
    WaiSession st a -> WaiSession st b -> WaiSession st a
    <* :: forall a b. WaiSession st a -> WaiSession st b -> WaiSession st a
    Applicative, Applicative (WaiSession st)
    Applicative (WaiSession st)
    -> (forall a b.
        WaiSession st a -> (a -> WaiSession st b) -> WaiSession st b)
    -> (forall a b.
        WaiSession st a -> WaiSession st b -> WaiSession st b)
    -> (forall a. a -> WaiSession st a)
    -> Monad (WaiSession st)
    forall st. Applicative (WaiSession st)
    forall a. a -> WaiSession st a
    forall st a. a -> WaiSession st a
    forall a b. WaiSession st a -> WaiSession st b -> WaiSession st b
    forall a b.
    WaiSession st a -> (a -> WaiSession st b) -> WaiSession st b
    forall st a b.
    WaiSession st a -> WaiSession st b -> WaiSession st b
    forall st a b.
    WaiSession st a -> (a -> WaiSession st b) -> WaiSession st 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
    $c>>= :: forall st a b.
    WaiSession st a -> (a -> WaiSession st b) -> WaiSession st b
    >>= :: forall a b.
    WaiSession st a -> (a -> WaiSession st b) -> WaiSession st b
    $c>> :: forall st a b.
    WaiSession st a -> WaiSession st b -> WaiSession st b
    >> :: forall a b. WaiSession st a -> WaiSession st b -> WaiSession st b
    $creturn :: forall st a. a -> WaiSession st a
    return :: forall a. a -> WaiSession st a
    Monad, Monad (WaiSession st)
    Monad (WaiSession st)
    -> (forall a. IO a -> WaiSession st a) -> MonadIO (WaiSession st)
    forall st. Monad (WaiSession st)
    forall a. IO a -> WaiSession st a
    forall st a. IO a -> WaiSession st a
    forall (m :: * -> *).
    Monad m -> (forall a. IO a -> m a) -> MonadIO m
    $cliftIO :: forall st a. IO a -> WaiSession st a
    liftIO :: forall a. IO a -> WaiSession st a
    MonadIO
    #if MIN_VERSION_base(4,9,0)
      , Monad (WaiSession st)
    Monad (WaiSession st)
    -> (forall a. String -> WaiSession st a)
    -> MonadFail (WaiSession st)
    forall st. Monad (WaiSession st)
    forall a. String -> WaiSession st a
    forall st a. String -> WaiSession st a
    forall (m :: * -> *).
    Monad m -> (forall a. String -> m a) -> MonadFail m
    $cfail :: forall st a. String -> WaiSession st a
    fail :: forall a. String -> WaiSession st a
    MonadFail
    #endif
      )

    runWaiSession :: WaiSession () a -> Application -> IO a
    runWaiSession :: forall a. WaiSession () a -> Application -> IO a
    runWaiSession WaiSession () a
    action Application
    app = WaiSession () a -> ((), Application) -> IO a
    forall st a. WaiSession st a -> (st, Application) -> IO a
    runWithState WaiSession () a
    action ((), Application
    app)

    runWithState :: WaiSession st a -> (st, Application) -> IO a
    runWithState :: forall st a. WaiSession st a -> (st, Application) -> IO a
    runWithState WaiSession st a
    action (st
    st, Application
    app) = Session a -> Application -> IO a
    forall a. Session a -> Application -> IO a
    runSession ((ReaderT st Session a -> st -> Session a)
    -> st -> ReaderT st Session a -> Session a
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip ReaderT st Session a -> st -> Session a
    forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
    runReaderT st
    st (ReaderT st Session a -> Session a)
    -> ReaderT st Session a -> Session a
    forall a b. (a -> b) -> a -> b
    $ WaiSession st a -> ReaderT st Session a
    forall st a. WaiSession st a -> ReaderT st Session a
    unWaiSession WaiSession st a
    action) Application
    app

    withApplication :: Application -> WaiSession () a -> IO a
    withApplication :: forall a. Application -> WaiSession () a -> IO a
    withApplication = (WaiSession () a -> Application -> IO a)
    -> Application -> WaiSession () a -> IO a
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip WaiSession () a -> Application -> IO a
    forall a. WaiSession () a -> Application -> IO a
    runWaiSession

    instance Example (WaiExpectation st) where
      type Arg (WaiExpectation st) = (st, Application)
      evaluateExample :: WaiExpectation st
    -> Params
    -> (ActionWith (Arg (WaiExpectation st)) -> IO ())
    -> ProgressCallback
    -> IO Result
    evaluateExample WaiExpectation st
    e Params
    p ActionWith (Arg (WaiExpectation st)) -> IO ()
    action = IO ()
    -> Params
    -> (ActionWith (Arg (IO ())) -> IO ())
    -> ProgressCallback
    -> IO Result
    forall e.
    Example e =>
    e
    -> Params
    -> (ActionWith (Arg e) -> IO ())
    -> ProgressCallback
    -> IO Result
    evaluateExample (ActionWith (Arg (WaiExpectation st)) -> IO ()
    action (ActionWith (Arg (WaiExpectation st)) -> IO ())
    -> ActionWith (Arg (WaiExpectation st)) -> IO ()
    forall a b. (a -> b) -> a -> b
    $ WaiExpectation st -> (st, Application) -> IO ()
    forall st a. WaiSession st a -> (st, Application) -> IO a
    runWithState WaiExpectation st
    e) Params
    p ((() -> IO ()) -> () -> IO ()
    forall a b. (a -> b) -> a -> b
    $ ())

    getApp :: WaiSession st Application
    getApp :: forall st. WaiSession st Application
    getApp = ReaderT st Session Application -> WaiSession st Application
    forall st a. ReaderT st Session a -> WaiSession st a
    WaiSession (Session Application -> ReaderT st Session Application
    forall (m :: * -> *) a. Monad m => m a -> ReaderT st m a
    forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
    (MonadTrans t, Monad m) =>
    m a -> t m a
    lift Session Application
    forall (m :: * -> *) r. Monad m => ReaderT r m r
    ask)

    getState :: WaiSession st st
    getState :: forall st. WaiSession st st
    getState = ReaderT st Session st -> WaiSession st st
    forall st a. ReaderT st Session a -> WaiSession st a
    WaiSession ReaderT st Session st
    forall (m :: * -> *) r. Monad m => ReaderT r m r
    ask