{-# 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 {WaiSession st a -> ReaderT st Session a
unWaiSession :: ReaderT st Session a}
  deriving (a -> WaiSession st b -> WaiSession st a
(a -> b) -> WaiSession st a -> WaiSession st b
(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
<$ :: a -> WaiSession st b -> WaiSession st a
$c<$ :: forall st a b. a -> WaiSession st b -> WaiSession st a
fmap :: (a -> b) -> WaiSession st a -> WaiSession st b
$cfmap :: forall st a b. (a -> b) -> WaiSession st a -> WaiSession st b
Functor, Functor (WaiSession st)
a -> WaiSession st a
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)
WaiSession st a -> WaiSession st b -> WaiSession st b
WaiSession st a -> WaiSession st b -> WaiSession st a
WaiSession st (a -> b) -> WaiSession st a -> WaiSession st b
(a -> b -> c)
-> WaiSession st a -> WaiSession st b -> WaiSession st c
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
<* :: WaiSession st a -> WaiSession st b -> WaiSession st a
$c<* :: forall st a b.
WaiSession st a -> WaiSession st b -> WaiSession st a
*> :: WaiSession st a -> WaiSession st b -> WaiSession st b
$c*> :: forall st a b.
WaiSession st a -> WaiSession st b -> WaiSession st b
liftA2 :: (a -> b -> c)
-> WaiSession st a -> WaiSession st b -> WaiSession st c
$cliftA2 :: forall st a b c.
(a -> b -> c)
-> WaiSession st a -> WaiSession st b -> WaiSession st c
<*> :: WaiSession st (a -> b) -> WaiSession st a -> WaiSession st b
$c<*> :: forall st a b.
WaiSession st (a -> b) -> WaiSession st a -> WaiSession st b
pure :: a -> WaiSession st a
$cpure :: forall st a. a -> WaiSession st a
$cp1Applicative :: forall st. Functor (WaiSession st)
Applicative, Applicative (WaiSession st)
a -> WaiSession st a
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)
WaiSession st a -> (a -> WaiSession st b) -> WaiSession st b
WaiSession st a -> WaiSession st b -> WaiSession st b
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
return :: a -> WaiSession st a
$creturn :: forall st a. a -> WaiSession st a
>> :: WaiSession st a -> WaiSession st b -> WaiSession st b
$c>> :: forall st a b.
WaiSession st a -> WaiSession st b -> WaiSession st b
>>= :: WaiSession st a -> (a -> WaiSession st b) -> WaiSession st b
$c>>= :: forall st a b.
WaiSession st a -> (a -> WaiSession st b) -> WaiSession st b
$cp1Monad :: forall st. Applicative (WaiSession st)
Monad, Monad (WaiSession st)
Monad (WaiSession st)
-> (forall a. IO a -> WaiSession st a) -> MonadIO (WaiSession st)
IO a -> WaiSession st a
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
liftIO :: IO a -> WaiSession st a
$cliftIO :: forall st a. IO a -> WaiSession st a
$cp1MonadIO :: forall st. Monad (WaiSession st)
MonadIO
#if MIN_VERSION_base(4,9,0)
  , Monad (WaiSession st)
Monad (WaiSession st)
-> (forall a. String -> WaiSession st a)
-> MonadFail (WaiSession st)
String -> WaiSession st a
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
fail :: String -> WaiSession st a
$cfail :: forall st a. String -> WaiSession st a
$cp1MonadFail :: forall st. Monad (WaiSession st)
MonadFail
#endif
  )

runWaiSession :: WaiSession () a -> Application -> IO a
runWaiSession :: 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 :: 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 :: 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 :: WaiSession st Application
getApp = ReaderT st Session Application -> WaiSession st Application
forall st a. ReaderT st Session a -> WaiSession st a
WaiSession (ReaderT Application (StateT ClientState IO) Application
-> ReaderT st Session Application
forall (t :: (* -> *) -> * -> *) (m :: * -> *) a.
(MonadTrans t, Monad m) =>
m a -> t m a
lift ReaderT Application (StateT ClientState IO) Application
forall (m :: * -> *) r. Monad m => ReaderT r m r
ask)

getState :: WaiSession st st
getState :: 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