154 lines
5.5 KiB
Haskell
154 lines
5.5 KiB
Haskell
{-# LANGUAGE CPP #-}
|
|
{-# LANGUAGE PolyKinds #-}
|
|
module Servant.QuickCheck.Internal.HasGenRequest where
|
|
|
|
import Data.Monoid ((<>))
|
|
import Data.String (fromString)
|
|
import Data.String.Conversions (cs)
|
|
import GHC.TypeLits (KnownSymbol, Nat, symbolVal)
|
|
import Network.HTTP.Client (Request, RequestBody (..), host, method, path,
|
|
port, queryString, requestBody, requestHeaders,
|
|
secure, defaultRequest)
|
|
import Network.HTTP.Media (renderHeader)
|
|
import Prelude.Compat
|
|
import Servant
|
|
import Servant.API.ContentTypes (AllMimeRender (..))
|
|
import Servant.Client (BaseUrl (..), Scheme (..))
|
|
import Test.QuickCheck (Arbitrary (..), Gen, elements, oneof)
|
|
#if MIN_VERSION_servant(0,8,0)
|
|
import qualified Data.ByteString as BS
|
|
#endif
|
|
|
|
|
|
class HasGenRequest a where
|
|
genRequest :: Proxy a -> Gen (BaseUrl -> Request)
|
|
|
|
instance (HasGenRequest a, HasGenRequest b) => HasGenRequest (a :<|> b) where
|
|
genRequest _
|
|
= oneof [ genRequest (Proxy :: Proxy a)
|
|
, genRequest (Proxy :: Proxy b)
|
|
]
|
|
|
|
instance (KnownSymbol path, HasGenRequest b) => HasGenRequest (path :> b) where
|
|
genRequest _ = do
|
|
old' <- old
|
|
return $ \burl -> let r = old' burl in r { path = new <> path r }
|
|
where
|
|
old = genRequest (Proxy :: Proxy b)
|
|
new = cs $ symbolVal (Proxy :: Proxy path)
|
|
|
|
instance (Arbitrary c, HasGenRequest b, ToHttpApiData c )
|
|
=> HasGenRequest (Capture x c :> b) where
|
|
genRequest _ = do
|
|
old' <- old
|
|
new' <- toUrlPiece <$> new
|
|
return $ \burl -> let r = old' burl in r { path = cs new' <> path r }
|
|
where
|
|
old = genRequest (Proxy :: Proxy b)
|
|
new = arbitrary :: Gen c
|
|
|
|
#if MIN_VERSION_servant(0,8,0)
|
|
instance (Arbitrary c, HasGenRequest b, ToHttpApiData c )
|
|
=> HasGenRequest (CaptureAll x c :> b) where
|
|
genRequest _ = do
|
|
old' <- old
|
|
new' <- fmap (cs . toUrlPiece) <$> new
|
|
let new'' = BS.intercalate "/" new'
|
|
return $ \burl -> let r = old' burl in r { path = new'' <> path r }
|
|
where
|
|
old = genRequest (Proxy :: Proxy b)
|
|
new = arbitrary :: Gen [c]
|
|
#endif
|
|
|
|
instance (Arbitrary c, KnownSymbol h, HasGenRequest b, ToHttpApiData c)
|
|
=> HasGenRequest (Header h c :> b) where
|
|
genRequest _ = do
|
|
old' <- old
|
|
new' <- toUrlPiece <$> new
|
|
return $ \burl -> let r = old' burl in r {
|
|
requestHeaders = (hdr, cs new') : requestHeaders r }
|
|
where
|
|
old = genRequest (Proxy :: Proxy b)
|
|
hdr = fromString $ symbolVal (Proxy :: Proxy h)
|
|
new = arbitrary :: Gen c
|
|
|
|
instance (AllMimeRender x c, Arbitrary c, HasGenRequest b)
|
|
=> HasGenRequest (ReqBody x c :> b) where
|
|
genRequest _ = do
|
|
old' <- old
|
|
new' <- new
|
|
(ct, bd) <- elements $ allMimeRender (Proxy :: Proxy x) new'
|
|
return $ \burl -> let r = old' burl in r {
|
|
requestBody = RequestBodyLBS bd
|
|
, requestHeaders = ("Content-Type", renderHeader ct) : requestHeaders r
|
|
}
|
|
where
|
|
old = genRequest (Proxy :: Proxy b)
|
|
new = arbitrary :: Gen c
|
|
|
|
instance (KnownSymbol x, Arbitrary c, ToHttpApiData c, HasGenRequest b)
|
|
=> HasGenRequest (QueryParam x c :> b) where
|
|
genRequest _ = do
|
|
new' <- new
|
|
old' <- old
|
|
return $ \burl -> let r = old' burl in r {
|
|
queryString = queryString r
|
|
<> param <> "=" <> cs (toQueryParam new') }
|
|
where
|
|
old = genRequest (Proxy :: Proxy b)
|
|
param = cs $ symbolVal (Proxy :: Proxy x)
|
|
new = arbitrary :: Gen c
|
|
|
|
instance (KnownSymbol x, Arbitrary c, ToHttpApiData c, HasGenRequest b)
|
|
=> HasGenRequest (QueryParams x c :> b) where
|
|
genRequest _ = do
|
|
new' <- new
|
|
old' <- old
|
|
return $ \burl -> let r = old' burl in r {
|
|
queryString = queryString r
|
|
<> if length new' > 0 then fold (toParam <$> new') else ""}
|
|
where
|
|
old = genRequest (Proxy :: Proxy b)
|
|
param = cs $ symbolVal (Proxy :: Proxy x)
|
|
new = arbitrary :: Gen [c]
|
|
toParam c = param <> "[]=" <> cs (toQueryParam c)
|
|
fold = foldr1 (\a b -> a <> "&" <> b)
|
|
|
|
instance (KnownSymbol x, HasGenRequest b)
|
|
=> HasGenRequest (QueryFlag x :> b) where
|
|
genRequest _ = do
|
|
old' <- old
|
|
return $ \burl -> let r = old' burl in r {
|
|
queryString = queryString r <> param <> "=" }
|
|
where
|
|
old = genRequest (Proxy :: Proxy b)
|
|
param = cs $ symbolVal (Proxy :: Proxy x)
|
|
|
|
instance (ReflectMethod method)
|
|
=> HasGenRequest (Verb (method :: k) (status :: Nat) (cts :: [*]) a) where
|
|
genRequest _ = return $ \burl -> defaultRequest
|
|
{ host = cs $ baseUrlHost burl
|
|
, port = baseUrlPort burl
|
|
, secure = baseUrlScheme burl == Https
|
|
, method = reflectMethod (Proxy :: Proxy method)
|
|
}
|
|
|
|
instance (HasGenRequest a) => HasGenRequest (RemoteHost :> a) where
|
|
genRequest _ = genRequest (Proxy :: Proxy a)
|
|
|
|
instance (HasGenRequest a) => HasGenRequest (IsSecure :> a) where
|
|
genRequest _ = genRequest (Proxy :: Proxy a)
|
|
|
|
instance (HasGenRequest a) => HasGenRequest (HttpVersion :> a) where
|
|
genRequest _ = genRequest (Proxy :: Proxy a)
|
|
|
|
instance (HasGenRequest a) => HasGenRequest (Vault :> a) where
|
|
genRequest _ = genRequest (Proxy :: Proxy a)
|
|
|
|
instance (HasGenRequest a) => HasGenRequest (WithNamedContext x y a) where
|
|
genRequest _ = genRequest (Proxy :: Proxy a)
|
|
|
|
-- TODO: Try logging in
|
|
instance (HasGenRequest a) => HasGenRequest (BasicAuth x y :> a) where
|
|
genRequest _ = genRequest (Proxy :: Proxy a)
|