hw-fingertree-0.1.2.0: tests/HaskellWorks/Data/FingerTreeSpec.hs
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
module HaskellWorks.Data.FingerTreeSpec (spec) where
import Control.Applicative (Applicative (..))
import Control.Monad (ap)
import Data.Foldable (Foldable (foldMap, foldl, foldr), all, toList)
import Data.Functor ((<$>))
import Data.List (inits)
import Data.Traversable (traverse)
import HaskellWorks.Data.FingerTree
import HaskellWorks.Hspec.Hedgehog
import Hedgehog hiding (evalM)
import Prelude hiding (null, reverse)
import Test.Hspec
import qualified HaskellWorks.Data.FingerTree.Gen as G
import qualified Hedgehog.Gen as G
import qualified Hedgehog.Range as R
import qualified Prelude as P
{-# ANN module ("HLint: ignore Redundant do" :: String) #-}
{-# ANN module ("HLint: ignore Reduce duplication" :: String) #-}
{-# ANN module ("HLint: ignore Redundant bracket" :: String) #-}
spec :: Spec
spec = do
it "foldr" $ require $ property $ do
xs <- forAll (G.fingerTree (G.int R.constantBounded))
foldr (:) [] xs === P.foldr (:) [] (toList xs)
it "foldl" $ require $ property $ do
xs <- forAll (G.fingerTree (G.int R.constantBounded))
foldl (flip (:)) [] xs === P.foldl (flip (:)) [] (toList xs)
it "(==)" $ require $ property $ do
xs <- forAll (G.fingerTree (G.int R.constantBounded))
ys <- forAll (G.fingerTree (G.int R.constantBounded))
(xs == ys) === (toList xs == toList ys)
it "compare" $ require $ property $ do
xs <- forAll (G.fingerTree (G.int R.constantBounded))
ys <- forAll (G.fingerTree (G.int R.constantBounded))
compare xs ys === compare (toList xs) (toList ys)
it "mappend" $ require $ property $ do
xs <- forAll (G.fingerTree (G.int R.constantBounded))
ys <- forAll (G.fingerTree (G.int R.constantBounded))
toList' (mappend xs ys) ~== toList xs ++ toList ys
it "empty" $ require $ property $ do
toList' (empty :: Seq Int) === Just []
it "singletone" $ require $ property $ do
x <- forAll (G.int R.constantBounded)
toList' (singleton x) ~== [x]
it "(<|)" $ require $ property $ do
x <- forAll (G.int R.constantBounded)
xs <- forAll (G.fingerTree (G.int R.constantBounded))
toList' (x <| xs) ~== x : toList xs
it "(|>)" $ require $ property $ do
x <- forAll (G.int R.constantBounded)
xs <- forAll (G.fingerTree (G.int R.constantBounded))
toList' (xs |> x) ~== toList xs ++ [x]
it "(><)" $ require $ property $ do
xs <- forAll (G.fingerTree (G.int R.constantBounded))
ys <- forAll (G.fingerTree (G.int R.constantBounded))
toList' (xs >< ys) ~== toList xs ++ toList ys
it "fromList" $ require $ property $ do
xs <- forAll (G.list (R.linear 0 100) (G.int R.constantBounded))
toList' (fromList xs) ~== xs
it "null" $ require $ property $ do
xs <- forAll (G.fingerTree (G.int R.constantBounded))
null xs === P.null (toList xs)
it "viewl" $ require $ property $ do
xs <- forAll (G.fingerTree (G.int R.constantBounded))
case viewl xs of
EmptyL -> P.null (toList xs) === True
x :< xs' -> do
valid xs' === True
toList xs === x : toList xs'
it "viewr" $ require $ property $ do
xs <- forAll (G.fingerTree (G.int R.constantBounded))
case viewr xs of
EmptyR -> P.null (toList xs) === True
xs' :> x -> do
valid xs' === True
toList xs === toList xs' ++ [x]
it "split" $ require $ property $ do
n <- forAll (G.int R.constantBounded)
let p ys = P.length ys > n
xs <- forAll (G.fingerTree (G.int R.constantBounded))
toListPair' (split p xs) ~== P.splitAt n (toList xs)
it "takeUntil" $ require $ property $ do
n <- forAll (G.int R.constantBounded)
let p ys = P.length ys > n
xs <- forAll (G.fingerTree (G.int R.constantBounded))
toList' (takeUntil p xs) ~== P.take n (toList xs)
it "dropUntil" $ require $ property $ do
n <- forAll (G.int R.constantBounded)
let p ys = P.length ys > n
xs <- forAll (G.fingerTree (G.int R.constantBounded))
toList' (dropUntil p xs) ~== P.drop n (toList xs)
it "reverse" $ require $ property $ do
xs <- forAll (G.fingerTree (G.int R.constantBounded))
toList' (reverse xs) ~== P.reverse (toList xs)
it "fmap" $ require $ property $ do
let f = Just
xs <- forAll (G.fingerTree (G.int R.constantBounded))
toList' (fmap' f xs) ~== map f (toList xs)
it "fmapWithPos" $ require $ property $ do
let f = (,)
xs <- forAll (G.fingerTree (G.int R.constantBounded))
let xs_list = toList xs
toList' (fmapWithPos f xs) ~== zipWith f (inits xs_list) xs_list
it "traverse" $ require $ property $ do
let f x = do
n <- step
return (n, x)
xs <- forAll (G.fingerTree (G.int R.constantBounded))
toList' (evalM (traverse' f xs)) ~== evalM (traverse f (toList xs))
it "traverseWithPos" $ require $ property $ do
xs <- forAll (G.fingerTree (G.int R.constantBounded))
let f ys y = do
n <- step
return (ys, n, y)
let xs_list = toList xs
toList' (evalM (traverseWithPos f xs)) ~== evalM (traverse (uncurry f) (zip (inits xs_list) xs_list))
infix 4 ~==
(~==) :: (Show a, Eq a) => Maybe a -> a -> PropertyT IO ()
(~==) = maybe (const failure) (===)
newtype M a = M (Int -> (Int, a))
runM :: M a -> Int -> (Int, a)
runM (M m) = m
evalM :: M a -> a
evalM m = snd (runM m 0)
instance Monad M where
return x = M $ \ n -> (n, x)
M u >>= f = M $ \ m -> let (n, x) = u m in runM (f x) n
instance Functor M where
fmap f (M u) = M $ \ m -> let (n, x) = u m in (n, f x)
instance Applicative M where
pure = return
(<*>) = ap
step :: M Int
step = M $ \ n -> (n+1, n)
toListPair' ::
(Eq a, Measured [a] a, Valid a, Eq b, Measured [b] b, Valid b) =>
(Seq a, Seq b) -> Maybe ([a], [b])
toListPair' (xs, ys) = (,) <$> toList' xs <*> toList' ys
toList' :: (Eq a, Measured [a] a, Valid a) => Seq a -> Maybe [a]
toList' xs
| valid xs = Just (toList xs)
| otherwise = Nothing
class Valid a where
valid :: a -> Bool
instance (Measured v a, Eq v, Valid a) => Valid (FingerTree v a) where
valid Empty = True
valid (Single x) = valid x
valid (Deep s pr m sf) =
s == measure pr `mappend` measure m `mappend` measure sf &&
valid pr && valid m && valid sf
instance (Measured v a, Eq v, Valid a) => Valid (Node v a) where
valid node = measure node == foldMap measure node && all valid node
instance Valid a => Valid (Digit a) where
valid = all valid
instance Valid Int where
valid = const True
instance Valid (a,b) where
valid = const True
instance Valid (a,b,c) where
valid = const True
instance Valid (Maybe a) where
valid = const True
instance Valid [a] where
valid = const True
------------------------------------------------------------------------
-- Use list of elements as the measure
------------------------------------------------------------------------
type Seq a = FingerTree [a] a
instance Measured [Int] Int where
measure x = [x]
instance Measured [Maybe a] (Maybe a) where
measure x = [x]
instance Measured [(a, b)] (a, b) where
measure x = [x]
instance Measured [(a, b, c)] (a, b, c) where
measure x = [x]