git.iko.soy/servant-quickcheck
on master help sign in
Merge pull request #29 from haskell-servant/issue-27/supportHspec2.4

Upgrade hspec to 2.4.4 and use safeEvaluateExample for tests

commite7206ec875e0e3e50babb7bc811c556d03dd3f78 authorJulian Arni <jkarni@gmail.com> dateSun 15 Oct 2017, 18:45 (9 years ago) parent66ce509a0ec177
4 files changed+74−39
servant-quickcheck.cabal+2−2 src/Servant/QuickCheck/Internal/QuickCheck.hs+4−6 stack.yaml+4−3 test/Servant/QuickCheck/InternalSpec.hs+64−28
servant-quickcheck.cabal+2−2
@@ -38,14 +38,14 @@ library
3838 , case-insensitive == 1.2.*
3939 , clock >= 0.7 && < 0.8
4040 , data-default-class >= 0.0 && < 0.2
41− , hspec >= 2.2 && < 2.4
41+ , hspec >= 2.2 && < 2.5
4242 , http-client >= 0.4.30 && < 0.6
4343 , http-media == 0.6.*
4444 , http-types > 0.8 && < 0.10
4545 , mtl > 2.1 && < 2.3
4646 , pretty == 1.1.*
4747 , process >= 1.2 && < 1.5
48− , QuickCheck > 2.7 && < 2.10
48+ , QuickCheck > 2.7 && < 2.11
4949 , servant > 0.6 && < 0.10
5050 , servant-client > 0.6 && < 0.10
5151 , servant-server > 0.6 && < 0.10
src/Servant/QuickCheck/Internal/QuickCheck.hs+4−6
@@ -14,8 +14,7 @@ import Servant (Context (EmptyContext), HasServer,
1414import Servant.Client (BaseUrl (..), Scheme (..))
1515import System.IO.Unsafe (unsafePerformIO)
1616import Test.Hspec (Expectation, expectationFailure)
17−import Test.QuickCheck (Args (..), Result (..),
18− quickCheckWithResult)
17+import Test.QuickCheck (Args (..), Result (..), quickCheckWithResult)
1918import Test.QuickCheck.Monadic (assert, forAllM, monadicIO, monitor,
2019 run)
2120import Test.QuickCheck.Property (counterexample)
@@ -85,11 +84,10 @@ serversEqual api burl1 burl2 args req = do
8584 assert False
8685 case r of
8786 Success {} -> return ()
88− Failure{..} -> readMVar deetsMVar >>= \x -> expectationFailure $
89− "Failed:\n" ++ show x
87+ Failure{..} -> readMVar deetsMVar >>= \x -> expectationFailure $ "Failed:\n" ++ show x
9088 GaveUp { numTests = n } -> expectationFailure $ "Gave up after " ++ show n ++ " tests"
91− NoExpectedFailure {} -> expectationFailure $ "No expected failure"
92− InsufficientCoverage {} -> expectationFailure $ "Insufficient coverage"
89+ NoExpectedFailure {} -> expectationFailure "No expected failure"
90+ InsufficientCoverage {} -> expectationFailure "Insufficient coverage"
9391
9492-- | Check that a server satisfies the set of properties specified.
9593--
stack.yaml+4−3
@@ -2,8 +2,9 @@ resolver: lts-8.4
22packages:
33- '.'
44extra-deps:
5−- hspec-2.3.2
6−- hspec-core-2.3.2
7−- hspec-discover-2.3.2
5+- hspec-2.4.4
6+- hspec-core-2.4.4
7+- hspec-discover-2.4.4
8+- quickcheck-io-0.2.0
89flags: {}
910extra-package-dbs: []
test/Servant/QuickCheck/InternalSpec.hs+64−28
@@ -1,21 +1,24 @@
11{-# LANGUAGE CPP #-}
22module Servant.QuickCheck.InternalSpec (spec) where
33
4−import Control.Concurrent.MVar (newMVar, readMVar, swapMVar)
5−import Control.Monad (replicateM)
6−import Control.Monad.IO.Class (liftIO)
7−import qualified Data.ByteString as BS
8−import qualified Data.ByteString.Char8 as C
9−import Data.Maybe (fromJust)
4+
5+import Control.Concurrent.MVar (newMVar, readMVar, swapMVar)
6+import Control.Exception (SomeException)
7+import Control.Monad (replicateM)
8+import Control.Monad.IO.Class (liftIO)
9+import qualified Data.ByteString as BS
10+import qualified Data.ByteString.Char8 as C
11+import Data.Maybe (fromJust)
12+import Network.HTTP.Client (path, queryString)
1013import Prelude.Compat
1114import Servant
12−import Test.Hspec (Spec, context, describe, it, shouldBe,
13− shouldContain)
14−import Test.Hspec.Core.Spec (Arg, Example, Result (..),
15− defaultParams, evaluateExample)
16−import Test.QuickCheck.Gen (unGen, generate)
17−import Test.QuickCheck.Random (mkQCGen)
18−import Network.HTTP.Client (queryString, path)
15+import Test.Hspec (Spec, context, describe, it, shouldBe,
16+ shouldContain)
17+import Test.Hspec.Core.Spec (Arg, Example, Result (..),
18+ defaultParams)
19+import Test.QuickCheck.Gen (generate, unGen)
20+import Test.QuickCheck.Random (mkQCGen)
21+
1922
2023#if MIN_VERSION_servant(0,8,0)
2124import Servant.API.Internal.Test.ComprehensiveAPI (comprehensiveAPIWithoutRaw)
@@ -24,8 +27,16 @@ import Servant.API.Internal.Test.ComprehensiveAPI (ComprehensiveAPI,
2427 comprehensiveAPI)
2528#endif
2629
30+#if MIN_VERSION_hspec(2,4,0)
31+import Test.Hspec.Core.Spec (safeEvaluateExample)
32+#else
33+import Control.Exception (try)
34+import Test.Hspec.Core.Spec (evaluateExample)
35+#endif
36+
2737import Servant.QuickCheck
28−import Servant.QuickCheck.Internal (genRequest, runGenRequest, serverDoesntSatisfy)
38+import Servant.QuickCheck.Internal (genRequest, runGenRequest,
39+ serverDoesntSatisfy)
2940
3041
3142spec :: Spec
@@ -50,9 +61,10 @@ serversEqualSpec = describe "serversEqual" $ do
5061
5162 context "when servers are not equal" $ do
5263 it "provides the failing responses in the error message" $ do
53− Fail _ err <- withServantServer api2 server2 $ \burl1 ->
64+ FailedWith err <- withServantServer api2 server2 $ \burl1 ->
5465 withServantServer api2 server3 $ \burl2 -> do
5566 evalExample $ serversEqual api2 burl1 burl2 args bodyEquality
67+ show err `shouldContain` "Server equality failed"
5668 show err `shouldContain` "Body: 1"
5769 show err `shouldContain` "Body: 2"
5870 show err `shouldContain` "Path: /failplz"
@@ -77,21 +89,21 @@ serverSatisfiesSpec = describe "serverSatisfies" $ do
7789 context "when predicates are false" $ do
7890
7991 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
8193 evalExample $ serverSatisfies api burl args (notAllowedContainsAllowHeader <%> mempty)
82− err `shouldContain` "notAllowedContainsAllowHeader"
83− err `shouldContain` "Headers"
84− err `shouldContain` "Body"
94+ show err `shouldContain` "notAllowedContainsAllowHeader"
95+ show err `shouldContain` "Headers"
96+ show err `shouldContain` "Body"
8597
8698
8799onlyJsonObjectSpec :: Spec
88100onlyJsonObjectSpec = describe "onlyJsonObjects" $ do
89101
90102 it "fails correctly" $ do
91− Fail _ err <- withServantServerAndContext api ctx server $ \burl -> do
103+ FailedWith err <- withServantServerAndContext api ctx server $ \burl -> do
92104 evalExample $ serverSatisfies (Proxy :: Proxy (Get '[JSON] Int)) burl args
93105 (onlyJsonObjects <%> mempty)
94− err `shouldContain` "onlyJsonObjects"
106+ show err `shouldContain` "onlyJsonObjects"
95107
96108 it "accepts non-JSON endpoints" $ do
97109 withServantServerAndContext octetAPI ctx serverOctetAPI $ \burl ->
@@ -101,10 +113,10 @@ notLongerThanSpec :: Spec
101113notLongerThanSpec = describe "notLongerThan" $ do
102114
103115 it "fails correctly" $ do
104− Fail _ err <- withServantServerAndContext api ctx server $ \burl -> do
116+ FailedWith err <- withServantServerAndContext api ctx server $ \burl -> do
105117 evalExample $ serverSatisfies (Proxy :: Proxy (Get '[JSON] Int)) burl args
106118 (notLongerThan 1 <%> mempty)
107− err `shouldContain` "notLongerThan"
119+ show err `shouldContain` "notLongerThan"
108120
109121 it "succeeds correctly" $ do
110122 withServantServerAndContext api ctx server $ \burl ->
@@ -166,8 +178,8 @@ unbiasedGenerationSpec = describe "Unbiased Generation of requests" $
166178 let mean = (sum $ map fromIntegral someRequests) / runs
167179 let variancer x = let ix = fromIntegral x in (ix - mean) * (ix - mean)
168180 let variance = (sum $ map variancer someRequests) / runs - 1
169− -- mean should be around 8
170− mean > 7 `shouldBe` True
181+ -- mean should be around 8.5. If this fails, we likely need more runs (or there's a bug!)
182+ mean > 8 `shouldBe` True
171183 mean < 9 `shouldBe` True
172184 -- Std dev is likely around 4. Variance is probably greater than 20.
173185 variance > 19.5 `shouldBe` True
@@ -255,11 +267,35 @@ ctx = BasicAuthCheck (const . return $ NoSuchUser) :. EmptyContext
255267------------------------------------------------------------------------------
256268-- Utils
257269------------------------------------------------------------------------------
258−
259−evalExample :: (Example e, Arg e ~ ()) => e -> IO Result
260−evalExample e = evaluateExample e defaultParams ($ ()) progCallback
270+evalExample :: (Example e, Arg e ~ ()) => e -> IO EvalResult
271+#if MIN_VERSION_hspec(2,4,0)
272+evalExample e = do
273+ r <- safeEvaluateExample e defaultParams ($ ()) progCallback
274+ case r of
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"
261279 where
262280 progCallback _ = return ()
281+#else
282+evalExample e = do
283+ r <- try $ evaluateExample e defaultParams ($ ()) progCallback
284+ case r of
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"
289+ where
290+ progCallback _ = return ()
291+#endif
292+
293+data EvalResult
294+ = AnException SomeException
295+ | AllGood
296+ | FailedWith String
297+ deriving (Show)
298+
263299
264300args :: Args
265301args = defaultArgs { maxSuccess = noOfTestCases }