packages feed

hspec-wai-json 0.6.1 → 0.12.0

raw patch · 4 files changed

Files

LICENSE view
@@ -1,4 +1,4 @@-Copyright (c) 2012-2014 Fujimura Daisuke, Simon Hengel+Copyright (c) 2012-2018 Fujimura Daisuke, Simon Hengel  Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal
hspec-wai-json.cabal view
@@ -1,54 +1,62 @@--- This file has been generated from package.yml by hpack version 0.2.0.+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.38.3. -- -- see: https://github.com/sol/hpack -name:             hspec-wai-json-version:          0.6.1-homepage:         https://github.com/hspec/hspec-wai#readme-bug-reports:      https://github.com/hspec/hspec-wai/issues-license:          MIT-license-file:     LICENSE-copyright:        (c) 2012-2014 Fujimura Daisuke,-                  (c) 2014 Simon Hengel-author:           Fujimura Daisuke <me@fujimuradaisuke.com>,-                  Simon Hengel <sol@typeful.net>-maintainer:       Fujimura Daisuke <me@fujimuradaisuke.com>,-                  Simon Hengel <sol@typeful.net>-build-type:       Simple-cabal-version:    >= 1.10-category:         Testing-synopsis:         Testing JSON APIs with hspec-wai-description:      Testing JSON APIs with hspec-wai+name:           hspec-wai-json+version:        0.12.0+synopsis:       Testing JSON APIs with hspec-wai+description:    Testing JSON APIs with hspec-wai+category:       Testing+homepage:       https://github.com/hspec/hspec-wai#readme+bug-reports:    https://github.com/hspec/hspec-wai/issues+author:         Fujimura Daisuke <me@fujimuradaisuke.com>,+                Simon Hengel <sol@typeful.net>+maintainer:     Fujimura Daisuke <me@fujimuradaisuke.com>,+                Simon Hengel <sol@typeful.net>+copyright:      (c) 2012-2014 Fujimura Daisuke,+                (c) 2014-2018 Simon Hengel+license:        MIT+license-file:   LICENSE+build-type:     Simple  source-repository head   type: git   location: https://github.com/hspec/hspec-wai  library-  hs-source-dirs: src   exposed-modules:       Test.Hspec.Wai.JSON+  other-modules:+      Paths_hspec_wai_json+  hs-source-dirs:+      src+  ghc-options: -Wall   build-depends:-      base == 4.*-    , hspec-wai == 0.6.*+      aeson+    , aeson-qq >=0.7.3+    , base ==4.*     , bytestring-    , template-haskell-    , aeson-    , aeson-qq >= 0.7.3     , case-insensitive-  ghc-options: -Wall+    , hspec-wai ==0.12.0+    , template-haskell   default-language: Haskell2010  test-suite spec   type: exitcode-stdio-1.0-  hs-source-dirs: test   main-is: Spec.hs   other-modules:       Test.Hspec.Wai.JSONSpec+      Paths_hspec_wai_json+  hs-source-dirs:+      test+  ghc-options: -Wall+  build-tool-depends:+      hspec-discover:hspec-discover   build-depends:-      base == 4.*-    , hspec-wai-json-    , hspec-wai+      base ==4.*     , hspec-  ghc-options: -Wall+    , hspec-wai+    , hspec-wai-json   default-language: Haskell2010
src/Test/Hspec/Wai/JSON.hs view
@@ -5,17 +5,15 @@ , FromValue(..) ) where -import           Control.Arrow (second)-import           Data.List import           Data.ByteString.Lazy (ByteString)-import qualified Data.ByteString.Lazy as BL-import           Data.Aeson (Value, encode)+import qualified Data.ByteString.Char8 as B+import           Data.Char+import           Data.Aeson (Value, decode, encode) import           Data.Aeson.QQ-import qualified Data.CaseInsensitive as CI import           Language.Haskell.TH.Quote  import           Test.Hspec.Wai-import           Test.Hspec.Wai.Internal (formatHeader)+import           Test.Hspec.Wai.Matcher  -- $setup -- The examples in this module assume that you have the @QuasiQuotes@ language@@ -56,19 +54,44 @@   fromValue :: Value -> a  instance FromValue ResponseMatcher where-  fromValue v = ResponseMatcher 200 [MatchHeader p] (Just body)+  fromValue = ResponseMatcher 200 [matchHeader] . equalsJSON     where-      body = fromValue v--      permissibleHeaders = addIfASCII ("Content-Type", "application/json") [("Content-Type", "application/json; charset=utf-8")]+      matchHeader = MatchHeader $ \headers _body ->+        case lookup "Content-Type" headers of+          Just h | isJSON h -> Nothing+          _ -> Just $ unlines [+              "missing header:"+            , formatHeader ("Content-Type", "application/json")+            ]+      isJSON c = media == "application/json" && parameters `elem` ignoredParameters+        where+          (media, parameters) = let (m, p) = breakAt ';' c in (strip m, strip p) -      addIfASCII h = if BL.all (< 128) body then (h :) else id+          -- Technically, no parameters are required nor optional for+          -- application/json.  However, as charset=utf-8 is widely added by+          -- other software and compliant recipients should ignore any charset+          -- (as per http://www.iana.org/assignments/media-types/application/json)+          -- we ignore charset=utf-8 here.+          --+          -- This is a decision made for pragmatism!+          --+          -- I'm still pretty much against ignoring any other charsets.  Adding+          -- a charset parameter is non-standard and hspec-wai is not just a+          -- compliant recipients but a testing software.  Hence I take the+          -- stance that the job of a testing software is not just to accept+          -- what a compliant client would accept but also to enforce standard+          -- conformance.+          ignoredParameters = ["", "charset=utf-8"] -      mkCI = map (second CI.mk)+      breakAt c = fmap (B.drop 1) . B.break (== c)+      strip = B.reverse . B.dropWhile isSpace . B.reverse . B.dropWhile isSpace -      p headers = if any (`elem` mkCI permissibleHeaders) (mkCI headers)-        then Nothing-        else (Just . unlines) ("missing header:" : (intersperse "  OR" $ map formatHeader permissibleHeaders))+equalsJSON :: Value -> MatchBody+equalsJSON expected = MatchBody matcher+  where+    matcher headers actualBody = case decode actualBody of+      Just actual | actual == expected -> Nothing+      _ -> let MatchBody m = bodyEquals (encode expected) in m headers actualBody  instance FromValue ByteString where   fromValue = encode
test/Test/Hspec/Wai/JSONSpec.hs view
@@ -1,9 +1,13 @@-{-# LANGUAGE OverloadedStrings, QuasiQuotes #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE NoMonomorphismRestriction #-}+{-# OPTIONS_GHC -fno-warn-incomplete-uni-patterns #-} module Test.Hspec.Wai.JSONSpec (main, spec) where  import           Test.Hspec+import           Data.String -import           Test.Hspec.Wai+import           Test.Hspec.Wai hiding (pending) import           Test.Hspec.Wai.JSON  main :: IO ()@@ -12,33 +16,48 @@ spec :: Spec spec = do   describe "json" $ do+    context "when matching body" $ do+      let MatchBody matcher = matchBody [json|{foo: 23}|]++      it "ignores whitespace" $ do+        let+          actual = fromString $ unlines [+              "{"+            , show ("foo" :: String) ++ " : 23"+            , "}"+            ]+        matcher [] actual `shouldBe` Nothing++      it "rejects bodies that are not equal" $ do+        matcher [] [json|{foo: 42}|] `shouldBe` Just (unlines [+            "body mismatch:"+          , "  expected: {\"foo\":23}"+          , "  but got:  {\"foo\":42}"+          ])+     context "when matching Content-Type header" $ do-      context "when JSON is ASCII" $ do-        let [MatchHeader matcher] = matchHeaders [json|{foo: 23}|]-        it "accepts 'application/json'" $ do-          matcher [("Content-Type", "application/json")] `shouldBe` Nothing+      let+        body = [json|{foo: 23}|]+        [MatchHeader matcher] = matchHeaders body+        match = (`matcher` body) -        it "accepts 'application/json; charset=utf-8'" $ do-          matcher [("Content-Type", "application/json; charset=utf-8")] `shouldBe` Nothing+      it "accepts 'application/json'" $ do+        match [("Content-Type", "application/json")] `shouldBe` Nothing -        it "ignores case" $ do-          matcher [("Content-Type", "application/JSON; charset=UTF-8")] `shouldBe` Nothing+      it "ignores 'charset=utf-8'" $ do+        match [("Content-Type", "application/json;charset=utf-8")] `shouldBe` Nothing -        it "rejects other headers" $ do-          matcher [("Content-Type", "foobar")] `shouldBe` (Just . unlines) [-              "missing header:"-            , "  Content-Type: application/json"-            , "  OR"-            , "  Content-Type: application/json; charset=utf-8"-            ]+      it "ignores whitespace" $ do+        match [("Content-Type", "application/json ; charset=utf-8")] `shouldBe` Nothing -      context "when JSON contains Unicode" $ do-        let [MatchHeader matcher] = matchHeaders [json|{foo: #{"\955" :: String}}|]-        it "rejects 'application/json'" $ do-          matcher [("Content-Type", "application/json")] `shouldBe` (Just . unlines) [-              "missing header:"-            , "  Content-Type: application/json; charset=utf-8"-            ]+      it "requires a Content-Type header" $ do+        match [] `shouldBe` (Just. unlines) [+            "missing header:"+          , "  Content-Type: application/json"+          ] -        it "accepts 'application/json; charset=utf-8'" $ do-          matcher [("Content-Type", "application/json; charset=utf-8")] `shouldBe` Nothing+      it "rejects other values for Content-Type" $ do+        match [("Content-Type", "foobar")] `shouldBe` (Just . unlines) [+            "missing header:"+          , "  Content-Type: application/json"+          ]