bitwise-enum-1.0.0.2: tests/set-properties.hs
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE MonadComprehensions #-}
import Prelude
import Control.Applicative ((<|>))
import Data.Foldable (foldl', foldr')
import Data.List ((\\), nub, sort)
import Data.Bits
import Test.Framework
import Test.Framework.Providers.QuickCheck2
import Test.QuickCheck
import Test.QuickCheck.Function
import Unsafe.Coerce (unsafeCoerce)
import qualified Data.Enum.Set.Base as E
main :: IO ()
main = defaultMain
[ -- Construction
testProperty "singleton" prop_singleton
, testProperty "fromFoldable" prop_fromFoldable
-- Insertion/Deletion
, testProperty "insert/delete" prop_insertDelete
-- Query
, testProperty "member" prop_member
, testProperty "notMember" prop_notMember
, testProperty "size" prop_size
, testProperty "isSubsetOf" prop_isSubsetOf
-- Combine
, testProperty "unionInsert" prop_unionInsert
, testProperty "unionAssoc" prop_unionAssoc
, testProperty "unionComm" prop_unionComm
, testProperty "difference" prop_difference
, testProperty "intersection" prop_intersection
-- Filter
, testProperty "filter" prop_filter
, testProperty "partition" prop_partition
-- Map
, testProperty "map" prop_map
, testProperty "map2" prop_map2
-- Folds
, testProperty "foldl" prop_foldl
, testProperty "foldl'" prop_foldl'
, testProperty "foldr" prop_foldr
, testProperty "foldr'" prop_foldr'
, testProperty "foldl_origin" prop_foldl_origin
, testProperty "foldl'_origin" prop_foldl'_origin
, testProperty "foldr_origin" prop_foldr_origin
, testProperty "foldr'_origin" prop_foldr'_origin
-- Special folds
, testProperty "foldMap" prop_foldMap
, testProperty "traverse" prop_traverse
, testProperty "any" prop_any
, testProperty "all" prop_all
-- Min/Max
, testProperty "minimum" prop_minimum
, testProperty "maximum" prop_maximum
, testProperty "minView" prop_minView
, testProperty "maxView" prop_maxView
-- Conversion
, testProperty "toList" prop_toList
, testProperty "Read/Show" prop_readShow
]
wordSize :: Int
wordSize = finiteBitSize (0 :: Word) - 1
newtype Key = Key Int deriving (Eq, Ord, Show, Read, Real, Integral)
instance Enum Key where
toEnum x
| x < 0 || x > wordSize = error $ "Key.toEnum: bad argument " ++ show x
| otherwise = Key x
fromEnum (Key x) = x
instance Num Key where
(Key x) + (Key y) = Key . min wordSize $ x + y
(Key x) - (Key y) = Key . max 0 $ x - y
(Key x) * (Key y) = Key . min wordSize $ x + y
negate = id
abs = id
signum (Key 0) = 0
signum _ = 1
fromInteger = toEnum . max 0 . min wordSize . fromInteger
instance Bounded Key where
minBound = 0
maxBound = Key $ finiteBitSize (0 :: Word) - 1
instance Arbitrary Key where
arbitrary = arbitrarySizedBoundedIntegral
shrink = shrinkIntegral
instance Function Key where
function = functionIntegral
instance CoArbitrary Key where
coarbitrary = coarbitraryIntegral
type ES = E.EnumSet Word Key
fromBits :: w -> E.EnumSet w a
fromBits = unsafeCoerce
toBits :: E.EnumSet w a -> w
toBits = unsafeCoerce
instance Arbitrary w => Arbitrary (E.EnumSet w a) where
arbitrary = fmap fromBits arbitrary
shrink = fmap fromBits . shrink . toBits
-- * Construction
prop_singleton :: Key -> Bool
prop_singleton x = E.insert x (E.empty :: ES) == E.singleton x
prop_fromFoldable :: [Key] -> Property
prop_fromFoldable xs =
(E.fromFoldable xs :: ES) === foldr E.insert E.empty xs
-- * Insertion/Deletion
prop_insertDelete :: Key -> ES -> Property
prop_insertDelete k t = not (E.member k t) ==> E.delete k (E.insert k t) == t
-- * Query
prop_member :: [Key] -> Key -> Bool
prop_member xs n =
let m = E.fromFoldable xs :: ES
in all (\k -> k `E.member` m == (k `elem` xs)) (n : xs)
prop_notMember :: [Key] -> Key -> Bool
prop_notMember xs n =
let m = E.fromFoldable xs :: ES
in all (\k -> k `E.notMember` m == (k `notElem` xs)) (n : xs)
prop_size :: ES -> Bool
prop_size s = E.size s == length (E.toList s)
-- TODO isSubsetOf
prop_isSubsetOf :: ES -> ES -> Bool
prop_isSubsetOf x y = x `E.isSubsetOf` y == all (`elem` E.toList y) (E.toList x)
-- * Combine
prop_unionInsert :: Key -> ES -> Bool
prop_unionInsert x t = E.union t (E.singleton x) == E.insert x t
prop_unionAssoc :: ES -> ES -> ES -> Bool
prop_unionAssoc x y z = E.union x (E.union y z) == E.union (E.union x y) z
prop_unionComm :: ES -> ES -> Bool
prop_unionComm x y = E.union x y == E.union y x
prop_difference :: [Key] -> [Key] -> Bool
prop_difference xs ys =
(E.toList :: ES -> [Key])
(E.difference (E.fromFoldable xs) (E.fromFoldable ys))
== sort ((\\) (nub xs) (nub ys))
prop_intersection :: ES -> ES -> Bool
prop_intersection x y =
x `E.intersection` y == E.fromFoldable (filter (`elem` E.toList x) (E.toList y))
-- * Filter
prop_filter :: ES -> Bool
prop_filter s = E.partition odd s == (E.filter odd s, E.filter even s)
prop_partition :: ES -> Bool
prop_partition s = case E.partition odd s of
(s1,s2) -> all odd (E.toList s1) && all even (E.toList s2)
&& s == s1 `E.union` s2
-- * Map
prop_map :: ES -> Bool
prop_map s = E.map id s == s
prop_map2 :: Fun Key Key -> Fun Key Key -> ES -> Property
prop_map2 f g s =
E.map (apply f) (E.map (apply g) s) === E.map (apply f . apply g) s
-- * Folds
prop_foldl :: ES -> Bool
prop_foldl s = E.foldl (flip (:)) [] s == foldl (flip (:)) [] (E.toList s)
prop_foldl' :: ES -> Bool
prop_foldl' s = E.foldl' (flip (:)) [] s == foldl' (flip (:)) [] (E.toList s)
prop_foldr :: ES -> Bool
prop_foldr s = E.foldr (:) [] s == E.toList s
prop_foldr' :: ES -> Bool
prop_foldr' s = E.foldr' (:) [] s == E.toList s
prop_foldl_origin :: Fun Key Bool -> ES -> Bool
prop_foldl_origin = originHelper id E.foldl foldl
prop_foldl'_origin :: Fun Key Bool -> ES -> Bool
prop_foldl'_origin = originHelper id E.foldl' foldl'
prop_foldr_origin :: Fun Key Bool -> ES -> Bool
prop_foldr_origin = originHelper flip E.foldr foldr
prop_foldr'_origin :: Fun Key Bool -> ES -> Bool
prop_foldr'_origin = originHelper flip E.foldr' foldr'
-- * Special folds
prop_all :: Fun Key Bool -> ES -> Property
prop_all p s = E.all (apply p) s === all (apply p) (E.toList s)
prop_any :: Fun Key Bool -> ES -> Property
prop_any p s = E.any (apply p) s === any (apply p) (E.toList s)
prop_foldMap :: ES -> Bool
prop_foldMap s = E.foldMap return s == foldMap (: []) (E.toList s)
prop_traverse :: ES -> Bool
prop_traverse s = map E.toList (E.traverse return s) == traverse (: []) (E.toList s)
-- * Min/Max
prop_minimum :: ES -> Property
prop_minimum s = not (E.null s) ==> E.minimum s == minimum (E.toList s)
prop_maximum :: ES -> Property
prop_maximum s = not (E.null s) ==> E.maximum s == maximum (E.toList s)
prop_minView :: ES -> Bool
prop_minView s = case E.minView s of
Nothing -> E.null s
Just (m,s') -> m == minimum (E.toList s)
&& s == E.insert m s' && m `E.notMember` s'
prop_maxView :: ES -> Bool
prop_maxView s = case E.maxView s of
Nothing -> E.null s
Just (m,s') -> m == maximum (E.toList s)
&& s == E.insert m s' && m `E.notMember` s'
-- * Conversion
prop_toList :: [Key] -> Bool
prop_toList xs = sort (nub xs) == E.toList (E.fromFoldable xs :: ES)
prop_readShow :: ES -> Bool
prop_readShow s = s == read (show s)
-- * Utility functions
originHelper :: ((Maybe Key -> Key -> Maybe Key) -> f)
-> (f -> Maybe Key -> ES -> Maybe Key)
-> (f -> Maybe Key -> [Key] -> Maybe Key)
-> Fun Key Bool -> ES -> Bool
originHelper reorder fSet fList p s =
fSet f Nothing s == fList f Nothing (E.toList s)
where
f = reorder \acc x -> acc <|> [x | apply p x]