3module Main (main) where
5import Control.Applicative (ZipList(..))
6import Control.Concurrent (MVar, takeMVar, putMVar, newEmptyMVar)
7import Control.Exception
8 (BlockedIndefinitelyOnMVar(..), catches,
9 BlockedIndefinitelyOnSTM(..), Handler(..))
10import Control.Monad (when, forM_, replicateM, replicateM_)
11import Control.Monad.IO.Class (MonadIO(..))
12import Data.Function ((&))
13import Data.IORef (readIORef, modifyIORef, newIORef)
15 (sort, foldl', scanl', findIndices, findIndex, elemIndices,
16 elemIndex, find, insertBy, intersperse, foldl1', (\\),
17 maximumBy, minimumBy, deleteBy, isPrefixOf, isSubsequenceOf,
19import Data.Maybe (mapMaybe)
20import GHC.Word (Word8)
22import Test.Hspec.QuickCheck
24 (counterexample, Property, withMaxSuccess, forAll, choose)
25import Test.QuickCheck.Monadic (run, monadicIO, monitor, assert, PropertyM)
30import Streamly.Prelude ((.:), nil)
31import qualified Streamly.Prelude as S
33-- Coverage build takes too long with default number of tests
41singleton :: IsStream t => a -> t m a
44sortEq :: Ord a => [a] -> [a] -> Bool
45sortEq a b = sort a == sort b
49 => (a -> a -> Bool) -> a -> a -> PropertyM m ()
50equals eq stream list = do
51 when (not $ stream `eq` list) $
54 "stream " <> show stream
55 <> "\nlist " <> show list
57 assert (stream `eq` list)
60 :: (Show a, Eq a, MonadIO m)
61 => ([a] -> [a] -> Bool) -> [a] -> [a] -> PropertyM m ()
62listEquals eq stream list = do
63 when (not $ stream `eq` list) $ liftIO $ putStrLn $
64 "stream " <> show stream
65 <> "\nlist " <> show list
66 <> "\nstream \\\\ list " <> show (stream \\ list)
67 <> "\nlist \\\\ stream " <> show (list \\ stream)
68 when (not $ stream `eq` list) $
71 "stream " <> show stream
72 <> "\nlist " <> show list
73 <> "\nstream \\\\ list " <> show (stream \\ list)
74 <> "\nlist \\\\ stream " <> show (list \\ stream)
76 assert (stream `eq` list)
78-------------------------------------------------------------------------------
79-- Construction operations
80-------------------------------------------------------------------------------
86 -> (t IO a -> SerialT IO a)
89constructWithLen mkStream mkList op len = withMaxSuccess maxTestCount $
91 stream <- run $ (S.toList . op) (mkStream (fromIntegral len))
92 let list = mkList (fromIntegral len)
93 listEquals (==) stream list
98 -> (t IO Int -> SerialT IO Int)
101constructWithLenM mkStream mkList op len = withMaxSuccess maxTestCount $
103 stream <- run $ (S.toList . op) (mkStream (fromIntegral len))
104 list <- run $ mkList (fromIntegral len)
105 listEquals (==) stream list
107constructWithReplicate, constructWithReplicateM, constructWithIntFromThenTo
109 => (t IO Int -> SerialT IO Int)
113constructWithReplicateM = constructWithLenM stream list
114 where list = flip replicateM (return 1 :: IO Int)
115 stream = flip S.replicateM (return 1 :: IO Int)
117constructWithReplicate = constructWithLen stream list
118 where list = flip replicate (1 :: Int)
119 stream = flip S.replicate (1 :: Int)
121constructWithIntFromThenTo op l =
122 forAll (choose (minBound, maxBound)) $ \from ->
123 forAll (choose (minBound, maxBound)) $ \next ->
124 forAll (choose (minBound, maxBound)) $ \to ->
125 let list len = take len [from,next..to]
126 stream len = S.take len $ S.intFromThenTo from next to
127 in constructWithLen stream list op l
129#if __GLASGOW_HASKELL__ >= 806
130-- XXX try very small steps close to 0
131constructWithDoubleFromThenTo
133 => (t IO Double -> SerialT IO Double)
136constructWithDoubleFromThenTo op l =
137 forAll (choose (-9007199254740999,9007199254740999)) $ \from ->
138 forAll (choose (-9007199254740999,9007199254740999)) $ \next ->
139 forAll (choose (-9007199254740999,9007199254740999)) $ \to ->
140 let list len = take len [from,next..to]
141 stream len = S.take len $ S.fracFromThenTo from next to
142 in constructWithLen stream list op l
145constructWithIterate :: IsStream t => (t IO Int -> SerialT IO Int) -> Spec
146constructWithIterate t = do
148 (S.toList . t . S.take 100) (S.iterate (+ 1) (0 :: Int))
149 `shouldReturn` take 100 (iterate (+ 1) 0)
151 let addM y = return (y + 1)
152 S.toList . t . S.take 100 $ S.iterateM addM (0 :: Int)
153 `shouldReturn` take 100 (iterate (+ 1) 0)
155-------------------------------------------------------------------------------
156-- Concurrent generation
157-------------------------------------------------------------------------------
159mvarExcHandler :: String -> BlockedIndefinitelyOnMVar -> IO ()
160mvarExcHandler label BlockedIndefinitelyOnMVar =
161 error $ label <> " " <> "BlockedIndefinitelyOnMVar\n"
163stmExcHandler :: String -> BlockedIndefinitelyOnSTM -> IO ()
164stmExcHandler label BlockedIndefinitelyOnSTM =
165 error $ label <> " " <> "BlockedIndefinitelyOnSTM\n"
167dbgMVar :: String -> IO () -> IO ()
168dbgMVar label action =
169 action `catches` [ Handler (mvarExcHandler label)
170 , Handler (stmExcHandler label)
173-- | first n actions takeMVar and the last action performs putMVar n times
174mvarSequenceOp :: MVar () -> Word8 -> Word8 -> IO Word8
175mvarSequenceOp mv n x = do
176 let msg = show x <> "/" <> show n
178 then dbgMVar ("take mvarSequenceOp " <> msg) (takeMVar mv) >> return x
179 else dbgMVar ("put mvarSequenceOp" <> msg)
180 (replicateM_ (fromIntegral n) (putMVar mv ())) >> return x
183 :: ([Word8] -> t IO Word8)
184 -> ([Word8] -> [Word8] -> Bool)
185 -> (Word8 -> MVar () -> t IO Word8 -> SerialT IO Word8)
188concurrentMapM constr eq op n =
192 mv <- newEmptyMVar :: IO (MVar ())
193 (S.toList . op n mv) (constr list)
194 listEquals eq stream list
196concurrentFromFoldable
198 => ([Word8] -> [Word8] -> Bool)
199 -> (t IO Word8 -> SerialT IO Word8)
202concurrentFromFoldable eq op n =
206 mv <- newEmptyMVar :: IO (MVar ())
207 (S.toList . op) (S.fromFoldableM (fmap (mvarSequenceOp mv n) list))
208 listEquals eq stream list
210sourceUnfoldrM :: IsStream t => MVar () -> Word8 -> t IO Word8
211sourceUnfoldrM mv n = S.unfoldrM step 0
213 -- argument must be integer to avoid overflow of word8 at 255
214 step :: Int -> IO (Maybe (Word8, Int))
216 let msg = show cnt <> "/" <> show n
217 if cnt > fromIntegral n
220 dbgMVar ("put sourceUnfoldrM " <> msg) (putMVar mv ())
221 return (Just (fromIntegral cnt, cnt + 1))
223-- Note that this test is not guaranteed to succeed, because there is no
224-- guarantee of parallelism in case of Async/Ahead streams.
227 => ([Word8] -> [Word8] -> Bool)
228 -> (t IO Word8 -> SerialT IO Word8)
231concurrentUnfoldrM eq op n =
233 -- XXX we should test empty list case as well
236 -- putStrLn $ "concurrentUnfoldrM: " <> show n
237 mv <- newEmptyMVar :: IO (MVar ())
239 -- since unfoldr happens in parallel with the stream processing we
240 -- can do two takeMVar in one iteration. If it is not parallel then
241 -- this will not work and the test will fail.
243 x <- op (sourceUnfoldrM mv n)
244 -- results may not be yielded in order, in case of
245 -- Async/WAsync/Parallel. So we use an increasing count
247 i <- S.yieldM $ readIORef cnt
248 S.yieldM $ modifyIORef cnt (+1)
249 let msg = show i <> "/" <> show n
252 dbgMVar ("first take concurrentUnfoldrM " <> msg)
255 dbgMVar ("second take concurrentUnfoldrM " <> msg)
258 listEquals eq stream list
262 => ([Word8] -> t IO Word8)
264 -> ([Word8] -> [Word8] -> Bool)
265 -> (t IO Word8 -> SerialT IO Word8)
267concurrentOps constr desc eq t = do
268 let prop1 d p = prop d $ withMaxSuccess maxTestCount p
270 prop1 (desc <> " fromFoldableM") $ concurrentFromFoldable eq t
271 prop1 (desc <> " unfoldrM") $ concurrentUnfoldrM eq t
272 -- we pass it the length of the stream n and an mvar mv.
273 -- The stream is [0..n]. The threads communicate in such a way that the
274 -- actions coming first in the stream are dependent on the last action. So
275 -- if the stream is not processed concurrently it will block forever.
276 -- Note that if the size of the stream is bigger than the thread limit
277 -- then it will block even if it is concurrent.
278 prop1 (desc <> " mapM") $
279 concurrentMapM constr eq $ \n mv stream ->
280 t $ S.mapM (mvarSequenceOp mv n) stream
282-------------------------------------------------------------------------------
283-- Concurrent Application
284-------------------------------------------------------------------------------
286concurrentApplication :: IsStream t
287 => ([Word8] -> [Word8] -> Bool)
288 -> (t IO Word8 -> SerialT IO Word8)
291concurrentApplication eq t n = withMaxSuccess maxTestCount $
293 -- XXX we should test empty list case as well
296 -- putStrLn $ "concurrentApplication: " <> show n
297 mv <- newEmptyMVar :: IO (MVar ())
298 -- since unfoldr happens in parallel with the stream processing we
299 -- can do two takeMVar in one iteration. If it is not parallel then
300 -- this will not work and the test will fail.
302 sourceUnfoldrM mv n |&
304 let msg = show x <> "/" <> show n
306 dbgMVar ("first take concurrentApp " <> msg)
309 dbgMVar ("second take concurrentApp " <> msg)
312 listEquals eq stream list
314sourceUnfoldrM1 :: IsStream t => Word8 -> t IO Word8
315sourceUnfoldrM1 n = S.unfoldrM step 0
317 -- argument must be integer to avoid overflow of word8 at 255
318 step :: Int -> IO (Maybe (Word8, Int))
320 if cnt > fromIntegral n
322 else return (Just (fromIntegral cnt, cnt + 1))
324concurrentFoldlApplication :: Word8 -> Property
325concurrentFoldlApplication n =
327 -- XXX we should test empty list case as well
330 sourceUnfoldrM1 n |&. S.foldlM' (\xs x -> return (x : xs)) []
331 listEquals (==) (reverse stream) list
333concurrentFoldrApplication :: Word8 -> Property
334concurrentFoldrApplication n =
336 -- XXX we should test empty list case as well
339 sourceUnfoldrM1 n |&. S.foldrM (\x xs -> return (x : xs)) []
340 listEquals (==) stream list
342-------------------------------------------------------------------------------
343-- Transformation operations
344-------------------------------------------------------------------------------
346transformCombineFromList
347 :: Semigroup (t IO Int)
348 => ([Int] -> t IO Int)
349 -> ([Int] -> [Int] -> Bool)
351 -> (t IO Int -> SerialT IO Int)
352 -> (t IO Int -> t IO Int)
357transformCombineFromList constr eq listOp t op a b c =
358 withMaxSuccess maxTestCount $
360 stream <- run ((S.toList . t) $
361 constr a <> op (constr b <> constr c))
362 let list = a <> listOp (b <> c)
363 listEquals eq stream list
365-- XXX add tests for MonadReader and MonadError etc. In case an SVar is
366-- accidentally passed through them.
368-- This tests transform ops along with detecting illegal sharing of SVar across
369-- conurrent streams. These tests work for all stream types whereas
370-- transformCombineOpsOrdered work only for ordered stream types i.e. excluding
372transformCombineOpsCommon
373 :: (IsStream t, Semigroup (t IO Int))
374 => ([Int] -> t IO Int)
376 -> ([Int] -> [Int] -> Bool)
377 -> (t IO Int -> SerialT IO Int)
379transformCombineOpsCommon constr desc eq t = do
380 let transform = transformCombineFromList constr eq
383 prop (desc <> " filter False") $
384 transform (filter (const False)) t (S.filter (const False))
385 prop (desc <> " filter True") $
386 transform (filter (const True)) t (S.filter (const True))
387 prop (desc <> " filter even") $
388 transform (filter even) t (S.filter even)
390 prop (desc <> " filterM False") $
391 transform (filter (const False)) t (S.filterM (const $ return False))
392 prop (desc <> " filterM True") $
393 transform (filter (const True)) t (S.filterM (const $ return True))
394 prop (desc <> " filterM even") $
395 transform (filter even) t (S.filterM (return . even))
397 prop (desc <> " take maxBound") $
398 transform (take maxBound) t (S.take maxBound)
399 prop (desc <> " take 0") $ transform (take 0) t (S.take 0)
401 prop (desc <> " takeWhile True") $
402 transform (takeWhile (const True)) t (S.takeWhile (const True))
403 prop (desc <> " takeWhile False") $
404 transform (takeWhile (const False)) t (S.takeWhile (const False))
406 prop (desc <> " takeWhileM True") $
407 transform (takeWhile (const True)) t (S.takeWhileM (const $ return True))
408 prop (desc <> " takeWhileM False") $
409 transform (takeWhile (const False)) t (S.takeWhileM (const $ return False))
411 prop (desc <> " drop maxBound") $
412 transform (drop maxBound) t (S.drop maxBound)
413 prop (desc <> " drop 0") $ transform (drop 0) t (S.drop 0)
415 prop (desc <> " dropWhile True") $
416 transform (dropWhile (const True)) t (S.dropWhile (const True))
417 prop (desc <> " dropWhile False") $
418 transform (dropWhile (const False)) t (S.dropWhile (const False))
420 prop (desc <> " dropWhileM True") $
421 transform (dropWhile (const True)) t (S.dropWhileM (const $ return True))
422 prop (desc <> " dropWhileM False") $
423 transform (dropWhile (const False)) t (S.dropWhileM (const $ return False))
425 prop (desc <> " deleteBy (<=) maxBound") $
426 transform (deleteBy (<=) maxBound) t (S.deleteBy (<=) maxBound)
427 prop (desc <> " deleteBy (==) 4") $
428 transform (deleteBy (==) 4) t (S.deleteBy (==) 4)
431 prop (desc <> " mapM (+1)") $
432 transform (fmap (+1)) t (S.mapM (\x -> return (x + 1)))
434 prop (desc <> " scanl'") $ transform (scanl' (flip const) 0) t
435 (S.scanl' (flip const) 0)
436 prop (desc <> " scanlM'") $ transform (scanl' (flip const) 0) t
437 (S.scanlM' (\_ a -> return a) 0)
438 prop (desc <> " scanl") $ transform (scanl' (flip const) 0) t
439 (S.scanl' (flip const) 0)
440 prop (desc <> " scanl1'") $ transform (scanl1 (flip const)) t
441 (S.scanl1' (flip const))
442 prop (desc <> " scanl1M'") $ transform (scanl1 (flip const)) t
443 (S.scanl1M' (\_ a -> return a))
445 let f x = if odd x then Just (x + 100) else Nothing
446 prop (desc <> " mapMaybe") $ transform (mapMaybe f) t (S.mapMaybe f)
449 prop (desc <> " reverse") $ transform reverse t S.reverse
452 prop (desc <> " intersperseM") $
453 forAll (choose (minBound, maxBound)) $ \n ->
454 transform (intersperse n) t (S.intersperseM $ return n)
455 prop (desc <> " insertBy 0") $
456 forAll (choose (minBound, maxBound)) $ \n ->
457 transform (insertBy compare n) t (S.insertBy compare n)
460 prop (desc <> " concatMap") $
461 forAll (choose (0, 100)) $ \n ->
462 transform (concatMap (const [1..n]))
463 t (S.concatMap (const (S.fromList [1..n])))
465-- transformation tests that can only work reliably for ordered streams i.e.
466-- Serial, Ahead and Zip. For example if we use "take 1" on an async stream, it
467-- might yield a different result every time.
468transformCombineOpsOrdered
469 :: (IsStream t, Semigroup (t IO Int))
470 => ([Int] -> t IO Int)
472 -> ([Int] -> [Int] -> Bool)
473 -> (t IO Int -> SerialT IO Int)
475transformCombineOpsOrdered constr desc eq t = do
476 let transform = transformCombineFromList constr eq
479 prop (desc <> " take 1") $ transform (take 1) t (S.take 1)
481 prop (desc <> " take 2") $ transform (take 2) t (S.take 2)
482 prop (desc <> " take 3") $ transform (take 3) t (S.take 3)
483 prop (desc <> " take 4") $ transform (take 4) t (S.take 4)
484 prop (desc <> " take 5") $ transform (take 5) t (S.take 5)
486 prop (desc <> " take 10") $ transform (take 10) t (S.take 10)
488 prop (desc <> " takeWhile > 0") $
489 transform (takeWhile (> 0)) t (S.takeWhile (> 0))
491 prop (desc <> " drop 1") $ transform (drop 1) t (S.drop 1)
492 prop (desc <> " drop 10") $ transform (drop 10) t (S.drop 10)
494 prop (desc <> " dropWhile > 0") $
495 transform (dropWhile (> 0)) t (S.dropWhile (> 0))
496 prop (desc <> " scan") $ transform (scanl' (+) 0) t (S.scanl' (+) 0)
499 prop (desc <> " deleteBy (<=) 0") $
500 transform (deleteBy (<=) 0) t (S.deleteBy (<=) 0)
502 prop (desc <> " findIndices") $
503 transform (findIndices odd) t (S.findIndices odd)
504 prop (desc <> " elemIndices") $
505 transform (elemIndices 0) t (S.elemIndices 0)
507 -- XXX this does not fail when the SVar is shared, need to fix.
508 prop (desc <> " concurrent application") $
509 transform (& fmap (+1)) t (|& S.map (+1))
511-------------------------------------------------------------------------------
512-- Elimination operations
513-------------------------------------------------------------------------------
522eliminateOp constr listOp op a =
524 stream <- run $ op (constr a)
526 equals (==) stream list
528wrapMaybe :: ([a1] -> a2) -> [a1] -> Maybe a2
529wrapMaybe f x = if null x then Nothing else Just (f x)
531wrapOutOfBounds :: ([a1] -> Int -> a2) -> Int -> [a1] -> Maybe a2
532wrapOutOfBounds f i x | null x = Nothing
533 | i >= length x = Nothing
534 | otherwise = Just (f x i)
536wrapThe :: Eq a => [a] -> Maybe a
537wrapThe (x:xs) | all (x ==) xs = Just x
538 | otherwise = Nothing
542 :: ([Int] -> t IO Int)
544 -> (t IO Int -> SerialT IO Int)
546eliminationOps constr desc t = do
548 prop (desc <> " null") $ eliminateOp constr null $ S.null . t
549 prop (desc <> " foldl'") $
550 eliminateOp constr (foldl' (+) 0) $ S.foldl' (+) 0 . t
551 prop (desc <> " foldl1'") $
552 eliminateOp constr (wrapMaybe $ foldl1' (+)) $ S.foldl1' (+) . t
553 prop (desc <> " foldr1") $
554 eliminateOp constr (wrapMaybe $ foldr1 (+)) $ S.foldr1 (+) . t
555 prop (desc <> " all") $ eliminateOp constr (all even) $ S.all even . t
556 prop (desc <> " any") $ eliminateOp constr (any even) $ S.any even . t
557 prop (desc <> " and") $ eliminateOp constr (and . fmap (> 0)) $
558 (S.and . S.map (> 0)) . t
559 prop (desc <> " or") $ eliminateOp constr (or . fmap (> 0)) $
560 (S.or . S.map (> 0)) . t
561 prop (desc <> " length") $ eliminateOp constr length $ S.length . t
562 prop (desc <> " sum") $ eliminateOp constr sum $ S.sum . t
563 prop (desc <> " product") $ eliminateOp constr product $ S.product . t
565 prop (desc <> " maximum") $
566 eliminateOp constr (wrapMaybe maximum) $ S.maximum . t
567 prop (desc <> " minimum") $
568 eliminateOp constr (wrapMaybe minimum) $ S.minimum . t
570 prop (desc <> " maximumBy compare") $
571 eliminateOp constr (wrapMaybe $ maximumBy compare) $
572 S.maximumBy compare . t
573 prop (desc <> " maximumBy flip compare") $
574 eliminateOp constr (wrapMaybe $ maximumBy $ flip compare) $
575 S.maximumBy (flip compare) . t
576 prop (desc <> " minimumBy compare") $
577 eliminateOp constr (wrapMaybe $ minimumBy compare) $
578 S.minimumBy compare . t
579 prop (desc <> " minimumBy flip compare") $
580 eliminateOp constr (wrapMaybe $ minimumBy $ flip compare) $
581 S.minimumBy (flip compare) . t
583 prop (desc <> " findIndex") $
584 eliminateOp constr (findIndex odd) $ S.findIndex odd . t
585 prop (desc <> " elemIndex") $
586 eliminateOp constr (elemIndex 3) $ S.elemIndex 3 . t
588 prop (desc <> " !! 5") $
589 eliminateOp constr (wrapOutOfBounds (!!) 5) $ (S.!! 5) . t
590 prop (desc <> " !! 4") $
591 eliminateOp constr (wrapOutOfBounds (!!) 0) $ (S.!! 0) . t
593 prop (desc <> " find") $ eliminateOp constr (find even) $ S.find even . t
594 prop (desc <> " lookup") $
595 eliminateOp constr (lookup 3 . flip zip [1..]) $
596 S.lookup 3 . S.zipWith (\a b -> (b, a)) (S.fromList [(1::Int)..]) . t
597 prop (desc <> " the") $ eliminateOp constr wrapThe $ S.the . t
599 -- Multi-stream eliminations
601 -- XXX Write better tests for substreams.
602 prop (desc <> " isPrefixOf 10") $ eliminateOp constr (isPrefixOf [1..10]) $
603 S.isPrefixOf (S.fromList [(1::Int)..10]) . t
604 prop (desc <> " isSubsequenceOf 10") $
605 eliminateOp constr (isSubsequenceOf $ filter even [1..10]) $
606 S.isSubsequenceOf (S.fromList $ filter even [(1::Int)..10]) . t
607 prop (desc <> " stripPrefix 10") $ eliminateOp constr (stripPrefix [1..10]) $
608 (\s -> s >>= maybe (return Nothing) (fmap Just . S.toList)) .
609 S.stripPrefix (S.fromList [(1::Int)..10]) . t
611-- head/tail/last may depend on the order in case of parallel streams
612-- so we test these only for serial streams.
614 :: ([Int] -> t IO Int)
616 -> (t IO Int -> SerialT IO Int)
618eliminationOpsOrdered constr desc t = do
619 prop (desc <> " head") $ eliminateOp constr (wrapMaybe head) $ S.head . t
620 prop (desc <> " tail") $ eliminateOp constr (wrapMaybe tail) $ \x -> do
623 Nothing -> return Nothing
624 Just s -> Just <$> S.toList s
625 prop (desc <> " last") $ eliminateOp constr (wrapMaybe last) $ S.last . t
626 prop (desc <> " init") $ eliminateOp constr (wrapMaybe init) $ \x -> do
629 Nothing -> return Nothing
630 Just s -> Just <$> S.toList s
633 :: ([Word8] -> t IO Word8)
634 -> (t IO Word8 -> SerialT IO Word8)
635 -> (Word8 -> SerialT IO Word8 -> IO Bool)
636 -> (Word8 -> [Word8] -> Bool)
639elemOp constr op streamOp listOp (x, xs) =
641 stream <- run $ (streamOp x . op) (constr xs)
642 let list = listOp x xs
643 equals (==) stream list
646 :: ([Word8] -> t IO Word8)
648 -> (t IO Word8 -> SerialT IO Word8)
650eliminationOpsWord8 constr desc t = do
651 prop (desc <> " elem") $ elemOp constr t S.elem elem
652 prop (desc <> " notElem") $ elemOp constr t S.notElem notElem
654-------------------------------------------------------------------------------
655-- Semigroup operations
656-------------------------------------------------------------------------------
661 -> ([b] -> [b] -> Bool)
663 -> (t IO a -> SerialT IO b)
666transformFromList constr eq listOp op a =
668 stream <- run ((S.toList . op) (constr a))
670 listEquals eq stream list
673 :: ([Int] -> t IO Int)
674 -> (t IO Int -> SerialT IO Int)
675 -> ([Int] -> [Int] -> Bool)
678foldFromList constr op eq = transformFromList constr eq id op
680-- XXX concatenate streams of multiple elements rather than single elements
684#if __GLASGOW_HASKELL__ < 804
685 , Semigroup (t IO Int)
689 -> ([Int] -> [Int] -> Bool)
690 -> (t IO Int -> SerialT IO Int)
692semigroupOps desc eq t = do
693 prop (desc <> " <>") $ foldFromList (foldMapWith (<>) singleton) t eq
694 prop (desc <> " mappend") $ foldFromList (foldMapWith mappend singleton) t eq
696-------------------------------------------------------------------------------
698-------------------------------------------------------------------------------
702 => ([Int] -> t IO Int)
704 -> ([Int] -> [Int] -> Bool)
705 -> (t IO Int -> SerialT IO Int)
707functorOps constr desc eq t = do
708 prop (desc <> " id") $ transformFromList constr eq id t
709 prop (desc <> " fmap (+1)") $ transformFromList constr eq (fmap (+1)) $ t . fmap (+1)
711-------------------------------------------------------------------------------
712-- Applicative operations
713-------------------------------------------------------------------------------
716 :: Applicative (t IO)
717 => ([Int] -> t IO Int)
718 -> ([(Int, Int)] -> [(Int, Int)] -> Bool)
719 -> (t IO (Int, Int) -> SerialT IO (Int, Int))
722applicativeOps constr eq t (a, b) = withMaxSuccess maxTestCount $
724 stream <- run ((S.toList . t) ((,) <$> constr a <*> constr b))
725 let list = (,) <$> a <*> b
726 listEquals eq stream list
728-------------------------------------------------------------------------------
730-------------------------------------------------------------------------------
733 :: (IsStream t, Applicative (t IO))
734 => ([Int] -> t IO Int)
735 -> ([(Int, Int)] -> [(Int, Int)] -> Bool)
736 -> (t IO (Int, Int) -> SerialT IO (Int, Int))
739zipApplicative constr eq t (a, b) = withMaxSuccess maxTestCount $
741 stream1 <- run ((S.toList . t) ((,) <$> constr a <*> constr b))
742 stream2 <- run ((S.toList . t) (pure (,) <*> constr a <*> constr b))
743 stream3 <- run ((S.toList . t) (S.zipWith (,) (constr a) (constr b)))
744 let list = getZipList $ (,) <$> ZipList a <*> ZipList b
745 listEquals eq stream1 list
746 listEquals eq stream2 list
747 listEquals eq stream3 list
751 => ([Int] -> t IO Int)
752 -> ([(Int, Int)] -> [(Int, Int)] -> Bool)
753 -> (t IO (Int, Int) -> SerialT IO (Int, Int))
756zipMonadic constr eq t (a, b) = withMaxSuccess maxTestCount $
761 (S.zipWithM (curry return) (constr a) (constr b)))
762 let list = getZipList $ (,) <$> ZipList a <*> ZipList b
763 listEquals eq stream1 list
767 => ([Int] -> t IO Int)
768 -> ([(Int, Int)] -> [(Int, Int)] -> Bool)
769 -> (t IO (Int, Int) -> SerialT IO (Int, Int))
772zipAsyncMonadic constr eq t (a, b) = withMaxSuccess maxTestCount $
777 (S.zipWithM (curry return) (constr a) (constr b)))
781 (S.zipAsyncWithM (curry return) (constr a) (constr b)))
782 let list = getZipList $ (,) <$> ZipList a <*> ZipList b
783 listEquals eq stream1 list
784 listEquals eq stream2 list
786-------------------------------------------------------------------------------
788-------------------------------------------------------------------------------
792 => ([Int] -> t IO Int)
793 -> ([Int] -> [Int] -> Bool)
794 -> (t IO Int -> SerialT IO Int)
797monadThen constr eq t (a, b) = withMaxSuccess maxTestCount $ monadicIO $ do
798 stream <- run ((S.toList . t) (constr a >> constr b))
800 listEquals eq stream list
804 => ([Int] -> t IO Int)
805 -> ([Int] -> [Int] -> Bool)
806 -> (t IO Int -> SerialT IO Int)
809monadBind constr eq t (a, b) = withMaxSuccess maxTestCount $
814 (constr a >>= \x -> (+ x) <$> constr b))
815 let list = a >>= \x -> (+ x) <$> b
816 listEquals eq stream list
822 $ modifyMaxSuccess (const 10)
825 let folded :: IsStream t => [a] -> t IO a
826 folded = serially . (\xs ->
828 [x] -> return x -- singleton stream case
829 _ -> foldMapWith (<>) return xs
834#ifndef COVERAGE_BUILD
835 , ("rate AvgRate 10000", t . avgRate 10000)
836 , ("rate Nothing", t . rate Nothing)
837 , ("maxBuffer 0", t . maxBuffer 0)
838 , ("maxBuffer 1", t . maxBuffer 1)
839 , ("maxThreads 0", t . maxThreads 0)
840 , ("maxThreads 1", t . maxThreads 1)
841 , ("maxThreads -1", t . maxThreads (-1))
845 let mapOps spec = mapM_ (\(desc, f) -> describe desc $ spec f)
846 let serialOps :: IsStream t => ((SerialT IO a -> t IO a) -> Spec) -> Spec
847 serialOps spec = mapOps spec $ makeOps serially
848#ifndef COVERAGE_BUILD
849 <> [("rate AvgRate 0.00000001", serially . avgRate 0.00000001)]
850 <> [("maxBuffer -1", serially . maxBuffer (-1))]
852 let wSerialOps :: IsStream t => ((WSerialT IO a -> t IO a) -> Spec) -> Spec
853 wSerialOps spec = mapOps spec $ makeOps wSerially
854#ifndef COVERAGE_BUILD
855 <> [("rate AvgRate 0.00000001", wSerially . avgRate 0.00000001)]
856 <> [("maxBuffer (-1)", wSerially . maxBuffer (-1))]
858 let asyncOps :: IsStream t => ((AsyncT IO a -> t IO a) -> Spec) -> Spec
859 asyncOps spec = mapOps spec $ makeOps asyncly
860#ifndef COVERAGE_BUILD
861 <> [("maxBuffer (-1)", asyncly . maxBuffer (-1))]
863 let wAsyncOps :: IsStream t => ((WAsyncT IO a -> t IO a) -> Spec) -> Spec
864 wAsyncOps spec = mapOps spec $ makeOps wAsyncly
865#ifndef COVERAGE_BUILD
866 <> [("maxBuffer (-1)", wAsyncly . maxBuffer (-1))]
868 let aheadOps :: IsStream t => ((AheadT IO a -> t IO a) -> Spec) -> Spec
869 aheadOps spec = mapOps spec $ makeOps aheadly
870#ifndef COVERAGE_BUILD
871 <> [("maxBuffer (-1)", aheadly . maxBuffer (-1))]
873 let parallelOps :: IsStream t => ((ParallelT IO a -> t IO a) -> Spec) -> Spec
874 parallelOps spec = mapOps spec $ makeOps parallely
875#ifndef COVERAGE_BUILD
876 <> [("rate AvgRate 0.00000001", parallely . avgRate 0.00000001)]
877 <> [("maxBuffer (-1)", parallely . maxBuffer (-1))]
879 let zipSerialOps :: IsStream t => ((ZipSerialM IO a -> t IO a) -> Spec) -> Spec
880 zipSerialOps spec = mapOps spec $ makeOps zipSerially
881#ifndef COVERAGE_BUILD
882 <> [("rate AvgRate 0.00000001", zipSerially . avgRate 0.00000001)]
883 <> [("maxBuffer (-1)", zipSerially . maxBuffer (-1))]
885 -- Note, the "pure" of applicative Zip streams generates and infinite
886 -- stream and therefore maxBuffer (-1) must not be used for that case.
887 let zipAsyncOps :: IsStream t => ((ZipAsyncM IO a -> t IO a) -> Spec) -> Spec
888 zipAsyncOps spec = mapOps spec $ makeOps zipAsyncly
890 describe "Construction" $ do
891 serialOps $ prop "serially replicate" . constructWithReplicate
893 serialOps $ prop "serially replicateM" . constructWithReplicateM
894 wSerialOps $ prop "wSerially replicateM" . constructWithReplicateM
895 aheadOps $ prop "aheadly replicateM" . constructWithReplicateM
896 asyncOps $ prop "asyncly replicateM" . constructWithReplicateM
897 wAsyncOps $ prop "wAsyncly replicateM" . constructWithReplicateM
898 parallelOps $ prop "parallely replicateM" . constructWithReplicateM
900 serialOps $ prop "serially intFromThenTo" .
901 constructWithIntFromThenTo
902#if __GLASGOW_HASKELL__ >= 806
903 serialOps $ prop "serially DoubleFromThenTo" .
904 constructWithDoubleFromThenTo
906 -- XXX test for all types of streams
907 constructWithIterate serially
908 -- XXX add tests for fromIndices
910 describe "Functor operations" $ do
911 serialOps $ functorOps S.fromFoldable "serially" (==)
912 serialOps $ functorOps folded "serially folded" (==)
913 wSerialOps $ functorOps S.fromFoldable "wSerially" (==)
914 wSerialOps $ functorOps folded "wSerially folded" (==)
915 aheadOps $ functorOps S.fromFoldable "aheadly" (==)
916 aheadOps $ functorOps folded "aheadly folded" (==)
917 asyncOps $ functorOps S.fromFoldable "asyncly" sortEq
918 asyncOps $ functorOps folded "asyncly folded" sortEq
919 wAsyncOps $ functorOps S.fromFoldable "wAsyncly" sortEq
920 wAsyncOps $ functorOps folded "wAsyncly folded" sortEq
921 parallelOps $ functorOps S.fromFoldable "parallely" sortEq
922 parallelOps $ functorOps folded "parallely folded" sortEq
923 zipSerialOps $ functorOps S.fromFoldable "zipSerially" (==)
924 zipSerialOps $ functorOps folded "zipSerially folded" (==)
925 zipAsyncOps $ functorOps S.fromFoldable "zipAsyncly" (==)
926 zipAsyncOps $ functorOps folded "zipAsyncly folded" (==)
928 describe "Semigroup operations" $ do
929 serialOps $ semigroupOps "serially" (==)
930 wSerialOps $ semigroupOps "wSerially" (==)
931 aheadOps $ semigroupOps "aheadly" (==)
932 asyncOps $ semigroupOps "asyncly" sortEq
933 wAsyncOps $ semigroupOps "wAsyncly" sortEq
934 parallelOps $ semigroupOps "parallely" sortEq
935 zipSerialOps $ semigroupOps "zipSerially" (==)
936 zipAsyncOps $ semigroupOps "zipAsyncly" (==)
938 describe "Applicative operations" $ do
939 -- The tests using sorted equality are weaker tests
940 -- We need to have stronger unit tests for all those
941 -- XXX applicative with three arguments
942 serialOps $ prop "serially applicative" . applicativeOps S.fromFoldable (==)
943 serialOps $ prop "serially applicative folded" . applicativeOps folded (==)
944 wSerialOps $ prop "wSerially applicative" . applicativeOps S.fromFoldable sortEq
945 wSerialOps $ prop "wSerially applicative folded" . applicativeOps folded sortEq
946 aheadOps $ prop "aheadly applicative" . applicativeOps S.fromFoldable (==)
947 aheadOps $ prop "aheadly applicative folded" . applicativeOps folded (==)
948 asyncOps $ prop "asyncly applicative" . applicativeOps S.fromFoldable sortEq
949 asyncOps $ prop "asyncly applicative folded" . applicativeOps folded sortEq
950 wAsyncOps $ prop "wAsyncly applicative" . applicativeOps S.fromFoldable sortEq
951 wAsyncOps $ prop "wAsyncly applicative folded" . applicativeOps folded sortEq
952 parallelOps $ prop "parallely applicative folded" . applicativeOps folded sortEq
954 -- XXX add tests for indexed/indexedR
955 describe "Zip operations" $ do
956 zipSerialOps $ prop "zipSerially applicative" . zipApplicative S.fromFoldable (==)
957 zipSerialOps $ prop "zipSerially applicative folded" . zipApplicative folded (==)
958 zipAsyncOps $ prop "zipAsyncly applicative" . zipApplicative S.fromFoldable (==)
959 zipAsyncOps $ prop "zipAsyncly applicative folded" . zipApplicative folded (==)
961 -- We test only the serial zip with serial streams and the parallel
962 -- stream, because the rate setting in these streams can slow down
964 serialOps $ prop "zip monadic serially" . zipMonadic S.fromFoldable (==)
965 serialOps $ prop "zip monadic serially folded" . zipMonadic folded (==)
966 wSerialOps $ prop "zip monadic wSerially" . zipMonadic S.fromFoldable (==)
967 wSerialOps $ prop "zip monadic wSerially folded" . zipMonadic folded (==)
968 aheadOps $ prop "zip monadic aheadly" . zipAsyncMonadic S.fromFoldable (==)
969 aheadOps $ prop "zip monadic aheadly folded" . zipAsyncMonadic folded (==)
970 asyncOps $ prop "zip monadic asyncly" . zipAsyncMonadic S.fromFoldable (==)
971 asyncOps $ prop "zip monadic asyncly folded" . zipAsyncMonadic folded (==)
972 wAsyncOps $ prop "zip monadic wAsyncly" . zipAsyncMonadic S.fromFoldable (==)
973 wAsyncOps $ prop "zip monadic wAsyncly folded" . zipAsyncMonadic folded (==)
974 parallelOps $ prop "zip monadic parallely" . zipMonadic S.fromFoldable (==)
975 parallelOps $ prop "zip monadic parallely folded" . zipMonadic folded (==)
977 -- XXX add merge tests like zip tests
978 -- for mergeBy, we can split a list randomly into two lists and
979 -- then merge them, it should result in original list
980 -- describe "Merge operations" $ do
982 describe "Monad operations" $ do
983 serialOps $ prop "serially monad then" . monadThen S.fromFoldable (==)
984 wSerialOps $ prop "wSerially monad then" . monadThen S.fromFoldable sortEq
985 aheadOps $ prop "aheadly monad then" . monadThen S.fromFoldable (==)
986 asyncOps $ prop "asyncly monad then" . monadThen S.fromFoldable sortEq
987 wAsyncOps $ prop "wAsyncly monad then" . monadThen S.fromFoldable sortEq
988 parallelOps $ prop "parallely monad then" . monadThen S.fromFoldable sortEq
990 serialOps $ prop "serially monad then folded" . monadThen folded (==)
991 wSerialOps $ prop "wSerially monad then folded" . monadThen folded sortEq
992 aheadOps $ prop "aheadly monad then folded" . monadThen folded (==)
993 asyncOps $ prop "asyncly monad then folded" . monadThen folded sortEq
994 wAsyncOps $ prop "wAsyncly monad then folded" . monadThen folded sortEq
995 parallelOps $ prop "parallely monad then folded" . monadThen folded sortEq
997 serialOps $ prop "serially monad bind" . monadBind S.fromFoldable (==)
998 wSerialOps $ prop "wSerially monad bind" . monadBind S.fromFoldable sortEq
999 aheadOps $ prop "aheadly monad bind" . monadBind S.fromFoldable (==)
1000 asyncOps $ prop "asyncly monad bind" . monadBind S.fromFoldable sortEq
1001 wAsyncOps $ prop "wAsyncly monad bind" . monadBind S.fromFoldable sortEq
1002 parallelOps $ prop "parallely monad bind" . monadBind S.fromFoldable sortEq
1004 serialOps $ prop "serially monad bind folded" . monadBind folded (==)
1005 wSerialOps $ prop "wSerially monad bind folded" . monadBind folded sortEq
1006 aheadOps $ prop "aheadly monad bind folded" . monadBind folded (==)
1007 asyncOps $ prop "asyncly monad bind folded" . monadBind folded sortEq
1008 wAsyncOps $ prop "wAsyncly monad bind folded" . monadBind folded sortEq
1009 parallelOps $ prop "parallely monad bind folded" . monadBind folded sortEq
1011 -- These tests won't work with maxBuffer or maxThreads set to 1, so we
1012 -- exclude those cases from these.
1015#ifndef COVERAGE_BUILD
1016 , ("rate Nothing", t . rate Nothing)
1017 , ("maxBuffer 0", t . maxBuffer 0)
1018 , ("maxThreads 0", t . maxThreads 0)
1019 , ("maxThreads 0", t . maxThreads (-1))
1023 let forOps ops spec = forM_ ops (\(desc, f) -> describe desc $ spec f)
1024 describe "Stream concurrent operations" $ do
1025 forOps (mkOps aheadly) $ concurrentOps S.fromFoldable "aheadly" (==)
1026 forOps (mkOps asyncly) $ concurrentOps S.fromFoldable "asyncly" sortEq
1027 forOps (mkOps wAsyncly) $ concurrentOps S.fromFoldable "wAsyncly" sortEq
1028 forOps (mkOps parallely) $ concurrentOps S.fromFoldable "parallely" sortEq
1030 forOps (mkOps aheadly) $ concurrentOps folded "aheadly folded" (==)
1031 forOps (mkOps asyncly) $ concurrentOps folded "asyncly folded" sortEq
1032 forOps (mkOps wAsyncly) $ concurrentOps folded "wAsyncly folded" sortEq
1033 forOps (mkOps parallely) $ concurrentOps folded "parallely folded" sortEq
1035 describe "Concurrent application" $ do
1036 serialOps $ prop "serial" . concurrentApplication (==)
1037 asyncOps $ prop "async" . concurrentApplication sortEq
1038 aheadOps $ prop "ahead" . concurrentApplication (==)
1039 parallelOps $ prop "parallel" . concurrentApplication sortEq
1041 prop "concurrent foldr application" $ withMaxSuccess maxTestCount
1042 concurrentFoldrApplication
1043 prop "concurrent foldl application" $ withMaxSuccess maxTestCount
1044 concurrentFoldlApplication
1046 describe "Stream transform and combine operations" $ do
1047 serialOps $ transformCombineOpsCommon S.fromFoldable "serially" (==)
1048 wSerialOps $ transformCombineOpsCommon S.fromFoldable "wSerially" sortEq
1049 aheadOps $ transformCombineOpsCommon S.fromFoldable "aheadly" (==)
1050 asyncOps $ transformCombineOpsCommon S.fromFoldable "asyncly" sortEq
1051 wAsyncOps $ transformCombineOpsCommon S.fromFoldable "wAsyncly" sortEq
1052 parallelOps $ transformCombineOpsCommon S.fromFoldable "parallely" sortEq
1053 zipSerialOps $ transformCombineOpsCommon S.fromFoldable "zipSerially" (==)
1054 zipAsyncOps $ transformCombineOpsCommon S.fromFoldable "zipAsyncly" (==)
1056 serialOps $ transformCombineOpsCommon folded "serially" (==)
1057 wSerialOps $ transformCombineOpsCommon folded "wSerially" sortEq
1058 aheadOps $ transformCombineOpsCommon folded "aheadly" (==)
1059 asyncOps $ transformCombineOpsCommon folded "asyncly" sortEq
1060 wAsyncOps $ transformCombineOpsCommon folded "wAsyncly" sortEq
1061 parallelOps $ transformCombineOpsCommon folded "parallely" sortEq
1062 zipSerialOps $ transformCombineOpsCommon folded "zipSerially" (==)
1063 zipAsyncOps $ transformCombineOpsCommon folded "zipAsyncly" (==)
1065 serialOps $ transformCombineOpsOrdered S.fromFoldable "serially" (==)
1066 aheadOps $ transformCombineOpsOrdered S.fromFoldable "aheadly" (==)
1067 zipSerialOps $ transformCombineOpsOrdered S.fromFoldable "zipSerially" (==)
1068 zipAsyncOps $ transformCombineOpsOrdered S.fromFoldable "zipAsyncly" (==)
1070 serialOps $ transformCombineOpsOrdered folded "serially" (==)
1071 aheadOps $ transformCombineOpsOrdered folded "aheadly" (==)
1072 zipSerialOps $ transformCombineOpsOrdered folded "zipSerially" (==)
1073 zipAsyncOps $ transformCombineOpsOrdered folded "zipAsyncly" (==)
1075 describe "Stream elimination operations" $ do
1076 serialOps $ eliminationOps S.fromFoldable "serially"
1077 wSerialOps $ eliminationOps S.fromFoldable "wSerially"
1078 aheadOps $ eliminationOps S.fromFoldable "aheadly"
1079 asyncOps $ eliminationOps S.fromFoldable "asyncly"
1080 wAsyncOps $ eliminationOps S.fromFoldable "wAsyncly"
1081 parallelOps $ eliminationOps S.fromFoldable "parallely"
1082 zipSerialOps $ eliminationOps S.fromFoldable "zipSerially"
1083 zipAsyncOps $ eliminationOps S.fromFoldable "zipAsyncly"
1085 serialOps $ eliminationOps folded "serially folded"
1086 wSerialOps $ eliminationOps folded "wSerially folded"
1087 aheadOps $ eliminationOps folded "aheadly folded"
1088 asyncOps $ eliminationOps folded "asyncly folded"
1089 wAsyncOps $ eliminationOps folded "wAsyncly folded"
1090 parallelOps $ eliminationOps folded "parallely folded"
1091 zipSerialOps $ eliminationOps folded "zipSerially folded"
1092 zipAsyncOps $ eliminationOps folded "zipAsyncly folded"
1094 serialOps $ eliminationOpsWord8 S.fromFoldable "serially"
1095 wSerialOps $ eliminationOpsWord8 S.fromFoldable "wSerially"
1096 aheadOps $ eliminationOpsWord8 S.fromFoldable "aheadly"
1097 asyncOps $ eliminationOpsWord8 S.fromFoldable "asyncly"
1098 wAsyncOps $ eliminationOpsWord8 S.fromFoldable "wAsyncly"
1099 parallelOps $ eliminationOpsWord8 S.fromFoldable "parallely"
1100 zipSerialOps $ eliminationOpsWord8 S.fromFoldable "zipSerially"
1101 zipAsyncOps $ eliminationOpsWord8 S.fromFoldable "zipAsyncly"
1103 serialOps $ eliminationOpsWord8 folded "serially folded"
1104 wSerialOps $ eliminationOpsWord8 folded "wSerially folded"
1105 aheadOps $ eliminationOpsWord8 folded "aheadly folded"
1106 asyncOps $ eliminationOpsWord8 folded "asyncly folded"
1107 wAsyncOps $ eliminationOpsWord8 folded "wAsyncly folded"
1108 parallelOps $ eliminationOpsWord8 folded "parallely folded"
1109 zipSerialOps $ eliminationOpsWord8 folded "zipSerially folded"
1110 zipAsyncOps $ eliminationOpsWord8 folded "zipAsyncly folded"
1112 -- XXX Add a test where we chain all transformation APIs and make sure that
1113 -- the state is being passed through all of them.
1114 describe "Stream serial elimination operations" $ do
1115 serialOps $ eliminationOpsOrdered S.fromFoldable "serially"
1116 wSerialOps $ eliminationOpsOrdered S.fromFoldable "wSerially"
1117 aheadOps $ eliminationOpsOrdered S.fromFoldable "aheadly"
1118 zipSerialOps $ eliminationOpsOrdered S.fromFoldable "zipSerially"
1119 zipAsyncOps $ eliminationOpsOrdered S.fromFoldable "zipAsyncly"
1121 serialOps $ eliminationOpsOrdered folded "serially folded"
1122 wSerialOps $ eliminationOpsOrdered folded "wSerially folded"
1123 aheadOps $ eliminationOpsOrdered folded "aheadly folded"
1124 zipSerialOps $ eliminationOpsOrdered folded "zipSerially folded"
1125 zipAsyncOps $ eliminationOpsOrdered folded "zipAsyncly folded"
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list