module Test.StateMachine.Internal.Utils where
import Data.List
(group, sort)
import Test.QuickCheck
(Property, chatty, counterexample, property,
stdArgs, whenFail)
import Test.QuickCheck.Counterexamples
(PropertyOf)
import qualified Test.QuickCheck.Counterexamples as CE
import Test.QuickCheck.Monadic
(PropertyM(MkPropertyM), monadicIO, run)
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
shrinkPropertyHelperC :: Show a => PropertyOf a -> (a -> Bool) -> Property
shrinkPropertyHelperC prop p = shrinkPropertyHelperC' prop (property . p)
shrinkPropertyHelperC' :: Show a => PropertyOf a -> (a -> Property) -> Property
shrinkPropertyHelperC' prop p = monadicIO $ do
ce_ <- run $ CE.quickCheckWith (stdArgs {chatty = False}) prop
case ce_ of
Nothing -> return ()
Just ce -> liftProperty $
counterexample ("failed: " ++ show ce) $ p ce
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
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