on 00a2f7b help sign in
463 lines 13 kB history raw
1module Main (main) where
3import Data.Semigroup (Sum(..), getSum)
4import Streamly.Test.Common (checkListEqual)
5import Test.QuickCheck
6 ( Gen
7 , Property
8 , arbitrary
9 , choose
10 , forAll
11 , listOf
12 , listOf1
13 , property
14 , vectorOf
15 , withMaxSuccess
16 )
17import Test.QuickCheck.Monadic (monadicIO, assert, run)
19import qualified Prelude
20import qualified Streamly.Internal.Data.Fold as F
21import qualified Streamly.Prelude as S
22import qualified Streamly.Data.Fold as FL
24import Prelude hiding
25 (maximum, minimum, elem, notElem, null, product, sum, head, last)
26import Test.Hspec as H
27import Test.Hspec.QuickCheck
29maxStreamLen :: Int
30maxStreamLen = 1000
32intMin :: Int
33intMin = minBound
35intMax :: Int
36intMax = maxBound
38min_value :: Int
39min_value = 0
41max_value :: Int
42max_value = 10000
44chooseInt :: (Int, Int) -> Gen Int
45chooseInt = choose
47{-# INLINE maxStreamLen #-}
48{-# INLINE intMin #-}
49{-# INLINE intMax #-}
51rollingHashFirstN :: Property
52rollingHashFirstN =
53 forAll (choose (0, maxStreamLen)) $ \len ->
54 forAll (choose (0, len)) $ \n ->
55 forAll (vectorOf len (arbitrary :: Gen Int)) $ \vec -> monadicIO $ do
56 a <- run $ S.fold F.rollingHash $ S.take n $ S.fromList vec
57 b <- run $ S.fold (F.rollingHashFirstN n) $ S.fromList vec
58 assert $ a == b
60head :: [Int] -> Expectation
61head ls = S.fold FL.head (S.fromList ls) `shouldReturn` headl ls
63 where
65 headl [] = Nothing
66 headl (x:_) = Just x
68length :: [Int] -> Expectation
69length ls = S.fold FL.length (S.fromList ls) `shouldReturn` Prelude.length ls
71sum :: [Int] -> Expectation
72sum ls = S.fold FL.sum (S.fromList ls) `shouldReturn` Prelude.sum ls
74product :: [Int] -> Expectation
75product ls =
76 S.fold FL.product (S.fromList ls) `shouldReturn` Prelude.product ls
78lesser :: (a -> a -> Ordering) -> a -> a -> a
79lesser f x y = if f x y == LT then x else y
81greater :: (a -> a -> Ordering) -> a -> a -> a
82greater f x y = if f x y == GT then x else y
84foldMaybe :: (b -> a -> b) -> b -> [a] -> Maybe b
85foldMaybe f acc ls =
86 case ls of
87 [] -> Nothing
88 _ -> Just (foldl f acc ls)
90maximumBy :: (Ord a, Show a) => a -> (a -> a -> Ordering) -> [a] -> Expectation
91maximumBy genmin f ls =
92 S.fold (FL.maximumBy f) (S.fromList ls)
93 `shouldReturn` foldMaybe (greater f) genmin ls
95maximum :: (Show a, Ord a) => a -> [a] -> Expectation
96maximum genmin ls =
97 S.fold FL.maximum (S.fromList ls)
98 `shouldReturn` foldMaybe (greater compare) genmin ls
100minimumBy :: (Ord a, Show a) => a -> (a -> a -> Ordering) -> [a] -> Expectation
101minimumBy genmax f ls =
102 S.fold (FL.minimumBy f) (S.fromList ls)
103 `shouldReturn` foldMaybe (lesser f) genmax ls
105minimum :: (Show a, Ord a) => a -> [a] -> Expectation
106minimum genmax ls =
107 S.fold FL.minimum (S.fromList ls)
108 `shouldReturn` foldMaybe (lesser compare) genmax ls
110toList :: [Int] -> Expectation
111toList ls = S.fold FL.toList (S.fromList ls) `shouldReturn` ls
113safeLast :: [a] -> Maybe a
114safeLast [] = Nothing
115safeLast (x:[]) = Just x
116safeLast (_:xs) = safeLast xs
118last :: [String] -> Expectation
119last ls = S.fold FL.last (S.fromList ls) `shouldReturn` safeLast ls
121mapMaybe :: [Int] -> Expectation
122mapMaybe ls =
123 let maybeEven x =
124 if even x
125 then Just x
126 else Nothing
127 f = F.mapMaybe maybeEven FL.toList
128 in S.fold f (S.fromList ls) `shouldReturn` filter even ls
130nth :: Int -> [a] -> Maybe a
131nth idx (x : xs)
132 | idx == 0 = Just x
133 | idx < 0 = Nothing
134 | otherwise = nth (idx - 1) xs
135nth _ [] = Nothing
137index :: Int -> [String] -> Expectation
138index idx ls =
139 let x = S.fold (FL.index idx) (S.fromList ls)
140 in x `shouldReturn` nth idx ls
142find :: (Show a, Eq a) => (a -> Bool) -> [a] -> Expectation
143find f ls = do
144 y <- S.fold (FL.findIndex f) (S.fromList ls)
145 case y of
146 Nothing ->
147 let fld = S.fold (FL.find f) (S.fromList ls)
148 in fld `shouldReturn` Nothing
149 Just idx ->
150 let fld = S.fold (FL.any f) (S.fromList $ take idx ls)
151 in fld `shouldReturn` False
153neg :: (a -> Bool) -> a -> Bool
154neg f x = not (f x)
156findIndex :: (a -> Bool) -> [a] -> Expectation
157findIndex f ls = do
158 y <- S.fold (FL.findIndex f) (S.fromList ls)
159 case y of
160 Nothing ->
161 let fld = S.fold (FL.all $ neg f) (S.fromList ls)
162 in fld `shouldReturn` True
163 Just idx ->
164 if idx == 0
165 then
166 S.fold (FL.all f) (S.fromList []) `shouldReturn` True
167 else
168 S.fold (FL.all f) (S.fromList $ take idx ls)
169 `shouldReturn` False
171predicate :: Int -> Bool
172predicate x = x * x < 100
174elemIndex :: Int -> [Int] -> Expectation
175elemIndex elm ls = do
176 y <- S.fold (FL.elemIndex elm) (S.fromList ls)
177 case y of
178 Nothing ->
179 let fld = S.fold (FL.any (== elm)) (S.fromList ls)
180 in fld `shouldReturn` False
181 Just idx ->
182 let fld = S.fold (FL.any (== elm)) (S.fromList $ take idx ls)
183 in fld `shouldReturn` False
185null :: [Int] -> Expectation
186null ls =
187 S.fold FL.null (S.fromList ls)
188 `shouldReturn`
189 case ls of
190 [] -> True
191 _ -> False
193elem :: Int -> [Int] -> Expectation
194elem elm ls = do
195 y <- S.fold (FL.elem elm) (S.fromList ls)
196 let fld = S.fold (FL.any (== elm)) (S.fromList ls)
197 fld `shouldReturn` y
199notElem :: Int -> [Int] -> Expectation
200notElem elm ls = do
201 y <- S.fold (FL.notElem elm) (S.fromList ls)
202 let fld = S.fold (FL.any (== elm)) (S.fromList ls)
203 fld `shouldReturn` not y
205all :: (a -> Bool) -> [a] -> Expectation
206all f ls =
207 S.fold (FL.all f) (S.fromList ls) `shouldReturn` Prelude.all f ls
209any :: (a -> Bool) -> [a] -> Expectation
210any f ls = S.fold (FL.any f) (S.fromList ls) `shouldReturn` Prelude.any f ls
212and :: [Bool] -> Expectation
213and ls = S.fold FL.and (S.fromList ls) `shouldReturn` Prelude.and ls
215or :: [Bool] -> Expectation
216or ls = S.fold FL.or (S.fromList ls) `shouldReturn` Prelude.or ls
218ltake :: [Int] -> Property
219ltake ls =
220 forAll (chooseInt (-1, Prelude.length ls + 2)) $ \n ->
221 S.fold (F.ltake n FL.toList) (S.fromList ls)
222 `shouldReturn` Prelude.take n ls
224sliceSepBy :: Property
225sliceSepBy =
226 forAll (listOf (chooseInt (0, 1))) $ \ls ->
227 let p = (== 1)
228 f = F.sliceSepBy p FL.toList
229 ys = Prelude.takeWhile (not . p) ls
230 in case S.fold f (S.fromList ls) of
231 Right xs -> checkListEqual xs ys
232 Left _ -> property False
234sliceSepByMax :: Property
235sliceSepByMax =
236 forAll (chooseInt (min_value, max_value)) $ \n ->
237 forAll (listOf (chooseInt (0, 1))) $ \ls ->
238 let p = (== 1)
239 f = F.sliceSepByMax p n FL.toList
240 ys = Prelude.take n (Prelude.takeWhile (not . p) ls)
241 in case S.fold f (S.fromList ls) of
242 Right xs -> checkListEqual xs ys
243 Left _ -> property False
245chooseFloat :: (Float, Float) -> Gen Float
246chooseFloat = choose
248drain :: [Int] -> Expectation
249drain ls = S.fold FL.drain (S.fromList ls) `shouldReturn` ()
251drainBy :: [Int] -> Expectation
252drainBy ls = S.fold (FL.drainBy return) (S.fromList ls) `shouldReturn` ()
254mean :: Property
255mean =
256 forAll (listOf1 (chooseFloat (-100.0, 100.0)))
257 $ \ls0 -> withMaxSuccess 1000 $ monadicIO $ action ls0
259 where
261 action ls = do
262 v1 <- run $ S.fold FL.mean (S.fromList ls)
263 let v2 = Prelude.sum ls / fromIntegral (Prelude.length ls)
264 assert (abs (v1 - v2) < 0.0001)
266stdDev :: Property
267stdDev =
268 forAll (listOf1 (chooseFloat (-100.0, 100.0)))
269 $ \ls0 -> withMaxSuccess 1000 $ monadicIO $ action ls0
271 where
273 action ls = do
274 v1 <- run $ S.fold FL.stdDev (S.fromList ls)
275 let avg = Prelude.sum ls / fromIntegral (Prelude.length ls)
276 se = Prelude.sum (fmap (\x -> (x - avg) * (x - avg)) ls)
277 sd = sqrt $ se / fromIntegral (Prelude.length ls)
278 assert (abs (v1 - sd) < 0.0001 )
280variance :: Property
281variance =
282 forAll (listOf1 (chooseFloat (-100.0, 100.0)))
283 $ \ls0 -> withMaxSuccess 1000 $ monadicIO $ action ls0
285 where
287 action ls = do
288 v1 <- run $ S.fold FL.variance (S.fromList ls)
289 let avg = Prelude.sum ls / fromIntegral (Prelude.length ls)
290 se = Prelude.sum (fmap (\x -> (x - avg) * (x - avg)) ls)
291 vr = se / fromIntegral (Prelude.length ls)
292 assert (abs (v1 - vr) < 0.01 )
294mconcat :: Property
295mconcat =
296 forAll (listOf1 (chooseInt (intMin, intMax)))
297 $ \ls0 -> monadicIO $ action ls0
299 where
301 action ls = do
302 v1 <- run $ S.fold FL.mconcat (S.map Sum $ S.fromList ls)
303 let v2 = Prelude.sum ls
304 assert (getSum v1 == v2)
306foldMap :: Property
307foldMap =
308 forAll (listOf1 (chooseInt (intMin, intMax)))
309 $ \ls0 -> monadicIO $ action ls0
311 where
313 action ls = do
314 v1 <- run $ S.fold (FL.foldMap Sum) $ S.fromList ls
315 let v2 = Prelude.sum ls
316 assert (getSum v1 == v2)
318foldMapM :: Property
319foldMapM =
320 forAll (listOf1 (chooseInt (intMin, intMax)))
321 $ \ls0 -> monadicIO $ action ls0
323 where
325 action ls = do
326 v1 <- run $ S.fold (FL.foldMapM (return . Sum)) $ S.fromList ls
327 let v2 = Prelude.sum ls
328 assert (getSum v1 == v2)
330lookup :: Property
331lookup =
332 forAll (chooseInt (1, 15))
333 $ \key0 ->monadicIO $ action key0
335 where
337 action key = do
338 let ls = [(1, "first"), (2, "second"), (3, "third"), (4, "fourth")
339 , (5, "fifth"), (6, "fifth+first"), (7, "fifth+second")
340 , (8, "fifth+third"), (9, "fifth+fourth")
341 , (10, "fifth+fifth")]
342 v1 <- run $ S.fold (FL.lookup key) $ S.fromList ls
343 let v2 = Prelude.lookup key ls
344 assert (v1 == v2)
346mapM :: Property
347mapM =
348 forAll (listOf1 (chooseInt (intMin, intMax)))
349 $ \ls0 -> monadicIO $ action ls0
351 where
353 action ls = do
354 let addLen x = return $ x + Prelude.length ls
355 fld = FL.mapM addLen FL.sum
356 v2 = foldl (+) (Prelude.length ls) ls
357 v1 <- run $ S.fold fld $ S.fromList ls
358 assert (v1 == v2)
360teeWithLength :: Property
361teeWithLength =
362 forAll (listOf1 (chooseInt (intMin, intMax)))
363 $ \ls0 -> monadicIO $ action ls0
365 where
367 action ls = do
368 v1 <- run $ S.fold (FL.tee FL.sum FL.length) $ S.fromList ls
369 let v2 = Prelude.sum ls
370 v3 = Prelude.length ls
371 assert (v1 == (v2, v3))
373teeWithMax :: Property
374teeWithMax =
375 forAll (listOf1 (chooseInt (intMin, intMax)))
376 $ \ls0 -> monadicIO $ action ls0
378 where
380 action ls = do
381 v1 <- run $ S.fold (FL.tee FL.sum FL.maximum) $ S.fromList ls
382 let v2 = Prelude.sum ls
383 v3 = foldMaybe (greater compare) intMin ls
384 assert (v1 == (v2, v3))
386distribute :: Property
387distribute =
388 forAll (listOf1 (chooseInt (intMin, intMax)))
389 $ \ls0 -> monadicIO $ action ls0
391 where
393 action ls = do
394 v1 <- run $ S.fold (FL.distribute [FL.sum, FL.length]) $ S.fromList ls
395 let v2 = Prelude.sum ls
396 v3 = Prelude.length ls
397 assert (v1 == [v2, v3])
399partition :: Property
400partition =
401 monadicIO $ do
402 v1 :: (Int, [String]) <-
403 run
404 $ S.fold (FL.partition FL.sum FL.toList)
405 $ S.fromList
406 [Left 1, Right "abc", Left 3, Right "xy", Right "pp2"]
407 let v2 = (4,["abc","xy","pp2"])
408 assert (v1 == v2)
410unzip :: Property
411unzip =
412 monadicIO $ do
413 v1 :: (Int, [String]) <-
414 run
415 $ S.fold (FL.unzip FL.sum FL.toList)
416 $ S.fromList [(1, "aa"), (2, "bb"), (3, "cc")]
417 let v2 = (6, ["aa", "bb", "cc"])
418 assert (v1 == v2)
420main :: IO ()
421main = hspec $
422 describe "Fold s" $ do
423 prop "RollingHashFirstN" rollingHashFirstN
424 prop "Index" index
425 prop "Head" head
426 prop "Last" last
427 prop "Length" Main.length
428 prop "Sum" sum
429 prop "Product" product
430 prop "MaximumBy" $ maximumBy intMin compare
431 prop "Maximum" $ maximum intMin
432 prop "MinimumBy" $ minimumBy intMax compare
433 prop "Minimum" $ minimum intMax
434 prop "ToList" toList
435 prop "Find" $ find predicate
436 prop "FindIndex" $ findIndex predicate
437 prop "ElemIndex" $ elemIndex 10
438 prop "Null" null
439 prop "Elem" $ elem 10
440 prop "NotElem" $ notElem 10
441 prop "All" $ Main.all predicate
442 prop "Any" $ Main.any predicate
443 prop "And" Main.and
444 prop "Or" Main.or
445 prop "mapMaybe" mapMaybe
446 prop "ltake" ltake
447 prop "sliceSepBy" sliceSepBy
448 prop "sliceSepByMax" sliceSepByMax
449 prop "drain" Main.drain
450 prop "drainBy" Main.drainBy
451 prop "mean" Main.mean
452 prop "stdDev" Main.stdDev
453 prop "variance" Main.variance
454 prop "mconcat" Main.mconcat
455 prop "foldMap" Main.foldMap
456 prop "foldMapM" Main.foldMapM
457 prop "lookup" Main.lookup
458 prop "mapM" Main.mapM
459 prop "teeWithLength" Main.teeWithLength
460 prop "teeWithMax" Main.teeWithMax
461 prop "distribute" Main.distribute
462 prop "partition" Main.partition
463 prop "unzip" Main.unzip