{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
import qualified Data.ByteString as B
import Test.Tasty
import Test.Tasty.HUnit
import Test.Tasty.QuickCheck
import Numeric.Natural
import Data.Word
import Data.Int
import Data.Bits
import Data.List
import Data.Typeable
import Data.Serialize.LEB128
newtype LargeInteger = LargeInteger Integer
deriving (Show, Eq, Ord, Num, Bits, Real, Enum, Integral, SLEB128)
newtype LargeNatural = LargeNatural Natural
deriving (Show, Eq, Ord, Num, Bits, Real, Enum, Integral, LEB128)
instance Arbitrary LargeNatural where
arbitrary = LargeNatural . fromWords <$> arbitrary
where
fromWords :: [Word8] -> Natural
fromWords = foldl' go 0
go :: Natural -> Word8 -> Natural
go acc w = (acc `shiftL` 8) + fromIntegral w
instance Arbitrary LargeInteger where
arbitrary = do
sign <- arbitrary
LargeNatural n <- arbitrary
return $ LargeInteger $ (if sign then negate else id) $ fromIntegral n
-- Only change the default (slight hack)
-- Needed to find corner cases involving non-short encodings
moreTests (QuickCheckTests 100) = QuickCheckTests 100000
moreTests (QuickCheckTests n) = QuickCheckTests n
leb128Tests :: forall a. (Typeable a, Arbitrary a, Show a, LEB128 a) => TestTree
leb128Tests = testGroup (show (typeRep (Proxy @a)))
[ testCase "empty input" $
fromLEB128 @a B.empty @=? Left "Failed reading: short encoding\nFrom:\tLEB128\n\n"
, testProperty "roundtrip" $
\i -> Right i === fromLEB128 (toLEB128 @a i)
, testProperty "unique rep" $
\(B.pack -> bs) -> case fromLEB128 @a bs of
Left _ -> property ()
Right i -> bs === toLEB128 i
]
sleb128Tests :: forall a. (Typeable a, Arbitrary a, Show a, SLEB128 a) => TestTree
sleb128Tests = testGroup (show (typeRep (Proxy @a)))
[ testCase "empty input" $
fromSLEB128 @a B.empty @=? Left "Failed reading: short encoding\nFrom:\tSLEB128\n\n"
, testProperty "roundtrip" $
\i -> Right i === fromSLEB128 (toSLEB128 @a i)
, testProperty "unique rep" $
\(B.pack -> bs) -> case fromSLEB128 @a bs of
Left _ -> property ()
Right i -> bs === toSLEB128 i
]
main = defaultMain $ adjustOption moreTests $
testGroup "tests"
[ leb128Tests @LargeNatural
, leb128Tests @Word
, leb128Tests @Word8
, leb128Tests @Word16
, leb128Tests @Word32
, leb128Tests @Word64
, sleb128Tests @LargeInteger
, sleb128Tests @Int
, sleb128Tests @Int8
, sleb128Tests @Int16
, sleb128Tests @Int32
, sleb128Tests @Int64
]