@@ -1,4 +1,4 @@
1−{-# LANGUAGE CPP, DeriveGeneric, OverloadedStrings, ScopedTypeVariables, TemplateHaskell, GeneralizedNewtypeDeriving #-}
1+{-# LANGUAGE CPP, GADTs, DeriveGeneric, OverloadedStrings, ScopedTypeVariables, TemplateHaskell, GeneralizedNewtypeDeriving #-}
2#if __GLASGOW_HASKELL__ >= 708
2#if __GLASGOW_HASKELL__ >= 708
3{-# LANGUAGE DataKinds #-}
3{-# LANGUAGE DataKinds #-}
@@ -10,6 +10,9 @@ module UnitTests (ioTests, tests) where
10import Prelude ()
10import Prelude ()
11import Prelude.Compat
11import Prelude.Compat
13+import Types (I, Compose3, Compose3', Approx(..))
13import Control.Applicative (Const(..))
16import Control.Applicative (Const(..))
14import Control.Monad (forM)
17import Control.Monad (forM)
15import Data.Aeson (FromJSONKeyFunction(..), FromJSONKey(..), decode, eitherDecode, encode, genericToJSON, genericToEncoding, object, FromJSON(..), withObject, (.=), (.:), (.:?), (.:!))
18import 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
20import Data.Char (toUpper)
23import Data.Char (toUpper)
21import Data.Hashable (hash)
24import Data.Hashable (hash)
22import Data.List.NonEmpty (NonEmpty(..))
25import Data.List.NonEmpty (NonEmpty(..))
26+import Data.Functor.Compose (Compose (..))
27+import Data.Functor.Identity (Identity (..))
23import Data.Maybe (fromMaybe)
28import Data.Maybe (fromMaybe)
24import Data.Proxy (Proxy(..))
29import Data.Proxy (Proxy(..))
25import Data.Sequence (Seq)
30import Data.Sequence (Seq)
@@ -70,6 +75,7 @@ tests = testGroup "unit" [
70 , testGroup ".:, .:?, .:!" $ fmap (testCase "-") dotColonMark
75 , testGroup ".:, .:?, .:!" $ fmap (testCase "-") dotColonMark
71 , testGroup "To JSON representation" $ fmap (testCase "-") jsonEncoding
76 , testGroup "To JSON representation" $ fmap (testCase "-") jsonEncoding
72 , testGroup "From JSON representation" $ fmap (testCase "-") jsonDecoding
77 , testGroup "From JSON representation" $ fmap (testCase "-") jsonDecoding
78+ , testGroup "To/From JSON representation" $ fmap assertJsonExample jsonExamples
73 , testGroup "JSONPath" $ fmap (testCase "-") jsonPath
79 , testGroup "JSONPath" $ fmap (testCase "-") jsonPath
74 , testGroup "Hashable laws" $ fmap (testCase "-") hashableLaws
80 , testGroup "Hashable laws" $ fmap (testCase "-") hashableLaws
75 , testGroup "Issue #351" $ fmap (testCase "-") issue351
81 , testGroup "Issue #351" $ fmap (testCase "-") issue351
@@ -234,31 +240,88 @@ dotColonMark = [
234-----------------------------------------------------------------------------
240-----------------------------------------------------------------------------
236jsonEncoding :: [Assertion]
242jsonEncoding :: [Assertion]
237−jsonEncoding = [
243+jsonEncoding =
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)
253+ :: (Eq a, Show a, ToJSON a, FromJSON a)
254+ => String -> L.ByteString -> a -> Example
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)
261+jsonExamples :: [Example]
238− assertEqual "Either Left" "{\"Left\":1}" $ encode (Left 1 :: Either Int Int)
264+ Example "Either Left" "{\"Left\":1}" (Left 1 :: Either Int Int)
239− , assertEqual "Either Right" "{\"Right\":1}" $ encode (Right 1 :: Either Int Int)
265+ , Example "Either Right" "{\"Right\":1}" (Right 1 :: Either Int Int)
240− , assertEqual "Nothing" "null" $ encode (Nothing :: Maybe Int)
266+ , Example "Nothing" "null" (Nothing :: Maybe Int)
241− , assertEqual "Just" "1" $ encode (Just 1 :: Maybe Int)
267+ , Example "Just" "1" (Just 1 :: Maybe Int)
242− , assertEqual "Just Nothing" "null" $ encode (Just Nothing :: Maybe (Maybe Int))
243− , assertEqual "Proxy Int" "null" $ encode (Proxy :: Proxy Int)
268+ , Example "Proxy Int" "null" (Proxy :: Proxy Int)
244− , assertEqual "Tagged Char Int" "1" $ encode (Tagged 1 :: Tagged Char Int)
269+ , Example "Tagged Char Int" "1" (Tagged 1 :: Tagged Char Int)
245#if __GLASGOW_HASKELL__ >= 708
270#if __GLASGOW_HASKELL__ >= 708
246 -- Test Tagged instance is polykinded
271 -- 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)
249− , assertEqual "Const Char Int" "\"c\"" $ encode (Const 'c' :: Const Char Int)
274+ , Example "Const Char Int" "\"c\"" (Const 'c' :: Const Char Int)
250− , assertEqual "Tuple" "[1,2]" $ encode ((1, 2) :: (Int, Int))
275+ , Example "Tuple" "[1,2]" ((1, 2) :: (Int, Int))
251− , assertEqual "NonEmpty" "[1,2,3]" $ encode (1 :| [2, 3] :: NonEmpty Int)
276+ , Example "NonEmpty" "[1,2,3]" (1 :| [2, 3] :: NonEmpty Int)
252− , assertEqual "Seq" "[1,2,3]" $ encode (Seq.fromList [1, 2, 3] :: Seq.Seq Int)
277+ , Example "Seq" "[1,2,3]" (Seq.fromList [1, 2, 3] :: Seq.Seq Int)
253− , assertEqual "DList" "[1,2,3]" $ encode (DList.fromList [1, 2, 3] :: DList.DList Int)
278+ , Example "DList" "[1,2,3]" (DList.fromList [1, 2, 3] :: DList.DList Int)
254− , assertEqual "()" "[]" $ encode ()
279+ , Example "()" "[]" ()
255− , assertEqual "HashMap Int Int" "{\"0\":1,\"2\":3}" $ encode (HM.fromList [(0,1),(2,3)] :: HM.HashMap Int Int)
280+ , Example "HashMap Int Int" "{\"0\":1,\"2\":3}" (HM.fromList [(0,1),(2,3)] :: HM.HashMap Int Int)
256− , assertEqual "nan :: Double" "null" $ encode (0/0 :: Double)
281+ , Example "nan :: Double" "null" (Approx $ 0/0 :: Approx Double)
257− , assertEqual "inf :: Double" "null" $ encode (1/0 :: Double)
258 -- Three separate cases, as ordering in HashMap is not defined
282 -- 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)
283+ , Example "HashMap Float Int, NaN" "{\"NaN\":1}" (Approx $ HM.singleton (0/0) 1 :: Approx (HM.HashMap Float Int))
260− , assertEqual "HashMap Float Int, Infinity" "{\"Infinity\":1}" $ encode (HM.singleton (1/0) 1 :: HM.HashMap Float Int)
284+ , Example "HashMap Float Int, Infinity" "{\"Infinity\":1}" (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)
285+ , Example "HashMap Float Int, +Infinity" "{\"-Infinity\":1}" (HM.singleton (negate 1/0) 1 :: HM.HashMap Float Int)
288+ , Example "Identity Int" "1" (pure 1 :: Identity Int)
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])
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])
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)
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)
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)
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)
264jsonDecoding :: [Assertion]
327jsonDecoding :: [Assertion]