{-# LANGUAGE BinaryLiterals #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE NegativeLiterals #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TemplateHaskell #-}
import Hedgehog
import qualified Hedgehog.Gen as Gen
import qualified Hedgehog.Range as Range
import Control.Exception.Safe
import Data.Bits
import Data.Bool
import Data.ByteString (ByteString)
import qualified Data.ByteString as ByteString
import Data.Foldable
import Data.Int
import qualified Data.Map as Map
import Data.Maybe
import Data.Monoid
import Data.Packer
import Data.Packer.MessagePack
import Data.Proxy
import Data.Text (Text)
import qualified Data.Text.Encoding as Text
import Data.Word
data Bit = Bit0 | Bit1
deriving (Eq, Show, Ord)
data BitException = BitParseFailure String
deriving (Show, Typeable)
instance Exception BitException
showBits :: [Bit] -> String
showBits = map convert
where convert Bit0 = '0'
convert Bit1 = '1'
parseBits :: MonadThrow m => String -> m [Bit]
parseBits s = case parseBits' s of
Right bits -> return bits
Left _ -> throwM $ BitParseFailure "Failure to bits"
parseBits' :: String -> Either String [Bit]
parseBits' = sequence . map parseBit
where parseBit '1' = Right Bit1
parseBit '0' = Right Bit0
parseBit c = Left ("Invalid character: " <> show c)
toBits :: FiniteBits a => a -> [Bit]
toBits a =
reverse $ map (\i -> bool Bit0 Bit1 (testBit a i)) [0..(n - 1)]
where n = finiteBitSize a
fromBits :: (Num a, Bits a) => [Bit] -> a
fromBits s =
foldl' f 0 (zip (reverse s) [0..])
where f accu (c, i) =
case c of
Bit1 -> setBit accu i
Bit0 -> accu
nthWord :: (Bits a, Integral a) => a -> Int -> Word8
nthWord = go
where go a 0 = fromIntegral $ a .&. 0xFF
go a i = go (a `shiftR` 8) (i - 1)
genPosFixInt :: (MonadGen m, Integral a) => m a
genPosFixInt =
Gen.integral (Range.linear 0 (2^7 - 1))
genNegFixInt :: forall m a. (MonadGen m, Integral a) => m a
genNegFixInt =
fromIntegral . (fromIntegral :: a -> Int8)
<$> Gen.integral (Range.linear (- 2^5) (- 1))
checkSerialization :: (Show a, Eq a, FromMsgPack a, ToMsgPack a)
=> a -> [Word8] -> PropertyT IO ()
checkSerialization a ws = do
annotate $ show a
size <- msgPackSize a
let bsSerialized = runPacking size (toMsgPack a)
bsExpected = ByteString.pack ws
annotate . show $ (ByteString.length bsSerialized)
annotate . show $ (ByteString.length bsExpected)
ByteString.unpack bsSerialized === ByteString.unpack bsExpected
annotate $ show bsSerialized
a === runUnpacking fromMsgPack bsSerialized
extractWordsBE :: forall a. (Integral a, FiniteBits a) => a -> [Word8]
extractWordsBE = go nWords []
where nWords = (finiteBitSize (undefined :: a) + 7) `div` 8
go 0 accu _ = accu
go i accu a =
let a' = fromIntegral (a `shiftR` 8)
in go (i - 1) (fromIntegral (a .&. 0xFF) : accu) a'
-- Nil
prop_nil :: Property
prop_nil = property $ do
nil <- forAll $ Gen.constant ObjectNil
checkSerialization nil [0xC0]
-- Bool
prop_bool :: Property
prop_bool = property $ do
b <- forAll $ Gen.bool
checkSerialization b [if b then 0xC3 else 0xC2]
prop_obj_bool :: Property
prop_obj_bool = property $ do
b <- forAll Gen.bool
checkSerialization (ObjectBool b) [if b then 0xC3 else 0xC2]
_prop_pos_fixnum_integral ::
forall a. (Show a, FromMsgPack a, ToMsgPack a, Integral a)
=> Proxy a -> PropertyT IO ()
_prop_pos_fixnum_integral _proxy = do
a :: a <- forAll genPosFixInt
checkSerialization a [fromIntegral a .&. 0b01111111]
_prop_obj_pos_fixnum_integral ::
forall a. (Show a, FromMsgPack a, ToMsgPack a, Integral a)
=> Proxy a -> PropertyT IO ()
_prop_obj_pos_fixnum_integral _proxy = do
a :: a <- forAll genPosFixInt
checkSerialization (ObjectInt (fromIntegral a)) [fromIntegral a .&. 0b01111111]
prop_pos_fixnum_int8 :: Property
prop_pos_fixnum_int8 = property $ _prop_pos_fixnum_integral (Proxy :: Proxy Int8)
prop_obj_pos_fixnum_int8 :: Property
prop_obj_pos_fixnum_int8 = property $ _prop_obj_pos_fixnum_integral (Proxy :: Proxy Int8)
prop_pos_fixnum_int16 :: Property
prop_pos_fixnum_int16 = property $ _prop_pos_fixnum_integral (Proxy :: Proxy Int16)
prop_obj_pos_fixnum_int16 :: Property
prop_obj_pos_fixnum_int16 = property $ _prop_obj_pos_fixnum_integral (Proxy :: Proxy Int16)
prop_pos_fixnum_int32 :: Property
prop_pos_fixnum_int32 = property $ _prop_pos_fixnum_integral (Proxy :: Proxy Int32)
prop_obj_pos_fixnum_int32 :: Property
prop_obj_pos_fixnum_int32 = property $ _prop_obj_pos_fixnum_integral (Proxy :: Proxy Int32)
prop_pos_fixnum_int64 :: Property
prop_pos_fixnum_int64 = property $ _prop_pos_fixnum_integral (Proxy :: Proxy Int64)
prop_obj_pos_fixnum_int64 :: Property
prop_obj_pos_fixnum_int64 = property $ _prop_obj_pos_fixnum_integral (Proxy :: Proxy Int64)
prop_obj_pos_fixnum_word8 :: Property
prop_obj_pos_fixnum_word8 = property $ _prop_obj_pos_fixnum_integral (Proxy :: Proxy Word8)
prop_pos_fixnum_word16 :: Property
prop_pos_fixnum_word16 = property $ _prop_pos_fixnum_integral (Proxy :: Proxy Word16)
prop_obj_pos_fixnum_word16 :: Property
prop_obj_pos_fixnum_word16 = property $ _prop_obj_pos_fixnum_integral (Proxy :: Proxy Word16)
prop_pos_fixnum_word32 :: Property
prop_pos_fixnum_word32 = property $ _prop_pos_fixnum_integral (Proxy :: Proxy Word32)
prop_obj_pos_fixnum_word32 :: Property
prop_obj_pos_fixnum_word32 = property $ _prop_obj_pos_fixnum_integral (Proxy :: Proxy Word32)
prop_pos_fixnum_word64 :: Property
prop_pos_fixnum_word64 = property $ _prop_pos_fixnum_integral (Proxy :: Proxy Word64)
prop_obj_pos_fixnum_word64 :: Property
prop_obj_pos_fixnum_word64 = property $ _prop_obj_pos_fixnum_integral (Proxy :: Proxy Word64)
_prop_neg_fixnum_integral ::
forall a. (Show a, FromMsgPack a, ToMsgPack a, Integral a)
=> Proxy a -> PropertyT IO ()
_prop_neg_fixnum_integral _proxy = do
a :: a <- forAll genNegFixInt
checkSerialization a [fromIntegral a .&. 0b11111111]
_prop_obj_neg_fixnum_integral ::
forall a. (Show a, FromMsgPack a, ToMsgPack a, Integral a)
=> Proxy a -> PropertyT IO ()
_prop_obj_neg_fixnum_integral _proxy = do
a :: a <- forAll genNegFixInt
checkSerialization (ObjectInt (fromIntegral a)) [fromIntegral a .&. 0b11111111]
prop_neg_fixnum_int8 :: Property
prop_neg_fixnum_int8 = property $ _prop_neg_fixnum_integral (Proxy :: Proxy Int8)
prop_obj_neg_fixnum_int8 :: Property
prop_obj_neg_fixnum_int8 = property $ _prop_obj_neg_fixnum_integral (Proxy :: Proxy Int8)
prop_neg_fixnum_int16 :: Property
prop_neg_fixnum_int16 = property $ _prop_neg_fixnum_integral (Proxy :: Proxy Int16)
prop_obj_neg_fixnum_int16 :: Property
prop_obj_neg_fixnum_int16 = property $ _prop_obj_neg_fixnum_integral (Proxy :: Proxy Int16)
prop_neg_fixnum_int32 :: Property
prop_neg_fixnum_int32 = property $ _prop_neg_fixnum_integral (Proxy :: Proxy Int32)
prop_obj_neg_fixnum_int32 :: Property
prop_obj_neg_fixnum_int32 = property $ _prop_obj_neg_fixnum_integral (Proxy :: Proxy Int32)
prop_neg_fixnum_int64 :: Property
prop_neg_fixnum_int64 = property $ _prop_neg_fixnum_integral (Proxy :: Proxy Int64)
prop_obj_neg_fixnum_int64 :: Property
prop_obj_neg_fixnum_int64 = property $ _prop_obj_neg_fixnum_integral (Proxy :: Proxy Int64)
genWord8 :: forall m a. (MonadGen m, Integral a) => m a
genWord8 =
fromIntegral . (fromIntegral :: a -> Word8)
<$> Gen.integral (Range.linear (2^7) (2^8 - 1))
prop_word8_word8 :: Property
prop_word8_word8 = property $ do
i :: Word8 <- forAll genWord8
checkSerialization i [0xCC, fromIntegral i]
prop_obj_word8 :: Property
prop_obj_word8 = property $ do
i <- forAll genWord8
checkSerialization (ObjectUInt i) [0xCC, fromIntegral i]
prop_word8_word16 :: Property
prop_word8_word16 = property $ do
i :: Word16 <- forAll genWord8
checkSerialization i [0xCC, fromIntegral i]
prop_word8_word32 :: Property
prop_word8_word32 = property $ do
i :: Word32 <- forAll genWord8
checkSerialization i [0xCC, fromIntegral i]
prop_word8_word64 :: Property
prop_word8_word64 = property $ do
i :: Word64 <- forAll genWord8
checkSerialization i [0xCC, fromIntegral i]
-- UInt16
genWord16 :: forall m a. (MonadGen m, Integral a) => m a
genWord16 =
fromIntegral . (fromIntegral :: a -> Word16)
<$> Gen.integral (Range.linear (2^8) (2^16 - 1))
prop_word16_word16 :: Property
prop_word16_word16 = property $ do
i :: Word16 <- forAll genWord16
checkSerialization i [0xCD, nthWord i 1, nthWord i 0]
prop_obj_word16 :: Property
prop_obj_word16 = property $ do
i :: Word16 <- forAll genWord16
checkSerialization (ObjectUInt (fromIntegral i)) (0xCD : extractWordsBE i)
prop_word16_word32 :: Property
prop_word16_word32 = property $ do
i :: Word16 <- forAll genWord16
checkSerialization (fromIntegral i :: Word32) (0xCD : extractWordsBE i)
prop_word16_word64 :: Property
prop_word16_word64 = property $ do
i :: Word64 <- forAll genWord16
checkSerialization i [0xCD, nthWord i 1, nthWord i 0]
-- UInt32
genWord32 :: forall m a. (MonadGen m, Integral a) => m a
genWord32 =
fromIntegral . (fromIntegral :: a -> Word32)
<$> Gen.integral (Range.linear (2^16) (2^32 - 1))
prop_word32_word32 :: Property
prop_word32_word32 = property $ do
i :: Word32 <- forAll genWord32
checkSerialization i (0xCE : extractWordsBE i)
prop_obj_word32 :: Property
prop_obj_word32 = property $ do
i :: Word32 <- forAll genWord32
checkSerialization (ObjectUInt (fromIntegral i)) (0xCE : extractWordsBE i)
prop_word32_word64 :: Property
prop_word32_word64 = property $ do
i :: Word32 <- forAll genWord32
checkSerialization (fromIntegral i :: Word64) (0xCE : extractWordsBE i)
-- UInt64
genWord64 :: forall m a. (MonadGen m, Integral a) => m a
genWord64 =
fromIntegral . (fromIntegral :: a -> Word64)
<$> Gen.integral (Range.linear (2^32) (2^64 - 1))
prop_word64_word64 :: Property
prop_word64_word64 = property $ do
i :: Word64 <- forAll genWord64
checkSerialization i (0xCF : extractWordsBE i)
prop_obj_word64 :: Property
prop_obj_word64 = property $ do
i :: Word64 <- forAll genWord64
checkSerialization (ObjectUInt i) (0xCF : extractWordsBE i)
-- Int8
genInt8 :: forall m a. (MonadGen m, Integral a) => m a
genInt8 =
fromIntegral . (fromIntegral :: a -> Int8)
<$> Gen.integral (Range.linear (-2^5 - 1) (-2^7))
prop_int8_int8 :: Property
prop_int8_int8 = property $ do
i :: Int8 <- forAll genInt8
checkSerialization i [0xD0, fromIntegral i]
prop_obj_int8 :: Property
prop_obj_int8 = property $ do
i :: Int8 <- forAll genInt8
checkSerialization (ObjectInt (fromIntegral i)) (0xD0 : extractWordsBE i)
prop_int8_int16 :: Property
prop_int8_int16 = property $ do
i :: Int8 <- forAll genInt8
checkSerialization (fromIntegral i :: Int16) (0xD0 : extractWordsBE i)
prop_int8_int32 :: Property
prop_int8_int32 = property $ do
i :: Int8 <- forAll genInt8
checkSerialization (fromIntegral i :: Int32) (0xD0 : extractWordsBE i)
prop_int8_int64 :: Property
prop_int8_int64 = property $ do
i :: Int8 <- forAll genInt8
checkSerialization (fromIntegral i :: Int64) (0xD0 : extractWordsBE i)
-- Int
prop_int8_int :: Property
prop_int8_int = property $ do
i :: Int8 <- forAll genInt8
checkSerialization (fromIntegral i :: Int) (0xD0 : extractWordsBE i)
prop_int16_int :: Property
prop_int16_int = property $ do
i :: Int16 <- forAll genInt16
checkSerialization (fromIntegral i :: Int) (0xD1 : extractWordsBE i)
-- Int16
genInt16 :: forall m a. (MonadGen m, Integral a) => m a
genInt16 =
fromIntegral . (fromIntegral :: a -> Int16)
<$> Gen.choice [ Gen.integral (Range.linear (-2^15) (-2^ 7 - 1))
, Gen.integral (Range.linear ( 2^ 7) ( 2^15 - 1)) ]
prop_int16_int16 :: Property
prop_int16_int16 = property $ do
i :: Int16 <- forAll genInt16
checkSerialization i (0xD1 : extractWordsBE i)
prop_obj_int16 :: Property
prop_obj_int16 = property $ do
i :: Int16 <- forAll genInt16
checkSerialization (ObjectInt (fromIntegral i)) (0xD1 : extractWordsBE i)
prop_int16_int32 :: Property
prop_int16_int32 = property $ do
i :: Int32 <- forAll genInt16
checkSerialization i (0xD1 : extractWordsBE (fromIntegral i :: Int16))
prop_int16_int64 :: Property
prop_int16_int64 = property $ do
i :: Int64 <- forAll genInt16
checkSerialization i (0xD1 : extractWordsBE (fromIntegral i :: Int16))
-- Int32
genInt32 :: forall m a. (MonadGen m, Integral a) => m a
genInt32 =
fromIntegral . (fromIntegral :: a -> Int32)
<$> Gen.choice [ Gen.integral (Range.linear (-2^31) (-2^15 - 1))
, Gen.integral (Range.linear ( 2^15) ( 2^31 - 1))]
prop_int32_int32 :: Property
prop_int32_int32 = property $ do
i :: Int32 <- forAll genInt32
checkSerialization i (0xD2 : extractWordsBE (fromIntegral i :: Int32))
prop_obj_int32 :: Property
prop_obj_int32 = property $ do
i :: Int32 <- forAll genInt32
checkSerialization (ObjectInt (fromIntegral i)) (0xD2 : extractWordsBE i)
prop_int32_int64 :: Property
prop_int32_int64 = property $ do
i :: Int64 <- forAll genInt32
checkSerialization i (0xD2 : extractWordsBE (fromIntegral i :: Int32))
-- Int64
genInt64 :: forall m a. (MonadGen m, Integral a) => m a
genInt64 =
fromIntegral . (fromIntegral :: a -> Int64)
<$> Gen.choice [ Gen.integral (Range.linear (-2^63) (-2^31 - 1))
, Gen.integral (Range.linear ( 2^31) ( 2^63 - 1))]
prop_int64_int64 :: Property
prop_int64_int64 = property $ do
i :: Int64 <- forAll genInt64
checkSerialization i (0xD3 : extractWordsBE (fromIntegral i :: Int64))
prop_obj_int64 :: Property
prop_obj_int64 = property $ do
i :: Int64 <- forAll genInt64
checkSerialization i (0xD3 : extractWordsBE i)
-- Float32
genFloat32 :: MonadGen m => m Float
genFloat32 = Gen.float (Range.exponentialFloat (- 2^32) (2^32))
prop_float32 :: Property
prop_float32 = property $ do
f <- forAll genFloat32
checkSerialization f (0xCA : ByteString.unpack (runPacking 16 (putFloat32BE f)))
floatWordsBE :: Float -> [Word8]
floatWordsBE f =
ByteString.unpack (runPacking 16 (putFloat32BE f))
doubleWordsBE :: Double -> [Word8]
doubleWordsBE f =
ByteString.unpack (runPacking 16 (putFloat64BE f))
prop_obj_float32 :: Property
prop_obj_float32 = property $ do
f <- forAll genFloat32
checkSerialization (ObjectFloat32 f) (0xCA : floatWordsBE f)
-- Float64
genFloat64 :: MonadGen m => m Double
genFloat64 = Gen.double (Range.exponentialFloat (- 2^64) (2^64))
prop_float64 :: Property
prop_float64 = property $ do
f <- forAll genFloat64
checkSerialization f (0xCB : ByteString.unpack (runPacking 16 (putFloat64BE f)))
prop_obj_float64 :: Property
prop_obj_float64 = property $ do
f <- forAll genFloat64
checkSerialization (ObjectFloat64 f) (0xCB : doubleWordsBE f)
-- Produces much more ASCII characters than unicode in order to
-- increase the change that generated texts will have a UTF decoded
-- bytestring in the requested range.
genChar :: MonadGen m => m Char
genChar = Gen.frequency [ (1, Gen.unicode)
, (9, Gen.ascii) ]
genStr :: MonadGen m => Range Int -> m Text
genStr range =
Gen.filter (decodedTextInRange range) (Gen.text range genChar)
decodedTextInRange :: Range Int -> Text -> Bool
decodedTextInRange range text =
let l = ByteString.length (Text.encodeUtf8 text)
lower = Range.lowerBound 100 range
upper = Range.upperBound 100 range
in lower <= l && l <= upper
decodeTextLength :: Integral a => Text -> (ByteString, a)
decodeTextLength t =
let bs = Text.encodeUtf8 t
n = fromIntegral $ ByteString.length bs
in (bs, n)
-- FixStr
genFixStr :: MonadGen m => m Text
genFixStr = genStr $ Range.linear 0 (2^5 - 1)
prop_fixstr :: Property
prop_fixstr = property $ do
t <- forAll genFixStr
let (bs, n :: Word8) = decodeTextLength t
checkSerialization t $ (fromIntegral n .|. 0b10100000) : ByteString.unpack bs
prop_obj_fixstr :: Property
prop_obj_fixstr = property $ do
t <- forAll genFixStr
let (bs, n :: Word8) = decodeTextLength t
checkSerialization (ObjectString t) $ (fromIntegral n .|. 0b10100000) : ByteString.unpack bs
-- Str8
genStr8 :: MonadGen m => m Text
genStr8 = genStr $ Range.linear (2^5) (2^8 - 1)
prop_str8 :: Property
prop_str8 = property $ do
s <- forAll genStr8
let (bs, l :: Word8) = decodeTextLength s
checkSerialization s (0xD9 : (extractWordsBE l ++ ByteString.unpack bs))
prop_obj_str8 :: Property
prop_obj_str8 = property $ do
s <- forAll genStr8
let (bs, l :: Word8) = decodeTextLength s
checkSerialization (ObjectString s) (0xD9 : (extractWordsBE l ++ ByteString.unpack bs))
-- Str16
genStr16 :: MonadGen m => m Text
genStr16 = genStr $ Range.linear (2^8) (2^9 - 1) -- 2^16 - 1 would be too slow.
prop_str16 :: Property
prop_str16 = property $ do
s <- forAll genStr16
let (bs, l :: Word16) = decodeTextLength s
checkSerialization s (0xDA : (extractWordsBE l ++ ByteString.unpack bs))
prop_obj_str16 :: Property
prop_obj_str16 = property $ do
s <- forAll genStr16
let (bs, l :: Word16) = decodeTextLength s
checkSerialization (ObjectString s) (0xDA : (extractWordsBE l ++ ByteString.unpack bs))
-- Bin8
genBin8 :: MonadGen m => m ByteString
genBin8 = Gen.bytes $ Range.linear 0 (2^8 - 1)
prop_bin8 :: Property
prop_bin8 = property $ do
b <- forAll genBin8
let l = fromIntegral (ByteString.length b) :: Word8
checkSerialization b (0xC4 : (extractWordsBE l ++ ByteString.unpack b))
prop_obj_bin8 :: Property
prop_obj_bin8 = property $ do
b <- forAll genBin8
let l = fromIntegral (ByteString.length b) :: Word8
checkSerialization (ObjectBinary b) (0xC4 : (extractWordsBE l ++ ByteString.unpack b))
-- Bin16
genBin16 :: MonadGen m => m ByteString
genBin16 = Gen.bytes $ Range.linear (2^8) (2^9 - 1) -- 2^16 - 1 would be too slow.
prop_bin16 :: Property
prop_bin16 = property $ do
b <- forAll genBin16
let l = fromIntegral (ByteString.length b) :: Word16
checkSerialization b (0xC5 : (extractWordsBE l ++ ByteString.unpack b))
prop_obj_bin16 :: Property
prop_obj_bin16 = property $ do
b <- forAll genBin16
let l = fromIntegral (ByteString.length b) :: Word16
checkSerialization (ObjectBinary b) (0xC5 : (extractWordsBE l ++ ByteString.unpack b))
genObject :: MonadGen m => m Object
genObject =
Gen.frequency [ (1, ObjectBinary <$> genBin8)
, (1, pure ObjectNil)
, (1, ObjectBool <$> Gen.bool)
, (1, ObjectString <$> genFixStr)
, (1, ObjectString <$> genStr8)
, (1, ObjectBinary <$> genBin8)
, (1, ObjectInt <$> genInt16)
, (1, ObjectUInt <$> genWord16)
]
genObjectWithSize :: MonadGen m => m (Maybe (Object, Int))
genObjectWithSize = do
obj <- genObject
case msgPackSize obj of
Just size -> return $ Just (obj, size)
Nothing -> return Nothing
serializeObj :: Object -> Int -> ByteString
serializeObj obj size =
runPacking size (toMsgPack obj)
genObjectPairWithSize :: MonadGen m => m (Maybe ((Object, Int), (Object, Int)))
genObjectPairWithSize = do
a <- genObjectWithSize
b <- genObjectWithSize
return $ (,) <$> a <*> b
prop_array :: Property
prop_array = property $ do
objsWithSize <- catMaybes <$> (forAll $ Gen.list (Range.linear (2^4) (2^6)) genObjectWithSize)
let objs = map fst objsWithSize
n = fromIntegral (length objs) :: Int16
objsSerialized = ByteString.unpack . mconcat . map (uncurry serializeObj) $ objsWithSize
checkSerialization (ObjectArray objs) (0xDC : (extractWordsBE n ++ objsSerialized))
serializeObjPair :: (Object, Int) -> (Object, Int) -> ByteString
serializeObjPair (obj0, size0) (obj1, size1) =
runPacking (fromIntegral (size0 + size1)) (toMsgPack obj0 >> toMsgPack obj1)
filterDuplicates :: (Ord a, Ord b) => [(a, b)] -> [(a, b)]
filterDuplicates = Map.toList . Map.fromList
prop_fixmap :: Property
prop_fixmap = property $ do
objsWithSize <- filterDuplicates . catMaybes <$> (forAll $ Gen.list (Range.linear 0 15) genObjectPairWithSize)
let objPairs = map (\(a, b) -> (fst a, fst b)) objsWithSize
n = fromIntegral (length objPairs) :: Int16
objsSerialized = ByteString.unpack . mconcat . map (uncurry serializeObjPair) $ objsWithSize
annotate . show $ n
checkSerialization (ObjectMap (Map.fromList objPairs)) ((0b10000000 .|. (fromIntegral n)) : objsSerialized)
tests :: IO Bool
tests = checkParallel $$(discover)
main :: IO ()
main =
tests >>= \case
True -> putStrLn "Tests Passed"
False -> putStrLn "Tests Failed"