@@ -9,7 +9,13 @@
99
1010module Streamly.Test.Prelude.Serial where
1111
12+import Control.Concurrent ( threadDelay )
13+import Control.Monad ( when )
14+import Data.Function ( (&) )
15+import Data.IORef ( newIORef, readIORef, writeIORef )
16+import Data.Int (Int64)
1217import Data.List (intercalate)
18+import Data.Maybe ( isJust, fromJust )
1319#if __GLASGOW_HASKELL__ < 808
1420import Data.Semigroup ((<>))
1521#endif
@@ -26,13 +32,18 @@ import Test.QuickCheck
2632 , vectorOf
2733 , withMaxSuccess
2834 )
29−import Test.QuickCheck.Monadic (assert, monadicIO, run)
35+import Test.QuickCheck.Monadic (assert, monadicIO, pick, run)
3036import Test.Hspec as H
3137
3238import Streamly.Prelude
3339 ( SerialT, IsStream, avgRate, maxBuffer, serial, serially)
3440import qualified Streamly.Prelude as S
3541import qualified Streamly.Data.Fold as FL
42+import qualified Streamly.Internal.Data.Unfold as UF
43+import qualified Streamly.Internal.Data.Stream.IsStream as IS
44+import Streamly.Internal.Data.Time.Units
45+ (AbsTime, NanoSecond64(..), toRelTime64, diffAbsTime64)
46+import Streamly.Internal.Data.Time.Clock (Clock(Monotonic), getTime)
3647
3748import Streamly.Test.Common
3849import Streamly.Test.Prelude.Common
@@ -163,6 +174,95 @@ associativityCheck desc t = prop desc assocCheckProp
163174 assocStream <- run $ S.toList $ t $ xStream <> yStream <> zStream
164175 listEquals (==) infixAssocstream assocStream
165176
177+max_length :: Int
178+max_length = 1000
179+
180+tenPow8 :: Int64
181+tenPow8 = 10^(8 :: Int)
182+
183+tenPow7 :: Int64
184+tenPow7 = 10^(7 :: Int)
185+
186+takeDropTime :: NanoSecond64
187+takeDropTime = NanoSecond64 $ 5 * tenPow8
188+
189+checkTakeDropTime :: (Maybe AbsTime, Maybe AbsTime) -> IO Bool
190+checkTakeDropTime (mt0, mt1) = do
191+ let graceTime = NanoSecond64 $ 8 * tenPow7
192+ case mt0 of
193+ Nothing -> return True
194+ Just t0 ->
195+ case mt1 of
196+ Nothing -> return True
197+ Just t1 -> do
198+ let tMax = toRelTime64 (takeDropTime + graceTime)
199+ let tMin = toRelTime64 (takeDropTime - graceTime)
200+ let t = diffAbsTime64 t1 t0
201+ let r = t >= tMin && t <= tMax
202+ when (not r) $ putStrLn $
203+ "t = " ++ show t ++
204+ " tMin = " ++ show tMin ++
205+ " tMax = " ++ show tMax
206+ return r
207+
208+testTakeByTime :: IO Bool
209+testTakeByTime = do
210+ r <-
211+ S.fold ((,) <$> FL.head <*> FL.last)
212+ $ IS.takeByTime takeDropTime
213+ $ S.repeatM (threadDelay 1000 >> getTime Monotonic)
214+ checkTakeDropTime r
215+
216+testDropByTime :: IO Bool
217+testDropByTime = do
218+ t0 <- getTime Monotonic
219+ mt1 <-
220+ S.head
221+ $ IS.dropByTime takeDropTime
222+ $ S.repeatM (threadDelay 1000 >> getTime Monotonic)
223+ checkTakeDropTime (Just t0, mt1)
224+
225+unfold :: Property
226+unfold = monadicIO $ do
227+ a <- pick $ choose (0, max_length `div` 2)
228+ b <- pick $ choose (0, max_length)
229+ let unf = UF.enumerateFromToIntegral b
230+ ls <- S.toList $ S.unfold unf a
231+ return $ ls == [a..b]
232+
233+unfold0 :: Property
234+unfold0 = monadicIO $ do
235+ a <- pick $ choose (0, max_length `div` 2)
236+ b <- pick $ choose (0, max_length)
237+ let unf = UF.supply (UF.enumerateFromToIntegral b) a
238+ ls <- S.toList $ IS.unfold0 unf
239+ return $ ls == [a..b]
240+
241+testFromCallback :: IO Int
242+testFromCallback = do
243+ ref <- newIORef Nothing
244+ let stream = S.map Just (IS.fromCallback (setCallback ref))
245+ `S.parallel` runCallback ref
246+ S.sum $ S.map fromJust $ S.takeWhile isJust stream
247+
248+ where
249+
250+ setCallback ref cb = do
251+ writeIORef ref (Just cb)
252+
253+ runCallback ref = S.yieldM $ do
254+ cb <-
255+ S.repeatM (readIORef ref)
256+ & IS.delayPost 0.1
257+ & S.mapMaybe id
258+ & S.head
259+
260+ S.fromList [1..100]
261+ & IS.delayPost 0.001
262+ & S.mapM_ (fromJust cb)
263+ threadDelay 100000
264+ return Nothing
265+
166266main :: IO ()
167267main = hspec
168268 $ H.parallel
@@ -209,6 +309,10 @@ main = hspec
209309 serialOps $ prop "serially fromIndices" . constructWithFromIndices
210310 serialOps $ prop "serially fromIndicesM" . constructWithFromIndicesM
211311
312+ describe "From Generators" $ do
313+ prop "unfold" unfold
314+ prop "unfold0" unfold0
315+
212316 describe "Functor operations" $ do
213317 serialOps $ functorOps S.fromFoldable "serially" (==)
214318 serialOps $ functorOps folded "serially folded" (==)
@@ -269,6 +373,10 @@ main = hspec
269373 serialOps $ transformCombineOpsOrdered S.fromFoldable "serially" (==)
270374 serialOps $ transformCombineOpsOrdered folded "serially" (==)
271375
376+ describe "Filtering" $ do
377+ it "takeByTime" (testTakeByTime `shouldReturn` True)
378+ it "dropByTime" (testDropByTime `shouldReturn` True)
379+
272380 describe "Stream group and split operations" $ do
273381 groupSplitOps "serially"
274382
@@ -289,3 +397,5 @@ main = hspec
289397 prop "testGroupsBySep" testGroupsBySep
290398
291399 describe "Composed MonadThrow serially" $ composeWithMonadThrow serially
400+
401+ it "fromCallback" $ testFromCallback `shouldReturn` (50*101)