{-# LANGUAGE ScopedTypeVariables , RankNTypes #-} module Main where import Data.Map.Strict as Map import Control.Monad (forM_) import Control.Concurrent (threadDelay) import Control.Concurrent.Async (async) import Control.Concurrent.STM.TMapMVar as TMapMVar import Control.Concurrent.STM.TVar (readTVar, newTVarIO, writeTVar, modifyTVar') import Control.Concurrent.STM.TMVar (tryReadTMVar) import Control.Concurrent.STM (atomically, STM) import Test.Tasty (defaultMain, testGroup) import Test.Tasty.QuickCheck (testProperty) import Test.QuickCheck (Arbitrary (..), Property, ioProperty) import System.IO.Unsafe (unsafePerformIO) main :: IO () main = defaultMain $ testGroup "Control.Concurrent.STM.TMapMVar" [ testProperty "Insert in Empty" insertInEmpty , testProperty "Insert in Full" insertInFull , testProperty "Insert Force doesn't Block" insertForceDoesntBlock , testProperty "Empty after Lookup" emptyAfterLookup , testProperty "Observe doesn't Mutate" nonMutativeObserve , testProperty "Lookup before Insert" lookupThenInsert ] insertInEmpty :: Int -> Int -> Property insertInEmpty k v = ioProperty $ do var <- atomically newTMapMVar TMapMVar.insert var k v v' <- TMapMVar.observe var k pure (v == v') insertInFull :: Int -> Int -> Property insertInFull k v = ioProperty $ do var <- do m <- atomically newTMapMVar TMapMVar.insert m k (v-1) pure m async $ do threadDelay 10 TMapMVar.delete var k TMapMVar.insert var k v v' <- TMapMVar.lookup var k pure (v == v') insertForceDoesntBlock :: Int -> Int -> Int -> Property insertForceDoesntBlock k v1 v2 = ioProperty $ do var <- atomically newTMapMVar TMapMVar.insert var k v1 TMapMVar.insertForce var k v2 v' <- TMapMVar.lookup var k pure (v' == v2) emptyAfterLookup :: Int -> Int -> Property emptyAfterLookup k v = ioProperty $ do var <- atomically newTMapMVar TMapMVar.insert var k v _ <- TMapMVar.lookup var k mV' <- TMapMVar.tryObserve var k pure (mV' == Nothing) nonMutativeObserve :: Int -> Int -> Property nonMutativeObserve k v = ioProperty $ do var <- atomically newTMapMVar TMapMVar.insert var k v v1 <- TMapMVar.observe var k v2 <- TMapMVar.observe var k pure (v1 == v2 && v2 == v) lookupThenInsert :: Int -> Int -> Property lookupThenInsert k v = ioProperty $ do var <- atomically newTMapMVar async $ do threadDelay 10 TMapMVar.insert var k v v' <- TMapMVar.lookup var k pure (v' == v)