@@ -1,13 +1,17 @@
1module Servant.QuickCheck.Internal.Predicates where
1module Servant.QuickCheck.Internal.Predicates where
3−import Data.Monoid ((<>))
4−import GHC.Generics (Generic)
5−import Control.Monad
3+import Control.Monad
6−import Network.HTTP.Client (Request, Response, responseStatus, Manager, httpLbs)
4+import Data.Aeson (Object, decode)
7−import Network.HTTP.Types (status500)
5+import Data.Bifunctor (Bifunctor (..))
8import qualified Data.ByteString.Lazy as LBS
6import qualified Data.ByteString.Lazy as LBS
9−import Data.Bifunctor (Bifunctor(..))
7+import qualified Data.ByteString as SBS
8+import Data.CaseInsensitive (mk)
9+import Data.Monoid ((<>))
10−import Data.Text (Text)
10+import Data.Text (Text)
11+import GHC.Generics (Generic)
12+import Network.HTTP.Client (Manager, Request, Response, httpLbs,
13+ responseBody, responseStatus, responseHeaders)
14+import Network.HTTP.Types (status500)
12-- | @500 Internal Server Error@ should be avoided - it may represent some
16-- | @500 Internal Server Error@ should be avoided - it may represent some
13-- issue with the application code, and it moreover gives the client little
17-- issue with the application code, and it moreover gives the client little
@@ -17,7 +21,6 @@ import Data.Text (Text)
17not500 :: ResponsePredicate Text Bool
21not500 :: ResponsePredicate Text Bool
18not500 = ResponsePredicate "not500" (\resp -> not $ responseStatus resp == status500)
22not500 = ResponsePredicate "not500" (\resp -> not $ responseStatus resp == status500)
21-- | Returning anything other than an object when returning JSON is considered
24-- | Returning anything other than an object when returning JSON is considered
22-- bad practice, as:
25-- bad practice, as:
@@ -30,10 +33,13 @@ not500 = ResponsePredicate "not500" (\resp -> not $ responseStatus resp == statu
31-- This function checks that any @application/json@ responses only return JSON
34-- This function checks that any @application/json@ responses only return JSON
32-- objects (and not arrays, strings, numbers, or booleans) at the top level.
35-- objects (and not arrays, strings, numbers, or booleans) at the top level.
33−onlyJsonObjects :: Response b -> IO Bool
36+onlyJsonObjects :: ResponsePredicate Text Bool
34onlyJsonObjects
37onlyJsonObjects
35− = ResponsePredicate "onlyJsonObjects" _
38+ = ResponsePredicate "onlyJsonObjects" (\resp -> case decode (responseBody resp) of
40+ Just (_ :: Object) -> True)
37-- | When creating a new resource, it is good practice to provide a @Location@
43-- | When creating a new resource, it is good practice to provide a @Location@
38-- header with a link to the created resource.
44-- header with a link to the created resource.
@@ -42,9 +48,9 @@ onlyJsonObjects
42-- requests.
48-- requests.
44-- References: <RFC 7231, Section 6.3.2 https://tools.ietf.org/html/rfc7231#section-6.3.2>
50-- References: <RFC 7231, Section 6.3.2 https://tools.ietf.org/html/rfc7231#section-6.3.2>
45−createContainsValidLocation :: Response b -> IO Bool
51+createContainsValidLocation :: ResponsePredicate Text Bool
46createContainsValidLocation
52createContainsValidLocation
47− = ResponsePredicate "createContainsValidLocation" _
53+ = ResponsePredicate "createContainsValidLocation" (\resp ->
49getsHaveLastModifiedHeader :: Response b -> IO Bool
55getsHaveLastModifiedHeader :: Response b -> IO Bool
50getsHaveLastModifiedHeader
56getsHaveLastModifiedHeader
@@ -221,3 +227,8 @@ finishPredicates p req mgr = do
221 resps <- reqResps (reqPreds p) req mgr
227 resps <- reqResps (reqPreds p) req mgr
222 let preds = reqPred (reqPreds p) <> respPreds p
228 let preds = reqPred (reqPreds p) <> respPreds p
223 return $ mconcat [respPred preds r | r <- resps ]
229 return $ mconcat [respPred preds r | r <- resps ]
233+hasHeader :: SBS.ByteString -> Response b -> Bool
234+hasHeader hdr r = mk hdr `elem` (fst <$> responseHeaders r)