packages feed

concurrent-extra-0.4: Control/Concurrent/Thread/Test.hs

{-# LANGUAGE NoImplicitPrelude
           , UnicodeSyntax
  #-}

module Control.Concurrent.Thread.Test ( tests ) where


-------------------------------------------------------------------------------
-- Imports
-------------------------------------------------------------------------------

-- from base:
import Control.Concurrent ( threadDelay )
import Control.Exception  ( unblock, block, blocked )
import Control.Monad      ( return, (>>=), fail, (>>) )
import Data.Bool          ( Bool(False, True), not )
import Data.Function      ( ($), id )
import Data.Functor       ( fmap  )
import Data.IORef         ( newIORef, readIORef, writeIORef )
import Data.Maybe         ( maybe )
import Prelude            ( fromInteger, toInteger )
import System.Timeout     ( timeout )

-- from base-unicode-symbols:
import Prelude.Unicode       ( (⋅) )

-- from concurrent-extra:
import qualified Control.Concurrent.Lock   as Lock
import qualified Control.Concurrent.Thread as Thread
import TestUtils ( a_moment, within )

-- from HUnit:
import Test.HUnit ( Assertion, assert )

-- from test-framework:
import Test.Framework ( Test )

-- from test-framework-hunit:
import Test.Framework.Providers.HUnit ( testCase )


-------------------------------------------------------------------------------
-- Tests for Thread
-------------------------------------------------------------------------------

tests ∷ [Test]
tests = [ testCase "wait"           test_wait
        , testCase "waitTimeout"    test_waitTimeout
        , testCase "isRunning"      test_isRunning
        , testCase "blockedState"   test_blockedState
        , testCase "unblockedState" test_unblockedState
        ]

test_wait ∷ Assertion
test_wait = assert $ fmap (maybe False id) $ timeout (10 ⋅ a_moment) $ do
  r ← newIORef False
  tid ← Thread.forkIO $ do
    threadDelay $ 2 ⋅ a_moment
    writeIORef r True
  _ ← Thread.wait tid
  readIORef r

test_waitTimeout ∷ Assertion
test_waitTimeout = assert $ within (10 ⋅ a_moment) $ do
  l ← Lock.newAcquired
  tid ← Thread.forkIO $ Lock.acquire l
  _ ← Thread.waitTimeout tid (toInteger $ 5 ⋅ a_moment)
  Lock.release l

test_isRunning ∷ Assertion
test_isRunning = assert $ fmap (maybe False id) $ timeout (10 ⋅ a_moment) $ do
  l ← Lock.newAcquired
  tid ← Thread.forkIO $ Lock.acquire l
  r ← Thread.isRunning tid
  Lock.release l
  return r

test_blockedState ∷ Assertion
test_blockedState = (block $ Thread.forkIO $ blocked) >>=
                    Thread.unsafeWait >>= assert

test_unblockedState ∷ Assertion
test_unblockedState = (unblock $ Thread.forkIO $ fmap not $ blocked) >>=
                      Thread.unsafeWait >>= assert


-- The End ---------------------------------------------------------------------