skew-list-0.1: tests/Strict.hs
module Strict (tests) where
import Test.QuickCheck
(Arbitrary (..), Fun, Gen, Property, applyFun, chooseInt, elements,
label, oneof, property, sized, vector, (.&&.), (===))
import Test.QuickCheck.Poly (A, B)
import Test.Tasty (TestTree, testGroup)
import Test.Tasty.QuickCheck (testProperty)
import qualified Data.Foldable.WithIndex as WI
import qualified Data.Functor.WithIndex as WI
import qualified Data.List as L
import qualified Data.SkewList.Strict as S
tests :: TestTree
tests = testGroup "Strict"
[ testProperty "valid" valid_prop
, testProperty "fromList . toList" $ \xs ->
xs === S.fromList (S.toList (xs :: S.SkewList Int))
, testProperty "toList . fromList" $ \xs ->
xs === S.toList (S.fromList (xs :: [Int]))
, testProperty "uncons" $ \xs ->
L.uncons xs === fmap (fmap S.toList) (S.uncons (S.fromList (xs :: [Int])))
, testProperty "length" $ \xs ->
L.length xs === S.length (S.fromList (xs :: [A]))
, testProperty "null" $ \xs ->
L.null xs === S.null (S.fromList (xs :: [A]))
, testProperty "eq" eq_prop
, testProperty "compare" compare_prop
, testProperty "map" map_prop
, testProperty "imap" imap_prop
, testProperty "append" append_prop
, testProperty "append" append_prop_valid
, testProperty "foldr" foldr_prop
, testProperty "foldMap" foldMap_prop
, testProperty "ifoldr" ifoldr_prop
, testProperty "ifoldMap" ifoldMap_prop
, testProperty "model" model_prop
]
data SmallA = A0 | A1 | A2 deriving (Eq, Ord, Show)
instance Arbitrary SmallA where
arbitrary = elements [A0,A1,A2]
valid_prop :: S.SkewList A -> Property
valid_prop xs = property (S.valid xs)
eq_prop :: [SmallA] -> [SmallA] -> Property
eq_prop xs ys = label (show (xs == ys)) $
(xs == ys) === (S.fromList xs == S.fromList ys)
compare_prop :: [SmallA] -> [SmallA] -> [SmallA] -> Property
compare_prop xs ys zs = label (show (compare xs' ys', compare ys' zs')) $ trans
(compare xs' ys')
(compare ys' zs')
(compare xs' zs')
where
xs' = S.fromList xs
ys' = S.fromList ys
zs' = S.fromList zs
trans :: Ordering -> Ordering -> Ordering -> Bool
trans LT LT o = o == LT
trans LT EQ o = o == LT
trans LT GT _ = True
trans EQ LT o = o == LT
trans EQ EQ o = o == EQ
trans EQ GT o = o == GT
trans GT LT _ = True
trans GT EQ o = o == GT
trans GT GT o = o == GT
map_prop :: Fun A B -> [A] -> Property
map_prop f' xs = S.fromList (L.map f xs) === S.map f (S.fromList xs)
where
f = applyFun f'
imap_prop :: Fun (Int, A) B -> [A] -> Property
imap_prop f' xs = WI.imap f xs === S.toList (S.imap f (S.fromList xs))
where
f i x = applyFun f' (i, x)
append_prop :: [A] -> [A] -> Property
append_prop xs ys = S.fromList (xs ++ ys) === S.append (S.fromList xs) (S.fromList ys)
append_prop_valid :: [A] -> [A] -> Property
append_prop_valid xs ys = property (S.valid (S.append (S.fromList xs) (S.fromList ys)))
foldr_prop :: Fun (A, B) B -> B -> [A] -> Property
foldr_prop f' z xs = L.foldr f z xs === S.foldr f z (S.fromList xs) where
f a b = applyFun f' (a, b)
ifoldr_prop :: Fun (Int, A, B) B -> B -> [A] -> Property
ifoldr_prop f' z xs = WI.ifoldr f z xs === S.ifoldr f z (S.fromList xs) where
f i a b = applyFun f' (i, a, b)
foldMap_prop :: Fun A [B] -> [A] -> Property
foldMap_prop f' xs = foldMap f xs === S.foldMap f (S.fromList xs) where
f = applyFun f'
ifoldMap_prop :: Fun (Int, A) [B] -> [A] -> Property
ifoldMap_prop f' xs = WI.ifoldMap f xs === WI.ifoldMap f (S.fromList xs) where
f i a = applyFun f' (i, a)
-- | Model of construction operators.
data Model a
= Empty
| Singleton a
| FromList [a]
| Cons a (Model a)
| Uncons (Model a)
| Append (Model a) (Model a)
deriving Show
instance Arbitrary a => Arbitrary (Model a) where
arbitrary = sized model
model :: Arbitrary a => Int -> Gen (Model a)
model n
| n <= 1
= oneof [ pure Empty, Singleton <$> arbitrary ]
| otherwise
= oneof
[ Cons <$> arbitrary <*> model (n - 2)
, Uncons <$> model (n - 2)
, FromList <$> vector n
, do
k <- chooseInt (1, n - 1)
Append <$> model k <*> model (n - 1 - k)
]
modelList :: Model a -> [a]
modelList Empty = []
modelList (Singleton x) = [x]
modelList (FromList xs) = xs
modelList (Cons x xs) = x : modelList xs
modelList (Uncons xs) = maybe [] snd (L.uncons (modelList xs))
modelList (Append xs ys) = modelList xs ++ modelList ys
modelSkewList :: Model a -> S.SkewList a
modelSkewList Empty = S.empty
modelSkewList (Singleton x) = S.singleton x
modelSkewList (FromList xs) = S.fromList xs
modelSkewList (Cons x xs) = S.cons x (modelSkewList xs)
modelSkewList (Uncons xs) = maybe S.empty snd (S.uncons (modelSkewList xs))
modelSkewList (Append xs ys) = S.append (modelSkewList xs) (modelSkewList ys)
model_prop :: Model A -> Property
model_prop m = S.valid (modelSkewList m) .&&. S.fromList (modelList m) === modelSkewList m