@@ -12,33 +12,23 @@ import Data.Maybe (fromJust)
12import Network.HTTP.Client (path, queryString)
12import Network.HTTP.Client (path, queryString)
13import Prelude.Compat
13import Prelude.Compat
14import Servant
14import Servant
15+import Servant.HTML.Blaze (HTML)
16+import qualified Text.Blaze.Html as Blaze
17+import qualified Text.Blaze.Html5 as Blaze5
15import Test.Hspec (Spec, context, describe, it, shouldBe,
18import Test.Hspec (Spec, context, describe, it, shouldBe,
16 shouldContain)
19 shouldContain)
17−import Test.Hspec.Core.Spec (Arg, Example, Result (..),
20+import Test.Hspec.Core.Spec (Arg, Example, Result (..), ResultStatus (..),
18− defaultParams)
21+ defaultParams, safeEvaluateExample)
19import Test.QuickCheck.Gen (generate, unGen)
22import Test.QuickCheck.Gen (generate, unGen)
20import Test.QuickCheck.Random (mkQCGen)
23import Test.QuickCheck.Random (mkQCGen)
23−#if MIN_VERSION_servant(0,8,0)
24−import Servant.API.Internal.Test.ComprehensiveAPI (comprehensiveAPIWithoutRaw)
26+import Servant.Test.ComprehensiveAPI (comprehensiveAPIWithoutStreamingOrRaw)
26−import Servant.API.Internal.Test.ComprehensiveAPI (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)
37import Servant.QuickCheck
28import Servant.QuickCheck
38import Servant.QuickCheck.Internal (genRequest, runGenRequest,
29import Servant.QuickCheck.Internal (genRequest, runGenRequest,
39 serverDoesntSatisfy)
30 serverDoesntSatisfy)
42spec :: Spec
32spec :: Spec
44 serversEqualSpec
34 serversEqualSpec
@@ -49,6 +39,7 @@ spec = do
49 queryParamsSpec
39 queryParamsSpec
50 queryFlagsSpec
40 queryFlagsSpec
51 deepPathSpec
41 deepPathSpec
52 unbiasedGenerationSpec
43 unbiasedGenerationSpec
54serversEqualSpec :: Spec
45serversEqualSpec :: Spec
@@ -72,9 +63,9 @@ serversEqualSpec = describe "serversEqual" $ do
72 context "when JSON is equal but looks a bit different as a ByteString" $ do
63 context "when JSON is equal but looks a bit different as a ByteString" $ do
74 it "sanity check: different whitespace same JSON objects bodyEquality fails" $ do
65 it "sanity check: different whitespace same JSON objects bodyEquality fails" $ do
75− Right (Failure _ err) <- withServantServer jsonApi jsonServer1 $ \burl1 ->
66+ FailedWith err <- withServantServer jsonApi jsonServer1 $ \burl1 ->
76 withServantServer jsonApi jsonServer2 $ \burl2 -> do
67 withServantServer jsonApi jsonServer2 $ \burl2 -> do
77− safeEvalExample $ serversEqual jsonApi burl1 burl2 args bodyEquality
68+ evalExample $ serversEqual jsonApi burl1 burl2 args bodyEquality
78 show err `shouldContain` "Server equality failed"
69 show err `shouldContain` "Server equality failed"
80 it "jsonEquality considers equal JSON apis equal regardless of key ordering or whitespace" $ do
71 it "jsonEquality considers equal JSON apis equal regardless of key ordering or whitespace" $ do
@@ -83,16 +74,16 @@ serversEqualSpec = describe "serversEqual" $ do
83 serversEqual jsonApi burl1 burl2 args jsonEquality
74 serversEqual jsonApi burl1 burl2 args jsonEquality
85 it "sees when JSON apis are not equal because any value is different" $ do
76 it "sees when JSON apis are not equal because any value is different" $ do
86− Right (Failure _ err) <- withServantServer jsonApi jsonServer2 $ \burl1 ->
77+ FailedWith err <- withServantServer jsonApi jsonServer2 $ \burl1 ->
87 withServantServer jsonApi jsonServer3 $ \burl2 -> do
78 withServantServer jsonApi jsonServer3 $ \burl2 -> do
88− safeEvalExample $ serversEqual jsonApi burl1 burl2 args jsonEquality
79+ evalExample $ serversEqual jsonApi burl1 burl2 args jsonEquality
89 show err `shouldContain` "Server equality failed"
80 show err `shouldContain` "Server equality failed"
90 show err `shouldContain` "Path: /jsonComparison"
81 show err `shouldContain` "Path: /jsonComparison"
92 it "sees when JSON apis are not equal due to different keys but same values" $ do
83 it "sees when JSON apis are not equal due to different keys but same values" $ do
93− Right (Failure _ err) <- withServantServer jsonApi jsonServer2 $ \burl1 ->
84+ FailedWith err <- withServantServer jsonApi jsonServer2 $ \burl1 ->
94 withServantServer jsonApi jsonServer4 $ \burl2 -> do
85 withServantServer jsonApi jsonServer4 $ \burl2 -> do
95− safeEvalExample $ serversEqual jsonApi burl1 burl2 args jsonEquality
86+ evalExample $ serversEqual jsonApi burl1 burl2 args jsonEquality
96 show err `shouldContain` "Server equality failed"
87 show err `shouldContain` "Server equality failed"
97 show err `shouldContain` "Path: /jsonComparison"
88 show err `shouldContain` "Path: /jsonComparison"
@@ -137,6 +128,10 @@ onlyJsonObjectSpec = describe "onlyJsonObjects" $ do
137 withServantServerAndContext octetAPI ctx serverOctetAPI $ \burl ->
128 withServantServerAndContext octetAPI ctx serverOctetAPI $ \burl ->
138 serverSatisfies octetAPI burl args (onlyJsonObjects <%> mempty)
129 serverSatisfies octetAPI burl args (onlyJsonObjects <%> mempty)
131+ it "does not fail when there is no content-type" $ do
132+ withServantServerAndContext api2 ctx serverFailing $ \burl ->
133+ serverSatisfies api2 burl args (onlyJsonObjects <%> mempty)
140notLongerThanSpec :: Spec
135notLongerThanSpec :: Spec
141notLongerThanSpec = describe "notLongerThan" $ do
136notLongerThanSpec = describe "notLongerThan" $ do
@@ -154,7 +149,7 @@ isComprehensiveSpec :: Spec
154isComprehensiveSpec = describe "HasGenRequest" $ do
149isComprehensiveSpec = describe "HasGenRequest" $ do
156 it "has instances for all 'servant' combinators" $ do
151 it "has instances for all 'servant' combinators" $ do
157− let _g = genRequest comprehensiveAPIWithoutRaw
152+ let _g = genRequest comprehensiveAPIWithoutStreamingOrRaw
158 True `shouldBe` True -- This is a type-level check
153 True `shouldBe` True -- This is a type-level check
160deepPathSpec :: Spec
155deepPathSpec :: Spec
@@ -190,6 +185,25 @@ queryFlagsSpec = describe "QueryFlags" $ do
190 qs = C.unpack $ queryString req
185 qs = C.unpack $ queryString req
191 qs `shouldBe` "one&two"
186 qs `shouldBe` "one&two"
188+htmlDocTypesSpec :: Spec
189+htmlDocTypesSpec = describe "HtmlDocTypes" $ do
191+ it "fails HTML without doctype correctly" $ do
192+ err <- withServantServerAndContext docTypeApi ctx noDocTypeServer $ \burl -> do
193+ evalExample $ serverSatisfies docTypeApi burl args
194+ (htmlIncludesDoctype <%> mempty)
195+ show err `shouldContain` "htmlIncludesDoctype"
197+ it "passes HTML with a doctype at start" $ do
198+ withServantServerAndContext docTypeApi ctx docTypeServer $ \burl ->
199+ serverSatisfies docTypeApi burl args (htmlIncludesDoctype <%> mempty)
201+ it "accepts json endpoints and passes over them in silence" $ do
202+ withServantServerAndContext api ctx server $ \burl -> do
203+ serverSatisfies (Proxy :: Proxy (Get '[JSON] Int)) burl args
204+ (htmlIncludesDoctype <%> mempty)
193makeRandomRequest :: Proxy LargeAPI -> BaseUrl -> IO Integer
207makeRandomRequest :: Proxy LargeAPI -> BaseUrl -> IO Integer
194makeRandomRequest large burl = do
208makeRandomRequest large burl = do
195 req <- generate $ runGenRequest large
209 req <- generate $ runGenRequest large
@@ -259,7 +273,23 @@ server2 = return $ return 1
259server3 :: IO (Server API2)
273server3 :: IO (Server API2)
260server3 = return $ return 2
274server3 = return $ return 2
276+serverFailing :: IO (Server API2)
277+serverFailing = return . throwError $ err405
280+type HtmlDoctype = Get '[HTML] Blaze.Html
282+docTypeApi :: Proxy HtmlDoctype
285+docTypeServer :: IO (Server HtmlDoctype)
286+docTypeServer = pure $ pure $ Blaze5.docTypeHtml $ Blaze5.span "Hello Test!"
288+noDocTypeServer :: IO (Server HtmlDoctype)
289+noDocTypeServer = pure $ pure $ Blaze.text "Hello Test!"
292+-- Api for unbiased generation of requests tests
263largeApi :: Proxy LargeAPI
293largeApi :: Proxy LargeAPI
264largeApi = Proxy
294largeApi = Proxy
@@ -314,27 +344,14 @@ ctx = BasicAuthCheck (const . return $ NoSuchUser) :. EmptyContext
315------------------------------------------------------------------------------
345------------------------------------------------------------------------------
316evalExample :: (Example e, Arg e ~ ()) => e -> IO EvalResult
346evalExample :: (Example e, Arg e ~ ()) => e -> IO EvalResult
317−#if MIN_VERSION_hspec(2,4,0)
318evalExample e = do
347evalExample e = do
319 r <- safeEvaluateExample e defaultParams ($ ()) progCallback
348 r <- safeEvaluateExample e defaultParams ($ ()) progCallback
320− case r of
349+ case resultStatus r of
321− Left err -> return $ AnException err
322− Right Success -> return $ AllGood
350+ Success -> return $ AllGood
323− Right (Failure _ reason) -> return $ FailedWith $ show reason
351+ Failure _ reason -> return $ FailedWith $ show reason
324− Right (Pending _) -> error "should not happen"
326− progCallback _ = return ()
329− r <- try $ evaluateExample e defaultParams ($ ()) progCallback
331− Left err -> return $ AnException err
332− Right Success -> return $ AllGood
333− Right (Fail _ reason) -> return $ FailedWith reason
334− Right (Pending _) -> error "should not happen"
352+ Pending {} -> error "should not happen"
336 progCallback _ = return ()
354 progCallback _ = return ()
339data EvalResult
356data EvalResult
340 = AnException SomeException
357 = AnException SomeException
@@ -352,8 +369,3 @@ noOfTestCases = 20000
353noOfTestCases = 1000
370noOfTestCases = 1000
356−#if !MIN_VERSION_servant(0,8,0)
357−comprehensiveAPIWithoutRaw :: Proxy ComprehensiveAPI
358−comprehensiveAPIWithoutRaw = comprehensiveAPI