@@ -1,4 +1,4 @@
1−{-# LANGUAGE CPP, DeriveGeneric, OverloadedStrings, ScopedTypeVariables, TemplateHaskell, GeneralizedNewtypeDeriving #-}
1+{-# LANGUAGE CPP, GADTs, DeriveGeneric, OverloadedStrings, ScopedTypeVariables, TemplateHaskell, GeneralizedNewtypeDeriving #-}
22#if __GLASGOW_HASKELL__ >= 708
33{-# LANGUAGE DataKinds #-}
44#endif
@@ -10,6 +10,9 @@ module UnitTests (ioTests, tests) where
1010import Prelude ()
1111import Prelude.Compat
1212
13+import Types (I, Compose3, Compose3', Approx(..))
14+import Instances ()
15+
1316import Control.Applicative (Const(..))
1417import Control.Monad (forM)
1518import Data.Aeson (FromJSONKeyFunction(..), FromJSONKey(..), decode, eitherDecode, encode, genericToJSON, genericToEncoding, object, FromJSON(..), withObject, (.=), (.:), (.:?), (.:!))
@@ -20,6 +23,8 @@ import Data.Aeson.Types (ToJSON(..), Value, camelTo, camelTo2, defaultOptions, o
2023import Data.Char (toUpper)
2124import Data.Hashable (hash)
2225import Data.List.NonEmpty (NonEmpty(..))
26+import Data.Functor.Compose (Compose (..))
27+import Data.Functor.Identity (Identity (..))
2328import Data.Maybe (fromMaybe)
2429import Data.Proxy (Proxy(..))
2530import Data.Sequence (Seq)
@@ -70,6 +75,7 @@ tests = testGroup "unit" [
7075 , testGroup ".:, .:?, .:!" $ fmap (testCase "-") dotColonMark
7176 , testGroup "To JSON representation" $ fmap (testCase "-") jsonEncoding
7277 , testGroup "From JSON representation" $ fmap (testCase "-") jsonDecoding
78+ , testGroup "To/From JSON representation" $ fmap assertJsonExample jsonExamples
7379 , testGroup "JSONPath" $ fmap (testCase "-") jsonPath
7480 , testGroup "Hashable laws" $ fmap (testCase "-") hashableLaws
7581 , testGroup "Issue #351" $ fmap (testCase "-") issue351
@@ -234,31 +240,88 @@ dotColonMark = [
234240-----------------------------------------------------------------------------
235241
236242jsonEncoding :: [Assertion]
237−jsonEncoding = [
238− assertEqual "Either Left" "{\"Left\":1}" $ encode (Left 1 :: Either Int Int)
239− , assertEqual "Either Right" "{\"Right\":1}" $ encode (Right 1 :: Either Int Int)
240− , assertEqual "Nothing" "null" $ encode (Nothing :: Maybe Int)
241− , assertEqual "Just" "1" $ encode (Just 1 :: Maybe Int)
242− , assertEqual "Just Nothing" "null" $ encode (Just Nothing :: Maybe (Maybe Int))
243− , assertEqual "Proxy Int" "null" $ encode (Proxy :: Proxy Int)
244− , assertEqual "Tagged Char Int" "1" $ encode (Tagged 1 :: Tagged Char Int)
243+jsonEncoding =
244+ [
245+ -- https://github.com/bos/aeson/issues/376
246+ assertEqual "Just Nothing" "null" $ encode (Just Nothing :: Maybe (Maybe Int))
247+ -- infinities cannot be recovered, null is decoded as NaN
248+ , assertEqual "inf :: Double" "null" $ encode (Approx $ 1/0 :: Approx Double)
249+ ]
250+
251+data Example where
252+ Example
253+ :: (Eq a, Show a, ToJSON a, FromJSON a)
254+ => String -> L.ByteString -> a -> Example
255+
256+assertJsonExample :: Example -> Test
257+assertJsonExample (Example name bs val) = testCase name $ do
258+ assertEqual "encode" bs (encode val)
259+ assertEqual "decode" (Just val) (decode bs)
260+
261+jsonExamples :: [Example]
262+jsonExamples =
263+ [
264+ Example "Either Left" "{\"Left\":1}" (Left 1 :: Either Int Int)
265+ , Example "Either Right" "{\"Right\":1}" (Right 1 :: Either Int Int)
266+ , Example "Nothing" "null" (Nothing :: Maybe Int)
267+ , Example "Just" "1" (Just 1 :: Maybe Int)
268+ , Example "Proxy Int" "null" (Proxy :: Proxy Int)
269+ , Example "Tagged Char Int" "1" (Tagged 1 :: Tagged Char Int)
245270#if __GLASGOW_HASKELL__ >= 708
246271 -- Test Tagged instance is polykinded
247− , assertEqual "Tagged 123 Int" "1" $ encode (Tagged 1 :: Tagged 123 Int)
272+ , Example "Tagged 123 Int" "1" (Tagged 1 :: Tagged 123 Int)
248273#endif
249− , assertEqual "Const Char Int" "\"c\"" $ encode (Const 'c' :: Const Char Int)
250− , assertEqual "Tuple" "[1,2]" $ encode ((1, 2) :: (Int, Int))
251− , assertEqual "NonEmpty" "[1,2,3]" $ encode (1 :| [2, 3] :: NonEmpty Int)
252− , assertEqual "Seq" "[1,2,3]" $ encode (Seq.fromList [1, 2, 3] :: Seq.Seq Int)
253− , assertEqual "DList" "[1,2,3]" $ encode (DList.fromList [1, 2, 3] :: DList.DList Int)
254− , assertEqual "()" "[]" $ encode ()
255− , assertEqual "HashMap Int Int" "{\"0\":1,\"2\":3}" $ encode (HM.fromList [(0,1),(2,3)] :: HM.HashMap Int Int)
256− , assertEqual "nan :: Double" "null" $ encode (0/0 :: Double)
257− , assertEqual "inf :: Double" "null" $ encode (1/0 :: Double)
274+ , Example "Const Char Int" "\"c\"" (Const 'c' :: Const Char Int)
275+ , Example "Tuple" "[1,2]" ((1, 2) :: (Int, Int))
276+ , Example "NonEmpty" "[1,2,3]" (1 :| [2, 3] :: NonEmpty Int)
277+ , Example "Seq" "[1,2,3]" (Seq.fromList [1, 2, 3] :: Seq.Seq Int)
278+ , Example "DList" "[1,2,3]" (DList.fromList [1, 2, 3] :: DList.DList Int)
279+ , Example "()" "[]" ()
280+ , Example "HashMap Int Int" "{\"0\":1,\"2\":3}" (HM.fromList [(0,1),(2,3)] :: HM.HashMap Int Int)
281+ , Example "nan :: Double" "null" (Approx $ 0/0 :: Approx Double)
258282 -- Three separate cases, as ordering in HashMap is not defined
259− , assertEqual "HashMap Float Int, NaN" "{\"NaN\":1}" $ encode (HM.singleton (0/0) 1 :: HM.HashMap Float Int)
260− , assertEqual "HashMap Float Int, Infinity" "{\"Infinity\":1}" $ encode (HM.singleton (1/0) 1 :: HM.HashMap Float Int)
261− , assertEqual "HashMap Float Int, +Infinity" "{\"-Infinity\":1}" $ encode (HM.singleton (negate 1/0) 1 :: HM.HashMap Float Int)
283+ , Example "HashMap Float Int, NaN" "{\"NaN\":1}" (Approx $ HM.singleton (0/0) 1 :: Approx (HM.HashMap Float Int))
284+ , Example "HashMap Float Int, Infinity" "{\"Infinity\":1}" (HM.singleton (1/0) 1 :: HM.HashMap Float Int)
285+ , Example "HashMap Float Int, +Infinity" "{\"-Infinity\":1}" (HM.singleton (negate 1/0) 1 :: HM.HashMap Float Int)
286+
287+ -- Functors
288+ , Example "Identity Int" "1" (pure 1 :: Identity Int)
289+
290+ , Example "Identity Char" "\"x\"" (pure 'x' :: Identity Char)
291+ , Example "Identity String" "\"foo\"" (pure "foo" :: Identity String)
292+ , Example "[Identity Char]" "\"xy\"" ([pure 'x', pure 'y'] :: [Identity Char])
293+
294+ , Example "Maybe Char" "\"x\"" (pure 'x' :: Maybe Char)
295+ , Example "Maybe String" "\"foo\"" (pure "foo" :: Maybe String)
296+ , Example "Maybe [Identity Char]" "\"xy\"" (pure [pure 'x', pure 'y'] :: Maybe [Identity Char])
297+
298+ , Example "Compose I I Int" "1" (pure 1 :: Compose I I Int)
299+ , Example "Compose I [] Int" "[1]" (pure 1 :: Compose I [] Int)
300+ , Example "Compose [] I Int" "[1]" (pure 1 :: Compose [] I Int)
301+ , Example "Compose [] [] Int" "[[1]]" (pure 1 :: Compose [] [] Int)
302+
303+ , Example "Compose I I Char" "\"x\"" (pure 'x' :: Compose I I Char)
304+ , Example "Compose I [] Char" "\"x\"" (pure 'x' :: Compose I [] Char)
305+ , Example "Compose [] I Char" "\"x\"" (pure 'x' :: Compose [] I Char)
306+ , Example "Compose [] [] Char" "[\"x\"]" (pure 'x' :: Compose [] [] Char)
307+
308+ , Example "Compose3 I I I Char" "\"x\"" (pure 'x' :: Compose3 I I I Char)
309+ , Example "Compose3 I I [] Char" "\"x\"" (pure 'x' :: Compose3 I I [] Char)
310+ , Example "Compose3 I [] I Char" "\"x\"" (pure 'x' :: Compose3 I [] I Char)
311+ , Example "Compose3 I [] [] Char" "[\"x\"]" (pure 'x' :: Compose3 I [] [] Char)
312+ , Example "Compose3 [] I I Char" "\"x\"" (pure 'x' :: Compose3 [] I I Char)
313+ , Example "Compose3 [] I [] Char" "[\"x\"]" (pure 'x' :: Compose3 [] I [] Char)
314+ , Example "Compose3 [] [] I Char" "[\"x\"]" (pure 'x' :: Compose3 [] [] I Char)
315+ , Example "Compose3 [] [] [] Char" "[[\"x\"]]" (pure 'x' :: Compose3 [] [] [] Char)
316+
317+ , Example "Compose3' I I I Char" "\"x\"" (pure 'x' :: Compose3' I I I Char)
318+ , Example "Compose3' I I [] Char" "\"x\"" (pure 'x' :: Compose3' I I [] Char)
319+ , Example "Compose3' I [] I Char" "\"x\"" (pure 'x' :: Compose3' I [] I Char)
320+ , Example "Compose3' I [] [] Char" "[\"x\"]" (pure 'x' :: Compose3' I [] [] Char)
321+ , Example "Compose3' [] I I Char" "\"x\"" (pure 'x' :: Compose3' [] I I Char)
322+ , Example "Compose3' [] I [] Char" "[\"x\"]" (pure 'x' :: Compose3' [] I [] Char)
323+ , Example "Compose3' [] [] I Char" "[\"x\"]" (pure 'x' :: Compose3' [] [] I Char)
324+ , Example "Compose3' [] [] [] Char" "[[\"x\"]]" (pure 'x' :: Compose3' [] [] [] Char)
262325 ]
263326
264327jsonDecoding :: [Assertion]