@@ -9,38 +9,126 @@
10module Streamly.Test.Prelude (main) where
10module Streamly.Test.Prelude (main) where
12+import Control.Concurrent (threadDelay)
12import Control.Exception (Exception, try)
13import Control.Exception (Exception, try)
14+import Control.Monad (when)
13import Control.Monad.Catch (throwM)
15import Control.Monad.Catch (throwM)
14import Control.Monad.Error.Class (throwError, MonadError)
16import Control.Monad.Error.Class (throwError, MonadError)
15import Control.Monad.Trans.Except (runExceptT, ExceptT)
17import Control.Monad.Trans.Except (runExceptT, ExceptT)
18+import Data.Function ((&))
19+import Data.IORef (newIORef, readIORef, writeIORef)
20+import Data.Int (Int64)
16import Data.List (sort)
21import Data.List (sort)
22+import Data.Maybe (fromJust, isJust)
17#if !(MIN_VERSION_base(4,11,0))
23#if !(MIN_VERSION_base(4,11,0))
18import Data.Semigroup (Semigroup(..))
24import Data.Semigroup (Semigroup(..))
22import Test.Hspec as H
26import Test.Hspec as H
23−
27+import Test.Hspec.QuickCheck (prop)
28+import Test.QuickCheck (Property, choose)
29+import Test.QuickCheck.Monadic (monadicIO, pick)
24−import Streamly.Prelude
31+import Streamly.Prelude (SerialT, IsStream)
25− ( SerialT, IsStream)
32+import Streamly.Internal.Data.Time.Units
33+ (AbsTime, NanoSecond64(..), toRelTime64, diffAbsTime64)
34+import Streamly.Internal.Data.Time.Clock (Clock(Monotonic), getTime)
36+import qualified Streamly.Internal.Data.Fold as FL
37+import qualified Streamly.Internal.Data.Unfold as UF
38+import qualified Streamly.Internal.Data.Stream.IsStream as IS
26import qualified Streamly.Prelude as S
39import qualified Streamly.Prelude as S
28toListSerial :: SerialT IO a -> IO [a]
41toListSerial :: SerialT IO a -> IO [a]
29toListSerial = S.toList . S.serially
42toListSerial = S.toList . S.serially
31−main :: IO ()
44+max_length :: Int
32−main = hspec $ H.parallel $ do
45+max_length = 1000
48+tenPow8 = 10^(8 :: Int)
51+tenPow7 = 10^(7 :: Int)
53+takeDropTime :: NanoSecond64
54+takeDropTime = NanoSecond64 $ 5 * tenPow8
56+checkTakeDropTime :: (Maybe AbsTime, Maybe AbsTime) -> IO Bool
57+checkTakeDropTime (mt0, mt1) = do
58+ let graceTime = NanoSecond64 $ 8 * tenPow7
60+ Nothing -> return True
63+ Nothing -> return True
65+ let tMax = toRelTime64 (takeDropTime + graceTime)
66+ let tMin = toRelTime64 (takeDropTime - graceTime)
67+ let t = diffAbsTime64 t1 t0
68+ let r = t >= tMin && t <= tMax
69+ when (not r) $ putStrLn $
71+ " tMin = " ++ show tMin ++
72+ " tMax = " ++ show tMax
75+testTakeByTime :: IO Bool
78+ S.fold ((,) <$> FL.head <*> FL.last)
79+ $ IS.takeByTime takeDropTime
80+ $ S.repeatM (threadDelay 1000 >> getTime Monotonic)
83+testDropByTime :: IO Bool
85+ t0 <- getTime Monotonic
88+ $ IS.dropByTime takeDropTime
89+ $ S.repeatM (threadDelay 1000 >> getTime Monotonic)
90+ checkTakeDropTime (Just t0, mt1)
93+unfold = monadicIO $ do
94+ a <- pick $ choose (0, max_length `div` 2)
95+ b <- pick $ choose (0, max_length)
96+ let unf = UF.enumerateFromToIntegral b
97+ ls <- S.toList $ S.unfold unf a
98+ return $ ls == [a..b]
101+unfold0 = monadicIO $ do
102+ a <- pick $ choose (0, max_length `div` 2)
103+ b <- pick $ choose (0, max_length)
104+ let unf = UF.supply (UF.enumerateFromToIntegral b) a
105+ ls <- S.toList $ IS.unfold0 unf
106+ return $ ls == [a..b]
108+testFromCallback :: IO Int
109+testFromCallback = do
110+ ref <- newIORef Nothing
111+ let stream = S.map Just (IS.fromCallback (setCallback ref))
112+ `S.parallel` runCallback ref
113+ S.sum $ S.map fromJust $ S.takeWhile isJust stream
34− describe "Miscellaneous combined examples" mixedOps
115+ where
35− describe "Miscellaneous combined examples aheadly" mixedOpsAheadly
36− describe "Simple MonadError and MonadThrow" simpleMonadError
38− {-
117+ setCallback ref cb = do
39− describe "Composed MonadError serially" $ composeWithMonadError serially
118+ writeIORef ref (Just cb)
40− describe "Composed MonadError wSerially" $ composeWithMonadError wSerially
119+
41− describe "Composed MonadError asyncly" $ composeWithMonadError asyncly
120+ runCallback ref = S.yieldM $ do
42− describe "Composed MonadError wAsyncly" $ composeWithMonadError wAsyncly
121+ cb <-
43− -}
122+ S.repeatM (readIORef ref)
128+ & IS.delayPost 0.001
129+ & S.mapM_ (fromJust cb)
45-- XXX need to test that we have promptly cleaned up everything after the error
133-- XXX need to test that we have promptly cleaned up everything after the error
46-- XXX We can also check the output that we are expected to get before the
134-- XXX We can also check the output that we are expected to get before the
@@ -138,3 +226,26 @@ mixedOpsAheadly =
138 return (x11 + y11 + z11)
226 return (x11 + y11 + z11)
139 return (x1 + y1 + z1)
227 return (x1 + y1 + z1)
140 return (x + y + z)
228 return (x + y + z)
231+main = hspec $ H.parallel $ do
232+ describe "Filtering" $ do
233+ it "takeByTime" (testTakeByTime `shouldReturn` True)
234+ it "dropByTime" (testDropByTime `shouldReturn` True)
236+ describe "From Generators" $ do
237+ prop "unfold" unfold
238+ prop "unfold0" unfold0
240+ it "fromCallback" $ testFromCallback `shouldReturn` (50*101)
242+ describe "Miscellaneous combined examples" mixedOps
243+ describe "Miscellaneous combined examples aheadly" mixedOpsAheadly
244+ describe "Simple MonadError and MonadThrow" simpleMonadError
247+ describe "Composed MonadError serially" $ composeWithMonadError serially
248+ describe "Composed MonadError wSerially" $ composeWithMonadError wSerially
249+ describe "Composed MonadError asyncly" $ composeWithMonadError asyncly
250+ describe "Composed MonadError wAsyncly" $ composeWithMonadError wAsyncly