You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

109 lines
3.9 KiB

module PropTest where
import Test.QuickCheck
import Test.QuickCheck.Modifiers (NonZero)
import Test.QuickCheck.Function
import Data.List (sort)
-- Note:
-- quickCheck takes a type of the Testable typeclass
-- Arbitrary a => a -> Bool is an instance of this, since
-- Bool is also Testable.
-- 1
half :: Fractional a => a -> a
half = (/2)
halfIdentity :: Fractional a => a -> a
halfIdentity = (*2) . half
prop_half :: (Eq a, Fractional a) => a -> Bool
prop_half = \x -> halfIdentity x == x
-- 2
listOrdered :: (Ord a) => [a] -> Bool
listOrdered xs =
snd $ foldr go (Nothing, True) xs
where go _ status@(_,False) = status
go y (Nothing, t) = (Just y, t)
go y (Just x, _) = (Just y, x >= y)
prop_sort :: Ord a => [a] -> Bool
prop_sort = listOrdered . sort
-- 3
plusAssociative :: (Num a, Eq a) => a -> a -> a -> Bool
plusAssociative x y z = x + (y + z) == (x + y) + z
plusCommutative :: (Num a, Eq a) => a -> a -> Bool
plusCommutative x y = x + y == y + x
-- 4
multAssociative :: (Num a, Eq a) => a -> a -> a -> Bool
multAssociative x y z = x * (y * z) == (x * y) * z
multCommutative :: (Num a, Eq a) => a -> a -> Bool
multCommutative x y = x * y == y * x
-- 5
prop_quotRem :: (Eq a, Integral a) => a -> a -> Bool
prop_quotRem _ 0 = True -- exclude 0 from the test
prop_quotRem x y = (quot x y)*y + (rem x y) == x
prop_divMod :: (Eq a, Integral a) => a -> a -> Bool
prop_divMod _ 0 = True -- exclude 0 from the test
prop_divMod x y = (div x y)*y + (mod x y) == x
-- other solution would be the create a generator for Int or Integers or ...
-- which excludes 0
-- OR use the modifiers from quickcheck
prop_quotRem' :: (Eq a, Integral a) => NonZero a -> NonZero a -> Bool
prop_quotRem' (NonZero x) (NonZero y) = (quot x y)*y + (rem x y) == x
prop_divMod' :: (Eq a, Integral a) => NonZero a -> NonZero a -> Bool
prop_divMod' (NonZero x) (NonZero y) = (div x y)*y + (mod x y) == x
-- 6 These will fail
prop_eAss :: (Eq a, Num a, Integral a) => a -> a -> a -> Bool
prop_eAss x y z = x ^ (y ^ z) == (x ^ y) ^ z
prop_eCom :: (Eq a, Num a, Integral a) => a -> a -> Bool
prop_eCom x y = x ^ y == y ^ x
-- 7
prop_reverse :: Eq a => [a] -> Bool
prop_reverse xs = (reverse . reverse) xs == id xs
-- 8
prop_apply :: Eq b => (Fun a b) -> a -> Bool
prop_apply (Fun _ f) a = (f $ a) == f a
prop_compose :: Eq c => (Fun b c) -> (Fun a b) -> a -> Bool
prop_compose (Fun _ f) (Fun _ g) a = (f . g) a == f (g a)
-- 9
prop_append :: Eq a => [a] -> [a] -> Bool
prop_append xs ys = foldr (:) xs ys == (++) xs ys
prop_concat :: Eq a => [[a]] -> Bool
prop_concat xs = foldr (++) [] xs == concat xs
-- 10
prop_length :: Int -> [a] -> Bool
prop_length n xs = length (take n xs) == n
-- 11
prop_readshow :: (Read a, Show a, Eq a) => a -> Bool
prop_readshow x = (read (show x)) == x
main :: IO ()
main = do
quickCheck (prop_half :: Double -> Bool) -- Float can also be checked
quickCheck (prop_sort :: [Int] -> Bool) -- Lots of other options available
quickCheck (plusAssociative :: Int -> Int -> Int -> Bool)
quickCheck (plusCommutative :: Integer -> Integer -> Bool)
quickCheck (multAssociative :: Int -> Int -> Int -> Bool)
quickCheck (multCommutative :: Integer -> Integer -> Bool)
quickCheck (prop_quotRem :: Integer -> Integer -> Bool)
quickCheck (prop_divMod :: Integer -> Integer -> Bool)
quickCheck (prop_quotRem' :: NonZero Integer -> NonZero Integer -> Bool)
quickCheck (prop_divMod' :: NonZero Integer -> NonZero Integer -> Bool)
quickCheck (prop_eAss :: Integer -> Integer -> Integer -> Bool) -- fails
quickCheck (prop_eCom :: Integer -> Integer -> Bool) -- fails
quickCheck (prop_reverse :: [Char] -> Bool)
quickCheck (prop_apply :: (Fun Integer Integer) -> Integer -> Bool)
quickCheck (prop_compose :: (Fun Int Int) -> (Fun Int Int) -> Int -> Bool)
quickCheck (prop_append :: [Char] -> [Char] -> Bool)
quickCheck (prop_concat :: [[Char]] -> Bool)
quickCheck (prop_length :: Int -> [String] -> Bool)
quickCheck (prop_readshow :: Int -> Bool)