@@ -1,16 +1,19 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2{-# LANGUAGE FlexibleContexts #-}
2{-# LANGUAGE FlexibleContexts #-}
3{-# LANGUAGE RankNTypes #-}
3{-# LANGUAGE RankNTypes #-}
4+{-# LANGUAGE ScopedTypeVariables #-}
5module Main (main) where
6module Main (main) where
7import Control.Concurrent (threadDelay)
8import Control.Concurrent (threadDelay)
8−import Control.Exception (Exception, try)
9+import Control.Exception (Exception, try, ErrorCall(..), catch, throw)
9import Control.Monad.Catch (throwM, MonadThrow)
10import Control.Monad.Catch (throwM, MonadThrow)
10import Control.Monad.Error.Class (throwError, MonadError)
11import Control.Monad.Error.Class (throwError, MonadError)
11import Control.Monad.Trans.Except (runExceptT, ExceptT)
12import Control.Monad.Trans.Except (runExceptT, ExceptT)
12import Data.Foldable (forM_, fold)
13import Data.Foldable (forM_, fold)
13import Data.List (sort)
14import Data.List (sort)
14import Test.Hspec
17import Test.Hspec
16import Streamly
19import Streamly
@@ -88,30 +91,6 @@ main = hspec $ do
88 (toListParallel ((,) <$> (return 1) <*> (return 2 <> return 3)) >>= return . sort)
91 (toListParallel ((,) <$> (return 1) <*> (return 2 <> return 3)) >>= return . sort)
89 `shouldReturn` ([(1,2),(1,3)] :: [(Int, Int)])
92 `shouldReturn` ([(1,2),(1,3)] :: [(Int, Int)])
91− ---------------------------------------------------------------------------
92− -- Semigroup/Monoidal Composition strict ordering checks
93− ---------------------------------------------------------------------------
95− -- test both (<>) and mappend to make sure we are using correct instance
96− -- for Monoid that is using the right version of semigroup. Instance
97− -- deriving can cause us to pick wrong instances sometimes.
99− describe "WSerial interleaved (<>) ordering check" $ interleaveCheck wSerially (<>)
100− describe "WSerial interleaved mappend ordering check" $ interleaveCheck wSerially mappend
102− -- describe "WAsync interleaved (<>) ordering check" $ interleaveCheck wAsyncly (<>)
103− -- describe "WAsync interleaved mappend ordering check" $ interleaveCheck wAsyncly mappend
105− describe "Async (<>) time order check" $ parallelCheck asyncly (<>)
106− describe "Async mappend time order check" $ parallelCheck asyncly mappend
108− -- XXX this keeps failing intermittently, need to investigate
109− -- describe "WAsync (<>) time order check" $ parallelCheck wAsyncly (<>)
110− -- describe "WAsync mappend time order check" $ parallelCheck wAsyncly mappend
112− describe "Parallel (<>) time order check" $ parallelCheck parallely (<>)
113− describe "Parallel mappend time order check" $ parallelCheck parallely mappend
115 ---------------------------------------------------------------------------
94 ---------------------------------------------------------------------------
116 -- Monoidal Compositions, multiset equality checks
95 -- Monoidal Compositions, multiset equality checks
117 ---------------------------------------------------------------------------
96 ---------------------------------------------------------------------------
@@ -384,6 +363,50 @@ main = hspec $ do
384 describe "take on infinite concurrent stream" $ takeInfinite wAsyncly
363 describe "take on infinite concurrent stream" $ takeInfinite wAsyncly
385 describe "take on infinite concurrent stream" $ takeInfinite aheadly
364 describe "take on infinite concurrent stream" $ takeInfinite aheadly
366+ ---------------------------------------------------------------------------
367+ -- Folds are strict enough
368+ ---------------------------------------------------------------------------
370+ it "foldx is strict enough" checkFoldxStrictness
371+ it "foldl' is strict enough" checkFoldl'Strictness
372+ it "scanx is strict enough" checkScanxStrictness
373+ it "scanl' is strict enough" checkScanl'Strictness
374+ it "foldxM is strict enough" (checkFoldMStrictness foldxMStrictCheck)
375+ it "foldlM' is strict enough" (checkFoldMStrictness foldlM'StrictCheck)
376+ it "scanlM' is strict enough" (checkScanlMStrictness scanlM'StrictCheck)
378+ ---------------------------------------------------------------------------
379+ -- Slower tests are at the end
380+ ---------------------------------------------------------------------------
382+ ---------------------------------------------------------------------------
383+ -- Semigroup/Monoidal Composition strict ordering checks
384+ ---------------------------------------------------------------------------
386+ -- test both (<>) and mappend to make sure we are using correct instance
387+ -- for Monoid that is using the right version of semigroup. Instance
388+ -- deriving can cause us to pick wrong instances sometimes.
390+ describe "WSerial interleaved (<>) ordering check" $ interleaveCheck wSerially (<>)
391+ describe "WSerial interleaved mappend ordering check" $ interleaveCheck wSerially mappend
393+ -- describe "WAsync interleaved (<>) ordering check" $ interleaveCheck wAsyncly (<>)
394+ -- describe "WAsync interleaved mappend ordering check" $ interleaveCheck wAsyncly mappend
396+ describe "Async (<>) time order check" $ parallelCheck asyncly (<>)
397+ describe "Async mappend time order check" $ parallelCheck asyncly mappend
399+ -- XXX this keeps failing intermittently, need to investigate
400+ -- describe "WAsync (<>) time order check" $ parallelCheck wAsyncly (<>)
401+ -- describe "WAsync mappend time order check" $ parallelCheck wAsyncly mappend
403+ describe "Parallel (<>) time order check" $ parallelCheck parallely (<>)
404+ describe "Parallel mappend time order check" $ parallelCheck parallely mappend
406+ ---------------------------------------------------------------------------
408+ ---------------------------------------------------------------------------
387 it "asyncly crosses thread limit (2000 threads)" $
410 it "asyncly crosses thread limit (2000 threads)" $
388 runStream (asyncly $ fold $
411 runStream (asyncly $ fold $
389 replicate 2000 $ S.yieldM $ threadDelay 1000000)
412 replicate 2000 $ S.yieldM $ threadDelay 1000000)
@@ -394,6 +417,90 @@ main = hspec $ do
394 replicate 4000 $ S.yieldM $ threadDelay 1000000)
417 replicate 4000 $ S.yieldM $ threadDelay 1000000)
395 `shouldReturn` ()
418 `shouldReturn` ()
421+checkFoldxStrictness :: IO ()
422+checkFoldxStrictness = do
423+ let s = return (1 :: Int) `S.consM` error "failure"
424+ catch (S.foldx (\_ a -> if a == 1 then error "success" else "done")
427+ ErrorCall err -> return err
429+ `shouldReturn` "success"
431+checkFoldl'Strictness :: IO ()
432+checkFoldl'Strictness = do
433+ let s = return (1 :: Int) `S.consM` error "failure"
434+ catch (S.foldl' (\_ a -> if a == 1 then error "success" else "done")
437+ ErrorCall err -> return err
439+ `shouldReturn` "success"
441+checkScanxStrictness :: IO ()
442+checkScanxStrictness = do
443+ let s = return (1 :: Int) `S.consM` error "failure"
448+ then error "success"
452+ >> return "finished"
455+ ErrorCall err -> return err
457+ `shouldReturn` "success"
459+checkScanl'Strictness :: IO ()
460+checkScanl'Strictness = do
461+ let s = return (1 :: Int) `S.consM` error "failure"
467+ then error "success"
471+ >> return "finished"
474+ ErrorCall err -> return err
476+ `shouldReturn` "success"
478+foldlM'StrictCheck :: IORef Int -> SerialT IO Int -> IO ()
479+foldlM'StrictCheck ref s =
480+ S.foldlM' (\_ _ -> writeIORef ref 1) () s
482+foldxMStrictCheck :: IORef Int -> SerialT IO Int -> IO ()
483+foldxMStrictCheck ref s =
484+ S.foldxM (\_ _ -> writeIORef ref 1) (return ()) return s
486+checkFoldMStrictness :: (IORef Int -> SerialT IO Int -> IO ()) -> IO ()
487+checkFoldMStrictness f = do
489+ let s = return 1 `S.consM` error "x"
490+ catch (f ref s) (\(_ :: ErrorCall) -> return ())
491+ readIORef ref `shouldReturn` 1
493+scanlM'StrictCheck :: IORef Int -> SerialT IO Int -> SerialT IO ()
494+scanlM'StrictCheck ref s =
495+ S.scanlM' (\_ _ -> writeIORef ref 1) () s
497+checkScanlMStrictness :: (IORef Int -> SerialT IO Int -> SerialT IO ()) -> IO ()
498+checkScanlMStrictness f = do
500+ let s = return 1 `S.consM` error "x"
501+ catch (runStream $ f ref s) (\(_ :: ErrorCall) -> return ())
502+ readIORef ref `shouldReturn` 1
397takeInfinite :: IsStream t => (t IO Int -> SerialT IO Int) -> Spec
504takeInfinite :: IsStream t => (t IO Int -> SerialT IO Int) -> Spec
398takeInfinite t = do
505takeInfinite t = do
399 it "take 1" $
506 it "take 1" $