2014-12-23 18:20:11 +03:00
|
|
|
{-# LANGUAGE RankNTypes #-}
|
|
|
|
module Tests.Utils where
|
|
|
|
|
|
|
|
import Control.Applicative ((<$>))
|
|
|
|
import Control.Monad.Conc.Fixed (Conc)
|
|
|
|
import Control.Monad.Conc.SCT (runSCT, sctRandom)
|
|
|
|
import Data.List (group, sort)
|
2014-12-24 01:01:00 +03:00
|
|
|
import Data.Maybe (isJust, isNothing)
|
2014-12-23 18:20:11 +03:00
|
|
|
import System.Random (mkStdGen)
|
|
|
|
|
|
|
|
-- Couldn't get Cabal's detailed tests to work, hence this approach.
|
|
|
|
data Test = Test { name :: String, result :: IO Result }
|
|
|
|
data Result = Pass | Fail String | Error String
|
|
|
|
|
2014-12-23 19:30:20 +03:00
|
|
|
-- | Test that a predicate holds over the results of a concurrent
|
|
|
|
-- computation.
|
|
|
|
testPred :: ([Maybe a] -> Result) -> Int -> (forall t. Conc t a) -> IO Result
|
|
|
|
testPred predicate num conc = predicate . map fst <$> runSCT sctRandom (mkStdGen 0) num conc
|
2014-12-23 18:20:11 +03:00
|
|
|
|
|
|
|
-- | Test that a concurrent computation is free of deadlocks.
|
|
|
|
testDeadlockFree :: Int -> (forall t. Conc t a) -> IO Result
|
2014-12-23 19:30:20 +03:00
|
|
|
testDeadlockFree = testPred predicate where
|
2014-12-23 18:20:11 +03:00
|
|
|
predicate xs = case filter isNothing xs of
|
|
|
|
[] -> Pass
|
|
|
|
ds -> Fail $ "Found " ++ show (length ds) ++ "/" ++ show (length xs) ++ " deadlocking schedules."
|
|
|
|
|
2014-12-24 01:01:00 +03:00
|
|
|
-- | Test that a concurrent computation always deadlocks.
|
|
|
|
testDeadlocks :: Int -> (forall t. Conc t a) -> IO Result
|
|
|
|
testDeadlocks = testPred predicate where
|
|
|
|
predicate xs = case filter isJust xs of
|
|
|
|
[] -> Pass
|
|
|
|
ds -> Fail $ "Found " ++ show (length ds) ++ "/" ++ show (length xs) ++ " productive schedules."
|
|
|
|
|
2014-12-23 18:20:11 +03:00
|
|
|
-- | Test that a concurrent computation always returns the same
|
|
|
|
-- result.
|
|
|
|
testAlwaysSame :: (Eq a, Ord a) => Int -> (forall t. Conc t a) -> IO Result
|
2014-12-23 19:30:20 +03:00
|
|
|
testAlwaysSame = testPred predicate where
|
2014-12-23 18:20:11 +03:00
|
|
|
predicate xs = case group $ sort xs of
|
|
|
|
[] -> Pass
|
|
|
|
[[_]] -> Pass
|
2014-12-24 01:01:00 +03:00
|
|
|
gs -> Fail $ "Found " ++ show (length gs) ++ " distinct results."
|
2014-12-23 18:20:11 +03:00
|
|
|
|
|
|
|
-- | Invert the result of a test.
|
|
|
|
testNot :: String -> IO Result -> IO Result
|
|
|
|
testNot err old = do
|
|
|
|
res <- old
|
|
|
|
return $
|
|
|
|
case res of
|
|
|
|
Pass -> Fail err
|
|
|
|
Fail _ -> Pass
|
|
|
|
e -> e
|