packages feed

avro-0.3.0.1: test/Avro/THUnionSpec.hs

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

import qualified Data.List.NonEmpty   as NE

import qualified Data.Aeson           as Aeson
import           Data.Avro
import           Data.Avro.Deriving
import qualified Data.Avro.Schema     as Schema
import qualified Data.Avro.Types      as Avro
import qualified Data.ByteString.Lazy as LBS

import           System.Directory     (doesFileExist)

import           Test.Hspec

import           Paths_avro

deriveAvro "test/data/unions.avsc"

spec :: Spec
spec = describe "Avro.THUnionSpec: Schema with unions." $ do
  let objA = Unions
        { unionsScalars = Left "foo"
        , unionsNullable = Nothing
        , unionsRecords = Left $ Foo { fooStuff = "stuff" }
        , unionsSameFields = Left $ Foo { fooStuff = "more stuff" }
        }
      objB = Unions
        { unionsScalars = Right 42
        , unionsNullable = Just 37
        , unionsRecords = Right $ Bar { barStuff = "stuff"
                                      , barThings = Foo { fooStuff = "things" }
                                      }
        , unionsSameFields = Right $ NotFoo { notFooStuff = "different from Foo" }
        }

      field name schema def = Schema.Field name [] Nothing (Just Schema.Ascending) schema def
      record name namespace fields =
        Schema.Record name namespace [] Nothing (Just Schema.Ascending) fields
      named = Schema.NamedType . Schema.TN

      expectedSchema = record "Unions" (Just "haskell.avro.example")
        [ field "scalars"    (Schema.mkUnion (NE.fromList [Schema.String, Schema.Long])) scalarsDefault
        , field "nullable"   (Schema.mkUnion (NE.fromList [Schema.Null, Schema.Int]))    nullableDefault
        , field "records"    (Schema.mkUnion (NE.fromList [fooSchema, barSchema]))       Nothing
        , field "sameFields" (Schema.mkUnion (NE.fromList [named "Foo", notFooSchema]))  Nothing
        ]
      scalarsDefault  = Just $ Avro.Union (NE.fromList [Schema.String, Schema.Long]) Schema.String (Avro.String "foo")
      nullableDefault = Just $ Avro.Union (NE.fromList [Schema.Null, Schema.Int])    Schema.Null   Avro.Null

      fooSchema = record "Foo" Nothing [field "stuff" Schema.String Nothing]
      barSchema = record "Bar" Nothing
        [ field "stuff"  Schema.String Nothing
        , field "things" (named "Foo") Nothing
        ]
      notFooSchema = record "NotFoo" Nothing [field "stuff" Schema.String Nothing]

  unionsSchemaFile <- runIO $ getFileName "test/data/unions.avsc" >>= LBS.readFile
  let Just unionsSchemaFromJSON = Aeson.decode unionsSchemaFile

  it "produces valid schemas" $ do
    schema'Unions        `shouldBe` expectedSchema
    unionsSchemaFromJSON `shouldBe` expectedSchema
  it "records with unions should roundtrip" $ do
    fromAvro (toAvro objA) `shouldBe` pure objA
    fromAvro (toAvro objB) `shouldBe` pure objB

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