on master help sign in
Split examples in test suites into a separate module and add a module
b8dac1dAdam Bergmark
aeson.cabal+2
@@ -163,10 +163,12 @@ test-suite tests
163 DataFamilies.Encoders
163 DataFamilies.Encoders
164 DataFamilies.Types
164 DataFamilies.Types
165 Encoders
165 Encoders
166+ ErrorMessages
166 Functions
167 Functions
167 Instances
168 Instances
168 Options
169 Options
169 Properties
170 Properties
171+ SerializationFormatSpec
170 Types
172 Types
171 UnitTests
173 UnitTests
172 UnitTests.NullaryConstructors
174 UnitTests.NullaryConstructors
tests/ErrorMessages.hsnew file+57
@@ -0,0 +1,57 @@
1+{-# LANGUAGE OverloadedStrings #-}
2+{-# LANGUAGE ScopedTypeVariables #-}
3+
4+module ErrorMessages
5+ (
6+ tests
7+ ) where
8+
9+import Prelude ()
10+import Prelude.Compat
11+
12+import Data.Aeson (FromJSON(..), eitherDecode)
13+import Data.Proxy (Proxy(..))
14+import Instances ()
15+import Test.Framework (Test)
16+import Test.Framework.Providers.HUnit (testCase)
17+import Test.HUnit (Assertion, assertFailure, assertEqual)
18+import qualified Data.ByteString.Lazy.Char8 as L
19+import qualified Data.HashMap.Strict as HM
20+
21+tests :: [Test]
22+tests =
23+ [
24+ testCase "Int" int
25+ , testCase "String" string
26+ , testCase "HashMap" hashMap
27+ ]
28+
29+int :: Assertion
30+int = do
31+ let t = test (Proxy :: Proxy Int)
32+ t "\"\"" $ expected "Int" "String"
33+ t "[]" $ expected "Int" "Array"
34+ t "{}" $ expected "Int" "Object"
35+ t "null" $ expected "Int" "Null"
36+
37+string :: Assertion
38+string = do
39+ let t = test (Proxy :: Proxy String)
40+ t "1" $ expected "String" "Number"
41+ t "[]" $ expected "String" "Array"
42+ t "{}" $ expected "String" "Object"
43+ t "null" $ expected "String" "Null"
44+
45+hashMap :: Assertion
46+hashMap = do
47+ let t = test (Proxy :: Proxy (HM.HashMap String Int))
48+ t "\"\"" $ expected "HashMap k v" "String"
49+ t "[]" $ expected "HashMap k v" "Array"
50+
51+expected :: String -> String -> String
52+expected ex enc = "Error in $: expected " ++ ex ++ ", encountered " ++ enc
53+
54+test :: forall a proxy . (FromJSON a, Show a) => proxy a -> L.ByteString -> String -> Assertion
55+test _ v msg = case eitherDecode v of
56+ Left e -> assertEqual "Invalid error message" msg e
57+ Right (x :: a) -> assertFailure $ "Expected parsing to fail but it suceeded with: " ++ show x
tests/SerializationFormatSpec.hsnew file+245
@@ -0,0 +1,245 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE DeriveGeneric #-}
3+{-# LANGUAGE GADTs #-}
4+{-# LANGUAGE OverloadedStrings #-}
5+#if __GLASGOW_HASKELL__ >= 708
6+{-# LANGUAGE DataKinds #-}
7+#endif
8+
9+------------------------------------------------------------------------------
10+-- These tests assert that the JSON serialization doesn't change by accident.
11+-----------------------------------------------------------------------------
12+
13+module SerializationFormatSpec
14+ (
15+ tests
16+ ) where
17+
18+import Prelude ()
19+import Prelude.Compat
20+
21+import Control.Applicative (Const(..))
22+import Data.Aeson (FromJSON(..), decode, encode, genericParseJSON, genericToEncoding, genericToJSON)
23+import Data.Aeson.Types (Options(..), SumEncoding(..), ToJSON(..), defaultOptions)
24+import Data.Fixed (Pico)
25+import Data.Functor.Compose (Compose(..))
26+import Data.Functor.Identity (Identity(..))
27+import Data.Functor.Product (Product(..))
28+import Data.Functor.Sum (Sum(..))
29+import Data.List.NonEmpty (NonEmpty(..))
30+import Data.Proxy (Proxy(..))
31+import Data.Scientific (Scientific)
32+import Data.Tagged (Tagged(..))
33+import Data.Time (fromGregorian)
34+import Data.Word (Word8)
35+import GHC.Generics (Generic)
36+import Instances ()
37+import Test.Framework (Test, testGroup)
38+import Test.Framework.Providers.HUnit (testCase)
39+import Test.HUnit (assertFailure, assertEqual)
40+import Types (Approx(..), Compose3, Compose3', I)
41+import qualified Data.ByteString.Lazy.Char8 as L
42+import qualified Data.DList as DList
43+import qualified Data.HashMap.Strict as HM
44+import qualified Data.HashSet as HashSet
45+import qualified Data.IntMap as IntMap
46+import qualified Data.IntSet as IntSet
47+import qualified Data.Map as M
48+import qualified Data.Monoid as Monoid
49+import qualified Data.Semigroup as Semigroup
50+import qualified Data.Sequence as Seq
51+import qualified Data.Set as Set
52+import qualified Data.Tree as Tree
53+import qualified Data.UUID.Types as UUID
54+import qualified Data.Vector as Vector
55+
56+tests :: [Test]
57+tests =
58+ [
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
62+
63+ ]
64+
65+jsonExamples :: [Example]
66+jsonExamples =
67+ [
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)
77+#endif
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 "()" "[]" ()
84+
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 [Char] 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)
91+
92+ , Example "nan :: Double" "null" (Approx $ 0/0 :: Approx Double)
93+
94+ , Example "Ordering LT" "\"LT\"" LT
95+ , Example "Ordering EQ" "\"EQ\"" EQ
96+ , Example "Ordering GT" "\"GT\"" GT
97+
98+ , Example "Float" "3.14" (3.14 :: Float)
99+ , Example "Pico" "3.14" (3.14 :: Pico)
100+ , Example "Scientific" "3.14" (3.14 :: Scientific)
101+
102+ , Example "UUID" "\"c2cc10e1-57d6-4b6f-9899-38d972112d8c\"" $ UUID.fromWords
103+ 0xc2cc10e1 0x57d64b6f 0x989938d9 0x72112d8c
104+
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)
111+
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)
116+
117+ -- Functors
118+ , Example "Identity Int" "1" (pure 1 :: Identity Int)
119+
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])
123+
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])
127+
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)
133+
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)
137+
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)
141+
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)
146+
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)
151+
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)
160+
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)
169+
170+ , Example "MyEither Int String: Left" "42" (MyLeft 42 :: MyEither Int String)
171+ , Example "MyEither Int String: Right" "\"foo\"" (MyRight "foo" :: MyEither Int String)
172+
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))
184+ ]
185+
186+jsonEncodingExamples :: [Example]
187+jsonEncodingExamples =
188+ [
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)
194+ ]
195+
196+jsonDecodingExamples :: [Example]
197+jsonDecodingExamples = [
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))
212+ ]
213+
214+data Example where
215+ Example
216+ :: (Eq a, Show a, ToJSON a, FromJSON a)
217+ => String -> L.ByteString -> a -> Example
218+ MaybeExample
219+ :: (Eq a, Show a, FromJSON a)
220+ => String -> L.ByteString -> Maybe a -> Example
221+
222+data MyEither a b = MyLeft a | MyRight b
223+ deriving (Generic, Show, Eq)
224+
225+instance (ToJSON a, ToJSON b) => ToJSON (MyEither a b) where
226+ toJSON = genericToJSON defaultOptions { sumEncoding = UntaggedValue }
227+ toEncoding = genericToEncoding defaultOptions { sumEncoding = UntaggedValue }
228+
229+instance (FromJSON a, FromJSON b) => FromJSON (MyEither a b) where
230+ parseJSON = genericParseJSON defaultOptions { sumEncoding = UntaggedValue }
231+
232+assertJsonExample :: Example -> Test
233+assertJsonExample (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)
237+assertJsonExample (MaybeExample name bs mval) = testCase name $
238+ assertEqual "decode" mval (decode bs)
239+
240+assertJsonEncodingExample :: Example -> Test
241+assertJsonEncodingExample (Example name bs val) = testCase name $ do
242+ assertEqual "encode" bs (encode val)
243+ assertEqual "encode/via value" bs (encode $ toJSON val)
244+assertJsonEncodingExample (MaybeExample name _ _) = testCase name $
245+ assertFailure "cannot encode MaybeExample"
tests/UnitTests.hs+10−224
@@ -1,14 +1,11 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2{-# LANGUAGE DeriveGeneric #-}
2{-# LANGUAGE DeriveGeneric #-}
3−{-# LANGUAGE GADTs #-}
4{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3{-# LANGUAGE GeneralizedNewtypeDeriving #-}
5{-# LANGUAGE OverloadedStrings #-}
4{-# LANGUAGE OverloadedStrings #-}
6{-# LANGUAGE ScopedTypeVariables #-}
5{-# LANGUAGE ScopedTypeVariables #-}
7{-# LANGUAGE TemplateHaskell #-}
6{-# LANGUAGE TemplateHaskell #-}
8−#if __GLASGOW_HASKELL__ >= 708
9−{-# LANGUAGE DataKinds #-}
10−#endif
11
7
8+-- For Data.Aeson.Types.camelTo
12{-# OPTIONS_GHC -fno-warn-deprecations #-}
9{-# OPTIONS_GHC -fno-warn-deprecations #-}
13
10
14module UnitTests
11module UnitTests
@@ -20,68 +17,49 @@ module UnitTests
20import Prelude ()
17import Prelude ()
21import Prelude.Compat
18import Prelude.Compat
22
19
23−import Control.Applicative (Const(..))
24import Control.Monad (forM, forM_, unless)
20import Control.Monad (forM, forM_, unless)
25−import Data.Aeson ((.=), (.:), (.:?), (.:!), FromJSON(..), FromJSONKeyFunction(..), FromJSONKey(..), ToJSON1(..), decode, eitherDecode, encode, genericParseJSON, genericToEncoding, genericToJSON, object, withObject)
21+import Data.Aeson ((.=), (.:), (.:?), (.:!), FromJSON(..), FromJSONKeyFunction(..), FromJSONKey(..), ToJSON1(..), decode, eitherDecode, encode, genericToEncoding, genericToJSON, object, withObject)
26import Data.Aeson.Internal (JSONPathElement(..), formatError)
22import Data.Aeson.Internal (JSONPathElement(..), formatError)
27import Data.Aeson.TH (deriveJSON, deriveToJSON, deriveToJSON1)
23import Data.Aeson.TH (deriveJSON, deriveToJSON, deriveToJSON1)
28import Data.Aeson.Text (encodeToTextBuilder)
24import Data.Aeson.Text (encodeToTextBuilder)
29−import Data.Aeson.Types (Options(..), SumEncoding(..), ToJSON(..), Value, camelTo, camelTo2, defaultOptions, omitNothingFields)
25+import Data.Aeson.Types (Options(..), ToJSON(..), Value, camelTo, camelTo2, defaultOptions, omitNothingFields)
30import Data.Char (toUpper)
26import Data.Char (toUpper)
31import Data.Either.Compat (isLeft, isRight)
27import Data.Either.Compat (isLeft, isRight)
32−import Data.Fixed (Pico)
33−import Data.Functor.Compose (Compose(..))
34−import Data.Functor.Identity (Identity(..))
35−import Data.Functor.Product (Product(..))
36−import Data.Functor.Sum (Sum(..))
37import Data.Hashable (hash)
28import Data.Hashable (hash)
38import Data.List (sort)
29import Data.List (sort)
39−import Data.List.NonEmpty (NonEmpty(..))
40import Data.Maybe (fromMaybe)
30import Data.Maybe (fromMaybe)
41−import Data.Proxy (Proxy(..))
42−import Data.Scientific (Scientific)
43import Data.Sequence (Seq)
31import Data.Sequence (Seq)
44import Data.Tagged (Tagged(..))
32import Data.Tagged (Tagged(..))
45import Data.Text (Text)
33import Data.Text (Text)
46−import Data.Time (UTCTime, fromGregorian)
34+import Data.Time (UTCTime)
47import Data.Time.Format (parseTime)
35import Data.Time.Format (parseTime)
48import Data.Time.Locale.Compat (defaultTimeLocale)
36import Data.Time.Locale.Compat (defaultTimeLocale)
49−import Data.Word (Word8)
50import GHC.Generics (Generic)
37import GHC.Generics (Generic)
51import Instances ()
38import Instances ()
52import System.Directory (doesDirectoryExist, getDirectoryContents)
39import System.Directory (doesDirectoryExist, getDirectoryContents)
53import System.Exit (exitWith, ExitCode(ExitFailure))
40import System.Exit (exitWith, ExitCode(ExitFailure))
54−import System.IO (hPutStrLn, stderr)
55import System.FilePath ((</>), takeExtension, takeFileName)
41import System.FilePath ((</>), takeExtension, takeFileName)
42+import System.IO (hPutStrLn, stderr)
56import Test.Framework (Test, testGroup)
43import Test.Framework (Test, testGroup)
57import Test.Framework.Providers.HUnit (testCase)
44import Test.Framework.Providers.HUnit (testCase)
58import Test.HUnit (Assertion, assertBool, assertFailure, assertEqual)
45import Test.HUnit (Assertion, assertBool, assertFailure, assertEqual)
59import Text.Printf (printf)
46import Text.Printf (printf)
60−import Types (Approx(..), Compose3, Compose3', I)
61import UnitTests.NullaryConstructors (nullaryConstructors)
47import UnitTests.NullaryConstructors (nullaryConstructors)
62import qualified Data.ByteString.Base16.Lazy as LBase16
48import qualified Data.ByteString.Base16.Lazy as LBase16
63import qualified Data.ByteString.Lazy.Char8 as L
49import qualified Data.ByteString.Lazy.Char8 as L
64−import qualified Data.DList as DList
65−import qualified Data.HashMap.Strict as HM
66import qualified Data.HashSet as HashSet
50import qualified Data.HashSet as HashSet
67−import qualified Data.IntMap as IntMap
68−import qualified Data.IntSet as IntSet
69−import qualified Data.Map as M
70−import qualified Data.Monoid as Monoid
71−import qualified Data.Semigroup as Semigroup
72−import qualified Data.Sequence as Seq
73−import qualified Data.Set as Set
74import qualified Data.Text.Lazy as LT
51import qualified Data.Text.Lazy as LT
75import qualified Data.Text.Lazy.Builder as TLB
52import qualified Data.Text.Lazy.Builder as TLB
76import qualified Data.Text.Lazy.Encoding as LT
53import qualified Data.Text.Lazy.Encoding as LT
77import qualified Data.Text.Lazy.Encoding as TLE
54import qualified Data.Text.Lazy.Encoding as TLE
78−import qualified Data.Tree as Tree
55+import qualified ErrorMessages
79−import qualified Data.UUID.Types as UUID
56+import qualified SerializationFormatSpec
80−import qualified Data.Vector as Vector
81
57
82tests :: Test
58tests :: Test
83tests = testGroup "unit" [
59tests = testGroup "unit" [
60+ testGroup "SerializationFormatSpec" SerializationFormatSpec.tests
61+ , testGroup "ErrorMessages" ErrorMessages.tests
84− testGroup "camelCase" [
62+ , testGroup "camelCase" [
85 testCase "camelTo" $ roundTripCamel "aName"
63 testCase "camelTo" $ roundTripCamel "aName"
86 , testCase "camelTo" $ roundTripCamel "another"
64 , testCase "camelTo" $ roundTripCamel "another"
87 , testCase "camelTo" $ roundTripCamel "someOtherName"
65 , testCase "camelTo" $ roundTripCamel "someOtherName"
@@ -104,9 +82,6 @@ tests = testGroup "unit" [
104 testCase "example 1" $ formatErrorExample
82 testCase "example 1" $ formatErrorExample
105 ]
83 ]
106 , testGroup ".:, .:?, .:!" $ fmap (testCase "-") dotColonMark
84 , testGroup ".:, .:?, .:!" $ fmap (testCase "-") dotColonMark
107− , testGroup "To JSON representation" $ fmap assertJsonEncodingExample jsonEncodingExamples
108− , testGroup "From JSON representation" $ fmap assertJsonExample jsonDecodingExamples
109− , testGroup "To/From JSON representation" $ fmap assertJsonExample jsonExamples
110 , testGroup "JSONPath" $ fmap (testCase "-") jsonPath
85 , testGroup "JSONPath" $ fmap (testCase "-") jsonPath
111 , testGroup "Hashable laws" $ fmap (testCase "-") hashableLaws
86 , testGroup "Hashable laws" $ fmap (testCase "-") hashableLaws
112 , testGroup "Issue #351" $ fmap (testCase "-") issue351
87 , testGroup "Issue #351" $ fmap (testCase "-") issue351
@@ -130,17 +105,6 @@ camelFrom c s = let (p:ps) = split c s
130 capitalize t = toUpper (head t) : tail t
105 capitalize t = toUpper (head t) : tail t
131
106
132
107
133−data MyEither a b = MyLeft a | MyRight b
134− deriving (Generic, Show, Eq)
135−
136−instance (ToJSON a, ToJSON b) => ToJSON (MyEither a b) where
137− toJSON = genericToJSON defaultOptions { sumEncoding = UntaggedValue }
138− toEncoding = genericToEncoding defaultOptions { sumEncoding = UntaggedValue }
139−
140−instance (FromJSON a, FromJSON b) => FromJSON (MyEither a b) where
141− parseJSON = genericParseJSON defaultOptions { sumEncoding = UntaggedValue }
142−
143−
144data Wibble = Wibble {
108data Wibble = Wibble {
145 wibbleString :: String
109 wibbleString :: String
146 , wibbleInt :: Int
110 , wibbleInt :: Int
@@ -280,184 +244,6 @@ dotColonMark = [
280 ex2 = "{\"value\": 42 }"
244 ex2 = "{\"value\": 42 }"
281 ex3 = "{\"value\": null }"
245 ex3 = "{\"value\": null }"
282
246
283−------------------------------------------------------------------------------
284−-- These tests assert that the JSON serialization doesn't change by accident.
285−-----------------------------------------------------------------------------
286−
287−data Example where
288− Example
289− :: (Eq a, Show a, ToJSON a, FromJSON a)
290− => String -> L.ByteString -> a -> Example
291− MaybeExample
292− :: (Eq a, Show a, FromJSON a)
293− => String -> L.ByteString -> Maybe a -> Example
294−
295−assertJsonExample :: Example -> Test
296−assertJsonExample (Example name bs val) = testCase name $ do
297− assertEqual "encode" bs (encode val)
298− assertEqual "encode/via value" bs (encode $ toJSON val)
299− assertEqual "decode" (Just val) (decode bs)
300−assertJsonExample (MaybeExample name bs mval) = testCase name $
301− assertEqual "decode" mval (decode bs)
302−
303−assertJsonEncodingExample :: Example -> Test
304−assertJsonEncodingExample (Example name bs val) = testCase name $ do
305− assertEqual "encode" bs (encode val)
306− assertEqual "encode/via value" bs (encode $ toJSON val)
307−assertJsonEncodingExample (MaybeExample name _ _) = testCase name $
308− assertFailure "cannot encode MaybeExample"
309−
310−jsonEncodingExamples :: [Example]
311−jsonEncodingExamples =
312− [
313− -- Maybe serialising is lossy
314− -- https://github.com/bos/aeson/issues/376
315− Example "Just Nothing" "null" (Just Nothing :: Maybe (Maybe Int))
316− -- infinities cannot be recovered, null is decoded as NaN
317− , Example "inf :: Double" "null" (Approx $ 1/0 :: Approx Double)
318− ]
319−
320−jsonDecodingExamples :: [Example]
321−jsonDecodingExamples = [
322− -- Maybe serialising is lossy
323− -- https://github.com/bos/aeson/issues/376
324− MaybeExample "Nothing" "null" (Just $ Nothing :: Maybe (Maybe Int))
325− , MaybeExample "Just" "1" (Just $ Just 1 :: Maybe (Maybe Int))
326− , MaybeExample "Just Nothing" "null" (Just $ Nothing :: Maybe (Maybe (Maybe Int)))
327− -- Integral values are truncated, and overflowed
328− -- https://github.com/bos/aeson/issues/317
329− , MaybeExample "Word8 3" "3" (Just 3 :: Maybe Word8)
330− , MaybeExample "Word8 3.00" "3.00" (Just 3 :: Maybe Word8)
331− , MaybeExample "Word8 3.14" "3.14" (Nothing :: Maybe Word8)
332− , MaybeExample "Word8 -1" "-1" (Nothing :: Maybe Word8)
333− , MaybeExample "Word8 300" "300" (Nothing :: Maybe Word8)
334− -- Negative zero year, encoding never produces such:
335− , MaybeExample "Day -0000-02-03" "\"-0000-02-03\"" (Just (fromGregorian 0 2 3))
336− ]
337−
338−jsonExamples :: [Example]
339−jsonExamples =
340− [
341− Example "Either Left" "{\"Left\":1}" (Left 1 :: Either Int Int)
342− , Example "Either Right" "{\"Right\":1}" (Right 1 :: Either Int Int)
343− , Example "Nothing" "null" (Nothing :: Maybe Int)
344− , Example "Just" "1" (Just 1 :: Maybe Int)
345− , Example "Proxy Int" "null" (Proxy :: Proxy Int)
346− , Example "Tagged Char Int" "1" (Tagged 1 :: Tagged Char Int)
347−#if __GLASGOW_HASKELL__ >= 708
348− -- Test Tagged instance is polykinded
349− , Example "Tagged 123 Int" "1" (Tagged 1 :: Tagged 123 Int)
350−#endif
351− , Example "Const Char Int" "\"c\"" (Const 'c' :: Const Char Int)
352− , Example "Tuple" "[1,2]" ((1, 2) :: (Int, Int))
353− , Example "NonEmpty" "[1,2,3]" (1 :| [2, 3] :: NonEmpty Int)
354− , Example "Seq" "[1,2,3]" (Seq.fromList [1, 2, 3] :: Seq.Seq Int)
355− , Example "DList" "[1,2,3]" (DList.fromList [1, 2, 3] :: DList.DList Int)
356− , Example "()" "[]" ()
357−
358− , Example "HashMap Int Int" "{\"0\":1,\"2\":3}" (HM.fromList [(0,1),(2,3)] :: HM.HashMap Int Int)
359− , Example "Map Int Int" "{\"0\":1,\"2\":3}" (M.fromList [(0,1),(2,3)] :: M.Map Int Int)
360− , Example "Map (Tagged Int Int) Int" "{\"0\":1,\"2\":3}" (M.fromList [(Tagged 0,1),(Tagged 2,3)] :: M.Map (Tagged Int Int) Int)
361− , Example "Map [Int] Int" "[[[0],1],[[2],3]]" (M.fromList [([0],1),([2],3)] :: M.Map [Int] Int)
362− , Example "Map [Char] Int" "{\"ab\":1,\"cd\":3}" (M.fromList [("ab",1),("cd",3)] :: M.Map [Char] Int)
363− , Example "Map [I Char] Int" "{\"ab\":1,\"cd\":3}" (M.fromList [(map pure "ab",1),(map pure "cd",3)] :: M.Map [I Char] Int)
364−
365− , Example "nan :: Double" "null" (Approx $ 0/0 :: Approx Double)
366−
367− , Example "Ordering LT" "\"LT\"" LT
368− , Example "Ordering EQ" "\"EQ\"" EQ
369− , Example "Ordering GT" "\"GT\"" GT
370−
371− , Example "Float" "3.14" (3.14 :: Float)
372− , Example "Pico" "3.14" (3.14 :: Pico)
373− , Example "Scientific" "3.14" (3.14 :: Scientific)
374−
375− , Example "UUID" "\"c2cc10e1-57d6-4b6f-9899-38d972112d8c\"" $ UUID.fromWords
376− 0xc2cc10e1 0x57d64b6f 0x989938d9 0x72112d8c
377−
378− , Example "Set Int" "[1,2,3]" (Set.fromList [3, 2, 1] :: Set.Set Int)
379− , Example "IntSet" "[1,2,3]" (IntSet.fromList [3, 2, 1])
380− , Example "IntMap" "[[1,2],[3,4]]" (IntMap.fromList [(3,4), (1,2)] :: IntMap.IntMap Int)
381− , Example "Vector" "[1,2,3]" (Vector.fromList [1, 2, 3] :: Vector.Vector Int)
382− , Example "HashSet Int" "[1,2,3]" (HashSet.fromList [3, 2, 1] :: HashSet.HashSet Int)
383− , 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)
384−
385− -- Three separate cases, as ordering in HashMap is not defined
386− , Example "HashMap Float Int, NaN" "{\"NaN\":1}" (Approx $ HM.singleton (0/0) 1 :: Approx (HM.HashMap Float Int))
387− , Example "HashMap Float Int, Infinity" "{\"Infinity\":1}" (HM.singleton (1/0) 1 :: HM.HashMap Float Int)
388− , Example "HashMap Float Int, +Infinity" "{\"-Infinity\":1}" (HM.singleton (negate 1/0) 1 :: HM.HashMap Float Int)
389−
390− -- Functors
391− , Example "Identity Int" "1" (pure 1 :: Identity Int)
392−
393− , Example "Identity Char" "\"x\"" (pure 'x' :: Identity Char)
394− , Example "Identity String" "\"foo\"" (pure "foo" :: Identity String)
395− , Example "[Identity Char]" "\"xy\"" ([pure 'x', pure 'y'] :: [Identity Char])
396−
397− , Example "Maybe Char" "\"x\"" (pure 'x' :: Maybe Char)
398− , Example "Maybe String" "\"foo\"" (pure "foo" :: Maybe String)
399− , Example "Maybe [Identity Char]" "\"xy\"" (pure [pure 'x', pure 'y'] :: Maybe [Identity Char])
400−
401− , Example "Day; year >= 1000" "\"1999-10-12\"" (fromGregorian 1999 10 12)
402− , Example "Day; year > 0 && < 1000" "\"0500-03-04\"" (fromGregorian 500 3 4)
403− , Example "Day; year == 0" "\"0000-02-20\"" (fromGregorian 0 2 20)
404− , Example "Day; year < 0" "\"-0234-01-01\"" (fromGregorian (-234) 1 1)
405− , Example "Day; year < -1000" "\"-1234-01-01\"" (fromGregorian (-1234) 1 1)
406−
407− , Example "Product I Maybe Int" "[1,2]" (Pair (pure 1) (pure 2) :: Product I Maybe Int)
408− , Example "Product I Maybe Int" "[1,null]" (Pair (pure 1) Nothing :: Product I Maybe Int)
409− , Example "Product I [] Char" "[\"a\",\"foo\"]" (Pair (pure 'a') "foo" :: Product I [] Char)
410−
411− , Example "Sum I [] Int: InL" "{\"InL\":1}" (InL (pure 1) :: Sum I [] Int)
412− , Example "Sum I [] Int: InR" "{\"InR\":[1,2]}" (InR [1, 2] :: Sum I [] Int)
413− , Example "Sum I [] Char: InR" "{\"InR\":\"foo\"}" (InR "foo" :: Sum I [] Char)
414−
415− , Example "Compose I I Int" "1" (pure 1 :: Compose I I Int)
416− , Example "Compose I [] Int" "[1]" (pure 1 :: Compose I [] Int)
417− , Example "Compose [] I Int" "[1]" (pure 1 :: Compose [] I Int)
418− , Example "Compose [] [] Int" "[[1]]" (pure 1 :: Compose [] [] Int)
419−
420− , Example "Compose I I Char" "\"x\"" (pure 'x' :: Compose I I Char)
421− , Example "Compose I [] Char" "\"x\"" (pure 'x' :: Compose I [] Char)
422− , Example "Compose [] I Char" "\"x\"" (pure 'x' :: Compose [] I Char)
423− , Example "Compose [] [] Char" "[\"x\"]" (pure 'x' :: Compose [] [] Char)
424−
425− , Example "Compose3 I I I Char" "\"x\"" (pure 'x' :: Compose3 I I I Char)
426− , Example "Compose3 I I [] Char" "\"x\"" (pure 'x' :: Compose3 I I [] Char)
427− , Example "Compose3 I [] I Char" "\"x\"" (pure 'x' :: Compose3 I [] I Char)
428− , Example "Compose3 I [] [] Char" "[\"x\"]" (pure 'x' :: Compose3 I [] [] Char)
429− , Example "Compose3 [] I I Char" "\"x\"" (pure 'x' :: Compose3 [] I I Char)
430− , Example "Compose3 [] I [] Char" "[\"x\"]" (pure 'x' :: Compose3 [] I [] Char)
431− , Example "Compose3 [] [] I Char" "[\"x\"]" (pure 'x' :: Compose3 [] [] I Char)
432− , Example "Compose3 [] [] [] Char" "[[\"x\"]]" (pure 'x' :: Compose3 [] [] [] Char)
433−
434− , Example "Compose3' I I I Char" "\"x\"" (pure 'x' :: Compose3' I I I Char)
435− , Example "Compose3' I I [] Char" "\"x\"" (pure 'x' :: Compose3' I I [] Char)
436− , Example "Compose3' I [] I Char" "\"x\"" (pure 'x' :: Compose3' I [] I Char)
437− , Example "Compose3' I [] [] Char" "[\"x\"]" (pure 'x' :: Compose3' I [] [] Char)
438− , Example "Compose3' [] I I Char" "\"x\"" (pure 'x' :: Compose3' [] I I Char)
439− , Example "Compose3' [] I [] Char" "[\"x\"]" (pure 'x' :: Compose3' [] I [] Char)
440− , Example "Compose3' [] [] I Char" "[\"x\"]" (pure 'x' :: Compose3' [] [] I Char)
441− , Example "Compose3' [] [] [] Char" "[[\"x\"]]" (pure 'x' :: Compose3' [] [] [] Char)
442−
443− , Example "MyEither Int String: Left" "42" (MyLeft 42 :: MyEither Int String)
444− , Example "MyEither Int String: Right" "\"foo\"" (MyRight "foo" :: MyEither Int String)
445−
446− -- newtypes from Monoid/Semigroup
447− , Example "Monoid.Dual Int" "2" (pure 2 :: Monoid.Dual Int)
448− , Example "Monoid.First Int" "2" (pure 2 :: Monoid.First Int)
449− , Example "Monoid.Last Int" "2" (pure 2 :: Monoid.Last Int)
450− , Example "Semigroup.Min Int" "2" (pure 2 :: Semigroup.Min Int)
451− , Example "Semigroup.Max Int" "2" (pure 2 :: Semigroup.Max Int)
452− , Example "Semigroup.First Int" "2" (pure 2 :: Semigroup.First Int)
453− , Example "Semigroup.Last Int" "2" (pure 2 :: Semigroup.Last Int)
454− , Example "Semigroup.WrappedMonoid Int" "2" (Semigroup.WrapMonoid 2 :: Semigroup.WrappedMonoid Int)
455− , Example "Semigroup.Option Just" "2" (pure 2 :: Semigroup.Option Int)
456− , Example "Semigroup.Option Nothing" "null" (Semigroup.Option (Nothing :: Maybe Bool))
457− ]
458−
459−
460−
461------------------------------------------------------------------------------
247------------------------------------------------------------------------------
462-- These tests check that JSONPath is tracked correctly
248-- These tests check that JSONPath is tracked correctly
463-----------------------------------------------------------------------------
249-----------------------------------------------------------------------------