@@ -45,6 +45,7 @@ import qualified Data.Aeson.KeyMap as KM
45
45
import Data.Char (toUpper, GeneralCategory(Control,Surrogate), generalCategory)
46
46
import Data.Hashable (hash)
47
47
import Data.HashMap.Strict (HashMap)
48
+ import Data.Kind (Type)
48
49
import Data.List (isSuffixOf)
49
50
import Data.Maybe (fromMaybe)
50
51
import Data.Scientific (Scientific, scientific)
@@ -53,7 +54,9 @@ import Data.Text (Text)
53
54
import Data.Time (UTCTime, ZonedTime)
54
55
import Data.Time.Format.Compat (parseTimeM, defaultTimeLocale)
55
56
import GHC.Generics (Generic)
57
+ #if __GLASGOW_HASKELL__ >= 806
56
58
import GHC.Generics.Generically (Generically (..))
59
+ #endif
57
60
import Instances ()
58
61
import Numeric.Natural (Natural)
59
62
import Test.Tasty (TestTree, testGroup)
@@ -78,8 +81,9 @@ roundTripCamel2 :: String -> Assertion
78
81
roundTripCamel2 name = assertEqual "" name (camelFrom '_' $ camelTo2 '_' name)
79
82
80
83
camelFrom :: Char -> String -> String
81
- camelFrom c s = let (p:ps) = split c s
82
- in concat $ p : map capitalize ps
84
+ camelFrom c s = case split c s of
85
+ p:ps -> concat $ p : map capitalize ps
86
+ _ -> s -- shouldn't happen?
83
87
where
84
88
split c' s' = map L.unpack $ L.split c' $ L.pack s'
85
89
capitalize t = toUpper (head t) : tail t
@@ -115,38 +119,33 @@ goodProducer = assertEqual "partial encoding should not explode on undefined"
115
119
arch32bit = (maxBound :: Int) == 2147483647
116
120
117
121
-- Test decoding various UTC time formats
118
- --
119
- -- Note: the incomplete pattern matches for UTCTimes are completely
120
- -- intentional. The test expects these parses to succeed. If the
121
- -- pattern matches fails, there's a bug in either the test or in aeson
122
- -- and needs to be investigated.
123
122
utcTimeGood :: Assertion
124
123
utcTimeGood = do
125
- let ts1 = "2015-01-01T12:13:00.00Z" :: LT.Text
126
- let ts2 = "2015-01-01T12:13:00Z" :: LT.Text
124
+ let ts1 = "2015-01-01T12:13:00.00Z"
125
+ let ts2 = "2015-01-01T12:13:00Z"
127
126
-- 'T' between date and time is not required, can be space
128
- let ts3 = "2015-01-03 12:13:00.00Z" :: LT.Text
129
- let ts4 = "2015-01-03 12:13:00.125Z" :: LT.Text
130
- let (Just ( t1 :: UTCTime)) = parseWithAeson ts1
131
- let (Just ( t2 :: UTCTime)) = parseWithAeson ts2
132
- let (Just ( t3 :: UTCTime)) = parseWithAeson ts3
133
- let (Just ( t4 :: UTCTime)) = parseWithAeson ts4
127
+ let ts3 = "2015-01-03 12:13:00.00Z"
128
+ let ts4 = "2015-01-03 12:13:00.125Z"
129
+ t1 <- parseWithAeson ts1
130
+ t2 <- parseWithAeson ts2
131
+ t3 <- parseWithAeson ts3
132
+ t4 <- parseWithAeson ts4
134
133
assertEqual "utctime" (parseWithRead "%FT%T%QZ" ts1) t1
135
134
assertEqual "utctime" (parseWithRead "%FT%T%QZ" ts2) t2
136
135
assertEqual "utctime" (parseWithRead "%F %T%QZ" ts3) t3
137
136
assertEqual "utctime" (parseWithRead "%F %T%QZ" ts4) t4
138
137
-- Time zones. Both +HHMM and +HH:MM are allowed for timezone
139
138
-- offset, and MM may be omitted.
140
- let ts5 = "2015-01-01T12:30:00.00+00" :: LT.Text
141
- let ts6 = "2015-01-01T12:30:00.00+01:15" :: LT.Text
142
- let ts7 = "2015-01-01T12:30:00.00-02" :: LT.Text
143
- let ts8 = "2015-01-01T22:00:00.00-03" :: LT.Text
144
- let ts9 = "2015-01-01T22:00:00.00-04:30" :: LT.Text
145
- let (Just ( t5 :: UTCTime)) = parseWithAeson ts5
146
- let (Just ( t6 :: UTCTime)) = parseWithAeson ts6
147
- let (Just ( t7 :: UTCTime)) = parseWithAeson ts7
148
- let (Just ( t8 :: UTCTime)) = parseWithAeson ts8
149
- let (Just ( t9 :: UTCTime)) = parseWithAeson ts9
139
+ let ts5 = "2015-01-01T12:30:00.00+00"
140
+ let ts6 = "2015-01-01T12:30:00.00+01:15"
141
+ let ts7 = "2015-01-01T12:30:00.00-02"
142
+ let ts8 = "2015-01-01T22:00:00.00-03"
143
+ let ts9 = "2015-01-01T22:00:00.00-04:30"
144
+ t5 <- parseWithAeson ts5
145
+ t6 <- parseWithAeson ts6
146
+ t7 <- parseWithAeson ts7
147
+ t8 <- parseWithAeson ts8
148
+ t9 <- parseWithAeson ts9
150
149
assertEqual "utctime" (parseWithRead "%FT%T%QZ" "2015-01-01T12:30:00.00Z") t5
151
150
assertEqual "utctime" (parseWithRead "%FT%T%QZ" "2015-01-01T11:15:00.00Z") t6
152
151
assertEqual "utctime" (parseWithRead "%FT%T%QZ" "2015-01-01T14:30:00Z") t7
@@ -155,30 +154,31 @@ utcTimeGood = do
155
154
assertEqual "utctime" (parseWithRead "%FT%T%QZ" "2015-01-02T02:30:00Z") t9
156
155
157
156
-- Seconds in Time can be omitted
158
- let ts10 = "2015-01-03T12:13Z" :: LT.Text
159
- let ts11 = "2015-01-03 12:13Z" :: LT.Text
160
- let ts12 = "2015-01-01T12:30-02" :: LT.Text
161
- let (Just ( t10 :: UTCTime)) = parseWithAeson ts10
162
- let (Just ( t11 :: UTCTime)) = parseWithAeson ts11
163
- let (Just ( t12 :: UTCTime)) = parseWithAeson ts12
157
+ let ts10 = "2015-01-03T12:13Z"
158
+ let ts11 = "2015-01-03 12:13Z"
159
+ let ts12 = "2015-01-01T12:30-02"
160
+ t10 <- parseWithAeson ts10
161
+ t11 <- parseWithAeson ts11
162
+ t12 <- parseWithAeson ts12
164
163
assertEqual "utctime" (parseWithRead "%FT%H:%MZ" ts10) t10
165
164
assertEqual "utctime" (parseWithRead "%F %H:%MZ" ts11) t11
166
165
assertEqual "utctime" (parseWithRead "%FT%T%QZ" "2015-01-01T14:30:00Z") t12
167
166
168
167
-- leap seconds are included correctly
169
- let ts13 = "2015-08-23T23:59:60.128+00" :: LT.Text
170
- let (Just ( t13 :: UTCTime)) = parseWithAeson ts13
168
+ let ts13 = "2015-08-23T23:59:60.128+00"
169
+ t13 <- parseWithAeson ts13
171
170
assertEqual "utctime" (parseWithRead "%FT%T%QZ" "2015-08-23T23:59:60.128Z") t13
172
- let ts14 = "2015-08-23T23:59:60.999999999999+00" :: LT.Text
173
- let (Just ( t14 :: UTCTime)) = parseWithAeson ts14
171
+ let ts14 = "2015-08-23T23:59:60.999999999999+00"
172
+ t14 <- parseWithAeson ts14
174
173
assertEqual "utctime" (parseWithRead "%FT%T%QZ" "2015-08-23T23:59:60.999999999999Z") t14
175
174
176
175
where
177
176
parseWithRead :: String -> LT.Text -> UTCTime
178
177
parseWithRead f s =
179
178
fromMaybe (error "parseTime input malformed") . parseTimeM True defaultTimeLocale f . LT.unpack $ s
180
- parseWithAeson :: LT.Text -> Maybe UTCTime
181
- parseWithAeson s = decode . LT.encodeUtf8 $ LT.concat ["\"", s, "\""]
179
+
180
+ parseWithAeson :: LT.Text -> IO UTCTime
181
+ parseWithAeson s = either fail return . eitherDecode . LT.encodeUtf8 $ LT.concat ["\"", s, "\""]
182
182
183
183
-- Test that a few non-timezone qualified timestamp formats get
184
184
-- rejected if decoding to UTCTime.
@@ -659,7 +659,7 @@ bigNaturalKeyDecoding =
659
659
((eitherDecode :: L.ByteString -> Either String (HashMap Natural Value)) "{ \"1e2000\": null }")
660
660
661
661
-- A regression test for: https://github.com/bos/aeson/issues/757
662
- type family Fam757 :: * -> *
662
+ type family Fam757 :: Type -> Type
663
663
type instance Fam757 = Maybe
664
664
newtype Newtype757 a = MkNewtype757 (Fam757 a)
665
665
deriveToJSON1 defaultOptions ''Newtype757
0 commit comments