@@ -221,6 +221,24 @@ concurrentFoldrApplication n =
221 sourceUnfoldrM1 n |&. A.foldrM (\x xs -> return (x : xs)) []
221 sourceUnfoldrM1 n |&. A.foldrM (\x xs -> return (x : xs)) []
222 equals (==) stream list
222 equals (==) stream list
224+transformCombineFromList
225+ :: Semigroup (t IO Int)
226+ => ([Int] -> t IO Int)
227+ -> ([Int] -> [Int] -> Bool)
229+ -> (t IO Int -> SerialT IO Int)
230+ -> (t IO Int -> t IO Int)
235+transformCombineFromList constr eq listOp t op a b c =
237+ stream <- run ((A.toList . t) $
238+ constr a <> op (constr b <> constr c))
239+ let list = a <> listOp (b <> c)
240+ equals eq stream list
224foldFromList
242foldFromList
225 :: ([Int] -> t IO Int)
243 :: ([Int] -> t IO Int)
226 -> (t IO Int -> SerialT IO Int)
244 -> (t IO Int -> SerialT IO Int)
@@ -336,6 +354,69 @@ concurrentOps constr desc t eq = do
336 concurrentMapM constr eq $ \n mv stream ->
354 concurrentMapM constr eq $ \n mv stream ->
337 t $ A.mapM (mvarSequenceOp mv n) stream
355 t $ A.mapM (mvarSequenceOp mv n) stream
357+-- XXX add tests for MonadReader and MonadError etc. In case an SVar is
358+-- accidentally passed through them.
359+transformCombineOpsCommon
360+ :: (IsStream t, Semigroup (t IO Int))
361+ => ([Int] -> t IO Int)
363+ -> (t IO Int -> SerialT IO Int)
364+ -> ([Int] -> [Int] -> Bool)
366+transformCombineOpsCommon constr desc t eq = do
367+ let transform = transformCombineFromList constr eq
369+ prop (desc ++ " filter False") $
370+ transform (filter (const False)) t (A.filter (const False))
371+ prop (desc ++ " filter True") $
372+ transform (filter (const True)) t (A.filter (const True))
373+ prop (desc ++ " filter even") $
374+ transform (filter even) t (A.filter even)
376+ prop (desc ++ " take maxBound") $
377+ transform (take maxBound) t (A.take maxBound)
378+ prop (desc ++ " take 0") $ transform (take 0) t (A.take 0)
380+ prop (desc ++ " takeWhile True") $
381+ transform (takeWhile (const True)) t (A.takeWhile (const True))
382+ prop (desc ++ " takeWhile False") $
383+ transform (takeWhile (const False)) t (A.takeWhile (const False))
385+ prop (desc ++ " drop maxBound") $
386+ transform (drop maxBound) t (A.drop maxBound)
387+ prop (desc ++ " drop 0") $ transform (drop 0) t (A.drop 0)
389+ prop (desc ++ " dropWhile True") $
390+ transform (dropWhile (const True)) t (A.dropWhile (const True))
391+ prop (desc ++ " dropWhile False") $
392+ transform (dropWhile (const False)) t (A.dropWhile (const False))
393+ prop (desc ++ " scan") $ transform (scanl' (flip const) 0) t
394+ (A.scanl' (flip const) 0)
395+ prop (desc ++ " reverse") $ transform reverse t A.reverse
397+transformCombineOpsOrdered
398+ :: (IsStream t, Semigroup (t IO Int))
399+ => ([Int] -> t IO Int)
401+ -> (t IO Int -> SerialT IO Int)
402+ -> ([Int] -> [Int] -> Bool)
404+transformCombineOpsOrdered constr desc t eq = do
405+ let transform = transformCombineFromList constr eq
407+ prop (desc ++ " take 1") $ transform (take 1) t (A.take 1)
408+ prop (desc ++ " take 10") $ transform (take 10) t (A.take 10)
410+ prop (desc ++ " takeWhile > 0") $
411+ transform (takeWhile (> 0)) t (A.takeWhile (> 0))
413+ prop (desc ++ " drop 1") $ transform (drop 1) t (A.drop 1)
414+ prop (desc ++ " drop 10") $ transform (drop 10) t (A.drop 10)
416+ prop (desc ++ " dropWhile > 0") $
417+ transform (dropWhile (> 0)) t (A.dropWhile (> 0))
418+ prop (desc ++ " scan") $ transform (scanl' (+) 0) t (A.scanl' (+) 0)
339wrapMaybe :: Eq a1 => ([a1] -> a2) -> [a1] -> Maybe a2
420wrapMaybe :: Eq a1 => ([a1] -> a2) -> [a1] -> Maybe a2
340wrapMaybe f =
421wrapMaybe f =
@@ -641,6 +722,32 @@ main = hspec $ do
641 prop "concurrent foldl application" $ withMaxSuccess maxTestCount $
722 prop "concurrent foldl application" $ withMaxSuccess maxTestCount $
642 concurrentFoldlApplication
723 concurrentFoldlApplication
725+ -- These tests are specifically targeted towards detecting illegal sharing
726+ -- of SVar across conurrent streams.
727+ describe "Stream transform and combine operations" $ do
728+ transformCombineOpsCommon A.fromFoldable "serially" serially (==)
729+ transformCombineOpsCommon A.fromFoldable "aheadly" aheadly (==)
730+ transformCombineOpsCommon A.fromFoldable "wSerially" wSerially sortEq
731+ transformCombineOpsCommon A.fromFoldable "zipSerially" zipSerially (==)
732+ transformCombineOpsCommon A.fromFoldable "zipAsyncly" zipAsyncly (==)
733+ transformCombineOpsCommon A.fromFoldable "asyncly" asyncly sortEq
734+ transformCombineOpsCommon A.fromFoldable "wAsyncly" wAsyncly sortEq
735+ transformCombineOpsCommon A.fromFoldable "parallely" parallely sortEq
737+ transformCombineOpsCommon folded "serially" serially (==)
738+ transformCombineOpsCommon folded "aheadly" aheadly (==)
739+ transformCombineOpsCommon folded "wSerially" wSerially sortEq
740+ transformCombineOpsCommon folded "zipSerially" zipSerially (==)
741+ transformCombineOpsCommon folded "zipAsyncly" zipAsyncly (==)
742+ transformCombineOpsCommon folded "asyncly" asyncly sortEq
743+ transformCombineOpsCommon folded "wAsyncly" wAsyncly sortEq
744+ transformCombineOpsCommon folded "parallely" parallely sortEq
746+ transformCombineOpsOrdered A.fromFoldable "serially" serially (==)
747+ transformCombineOpsOrdered A.fromFoldable "serially" aheadly (==)
748+ transformCombineOpsOrdered A.fromFoldable "zipSerially" zipSerially (==)
749+ transformCombineOpsOrdered A.fromFoldable "zipAsyncly" zipAsyncly (==)
644 describe "Stream elimination operations" $ do
751 describe "Stream elimination operations" $ do
645 eliminationOps A.fromFoldable "serially" serially
752 eliminationOps A.fromFoldable "serially" serially
646 eliminationOps A.fromFoldable "aheadly" aheadly
753 eliminationOps A.fromFoldable "aheadly" aheadly