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, intersperse, foldl1', (\\))
17import Data.Maybe (mapMaybe)
18import GHC.Word (Word8)
20import Test.Hspec.QuickCheck
21import Test.QuickCheck (counterexample, Property, withMaxSuccess)
22import Test.QuickCheck.Monadic (run, monadicIO, monitor, assert, PropertyM)
27import Streamly.Prelude ((.:), nil)
28import qualified Streamly.Prelude as S
30-- Coverage build takes too long with default number of tests
38singleton :: IsStream t => a -> t m a
41sortEq :: Ord a => [a] -> [a] -> Bool
42sortEq a b = sort a == sort b
46 => (a -> a -> Bool) -> a -> a -> PropertyM m ()
47equals eq stream list = do
48 when (not $ stream `eq` list) $
51 "stream " <> show stream
52 <> "\nlist " <> show list
54 assert (stream `eq` list)
57 :: (Show a, Eq a, MonadIO m)
58 => ([a] -> [a] -> Bool) -> [a] -> [a] -> PropertyM m ()
59listEquals eq stream list = do
60 when (not $ stream `eq` list) $ liftIO $ putStrLn $
61 "stream " <> show stream
62 <> "\nlist " <> show list
63 <> "\nstream \\\\ list " <> show (stream \\ list)
64 <> "\nlist \\\\ stream " <> show (list \\ stream)
65 when (not $ stream `eq` list) $
68 "stream " <> show stream
69 <> "\nlist " <> show list
70 <> "\nstream \\\\ list " <> show (stream \\ list)
71 <> "\nlist \\\\ stream " <> show (list \\ stream)
73 assert (stream `eq` list)
75constructWithReplicateM
77 => (t IO Int -> SerialT IO Int)
80constructWithReplicateM op len = withMaxSuccess maxTestCount $
82 let x = return (1 :: Int)
83 stream <- run $ (S.toList . op) (S.replicateM (fromIntegral len) x)
84 list <- run $ replicateM (fromIntegral len) x
85 listEquals (==) stream list
90 -> ([b] -> [b] -> Bool)
92 -> (t IO a -> SerialT IO b)
95transformFromList constr eq listOp op a =
97 stream <- run ((S.toList . op) (constr a))
99 listEquals eq stream list
101mvarExcHandler :: String -> BlockedIndefinitelyOnMVar -> IO ()
102mvarExcHandler label BlockedIndefinitelyOnMVar =
103 error $ label <> " " <> "BlockedIndefinitelyOnMVar\n"
105stmExcHandler :: String -> BlockedIndefinitelyOnSTM -> IO ()
106stmExcHandler label BlockedIndefinitelyOnSTM =
107 error $ label <> " " <> "BlockedIndefinitelyOnSTM\n"
109dbgMVar :: String -> IO () -> IO ()
110dbgMVar label action =
111 action `catches` [ Handler (mvarExcHandler label)
112 , Handler (stmExcHandler label)
115-- | first n actions takeMVar and the last action performs putMVar n times
116mvarSequenceOp :: MVar () -> Word8 -> Word8 -> IO Word8
117mvarSequenceOp mv n x = do
118 let msg = show x <> "/" <> show n
120 then dbgMVar ("take mvarSequenceOp " <> msg) (takeMVar mv) >> return x
121 else dbgMVar ("put mvarSequenceOp" <> msg)
122 (replicateM_ (fromIntegral n) (putMVar mv ())) >> return x
125 :: ([Word8] -> t IO Word8)
126 -> ([Word8] -> [Word8] -> Bool)
127 -> (Word8 -> MVar () -> t IO Word8 -> SerialT IO Word8)
130concurrentMapM constr eq op n =
134 mv <- newEmptyMVar :: IO (MVar ())
135 (S.toList . op n mv) (constr list)
136 listEquals eq stream list
138concurrentFromFoldable
140 => ([Word8] -> [Word8] -> Bool)
141 -> (t IO Word8 -> SerialT IO Word8)
144concurrentFromFoldable eq op n =
148 mv <- newEmptyMVar :: IO (MVar ())
149 (S.toList . op) (S.fromFoldableM (fmap (mvarSequenceOp mv n) list))
150 listEquals eq stream list
152sourceUnfoldrM :: IsStream t => MVar () -> Word8 -> t IO Word8
153sourceUnfoldrM mv n = S.unfoldrM step 0
155 -- argument must be integer to avoid overflow of word8 at 255
156 step :: Int -> IO (Maybe (Word8, Int))
158 let msg = show cnt <> "/" <> show n
159 if cnt > fromIntegral n
162 dbgMVar ("put sourceUnfoldrM " <> msg) (putMVar mv ())
163 return (Just (fromIntegral cnt, cnt + 1))
165-- Note that this test is not guaranteed to succeed, because there is no
166-- guarantee of parallelism in case of Async/Ahead streams.
169 => ([Word8] -> [Word8] -> Bool)
170 -> (t IO Word8 -> SerialT IO Word8)
173concurrentUnfoldrM eq op n =
175 -- XXX we should test empty list case as well
178 -- putStrLn $ "concurrentUnfoldrM: " <> show n
179 mv <- newEmptyMVar :: IO (MVar ())
181 -- since unfoldr happens in parallel with the stream processing we
182 -- can do two takeMVar in one iteration. If it is not parallel then
183 -- this will not work and the test will fail.
185 x <- op (sourceUnfoldrM mv n)
186 -- results may not be yielded in order, in case of
187 -- Async/WAsync/Parallel. So we use an increasing count
189 i <- S.yieldM $ readIORef cnt
190 S.yieldM $ modifyIORef cnt (+1)
191 let msg = show i <> "/" <> show n
194 dbgMVar ("first take concurrentUnfoldrM " <> msg)
197 dbgMVar ("second take concurrentUnfoldrM " <> msg)
200 listEquals eq stream list
202concurrentApplication :: IsStream t
203 => ([Word8] -> [Word8] -> Bool)
204 -> (t IO Word8 -> SerialT IO Word8)
207concurrentApplication eq t n = withMaxSuccess maxTestCount $
209 -- XXX we should test empty list case as well
212 -- putStrLn $ "concurrentApplication: " <> show n
213 mv <- newEmptyMVar :: IO (MVar ())
214 -- since unfoldr happens in parallel with the stream processing we
215 -- can do two takeMVar in one iteration. If it is not parallel then
216 -- this will not work and the test will fail.
218 sourceUnfoldrM mv n |&
220 let msg = show x <> "/" <> show n
222 dbgMVar ("first take concurrentApp " <> msg)
225 dbgMVar ("second take concurrentApp " <> msg)
228 listEquals eq stream list
230sourceUnfoldrM1 :: IsStream t => Word8 -> t IO Word8
231sourceUnfoldrM1 n = S.unfoldrM step 0
233 -- argument must be integer to avoid overflow of word8 at 255
234 step :: Int -> IO (Maybe (Word8, Int))
236 if cnt > fromIntegral n
238 else return (Just (fromIntegral cnt, cnt + 1))
240concurrentFoldlApplication :: Word8 -> Property
241concurrentFoldlApplication n =
243 -- XXX we should test empty list case as well
246 sourceUnfoldrM1 n |&. S.foldlM' (\xs x -> return (x : xs)) []
247 listEquals (==) (reverse stream) list
249concurrentFoldrApplication :: Word8 -> Property
250concurrentFoldrApplication n =
252 -- XXX we should test empty list case as well
255 sourceUnfoldrM1 n |&. S.foldrM (\x xs -> return (x : xs)) []
256 listEquals (==) stream list
258transformCombineFromList
259 :: Semigroup (t IO Int)
260 => ([Int] -> t IO Int)
261 -> ([Int] -> [Int] -> Bool)
263 -> (t IO Int -> SerialT IO Int)
264 -> (t IO Int -> t IO Int)
269transformCombineFromList constr eq listOp t op a b c =
270 withMaxSuccess maxTestCount $
272 stream <- run ((S.toList . t) $
273 constr a <> op (constr b <> constr c))
274 let list = a <> listOp (b <> c)
275 listEquals eq stream list
278 :: ([Int] -> t IO Int)
279 -> (t IO Int -> SerialT IO Int)
280 -> ([Int] -> [Int] -> Bool)
283foldFromList constr op eq = transformFromList constr eq id op
292eliminateOp constr listOp op a =
294 stream <- run $ op (constr a)
296 equals (==) stream list
299 :: ([Word8] -> t IO Word8)
300 -> (t IO Word8 -> SerialT IO Word8)
301 -> (Word8 -> SerialT IO Word8 -> IO Bool)
302 -> (Word8 -> [Word8] -> Bool)
305elemOp constr op streamOp listOp (x, xs) =
307 stream <- run $ (streamOp x . op) (constr xs)
308 let list = listOp x xs
309 equals (==) stream list
313 => ([Int] -> t IO Int)
315 -> ([Int] -> [Int] -> Bool)
316 -> (t IO Int -> SerialT IO Int)
318functorOps constr desc eq t = do
319 prop (desc <> " id") $ transformFromList constr eq id t
320 prop (desc <> " fmap (+1)") $ transformFromList constr eq (fmap (+1)) $ t . fmap (+1)
324 => ([Int] -> t IO Int)
326 -> ([Int] -> [Int] -> Bool)
327 -> (t IO Int -> SerialT IO Int)
329transformOps constr desc eq t = do
330 let transform = transformFromList constr eq
332 prop (desc <> " filter False") $
333 transform (filter (const False)) $ t . S.filter (const False)
334 prop (desc <> " filter True") $
335 transform (filter (const True)) $ t . S.filter (const True)
336 prop (desc <> " filter even") $
337 transform (filter even) $ t . S.filter even
339 prop (desc <> " take maxBound") $
340 transform (take maxBound) $ t . S.take maxBound
341 prop (desc <> " take 0") $ transform (take 0) $ t . S.take 0
342 prop (desc <> " take 1") $ transform (take 1) $ t . S.take 1
343 prop (desc <> " take 10") $ transform (take 10) $ t . S.take 10
345 prop (desc <> " takeWhile True") $
346 transform (takeWhile (const True)) $ t . S.takeWhile (const True)
347 prop (desc <> " takeWhile False") $
348 transform (takeWhile (const False)) $ t . S.takeWhile (const False)
349 prop (desc <> " takeWhile > 0") $
350 transform (takeWhile (> 0)) $ t . S.takeWhile (> 0)
352 let f x = if odd x then Just (x + 100) else Nothing
353 prop (desc <> " mapMaybe") $ transform (mapMaybe f) $ t . S.mapMaybe f
355 prop (desc <> " drop maxBound") $
356 transform (drop maxBound) $ t . S.drop maxBound
357 prop (desc <> " drop 0") $ transform (drop 0) $ t . S.drop 0
358 prop (desc <> " drop 1") $ transform (drop 1) $ t . S.drop 1
359 prop (desc <> " drop 10") $ transform (drop 10) $ t . S.drop 10
361 prop (desc <> " dropWhile True") $
362 transform (dropWhile (const True)) $ t . S.dropWhile (const True)
363 prop (desc <> " dropWhile False") $
364 transform (dropWhile (const False)) $ t . S.dropWhile (const False)
365 prop (desc <> " dropWhile > 0") $
366 transform (dropWhile (> 0)) $ t . S.dropWhile (> 0)
367 prop (desc <> " scan") $ transform (scanl' (+) 0) $ t . S.scanl' (+) 0
368 prop (desc <> " reverse") $ transform reverse $ t . S.reverse
370 prop (desc <> " findIndices") $ transform (findIndices odd) $ t . S.findIndices odd
371 prop (desc <> " elemIndices") $ transform (elemIndices 3) $ t . S.elemIndices 3
373 prop (desc <> " intersperseM") $ transform (intersperse 3) $ t . S.intersperseM (return 3)
378 => ([Word8] -> t IO Word8)
380 -> ([Word8] -> [Word8] -> Bool)
381 -> (t IO Word8 -> SerialT IO Word8)
383concurrentOps constr desc eq t = do
384 let prop1 d p = prop d $ withMaxSuccess maxTestCount p
386 prop1 (desc <> " fromFoldableM") $ concurrentFromFoldable eq t
387 prop1 (desc <> " unfoldrM") $ concurrentUnfoldrM eq t
388 -- we pass it the length of the stream n and an mvar mv.
389 -- The stream is [0..n]. The threads communicate in such a way that the
390 -- actions coming first in the stream are dependent on the last action. So
391 -- if the stream is not processed concurrently it will block forever.
392 -- Note that if the size of the stream is bigger than the thread limit
393 -- then it will block even if it is concurrent.
394 prop1 (desc <> " mapM") $
395 concurrentMapM constr eq $ \n mv stream ->
396 t $ S.mapM (mvarSequenceOp mv n) stream
398-- XXX add tests for MonadReader and MonadError etc. In case an SVar is
399-- accidentally passed through them.
400transformCombineOpsCommon
401 :: (IsStream t, Semigroup (t IO Int))
402 => ([Int] -> t IO Int)
404 -> ([Int] -> [Int] -> Bool)
405 -> (t IO Int -> SerialT IO Int)
407transformCombineOpsCommon constr desc eq t = do
408 let transform = transformCombineFromList constr eq
410 prop (desc <> " filter False") $
411 transform (filter (const False)) t (S.filter (const False))
412 prop (desc <> " filter True") $
413 transform (filter (const True)) t (S.filter (const True))
414 prop (desc <> " filter even") $
415 transform (filter even) t (S.filter even)
417 prop (desc <> " filterM False") $
418 transform (filter (const False)) t (S.filterM (const $ return False))
419 prop (desc <> " filterM True") $
420 transform (filter (const True)) t (S.filterM (const $ return True))
421 prop (desc <> " filterM even") $
422 transform (filter even) t (S.filterM (return . even))
424 prop (desc <> " take maxBound") $
425 transform (take maxBound) t (S.take maxBound)
426 prop (desc <> " take 0") $ transform (take 0) t (S.take 0)
428 prop (desc <> " takeWhile True") $
429 transform (takeWhile (const True)) t (S.takeWhile (const True))
430 prop (desc <> " takeWhile False") $
431 transform (takeWhile (const False)) t (S.takeWhile (const False))
433 prop (desc <> " takeWhileM True") $
434 transform (takeWhile (const True)) t (S.takeWhileM (const $ return True))
435 prop (desc <> " takeWhileM False") $
436 transform (takeWhile (const False)) t (S.takeWhileM (const $ return False))
438 prop (desc <> " drop maxBound") $
439 transform (drop maxBound) t (S.drop maxBound)
440 prop (desc <> " drop 0") $ transform (drop 0) t (S.drop 0)
442 prop (desc <> " dropWhile True") $
443 transform (dropWhile (const True)) t (S.dropWhile (const True))
444 prop (desc <> " dropWhile False") $
445 transform (dropWhile (const False)) t (S.dropWhile (const False))
447 prop (desc <> " dropWhileM True") $
448 transform (dropWhile (const True)) t (S.dropWhileM (const $ return True))
449 prop (desc <> " dropWhileM False") $
450 transform (dropWhile (const False)) t (S.dropWhileM (const $ return False))
452 prop (desc <> " mapM (+1)") $
453 transform (fmap (+1)) t (S.mapM (\x -> return (x + 1)))
455 prop (desc <> " scan") $ transform (scanl' (flip const) 0) t
456 (S.scanl' (flip const) 0)
457 prop (desc <> " scanlM'") $ transform (scanl' (flip const) 0) t
458 (S.scanlM' (\_ a -> return a) 0)
459 prop (desc <> " reverse") $ transform reverse t S.reverse
461 prop (desc <> " intersperseM") $
462 transform (intersperse 3) t (S.intersperseM $ return 3)
464transformCombineOpsOrdered
465 :: (IsStream t, Semigroup (t IO Int))
466 => ([Int] -> t IO Int)
468 -> ([Int] -> [Int] -> Bool)
469 -> (t IO Int -> SerialT IO Int)
471transformCombineOpsOrdered constr desc eq t = do
472 let transform = transformCombineFromList constr eq
474 prop (desc <> " take 1") $ transform (take 1) t (S.take 1)
476 prop (desc <> " take 2") $ transform (take 2) t (S.take 2)
477 prop (desc <> " take 3") $ transform (take 3) t (S.take 3)
478 prop (desc <> " take 4") $ transform (take 4) t (S.take 4)
479 prop (desc <> " take 5") $ transform (take 5) t (S.take 5)
481 prop (desc <> " take 10") $ transform (take 10) t (S.take 10)
483 prop (desc <> " takeWhile > 0") $
484 transform (takeWhile (> 0)) t (S.takeWhile (> 0))
486 prop (desc <> " drop 1") $ transform (drop 1) t (S.drop 1)
487 prop (desc <> " drop 10") $ transform (drop 10) t (S.drop 10)
489 prop (desc <> " dropWhile > 0") $
490 transform (dropWhile (> 0)) t (S.dropWhile (> 0))
491 prop (desc <> " scan") $ transform (scanl' (+) 0) t (S.scanl' (+) 0)
493 -- XXX this does not fail when the SVar is shared, need to fix.
494 prop (desc <> " concurrent application") $
495 transform (& fmap (+1)) t (|& S.map (+1))
497 prop (desc <> " findIndices") $
498 transform (findIndices odd) t (S.findIndices odd)
499 prop (desc <> " elemIndices") $
500 transform (elemIndices 0) t (S.elemIndices 0)
502wrapMaybe :: ([a1] -> a2) -> [a1] -> Maybe a2
503wrapMaybe f x = if null x then Nothing else Just (f x)
506 :: ([Int] -> t IO Int)
508 -> (t IO Int -> SerialT IO Int)
510eliminationOps constr desc t = do
512 prop (desc <> " null") $ eliminateOp constr null $ S.null . t
513 prop (desc <> " foldl'") $
514 eliminateOp constr (foldl' (+) 0) $ S.foldl' (+) 0 . t
515 prop (desc <> " foldl1'") $
516 eliminateOp constr (wrapMaybe $ foldl1' (+)) $ S.foldl1' (+) . t
517 prop (desc <> " foldr1") $
518 eliminateOp constr (wrapMaybe $ foldr1 (+)) $ S.foldr1 (+) . t
519 prop (desc <> " all") $ eliminateOp constr (all even) $ S.all even . t
520 prop (desc <> " any") $ eliminateOp constr (any even) $ S.any even . t
521 prop (desc <> " and") $ eliminateOp constr (and . fmap (> 0)) $
522 (S.and . S.map (> 0)) . t
523 prop (desc <> " or") $ eliminateOp constr (or . fmap (> 0)) $
524 (S.or . S.map (> 0)) . t
525 prop (desc <> " length") $ eliminateOp constr length $ S.length . t
526 prop (desc <> " sum") $ eliminateOp constr sum $ S.sum . t
527 prop (desc <> " product") $ eliminateOp constr product $ S.product . t
529 prop (desc <> " maximum") $ eliminateOp constr (wrapMaybe maximum) $ S.maximum . t
530 prop (desc <> " minimum") $ eliminateOp constr (wrapMaybe minimum) $ S.minimum . t
532 prop (desc <> " findIndex") $ eliminateOp constr (findIndex odd) $ S.findIndex odd . t
533 prop (desc <> " elemIndex") $ eliminateOp constr (elemIndex 3) $ S.elemIndex 3 . t
535 prop (desc <> " find") $ eliminateOp constr (find even) $ S.find even . t
536 prop (desc <> " lookup") $
537 eliminateOp constr (lookup 3 . flip zip [1..]) $
538 S.lookup 3 . S.zipWith (\a b -> (b, a)) (S.fromList [(1::Int)..]) . t
540-- head/tail/last may depend on the order in case of parallel streams
541-- so we test these only for serial streams.
543 :: ([Int] -> t IO Int)
545 -> (t IO Int -> SerialT IO Int)
547serialEliminationOps constr desc t = do
548 prop (desc <> " head") $ eliminateOp constr (wrapMaybe head) $ S.head . t
549 prop (desc <> " tail") $ eliminateOp constr (wrapMaybe tail) $ \x -> do
552 Nothing -> return Nothing
553 Just s -> Just <$> S.toList s
554 prop (desc <> " last") $ eliminateOp constr (wrapMaybe last) $ S.last . t
555 prop (desc <> " init") $ eliminateOp constr (wrapMaybe init) $ \x -> do
558 Nothing -> return Nothing
559 Just s -> Just <$> S.toList s
562 :: ([Word8] -> t IO Word8)
564 -> (t IO Word8 -> SerialT IO Word8)
566transformOpsWord8 constr desc t = do
567 prop (desc <> " elem") $ elemOp constr t S.elem elem
568 prop (desc <> " elem") $ elemOp constr t S.notElem notElem
570-- XXX concatenate streams of multiple elements rather than single elements
574#if __GLASGOW_HASKELL__ < 804
575 , Semigroup (t IO Int)
579 -> ([Int] -> [Int] -> Bool)
580 -> (t IO Int -> SerialT IO Int)
582semigroupOps desc eq t = do
583 prop (desc <> " <>") $ foldFromList (foldMapWith (<>) singleton) t eq
584 prop (desc <> " mappend") $ foldFromList (foldMapWith mappend singleton) t eq
587 :: Applicative (t IO)
588 => ([Int] -> t IO Int)
589 -> ([(Int, Int)] -> [(Int, Int)] -> Bool)
590 -> (t IO (Int, Int) -> SerialT IO (Int, Int))
593applicativeOps constr eq t (a, b) = withMaxSuccess maxTestCount $
595 stream <- run ((S.toList . t) ((,) <$> constr a <*> constr b))
596 let list = (,) <$> a <*> b
597 listEquals eq stream list
600 :: (IsStream t, Applicative (t IO))
601 => ([Int] -> t IO Int)
602 -> ([(Int, Int)] -> [(Int, Int)] -> Bool)
603 -> (t IO (Int, Int) -> SerialT IO (Int, Int))
606zipApplicative constr eq t (a, b) = withMaxSuccess maxTestCount $
608 stream1 <- run ((S.toList . t) ((,) <$> constr a <*> constr b))
609 stream2 <- run ((S.toList . t) (pure (,) <*> constr a <*> constr b))
610 stream3 <- run ((S.toList . t) (S.zipWith (,) (constr a) (constr b)))
611 let list = getZipList $ (,) <$> ZipList a <*> ZipList b
612 listEquals eq stream1 list
613 listEquals eq stream2 list
614 listEquals eq stream3 list
618 => ([Int] -> t IO Int)
619 -> ([(Int, Int)] -> [(Int, Int)] -> Bool)
620 -> (t IO (Int, Int) -> SerialT IO (Int, Int))
623zipMonadic constr eq t (a, b) = withMaxSuccess maxTestCount $
628 (S.zipWithM (curry return) (constr a) (constr b)))
629 let list = getZipList $ (,) <$> ZipList a <*> ZipList b
630 listEquals eq stream1 list
634 => ([Int] -> t IO Int)
635 -> ([(Int, Int)] -> [(Int, Int)] -> Bool)
636 -> (t IO (Int, Int) -> SerialT IO (Int, Int))
639zipAsyncMonadic constr eq t (a, b) = withMaxSuccess maxTestCount $
644 (S.zipWithM (curry return) (constr a) (constr b)))
648 (S.zipAsyncWithM (curry return) (constr a) (constr b)))
649 let list = getZipList $ (,) <$> ZipList a <*> ZipList b
650 listEquals eq stream1 list
651 listEquals eq stream2 list
655 => ([Int] -> t IO Int)
656 -> ([Int] -> [Int] -> Bool)
657 -> (t IO Int -> SerialT IO Int)
660monadThen constr eq t (a, b) = withMaxSuccess maxTestCount $ monadicIO $ do
661 stream <- run ((S.toList . t) (constr a >> constr b))
663 listEquals eq stream list
667 => ([Int] -> t IO Int)
668 -> ([Int] -> [Int] -> Bool)
669 -> (t IO Int -> SerialT IO Int)
672monadBind constr eq t (a, b) = withMaxSuccess maxTestCount $
677 (constr a >>= \x -> (+ x) <$> constr b))
678 let list = a >>= \x -> (+ x) <$> b
679 listEquals eq stream list
681constructWithIterate :: IsStream t => (t IO Int -> SerialT IO Int) -> Spec
682constructWithIterate t = do
684 (S.toList . t . S.take 100) (S.iterate (+ 1) (0 :: Int))
685 `shouldReturn` take 100 (iterate (+ 1) 0)
687 let addM y = return (y + 1)
688 S.toList . t . S.take 100 $ S.iterateM addM (0 :: Int)
689 `shouldReturn` take 100 (iterate (+ 1) 0)
695 $ modifyMaxSuccess (const 10)
698 let folded :: IsStream t => [a] -> t IO a
699 folded = serially . (\xs ->
701 [x] -> return x -- singleton stream case
702 _ -> foldMapWith (<>) return xs
707#ifndef COVERAGE_BUILD
708 , ("rate AvgRate 10000", t . avgRate 10000)
709 , ("rate Nothing", t . rate Nothing)
710 , ("maxBuffer 0", t . maxBuffer 0)
711 , ("maxBuffer 1", t . maxBuffer 1)
712 , ("maxThreads 0", t . maxThreads 0)
713 , ("maxThreads 1", t . maxThreads 1)
714 , ("maxThreads -1", t . maxThreads (-1))
718 let mapOps spec = mapM_ (\(desc, f) -> describe desc $ spec f)
719 let serialOps :: IsStream t => ((SerialT IO a -> t IO a) -> Spec) -> Spec
720 serialOps spec = mapOps spec $ makeOps serially
721#ifndef COVERAGE_BUILD
722 <> [("rate AvgRate 0.00000001", serially . avgRate 0.00000001)]
723 <> [("maxBuffer -1", serially . maxBuffer (-1))]
725 let wSerialOps :: IsStream t => ((WSerialT IO a -> t IO a) -> Spec) -> Spec
726 wSerialOps spec = mapOps spec $ makeOps wSerially
727#ifndef COVERAGE_BUILD
728 <> [("rate AvgRate 0.00000001", wSerially . avgRate 0.00000001)]
729 <> [("maxBuffer (-1)", wSerially . maxBuffer (-1))]
731 let asyncOps :: IsStream t => ((AsyncT IO a -> t IO a) -> Spec) -> Spec
732 asyncOps spec = mapOps spec $ makeOps asyncly
733#ifndef COVERAGE_BUILD
734 <> [("maxBuffer (-1)", asyncly . maxBuffer (-1))]
736 let wAsyncOps :: IsStream t => ((WAsyncT IO a -> t IO a) -> Spec) -> Spec
737 wAsyncOps spec = mapOps spec $ makeOps wAsyncly
738#ifndef COVERAGE_BUILD
739 <> [("maxBuffer (-1)", wAsyncly . maxBuffer (-1))]
741 let aheadOps :: IsStream t => ((AheadT IO a -> t IO a) -> Spec) -> Spec
742 aheadOps spec = mapOps spec $ makeOps aheadly
743#ifndef COVERAGE_BUILD
744 <> [("maxBuffer (-1)", aheadly . maxBuffer (-1))]
746 let parallelOps :: IsStream t => ((ParallelT IO a -> t IO a) -> Spec) -> Spec
747 parallelOps spec = mapOps spec $ makeOps parallely
748#ifndef COVERAGE_BUILD
749 <> [("rate AvgRate 0.00000001", parallely . avgRate 0.00000001)]
750 <> [("maxBuffer (-1)", parallely . maxBuffer (-1))]
752 let zipSerialOps :: IsStream t => ((ZipSerialM IO a -> t IO a) -> Spec) -> Spec
753 zipSerialOps spec = mapOps spec $ makeOps zipSerially
754#ifndef COVERAGE_BUILD
755 <> [("rate AvgRate 0.00000001", zipSerially . avgRate 0.00000001)]
756 <> [("maxBuffer (-1)", zipSerially . maxBuffer (-1))]
758 -- Note, the "pure" of applicative Zip streams generates and infinite
759 -- stream and therefore maxBuffer (-1) must not be used for that case.
760 let zipAsyncOps :: IsStream t => ((ZipAsyncM IO a -> t IO a) -> Spec) -> Spec
761 zipAsyncOps spec = mapOps spec $ makeOps zipAsyncly
763 describe "Construction" $ do
764 serialOps $ prop "serially replicateM" . constructWithReplicateM
765 wSerialOps $ prop "wSerially replicateM" . constructWithReplicateM
766 aheadOps $ prop "aheadly replicateM" . constructWithReplicateM
767 asyncOps $ prop "asyncly replicateM" . constructWithReplicateM
768 wAsyncOps $ prop "wAsyncly replicateM" . constructWithReplicateM
769 parallelOps $ prop "parallely replicateM" . constructWithReplicateM
770 -- XXX test for all types of streams
771 constructWithIterate serially
773 describe "Functor operations" $ do
774 serialOps $ functorOps S.fromFoldable "serially" (==)
775 serialOps $ functorOps folded "serially folded" (==)
776 wSerialOps $ functorOps S.fromFoldable "wSerially" (==)
777 wSerialOps $ functorOps folded "wSerially folded" (==)
778 aheadOps $ functorOps S.fromFoldable "aheadly" (==)
779 aheadOps $ functorOps folded "aheadly folded" (==)
780 asyncOps $ functorOps S.fromFoldable "asyncly" sortEq
781 asyncOps $ functorOps folded "asyncly folded" sortEq
782 wAsyncOps $ functorOps S.fromFoldable "wAsyncly" sortEq
783 wAsyncOps $ functorOps folded "wAsyncly folded" sortEq
784 parallelOps $ functorOps S.fromFoldable "parallely" sortEq
785 parallelOps $ functorOps folded "parallely folded" sortEq
786 zipSerialOps $ functorOps S.fromFoldable "zipSerially" (==)
787 zipSerialOps $ functorOps folded "zipSerially folded" (==)
788 zipAsyncOps $ functorOps S.fromFoldable "zipAsyncly" (==)
789 zipAsyncOps $ functorOps folded "zipAsyncly folded" (==)
791 describe "Semigroup operations" $ do
792 serialOps $ semigroupOps "serially" (==)
793 wSerialOps $ semigroupOps "wSerially" (==)
794 aheadOps $ semigroupOps "aheadly" (==)
795 asyncOps $ semigroupOps "asyncly" sortEq
796 wAsyncOps $ semigroupOps "wAsyncly" sortEq
797 parallelOps $ semigroupOps "parallely" sortEq
798 zipSerialOps $ semigroupOps "zipSerially" (==)
799 zipAsyncOps $ semigroupOps "zipAsyncly" (==)
801 describe "Applicative operations" $ do
802 -- The tests using sorted equality are weaker tests
803 -- We need to have stronger unit tests for all those
804 -- XXX applicative with three arguments
805 serialOps $ prop "serially applicative" . applicativeOps S.fromFoldable (==)
806 serialOps $ prop "serially applicative folded" . applicativeOps folded (==)
807 wSerialOps $ prop "wSerially applicative" . applicativeOps S.fromFoldable sortEq
808 wSerialOps $ prop "wSerially applicative folded" . applicativeOps folded sortEq
809 aheadOps $ prop "aheadly applicative" . applicativeOps S.fromFoldable (==)
810 aheadOps $ prop "aheadly applicative folded" . applicativeOps folded (==)
811 asyncOps $ prop "asyncly applicative" . applicativeOps S.fromFoldable sortEq
812 asyncOps $ prop "asyncly applicative folded" . applicativeOps folded sortEq
813 wAsyncOps $ prop "wAsyncly applicative" . applicativeOps S.fromFoldable sortEq
814 wAsyncOps $ prop "wAsyncly applicative folded" . applicativeOps folded sortEq
815 parallelOps $ prop "parallely applicative folded" . applicativeOps folded sortEq
817 describe "Zip operations" $ do
818 zipSerialOps $ prop "zipSerially applicative" . zipApplicative S.fromFoldable (==)
819 zipSerialOps $ prop "zipSerially applicative folded" . zipApplicative folded (==)
820 zipAsyncOps $ prop "zipAsyncly applicative" . zipApplicative S.fromFoldable (==)
821 zipAsyncOps $ prop "zipAsyncly applicative folded" . zipApplicative folded (==)
823 -- We test only the serial zip with serial streams and the parallel
824 -- stream, because the rate setting in these streams can slow down
826 serialOps $ prop "zip monadic serially" . zipMonadic S.fromFoldable (==)
827 serialOps $ prop "zip monadic serially folded" . zipMonadic folded (==)
828 wSerialOps $ prop "zip monadic wSerially" . zipMonadic S.fromFoldable (==)
829 wSerialOps $ prop "zip monadic wSerially folded" . zipMonadic folded (==)
830 aheadOps $ prop "zip monadic aheadly" . zipAsyncMonadic S.fromFoldable (==)
831 aheadOps $ prop "zip monadic aheadly folded" . zipAsyncMonadic folded (==)
832 asyncOps $ prop "zip monadic asyncly" . zipAsyncMonadic S.fromFoldable (==)
833 asyncOps $ prop "zip monadic asyncly folded" . zipAsyncMonadic folded (==)
834 wAsyncOps $ prop "zip monadic wAsyncly" . zipAsyncMonadic S.fromFoldable (==)
835 wAsyncOps $ prop "zip monadic wAsyncly folded" . zipAsyncMonadic folded (==)
836 parallelOps $ prop "zip monadic parallely" . zipMonadic S.fromFoldable (==)
837 parallelOps $ prop "zip monadic parallely folded" . zipMonadic folded (==)
839 describe "Monad operations" $ do
840 serialOps $ prop "serially monad then" . monadThen S.fromFoldable (==)
841 wSerialOps $ prop "wSerially monad then" . monadThen S.fromFoldable sortEq
842 aheadOps $ prop "aheadly monad then" . monadThen S.fromFoldable (==)
843 asyncOps $ prop "asyncly monad then" . monadThen S.fromFoldable sortEq
844 wAsyncOps $ prop "wAsyncly monad then" . monadThen S.fromFoldable sortEq
845 parallelOps $ prop "parallely monad then" . monadThen S.fromFoldable sortEq
847 serialOps $ prop "serially monad then folded" . monadThen folded (==)
848 wSerialOps $ prop "wSerially monad then folded" . monadThen folded sortEq
849 aheadOps $ prop "aheadly monad then folded" . monadThen folded (==)
850 asyncOps $ prop "asyncly monad then folded" . monadThen folded sortEq
851 wAsyncOps $ prop "wAsyncly monad then folded" . monadThen folded sortEq
852 parallelOps $ prop "parallely monad then folded" . monadThen folded sortEq
854 serialOps $ prop "serially monad bind" . monadBind S.fromFoldable (==)
855 wSerialOps $ prop "wSerially monad bind" . monadBind S.fromFoldable sortEq
856 aheadOps $ prop "aheadly monad bind" . monadBind S.fromFoldable (==)
857 asyncOps $ prop "asyncly monad bind" . monadBind S.fromFoldable sortEq
858 wAsyncOps $ prop "wAsyncly monad bind" . monadBind S.fromFoldable sortEq
859 parallelOps $ prop "parallely monad bind" . monadBind S.fromFoldable sortEq
861 serialOps $ prop "serially monad bind folded" . monadBind folded (==)
862 wSerialOps $ prop "wSerially monad bind folded" . monadBind folded sortEq
863 aheadOps $ prop "aheadly monad bind folded" . monadBind folded (==)
864 asyncOps $ prop "asyncly monad bind folded" . monadBind folded sortEq
865 wAsyncOps $ prop "wAsyncly monad bind folded" . monadBind folded sortEq
866 parallelOps $ prop "parallely monad bind folded" . monadBind folded sortEq
868 describe "Stream transform operations" $ do
869 serialOps $ transformOps S.fromFoldable "serially" (==)
870 wSerialOps $ transformOps S.fromFoldable "wSerially" (==)
871 aheadOps $ transformOps S.fromFoldable "aheadly" (==)
872 asyncOps $ transformOps S.fromFoldable "asyncly" sortEq
873 wAsyncOps $ transformOps S.fromFoldable "wAsyncly" sortEq
874 parallelOps $ transformOps S.fromFoldable "parallely" sortEq
875 zipSerialOps $ transformOps S.fromFoldable "zipSerially" (==)
876 zipAsyncOps $ transformOps S.fromFoldable "zipAsyncly" (==)
878 serialOps $ transformOps folded "serially folded" (==)
879 wSerialOps $ transformOps folded "wSerially folded" (==)
880 aheadOps $ transformOps folded "aheadly folded" (==)
881 asyncOps $ transformOps folded "asyncly folded" sortEq
882 wAsyncOps $ transformOps folded "wAsyncly folded" sortEq
883 parallelOps $ transformOps folded "parallely folded" sortEq
884 zipSerialOps $ transformOps folded "zipSerially folded" (==)
885 zipAsyncOps $ transformOps folded "zipAsyncly folded" (==)
887 serialOps $ transformOpsWord8 S.fromFoldable "serially"
888 wSerialOps $ transformOpsWord8 S.fromFoldable "wSerially"
889 aheadOps $ transformOpsWord8 S.fromFoldable "aheadly"
890 asyncOps $ transformOpsWord8 S.fromFoldable "asyncly"
891 wAsyncOps $ transformOpsWord8 S.fromFoldable "wAsyncly"
892 parallelOps $ transformOpsWord8 S.fromFoldable "parallely"
893 zipSerialOps $ transformOpsWord8 S.fromFoldable "zipSerially"
894 zipAsyncOps $ transformOpsWord8 S.fromFoldable "zipAsyncly"
896 serialOps $ transformOpsWord8 folded "serially folded"
897 wSerialOps $ transformOpsWord8 folded "wSerially folded"
898 aheadOps $ transformOpsWord8 folded "aheadly folded"
899 asyncOps $ transformOpsWord8 folded "asyncly folded"
900 wAsyncOps $ transformOpsWord8 folded "wAsyncly folded"
901 parallelOps $ transformOpsWord8 folded "parallely folded"
902 zipSerialOps $ transformOpsWord8 folded "zipSerially folded"
903 zipAsyncOps $ transformOpsWord8 folded "zipAsyncly folded"
905 -- These tests won't work with maxBuffer or maxThreads set to 1, so we
906 -- exclude those cases from these.
909#ifndef COVERAGE_BUILD
910 , ("rate Nothing", t . rate Nothing)
911 , ("maxBuffer 0", t . maxBuffer 0)
912 , ("maxThreads 0", t . maxThreads 0)
913 , ("maxThreads 0", t . maxThreads (-1))
917 let forOps ops spec = forM_ ops (\(desc, f) -> describe desc $ spec f)
918 describe "Stream concurrent operations" $ do
919 forOps (mkOps aheadly) $ concurrentOps S.fromFoldable "aheadly" (==)
920 forOps (mkOps asyncly) $ concurrentOps S.fromFoldable "asyncly" sortEq
921 forOps (mkOps wAsyncly) $ concurrentOps S.fromFoldable "wAsyncly" sortEq
922 forOps (mkOps parallely) $ concurrentOps S.fromFoldable "parallely" sortEq
924 forOps (mkOps aheadly) $ concurrentOps folded "aheadly folded" (==)
925 forOps (mkOps asyncly) $ concurrentOps folded "asyncly folded" sortEq
926 forOps (mkOps wAsyncly) $ concurrentOps folded "wAsyncly folded" sortEq
927 forOps (mkOps parallely) $ concurrentOps folded "parallely folded" sortEq
929 describe "Concurrent application" $ do
930 serialOps $ prop "serial" . concurrentApplication (==)
931 asyncOps $ prop "async" . concurrentApplication sortEq
932 aheadOps $ prop "ahead" . concurrentApplication (==)
933 parallelOps $ prop "parallel" . concurrentApplication sortEq
935 prop "concurrent foldr application" $ withMaxSuccess maxTestCount
936 concurrentFoldrApplication
937 prop "concurrent foldl application" $ withMaxSuccess maxTestCount
938 concurrentFoldlApplication
940 -- These tests are specifically targeted towards detecting illegal sharing
941 -- of SVar across conurrent streams. All transform ops must be added here.
942 describe "Stream transform and combine operations" $ do
943 serialOps $ transformCombineOpsCommon S.fromFoldable "serially" (==)
944 wSerialOps $ transformCombineOpsCommon S.fromFoldable "wSerially" sortEq
945 aheadOps $ transformCombineOpsCommon S.fromFoldable "aheadly" (==)
946 asyncOps $ transformCombineOpsCommon S.fromFoldable "asyncly" sortEq
947 wAsyncOps $ transformCombineOpsCommon S.fromFoldable "wAsyncly" sortEq
948 parallelOps $ transformCombineOpsCommon S.fromFoldable "parallely" sortEq
949 zipSerialOps $ transformCombineOpsCommon S.fromFoldable "zipSerially" (==)
950 zipAsyncOps $ transformCombineOpsCommon S.fromFoldable "zipAsyncly" (==)
952 serialOps $ transformCombineOpsCommon folded "serially" (==)
953 wSerialOps $ transformCombineOpsCommon folded "wSerially" sortEq
954 aheadOps $ transformCombineOpsCommon folded "aheadly" (==)
955 asyncOps $ transformCombineOpsCommon folded "asyncly" sortEq
956 wAsyncOps $ transformCombineOpsCommon folded "wAsyncly" sortEq
957 parallelOps $ transformCombineOpsCommon folded "parallely" sortEq
958 zipSerialOps $ transformCombineOpsCommon folded "zipSerially" (==)
959 zipAsyncOps $ transformCombineOpsCommon folded "zipAsyncly" (==)
961 serialOps $ transformCombineOpsOrdered S.fromFoldable "serially" (==)
962 aheadOps $ transformCombineOpsOrdered S.fromFoldable "aheadly" (==)
963 zipSerialOps $ transformCombineOpsOrdered S.fromFoldable "zipSerially" (==)
964 zipAsyncOps $ transformCombineOpsOrdered S.fromFoldable "zipAsyncly" (==)
966 serialOps $ transformCombineOpsOrdered folded "serially" (==)
967 aheadOps $ transformCombineOpsOrdered folded "aheadly" (==)
968 zipSerialOps $ transformCombineOpsOrdered folded "zipSerially" (==)
969 zipAsyncOps $ transformCombineOpsOrdered folded "zipAsyncly" (==)
971 describe "Stream elimination operations" $ do
972 serialOps $ eliminationOps S.fromFoldable "serially"
973 wSerialOps $ eliminationOps S.fromFoldable "wSerially"
974 aheadOps $ eliminationOps S.fromFoldable "aheadly"
975 asyncOps $ eliminationOps S.fromFoldable "asyncly"
976 wAsyncOps $ eliminationOps S.fromFoldable "wAsyncly"
977 parallelOps $ eliminationOps S.fromFoldable "parallely"
978 zipSerialOps $ eliminationOps S.fromFoldable "zipSerially"
979 zipAsyncOps $ eliminationOps S.fromFoldable "zipAsyncly"
981 serialOps $ eliminationOps folded "serially folded"
982 wSerialOps $ eliminationOps folded "wSerially folded"
983 aheadOps $ eliminationOps folded "aheadly folded"
984 asyncOps $ eliminationOps folded "asyncly folded"
985 wAsyncOps $ eliminationOps folded "wAsyncly folded"
986 parallelOps $ eliminationOps folded "parallely folded"
987 zipSerialOps $ eliminationOps folded "zipSerially folded"
988 zipAsyncOps $ eliminationOps folded "zipAsyncly folded"
990 -- XXX Add a test where we chain all transformation APIs and make sure that
991 -- the state is being passed through all of them.
992 describe "Stream serial elimination operations" $ do
993 serialOps $ serialEliminationOps S.fromFoldable "serially"
994 wSerialOps $ serialEliminationOps S.fromFoldable "wSerially"
995 aheadOps $ serialEliminationOps S.fromFoldable "aheadly"
996 zipSerialOps $ serialEliminationOps S.fromFoldable "zipSerially"
997 zipAsyncOps $ serialEliminationOps S.fromFoldable "zipAsyncly"
999 serialOps $ serialEliminationOps folded "serially folded"
1000 wSerialOps $ serialEliminationOps folded "wSerially folded"
1001 aheadOps $ serialEliminationOps folded "aheadly folded"
1002 zipSerialOps $ serialEliminationOps folded "zipSerially folded"
1003 zipAsyncOps $ serialEliminationOps 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