bytehash-0.1.0.0: test/Main.hs
import Control.Exception (try,bracket)
import Control.Monad (forM_)
import Data.Bytes (Bytes)
import Data.Bytes.Hash (entropy)
import Data.Primitive (ByteArray)
import Data.Word (Word8)
import Hedgehog (Property,Gen,property,forAll,(===),failure,evalIO,annotateShow)
import Hedgehog.Gen (integral,word8,word)
import Hedgehog.Gen (shuffle,list,enumBounded,int,frequency,choice,element)
import Hedgehog.Range (Range,linear)
import Test.Tasty (defaultMain,testGroup,TestTree)
import Test.Tasty.HUnit (testCase,assertEqual,Assertion,(@=?))
import Test.Tasty.Hedgehog (testProperty)
import Control.Monad.IO.Class (liftIO)
import System.IO (openBinaryFile,Handle,IOMode(ReadMode))
import System.IO.Unsafe (unsafePerformIO)
import System.Entropy (CryptHandle,openHandle,closeHandle)
import qualified Data.Bytes as Bytes
import qualified Data.Bytes.Hash as Hash
import qualified Data.Bytes.HashMap as BT
import qualified Data.List as List
import qualified GHC.Exts as Exts
main :: IO ()
main = do
rand <- openHandle
defaultMain (tests rand)
tests :: CryptHandle -> TestTree
tests rand = testGroup "bytehash"
[ testCase "A" (Hash.bytes myEntropy fooBytesA @=? Hash.bytes myEntropy fooBytesB)
, testCase "B" (Hash.bytes myEntropy fooBytesA @=? Hash.byteArray myEntropy fooByteArray)
, testCase "C" (Hash.bytes myEntropy mediumBytesA @=? Hash.bytes myEntropy mediumBytesB)
, testCase "D" (Hash.bytes myEntropy mediumBytesA @=? Hash.byteArray myEntropy mediumByteArray)
-- , testProperty "small-zero-collisions" smallZeroCollisionsProp
, testGroup "Map"
[ testProperty "lookup" byteTableLookupProp
, testCase "lookup-A" (byteTableLookupA rand)
]
]
fooByteArray :: ByteArray
fooByteArray = Bytes.toByteArray (Bytes.fromAsciiString "foo")
fooBytesA :: Bytes
fooBytesA = Bytes.unsafeDrop 1 (Bytes.fromAsciiString "xfoo")
fooBytesB :: Bytes
fooBytesB = Bytes.unsafeDrop 2 (Bytes.fromAsciiString "abfoo")
mediumByteArray :: ByteArray
mediumByteArray = Bytes.toByteArray $ Bytes.fromAsciiString
"abcdefghijklmnopqrstuvwxyz_now_i_know_my_abcs"
mediumBytesA :: Bytes
mediumBytesA = Bytes.unsafeDrop 1 $ Bytes.fromAsciiString
"7abcdefghijklmnopqrstuvwxyz_now_i_know_my_abcs"
mediumBytesB :: Bytes
mediumBytesB = Bytes.unsafeDrop 2 $ Bytes.fromAsciiString
"98abcdefghijklmnopqrstuvwxyz_now_i_know_my_abcs"
myEntropy :: ByteArray
myEntropy = Exts.fromList $ List.take 2000 $ List.cycle
[ 0x42,0x13,0x12,0x05,0xFF,0x47,0x19,0xE3,0x03,0xFF ]
byteTableLookupProp :: Property
byteTableLookupProp = property $ do
bytesList <- forAll $ list (linear 0 42) genBytes
let pairs = map (\x -> (x,x)) bytesList
case performFromList pairs of
Left e@(BT.HashMapException{}) -> do
annotateShow e
failure
Right table -> forM_ bytesList $ \bytes -> do
BT.lookup bytes table === Just bytes
performFromList :: [(Bytes,v)] -> Either BT.HashMapException (BT.Map v)
{-# noinline performFromList #-}
performFromList xs = unsafePerformIO
$ bracket openHandle closeHandle (\rand -> try (BT.fromList rand xs))
genBytes :: Gen Bytes
genBytes = do
byteList <- list (linear 0 64) genByte
front <- genOffset (List.length byteList)
let raw = Exts.fromList byteList
if Bytes.length raw >= front
then return (Bytes.unsafeDrop front raw)
else error "genBytes: bad"
genByte :: Gen Word8
genByte = word8 (linear minBound maxBound)
genOffset :: Int -> Gen Int
genOffset originalLen = integral (linear 0 maxDiscard)
where
maxDiscard = min 19 (div originalLen 3)
byteTableLookupA :: CryptHandle -> IO ()
byteTableLookupA h = do
let bs :: [(Bytes,Bytes)]
bs = map (\x -> (Exts.fromList x, Exts.fromList x))
[ []
, [0x34,0x36,0x5f,0xe2,0xf3,0x30]
, [0x7b,0x19,0x08,0xd0,0x0d,0x6b,0xd9,0xa5,0x94,0xc1
,0x94,0xf7,0xa7,0x20,0x44,0x45,0x32
]
, [0x28,0xd8,0xeb,0x78,0x7b,0x14,0x3a,0x0d]
, [0xf3,0xa0,0x02,0xd0]
]
m <- BT.fromList h bs
forM_ bs $ \(b,_) -> do
BT.lookup b m @=? Just b