avro-0.5.2.1: test/Avro/Decode/RawBlocksSpec.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Avro.Decode.RawBlocksSpec
where
import Avro.Data.Endpoint
import Control.Monad (forM_)
import Data.Avro (decodeContainerWithEmbeddedSchema, encodeContainerWithSchema, encodeValueWithSchema, nullCodec)
import Data.Avro.Internal.Container (decodeRawBlocks, packContainerBlocks, packContainerValues)
import Data.Either (rights)
import Data.List (unfoldr)
import Data.Semigroup ((<>))
import Data.Text (pack)
import HaskellWorks.Hspec.Hedgehog
import Hedgehog
import Hedgehog.Range (Range)
import Test.Hspec
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
{- HLINT ignore "Reduce duplication" -}
{- HLINT ignore "Redundant do" -}
spec :: Spec
spec = describe "Avro.Decode.RawBlocksSpec" $ do
it "should decode empty container" $ require $ withTests 1 $ property $ do
empty <- evalIO $ encodeContainerWithSchema @Endpoint nullCodec schema'Endpoint []
decoded <- evalEither $ decodeRawBlocks empty
decoded === (schema'Endpoint, [])
it "should decode container with one block" $ require $ withTests 5 $ property $ do
msgs <- forAll $ Gen.list (Range.linear 1 5) endpointGen
container <- evalIO $ encodeContainerWithSchema nullCodec schema'Endpoint [msgs]
(s, bs) <- evalEither $ decodeRawBlocks container
s === schema'Endpoint
blocks <- evalEither $ sequence bs
fmap fst blocks === [length msgs]
it "should decode container with multiple blocks" $ require $ withTests 20 $ property $ do
msgs <- forAll $ Gen.list (Range.linear 1 19) endpointGen
container <- evalIO $ encodeContainerWithSchema nullCodec schema'Endpoint (chunksOf 4 msgs)
(s, bs) <- evalEither $ decodeRawBlocks container
s === schema'Endpoint
blocks <- evalEither $ sequence bs
let blockLengths = fst <$> blocks
sum blockLengths === length msgs
diff (last blockLengths) (<=) 4
assert $ all (==4) (init blockLengths)
it "should repack container" $ require $ withTests 20 $ property $ do
srcValues <- forAll $ Gen.list (Range.linear 1 19) endpointGen
srcContainer <- evalIO $ encodeContainerWithSchema nullCodec schema'Endpoint (chunksOf 4 srcValues)
(s, bs) <- evalEither $ decodeRawBlocks srcContainer
tgtContainer <- evalIO $ packContainerBlocks nullCodec s (rights bs)
tgtValues <- evalEither . sequence $ decodeContainerWithEmbeddedSchema tgtContainer
tgtValues === srcValues
it "should pack container with individual values" $ require $ withTests 20 $ property $ do
srcValues <- forAll $ Gen.list (Range.linear 1 19) endpointGen
let values = encodeValueWithSchema schema'Endpoint <$> srcValues
container <- evalIO $ packContainerValues nullCodec schema'Endpoint (chunksOf 4 values)
(s, bs) <- evalEither $ decodeRawBlocks container
s === schema'Endpoint
blocks <- evalEither $ sequence bs
let blockLengths = fst <$> blocks
diff (last blockLengths) (<=) 4
assert $ all (==4) (init blockLengths)
tgtValues <- evalEither . sequence $ decodeContainerWithEmbeddedSchema container
tgtValues === srcValues
chunksOf :: Int -> [a] -> [[a]]
chunksOf n = takeWhile (not.null) . unfoldr (Just . splitAt n)