mirror of
https://github.com/ilyakooo0/streamly.git
synced 2024-09-11 08:25:40 +03:00
816 lines
24 KiB
Haskell
816 lines
24 KiB
Haskell
{-# OPTIONS_GHC -fno-warn-warnings-deprecations #-}
|
|
|
|
module Main (main) where
|
|
|
|
import Data.List (sort, sortBy)
|
|
import Data.Ord (comparing, Down(..))
|
|
import Data.Semigroup (Sum(..), getSum)
|
|
import Streamly.Test.Common (checkListEqual, listEquals)
|
|
import Test.QuickCheck
|
|
( Gen
|
|
, Property
|
|
, arbitrary
|
|
, choose
|
|
, forAll
|
|
, listOf
|
|
, listOf1
|
|
, property
|
|
, vectorOf
|
|
, withMaxSuccess
|
|
, generate
|
|
)
|
|
import Control.Monad.IO.Class (liftIO)
|
|
import Test.QuickCheck.Monadic (monadicIO, assert, run)
|
|
|
|
import qualified Data.Map
|
|
import qualified Prelude
|
|
import qualified Streamly.Internal.Data.MutArray as MArray
|
|
import qualified Streamly.Internal.Data.Fold as Fold
|
|
import qualified Streamly.Internal.Data.Stream as Stream
|
|
|
|
import Prelude hiding
|
|
(maximum, minimum, elem, notElem, null, product, sum, head, last, take)
|
|
import Test.Hspec as H
|
|
import Test.Hspec.QuickCheck
|
|
|
|
maxStreamLen :: Int
|
|
maxStreamLen = 1000
|
|
|
|
intMin :: Int
|
|
intMin = minBound
|
|
|
|
intMax :: Int
|
|
intMax = maxBound
|
|
|
|
min_value :: Int
|
|
min_value = 0
|
|
|
|
max_value :: Int
|
|
max_value = 10000
|
|
|
|
chooseInt :: (Int, Int) -> Gen Int
|
|
chooseInt = choose
|
|
|
|
{-# INLINE maxStreamLen #-}
|
|
{-# INLINE intMin #-}
|
|
{-# INLINE intMax #-}
|
|
|
|
rollingHashFirstN :: Property
|
|
rollingHashFirstN =
|
|
forAll (choose (0, maxStreamLen)) $ \len ->
|
|
forAll (choose (0, len)) $ \n ->
|
|
forAll (vectorOf len (arbitrary :: Gen Int)) $ \vec ->
|
|
monadicIO $ do
|
|
a <- run
|
|
$ Stream.fold Fold.rollingHash
|
|
$ Stream.take n
|
|
$ Stream.fromList vec
|
|
b <- run
|
|
$ Stream.fold (Fold.rollingHashFirstN n)
|
|
$ Stream.fromList vec
|
|
assert $ a == b
|
|
|
|
head :: [Int] -> Expectation
|
|
head ls = Stream.fold Fold.one (Stream.fromList ls) `shouldReturn` headl ls
|
|
|
|
headl :: [a] -> Maybe a
|
|
headl [] = Nothing
|
|
headl (x:_) = Just x
|
|
|
|
length :: [Int] -> Expectation
|
|
length ls = Stream.fold Fold.length (Stream.fromList ls) `shouldReturn` Prelude.length ls
|
|
|
|
sum :: [Int] -> Expectation
|
|
sum ls = Stream.fold Fold.sum (Stream.fromList ls) `shouldReturn` Prelude.sum ls
|
|
|
|
product :: [Int] -> Expectation
|
|
product ls =
|
|
Stream.fold Fold.product (Stream.fromList ls) `shouldReturn` Prelude.product ls
|
|
|
|
lesser :: (a -> a -> Ordering) -> a -> a -> a
|
|
lesser f x y = if f x y == LT then x else y
|
|
|
|
greater :: (a -> a -> Ordering) -> a -> a -> a
|
|
greater f x y = if f x y == GT then x else y
|
|
|
|
foldMaybe :: (b -> a -> b) -> b -> [a] -> Maybe b
|
|
foldMaybe f acc ls =
|
|
case ls of
|
|
[] -> Nothing
|
|
_ -> Just (foldl f acc ls)
|
|
|
|
maximumBy :: (Ord a, Show a) => a -> (a -> a -> Ordering) -> [a] -> Expectation
|
|
maximumBy genmin f ls =
|
|
Stream.fold (Fold.maximumBy f) (Stream.fromList ls)
|
|
`shouldReturn` foldMaybe (greater f) genmin ls
|
|
|
|
maximum :: (Show a, Ord a) => a -> [a] -> Expectation
|
|
maximum genmin ls =
|
|
Stream.fold Fold.maximum (Stream.fromList ls)
|
|
`shouldReturn` foldMaybe (greater compare) genmin ls
|
|
|
|
minimumBy :: (Ord a, Show a) => a -> (a -> a -> Ordering) -> [a] -> Expectation
|
|
minimumBy genmax f ls =
|
|
Stream.fold (Fold.minimumBy f) (Stream.fromList ls)
|
|
`shouldReturn` foldMaybe (lesser f) genmax ls
|
|
|
|
minimum :: (Show a, Ord a) => a -> [a] -> Expectation
|
|
minimum genmax ls =
|
|
Stream.fold Fold.minimum (Stream.fromList ls)
|
|
`shouldReturn` foldMaybe (lesser compare) genmax ls
|
|
|
|
toList :: [Int] -> Expectation
|
|
toList ls = Stream.fold Fold.toList (Stream.fromList ls) `shouldReturn` ls
|
|
|
|
toListRev :: [Int] -> Expectation
|
|
toListRev ls = Stream.fold Fold.toListRev (Stream.fromList ls) `shouldReturn` reverse ls
|
|
|
|
safeLast :: [a] -> Maybe a
|
|
safeLast [] = Nothing
|
|
safeLast (x:[]) = Just x
|
|
safeLast (_:xs) = safeLast xs
|
|
|
|
last :: [String] -> Expectation
|
|
last ls = Stream.fold Fold.last (Stream.fromList ls) `shouldReturn` safeLast ls
|
|
|
|
mapMaybe :: [Int] -> Expectation
|
|
mapMaybe ls =
|
|
let maybeEven x =
|
|
if even x
|
|
then Just x
|
|
else Nothing
|
|
f = Fold.mapMaybe maybeEven Fold.toList
|
|
in Stream.fold f (Stream.fromList ls) `shouldReturn` filter even ls
|
|
|
|
nth :: Int -> [a] -> Maybe a
|
|
nth idx (x : xs)
|
|
| idx == 0 = Just x
|
|
| idx < 0 = Nothing
|
|
| otherwise = nth (idx - 1) xs
|
|
nth _ [] = Nothing
|
|
|
|
index :: Int -> [String] -> Expectation
|
|
index idx ls =
|
|
let x = Stream.fold (Fold.index idx) (Stream.fromList ls)
|
|
in x `shouldReturn` nth idx ls
|
|
|
|
find :: (Show a, Eq a) => (a -> Bool) -> [a] -> Expectation
|
|
find f ls = do
|
|
y <- Stream.fold (Fold.findIndex f) (Stream.fromList ls)
|
|
case y of
|
|
Nothing ->
|
|
let fld = Stream.fold (Fold.find f) (Stream.fromList ls)
|
|
in fld `shouldReturn` Nothing
|
|
Just idx ->
|
|
let fld = Stream.fold (Fold.any f) (Stream.fromList $ Prelude.take idx ls)
|
|
in fld `shouldReturn` False
|
|
|
|
neg :: (a -> Bool) -> a -> Bool
|
|
neg f x = not (f x)
|
|
|
|
findIndex :: (a -> Bool) -> [a] -> Expectation
|
|
findIndex f ls = do
|
|
y <- Stream.fold (Fold.findIndex f) (Stream.fromList ls)
|
|
case y of
|
|
Nothing ->
|
|
let fld = Stream.fold (Fold.all $ neg f) (Stream.fromList ls)
|
|
in fld `shouldReturn` True
|
|
Just idx ->
|
|
if idx == 0
|
|
then
|
|
Stream.fold (Fold.all f) (Stream.fromList []) `shouldReturn` True
|
|
else
|
|
Stream.fold (Fold.all f) (Stream.fromList $ Prelude.take idx ls)
|
|
`shouldReturn` False
|
|
|
|
predicate :: Int -> Bool
|
|
predicate x = x * x < 100
|
|
|
|
elemIndex :: Int -> [Int] -> Expectation
|
|
elemIndex elm ls = do
|
|
y <- Stream.fold (Fold.elemIndex elm) (Stream.fromList ls)
|
|
case y of
|
|
Nothing ->
|
|
let fld = Stream.fold (Fold.any (== elm)) (Stream.fromList ls)
|
|
in fld `shouldReturn` False
|
|
Just idx ->
|
|
let fld =
|
|
Stream.fold
|
|
(Fold.any (== elm))
|
|
(Stream.fromList $ Prelude.take idx ls)
|
|
in fld `shouldReturn` False
|
|
|
|
null :: [Int] -> Expectation
|
|
null ls =
|
|
Stream.fold Fold.null (Stream.fromList ls)
|
|
`shouldReturn`
|
|
case ls of
|
|
[] -> True
|
|
_ -> False
|
|
|
|
elem :: Int -> [Int] -> Expectation
|
|
elem elm ls = do
|
|
y <- Stream.fold (Fold.elem elm) (Stream.fromList ls)
|
|
let fld = Stream.fold (Fold.any (== elm)) (Stream.fromList ls)
|
|
fld `shouldReturn` y
|
|
|
|
notElem :: Int -> [Int] -> Expectation
|
|
notElem elm ls = do
|
|
y <- Stream.fold (Fold.notElem elm) (Stream.fromList ls)
|
|
let fld = Stream.fold (Fold.any (== elm)) (Stream.fromList ls)
|
|
fld `shouldReturn` not y
|
|
|
|
all :: (a -> Bool) -> [a] -> Expectation
|
|
all f ls =
|
|
Stream.fold (Fold.all f) (Stream.fromList ls) `shouldReturn` Prelude.all f ls
|
|
|
|
any :: (a -> Bool) -> [a] -> Expectation
|
|
any f ls = Stream.fold (Fold.any f) (Stream.fromList ls) `shouldReturn` Prelude.any f ls
|
|
|
|
and :: [Bool] -> Expectation
|
|
and ls = Stream.fold Fold.and (Stream.fromList ls) `shouldReturn` Prelude.and ls
|
|
|
|
or :: [Bool] -> Expectation
|
|
or ls = Stream.fold Fold.or (Stream.fromList ls) `shouldReturn` Prelude.or ls
|
|
|
|
take :: [Int] -> Property
|
|
take ls =
|
|
forAll (chooseInt (-1, Prelude.length ls + 2)) $ \n ->
|
|
Stream.fold (Fold.take n Fold.toList) (Stream.fromList ls)
|
|
`shouldReturn` Prelude.take n ls
|
|
|
|
takeEndBy_ :: Property
|
|
takeEndBy_ =
|
|
forAll (listOf (chooseInt (0, 1))) $ \ls ->
|
|
let p = (== 1)
|
|
f = Fold.takeEndBy_ p Fold.toList
|
|
ys = Prelude.takeWhile (not . p) ls
|
|
in case Stream.fold f (Stream.fromList ls) of
|
|
Right xs -> checkListEqual xs ys
|
|
Left _ -> property False
|
|
|
|
takeEndByOrMax :: Property
|
|
takeEndByOrMax =
|
|
forAll (chooseInt (min_value, max_value)) $ \n ->
|
|
forAll (listOf (chooseInt (0, 1))) $ \ls ->
|
|
let p = (== 1)
|
|
f = Fold.takeEndBy_ p (Fold.take n Fold.toList)
|
|
ys = Prelude.take n (Prelude.takeWhile (not . p) ls)
|
|
in case Stream.fold f (Stream.fromList ls) of
|
|
Right xs -> checkListEqual xs ys
|
|
Left _ -> property False
|
|
|
|
chooseFloat :: (Float, Float) -> Gen Float
|
|
chooseFloat = choose
|
|
|
|
drain :: [Int] -> Expectation
|
|
drain ls = Stream.fold Fold.drain (Stream.fromList ls) `shouldReturn` ()
|
|
|
|
drainBy :: [Int] -> Expectation
|
|
drainBy ls = Stream.fold (Fold.drainBy return) (Stream.fromList ls) `shouldReturn` ()
|
|
|
|
mean :: Property
|
|
mean =
|
|
forAll (listOf1 (chooseFloat (-100.0, 100.0)))
|
|
$ \ls0 -> withMaxSuccess 1000 $ monadicIO $ action ls0
|
|
|
|
where
|
|
|
|
action ls = do
|
|
v1 <- run $ Stream.fold Fold.mean (Stream.fromList ls)
|
|
let v2 = Prelude.sum ls / fromIntegral (Prelude.length ls)
|
|
assert (abs (v1 - v2) < 0.0001)
|
|
|
|
stdDev :: Property
|
|
stdDev =
|
|
forAll (listOf1 (chooseFloat (-100.0, 100.0)))
|
|
$ \ls0 -> withMaxSuccess 1000 $ monadicIO $ action ls0
|
|
|
|
where
|
|
|
|
action ls = do
|
|
v1 <- run $ Stream.fold Fold.stdDev (Stream.fromList ls)
|
|
let avg = Prelude.sum ls / fromIntegral (Prelude.length ls)
|
|
se = Prelude.sum (fmap (\x -> (x - avg) * (x - avg)) ls)
|
|
sd = sqrt $ se / fromIntegral (Prelude.length ls)
|
|
assert (abs (v1 - sd) < 0.0001 )
|
|
|
|
variance :: Property
|
|
variance =
|
|
forAll (listOf1 (chooseFloat (-100.0, 100.0)))
|
|
$ \ls0 -> withMaxSuccess 1000 $ monadicIO $ action ls0
|
|
|
|
where
|
|
|
|
action ls = do
|
|
v1 <- run $ Stream.fold Fold.variance (Stream.fromList ls)
|
|
let avg = Prelude.sum ls / fromIntegral (Prelude.length ls)
|
|
se = Prelude.sum (fmap (\x -> (x - avg) * (x - avg)) ls)
|
|
vr = se / fromIntegral (Prelude.length ls)
|
|
assert (abs (v1 - vr) < 0.01 )
|
|
|
|
mconcat :: Property
|
|
mconcat =
|
|
forAll (listOf1 (chooseInt (intMin, intMax)))
|
|
$ \ls0 -> monadicIO $ action ls0
|
|
|
|
where
|
|
|
|
action ls = do
|
|
v1 <- run $ Stream.fold Fold.mconcat (fmap Sum $ Stream.fromList ls)
|
|
let v2 = Prelude.sum ls
|
|
assert (getSum v1 == v2)
|
|
|
|
foldMap :: Property
|
|
foldMap =
|
|
forAll (listOf1 (chooseInt (intMin, intMax)))
|
|
$ \ls0 -> monadicIO $ action ls0
|
|
|
|
where
|
|
|
|
action ls = do
|
|
v1 <- run $ Stream.fold (Fold.foldMap Sum) $ Stream.fromList ls
|
|
let v2 = Prelude.sum ls
|
|
assert (getSum v1 == v2)
|
|
|
|
foldMapM :: Property
|
|
foldMapM =
|
|
forAll (listOf1 (chooseInt (intMin, intMax)))
|
|
$ \ls0 -> monadicIO $ action ls0
|
|
|
|
where
|
|
|
|
action ls = do
|
|
v1 <- run $ Stream.fold (Fold.foldMapM (return . Sum)) $ Stream.fromList ls
|
|
let v2 = Prelude.sum ls
|
|
assert (getSum v1 == v2)
|
|
|
|
lookup :: Property
|
|
lookup =
|
|
forAll (chooseInt (1, 15))
|
|
$ \key0 ->monadicIO $ action key0
|
|
|
|
where
|
|
|
|
action key = do
|
|
let ls = [ (1, "first"), (2, "second"), (3, "third"), (4, "fourth")
|
|
, (5, "fifth"), (6, "fifth+first"), (7, "fifth+second")
|
|
, (8, "fifth+third"), (9, "fifth+fourth")
|
|
, (10, "fifth+fifth")
|
|
]
|
|
v1 <- run $ Stream.fold (Fold.lookup key) $ Stream.fromList ls
|
|
let v2 = Prelude.lookup key ls
|
|
assert (v1 == v2)
|
|
|
|
rmapM :: Property
|
|
rmapM =
|
|
forAll (listOf1 (chooseInt (intMin, intMax)))
|
|
$ \ls0 -> monadicIO $ action ls0
|
|
|
|
where
|
|
|
|
action ls = do
|
|
let addLen x = return $ x + Prelude.length ls
|
|
fld = Fold.rmapM addLen Fold.sum
|
|
v2 = foldl (+) (Prelude.length ls) ls
|
|
v1 <- run $ Stream.fold fld $ Stream.fromList ls
|
|
assert (v1 == v2)
|
|
|
|
teeWithLength :: Property
|
|
teeWithLength =
|
|
forAll (listOf1 (chooseInt (intMin, intMax)))
|
|
$ \ls0 -> monadicIO $ action ls0
|
|
|
|
where
|
|
|
|
action ls = do
|
|
v1 <- run $ Stream.fold (Fold.tee Fold.sum Fold.length) $ Stream.fromList ls
|
|
let v2 = Prelude.sum ls
|
|
v3 = Prelude.length ls
|
|
assert (v1 == (v2, v3))
|
|
|
|
teeWithFstLength :: Property
|
|
teeWithFstLength =
|
|
forAll (listOf1 (chooseInt (intMin, intMax)))
|
|
$ \ls0 -> monadicIO $ action ls0
|
|
|
|
where
|
|
|
|
action ls = do
|
|
v1 <-
|
|
run
|
|
$ Stream.fold (Fold.teeWithFst (,) (Fold.take 5 Fold.sum) Fold.length)
|
|
$ Stream.fromList ls
|
|
let v2 = Prelude.sum (Prelude.take 5 ls)
|
|
v3 = Prelude.length (Prelude.take 5 ls)
|
|
assert (v1 == (v2, v3))
|
|
|
|
partitionByM :: Property
|
|
partitionByM =
|
|
forAll (listOf1 (chooseInt (intMin, intMax)))
|
|
$ \ls0 -> monadicIO $ action ls0
|
|
|
|
where
|
|
|
|
action ls = do
|
|
let f x = if odd x then return (Left x) else return (Right x)
|
|
v1 <-
|
|
run
|
|
$ Stream.fold (Fold.partitionByM f Fold.length Fold.length)
|
|
$ Stream.fromList ls
|
|
let v2 = foldl (\b a -> if odd a then b+1 else b) 0 ls
|
|
v3 = foldl (\b a -> if even a then b+1 else b) 0 ls
|
|
assert (v1 == (v2, v3))
|
|
|
|
partitionByFstM :: Property
|
|
partitionByFstM =
|
|
forAll (listOf1 (chooseInt (intMin, intMax)))
|
|
$ \ls0 -> monadicIO $ action ls0
|
|
|
|
where
|
|
|
|
action _ = do
|
|
let f x = if odd x then return (Left x) else return (Right x)
|
|
v1 <-
|
|
run
|
|
$ Stream.fold
|
|
(Fold.partitionByFstM f (Fold.take 25 Fold.length) Fold.length)
|
|
(Stream.fromList ([1 .. 100] :: [Int]))
|
|
let v2 = foldl (\b a -> if odd a then b+1 else b) 0 ([1..49] :: [Int])
|
|
v3 = foldl (\b a -> if even a then b+1 else b) 0 ([1..49] :: [Int])
|
|
assert (v1 == (v2, v3))
|
|
|
|
partitionByMinM1 :: Property
|
|
partitionByMinM1 =
|
|
forAll (listOf1 (chooseInt (intMin, intMax)))
|
|
$ \ls0 -> monadicIO $ action ls0
|
|
|
|
where
|
|
|
|
action _ = do
|
|
let f x = if odd x then return (Left x) else return (Right x)
|
|
v1 <-
|
|
run
|
|
$ Stream.fold
|
|
(Fold.partitionByMinM f Fold.length (Fold.take 25 Fold.length))
|
|
(Stream.fromList ([1 .. 100] :: [Int]))
|
|
let v2 = foldl (\b a -> if odd a then b+1 else b) 0 ([1..50] :: [Int])
|
|
v3 = foldl (\b a -> if even a then b+1 else b) 0 ([1..50] :: [Int])
|
|
assert (v1 == (v2, v3))
|
|
|
|
partitionByMinM2 :: Property
|
|
partitionByMinM2 =
|
|
forAll (listOf1 (chooseInt (intMin, intMax)))
|
|
$ \ls0 -> monadicIO $ action ls0
|
|
|
|
where
|
|
|
|
action _ = do
|
|
let f x = if odd x then return (Left x) else return (Right x)
|
|
v1 <-
|
|
run
|
|
$ Stream.fold
|
|
(Fold.partitionByMinM f (Fold.take 25 Fold.length) Fold.length)
|
|
(Stream.fromList ([1 .. 100] :: [Int]))
|
|
let v2 = foldl (\b a -> if odd a then b+1 else b) 0 ([1..49] :: [Int])
|
|
v3 = foldl (\b a -> if even a then b+1 else b) 0 ([1..49] :: [Int])
|
|
assert (v1 == (v2, v3))
|
|
|
|
teeWithMinLength1 :: Property
|
|
teeWithMinLength1 =
|
|
forAll (listOf1 (chooseInt (intMin, intMax)))
|
|
$ \ls0 -> monadicIO $ action ls0
|
|
|
|
where
|
|
|
|
action ls = do
|
|
v1 <-
|
|
run
|
|
$ Stream.fold (Fold.teeWithMin (,) (Fold.take 5 Fold.sum) Fold.length)
|
|
$ Stream.fromList ls
|
|
let v2 = Prelude.sum (Prelude.take 5 ls)
|
|
v3 = Prelude.length (Prelude.take 5 ls)
|
|
assert (v1 == (v2, v3))
|
|
|
|
|
|
teeWithMinLength2 :: Property
|
|
teeWithMinLength2 =
|
|
forAll (listOf1 (chooseInt (intMin, intMax)))
|
|
$ \ls0 -> monadicIO $ action ls0
|
|
|
|
where
|
|
|
|
action ls = do
|
|
v1 <-
|
|
run
|
|
$ Stream.fold (Fold.teeWithMin (,) Fold.sum (Fold.take 5 Fold.length))
|
|
$ Stream.fromList ls
|
|
let v2 = Prelude.sum (Prelude.take 5 ls)
|
|
v3 = Prelude.length (Prelude.take 5 ls)
|
|
assert (v1 == (v2, v3))
|
|
|
|
teeWithMax :: Property
|
|
teeWithMax =
|
|
forAll (listOf1 (chooseInt (intMin, intMax)))
|
|
$ \ls0 -> monadicIO $ action ls0
|
|
|
|
where
|
|
|
|
action ls = do
|
|
v1 <- run $ Stream.fold (Fold.tee Fold.sum Fold.maximum) $ Stream.fromList ls
|
|
let v2 = Prelude.sum ls
|
|
v3 = foldMaybe (greater compare) intMin ls
|
|
assert (v1 == (v2, v3))
|
|
|
|
distribute :: Property
|
|
distribute =
|
|
forAll (listOf1 (chooseInt (intMin, intMax)))
|
|
$ \ls0 -> monadicIO $ action ls0
|
|
|
|
where
|
|
|
|
action ls = do
|
|
v1 <-
|
|
run $ Stream.fold (Fold.distribute [Fold.sum, Fold.length]) $ Stream.fromList ls
|
|
let v2 = Prelude.sum ls
|
|
v3 = Prelude.length ls
|
|
assert (v1 == [v2, v3])
|
|
|
|
partition :: Property
|
|
partition =
|
|
monadicIO $ do
|
|
v1 :: (Int, [String]) <-
|
|
run
|
|
$ Stream.fold (Fold.partition Fold.sum Fold.toList)
|
|
$ Stream.fromList
|
|
[Left 1, Right "abc", Left 3, Right "xy", Right "pp2"]
|
|
let v2 = (4,["abc","xy","pp2"])
|
|
assert (v1 == v2)
|
|
|
|
unzip :: Property
|
|
unzip =
|
|
monadicIO $ do
|
|
v1 :: (Int, [String]) <-
|
|
run
|
|
$ Stream.fold (Fold.unzip Fold.sum Fold.toList)
|
|
$ Stream.fromList [(1, "aa"), (2, "bb"), (3, "cc")]
|
|
let v2 = (6, ["aa", "bb", "cc"])
|
|
assert (v1 == v2)
|
|
|
|
postscan :: Property
|
|
postscan = forAll (listOf (chooseInt (intMin, intMax))) $ \ls ->
|
|
monadicIO $ do
|
|
v1 :: [Int] <-
|
|
run
|
|
$ Stream.fold (Fold.postscan Fold.sum Fold.toList)
|
|
$ Stream.fromList ls
|
|
let v2 = scanl1 (+) ls
|
|
assert (v1 == v2)
|
|
|
|
many :: Property
|
|
many =
|
|
forAll (listOf (chooseInt (0, 100))) $ \lst ->
|
|
forAll (chooseInt (1, 100)) $ \i ->
|
|
monadicIO $ do
|
|
let strm = Stream.fromList lst
|
|
r1 <- Stream.fold (Fold.many (split i) Fold.toList) strm
|
|
r2 <- Stream.fold Fold.toList $ Stream.foldMany (split i) strm
|
|
assert $ r1 == r2
|
|
|
|
where
|
|
|
|
split i = Fold.take i Fold.toList
|
|
|
|
foldBreak :: [Int] -> Property
|
|
foldBreak ls = monadicIO $ do
|
|
(mbh, rest) <- run $ Stream.foldBreak Fold.one (Stream.fromList ls)
|
|
rests <- run $ Stream.fold Fold.toList rest
|
|
assert (mbh == headl ls)
|
|
listEquals (==) rests (taill ls)
|
|
|
|
where
|
|
|
|
taill :: [a] -> [a]
|
|
taill [] = []
|
|
taill (_:xs) = xs
|
|
|
|
demux :: Expectation
|
|
demux =
|
|
let table "SUM" = return Fold.sum
|
|
table "PRODUCT" = return Fold.product
|
|
table _ = return Fold.length
|
|
input = Stream.fromList (
|
|
[ ("SUM", 1)
|
|
, ("abc", 1)
|
|
, ("PRODUCT", 2)
|
|
, ("abc", 2)
|
|
, ("SUM",3)
|
|
, ("xyz", 1)
|
|
, ("PRODUCT", 4)
|
|
, ("xyz", 2)
|
|
, ("abc", 2)
|
|
] :: [(String, Int)])
|
|
in Stream.fold
|
|
(Fold.demuxKvToMap table)
|
|
input
|
|
`shouldReturn`
|
|
Data.Map.fromList [("PRODUCT", 8),("SUM", 4),("abc",3),("xyz",2)]
|
|
|
|
|
|
demuxWith :: Expectation
|
|
demuxWith =
|
|
let getKey x | even x = "SUM"
|
|
| otherwise = "PRODUCT"
|
|
|
|
getFold "SUM" = return Fold.sum
|
|
getFold "PRODUCT" = return Fold.product
|
|
getFold _ = error "demuxWith: bug"
|
|
|
|
input = Stream.fromList [1, 2, 3, 4 :: Int]
|
|
in Stream.fold
|
|
(Fold.demuxToContainer getKey (getFold . getKey))
|
|
input
|
|
`shouldReturn`
|
|
Data.Map.fromList [("PRODUCT",3),("SUM",6)]
|
|
|
|
classifyWith :: Expectation
|
|
classifyWith =
|
|
let input = Stream.fromList [("ONE",1),("ONE",1.1),("TWO",2), ("TWO",2.2)]
|
|
in Stream.fold
|
|
(Fold.toContainer fst (Fold.lmap snd Fold.toList))
|
|
input
|
|
`shouldReturn`
|
|
Data.Map.fromList
|
|
[("ONE",[1.0, 1.1 :: Double]), ("TWO",[2.0, 2.2])]
|
|
|
|
classify :: Expectation
|
|
classify =
|
|
let input =
|
|
Stream.fromList
|
|
[
|
|
("ONE", (1::Int, 1))
|
|
, ("ONE", (1, 1.1:: Double))
|
|
, ("TWO", (2, 2))
|
|
, ("TWO",(2, 2.2))
|
|
]
|
|
in Stream.fold
|
|
(Fold.kvToMap (Fold.lmap snd Fold.toList))
|
|
input
|
|
`shouldReturn`
|
|
Data.Map.fromList
|
|
[("ONE",[1.0, 1.1 :: Double]), ("TWO",[2.0, 2.2])]
|
|
|
|
splitAt :: Expectation
|
|
splitAt =
|
|
Stream.fold
|
|
(Fold.splitAt 6 Fold.toList Fold.toList)
|
|
(Stream.fromList "Hello World!")
|
|
`shouldReturn`
|
|
("Hello ","World!")
|
|
|
|
scan :: Property
|
|
scan = forAll (listOf (chooseInt (0, 100))) $ \lst ->
|
|
monadicIO $ do
|
|
v1 :: [Int] <-
|
|
run
|
|
$ Stream.fold (Fold.scan Fold.sum Fold.toList)
|
|
$ Stream.fromList lst
|
|
let v2 = scanl (+) 0 lst
|
|
assert (v1 == v2)
|
|
|
|
topBy :: Bool -> Property
|
|
topBy isTop = forAll (listOf (chooseInt (-50, 100))) $ \ls0 ->
|
|
monadicIO $ action ls0
|
|
|
|
where
|
|
|
|
action ls = do
|
|
|
|
let n0 = Prelude.length ls
|
|
n <- liftIO $ generate $ chooseInt (-2, n0 + 2)
|
|
if isTop
|
|
then do
|
|
lst <- Stream.fold (Fold.top n) (Stream.fromList ls) >>= MArray.toList
|
|
assert ((Prelude.take n . sortBy (comparing Down)) ls == lst)
|
|
else do
|
|
lst <- Stream.fold (Fold.bottom n) (Stream.fromList ls) >>= MArray.toList
|
|
assert ((Prelude.take n . sort) ls == lst)
|
|
|
|
top :: Property
|
|
top = topBy True
|
|
|
|
bottom :: Property
|
|
bottom = topBy False
|
|
|
|
nub :: Property
|
|
nub = monadicIO $ do
|
|
vals <- Stream.fold Fold.toList
|
|
$ Stream.catMaybes
|
|
$ Stream.postscan Fold.nub
|
|
$ Stream.fromList [1::Int, 1, 2, 3, 4, 4, 5, 1, 5, 7]
|
|
assert (vals == [1, 2, 3, 4, 5, 7])
|
|
|
|
moduleName :: String
|
|
moduleName = "Data.Fold"
|
|
|
|
main :: IO ()
|
|
main = hspec $ do
|
|
describe moduleName $ do
|
|
-- Folds
|
|
-- Accumulators
|
|
prop "mconcat" Main.mconcat
|
|
prop "foldMap" Main.foldMap
|
|
prop "foldMapM" Main.foldMapM
|
|
|
|
prop "drain" Main.drain
|
|
prop "drainBy" Main.drainBy
|
|
prop "last" last
|
|
prop "length" Main.length
|
|
prop "sum" sum
|
|
prop "product" product
|
|
prop "maximumBy" $ maximumBy intMin compare
|
|
prop "maximum" $ maximum intMin
|
|
prop "minimumBy" $ minimumBy intMax compare
|
|
prop "minimum" $ minimum intMax
|
|
prop "mean" Main.mean
|
|
prop "stdDev" Main.stdDev
|
|
prop "variance" Main.variance
|
|
prop "rollingHashFirstN" rollingHashFirstN
|
|
|
|
prop "toList" toList
|
|
prop "toListRev" toListRev
|
|
prop "demux" demux
|
|
prop "demuxWith" demuxWith
|
|
prop "classifyWith" classifyWith
|
|
prop "classify" classify
|
|
|
|
-- Terminating folds
|
|
prop "index" index
|
|
prop "head" head
|
|
prop "find" $ find predicate
|
|
prop "lookup" Main.lookup
|
|
prop "findIndex" $ findIndex predicate
|
|
prop "elemIndex" $ elemIndex 10
|
|
prop "null" null
|
|
prop "elem" $ elem 10
|
|
prop "notElem" $ notElem 10
|
|
prop "all" $ Main.all predicate
|
|
prop "any" $ Main.any predicate
|
|
prop "and" Main.and
|
|
prop "or" Main.or
|
|
prop "top" Main.top
|
|
prop "bottom" Main.bottom
|
|
prop "nub" Main.nub
|
|
|
|
-- Combinators
|
|
|
|
-- Transformation
|
|
prop "scan" scan
|
|
prop "postscan" Main.postscan
|
|
-- rsequence
|
|
-- Functor instance
|
|
prop "rmapM" Main.rmapM
|
|
-- lmap/lmapM
|
|
|
|
-- Filtering
|
|
-- filter/filterM
|
|
-- catMaybes
|
|
prop "mapMaybe" mapMaybe
|
|
|
|
-- Trimming
|
|
prop "take" take
|
|
-- takeEndBy
|
|
prop "takeEndBy_" takeEndBy_
|
|
prop "takeEndByOrMax" takeEndByOrMax
|
|
|
|
-- Appending
|
|
-- splitWith
|
|
|
|
-- Distributing
|
|
-- tee
|
|
prop "teeWithLength" Main.teeWithLength
|
|
prop "teeWithFstLength" Main.teeWithFstLength
|
|
prop "teeWithMinLength1" Main.teeWithMinLength1
|
|
prop "teeWithMinLength2" Main.teeWithMinLength2
|
|
prop "teeWithMax" Main.teeWithMax
|
|
prop "partitionByM" Main.partitionByM
|
|
prop "partitionByFstM" Main.partitionByFstM
|
|
prop "partitionByMinM1" Main.partitionByMinM1
|
|
prop "partitionByMinM2" Main.partitionByMinM2
|
|
prop "distribute" Main.distribute
|
|
|
|
-- Partitioning
|
|
prop "partition" Main.partition
|
|
prop "partitionByM" partitionByM
|
|
|
|
-- Unzipping
|
|
prop "unzip" Main.unzip
|
|
prop "splitAt" Main.splitAt
|
|
|
|
-- Nesting
|
|
prop "many" Main.many
|
|
-- concatMap
|
|
-- chunksOf
|
|
|
|
prop "foldBreak" foldBreak
|