containers-0.5.6.1: tests/seq-properties.hs
import Data.Sequence -- needs to be compiled with -DTESTING for use here
import Control.Applicative (Applicative(..))
import Control.Arrow ((***))
import Data.Array (listArray)
import Data.Foldable (Foldable(foldl, foldl1, foldr, foldr1, foldMap), toList, all, sum)
import Data.Functor ((<$>), (<$))
import Data.Maybe
import Data.Monoid (Monoid(..))
import Data.Traversable (Traversable(traverse), sequenceA)
import Prelude hiding (
null, length, take, drop, splitAt,
foldl, foldl1, foldr, foldr1, scanl, scanl1, scanr, scanr1,
filter, reverse, replicate, zip, zipWith, zip3, zipWith3,
all, sum)
import qualified Prelude
import qualified Data.List
import Test.QuickCheck hiding ((><))
import Test.QuickCheck.Poly
import Test.Framework
import Test.Framework.Providers.QuickCheck2
main :: IO ()
main = defaultMain
[ testProperty "fmap" prop_fmap
, testProperty "(<$)" prop_constmap
, testProperty "foldr" prop_foldr
, testProperty "foldr1" prop_foldr1
, testProperty "foldl" prop_foldl
, testProperty "foldl1" prop_foldl1
, testProperty "(==)" prop_equals
, testProperty "compare" prop_compare
, testProperty "mappend" prop_mappend
, testProperty "singleton" prop_singleton
, testProperty "(<|)" prop_cons
, testProperty "(|>)" prop_snoc
, testProperty "(><)" prop_append
, testProperty "fromList" prop_fromList
, testProperty "fromFunction" prop_fromFunction
, testProperty "fromArray" prop_fromArray
, testProperty "replicate" prop_replicate
, testProperty "replicateA" prop_replicateA
, testProperty "replicateM" prop_replicateM
, testProperty "iterateN" prop_iterateN
, testProperty "unfoldr" prop_unfoldr
, testProperty "unfoldl" prop_unfoldl
, testProperty "null" prop_null
, testProperty "length" prop_length
, testProperty "viewl" prop_viewl
, testProperty "viewr" prop_viewr
, testProperty "scanl" prop_scanl
, testProperty "scanl1" prop_scanl1
, testProperty "scanr" prop_scanr
, testProperty "scanr1" prop_scanr1
, testProperty "tails" prop_tails
, testProperty "inits" prop_inits
, testProperty "takeWhileL" prop_takeWhileL
, testProperty "takeWhileR" prop_takeWhileR
, testProperty "dropWhileL" prop_dropWhileL
, testProperty "dropWhileR" prop_dropWhileR
, testProperty "spanl" prop_spanl
, testProperty "spanr" prop_spanr
, testProperty "breakl" prop_breakl
, testProperty "breakr" prop_breakr
, testProperty "partition" prop_partition
, testProperty "filter" prop_filter
, testProperty "sort" prop_sort
, testProperty "sortBy" prop_sortBy
, testProperty "unstableSort" prop_unstableSort
, testProperty "unstableSortBy" prop_unstableSortBy
, testProperty "index" prop_index
, testProperty "adjust" prop_adjust
, testProperty "update" prop_update
, testProperty "take" prop_take
, testProperty "drop" prop_drop
, testProperty "splitAt" prop_splitAt
, testProperty "elemIndexL" prop_elemIndexL
, testProperty "elemIndicesL" prop_elemIndicesL
, testProperty "elemIndexR" prop_elemIndexR
, testProperty "elemIndicesR" prop_elemIndicesR
, testProperty "findIndexL" prop_findIndexL
, testProperty "findIndicesL" prop_findIndicesL
, testProperty "findIndexR" prop_findIndexR
, testProperty "findIndicesR" prop_findIndicesR
, testProperty "foldlWithIndex" prop_foldlWithIndex
, testProperty "foldrWithIndex" prop_foldrWithIndex
, testProperty "mapWithIndex" prop_mapWithIndex
, testProperty "reverse" prop_reverse
, testProperty "zip" prop_zip
, testProperty "zipWith" prop_zipWith
, testProperty "zip3" prop_zip3
, testProperty "zipWith3" prop_zipWith3
, testProperty "zip4" prop_zip4
, testProperty "zipWith4" prop_zipWith4
]
------------------------------------------------------------------------
-- Arbitrary
------------------------------------------------------------------------
instance Arbitrary a => Arbitrary (Seq a) where
arbitrary = Seq <$> arbitrary
shrink (Seq x) = map Seq (shrink x)
instance Arbitrary a => Arbitrary (Elem a) where
arbitrary = Elem <$> arbitrary
instance (Arbitrary a, Sized a) => Arbitrary (FingerTree a) where
arbitrary = sized arb
where
arb :: (Arbitrary a, Sized a) => Int -> Gen (FingerTree a)
arb 0 = return Empty
arb 1 = Single <$> arbitrary
arb n = deep <$> arbitrary <*> arb (n `div` 2) <*> arbitrary
shrink (Deep _ (One a) Empty (One b)) = [Single a, Single b]
shrink (Deep _ pr m sf) =
[deep pr' m sf | pr' <- shrink pr] ++
[deep pr m' sf | m' <- shrink m] ++
[deep pr m sf' | sf' <- shrink sf]
shrink (Single x) = map Single (shrink x)
shrink Empty = []
instance (Arbitrary a, Sized a) => Arbitrary (Node a) where
arbitrary = oneof [
node2 <$> arbitrary <*> arbitrary,
node3 <$> arbitrary <*> arbitrary <*> arbitrary]
shrink (Node2 _ a b) =
[node2 a' b | a' <- shrink a] ++
[node2 a b' | b' <- shrink b]
shrink (Node3 _ a b c) =
[node2 a b, node2 a c, node2 b c] ++
[node3 a' b c | a' <- shrink a] ++
[node3 a b' c | b' <- shrink b] ++
[node3 a b c' | c' <- shrink c]
instance Arbitrary a => Arbitrary (Digit a) where
arbitrary = oneof [
One <$> arbitrary,
Two <$> arbitrary <*> arbitrary,
Three <$> arbitrary <*> arbitrary <*> arbitrary,
Four <$> arbitrary <*> arbitrary <*> arbitrary <*> arbitrary]
shrink (One a) = map One (shrink a)
shrink (Two a b) = [One a, One b]
shrink (Three a b c) = [Two a b, Two a c, Two b c]
shrink (Four a b c d) = [Three a b c, Three a b d, Three a c d, Three b c d]
------------------------------------------------------------------------
-- Valid trees
------------------------------------------------------------------------
class Valid a where
valid :: a -> Bool
instance Valid (Elem a) where
valid _ = True
instance Valid (Seq a) where
valid (Seq xs) = valid xs
instance (Sized a, Valid a) => Valid (FingerTree a) where
valid Empty = True
valid (Single x) = valid x
valid (Deep s pr m sf) =
s == size pr + size m + size sf && valid pr && valid m && valid sf
instance (Sized a, Valid a) => Valid (Node a) where
valid node = size node == sum (fmap size node) && all valid node
instance Valid a => Valid (Digit a) where
valid = all valid
{--------------------------------------------------------------------
The general plan is to compare each function with a list equivalent.
Each operation should produce a valid tree representing the same
sequence as produced by its list counterpart on corresponding inputs.
(The list versions are often lazier, but these properties ignore
strictness.)
--------------------------------------------------------------------}
-- utilities for partial conversions
infix 4 ~=
(~=) :: Eq a => Maybe a -> a -> Bool
(~=) = maybe (const False) (==)
-- Partial conversion of an output sequence to a list.
toList' :: Seq a -> Maybe [a]
toList' xs
| valid xs = Just (toList xs)
| otherwise = Nothing
toListList' :: Seq (Seq a) -> Maybe [[a]]
toListList' xss = toList' xss >>= mapM toList'
toListPair' :: (Seq a, Seq b) -> Maybe ([a], [b])
toListPair' (xs, ys) = (,) <$> toList' xs <*> toList' ys
-- instances
prop_fmap :: Seq Int -> Bool
prop_fmap xs =
toList' (fmap f xs) ~= map f (toList xs)
where f = (+100)
prop_constmap :: A -> Seq A -> Bool
prop_constmap x xs =
toList' (x <$ xs) ~= map (const x) (toList xs)
prop_foldr :: Seq A -> Bool
prop_foldr xs =
foldr f z xs == Prelude.foldr f z (toList xs)
where
f = (:)
z = []
prop_foldr1 :: Seq Int -> Property
prop_foldr1 xs =
not (null xs) ==> foldr1 f xs == Data.List.foldr1 f (toList xs)
where f = (-)
prop_foldl :: Seq A -> Bool
prop_foldl xs =
foldl f z xs == Prelude.foldl f z (toList xs)
where
f = flip (:)
z = []
prop_foldl1 :: Seq Int -> Property
prop_foldl1 xs =
not (null xs) ==> foldl1 f xs == Data.List.foldl1 f (toList xs)
where f = (-)
prop_equals :: Seq OrdA -> Seq OrdA -> Bool
prop_equals xs ys =
(xs == ys) == (toList xs == toList ys)
prop_compare :: Seq OrdA -> Seq OrdA -> Bool
prop_compare xs ys =
compare xs ys == compare (toList xs) (toList ys)
prop_mappend :: Seq A -> Seq A -> Bool
prop_mappend xs ys =
toList' (mappend xs ys) ~= toList xs ++ toList ys
-- * Construction
{-
toList' empty ~= []
-}
prop_singleton :: A -> Bool
prop_singleton x =
toList' (singleton x) ~= [x]
prop_cons :: A -> Seq A -> Bool
prop_cons x xs =
toList' (x <| xs) ~= x : toList xs
prop_snoc :: Seq A -> A -> Bool
prop_snoc xs x =
toList' (xs |> x) ~= toList xs ++ [x]
prop_append :: Seq A -> Seq A -> Bool
prop_append xs ys =
toList' (xs >< ys) ~= toList xs ++ toList ys
prop_fromList :: [A] -> Bool
prop_fromList xs =
toList' (fromList xs) ~= xs
prop_fromFunction :: [A] -> Bool
prop_fromFunction xs =
toList' (fromFunction (Prelude.length xs) (xs!!)) ~= xs
prop_fromArray :: [A] -> Bool
prop_fromArray xs =
toList' (fromArray (listArray (42, 42+Prelude.length xs-1) xs)) ~= xs
-- ** Repetition
prop_replicate :: NonNegative Int -> A -> Bool
prop_replicate (NonNegative m) x =
toList' (replicate n x) ~= Prelude.replicate n x
where n = m `mod` 10000
prop_replicateA :: NonNegative Int -> Bool
prop_replicateA (NonNegative m) =
traverse toList' (replicateA n a) ~= sequenceA (Prelude.replicate n a)
where
n = m `mod` 10000
a = Action 1 0 :: M Int
prop_replicateM :: NonNegative Int -> Bool
prop_replicateM (NonNegative m) =
traverse toList' (replicateM n a) ~= sequence (Prelude.replicate n a)
where
n = m `mod` 10000
a = Action 1 0 :: M Int
-- ** Iterative construction
prop_iterateN :: NonNegative Int -> Int -> Bool
prop_iterateN (NonNegative m) x =
toList' (iterateN n f x) ~= Prelude.take n (Prelude.iterate f x)
where
n = m `mod` 10000
f = (+1)
prop_unfoldr :: [A] -> Bool
prop_unfoldr z =
toList' (unfoldr f z) ~= Data.List.unfoldr f z
where
f [] = Nothing
f (x:xs) = Just (x, xs)
prop_unfoldl :: [A] -> Bool
prop_unfoldl z =
toList' (unfoldl f z) ~= Data.List.reverse (Data.List.unfoldr (fmap swap . f) z)
where
f [] = Nothing
f (x:xs) = Just (xs, x)
swap (x,y) = (y,x)
-- * Deconstruction
-- ** Queries
prop_null :: Seq A -> Bool
prop_null xs =
null xs == Prelude.null (toList xs)
prop_length :: Seq A -> Bool
prop_length xs =
length xs == Prelude.length (toList xs)
-- ** Views
prop_viewl :: Seq A -> Bool
prop_viewl xs =
case viewl xs of
EmptyL -> Prelude.null (toList xs)
x :< xs' -> valid xs' && toList xs == x : toList xs'
prop_viewr :: Seq A -> Bool
prop_viewr xs =
case viewr xs of
EmptyR -> Prelude.null (toList xs)
xs' :> x -> valid xs' && toList xs == toList xs' ++ [x]
-- * Scans
prop_scanl :: [A] -> Seq A -> Bool
prop_scanl z xs =
toList' (scanl f z xs) ~= Data.List.scanl f z (toList xs)
where f = flip (:)
prop_scanl1 :: Seq Int -> Property
prop_scanl1 xs =
not (null xs) ==> toList' (scanl1 f xs) ~= Data.List.scanl1 f (toList xs)
where f = (-)
prop_scanr :: [A] -> Seq A -> Bool
prop_scanr z xs =
toList' (scanr f z xs) ~= Data.List.scanr f z (toList xs)
where f = (:)
prop_scanr1 :: Seq Int -> Property
prop_scanr1 xs =
not (null xs) ==> toList' (scanr1 f xs) ~= Data.List.scanr1 f (toList xs)
where f = (-)
-- * Sublists
prop_tails :: Seq A -> Bool
prop_tails xs =
toListList' (tails xs) ~= Data.List.tails (toList xs)
prop_inits :: Seq A -> Bool
prop_inits xs =
toListList' (inits xs) ~= Data.List.inits (toList xs)
-- ** Sequential searches
-- We use predicates with varying density.
prop_takeWhileL :: Positive Int -> Seq Int -> Bool
prop_takeWhileL (Positive n) xs =
toList' (takeWhileL p xs) ~= Prelude.takeWhile p (toList xs)
where p x = x `mod` n == 0
prop_takeWhileR :: Positive Int -> Seq Int -> Bool
prop_takeWhileR (Positive n) xs =
toList' (takeWhileR p xs) ~= Prelude.reverse (Prelude.takeWhile p (Prelude.reverse (toList xs)))
where p x = x `mod` n == 0
prop_dropWhileL :: Positive Int -> Seq Int -> Bool
prop_dropWhileL (Positive n) xs =
toList' (dropWhileL p xs) ~= Prelude.dropWhile p (toList xs)
where p x = x `mod` n == 0
prop_dropWhileR :: Positive Int -> Seq Int -> Bool
prop_dropWhileR (Positive n) xs =
toList' (dropWhileR p xs) ~= Prelude.reverse (Prelude.dropWhile p (Prelude.reverse (toList xs)))
where p x = x `mod` n == 0
prop_spanl :: Positive Int -> Seq Int -> Bool
prop_spanl (Positive n) xs =
toListPair' (spanl p xs) ~= Data.List.span p (toList xs)
where p x = x `mod` n == 0
prop_spanr :: Positive Int -> Seq Int -> Bool
prop_spanr (Positive n) xs =
toListPair' (spanr p xs) ~= (Prelude.reverse *** Prelude.reverse) (Data.List.span p (Prelude.reverse (toList xs)))
where p x = x `mod` n == 0
prop_breakl :: Positive Int -> Seq Int -> Bool
prop_breakl (Positive n) xs =
toListPair' (breakl p xs) ~= Data.List.break p (toList xs)
where p x = x `mod` n == 0
prop_breakr :: Positive Int -> Seq Int -> Bool
prop_breakr (Positive n) xs =
toListPair' (breakr p xs) ~= (Prelude.reverse *** Prelude.reverse) (Data.List.break p (Prelude.reverse (toList xs)))
where p x = x `mod` n == 0
prop_partition :: Positive Int -> Seq Int -> Bool
prop_partition (Positive n) xs =
toListPair' (partition p xs) ~= Data.List.partition p (toList xs)
where p x = x `mod` n == 0
prop_filter :: Positive Int -> Seq Int -> Bool
prop_filter (Positive n) xs =
toList' (filter p xs) ~= Prelude.filter p (toList xs)
where p x = x `mod` n == 0
-- * Sorting
prop_sort :: Seq OrdA -> Bool
prop_sort xs =
toList' (sort xs) ~= Data.List.sort (toList xs)
prop_sortBy :: Seq (OrdA, B) -> Bool
prop_sortBy xs =
toList' (sortBy f xs) ~= Data.List.sortBy f (toList xs)
where f (x1, _) (x2, _) = compare x1 x2
prop_unstableSort :: Seq OrdA -> Bool
prop_unstableSort xs =
toList' (unstableSort xs) ~= Data.List.sort (toList xs)
prop_unstableSortBy :: Seq OrdA -> Bool
prop_unstableSortBy xs =
toList' (unstableSortBy compare xs) ~= Data.List.sort (toList xs)
-- * Indexing
prop_index :: Seq A -> Property
prop_index xs =
not (null xs) ==> forAll (choose (0, length xs-1)) $ \ i ->
index xs i == toList xs !! i
prop_adjust :: Int -> Int -> Seq Int -> Bool
prop_adjust n i xs =
toList' (adjust f i xs) ~= adjustList f i (toList xs)
where f = (+n)
prop_update :: Int -> A -> Seq A -> Bool
prop_update i x xs =
toList' (update i x xs) ~= adjustList (const x) i (toList xs)
prop_take :: Int -> Seq A -> Bool
prop_take n xs =
toList' (take n xs) ~= Prelude.take n (toList xs)
prop_drop :: Int -> Seq A -> Bool
prop_drop n xs =
toList' (drop n xs) ~= Prelude.drop n (toList xs)
prop_splitAt :: Int -> Seq A -> Bool
prop_splitAt n xs =
toListPair' (splitAt n xs) ~= Prelude.splitAt n (toList xs)
adjustList :: (a -> a) -> Int -> [a] -> [a]
adjustList f i xs =
[if j == i then f x else x | (j, x) <- Prelude.zip [0..] xs]
-- ** Indexing with predicates
-- The elem* tests have poor coverage, but for find* we use predicates
-- of varying density.
prop_elemIndexL :: A -> Seq A -> Bool
prop_elemIndexL x xs =
elemIndexL x xs == Data.List.elemIndex x (toList xs)
prop_elemIndicesL :: A -> Seq A -> Bool
prop_elemIndicesL x xs =
elemIndicesL x xs == Data.List.elemIndices x (toList xs)
prop_elemIndexR :: A -> Seq A -> Bool
prop_elemIndexR x xs =
elemIndexR x xs == listToMaybe (Prelude.reverse (Data.List.elemIndices x (toList xs)))
prop_elemIndicesR :: A -> Seq A -> Bool
prop_elemIndicesR x xs =
elemIndicesR x xs == Prelude.reverse (Data.List.elemIndices x (toList xs))
prop_findIndexL :: Positive Int -> Seq Int -> Bool
prop_findIndexL (Positive n) xs =
findIndexL p xs == Data.List.findIndex p (toList xs)
where p x = x `mod` n == 0
prop_findIndicesL :: Positive Int -> Seq Int -> Bool
prop_findIndicesL (Positive n) xs =
findIndicesL p xs == Data.List.findIndices p (toList xs)
where p x = x `mod` n == 0
prop_findIndexR :: Positive Int -> Seq Int -> Bool
prop_findIndexR (Positive n) xs =
findIndexR p xs == listToMaybe (Prelude.reverse (Data.List.findIndices p (toList xs)))
where p x = x `mod` n == 0
prop_findIndicesR :: Positive Int -> Seq Int -> Bool
prop_findIndicesR (Positive n) xs =
findIndicesR p xs == Prelude.reverse (Data.List.findIndices p (toList xs))
where p x = x `mod` n == 0
-- * Folds
prop_foldlWithIndex :: [(Int, A)] -> Seq A -> Bool
prop_foldlWithIndex z xs =
foldlWithIndex f z xs == Data.List.foldl (uncurry . f) z (Data.List.zip [0..] (toList xs))
where f ys n y = (n,y):ys
prop_foldrWithIndex :: [(Int, A)] -> Seq A -> Bool
prop_foldrWithIndex z xs =
foldrWithIndex f z xs == Data.List.foldr (uncurry f) z (Data.List.zip [0..] (toList xs))
where f n y ys = (n,y):ys
-- * Transformations
prop_mapWithIndex :: Seq A -> Bool
prop_mapWithIndex xs =
toList' (mapWithIndex f xs) ~= map (uncurry f) (Data.List.zip [0..] (toList xs))
where f = (,)
prop_reverse :: Seq A -> Bool
prop_reverse xs =
toList' (reverse xs) ~= Prelude.reverse (toList xs)
-- ** Zips
prop_zip :: Seq A -> Seq B -> Bool
prop_zip xs ys =
toList' (zip xs ys) ~= Prelude.zip (toList xs) (toList ys)
prop_zipWith :: Seq A -> Seq B -> Bool
prop_zipWith xs ys =
toList' (zipWith f xs ys) ~= Prelude.zipWith f (toList xs) (toList ys)
where f = (,)
prop_zip3 :: Seq A -> Seq B -> Seq C -> Bool
prop_zip3 xs ys zs =
toList' (zip3 xs ys zs) ~= Prelude.zip3 (toList xs) (toList ys) (toList zs)
prop_zipWith3 :: Seq A -> Seq B -> Seq C -> Bool
prop_zipWith3 xs ys zs =
toList' (zipWith3 f xs ys zs) ~= Prelude.zipWith3 f (toList xs) (toList ys) (toList zs)
where f = (,,)
prop_zip4 :: Seq A -> Seq B -> Seq C -> Seq Int -> Bool
prop_zip4 xs ys zs ts =
toList' (zip4 xs ys zs ts) ~= Data.List.zip4 (toList xs) (toList ys) (toList zs) (toList ts)
prop_zipWith4 :: Seq A -> Seq B -> Seq C -> Seq Int -> Bool
prop_zipWith4 xs ys zs ts =
toList' (zipWith4 f xs ys zs ts) ~= Data.List.zipWith4 f (toList xs) (toList ys) (toList zs) (toList ts)
where f = (,,,)
-- Simple test monad
data M a = Action Int a
deriving (Eq, Show)
instance Functor M where
fmap f (Action n x) = Action n (f x)
instance Applicative M where
pure x = Action 0 x
Action m f <*> Action n x = Action (m+n) (f x)
instance Monad M where
return x = Action 0 x
Action m x >>= f = let Action n y = f x in Action (m+n) y
instance Foldable M where
foldMap f (Action _ x) = f x
instance Traversable M where
traverse f (Action n x) = Action n <$> f x