|
Packit |
1d8052 |
{-# LANGUAGE TemplateHaskell, GeneralizedNewtypeDeriving, Rank2Types, NoMonomorphismRestriction #-}
|
|
Packit |
1d8052 |
import Test.QuickCheck
|
|
Packit |
1d8052 |
import Test.QuickCheck.Gen.Unsafe
|
|
Packit |
1d8052 |
import Data.List
|
|
Packit |
1d8052 |
import Data.Int
|
|
Packit |
1d8052 |
import Data.Word
|
|
Packit |
1d8052 |
import Data.Version (showVersion, parseVersion)
|
|
Packit |
1d8052 |
import Text.ParserCombinators.ReadP (readP_to_S)
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
newtype Path a = Path [a] deriving (Show, Functor)
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
instance Arbitrary a => Arbitrary (Path a) where
|
|
Packit |
1d8052 |
arbitrary = do
|
|
Packit |
1d8052 |
x <- arbitrary
|
|
Packit |
1d8052 |
fmap Path (pathFrom x)
|
|
Packit |
1d8052 |
where
|
|
Packit |
1d8052 |
pathFrom x = sized $ \n ->
|
|
Packit |
1d8052 |
fmap (x:) $
|
|
Packit |
1d8052 |
oneof $
|
|
Packit |
1d8052 |
[return []] ++
|
|
Packit |
1d8052 |
[resize (n-1) (pathFrom y) | n > 0, y <- shrink x]
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
shrink (Path xs) = map Path [ ys | ys <- inits xs, length ys > 0 && length ys < length xs ]
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
path :: (a -> Bool) -> Path a -> Bool
|
|
Packit |
1d8052 |
path p (Path xs) = all p xs
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
somePath :: (a -> Bool) -> Path a -> Property
|
|
Packit |
1d8052 |
somePath p = expectFailure . path (not . p)
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
newtype Extremal a = Extremal { getExtremal :: a } deriving (Show, Eq, Ord, Num, Enum, Real, Integral)
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
instance (Arbitrary a, Bounded a) => Arbitrary (Extremal a) where
|
|
Packit |
1d8052 |
arbitrary =
|
|
Packit |
1d8052 |
fmap Extremal $
|
|
Packit |
1d8052 |
frequency
|
|
Packit |
1d8052 |
[(1, return minBound),
|
|
Packit |
1d8052 |
(1, return maxBound),
|
|
Packit |
1d8052 |
(8, arbitrary)]
|
|
Packit |
1d8052 |
shrink (Extremal x) = map Extremal (shrink x)
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
smallProp :: Integral a => Path a -> Bool
|
|
Packit |
1d8052 |
smallProp = path (\x -> (x >= -100 || -100 `asTypeOf` x >= 0) && x <= 100)
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
largeProp :: Integral a => Path a -> Property
|
|
Packit |
1d8052 |
largeProp = somePath (\x -> x < -1000000 || x > 1000000)
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
prop_int :: Path Int -> Bool
|
|
Packit |
1d8052 |
prop_int = smallProp
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
prop_int32 :: Path Int32 -> Property
|
|
Packit |
1d8052 |
prop_int32 = largeProp
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
prop_word :: Path Word -> Property
|
|
Packit |
1d8052 |
prop_word = largeProp
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
prop_word32 :: Path Word32 -> Property
|
|
Packit |
1d8052 |
prop_word32 = largeProp
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
prop_integer :: Path Integer -> Bool
|
|
Packit |
1d8052 |
prop_integer = smallProp
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
prop_small :: Path (Small Int) -> Bool
|
|
Packit |
1d8052 |
prop_small = smallProp
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
prop_large :: Path (Large Int) -> Property
|
|
Packit |
1d8052 |
prop_large = largeProp
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
prop_smallWord :: Path (Small Word) -> Bool
|
|
Packit |
1d8052 |
prop_smallWord = smallProp
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
prop_largeWord :: Path (Large Word) -> Property
|
|
Packit |
1d8052 |
prop_largeWord = largeProp
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
data Choice a b = Choice a b deriving Show
|
|
Packit |
1d8052 |
instance (Arbitrary a, Arbitrary b) => Arbitrary (Choice a b) where
|
|
Packit |
1d8052 |
arbitrary = do
|
|
Packit |
1d8052 |
Capture eval <- capture
|
|
Packit |
1d8052 |
return (Choice (eval arbitrary) (eval arbitrary))
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
idemProp :: (Eq a, Arbitrary a, Arbitrary b) => (b -> a) -> Choice a b -> Bool
|
|
Packit |
1d8052 |
idemProp f (Choice x y) = x == f y
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
prop_fixed_length :: Arbitrary a => Path (Fixed a) -> Bool
|
|
Packit |
1d8052 |
prop_fixed_length (Path xs) = length xs == 1
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
prop_fixed_idem = idemProp getFixed
|
|
Packit |
1d8052 |
prop_blind_idem = idemProp getBlind
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
prop_ordered_list = path (\(Ordered xs) -> sort xs == xs)
|
|
Packit |
1d8052 |
prop_nonempty_list = path (\(NonEmpty xs) -> not (null xs))
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
pathInt, somePathInt ::
|
|
Packit |
1d8052 |
(Arbitrary (f (Extremal Int)), Show (f (Extremal Int)),
|
|
Packit |
1d8052 |
Arbitrary (f Integer), Show (f Integer),
|
|
Packit |
1d8052 |
Arbitrary (f (Extremal Int8)), Show (f (Extremal Int8)),
|
|
Packit |
1d8052 |
Arbitrary (f (Extremal Int16)), Show (f (Extremal Int16)),
|
|
Packit |
1d8052 |
Arbitrary (f (Extremal Int32)), Show (f (Extremal Int32)),
|
|
Packit |
1d8052 |
Arbitrary (f (Extremal Int64)), Show (f (Extremal Int64)),
|
|
Packit |
1d8052 |
Arbitrary (f (Extremal Word)), Show (f (Extremal Word)),
|
|
Packit |
1d8052 |
Arbitrary (f (Extremal Word8)), Show (f (Extremal Word8)),
|
|
Packit |
1d8052 |
Arbitrary (f (Extremal Word16)), Show (f (Extremal Word16)),
|
|
Packit |
1d8052 |
Arbitrary (f (Extremal Word32)), Show (f (Extremal Word32)),
|
|
Packit |
1d8052 |
Arbitrary (f (Extremal Word64)), Show (f (Extremal Word64))) =>
|
|
Packit |
1d8052 |
(forall a. f a -> a) -> (forall a. Integral a => a -> Bool) -> Property
|
|
Packit |
1d8052 |
pathInt f p =
|
|
Packit |
1d8052 |
conjoin
|
|
Packit |
1d8052 |
[counterexample "Int" (path ((p :: Int -> Bool) . getExtremal . f)),
|
|
Packit |
1d8052 |
counterexample "Integer" (path ((p :: Integer -> Bool) . f)),
|
|
Packit |
1d8052 |
counterexample "Int8" (path ((p :: Int8 -> Bool) . getExtremal . f)),
|
|
Packit |
1d8052 |
counterexample "Int16" (path ((p :: Int16 -> Bool) . getExtremal . f)),
|
|
Packit |
1d8052 |
counterexample "Int32" (path ((p :: Int32 -> Bool) . getExtremal . f)),
|
|
Packit |
1d8052 |
counterexample "Int64" (path ((p :: Int64 -> Bool) . getExtremal . f)),
|
|
Packit |
1d8052 |
counterexample "Word" (path ((p :: Word -> Bool) . getExtremal . f)),
|
|
Packit |
1d8052 |
counterexample "Word8" (path ((p :: Word8 -> Bool) . getExtremal . f)),
|
|
Packit |
1d8052 |
counterexample "Word16" (path ((p :: Word16 -> Bool) . getExtremal . f)),
|
|
Packit |
1d8052 |
counterexample "Word32" (path ((p :: Word32 -> Bool) . getExtremal . f)),
|
|
Packit |
1d8052 |
counterexample "Word64" (path ((p :: Word64 -> Bool) . getExtremal . f))]
|
|
Packit |
1d8052 |
somePathInt f p = expectFailure (pathInt f (not . p))
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
prop_positive = pathInt getPositive (> 0)
|
|
Packit |
1d8052 |
prop_positive_bound = somePathInt getPositive (== 1)
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
prop_nonzero = pathInt getNonZero (/= 0)
|
|
Packit |
1d8052 |
prop_nonzero_bound_1 = somePathInt getNonZero (== 1)
|
|
Packit |
1d8052 |
prop_nonzero_bound_2 = somePathInt getNonZero (== -1)
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
prop_nonnegative = pathInt getNonNegative (>= 0)
|
|
Packit |
1d8052 |
prop_nonnegative_bound = somePathInt getNonNegative (== 0)
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
reachesBound :: (Bounded a, Integral a, Arbitrary a) =>
|
|
Packit |
1d8052 |
a -> Property
|
|
Packit |
1d8052 |
reachesBound x = expectFailure (x < 3 * (maxBound `div` 4))
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
prop_reachesBound_Int8 = reachesBound :: Int8 -> Property
|
|
Packit |
1d8052 |
prop_reachesBound_Int16 = reachesBound :: Int16 -> Property
|
|
Packit |
1d8052 |
prop_reachesBound_Int32 = reachesBound :: Int32 -> Property
|
|
Packit |
1d8052 |
prop_reachesBound_Int64 = reachesBound :: Int64 -> Property
|
|
Packit |
1d8052 |
prop_reachesBound_Word = reachesBound :: Word -> Property
|
|
Packit |
1d8052 |
prop_reachesBound_Word8 = reachesBound :: Word8 -> Property
|
|
Packit |
1d8052 |
prop_reachesBound_Word16 = reachesBound :: Word16 -> Property
|
|
Packit |
1d8052 |
prop_reachesBound_Word32 = reachesBound :: Word32 -> Property
|
|
Packit |
1d8052 |
prop_reachesBound_Word64 = reachesBound :: Word64 -> Property
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
-- Bad shrink: infinite list
|
|
Packit |
1d8052 |
--
|
|
Packit |
1d8052 |
-- remove unexpectedFailure in prop_B1, shrinking should not loop forever.
|
|
Packit |
1d8052 |
data B1 = B1 Int deriving (Eq, Show)
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
instance Arbitrary B1 where
|
|
Packit |
1d8052 |
arbitrary = fmap B1 arbitrary
|
|
Packit |
1d8052 |
shrink x = x : shrink x
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
prop_B1 :: B1 -> Property
|
|
Packit |
1d8052 |
prop_B1 (B1 n) = expectFailure $ n === n + 1
|
|
Packit |
1d8052 |
|
|
Packit |
1d8052 |
return []
|
|
Packit |
1d8052 |
main = $forAllProperties (quickCheckWithResult stdArgs { maxShrinks = 10000 }) >>= print
|