hash-cons-0.1.0.0: test/Main.hs
module Main (main) where
import Control.Concurrent.Async
import Control.Monad
import Data.HashCons.Internal
import Data.Hashable
import Data.IORef
import System.Mem.StableName
import Test.Tasty
import Test.Tasty.HUnit
import Test.Tasty.QuickCheck as QC
main :: IO ()
main = defaultMain tests
tests :: TestTree
tests = testGroup "HashCons Tests"
[ QC.testProperty "Reflexivity" prop_reflexivity
, QC.testProperty "Symmetry" prop_symmetry
, QC.testProperty "Consistency of unHashCons" prop_consistency_unHashCons
, QC.testProperty "Deduplication" prop_deduplication
, QC.testProperty "Ord and Eq Consistency" prop_ord_eq_consistency
, QC.testProperty "Ord Transitivity" prop_ord_transitivity
]
prop_reflexivity :: Int -> Property
prop_reflexivity x = let hx = hashCons x in hx === hx
prop_symmetry :: Int -> Int -> Property
prop_symmetry x y = let hx = hashCons x; hy = hashCons y in (hx == hy) === (hy == hx)
prop_consistency_unHashCons :: Int -> Int -> Property
prop_consistency_unHashCons x y = let hx = hashCons x; hy = hashCons y in
(hx == hy) === (unHashCons hx == unHashCons hy)
prop_deduplication :: Int -> Int -> Property
prop_deduplication x y = ioProperty $ do
let hx = hashCons x
hy = hashCons y
-- Perform the equality check to trigger deduplication
areEqual <- eqHashConsIO hx hy
if areEqual
then do
-- Read the contents of both IORefs
a1 <- readIORef (_hashCons_ref hx)
a2 <- readIORef (_hashCons_ref hy)
-- Create StableNames for both contents
sn1 <- makeStableName a1
sn2 <- makeStableName a2
-- Check if the StableNames are equal (pointer equality)
return $ sn1 == sn2
else return True -- If not equal, deduplication isn't expected
-- Helper function to perform equality check in IO
eqHashConsIO :: Eq a => HashCons a -> HashCons a -> IO Bool
eqHashConsIO (HashCons h1 ref1) (HashCons h2 ref2)
| h1 /= h2 = return False
| ref1 == ref2 = return True
| otherwise = do
a1 <- readIORef ref1
a2 <- readIORef ref2
if a1 == a2
then do
writeIORef ref1 a2
return True
else return False
prop_ord_eq_consistency :: Int -> Int -> Bool
prop_ord_eq_consistency x y = let hx = hashCons x; hy = hashCons y in
(hx == hy) == (compare hx hy == EQ)
prop_ord_transitivity :: Int -> Int -> Int -> Property
prop_ord_transitivity x y z = let hx = hashCons x; hy = hashCons y; hz = hashCons z in
(compare hx hy == LT && compare hy hz == LT) ==> (compare hx hz == LT)