streaming-0.2.3.1: test/test.hs
module Main where
import qualified Data.Foldable as Foldable
import Data.Functor.Identity
import Data.Ord
import qualified Streaming.Prelude as S
import Test.Hspec
import Test.QuickCheck
toL :: S.Stream (S.Of a) Identity b -> [a]
toL = runIdentity . S.toList_
main :: IO ()
main =
hspec $ do
describe "slidingWindowMin" $ do
it "works with a few simple cases" $ do
toL (S.slidingWindowMin 2 (S.each [1, 3, 9, 4, 6, 4])) `shouldBe` [1, 3, 4, 4, 4]
toL (S.slidingWindowMin 3 (S.each [1, 3, 2, 6, 3, 7, 8, 9])) `shouldBe` [1, 2, 2, 3, 3, 7]
it "produces no results with empty streams" $
property $ \k -> toL (S.slidingWindowMin k (mempty :: S.Stream (S.Of Int) Identity ())) `shouldBe` []
it "behaves like a (S.map Foldable.minimum) (slidingWindow) for non-empty streams" $
property $ \(NonEmpty xs) k -- we use NonEmpty because Foldable.minimum crashes on empty lists
->
toL (S.slidingWindowMin k (S.each xs)) ===
toL (S.map Foldable.minimum (S.slidingWindow k (S.each (xs :: [Int]))))
it "behaves like identity when window size is 1" $
property $ \xs -> toL (S.slidingWindowMin 1 (S.each (xs :: [Int]))) === xs
it "produces a prefix when the stream elements are sorted" $
property $ \(Sorted xs) k ->
(length xs >= k) ==> (toL (S.slidingWindowMin k (S.each (xs :: [Int]))) === take (length xs - (k - 1)) xs)
describe "slidingWindowMinBy" $ do
it "prefers earlier elements when several elements compare equal" $ do
toL (S.slidingWindowMinBy (comparing fst) 2 (S.each [(1, 1), (2, 2), (2, 3), (2, 4)])) `shouldBe`
[(1, 1), (2, 2), (2, 3)]
it "behaves like a (S.map (Foldable.minimumBy f)) (slidingWindow) for non-empty streams" $ do
property $ \(NonEmpty xs) k -- we use NonEmpty because Foldable.minimumBy crashes on empty lists
->
toL (S.slidingWindowMinBy (comparing fst) k (S.each xs)) ===
toL (S.map (Foldable.minimumBy (comparing fst)) (S.slidingWindow k (S.each (xs :: [(Int, Int)]))))
describe "slidingWindowMinOn" $ do
it "behaves like a (S.map (Foldable.minimumBy (comparing p))) (slidingWindow) for non-empty streams" $ do
property $ \(NonEmpty xs) k -- we use NonEmpty because Foldable.minimumBy crashes on empty lists
->
toL (S.slidingWindowMinOn fst k (S.each xs)) ===
toL (S.map (Foldable.minimumBy (comparing fst)) (S.slidingWindow k (S.each (xs :: [(Int, Int)]))))
it "does not force the projected value to WHNF" $
property $ \xs k ->
(length xs >= k) ==>
(toL (S.slidingWindowMinOn (const (undefined :: UnitWithLazyEq)) k (S.each (xs :: [Int]))) ===
take (length xs - (k - 1)) xs)
describe "slidingWindowMax" $ do
it "produces no results with empty streams" $
property $ \k -> toL (S.slidingWindowMax k (mempty :: S.Stream (S.Of Int) Identity ())) `shouldBe` []
it "behaves like a (S.map Foldable.maximum) (slidingWindow n s) for non-empty streams" $
property $ \(NonEmpty xs) k -- we use NonEmpty because Foldable.maximum crashes on empty lists
->
toL (S.slidingWindowMax k (S.each xs)) ===
toL (S.map Foldable.maximum (S.slidingWindow k (S.each (xs :: [Int]))))
it "behaves like identity when window size is 1" $
property $ \xs -> toL (S.slidingWindowMax 1 (S.each (xs :: [Int]))) === xs
it "produces a suffix when the stream elements are sorted" $
property $ \(Sorted xs) k ->
(length xs >= k) ==> (toL (S.slidingWindowMax k (S.each (xs :: [Int]))) === drop (k - 1) xs)
describe "slidingWindowMaxBy" $ do
it "prefers later elements when several elements compare equal" $ do
toL (S.slidingWindowMaxBy (comparing fst) 2 (S.each [(1, 1), (2, 2), (2, 3), (2, -900)])) `shouldBe`
[(2, 2), (2, 3), (2, -900)]
it "behaves like a (S.map (Foldable.maximumBy f)) (slidingWindow) for non-empty streams" $ do
property $ \(NonEmpty xs) k -- we use NonEmpty because Foldable.maximumBy crashes on empty lists
->
toL (S.slidingWindowMaxBy (comparing fst) k (S.each xs)) ===
toL (S.map (Foldable.maximumBy (comparing fst)) (S.slidingWindow k (S.each (xs :: [(Int, Int)]))))
describe "slidingWindowMaxOn" $ do
it "behaves like a (S.map (Foldable.maximumBy (comparing p))) (slidingWindow) for non-empty streams" $ do
property $ \(NonEmpty xs) k -- we use NonEmpty because Foldable.maximumBy crashes on empty lists
->
toL (S.slidingWindowMaxOn fst k (S.each xs)) ===
toL (S.map (Foldable.maximumBy (comparing fst)) (S.slidingWindow k (S.each (xs :: [(Int, Int)]))))
it "does not force the projected value to WHNF" $
property $ \xs k ->
(length xs >= k) ==>
(toL (S.slidingWindowMaxOn (const (undefined :: UnitWithLazyEq)) k (S.each (xs :: [Int]))) === drop (k - 1) xs)
data UnitWithLazyEq = UnitWithLazyEq
instance Eq UnitWithLazyEq where
_ == _ = True
instance Ord UnitWithLazyEq where
compare _ _ = EQ