packages feed

avro-0.3.6.0: test/Avro/JSONSpec.hs

{-# LANGUAGE DeriveGeneric       #-}
{-# LANGUAGE OverloadedStrings   #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell     #-}
module Avro.JSONSpec where

import           Control.Monad        (forM_)

import qualified Data.Aeson           as Aeson
import qualified Data.ByteString.Lazy as LBS

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"

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" }
        , unionsThree      = E3_1 37
        , unionsFour       = E4_2 "foo"
        , unionsFive       = E5_4 $ Foo { fooStuff = "foo stuff" }
        }
      unionsExampleB = Unions
        { unionsScalars    = Right 37
        , unionsNullable   = Just 42
        , unionsRecords    = Right $ Bar { barStuff = "stuff"
                                      , barThings = Foo "things"
                                      }
        , unionsSameFields = Right $ NotFoo { notFooStuff = "not foo stuff" }
        , unionsThree      = E3_3 37
        , unionsFour       = E4_4 $ Foo { fooStuff = "foo stuff" }
        , unionsFive       = E5_5 $ NotFoo { notFooStuff = "not foo stuff" }
        }
  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

getFileName :: FilePath -> IO FilePath
getFileName p = do
  path <- getDataFileName p
  isOk <- doesFileExist path
  pure $ if isOk then path else p