producer-0.1.0.0: test/Test/Streaming/ProducerSpec.hs
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# OPTIONS_GHC -fno-warn-missing-signatures #-}
module Test.Streaming.ProducerSpec where
import Data.Foldable
import Data.Functor.Identity
import qualified Data.List as DL
import Data.Proxy
import Prelude hiding (drop, filter, take)
import Streaming.Producer
import Test.QuickCheck.Arbitrary
import Test.QuickCheck.Checkers
import Test.QuickCheck.Classes
import Test.QuickCheck.Gen
import Test.QuickCheck.Property
import Test.Tasty
import Test.Tasty.Extensions
import Test.Tasty.HUnit as H
import Test.Tasty.QuickCheck as QC
test_show = prop "show" $ \(p :: ProducerInt) ->
show p == show (runList p)
test_append = testGroup "append" [
eg "sanity check - runList done" $
null $ run done
, eg "append done - done" $
null $ run $ append done done
, prop "append 2 producers" $ \(p1, p2) ->
run (append p1 p2) == (run p1 ++ run p2)
]
test_filter = testGroup "filter" [
prop "filter ints with tight predicate" $ \p ->
let f = (== 0) in
run (filter f p) == DL.filter f (run p)
, prop "filter ints with more accepting predicate" $ \p ->
let f = (> 0) in
run (filter f p) == DL.filter f (run p)
]
test_take = testGroup "take, drop, chunk" [
prop "take values" $ \(p, n) ->
run (take n p) == DL.take n (run p)
, prop "drop values" $ \(p, n) ->
run (drop n p) == DL.drop n (run p)
, prop "chunk values returns all values" $ \(p, n) ->
run (chunk n p) == run p
, minTestsOk 1000 $ prop "chunk values returns chunks of size == n, excepted possibly for the last one" $ \(p, n) ->
n <= 1 ||
size p < n ||
if n `rem` size p == 0 then
all (\c -> n == length c) (runC (chunk n p))
else
all (\c -> n == length c) (dropLast (runC (chunk n p)))
, prop "chunk values for a producer with no elements" $ \n ->
null $ runC (chunk n done)
, prop "chunk values for a producer with one element" $ \(n, a) ->
runC (chunk n (one a)) == [[a]]
]
test_monad = testGroup "laws" [
functorLaws (Proxy :: Proxy ProducerIntIntInt)
, applicativeLaws (Proxy :: Proxy ProducerIntIntInt)
, monadLaws (Proxy :: Proxy ProducerIntIntInt)
]
-- HELPERS
instance Arbitrary ProducerInt where
arbitrary = oneof [
elements [done, one 1],
more <$> arbitrary <*> arbitrary
]
instance Arbitrary (Producer Identity (Int -> Int)) where
arbitrary = oneof [
elements [done, one (+1), one (* 2)],
more <$> arbitrary <*> arbitrary
]
instance Arbitrary ProducerIntIntInt where
arbitrary =
do a <- arbitrary
b <- arbitrary
c <- arbitrary
oneof [
elements [done, one (a :: Int, b :: Int, c :: Int)],
more <$> arbitrary <*> arbitrary
]
run :: ProducerInt -> [Int]
run = runIdentity . runList
size :: ProducerInt -> Int
size = length . run
empty :: ProducerInt -> Bool
empty p = size p == 0
dropLast :: [a] -> [a]
dropLast [] = []
dropLast [_] = []
dropLast (a:as) = a : dropLast as
runC :: ProducerInt -> [[Int]]
runC = runIdentity . runChunks
type ProducerInt = Producer Identity Int
type ProducerIntIntInt = Producer Identity (Int, Int, Int)
instance Eq ProducerInt where
(==) p1 p2 = runList p1 == runList p2
instance EqProp ProducerInt where
(=-=) = eq