packages feed

groan-0.1.0.0: tests/spec.hs

import Control.Exception (SomeException, try)
import Control.Monad (void)
import Control.Monad.IO.Class (MonadIO (liftIO))
import Control.Monad.Primitive (RealWorld)
import Data.Foldable (forM_)
import Data.Functor ((<&>))
import Data.Int
import Data.Primitive.Contiguous qualified as C
import Data.Vector.Groan (pushFoldableBack)
import Data.Vector.Groan qualified as B
import Data.Vector.Groan.List qualified as List
import Data.Vector.Groan.Unboxed qualified as U
import Data.Vector.Unboxed qualified as UV
import Hedgehog.Gen qualified as Gen
import Hedgehog.Range qualified as Range
import Test.Hspec
import Test.Hspec.Hedgehog
import Prelude

type Element = Int32

genElement :: Gen Element
genElement = Gen.int32 (Range.linear minBound maxBound)

genElements :: Gen [Element]
genElements = Gen.list (Range.exponential 0 100) genElement

genManyElements :: Gen [Element]
genManyElements = Gen.list (Range.exponential 100 5000) genElement

testOp
  :: (a ~ Element, Show r, Eq r)
  => ([a] -> IO (buffer a))
  -> (buffer a -> IO (C.Array a))
  -> (buffer a -> IO r)
  -> (List.Buffer a -> IO r)
  -> PropertyT IO ()
testOp bufferNew bufferFreeze bufferOp listOp = do
  elements <- forAll genElements
  buf <- liftIO (bufferNew elements)
  listBuf <- liftIO (List.thaw (C.fromList elements))
  referenceOpResult <- liftIO (try @SomeException (listOp listBuf) <&> either (const Nothing) Just)
  actualOpResult <- liftIO (try @SomeException (bufferOp buf) <&> either (const Nothing) Just)
  reference <- liftIO (List.freeze listBuf)
  actual <- liftIO (bufferFreeze buf)
  referenceOpResult === actualOpResult
  reference === actual

main :: IO ()
main = hspec do
  describe "Data.Vector.Groan" do
    let
      testBOp
        :: (Eq r, Show r)
        => (B.Buffer RealWorld Element -> IO r)
        -> (List.Buffer Element -> IO r)
        -> PropertyT IO ()
      testBOp = testOp (B.thaw . C.fromList) B.freeze
    it "pushBack[1]" do
      elt <- forAll genElement
      testBOp
        (`B.pushBack` elt)
        (`List.pushBack` elt)
    it "pushBack[n]" do
      elts <- forAll genManyElements
      testBOp
        (\buf -> mapM_ (B.pushBack buf) elts)
        (\list -> mapM_ (List.pushBack list) elts)
    it "pushFoldableBack" do
      elts <- forAll genElements
      testBOp
        (`B.pushFoldableBack` elts)
        (`List.pushFoldableBack` elts)
    it "pushAllBack" do
      elts <- forAll genElements
      testBOp
        (`B.pushAllBack` C.toSlice (C.fromList @C.Array elts))
        (`List.pushFoldableBack` elts)
    it "popBack" do
      testBOp B.popBack List.popBack
    it "read" do
      i <- forAll (Gen.int (Range.linear 0 100))
      testBOp (`B.read` i) (`List.read` i)

  describe "Data.Vector.Groan.Unboxed" do
    let
      testUOp
        :: (Eq r, Show r)
        => (U.Buffer RealWorld Element -> IO r)
        -> (List.Buffer Element -> IO r)
        -> PropertyT IO ()
      testUOp = testOp (U.thaw . UV.fromList) (fmap (C.fromList . UV.toList) . U.freeze)
    it "pushBack[1]" do
      elt <- forAll genElement
      testUOp
        (`U.pushBack` elt)
        (`List.pushBack` elt)
    it "pushBack[n]" do
      elts <- forAll genManyElements
      testUOp
        (\buf -> mapM_ (U.pushBack buf) elts)
        (\list -> mapM_ (List.pushBack list) elts)
    it "popBack" do
      testUOp U.popBack List.popBack
    it "read" do
      i <- forAll (Gen.int (Range.linear 0 100))
      testUOp (`U.read` i) (`List.read` i)