{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE DerivingVia, DeriveGeneric #-}
{-# LANGUAGE DataKinds #-}
import Data.Binary
import GHC.Generics
import Test.Hspec
import Test.QuickCheck
import Test.QuickCheck.Arbitrary.Generic
import Data.Binary.Combinators
import Data.Binary.DerivingVia
decenc :: Binary a => a -> a
decenc = decode . encode
data SimpleSumType1
= SST11 (MatchBytes "test context" '[ 0xd3, 0x4d, 0xf0, 0x0d ])
| SST12 (MatchBytes "test context" '[ 0xde, 0xad, 0xbe, 0xef ])
deriving (Show, Eq, Generic)
deriving Binary via Alternatively SimpleSumType1
data SimpleSumType2
= SST21 (MatchBytes "test context" '[ 0xde, 0xad, 0xbe, 0xef ])
| SST22 (MatchBytes "test context" '[ 0xd3, 0x4d, 0xf0, 0x0d ])
deriving (Show, Eq, Generic)
deriving Binary via Alternatively SimpleSumType2
data ComplexType
= CT1
{ header1 :: MatchBytes "test context" '[ 0xaa, 0xbb, 0xff ]
, skip1 :: SkipByte 0xff
, skipCount1 :: SkipCount Word8 123
, counted1 :: CountedBy Word16 Word8
, rest1 :: Some Word8
}
| CT2
{ header2 :: MatchBytes "test context" '[ 0xdd, 0xea, 0xae ]
, skipCount2 :: SkipCount Word16 9
, counted2 :: CountedBy Word32 Word16
, rest2 :: Some Word16
}
| CT3
{ header3 :: MatchBytes "test context" '[ 0xda, 0xdd, 0xee ]
, skipCount3 :: SkipCount Int 17
, rest3 :: Some Word16
}
deriving (Show, Eq, Generic)
deriving Binary via Alternatively ComplexType
instance Arbitrary ComplexType where
arbitrary = genericArbitrary
shrink = genericShrink
main :: IO ()
main = hspec $ do
describe "Alternatively" $ do
it "works for simple types" $ do
let val = SST11 matchBytes in decenc val `shouldBe` val
let val = SST12 matchBytes in decenc val `shouldBe` val
it "is order-invariant" $ do
decode (encode $ SST11 matchBytes) `shouldBe` SST22 matchBytes
describe "decode . encode = id" $ do
it "for Many" $ property $ \(xs :: Many Int) -> decenc xs `shouldBe` xs
it "for Some" $ property $ \(xs :: Some Int) -> decenc xs `shouldBe` xs
it "for CountedBy" $ property $ \(xs :: CountedBy Word16 Int) -> decenc xs `shouldBe` xs
it "for complex types" $ property $ \(val :: ComplexType) -> decenc val `shouldBe` val