module Test.StateMachine.Internal.Utils where
import Control.Concurrent.STM
(atomically)
import Control.Concurrent.STM.TChan
(TChan, tryReadTChan)
import Data.List
(group, sort)
import Test.QuickCheck
(Gen, Property, Testable, again, chatty,
counterexample, ioProperty, property, shrinking,
stdArgs, whenFail)
import Test.QuickCheck.Counterexamples
((:&:)(..), Counterexample, PropertyOf)
import qualified Test.QuickCheck.Counterexamples as CE
import Test.QuickCheck.Monadic
(PropertyM(MkPropertyM), run)
import Test.QuickCheck.Property
(Property(MkProperty), unProperty)
import Test.QuickCheck.Property
((.&&.), (.||.))
anyP :: (a -> Property) -> [a] -> Property
anyP p = foldr (\x ih -> p x .||. ih) (property False)
liftProperty :: Monad m => Property -> PropertyM m ()
liftProperty prop = MkPropertyM (\k -> fmap (prop .&&.) <$> k ())
whenFailM :: Monad m => IO () -> Property -> PropertyM m ()
whenFailM m prop = liftProperty (m `whenFail` prop)
alwaysP :: Int -> Property -> Property
alwaysP n prop
| n <= 0 = error "alwaysP: expected positive integer."
| n == 1 = prop
| otherwise = prop .&&. alwaysP (n 1) prop
shrinkPair' :: (a -> [a]) -> (b -> [b]) -> ((a, b) -> [(a, b)])
shrinkPair' shrinkerA shrinkerB (x, y) =
[ (x', y) | x' <- shrinkerA x ] ++
[ (x, y') | y' <- shrinkerB y ]
shrinkPair :: (a -> [a]) -> ((a, a) -> [(a, a)])
shrinkPair shrinker = shrinkPair' shrinker shrinker
forAllShrinkShow
:: Testable prop
=> Gen a -> (a -> [a]) -> (a -> String) -> (a -> prop) -> Property
forAllShrinkShow gen shrinker shower pf =
again $
MkProperty $
gen >>= \x ->
unProperty $
shrinking shrinker x $ \x' ->
counterexample (shower x') (pf x')
forAllShrinkShowC
:: CE.Testable prop
=> Gen a -> (a -> [a]) -> (a -> String) -> (a -> prop) -> PropertyOf (a :&: Counterexample prop)
forAllShrinkShowC arb shr shower prop =
CE.MkProperty $ \f ->
forAllShrinkShow arb shr shower $ \x ->
CE.unProperty (CE.property (prop x)) (\y -> f (x :&: y))
nub :: Ord a => [a] -> [a]
nub = fmap head . group . sort
dropLast :: Int -> [a] -> [a]
dropLast n xs = zipWith const xs (drop n xs)
toLast :: Int -> [a] -> a
toLast n = last . dropLast n
getChanContents :: TChan a -> IO [a]
getChanContents chan = reverse <$> atomically (go [])
where
go acc = do
mx <- tryReadTChan chan
case mx of
Just x -> go $ x : acc
Nothing -> return acc