git.iko.soy/typeable/servant
on master help sign in
Add test for FormUrlEncoded using Network.URL
4f91a28Timo von Holtz
servant.cabal+1
@@ -94,3 +94,4 @@ test-suite spec
94 , servant
94 , servant
95 , string-conversions
95 , string-conversions
96 , text
96 , text
97+ , url
src/Servant/API/ContentTypes.hs+2
@@ -261,6 +261,7 @@ encodeFormUrlEncoded xs =
261 let escape :: TextS.Text -> ByteString
261 let escape :: TextS.Text -> ByteString
262 escape = cs . escapeURIString isUnreserved . cs
262 escape = cs . escapeURIString isUnreserved . cs
263 encodePair :: (TextS.Text, TextS.Text) -> ByteString
263 encodePair :: (TextS.Text, TextS.Text) -> ByteString
264+ encodePair (k, "") = escape k
264 encodePair (k, v) = escape k <> "=" <> escape v
265 encodePair (k, v) = escape k <> "=" <> escape v
265 in B.intercalate "&" $ map encodePair xs
266 in B.intercalate "&" $ map encodePair xs
266
267
@@ -275,6 +276,7 @@ decodeFormUrlEncoded q = do
275 [k,v] -> return ( unescape k
276 [k,v] -> return ( unescape k
276 , unescape v
277 , unescape v
277 )
278 )
279+ [k] -> return ( unescape k, "" )
278 _ -> Left $ "not a valid pair: " <> cs p
280 _ -> Left $ "not a valid pair: " <> cs p
279 unescape :: TextS.Text -> TextS.Text
281 unescape :: TextS.Text -> TextS.Text
280 unescape = cs . unEscapeString . cs . TextS.intercalate "%20" . TextS.splitOn "+"
282 unescape = cs . unEscapeString . cs . TextS.intercalate "%20" . TextS.splitOn "+"
test/Servant/API/ContentTypesSpec.hs+11−1
@@ -6,11 +6,12 @@
6module Servant.API.ContentTypesSpec where
6module Servant.API.ContentTypesSpec where
7
7
8import Control.Applicative
8import Control.Applicative
9+import Control.Arrow
9import Data.Aeson
10import Data.Aeson
10import Data.Function (on)
11import Data.Function (on)
11import Data.Proxy
12import Data.Proxy
12
13
13−import Data.ByteString.Char8
14+import Data.ByteString.Char8 (ByteString, append, pack)
14import qualified Data.ByteString.Lazy as BSL
15import qualified Data.ByteString.Lazy as BSL
15import Data.List (maximumBy)
16import Data.List (maximumBy)
16import Data.Maybe (fromJust, isJust, isNothing)
17import Data.Maybe (fromJust, isJust, isNothing)
@@ -19,6 +20,7 @@ import Data.String.Conversions (cs)
19import qualified Data.Text as TextS
20import qualified Data.Text as TextS
20import qualified Data.Text.Lazy as TextL
21import qualified Data.Text.Lazy as TextL
21import GHC.Generics
22import GHC.Generics
23+import Network.URL (importParams, exportParams)
22import Test.Hspec
24import Test.Hspec
23import Test.QuickCheck
25import Test.QuickCheck
24import Test.QuickCheck.Instances ()
26import Test.QuickCheck.Instances ()
@@ -44,6 +46,14 @@ spec = describe "Servant.API.ContentTypes" $ do
44 let p = Proxy :: Proxy FormUrlEncoded
46 let p = Proxy :: Proxy FormUrlEncoded
45 property $ \x -> fromByteString p (toByteString p x) == Right (x::[(TextS.Text,TextS.Text)])
47 property $ \x -> fromByteString p (toByteString p x) == Right (x::[(TextS.Text,TextS.Text)])
46
48
49+ it "has fromByteString reverse exportParams (Network.URL)" $ do
50+ let p = Proxy :: Proxy FormUrlEncoded
51+ property $ \x -> (fromByteString p . cs . exportParams . map (cs *** cs) $ x) == Right (x::[(TextS.Text,TextS.Text)])
52+
53+ it "has importParams (Network.URL) reverse toByteString" $ do
54+ let p = Proxy :: Proxy FormUrlEncoded
55+ property $ \x -> (fmap (map (cs *** cs)) . importParams . cs . toByteString p $ x) == Just (x::[(TextS.Text,TextS.Text)])
56+
47 describe "The PlainText Content-Type type" $ do
57 describe "The PlainText Content-Type type" $ do
48
58
49 it "has fromByteString reverse toByteString (lazy Text)" $ do
59 it "has fromByteString reverse toByteString (lazy Text)" $ do