git.iko.soy/typeable/http-api-data
on master help sign in
Merge pull request #34 from phadej/uuid
9ac2465Nickolay Kudasov
CHANGELOG.md+6
@@ -1,3 +1,9 @@
1+0.3.1
2+---
3+
4+* Minor changes
5+ * Add instances for `Data.UUID`
6+
10.3
70.3
2---
8---
3* Major changes:
9* Major changes:
http-api-data.cabal+5−2
@@ -1,5 +1,5 @@
1name: http-api-data
1name: http-api-data
2−version: 0.3
2+version: 0.3.1
3license: BSD3
3license: BSD3
4license-file: LICENSE
4license-file: LICENSE
5author: Nickolay Kudasov <nickolay.kudasov@gmail.com>
5author: Nickolay Kudasov <nickolay.kudasov@gmail.com>
@@ -33,6 +33,7 @@ library
33 , time-locale-compat >=0.1.1.0 && <0.2
33 , time-locale-compat >=0.1.1.0 && <0.2
34 , unordered-containers
34 , unordered-containers
35 , uri-bytestring
35 , uri-bytestring
36+ , uuid-types >= 1.0.2 && <1.1
36 if flag(use-text-show)
37 if flag(use-text-show)
37 cpp-options: -DUSE_TEXT_SHOW
38 cpp-options: -DUSE_TEXT_SHOW
38 build-depends: text-show >= 2
39 build-depends: text-show >= 2
@@ -58,12 +59,14 @@ test-suite spec
58 , hspec >= 1.3
59 , hspec >= 1.3
59 , base >= 4 && < 5
60 , base >= 4 && < 5
60 , bytestring
61 , bytestring
61− , QuickCheck
62+ , QuickCheck >=2.9
63+ , quickcheck-instances >= 0.3.12
62 , unordered-containers
64 , unordered-containers
63 , http-api-data
65 , http-api-data
64 , text
66 , text
65 , time
67 , time
66 , bytestring
68 , bytestring
69+ , uuid
67
70
68test-suite doctest
71test-suite doctest
69 ghc-options: -Wall
72 ghc-options: -Wall
src/Web/Internal/HttpApiData.hs+9
@@ -46,6 +46,8 @@ import Text.ParserCombinators.ReadP (readP_to_S)
46import TextShow (TextShow, showt)
46import TextShow (TextShow, showt)
47#endif
47#endif
48
48
49+import qualified Data.UUID.Types as UUID
50+
49-- $setup
51-- $setup
50-- >>> data BasicAuthToken = BasicAuthToken Text deriving (Show)
52-- >>> data BasicAuthToken = BasicAuthToken Text deriving (Show)
51-- >>> instance FromHttpApiData BasicAuthToken where parseHeader h = BasicAuthToken <$> parseHeaderWithPrefix "Basic " h; parseQueryParam p = BasicAuthToken <$> parseQueryParam p
53-- >>> instance FromHttpApiData BasicAuthToken where parseHeader h = BasicAuthToken <$> parseHeaderWithPrefix "Basic " h; parseQueryParam p = BasicAuthToken <$> parseQueryParam p
@@ -577,3 +579,10 @@ instance (FromHttpApiData a, FromHttpApiData b) => FromHttpApiData (Either a b)
577 Left _ <!> y = y
579 Left _ <!> y = y
578 x <!> _ = x
580 x <!> _ = x
579
581
582+instance ToHttpApiData UUID.UUID where
583+ toUrlPiece = UUID.toText
584+ toHeader = UUID.toASCIIBytes
585+
586+instance FromHttpApiData UUID.UUID where
587+ parseUrlPiece = maybe (Left "invalid UUID") Right . UUID.fromText
588+ parseHeader = maybe (Left "invalid UUID") Right . UUID.fromASCIIBytes
stack-ghc-7.10.yaml+2−1
@@ -7,5 +7,6 @@ flags:
7 http-api-data:
7 http-api-data:
8 use-text-show: false
8 use-text-show: false
9
9
10−extra-deps: []
10+extra-deps:
11+- QuickCheck-2.9.2
11extra-package-dbs: []
12extra-package-dbs: []
stack-ghc-7.8.yaml+3
@@ -20,4 +20,7 @@ extra-deps:
20- base-orphans-0.5.4
20- base-orphans-0.5.4
21- generic-deriving-1.9.0
21- generic-deriving-1.9.0
22- doctest-0.11.0
22- doctest-0.11.0
23+- QuickCheck-2.9.2
24+- quickcheck-instances-0.3.12
25+- quickcheck-io-0.1.3
23extra-package-dbs: []
26extra-package-dbs: []
stack.yaml+2−1
@@ -7,5 +7,6 @@ flags:
7 http-api-data:
7 http-api-data:
8 use-text-show: false
8 use-text-show: false
9
9
10−extra-deps: []
10+extra-deps:
11+- QuickCheck-2.9.2
11extra-package-dbs: []
12extra-package-dbs: []
test/Web/Internal/HttpApiDataSpec.hs+31−4
@@ -2,6 +2,7 @@
2{-# LANGUAGE ScopedTypeVariables #-}
2{-# LANGUAGE ScopedTypeVariables #-}
3module Web.Internal.HttpApiDataSpec (spec) where
3module Web.Internal.HttpApiDataSpec (spec) where
4
4
5+import Control.Applicative
5import Data.Int
6import Data.Int
6import Data.Word
7import Data.Word
7import Data.Time
8import Data.Time
@@ -9,6 +10,7 @@ import qualified Data.Text as T
9import qualified Data.Text.Lazy as L
10import qualified Data.Text.Lazy as L
10import qualified Data.ByteString as BS
11import qualified Data.ByteString as BS
11import Data.Version
12import Data.Version
13+import qualified Data.UUID as UUID
12
14
13import Data.Proxy
15import Data.Proxy
14
16
@@ -30,6 +32,10 @@ import Web.Internal.TestInstances
30checkUrlPiece :: forall a. (Eq a, ToHttpApiData a, FromHttpApiData a, Show a, Arbitrary a) => Proxy a -> String -> Spec
32checkUrlPiece :: forall a. (Eq a, ToHttpApiData a, FromHttpApiData a, Show a, Arbitrary a) => Proxy a -> String -> Spec
31checkUrlPiece _ name = prop name (toUrlPiece <=> parseUrlPiece :: a -> Bool)
33checkUrlPiece _ name = prop name (toUrlPiece <=> parseUrlPiece :: a -> Bool)
32
34
35+-- | Check with given generator
36+checkUrlPiece' :: forall a. (Eq a, ToHttpApiData a, FromHttpApiData a, Show a) => Gen a -> String -> Spec
37+checkUrlPiece' gen name = prop name $ forAll gen (toUrlPiece <=> parseUrlPiece)
38+
33-- | Check case insensitivity for @parseUrlPiece@.
39-- | Check case insensitivity for @parseUrlPiece@.
34checkUrlPieceI :: forall a. (Eq a, ToHttpApiData a, FromHttpApiData a, Arbitrary a) => Proxy a -> String -> Spec
40checkUrlPieceI :: forall a. (Eq a, ToHttpApiData a, FromHttpApiData a, Arbitrary a) => Proxy a -> String -> Spec
35checkUrlPieceI _ = checkUrlPiece (Proxy :: Proxy (RandomCase a))
41checkUrlPieceI _ = checkUrlPiece (Proxy :: Proxy (RandomCase a))
@@ -56,11 +62,12 @@ spec = do
56 checkUrlPiece (Proxy :: Proxy T.Text) "Text.Strict"
62 checkUrlPiece (Proxy :: Proxy T.Text) "Text.Strict"
57 checkUrlPiece (Proxy :: Proxy L.Text) "Text.Lazy"
63 checkUrlPiece (Proxy :: Proxy L.Text) "Text.Lazy"
58 checkUrlPiece (Proxy :: Proxy Day) "Day"
64 checkUrlPiece (Proxy :: Proxy Day) "Day"
59− checkUrlPiece (Proxy :: Proxy LocalTime) "LocalTime"
65+ checkUrlPiece' localTimeGen "LocalTime"
60− checkUrlPiece (Proxy :: Proxy ZonedTime) "ZonedTime"
66+ checkUrlPiece' zonedTimeGen "ZonedTime"
61− checkUrlPiece (Proxy :: Proxy UTCTime) "UTCTime"
67+ checkUrlPiece' utcTimeGen "UTCTime"
62− checkUrlPiece (Proxy :: Proxy NominalDiffTime) "NominalDiffTime"
68+ checkUrlPiece' nominalDiffTimeGen "NominalDiffTime"
63 checkUrlPiece (Proxy :: Proxy Version) "Version"
69 checkUrlPiece (Proxy :: Proxy Version) "Version"
70+ checkUrlPiece' uuidGen "UUID"
64
71
65 checkUrlPiece (Proxy :: Proxy (Maybe String)) "Maybe String"
72 checkUrlPiece (Proxy :: Proxy (Maybe String)) "Maybe String"
66 checkUrlPieceI (Proxy :: Proxy (Maybe Integer)) "Maybe Integer"
73 checkUrlPieceI (Proxy :: Proxy (Maybe Integer)) "Maybe Integer"
@@ -80,3 +87,23 @@ spec = do
80
87
81 it "invalid utf8 is handled" $ do
88 it "invalid utf8 is handled" $ do
82 parseHeaderMaybe (BS.pack [128]) `shouldBe` (Nothing :: Maybe T.Text)
89 parseHeaderMaybe (BS.pack [128]) `shouldBe` (Nothing :: Maybe T.Text)
90+
91+uuidGen :: Gen UUID.UUID
92+uuidGen = UUID.fromWords <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary
93+
94+-- TODO: this generators don't generate full range items
95+localTimeGen :: Gen LocalTime
96+localTimeGen = LocalTime
97+ <$> arbitrary
98+ <*> liftA3 TimeOfDay (choose (0, 23)) (choose (0, 59)) (fromInteger <$> choose (0, 60))
99+
100+zonedTimeGen :: Gen ZonedTime
101+zonedTimeGen = ZonedTime
102+ <$> localTimeGen -- Note: not arbitrary!
103+ <*> liftA3 TimeZone arbitrary arbitrary (vectorOf 3 (elements ['A'..'Z']))
104+
105+utcTimeGen :: Gen UTCTime
106+utcTimeGen = UTCTime <$> arbitrary <*> fmap fromInteger (choose (0, 86400))
107+
108+nominalDiffTimeGen :: Gen NominalDiffTime
109+nominalDiffTimeGen = fromInteger <$> arbitrary
test/Web/Internal/TestInstances.hs+1−37
@@ -9,58 +9,22 @@ module Web.Internal.TestInstances
9 ) where
9 ) where
10
10
11import Control.Applicative
11import Control.Applicative
12−import qualified Data.ByteString.Lazy.Char8 as BSL
13import Data.Char
12import Data.Char
14import qualified Data.HashMap.Strict as HashMap
13import qualified Data.HashMap.Strict as HashMap
15import qualified Data.Text as T
14import qualified Data.Text as T
16−import qualified Data.Text.Lazy as L
17import Data.Time
15import Data.Time
18−import Data.Version
19import GHC.Exts (fromList)
16import GHC.Exts (fromList)
20import GHC.Generics
17import GHC.Generics
21
18
22import Test.QuickCheck
19import Test.QuickCheck
20+import Test.QuickCheck.Instances ()
23
21
24import Web.Internal.FormUrlEncoded
22import Web.Internal.FormUrlEncoded
25import Web.Internal.HttpApiData
23import Web.Internal.HttpApiData
26
24
27−instance Arbitrary T.Text where
28− arbitrary = T.pack <$> arbitrary
29−
30−instance Arbitrary L.Text where
31− arbitrary = L.pack <$> arbitrary
32−
33−instance Arbitrary BSL.ByteString where
34− arbitrary = BSL.pack <$> arbitrary
35−
36−instance Arbitrary Day where
37− arbitrary = liftA3 fromGregorian (fmap abs arbitrary) arbitrary arbitrary
38−
39−instance Arbitrary LocalTime where
40− arbitrary = LocalTime
41− <$> arbitrary
42− <*> liftA3 TimeOfDay (choose (0, 23)) (choose (0, 59)) (fromInteger <$> choose (0, 60))
43−
44instance Eq ZonedTime where
25instance Eq ZonedTime where
45 ZonedTime t (TimeZone x _ _) == ZonedTime t' (TimeZone y _ _) = t == t' && x == y
26 ZonedTime t (TimeZone x _ _) == ZonedTime t' (TimeZone y _ _) = t == t' && x == y
46
27
47−instance Arbitrary ZonedTime where
48− arbitrary = ZonedTime
49− <$> arbitrary
50− <*> liftA3 TimeZone arbitrary arbitrary (vectorOf 3 (elements ['A'..'Z']))
51−
52−instance Arbitrary UTCTime where
53− arbitrary = UTCTime <$> arbitrary <*> fmap fromInteger (choose (0, 86400))
54−
55−instance Arbitrary NominalDiffTime where
56− arbitrary = fromInteger <$> arbitrary
57−
58−instance Arbitrary Version where
59− arbitrary = (version . map abs) <$> nonempty
60− where
61− version branch = Version branch []
62− nonempty = liftA2 (:) arbitrary arbitrary
63−
64instance Arbitrary Form where
28instance Arbitrary Form where
65 arbitrary = fromList <$> arbitrary
29 arbitrary = fromList <$> arbitrary
66
30