2{-# LANGUAGE DeriveGeneric #-}
4{-# LANGUAGE OverloadedStrings #-}
5#if __GLASGOW_HASKELL__ >= 708
6{-# LANGUAGE DataKinds #-}
9------------------------------------------------------------------------------
10-- These tests assert that the JSON serialization doesn't change by accident.
11-----------------------------------------------------------------------------
13module SerializationFormatSpec
21import Control.Applicative (Const(..))
22import Data.Aeson (FromJSON(..), decode, encode, genericParseJSON, genericToEncoding, genericToJSON)
23import Data.Aeson.Types (Options(..), SumEncoding(..), ToJSON(..), defaultOptions)
24import Data.Fixed (Pico)
25import Data.Functor.Compose (Compose(..))
26import Data.Functor.Identity (Identity(..))
27import Data.Functor.Product (Product(..))
28import Data.Functor.Sum (Sum(..))
29import Data.List.NonEmpty (NonEmpty(..))
30import Data.Proxy (Proxy(..))
31import Data.Scientific (Scientific)
32import Data.Tagged (Tagged(..))
33import Data.Time (fromGregorian)
34import Data.Word (Word8)
35import GHC.Generics (Generic)
37import Test.Framework (Test, testGroup)
38import Test.Framework.Providers.HUnit (testCase)
39import Test.HUnit (assertFailure, assertEqual)
40import Types (Approx(..), Compose3, Compose3', I)
41import qualified Data.ByteString.Lazy.Char8 as L
42import qualified Data.DList as DList
43import qualified Data.HashMap.Strict as HM
44import qualified Data.HashSet as HashSet
45import qualified Data.IntMap as IntMap
46import qualified Data.IntSet as IntSet
47import qualified Data.Map as M
48import qualified Data.Monoid as Monoid
49import qualified Data.Semigroup as Semigroup
50import qualified Data.Sequence as Seq
51import qualified Data.Set as Set
52import qualified Data.Tree as Tree
53import qualified Data.UUID.Types as UUID
54import qualified Data.Vector as Vector
59 testGroup "To JSON representation" $ fmap assertJsonEncodingExample jsonEncodingExamples
60 , testGroup "From JSON representation" $ fmap assertJsonExample jsonDecodingExamples
61 , testGroup "To/From JSON representation" $ fmap assertJsonExample jsonExamples
65jsonExamples :: [Example]
68 Example "Either Left" "{\"Left\":1}" (Left 1 :: Either Int Int)
69 , Example "Either Right" "{\"Right\":1}" (Right 1 :: Either Int Int)
70 , Example "Nothing" "null" (Nothing :: Maybe Int)
71 , Example "Just" "1" (Just 1 :: Maybe Int)
72 , Example "Proxy Int" "null" (Proxy :: Proxy Int)
73 , Example "Tagged Char Int" "1" (Tagged 1 :: Tagged Char Int)
74#if __GLASGOW_HASKELL__ >= 708
75 -- Test Tagged instance is polykinded
76 , Example "Tagged 123 Int" "1" (Tagged 1 :: Tagged 123 Int)
78 , Example "Const Char Int" "\"c\"" (Const 'c' :: Const Char Int)
79 , Example "Tuple" "[1,2]" ((1, 2) :: (Int, Int))
80 , Example "NonEmpty" "[1,2,3]" (1 :| [2, 3] :: NonEmpty Int)
81 , Example "Seq" "[1,2,3]" (Seq.fromList [1, 2, 3] :: Seq.Seq Int)
82 , Example "DList" "[1,2,3]" (DList.fromList [1, 2, 3] :: DList.DList Int)
83 , Example "()" "[]" ()
85 , Example "HashMap Int Int" "{\"0\":1,\"2\":3}" (HM.fromList [(0,1),(2,3)] :: HM.HashMap Int Int)
86 , Example "Map Int Int" "{\"0\":1,\"2\":3}" (M.fromList [(0,1),(2,3)] :: M.Map Int Int)
87 , Example "Map (Tagged Int Int) Int" "{\"0\":1,\"2\":3}" (M.fromList [(Tagged 0,1),(Tagged 2,3)] :: M.Map (Tagged Int Int) Int)
88 , Example "Map [Int] Int" "[[[0],1],[[2],3]]" (M.fromList [([0],1),([2],3)] :: M.Map [Int] Int)
89 , Example "Map [Char] Int" "{\"ab\":1,\"cd\":3}" (M.fromList [("ab",1),("cd",3)] :: M.Map String Int)
90 , Example "Map [I Char] Int" "{\"ab\":1,\"cd\":3}" (M.fromList [(map pure "ab",1),(map pure "cd",3)] :: M.Map [I Char] Int)
92 , Example "nan :: Double" "null" (Approx $ 0/0 :: Approx Double)
94 , Example "Ordering LT" "\"LT\"" LT
95 , Example "Ordering EQ" "\"EQ\"" EQ
96 , Example "Ordering GT" "\"GT\"" GT
98 , Example "Float" "3.14" (3.14 :: Float)
99 , Example "Pico" "3.14" (3.14 :: Pico)
100 , Example "Scientific" "3.14" (3.14 :: Scientific)
102 , Example "UUID" "\"c2cc10e1-57d6-4b6f-9899-38d972112d8c\"" $ UUID.fromWords
103 0xc2cc10e1 0x57d64b6f 0x989938d9 0x72112d8c
105 , Example "Set Int" "[1,2,3]" (Set.fromList [3, 2, 1] :: Set.Set Int)
106 , Example "IntSet" "[1,2,3]" (IntSet.fromList [3, 2, 1])
107 , Example "IntMap" "[[1,2],[3,4]]" (IntMap.fromList [(3,4), (1,2)] :: IntMap.IntMap Int)
108 , Example "Vector" "[1,2,3]" (Vector.fromList [1, 2, 3] :: Vector.Vector Int)
109 , Example "HashSet Int" "[1,2,3]" (HashSet.fromList [3, 2, 1] :: HashSet.HashSet Int)
110 , Example "Tree Int" "[1,[[2,[[3,[]],[4,[]]]],[5,[]]]]" (let n = Tree.Node in n 1 [n 2 [n 3 [], n 4 []], n 5 []] :: Tree.Tree Int)
112 -- Three separate cases, as ordering in HashMap is not defined
113 , Example "HashMap Float Int, NaN" "{\"NaN\":1}" (Approx $ HM.singleton (0/0) 1 :: Approx (HM.HashMap Float Int))
114 , Example "HashMap Float Int, Infinity" "{\"Infinity\":1}" (HM.singleton (1/0) 1 :: HM.HashMap Float Int)
115 , Example "HashMap Float Int, +Infinity" "{\"-Infinity\":1}" (HM.singleton (negate 1/0) 1 :: HM.HashMap Float Int)
118 , Example "Identity Int" "1" (pure 1 :: Identity Int)
120 , Example "Identity Char" "\"x\"" (pure 'x' :: Identity Char)
121 , Example "Identity String" "\"foo\"" (pure "foo" :: Identity String)
122 , Example "[Identity Char]" "\"xy\"" ([pure 'x', pure 'y'] :: [Identity Char])
124 , Example "Maybe Char" "\"x\"" (pure 'x' :: Maybe Char)
125 , Example "Maybe String" "\"foo\"" (pure "foo" :: Maybe String)
126 , Example "Maybe [Identity Char]" "\"xy\"" (pure [pure 'x', pure 'y'] :: Maybe [Identity Char])
128 , Example "Day; year >= 1000" "\"1999-10-12\"" (fromGregorian 1999 10 12)
129 , Example "Day; year > 0 && < 1000" "\"0500-03-04\"" (fromGregorian 500 3 4)
130 , Example "Day; year == 0" "\"0000-02-20\"" (fromGregorian 0 2 20)
131 , Example "Day; year < 0" "\"-0234-01-01\"" (fromGregorian (-234) 1 1)
132 , Example "Day; year < -1000" "\"-1234-01-01\"" (fromGregorian (-1234) 1 1)
134 , Example "Product I Maybe Int" "[1,2]" (Pair (pure 1) (pure 2) :: Product I Maybe Int)
135 , Example "Product I Maybe Int" "[1,null]" (Pair (pure 1) Nothing :: Product I Maybe Int)
136 , Example "Product I [] Char" "[\"a\",\"foo\"]" (Pair (pure 'a') "foo" :: Product I [] Char)
138 , Example "Sum I [] Int: InL" "{\"InL\":1}" (InL (pure 1) :: Sum I [] Int)
139 , Example "Sum I [] Int: InR" "{\"InR\":[1,2]}" (InR [1, 2] :: Sum I [] Int)
140 , Example "Sum I [] Char: InR" "{\"InR\":\"foo\"}" (InR "foo" :: Sum I [] Char)
142 , Example "Compose I I Int" "1" (pure 1 :: Compose I I Int)
143 , Example "Compose I [] Int" "[1]" (pure 1 :: Compose I [] Int)
144 , Example "Compose [] I Int" "[1]" (pure 1 :: Compose [] I Int)
145 , Example "Compose [] [] Int" "[[1]]" (pure 1 :: Compose [] [] Int)
147 , Example "Compose I I Char" "\"x\"" (pure 'x' :: Compose I I Char)
148 , Example "Compose I [] Char" "\"x\"" (pure 'x' :: Compose I [] Char)
149 , Example "Compose [] I Char" "\"x\"" (pure 'x' :: Compose [] I Char)
150 , Example "Compose [] [] Char" "[\"x\"]" (pure 'x' :: Compose [] [] Char)
152 , Example "Compose3 I I I Char" "\"x\"" (pure 'x' :: Compose3 I I I Char)
153 , Example "Compose3 I I [] Char" "\"x\"" (pure 'x' :: Compose3 I I [] Char)
154 , Example "Compose3 I [] I Char" "\"x\"" (pure 'x' :: Compose3 I [] I Char)
155 , Example "Compose3 I [] [] Char" "[\"x\"]" (pure 'x' :: Compose3 I [] [] Char)
156 , Example "Compose3 [] I I Char" "\"x\"" (pure 'x' :: Compose3 [] I I Char)
157 , Example "Compose3 [] I [] Char" "[\"x\"]" (pure 'x' :: Compose3 [] I [] Char)
158 , Example "Compose3 [] [] I Char" "[\"x\"]" (pure 'x' :: Compose3 [] [] I Char)
159 , Example "Compose3 [] [] [] Char" "[[\"x\"]]" (pure 'x' :: Compose3 [] [] [] Char)
161 , Example "Compose3' I I I Char" "\"x\"" (pure 'x' :: Compose3' I I I Char)
162 , Example "Compose3' I I [] Char" "\"x\"" (pure 'x' :: Compose3' I I [] Char)
163 , Example "Compose3' I [] I Char" "\"x\"" (pure 'x' :: Compose3' I [] I Char)
164 , Example "Compose3' I [] [] Char" "[\"x\"]" (pure 'x' :: Compose3' I [] [] Char)
165 , Example "Compose3' [] I I Char" "\"x\"" (pure 'x' :: Compose3' [] I I Char)
166 , Example "Compose3' [] I [] Char" "[\"x\"]" (pure 'x' :: Compose3' [] I [] Char)
167 , Example "Compose3' [] [] I Char" "[\"x\"]" (pure 'x' :: Compose3' [] [] I Char)
168 , Example "Compose3' [] [] [] Char" "[[\"x\"]]" (pure 'x' :: Compose3' [] [] [] Char)
170 , Example "MyEither Int String: Left" "42" (MyLeft 42 :: MyEither Int String)
171 , Example "MyEither Int String: Right" "\"foo\"" (MyRight "foo" :: MyEither Int String)
173 -- newtypes from Monoid/Semigroup
174 , Example "Monoid.Dual Int" "2" (pure 2 :: Monoid.Dual Int)
175 , Example "Monoid.First Int" "2" (pure 2 :: Monoid.First Int)
176 , Example "Monoid.Last Int" "2" (pure 2 :: Monoid.Last Int)
177 , Example "Semigroup.Min Int" "2" (pure 2 :: Semigroup.Min Int)
178 , Example "Semigroup.Max Int" "2" (pure 2 :: Semigroup.Max Int)
179 , Example "Semigroup.First Int" "2" (pure 2 :: Semigroup.First Int)
180 , Example "Semigroup.Last Int" "2" (pure 2 :: Semigroup.Last Int)
181 , Example "Semigroup.WrappedMonoid Int" "2" (Semigroup.WrapMonoid 2 :: Semigroup.WrappedMonoid Int)
182 , Example "Semigroup.Option Just" "2" (pure 2 :: Semigroup.Option Int)
183 , Example "Semigroup.Option Nothing" "null" (Semigroup.Option (Nothing :: Maybe Bool))
186jsonEncodingExamples :: [Example]
187jsonEncodingExamples =
189 -- Maybe serialising is lossy
190 -- https://github.com/bos/aeson/issues/376
191 Example "Just Nothing" "null" (Just Nothing :: Maybe (Maybe Int))
192 -- infinities cannot be recovered, null is decoded as NaN
193 , Example "inf :: Double" "null" (Approx $ 1/0 :: Approx Double)
196jsonDecodingExamples :: [Example]
197jsonDecodingExamples = [
198 -- Maybe serialising is lossy
199 -- https://github.com/bos/aeson/issues/376
200 MaybeExample "Nothing" "null" (Just Nothing :: Maybe (Maybe Int))
201 , MaybeExample "Just" "1" (Just $ Just 1 :: Maybe (Maybe Int))
202 , MaybeExample "Just Nothing" "null" (Just Nothing :: Maybe (Maybe (Maybe Int)))
203 -- Integral values are truncated, and overflowed
204 -- https://github.com/bos/aeson/issues/317
205 , MaybeExample "Word8 3" "3" (Just 3 :: Maybe Word8)
206 , MaybeExample "Word8 3.00" "3.00" (Just 3 :: Maybe Word8)
207 , MaybeExample "Word8 3.14" "3.14" (Nothing :: Maybe Word8)
208 , MaybeExample "Word8 -1" "-1" (Nothing :: Maybe Word8)
209 , MaybeExample "Word8 300" "300" (Nothing :: Maybe Word8)
210 -- Negative zero year, encoding never produces such:
211 , MaybeExample "Day -0000-02-03" "\"-0000-02-03\"" (Just (fromGregorian 0 2 3))
216 :: (Eq a, Show a, ToJSON a, FromJSON a)
217 => String -> L.ByteString -> a -> Example
219 :: (Eq a, Show a, FromJSON a)
220 => String -> L.ByteString -> Maybe a -> Example
222data MyEither a b = MyLeft a | MyRight b
223 deriving (Generic, Show, Eq)
225instance (ToJSON a, ToJSON b) => ToJSON (MyEither a b) where
226 toJSON = genericToJSON defaultOptions { sumEncoding = UntaggedValue }
227 toEncoding = genericToEncoding defaultOptions { sumEncoding = UntaggedValue }
229instance (FromJSON a, FromJSON b) => FromJSON (MyEither a b) where
230 parseJSON = genericParseJSON defaultOptions { sumEncoding = UntaggedValue }
232assertJsonExample :: Example -> Test
233assertJsonExample (Example name bs val) = testCase name $ do
234 assertEqual "encode" bs (encode val)
235 assertEqual "encode/via value" bs (encode $ toJSON val)
236 assertEqual "decode" (Just val) (decode bs)
237assertJsonExample (MaybeExample name bs mval) = testCase name $
238 assertEqual "decode" mval (decode bs)
240assertJsonEncodingExample :: Example -> Test
241assertJsonEncodingExample (Example name bs val) = testCase name $ do
242 assertEqual "encode" bs (encode val)
243 assertEqual "encode/via value" bs (encode $ toJSON val)
244assertJsonEncodingExample (MaybeExample name _ _) = testCase name $
245 assertFailure "cannot encode MaybeExample"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list