@@ -1,21 +1,24 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2module Servant.QuickCheck.InternalSpec (spec) where
2module Servant.QuickCheck.InternalSpec (spec) where
4−import Control.Concurrent.MVar (newMVar, readMVar, swapMVar)
5+import Control.Concurrent.MVar (newMVar, readMVar, swapMVar)
6+import Control.Exception (SomeException)
5−import Control.Monad (replicateM)
7+import Control.Monad (replicateM)
6−import Control.Monad.IO.Class (liftIO)
8+import Control.Monad.IO.Class (liftIO)
7−import qualified Data.ByteString as BS
9+import qualified Data.ByteString as BS
8−import qualified Data.ByteString.Char8 as C
10+import qualified Data.ByteString.Char8 as C
9−import Data.Maybe (fromJust)
11+import Data.Maybe (fromJust)
12+import Network.HTTP.Client (path, queryString)
10import Prelude.Compat
13import Prelude.Compat
11import Servant
14import Servant
12−import Test.Hspec (Spec, context, describe, it, shouldBe,
15+import Test.Hspec (Spec, context, describe, it, shouldBe,
13− shouldContain)
16+ shouldContain)
14−import Test.Hspec.Core.Spec (Arg, Example, Result (..),
17+import Test.Hspec.Core.Spec (Arg, Example, Result (..),
15− defaultParams, evaluateExample)
18+ defaultParams)
16−import Test.QuickCheck.Gen (unGen, generate)
19+import Test.QuickCheck.Gen (generate, unGen)
17−import Test.QuickCheck.Random (mkQCGen)
20+import Test.QuickCheck.Random (mkQCGen)
18−import Network.HTTP.Client (queryString, path)
21+
20#if MIN_VERSION_servant(0,8,0)
23#if MIN_VERSION_servant(0,8,0)
21import Servant.API.Internal.Test.ComprehensiveAPI (comprehensiveAPIWithoutRaw)
24import Servant.API.Internal.Test.ComprehensiveAPI (comprehensiveAPIWithoutRaw)
@@ -24,8 +27,16 @@ import Servant.API.Internal.Test.ComprehensiveAPI (ComprehensiveAPI,
24 comprehensiveAPI)
27 comprehensiveAPI)
30+#if MIN_VERSION_hspec(2,4,0)
31+import Test.Hspec.Core.Spec (safeEvaluateExample)
33+import Control.Exception (try)
34+import Test.Hspec.Core.Spec (evaluateExample)
27import Servant.QuickCheck
37import Servant.QuickCheck
28−import Servant.QuickCheck.Internal (genRequest, runGenRequest, serverDoesntSatisfy)
38+import Servant.QuickCheck.Internal (genRequest, runGenRequest,
31spec :: Spec
42spec :: Spec
@@ -50,9 +61,10 @@ serversEqualSpec = describe "serversEqual" $ do
51 context "when servers are not equal" $ do
62 context "when servers are not equal" $ do
52 it "provides the failing responses in the error message" $ do
63 it "provides the failing responses in the error message" $ do
53− Fail _ err <- withServantServer api2 server2 $ \burl1 ->
64+ FailedWith err <- withServantServer api2 server2 $ \burl1 ->
54 withServantServer api2 server3 $ \burl2 -> do
65 withServantServer api2 server3 $ \burl2 -> do
55 evalExample $ serversEqual api2 burl1 burl2 args bodyEquality
66 evalExample $ serversEqual api2 burl1 burl2 args bodyEquality
67+ show err `shouldContain` "Server equality failed"
56 show err `shouldContain` "Body: 1"
68 show err `shouldContain` "Body: 1"
57 show err `shouldContain` "Body: 2"
69 show err `shouldContain` "Body: 2"
58 show err `shouldContain` "Path: /failplz"
70 show err `shouldContain` "Path: /failplz"
@@ -77,21 +89,21 @@ serverSatisfiesSpec = describe "serverSatisfies" $ do
77 context "when predicates are false" $ do
89 context "when predicates are false" $ do
79 it "fails with informative error messages" $ do
91 it "fails with informative error messages" $ do
80− Fail _ err <- withServantServerAndContext api ctx server $ \burl -> do
92+ FailedWith err <- withServantServerAndContext api ctx server $ \burl -> do
81 evalExample $ serverSatisfies api burl args (notAllowedContainsAllowHeader <%> mempty)
93 evalExample $ serverSatisfies api burl args (notAllowedContainsAllowHeader <%> mempty)
82− err `shouldContain` "notAllowedContainsAllowHeader"
94+ show err `shouldContain` "notAllowedContainsAllowHeader"
83− err `shouldContain` "Headers"
95+ show err `shouldContain` "Headers"
84− err `shouldContain` "Body"
96+ show err `shouldContain` "Body"
87onlyJsonObjectSpec :: Spec
99onlyJsonObjectSpec :: Spec
88onlyJsonObjectSpec = describe "onlyJsonObjects" $ do
100onlyJsonObjectSpec = describe "onlyJsonObjects" $ do
90 it "fails correctly" $ do
102 it "fails correctly" $ do
91− Fail _ err <- withServantServerAndContext api ctx server $ \burl -> do
103+ FailedWith err <- withServantServerAndContext api ctx server $ \burl -> do
92 evalExample $ serverSatisfies (Proxy :: Proxy (Get '[JSON] Int)) burl args
104 evalExample $ serverSatisfies (Proxy :: Proxy (Get '[JSON] Int)) burl args
93 (onlyJsonObjects <%> mempty)
105 (onlyJsonObjects <%> mempty)
94− err `shouldContain` "onlyJsonObjects"
106+ show err `shouldContain` "onlyJsonObjects"
96 it "accepts non-JSON endpoints" $ do
108 it "accepts non-JSON endpoints" $ do
97 withServantServerAndContext octetAPI ctx serverOctetAPI $ \burl ->
109 withServantServerAndContext octetAPI ctx serverOctetAPI $ \burl ->
@@ -101,10 +113,10 @@ notLongerThanSpec :: Spec
101notLongerThanSpec = describe "notLongerThan" $ do
113notLongerThanSpec = describe "notLongerThan" $ do
103 it "fails correctly" $ do
115 it "fails correctly" $ do
104− Fail _ err <- withServantServerAndContext api ctx server $ \burl -> do
116+ FailedWith err <- withServantServerAndContext api ctx server $ \burl -> do
105 evalExample $ serverSatisfies (Proxy :: Proxy (Get '[JSON] Int)) burl args
117 evalExample $ serverSatisfies (Proxy :: Proxy (Get '[JSON] Int)) burl args
106 (notLongerThan 1 <%> mempty)
118 (notLongerThan 1 <%> mempty)
107− err `shouldContain` "notLongerThan"
119+ show err `shouldContain` "notLongerThan"
109 it "succeeds correctly" $ do
121 it "succeeds correctly" $ do
110 withServantServerAndContext api ctx server $ \burl ->
122 withServantServerAndContext api ctx server $ \burl ->
@@ -166,8 +178,8 @@ unbiasedGenerationSpec = describe "Unbiased Generation of requests" $
166 let mean = (sum $ map fromIntegral someRequests) / runs
178 let mean = (sum $ map fromIntegral someRequests) / runs
167 let variancer x = let ix = fromIntegral x in (ix - mean) * (ix - mean)
179 let variancer x = let ix = fromIntegral x in (ix - mean) * (ix - mean)
168 let variance = (sum $ map variancer someRequests) / runs - 1
180 let variance = (sum $ map variancer someRequests) / runs - 1
169− -- mean should be around 8
181+ -- mean should be around 8.5. If this fails, we likely need more runs (or there's a bug!)
170− mean > 7 `shouldBe` True
182+ mean > 8 `shouldBe` True
171 mean < 9 `shouldBe` True
183 mean < 9 `shouldBe` True
172 -- Std dev is likely around 4. Variance is probably greater than 20.
184 -- Std dev is likely around 4. Variance is probably greater than 20.
173 variance > 19.5 `shouldBe` True
185 variance > 19.5 `shouldBe` True
@@ -255,11 +267,35 @@ ctx = BasicAuthCheck (const . return $ NoSuchUser) :. EmptyContext
255------------------------------------------------------------------------------
267------------------------------------------------------------------------------
257------------------------------------------------------------------------------
269------------------------------------------------------------------------------
259−evalExample :: (Example e, Arg e ~ ()) => e -> IO Result
270+evalExample :: (Example e, Arg e ~ ()) => e -> IO EvalResult
271+#if MIN_VERSION_hspec(2,4,0)
260−evalExample e = evaluateExample e defaultParams ($ ()) progCallback
273+ r <- safeEvaluateExample e defaultParams ($ ()) progCallback
275+ Left err -> return $ AnException err
276+ Right Success -> return $ AllGood
277+ Right (Failure _ reason) -> return $ FailedWith $ show reason
278+ Right (Pending _) -> error "should not happen"
262 progCallback _ = return ()
280 progCallback _ = return ()
283+ r <- try $ evaluateExample e defaultParams ($ ()) progCallback
285+ Left err -> return $ AnException err
286+ Right Success -> return $ AllGood
287+ Right (Fail _ reason) -> return $ FailedWith reason
288+ Right (Pending _) -> error "should not happen"
290+ progCallback _ = return ()
294+ = AnException SomeException
264args :: Args
300args :: Args
265args = defaultArgs { maxSuccess = noOfTestCases }
301args = defaultArgs { maxSuccess = noOfTestCases }