wireform-derive-0.2.0.0: test/Test/Derive/Aeson.hs
{-# LANGUAGE OverloadedStrings #-}
module Test.Derive.Aeson (tests) where
import Data.Aeson qualified as A
import Data.Aeson.Key qualified as Key
import Data.Aeson.KeyMap qualified as KM
import Test.Derive.Aeson.Instances ()
import Test.Derive.Aeson.Types
import Test.Syd
tests :: Spec
tests =
describe "Aeson deriver" $
sequence_
[ recordTests
, newtypeTests
, enumTests
, sumTests
]
-- ---------------------------------------------------------------------------
-- Record
-- ---------------------------------------------------------------------------
recordTests :: Spec
recordTests =
describe "record" $
sequence_
[ it "encode applies rename / renameStyle" $ do
let a = Address "1 Main" "Springfield" "12345" "secret"
let v = A.toJSON a
case v of
A.Object o -> do
KM.lookup (Key.fromText "street") o `shouldBe` Just (A.String "1 Main")
KM.lookup (Key.fromText "addr_city") o `shouldBe` Just (A.String "Springfield")
KM.lookup (Key.fromText "zip") o `shouldBe` Just (A.String "12345")
(not (KM.member (Key.fromText "addrInternal") o)) `shouldBe` True
_ -> expectationFailure "expected JSON object"
, it "decode round-trips (skipped field filled by defaults)" $ do
let a = Address "1 Main" "Springfield" "12345" "secret"
case A.fromJSON (A.toJSON a) of
A.Success a' -> do
addrStreet a' `shouldBe` addrStreet a
addrCity a' `shouldBe` addrCity a
addrZip a' `shouldBe` addrZip a
addrInternal a' `shouldBe` defaultAddrInternal
A.Error e -> expectationFailure ("decode failed: " ++ e)
]
-- ---------------------------------------------------------------------------
-- Newtype
-- ---------------------------------------------------------------------------
newtypeTests :: Spec
newtypeTests =
describe "newtype" $
sequence_
[ it "encode passes through" $
A.toJSON (UserId 42) `shouldBe` A.Number 42
, it "round-trip" $ do
case A.fromJSON (A.toJSON (UserId 7)) of
A.Success (UserId n) -> n `shouldBe` 7
A.Error e -> expectationFailure e
]
-- ---------------------------------------------------------------------------
-- Enum
-- ---------------------------------------------------------------------------
enumTests :: Spec
enumTests =
describe "enum" $
sequence_
[ it
"encode literal-renamed constructor"
(A.toJSON Red `shouldBe` A.String "red")
, it
"encode style-renamed constructor (DarkBlue -> dark-blue)"
(A.toJSON DarkBlue `shouldBe` A.String "dark-blue")
, it "round-trip Red" $
A.fromJSON (A.String "red") `shouldBe` A.Success Red
, it "round-trip Green" $
A.fromJSON (A.String "green") `shouldBe` A.Success Green
, it "round-trip DarkBlue" $
A.fromJSON (A.String "dark-blue") `shouldBe` A.Success DarkBlue
, it "unknown value fails" $ do
case A.fromJSON (A.String "purple") :: A.Result Color of
A.Error _ -> pure ()
A.Success c -> expectationFailure ("unexpected " ++ show c)
]
-- ---------------------------------------------------------------------------
-- Sum
-- ---------------------------------------------------------------------------
sumTests :: Spec
sumTests =
describe "sum" $
sequence_
[ it "Point -> tag/contents (null payload)" $
A.toJSON Point
`shouldBe` A.object
[ Key.fromText "tag" A..= A.String "point"
, Key.fromText "contents" A..= A.Null
]
, it "Circle -> tag/contents (single payload)" $
A.toJSON (Circle 1.5)
`shouldBe` A.object
[ Key.fromText "tag" A..= A.String "circle"
, Key.fromText "contents" A..= A.Number 1.5
]
, it "Rect (renameStyle SnakeCase) -> tag = \"rect\", array contents" $ do
let v = A.toJSON (Rect 2 3)
case v of
A.Object o -> do
KM.lookup (Key.fromText "tag") o
`shouldBe` Just (A.String "rect")
KM.lookup (Key.fromText "contents") o
`shouldBe` Just (A.toJSON ([A.Number 2, A.Number 3] :: [A.Value]))
_ -> expectationFailure "expected JSON object"
, it "round-trip Point" $ rt Point
, it "round-trip Circle" $ rt (Circle 2.5)
, it "round-trip Rect" $ rt (Rect 4 5)
, it "unknown tag fails" $ do
let bad =
A.object
[ Key.fromText "tag" A..= A.String "triangle"
, Key.fromText "contents" A..= A.Null
]
case A.fromJSON bad :: A.Result Shape of
A.Error _ -> pure ()
A.Success s -> expectationFailure ("unexpected " ++ show s)
]
where
rt :: Shape -> IO ()
rt s = case A.fromJSON (A.toJSON s) of
A.Success s' -> s' `shouldBe` s
A.Error e -> expectationFailure ("round-trip failed: " ++ e)