@@ -1,14 +1,11 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2{-# LANGUAGE DeriveGeneric #-}
2{-# LANGUAGE DeriveGeneric #-}
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 #-}
8+-- For Data.Aeson.Types.camelTo
12{-# OPTIONS_GHC -fno-warn-deprecations #-}
9{-# OPTIONS_GHC -fno-warn-deprecations #-}
14module UnitTests
11module UnitTests
@@ -20,68 +17,49 @@ module UnitTests
20import Prelude ()
17import Prelude ()
21import Prelude.Compat
18import Prelude.Compat
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
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
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
133−data MyEither a b = MyLeft a | MyRight b
134− deriving (Generic, Show, Eq)
136−instance (ToJSON a, ToJSON b) => ToJSON (MyEither a b) where
137− toJSON = genericToJSON defaultOptions { sumEncoding = UntaggedValue }
138− toEncoding = genericToEncoding defaultOptions { sumEncoding = UntaggedValue }
140−instance (FromJSON a, FromJSON b) => FromJSON (MyEither a b) where
141− parseJSON = genericParseJSON defaultOptions { sumEncoding = UntaggedValue }
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 }"
283−------------------------------------------------------------------------------
284−-- These tests assert that the JSON serialization doesn't change by accident.
285−-----------------------------------------------------------------------------
289− :: (Eq a, Show a, ToJSON a, FromJSON a)
290− => String -> L.ByteString -> a -> Example
292− :: (Eq a, Show a, FromJSON a)
293− => String -> L.ByteString -> Maybe a -> Example
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)
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"
310−jsonEncodingExamples :: [Example]
311−jsonEncodingExamples =
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)
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))
338−jsonExamples :: [Example]
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)
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 "()" "[]" ()
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)
365− , Example "nan :: Double" "null" (Approx $ 0/0 :: Approx Double)
367− , Example "Ordering LT" "\"LT\"" LT
368− , Example "Ordering EQ" "\"EQ\"" EQ
369− , Example "Ordering GT" "\"GT\"" GT
371− , Example "Float" "3.14" (3.14 :: Float)
372− , Example "Pico" "3.14" (3.14 :: Pico)
373− , Example "Scientific" "3.14" (3.14 :: Scientific)
375− , Example "UUID" "\"c2cc10e1-57d6-4b6f-9899-38d972112d8c\"" $ UUID.fromWords
376− 0xc2cc10e1 0x57d64b6f 0x989938d9 0x72112d8c
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)
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)
391− , Example "Identity Int" "1" (pure 1 :: Identity Int)
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])
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])
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)
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)
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)
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)
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)
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)
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)
443− , Example "MyEither Int String: Left" "42" (MyLeft 42 :: MyEither Int String)
444− , Example "MyEither Int String: Right" "\"foo\"" (MyRight "foo" :: MyEither Int String)
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))
461------------------------------------------------------------------------------
247------------------------------------------------------------------------------
462-- These tests check that JSONPath is tracked correctly
248-- These tests check that JSONPath is tracked correctly
463-----------------------------------------------------------------------------
249-----------------------------------------------------------------------------