git.iko.soy/typeable/servant
on master help sign in
test suite: quickcheck property for a more complex client function
fd636eaSönke Hahn
servant.cabal+1
@@ -90,6 +90,7 @@ test-suite spec
90 , http-types
90 , http-types
91 , network >= 2.6
91 , network >= 2.6
92 , network-uri >= 2.6
92 , network-uri >= 2.6
93+ , QuickCheck
93 , servant
94 , servant
94 , string-conversions
95 , string-conversions
95 , text
96 , text
test/Servant/ClientSpec.hs+31−3
@@ -8,15 +8,17 @@ module Servant.ClientSpec where
8import Control.Concurrent
8import Control.Concurrent
9import Control.Exception
9import Control.Exception
10import Control.Monad.Trans.Either
10import Control.Monad.Trans.Either
11−import Data.Foldable
11+import Data.Char
12+import Data.Foldable (forM_)
12import Data.Proxy
13import Data.Proxy
13import Data.Typeable
14import Data.Typeable
14import Network.Socket
15import Network.Socket
15import Network.URI
16import Network.URI
16import Network.Wai
17import Network.Wai
17import Network.Wai.Handler.Warp
18import Network.Wai.Handler.Warp
18−import Prelude hiding (mapM_)
19import Test.Hspec
19import Test.Hspec
20+import Test.Hspec.QuickCheck
21+import Test.QuickCheck
20
22
21import Servant.API
23import Servant.API
22import Servant.Client
24import Servant.Client
@@ -31,6 +33,12 @@ type Api =
31 :<|> "param" :> QueryParam "name" String :> Get Person
33 :<|> "param" :> QueryParam "name" String :> Get Person
32 :<|> "params" :> QueryParams "names" String :> Get [Person]
34 :<|> "params" :> QueryParams "names" String :> Get [Person]
33 :<|> "flag" :> QueryFlag "flag" :> Get Bool
35 :<|> "flag" :> QueryFlag "flag" :> Get Bool
36+ :<|> "multiple" :>
37+ Capture "first" String :>
38+ QueryParam "second" Int :>
39+ QueryFlag "third" :>
40+ ReqBody [(String, [Rational])] :>
41+ Get (String, Maybe Int, Bool, [(String, [Rational])])
34api :: Proxy Api
42api :: Proxy Api
35api = Proxy
43api = Proxy
36
44
@@ -45,6 +53,7 @@ server = serve api (
45 Nothing -> left (400, "missing parameter"))
53 Nothing -> left (400, "missing parameter"))
46 :<|> (\ names -> return (zipWith Person names [0..]))
54 :<|> (\ names -> return (zipWith Person names [0..]))
47 :<|> return
55 :<|> return
56+ :<|> \ a b c d -> return (a, b, c, d)
48 )
57 )
49
58
50withServer :: (URIAuth -> IO a) -> IO a
59withServer :: (URIAuth -> IO a) -> IO a
@@ -56,12 +65,16 @@ getBody :: Person -> URIAuth -> EitherT String IO Person
56getQueryParam :: Maybe String -> URIAuth -> EitherT String IO Person
65getQueryParam :: Maybe String -> URIAuth -> EitherT String IO Person
57getQueryParams :: [String] -> URIAuth -> EitherT String IO [Person]
66getQueryParams :: [String] -> URIAuth -> EitherT String IO [Person]
58getQueryFlag :: Bool -> URIAuth -> EitherT String IO Bool
67getQueryFlag :: Bool -> URIAuth -> EitherT String IO Bool
68+getMultiple :: String -> Maybe Int -> Bool -> [(String, [Rational])]
69+ -> URIAuth
70+ -> EitherT String IO (String, Maybe Int, Bool, [(String, [Rational])])
59( getGet
71( getGet
60 :<|> getCapture
72 :<|> getCapture
61 :<|> getBody
73 :<|> getBody
62 :<|> getQueryParam
74 :<|> getQueryParam
63 :<|> getQueryParams
75 :<|> getQueryParams
64− :<|> getQueryFlag)
76+ :<|> getQueryFlag
77+ :<|> getMultiple)
65 = client api
78 = client api
66
79
67spec :: Spec
80spec :: Spec
@@ -91,6 +104,15 @@ spec = do
91 it (show flag) $ withServer $ \ host -> do
104 it (show flag) $ withServer $ \ host -> do
92 runEitherT (getQueryFlag flag host) `shouldReturn` Right flag
105 runEitherT (getQueryFlag flag host) `shouldReturn` Right flag
93
106
107+ modifyMaxSuccess (const 20) $ do
108+ it "works for a combination of Capture, QueryParam, QueryFlag and ReqBody" $
109+ property $ forAllShrink pathGen shrink $ \ a -> \ b c d ->
110+ ioProperty $ do
111+ withServer $ \ host -> do
112+ result <- runEitherT (getMultiple a b c d host)
113+ return $
114+ result === Right (a, b, c, d)
115+
94
116
95 context "client correctly handles error status codes" $ do
117 context "client correctly handles error status codes" $ do
96 let test :: WrappedApi -> Spec
118 let test :: WrappedApi -> Spec
@@ -156,3 +178,9 @@ openTestSocket = do
156 listen s 1
178 listen s 1
157 port <- socketPort s
179 port <- socketPort s
158 return (fromIntegral port, s)
180 return (fromIntegral port, s)
181+
182+pathGen :: Gen String
183+pathGen = listOf $ elements $
184+ filter (not . (`elem` "?%[]/#")) $
185+ filter isPrint $
186+ map chr [0..127]