3-- Copyright : (c) 2020 Composewell Technologies
5-- License : BSD-3-Clause
6-- Maintainer : streamly@composewell.com
7-- Stability : experimental
10module Main (main) where
12import Streamly.Internal.Data.Unfold (Unfold)
14import qualified Data.List as List
15import qualified Prelude
16import qualified Streamly.Internal.Data.Unfold as UF
17import qualified Streamly.Internal.Data.Stream.IsStream as S
18import qualified Streamly.Internal.Data.Stream.StreamD as D
19import qualified Streamly.Internal.Data.Stream.StreamK as K
21import Control.Monad.Trans.State.Strict
22import Data.Functor.Identity
23import Prelude hiding (const, take, drop, concat, mapM)
24import Streamly.Prelude (SerialT)
26import Test.Hspec.QuickCheck
28import Test.QuickCheck.Function
30-------------------------------------------------------------------------------
32-------------------------------------------------------------------------------
34-- | @testUnfoldM unf seed initial final xs@, runs an unfold under state monad
35-- using @initial@ as the initial state. @final@ is the expected state after
36-- running it and @xs@ is the list of elements the stream must produce.
38 (Eq s, Eq b) => Unfold (State s) a b -> a -> s -> s -> [b] -> Bool
39testUnfoldM unf seed si sf lst = evalState action si
44 x <- S.toList $ S.unfold unf seed
46 return $ x == lst && y == sf
48testUnfoldMD :: Unfold (State Int) a Int -> a -> Int -> Int -> [Int] -> Bool
49testUnfoldMD = testUnfoldM
51-- | This is similar to 'testUnfoldM' but without the state monad.
52testUnfold :: Eq b => Unfold Identity a b -> a -> [b] -> Bool
53testUnfold unf seed lst = runIdentity action
58 x <- S.toList $ S.unfold unf seed
61testUnfoldD :: Unfold Identity a Int -> a -> [Int] -> Bool
62testUnfoldD = testUnfold
64-------------------------------------------------------------------------------
66-------------------------------------------------------------------------------
70 let unf = UF.lmapM (\x -> modify (+ 1) >> return x) (UF.singleton id)
71 in testUnfoldMD unf 1 0 1 [1]
75 let unf = UF.supply (UF.singleton id) 1
76 in testUnfold unf undefined ([1] :: [Int])
80 let unf = UF.supplyFirst (UF.singleton id) 1
81 in testUnfold unf 2 ([(1, 2)] :: [(Int, Int)])
85 let unf = UF.supplySecond (UF.singleton id) 1
86 in testUnfold unf 2 ([(2, 1)] :: [(Int, Int)])
90 let unf = UF.discardFirst (UF.singleton id)
91 in testUnfold unf ((1, 2) :: (Int, Int)) [2]
95 let unf = UF.discardSecond (UF.singleton id)
96 in testUnfold unf ((1, 2) :: (Int, Int)) [1]
100 let unf = UF.swap (UF.singleton id)
101 in testUnfold unf ((1, 2) :: (Int, Int)) [(2, 1)]
103-------------------------------------------------------------------------------
105-------------------------------------------------------------------------------
107fromStream :: Property
113 (S.fromList list :: SerialT Identity Int)
116fromStreamD :: Property
119 $ \list -> testUnfoldD UF.fromStreamD (D.fromList list) (list :: [Int])
121fromStreamK :: Property
124 $ \list -> testUnfoldD UF.fromStreamK (K.fromList list) (list :: [Int])
128 let unf = UF.nilM put
129 in testUnfoldMD unf 1 0 1 []
133 let cns = UF.consM (\a -> modify (+ a) >> get)
134 unf = cns $ cns $ UF.nilM $ \a -> modify (+ a)
135 in testUnfoldMD unf 1 0 3 [1, 2]
139 let unf = UF.effect (modify (+ 1) >> get)
140 in testUnfoldMD unf undefined 0 1 [1]
144 let unf = UF.singletonM (\a -> modify (+ a) >> get)
145 in testUnfoldMD unf 1 0 1 [1]
149 let unf = UF.take 10 $ UF.const (modify (+ 1) >> get)
150 in testUnfoldMD unf (0 :: Int) 0 10 [1 .. 10]
156 let genA = apply gen :: Int -> Maybe (Int, Int)
157 genM x = modify (+ 1) >> return (genA x)
158 list = Prelude.take 100 $ List.unfoldr genA 1
159 unf = UF.take 100 $ UF.unfoldrM genM
161 fs = if ll < 100 then ll + 1 else 100
162 in testUnfoldMD unf 1 0 fs list
168 let listM = Prelude.map (\x -> modify (+ 1) >> return x) list
169 in testUnfoldMD UF.fromListM listM 0 (length list) list
171replicateM :: Property
176 seed = modify (+ 1) >> get
177 in testUnfoldMD (UF.replicateM i) seed 0 ns [1 .. i]
181 testUnfoldMD (UF.take 10 UF.repeatM) (modify (+ 1) >> get) 0 10 [1 .. 10]
187 let nextA = apply next :: Int -> Int
188 nextM x = modify (+ 1) >> return (nextA x)
189 list = Prelude.take 100 $ List.iterate nextA 1
190 unf = UF.take 100 $ UF.iterateM nextM
191 in testUnfoldMD unf (modify (+ 10) >> return 1) 0 110 list
193fromIndicesM :: Property
197 let indFA = apply indF :: Int -> Int
198 indFM x = modify (+ 1) >> return (indFA x)
199 list = Prelude.take 100 $ Prelude.map indFA [1 ..]
200 unf = UF.take 100 $ UF.fromIndicesM indFM
201 in testUnfoldMD unf 1 0 (length list) list
203enumerateFromStepNum :: Property
204enumerateFromStepNum =
207 let unf = UF.take 10 $ UF.enumerateFromStepNum s
208 lst = Prelude.take 10 $ List.unfoldr (\x -> Just (x, x + s)) f
209 in testUnfoldD unf f lst
211enumerateFromToFractional :: Property
212enumerateFromToFractional =
215 let unf = UF.enumerateFromToFractional (t :: Double)
217 Prelude.takeWhile (<= t + 0.5)
218 $ List.unfoldr (\x -> Just (x, x + 1)) f
219 in testUnfold unf (f :: Double) list
221enumerateFromStepIntegral :: Property
222enumerateFromStepIntegral =
225 let unf = UF.take 10 UF.enumerateFromStepIntegral
226 lst = Prelude.take 10 $ List.unfoldr (\x -> Just (x, x + s)) f
227 in testUnfoldD unf (f, s) lst
229enumerateFromToIntegral :: Property
230enumerateFromToIntegral =
233 let unf = UF.enumerateFromToIntegral t
234 in testUnfoldD unf f [f .. t]
236-------------------------------------------------------------------------------
237-- Stream transformation
238-------------------------------------------------------------------------------
244 let fA = apply f :: Int -> Int
245 fM x = modify (+ 1) >> return (fA x)
246 unf = UF.mapM fM UF.fromList
247 mList = Prelude.map fA list
248 in testUnfoldMD unf list 0 (length list) mList
250mapMWithInput :: Property
254 let fA = applyFun2 f :: [Int] -> Int -> Int
255 fM x y = modify (+ 1) >> return (fA x y)
256 unf = UF.mapMWithInput fM UF.fromList
257 mList = Prelude.map (fA list) list
258 in testUnfoldMD unf list 0 (length list) mList
265 (UF.take i UF.repeatM)
267 (Prelude.take i (Prelude.repeat 1))
269takeWhileM :: Property
275 then modify (+ 1) >> return True
277 unf = UF.takeWhileM fM UF.fromList
278 fL = Prelude.takeWhile (apply f) list
279 fS = Prelude.length fL
280 in testUnfoldMD unf list 0 fS fL
288 then modify (+ 1) >> return True
290 unf = UF.filterM fM UF.fromList
291 fL = Prelude.filter (apply f) list
292 fS = Prelude.length fL
293 in testUnfoldMD unf list 0 fS fL
299 let unf = UF.drop i UF.fromList
300 fL = Prelude.drop i list
301 in testUnfoldD unf list fL
303dropWhileM :: Property
309 then modify (+ 1) >> return True
311 unf = UF.dropWhileM fM UF.fromList
312 fL = Prelude.dropWhile (apply f) list
313 fS = Prelude.length list - Prelude.length fL
314 in testUnfoldMD unf list 0 fS fL
316-------------------------------------------------------------------------------
318-------------------------------------------------------------------------------
324 let unf1 = UF.enumerateFromToIntegral 10
325 unf2 = UF.enumerateFromToIntegral 20
326 fA = applyFun2 f :: Int -> Int -> Int
327 fM a b = modify (+ 1) >> return (fA a b)
328 unf = UF.zipWithM fM unf1 unf2
329 lst = Prelude.zipWith fA [1 .. 10] [1 .. 20]
330 in testUnfoldMD unf (1, 1) 0 10 lst
334 let unfIn = UF.replicateM 10
335 unfOut = UF.map return $ UF.enumerateFromToIntegral 10
336 unf = UF.concat unfOut unfIn
337 lst = Prelude.concat $ Prelude.map (Prelude.replicate 10) [1 .. 10]
338 in testUnfoldD unf 1 lst
342 let unf1 = UF.enumerateFromToIntegral 10
343 unf2 = UF.enumerateFromToIntegral 20
344 unf = UF.outerProduct unf1 unf2
345 lst = [(a, b) :: (Int, Int) | a <- [0 .. 10], b <- [0 .. 20]]
346 in testUnfold unf ((0, 0) :: (Int, Int)) lst
353 (UF.supply (UF.replicateM 10) (modify (+ 1) >> return b))
354 listInF b = replicate 10 b
355 unfOut = UF.enumerateFromToIntegral 10
356 unf = UF.concatMapM unfInF unfOut
357 list = List.concatMap listInF [1 .. 10]
358 in testUnfoldMD unf 1 0 110 list
360-------------------------------------------------------------------------------
362-------------------------------------------------------------------------------
371 prop "supplyFirst" supplyFirst
372 prop "supplySecond" supplySecond
373 prop "discardFirst" discardFirst
374 prop "discardSecond" discardSecond
377testGeneration :: Spec
379 describe "Generation"
381 prop "fromStream" fromStream
382 prop "fromStreamK" fromStreamK
383 prop "fromStreamD" fromStreamD
387 prop "singletonM" singletonM
388 -- prop "singleton" singleton
389 -- prop "identity" identity
391 prop "unfoldrM" unfoldrM
392 -- prop "fromList" fromList
393 prop "fromListM" fromListM
394 -- prop "fromSVar" fromSVar
395 -- prop "fromProducer" fromProducer
396 prop "replicateM" replicateM
397 prop "repeatM" repeatM
398 prop "iterateM" iterateM
399 prop "fromIndicesM" fromIndicesM
400 prop "enumerateFromStepIntegral" enumerateFromStepIntegral
401 prop "enumerateFromToIntegral" enumerateFromToIntegral
402 -- prop "enumerateFromIntegral" enumerateFromIntegral
403 prop "enumerateFromStepNum" enumerateFromStepNum
404 -- prop "numFrom" numFrom
405 prop "enumerateFromToFractional" enumerateFromToFractional
407testTransformation :: Spec
409 describe "Transformation"
413 prop "mapMWithInput" mapMWithInput
414 prop "takeWhileM" takeWhileM
415 -- prop "takeWhile" takeWhile
417 -- prop "filter" filter
418 prop "filterM" filterM
420 -- prop "dropWhile" dropWhile
421 prop "dropWhileM" dropWhileM
423testCombination :: Spec
425 describe "Transformation"
427 prop "zipWithM" zipWithM
428 -- prop "zipWith" zipWith
429 -- prop "teeZipWith" teeZipWith
431 prop "concatMapM" concatMapM
432 prop "outerProduct" outerProduct
434 -- prop "apDiscardFst" apDiscardFst
435 -- prop "apDiscardSnd" apDiscardSnd
437-------------------------------------------------------------------------------
439-------------------------------------------------------------------------------
444 $ describe "Unfold tests"
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