hspec-wai 0.6.0 → 0.6.1
raw patch · 3 files changed
+81/−7 lines, 3 filesdep +QuickCheckdep ~bytestring
Dependencies added: QuickCheck
Dependency ranges changed: bytestring
Files
- hspec-wai.cabal +5/−4
- src/Test/Hspec/Wai.hs +13/−0
- src/Test/Hspec/Wai/Util.hs +63/−3
hspec-wai.cabal view
@@ -1,5 +1,5 @@ name: hspec-wai-version: 0.6.0+version: 0.6.1 license: MIT license-file: LICENSE copyright: (c) 2012-2014 Fujimura Daisuke,@@ -9,8 +9,8 @@ build-type: Simple cabal-version: >= 1.8 category: Testing-synopsis: Experimental Hspec support for testing WAI applications (depends on hspec2!)-description: Experimental Hspec support for testing WAI applications (depends on hspec2!)+synopsis: Experimental Hspec support for testing WAI applications+description: Experimental Hspec support for testing WAI applications source-repository head type: git@@ -29,7 +29,7 @@ Test.Hspec.Wai.Matcher build-depends: base == 4.*- , bytestring+ , bytestring >= 0.10 , text , transformers , case-insensitive@@ -61,3 +61,4 @@ , hspec-expectations , hspec+ , QuickCheck
src/Test/Hspec/Wai.hs view
@@ -14,6 +14,9 @@ , delete , request +-- ** Posting HTML forms+, postHtmlForm+ -- * Matching on the response , shouldRespondWith , ResponseMatcher(..)@@ -41,6 +44,7 @@ import Test.Hspec.Core.Hooks import Test.Hspec.Expectations (expectationFailure) +import Test.Hspec.Wai.Util import Test.Hspec.Wai.Internal import Test.Hspec.Wai.Matcher @@ -121,3 +125,12 @@ request method path headers body = getApp >>= liftIO . runSession (Wai.srequest $ SRequest req body) where req = setPath defaultRequest {requestMethod = method, requestHeaders = headers} path++-- | Perform a @POST@ request to the application under test.+--+-- The specified list of key-value pairs is encoded as+-- @application/x-www-form-urlencoded@ and used as request body.+--+-- In additon the @Content-Type@ is set to @application/x-www-form-urlencoded@.+postHtmlForm :: ByteString -> [(String, String)] -> WaiSession SResponse+postHtmlForm path = request methodPost path [(hContentType, "application/x-www-form-urlencoded")] . formUrlEncodeQuery
src/Test/Hspec/Wai/Util.hs view
@@ -4,17 +4,23 @@ import Control.Monad import Data.Monoid import Data.Maybe-import Data.Char+import Data.List+import Data.Word+import Data.Char hiding (ord)+import qualified Data.Char as Char import Data.ByteString (ByteString)-import qualified Data.ByteString.Char8 as B+import qualified Data.ByteString as B+import qualified Data.ByteString.Char8 as B8 import qualified Data.ByteString.Lazy as LB+import Data.ByteString.Lazy.Builder (Builder)+import qualified Data.ByteString.Lazy.Builder as Builder import qualified Data.Text as T import qualified Data.Text.Encoding as T import qualified Data.CaseInsensitive as CI import Network.HTTP.Types formatHeader :: Header -> String-formatHeader header@(name, value) = " " ++ fromMaybe (show header) (safeToString $ B.concat [CI.original name, ": ", value])+formatHeader header@(name, value) = " " ++ fromMaybe (show header) (safeToString $ B8.concat [CI.original name, ": ", value]) safeToString :: ByteString -> Maybe String safeToString bs = do@@ -27,3 +33,57 @@ -- for compatibility with older versions of `bytestring` toStrict :: LB.ByteString -> ByteString toStrict = mconcat . LB.toChunks++formUrlEncodeQuery :: [(String, String)] -> LB.ByteString+formUrlEncodeQuery = Builder.toLazyByteString . mconcat . intersperse amp . map encodePair+ where+ equals = Builder.word8 (ord '=')+ amp = Builder.word8 (ord '&')+ percent = Builder.word8 (ord '%')+ plus = Builder.word8 (ord '+')++ encodePair :: (String, String) -> Builder+ encodePair (key, value) = encode key <> equals <> encode value++ encode :: String -> Builder+ encode = escape . T.encodeUtf8 . T.pack . newlineNormalize++ newlineNormalize :: String -> String+ newlineNormalize input = case input of+ [] -> []+ '\n' : xs -> '\r' : '\n': newlineNormalize xs+ x : xs -> x : newlineNormalize xs++ escape :: ByteString -> Builder+ escape = mconcat . map f . B.unpack+ where+ f :: Word8 -> Builder+ f c+ | p c = Builder.word8 c+ | c == ord ' ' = plus+ | otherwise = percentEncode c++ p :: Word8 -> Bool+ p c =+ ord 'a' <= c && c <= ord 'z'+ || c == ord '_'+ || c == ord '*'+ || c == ord '-'+ || c == ord '.'+ || ord '0' <= c && c <= ord '9'+ || ord 'A' <= c && c <= ord 'Z'++ ord :: Char -> Word8+ ord = fromIntegral . Char.ord++ percentEncode :: Word8 -> Builder+ percentEncode n = percent <> hex hi <> hex lo+ where+ (hi, lo) = n `divMod` 16++ hex :: Word8 -> Builder+ hex n = Builder.word8 (offset + n)+ where+ offset+ | n < 10 = 48+ | otherwise = 55