packages feed

croaring-ffi-1.0: test/Test/Memory.hs

module Test.Memory
  ( tests
  , countingHooks
  ) where

import Data.Bitmap.Roaring.FFI.Bitmap qualified as Bitmap
import Data.Bitmap.Roaring.FFI.Memory (Hooks (..))
import Data.Bitmap.Roaring.FFI.Memory qualified as Memory
import Foreign.C.Types (CSize (..))
import Foreign.Marshal.Array (withArrayLen)
import Foreign.Ptr (FunPtr, castPtrToFunPtr, nullPtr, plusPtr)
import Foreign.Storable (peek, poke)
import Hedgehog (Property, assert, evalIO, (===))
import Test.Property (returns)
import Test.Property qualified as Property
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.Hedgehog (testProperty)

foreign import ccall "&counting_malloc"
  countingMalloc :: FunPtr Memory.Malloc

foreign import ccall "&counting_realloc"
  countingRealloc :: FunPtr Memory.Realloc

foreign import ccall "&counting_calloc"
  countingCalloc :: FunPtr Memory.Calloc

foreign import ccall "&counting_aligned_malloc"
  countingAlignedMalloc :: FunPtr Memory.AlignedMalloc

foreign import ccall "stdlib.h &free"
  libcFree :: FunPtr Memory.Free

foreign import ccall unsafe "counting_allocations"
  allocations :: IO CSize

countingHooks :: Hooks
countingHooks =
  Hooks
    { malloc = countingMalloc
    , realloc = countingRealloc
    , calloc = countingCalloc
    , free = libcFree
    , alignedMalloc = countingAlignedMalloc
    , alignedFree = libcFree
    }

tests :: TestTree
tests =
  testGroup
    "Memory"
    [ testProperty "hooks poke and peek agree" hooksStorable
    , testProperty "allocations go through the installed hooks" counted
    ]

hooksStorable :: Property
hooksStorable =
  Property.example $ do
    let
      pointer offset = castPtrToFunPtr $ nullPtr `plusPtr` offset
      hooks = Hooks (pointer 16) (pointer 32) (pointer 48) (pointer 64) (pointer 80) (pointer 96)
    ptr <- Property.array 1
    evalIO $ poke ptr hooks
    peek ptr `returns` hooks

counted :: Property
counted =
  Property.example $ do
    before <- evalIO allocations
    total <- evalIO . Bitmap.with (withArrayLen [0, 2 .. 200000] $ \count values -> Bitmap.ofPtr (fromIntegral count) values) $ Bitmap.getCardinality
    total === 100001
    after <- evalIO allocations
    assert $ after > before