packages feed

vault-0.3.2.0: test/Data/Vault/Spec.h

import Prelude hiding (lookup)

import Control.Concurrent (forkFinally, threadDelay)
import Control.Concurrent.MVar (MVar, putMVar, takeMVar, newEmptyMVar)
import Control.Monad.ST (RealWorld, stToIO)
import Test.Hspec
import MODULE_UNDER_TEST

newKey' :: IO (Key RealWorld a)
newKey' = stToIO newKey

spec :: Spec
spec = describe TEST_NAME $ do

  describe "Locker" $ do

    it "unlock retrieves locked item" $ do
      key <- newKey' :: IO (Key RealWorld Int)
      unlock key (lock key 42) `shouldBe` Just 42

    it "unlock with different key retrieves Nothing" $ do
      key  <- newKey' :: IO (Key RealWorld Int)
      key' <- newKey' :: IO (Key RealWorld Int)
      unlock key' (lock key 42) `shouldBe` Nothing

    -- Even though the code contained a potential race condition,
    -- this test was unable to trigger it.
    -- Still, we keep it as a regression test.
    it "no race condition for simultaneous unlock" $ do
      key  <- newKey' :: IO (Key RealWorld Int)
      let check n = unlock key (lock key n) `shouldBe` Just n
      race $ map check [1..500]

  describe "Vault" $ do

    it "lookup empty returns Nothing" $ do
      key <- newKey' :: IO (Key RealWorld Int)
      lookup key empty `shouldBe` Nothing

{-----------------------------------------------------------------------------
    Helper functions
------------------------------------------------------------------------------}
-- | Race multiple IO actions against each other.
race :: [IO ()] -> IO ()
race xs = do
    mvars <- mapM (\_ -> newEmptyMVar :: IO (MVar ())) xs
    sequence $
        zipWith
          (\mvar m -> forkFinally (threadDelay 10 >> m) (const $ putMVar mvar ()))
          mvars
          xs
    mapM_ takeMVar mvars