{-# LANGUAGE ForeignFunctionInterface, RankNTypes, FlexibleContexts #-}
-- Test framework imports
import Test.Framework (defaultMain, testGroup, Test)
import Test.Framework.Providers.HUnit
import Test.HUnit hiding (Test, Testable)
import Test.Framework.Providers.QuickCheck2
import Test.QuickCheck
-- Code to test
import Data.Bits.Atomic
import Foreign.Marshal.Alloc
import Foreign.Storable
import Data.Word
import Data.Int
import Data.Bits
tests :: [Test]
tests = [ testGroup "Test Cases"
[ testCase "compareAndSwap" test_compareAndSwap_all
, testCase "compareAndSwapBool" test_compareAndSwapBool_all
, testCase "lockTestAndSet and lockRelease" test_lockTestRelease_all
, testCase "fetchAndAdd" test_fetchAndAdd_all
, testCase "fetchAndSub" test_fetchAndSub_all
, testCase "fetchAndXor" test_fetchAndXor_all
, testCase "subAndFetch" test_subAndFetch_all
]
]
main :: IO ()
main = defaultMain tests
testPattern :: Integral a => a
testPattern = 0xdeadbeef
type PolyTest = (AtomicBits a, Storable a, Integral a, Bounded a) => a -> Assertion
testTypes :: PolyTest -> Assertion
testTypes _test = do
_test (1 :: Int)
_test (1 :: Word)
_test (1 :: Int8)
_test (1 :: Int16)
_test (1 :: Int32)
_test (1 :: Int64)
_test (1 :: Word8)
_test (1 :: Word16)
_test (1 :: Word32)
_test (1 :: Word64)
test_compareAndSwap :: (AtomicBits a, Storable a, Integral a, Bounded a) =>
a -> Assertion
test_compareAndSwap i = alloca $ \p -> do
poke p i
old1 <- compareAndSwap p i 2
old1 @?= i
old2 <- compareAndSwap p 3 3
old2 @?= 2
new <- peek p
new @?= 2
old3 <- compareAndSwap p 2 3
old3 @?= 2
test_compareAndSwap_all :: Assertion
test_compareAndSwap_all = testTypes test_compareAndSwap
test_compareAndSwapBool :: (AtomicBits a, Storable a, Integral a, Bounded a) =>
a -> Assertion
test_compareAndSwapBool i = alloca $ \p -> do
poke p i
swap0 <- compareAndSwapBool p i 2
swap0 @?= True
swap1 <- compareAndSwapBool p 3 3
swap1 @?= False
new <- peek p
new @?= 2
swap2 <- compareAndSwapBool p 2 3
swap2 @?= True
test_compareAndSwapBool_all :: Assertion
test_compareAndSwapBool_all = testTypes test_compareAndSwapBool
test_fetchAndAdd :: (AtomicBits a, Storable a, Integral a, Bounded a) =>
a -> Assertion
test_fetchAndAdd i = alloca $ \p -> do
poke p i
old0 <- fetchAndAdd p 1
old0 @?= i
new <- peek p
new @?= i + 1
poke p (maxBound `asTypeOf` i)
old1 <- fetchAndAdd p 1
old1 @?= (maxBound `asTypeOf` i)
new1 <- peek p
new1 @?= (minBound `asTypeOf` i)
test_fetchAndAdd_all :: Assertion
test_fetchAndAdd_all = testTypes test_fetchAndAdd
test_fetchAndSub :: (AtomicBits a, Storable a, Integral a, Bounded a) =>
a -> Assertion
test_fetchAndSub i = alloca $ \p -> do
poke p i
old0 <- fetchAndSub p 1
old0 @?= i
new <- peek p
new @?= i - 1
poke p (minBound `asTypeOf` i)
old1 <- fetchAndSub p 1
old1 @?= (minBound `asTypeOf` i)
new1 <- peek p
new1 @?= (maxBound `asTypeOf` i)
test_fetchAndSub_all :: Assertion
test_fetchAndSub_all = testTypes test_fetchAndSub
test_fetchAndXor :: (AtomicBits a, Storable a, Integral a, Bounded a) =>
a -> Assertion
test_fetchAndXor i = alloca $ \p -> do
poke p i
old0 <- fetchAndXor p 1
old0 @?= i
new <- peek p
new @?= i `xor` 1
test_fetchAndXor_all :: Assertion
test_fetchAndXor_all = testTypes test_fetchAndXor
test_subAndFetch :: (AtomicBits a, Storable a, Integral a, Bounded a) =>
a -> Assertion
test_subAndFetch i = alloca $ \p -> do
poke p i
new0 <- subAndFetch p 1
new0 @?= i - 1
poke p (minBound `asTypeOf` i)
new1 <- subAndFetch p 1
new1 @?= (maxBound `asTypeOf` i)
test_subAndFetch_all :: Assertion
test_subAndFetch_all = testTypes test_subAndFetch
test_lockTestRelease :: (AtomicBits a, Storable a, Integral a, Bounded a) =>
a -> Assertion
test_lockTestRelease i = alloca $ \p -> do
poke p i
new0 <- lockTestAndSet p
new0 @?= i
new1 <- peek p
new1 @?= 1
lockRelease p
new2 <- peek p
new2 @?= 0
test_lockTestRelease_all :: Assertion
test_lockTestRelease_all = testTypes test_lockTestRelease