packages feed

lvish-1.1.2: tests/AddRemoveSetTests.hs

{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE DataKinds #-}

-- | Tests for the Data.LVar.AddRemoveSet module.

module AddRemoveSetTests(tests, runTests) where

import Control.Concurrent
import Test.Framework.Providers.HUnit 
import Test.Framework (Test, defaultMain, testGroup)
import Test.HUnit (Assertion, assertEqual, assertBool, Counts(..))
import Test.Framework.TH (testGroupGenerator)
import qualified Test.HUnit as HU
import           TestHelpers2 as T

import qualified Data.Set as S

import qualified Data.LVar.AddRemoveSet as ARS

import           Control.LVish
import           Control.LVish.DeepFrz (DeepFrz(..), Frzn, Trvrsbl, runParThenFreeze, runParThenFreezeIO)
import           Control.LVish.Internal (liftIO)

--------------------------------------------------------------------------------

tests :: Test
tests = $(testGroupGenerator)

runTests :: IO ()
runTests = T.defaultMainSeqTests [tests]

--------------------------------------------------------------------------------

case_v1 :: Assertion
case_v1 = v1 >>= assertEqual "freeze with 3 elements"
          (S.fromList [1..3] :: S.Set Int)

-- If you have a computation that does freezing, you have to run it with runParIO.
v1 :: IO (S.Set Int)
v1 = runParIO $
     do s <- ARS.newEmptySet
        ARS.insert 1 s
        ARS.insert 2 s
        ARS.insert 3 s
        ARS.waitAddedSize 3 s
        ARS.freezeSet s

case_v2 :: Assertion
case_v2 = v2 >>= assertEqual "freeze with 10 elements added, asynchronously"
          (S.fromList [1.. v2size] :: S.Set Int)

v2 :: IO (S.Set Int)
v2 = runParIO $
     do s <- ARS.newEmptySet
        mapM_ (\n -> fork $ do
                     -- liftIO$ threadDelay 5000 
                     logDbgLn 3$ " [AR-v2] Doing one insert: "++show n
                     ARS.insert n s) [1.. v2size]
        logDbgLn 3$ " [AR-v2] now waiting.."
        ARS.waitAddedSize v2size s
        logDbgLn 3$ " [AR-v2] now freezing.."
        ARS.freezeSet s

v2size =
  case numElems of
    Just x -> x
    Nothing -> 10

case_v3 :: Assertion
case_v3 = stressTest T.stressTestReps 15 v3 (\()->True)

-- "freeze with 3 elements added, asynchronously"
-- If we're doing a guaranteed-deterministic computation we can't
-- actually read out the contents of the set.
v3 :: Par d s ()
v3 = 
     do s <- ARS.newEmptySet
        mapM_ (\n -> fork $ ARS.insert n s) [1..10]
        ARS.waitAddedSize 10 s

-- Getting occasional failures here with -N2, don't know what's
-- wrong. :(
case_v4 :: Assertion
case_v4 = stressTest T.stressTestReps 30 v4 (== (S.fromList [1..10] :: S.Set Int))

-- "additions and removals"
v4 :: Par QuasiDet s (S.Set Int)
v4 = 
     do s <- ARS.newEmptySet
        mapM_ (\n -> fork $ ARS.insert n s) [1..15]
        mapM_ (\n -> fork $ ARS.remove n s) [11..15]
        ARS.waitAddedSize 15 s 
        ARS.waitRemovedSize 5 s 
        ARS.freezeSet s

-- This one is intentionally undersynchronized.
case_i1 :: Assertion
case_i1 = do
  allowSomeExceptions ["Attempt to change a frozen LVar"] $
    do x <- i1
       assertEqual "additions and removals, undersynchronized"
         (S.fromList [1..10] :: S.Set Int) x
  return ()

-- Unblock too early, leaving a put-after-freeze possibility.
i1 :: IO (S.Set Int)
i1 = runParIO $
     do s <- ARS.newEmptySet
        mapM_ (\n -> fork $ ARS.insert n s) [1..15]
        mapM_ (\n -> fork $ ARS.remove n s) [11..15]
        -- If we don't wait for 15 additions, they might not all be
        -- there when we check.
        ARS.waitRemovedSize 5 s 
        ARS.freezeSet s