{-# 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