avro-0.4.7.0: test/Avro/JSONSpec.hs
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
module Avro.JSONSpec where
import Control.Monad (forM_)
import Control.Monad.Identity (Identity (..))
import qualified Data.Aeson as Aeson
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS
import qualified Data.Map as Map
import Data.Avro.Deriving
import Data.Avro.EitherN
import Data.Avro.JSON
import Test.Hspec
import Paths_avro
import System.Directory (doesFileExist, getCurrentDirectory)
import System.Environment (setEnv)
deriveAvro "test/data/enums.avsc"
deriveAvro "test/data/reused.avsc"
deriveAvro "test/data/small.avsc"
deriveAvro "test/data/unions.avsc"
deriveAvro "test/data/unions-no-namespace.avsc"
spec :: Spec
spec = describe "Avro.JSONSpec: JSON serialization/parsing" $ do
it "should do roundtrip (enums)" $ do
let msg = EnumWrapper
{ enumWrapperId = 42
, enumWrapperName = "Text"
, enumWrapperReason = EnumReasonBecause
}
parseJSON (Aeson.encode (toJSON msg)) `shouldBe` pure msg
it "should do roundtrip (reused)" $ do
let msg = ReusedWrapper
{ reusedWrapperFull = ReusedChild 42
, reusedWrapperInner = ContainerChild
{ containerChildFstIncluded = ReusedChild 37
, containerChildSndIncluded = ReusedChild 64
}
}
parseJSON (Aeson.encode (toJSON msg)) `shouldBe` pure msg
it "should do roundtrip (small)" $ do
let msgs =
[ Endpoint
{ endpointIps = ["192.168.1.1", "127.0.0.1"]
, endpointPorts = [PortRange 1 10, PortRange 11 20]
, endpointOpaque = Opaque "16-b-long-string"
, endpointCorrelation = Opaque "opaq-correlation"
, endpointTag = Left 14
}
, Endpoint
{ endpointIps = []
, endpointPorts = [PortRange 1 10, PortRange 11 20]
, endpointOpaque = Opaque "opaque-long-text"
, endpointCorrelation = Opaque "correlation-data"
, endpointTag = Right "first-tag"
}
]
forM_ msgs $ \ msg ->
parseJSON (Aeson.encode (toJSON msg)) `shouldBe` pure msg
enumsExampleJSON <- runIO $ getFileName "test/data/enums-object.json" >>= LBS.readFile
it "should parse (enums)" $ do
let expected = EnumWrapper 37 "blarg" EnumReasonInstead
parseJSON enumsExampleJSON `shouldBe` pure expected
let unionsExampleA = Unions
{ unionsScalars = Left "blarg"
, unionsNullable = Nothing
, unionsRecords = Left $ Foo { fooStuff = "stuff" }
, unionsSameFields = Left $ Foo { fooStuff = "foo stuff" }
, unionsArrayAndMap = Left ["foo"]
, unionsOne = Identity 42
, unionsThree = E3_1 37
, unionsFour = E4_2 "foo"
, unionsFive = E5_4 $ Foo { fooStuff = "foo stuff" }
, unionsSix = E6_2 "foo"
, unionsSeven = E7_6 6.28
, unionsEight = E8_3 37
, unionsNine = E9_1 37
, unionsTen = E10_9 $ BS.pack [70, 79, 79, 66, 65, 82]
}
unionsExampleB = Unions
{ unionsScalars = Right 37
, unionsNullable = Just 42
, unionsRecords = Right $ Bar { barStuff = "stuff"
, barThings = Foo "things"
}
, unionsSameFields = Right $ NotFoo { notFooStuff = "not foo stuff" }
, unionsArrayAndMap = Right $ Map.fromList [("a", 5)]
, unionsOne = Identity 42
, unionsThree = E3_3 37
, unionsFour = E4_4 $ Foo { fooStuff = "foo stuff" }
, unionsFive = E5_5 $ NotFoo { notFooStuff = "not foo stuff" }
, unionsSix = E6_6 6.28
, unionsSeven = E7_7 False
, unionsEight = E8_8 2.718
, unionsNine = E9_9 $ BS.pack [70, 79, 79, 66, 65, 82]
, unionsTen = E10_10 $ Bar { barStuff = "bar stuff",
barThings = Foo { fooStuff = "things" }
}
}
it "should roundtrip (unions)" $ do
forM_ [unionsExampleA, unionsExampleB] $ \ msg ->
parseJSON (Aeson.encode (toJSON msg)) `shouldBe` pure msg
unionsJsonA <- runIO $ getFileName "test/data/unions-object-a.json" >>= LBS.readFile
unionsJsonB <- runIO $ getFileName "test/data/unions-object-b.json" >>= LBS.readFile
it "should parse (unions)" $ do
parseJSON unionsJsonA `shouldBe` pure unionsExampleA
parseJSON unionsJsonB `shouldBe` pure unionsExampleB
let unionsNoNamespaceA = UnionsNoNamespace (Left TypeA)
unionsNoNamespaceB = UnionsNoNamespace (Right TypeB)
it "should roundtrip (unions-no-namespace)" $ do
parseJSON (Aeson.encode (toJSON unionsNoNamespaceA)) `shouldBe`
pure unionsNoNamespaceA
parseJSON (Aeson.encode (toJSON unionsNoNamespaceB)) `shouldBe`
pure unionsNoNamespaceB
let noNamespace = "test/data/unions-no-namespace-object.json"
objectA = "{ \"unionField\" : { \"TypeA\" : {} } }"
objectB = "{ \"unionField\" : { \"TypeB\" : {} } }"
it "should parse (unions-no-namespace)" $ do
parseJSON objectA `shouldBe` pure unionsNoNamespaceA
parseJSON objectB `shouldBe` pure unionsNoNamespaceB
getFileName :: FilePath -> IO FilePath
getFileName p = do
path <- getDataFileName p
isOk <- doesFileExist path
pure $ if isOk then path else p