1{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE DeriveGeneric #-}
3{-# LANGUAGE MultiParamTypeClasses #-}
4{-# LANGUAGE OverloadedStrings #-}
5{-# OPTIONS_GHC -fno-warn-orphans #-}
6module Servant.API.ContentTypesSpec where
8import Control.Applicative
10import Data.Function (on)
13import Data.ByteString.Char8
14import qualified Data.ByteString.Lazy as BSL
15import Data.List (maximumBy)
16import Data.Maybe (fromJust, isJust, isNothing)
17import Data.String (IsString (..))
18import Data.String.Conversions (cs)
19import qualified Data.Text as TextS
20import qualified Data.Text.Lazy as TextL
24import Test.QuickCheck.Instances ()
26import Servant.API.ContentTypes
29spec = describe "Servant.API.ContentTypes" $ do
31 describe "The JSON Content-Type type" $ do
33 it "has fromByteString reverse toByteString for valid top-level json ([Int]) " $ do
34 let p = Proxy :: Proxy JSON
35 property $ \x -> fromByteString p (toByteString p x) == Right (x::[Int])
37 it "has fromByteString reverse toByteString for valid top-level json " $ do
38 let p = Proxy :: Proxy JSON
39 property $ \x -> fromByteString p (toByteString p x) == Right (x::SomeData)
41 describe "The PlainText Content-Type type" $ do
43 it "has fromByteString reverse toByteString (lazy Text)" $ do
44 let p = Proxy :: Proxy PlainText
45 property $ \x -> fromByteString p (toByteString p x) == Right (x::TextL.Text)
47 it "has fromByteString reverse toByteString (strict Text)" $ do
48 let p = Proxy :: Proxy PlainText
49 property $ \x -> fromByteString p (toByteString p x) == Right (x::TextS.Text)
51 describe "The OctetStream Content-Type type" $ do
53 it "is id (Lazy ByteString)" $ do
54 let p = Proxy :: Proxy OctetStream
55 property $ \x -> toByteString p x == (x :: BSL.ByteString)
56 && fromByteString p x == Right x
58 it "is fromStrict/toStrict (Strict ByteString)" $ do
59 let p = Proxy :: Proxy OctetStream
60 property $ \x -> toByteString p x == BSL.fromStrict (x :: ByteString)
61 && fromByteString p (BSL.fromStrict x) == Right x
63 describe "handleAcceptH" $ do
65 it "returns Nothing if the 'Accept' header doesn't match" $ do
66 handleAcceptH (Proxy :: Proxy '[JSON]) "text/plain" (3 :: Int)
67 `shouldSatisfy` isNothing
69 it "returns Just if the 'Accept' header matches" $ do
70 handleAcceptH (Proxy :: Proxy '[JSON]) "*/*" (3 :: Int)
71 `shouldSatisfy` isJust
72 handleAcceptH (Proxy :: Proxy '[PlainText, JSON]) "application/json" (3 :: Int)
73 `shouldSatisfy` isJust
74 handleAcceptH (Proxy :: Proxy '[PlainText, JSON, OctetStream])
75 "application/octet-stream" ("content" :: ByteString)
76 `shouldSatisfy` isJust
78 it "returns the Content-Type as the first element of the tuple" $ do
79 handleAcceptH (Proxy :: Proxy '[JSON]) "*/*" (3 :: Int)
80 `shouldSatisfy` ((== "application/json") . fst . fromJust)
81 handleAcceptH (Proxy :: Proxy '[PlainText, JSON]) "application/json" (3 :: Int)
82 `shouldSatisfy` ((== "application/json") . fst . fromJust)
83 handleAcceptH (Proxy :: Proxy '[PlainText, JSON, OctetStream])
84 "application/octet-stream" ("content" :: ByteString)
85 `shouldSatisfy` ((== "application/octet-stream") . fst . fromJust)
87 it "returns the appropriately serialized representation" $ do
88 property $ \x -> handleAcceptH (Proxy :: Proxy '[JSON]) "*/*" (x :: SomeData)
89 == Just ("application/json", encode x)
91 it "respects the Accept spec ordering" $ do
92 let highest a b c = maximumBy (compare `on` snd)
93 [ ("application/octet-stream", a)
94 , ("application/json", b)
95 , ("text/plain;charset=utf-8", c)
97 let acceptH a b c = addToAccept (Proxy :: Proxy OctetStream) a $
98 addToAccept (Proxy :: Proxy JSON) b $
99 addToAccept (Proxy :: Proxy PlainText ) c ""
100 let val a b c i = handleAcceptH (Proxy :: Proxy '[OctetStream, JSON, PlainText])
101 (acceptH a b c) (i :: Int)
102 property $ \a b c i -> fst (fromJust $ val a b c i) == fst (highest a b c)
104 describe "handleCTypeH" $ do
106 it "returns Nothing if the 'Content-Type' header doesn't match" $ do
107 handleCTypeH (Proxy :: Proxy '[JSON]) "text/plain" "๐ฝ๐ฑ๐ฎ ๐ฝ๐ฒ๐ถ๐ฎ ๐ฑ๐ช๐ผ ๐ฌ๐ธ๐ถ๐ฎ, ๐ฝ๐ฑ๐ฎ ๐๐ช๐ต๐ป๐พ๐ผ ๐ผ๐ช๐ฒ๐ญ "
108 `shouldBe` (Nothing :: Maybe (Either String Value))
110 context "the 'Content-Type' header matches" $ do
111 it "returns Just if the parameter matches" $ do
112 handleCTypeH (Proxy :: Proxy '[JSON]) "application/json"
113 "๐ฅ๐ ๐ฅ๐๐๐ ๐ ๐ ๐๐๐๐ช ๐ฅ๐๐๐๐๐ค "
114 `shouldSatisfy` (isJust :: Maybe (Either String Value) -> Bool)
116 it "returns Just if there is no parameter" $ do
117 handleCTypeH (Proxy :: Proxy '[JSON]) "application/json"
118 "๐ฅ๐ ๐ฅ๐๐๐ ๐ ๐ ๐๐๐๐ช ๐ฅ๐๐๐๐๐ค "
119 `shouldSatisfy` (isJust :: Maybe (Either String Value) -> Bool)
121 it "returns Just Left if the decoding fails" $ do
122 let isJustLeft :: Maybe (Either String Value) -> Bool
123 isJustLeft (Just (Left _)) = True
125 handleCTypeH (Proxy :: Proxy '[JSON]) "application/json"
126 "๐บ๐ ๐๐๐๐๐--๐๐๐ ๐๐๐๐๐--๐๐๐ ๐๐๐๐๐๐๐-๐๐๐-- "
127 `shouldSatisfy` isJustLeft
129 it "returns Just (Right val) if the decoding succeeds" $ do
130 let val = SomeData "Of cabbages--and kings" 12
131 handleCTypeH (Proxy :: Proxy '[JSON]) "application/json"
133 `shouldBe` Just (Right val)
136data SomeData = SomeData { record1 :: String, record2 :: Int }
137 deriving (Generic, Eq, Show)
139newtype ZeroToOne = ZeroToOne Float
140 deriving (Eq, Show, Ord)
142instance FromJSON SomeData
144instance ToJSON SomeData
146instance Arbitrary SomeData where
147 arbitrary = SomeData <$> arbitrary <*> arbitrary
149instance Arbitrary ZeroToOne where
150 arbitrary = ZeroToOne <$> elements [ x / 10 | x <- [1..10]]
152instance MimeRender OctetStream Int where
153 toByteString _ = cs . show
155instance MimeRender PlainText Int where
156 toByteString _ = cs . show
158instance MimeRender PlainText ByteString where
161instance ToJSON ByteString where
162 toJSON x = object [ "val" .= x ]
164instance IsString AcceptHeader where
165 fromString = AcceptHeader . fromString
167addToAccept :: Accept a => Proxy a -> ZeroToOne -> AcceptHeader -> AcceptHeader
168addToAccept p (ZeroToOne f) (AcceptHeader h) = AcceptHeader (cont h)
169 where new = cs (show $ contentType p) `append` "; q=" `append` pack (show f)
171 cont old = old `append` ", " `append` new
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list