tasty-laws 0.2 → 0.3
raw patch · 9 files changed
+358/−120 lines, 9 filesdep ~smallcheck-laws
Dependency ranges changed: smallcheck-laws
Files
- CHANGELOG.md +9/−0
- README.md +1/−1
- Test/Tasty/Laws/Applicative.hs +71/−23
- Test/Tasty/Laws/Functor.hs +109/−17
- Test/Tasty/Laws/Monad.hs +54/−19
- Test/Tasty/Laws/Monoid.hs +52/−15
- stack.yaml +1/−1
- tasty-laws.cabal +6/−4
- tests/tasty.hs +55/−40
CHANGELOG.md view
@@ -4,6 +4,14 @@ CHANGELOG](http://keepachangelog.com/). This project adheres to [Semantic Versioning](http://semver.org/). +## [Unreleased][unreleased]+### Changed+- `Serial` instances instead `Proxy` where possible.++### Added+- Default tests for type constructors parametrized with `()`.+- Exhaustive `TestTree`s.+ ## [0.2] - 2015-09-04 ### Removed - `smallcheck` specific modules from@@ -13,4 +21,5 @@ ### Changed - Simplify module hierarchy: `Test.Tasty.SmallCheck.Laws` -> `Test.Tasty.Laws` +[unreleased]: https://github.com/jdnavarro/tasty-laws/compare/v0.2...HEAD [0.2]: https://github.com/jdnavarro/tasty-laws/compare/bf1caa5...v0.2
README.md view
@@ -3,7 +3,7 @@ [](https://hackage.haskell.org/package/tasty-laws) [](https://travis-ci.org/jdnavarro/tasty-laws) -Preassembled `tasty` runners for property testing the following laws:+Preassembled `tasty` `TestTree`s for property testing the following laws: - Monoids - Functors
Test/Tasty/Laws/Applicative.hs view
@@ -1,7 +1,16 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-}-module Test.Tasty.Laws.Applicative where+-- | This module is intended to be imported @qualified@, for example:+--+-- > import qualified Test.Tasty.Laws.Applicative as Applicative+--+module Test.Tasty.Laws.Applicative+ ( test+ , testMono+ , testMonoExhaustive+ , module Test.SmallCheck.Laws.Applicative+ ) where #if !MIN_VERSION_base(4,8,0) import Control.Applicative (Applicative)@@ -11,39 +20,78 @@ import Test.Tasty (TestTree, testGroup) import Test.Tasty.SmallCheck (testProperty) import Test.SmallCheck.Series (Series, Serial(series))+import Test.SmallCheck.Laws.Applicative+ ( identity+ , composition+ , compositionSum+ , homomorphism+ , homomorphismSum+ , interchange+ , interchangeSum+ ) -import qualified Test.SmallCheck.Laws.Applicative as Applicative-import Test.Tasty.Laws.Functor+import qualified Test.Tasty.Laws.Functor as Functor --- | @tasty@ 'TestTree' for 'Applicative' laws. You need to provide the type--- wrapped in a `Proxy` and make sure 'a' is an instance of 'Serial'.-testApplicative+-- | @tasty@ 'TestTree' for 'Applicative' laws. The type signature forces the+-- parameter to be '()' which, unless you are dealing with non-total+-- functions, should be enough to test any 'Applicative's.+test+ :: ( Applicative f+ , Eq (f ()), Eq (f (f ())), Show (f ()), Show (f (() -> ()))+ , Serial Identity (f ())+ , Serial IO (f ()), Serial IO (f (() -> ()))+ )+ => Series IO (f ()) -> TestTree+test = testMonoExhaustive++-- | @tasty@ 'TestTree' for 'Applicative' laws. Monomorphic sum 'Series'.+testMono :: forall f a . ( Applicative f- , Show a, Eq a- , Show (f a), Eq (f a), (Eq (f (f a)))- , Show (f (a -> a))- , Serial IO a- , Serial IO (f a)- , Serial IO (a -> a)- , Serial IO (f (a -> a))+ , Eq a, Eq (f a), (Eq (f (f a)))+ , Show a, Show (f a), Show (f (a -> a)) , Serial Identity a, Serial Identity (f a)+ , Serial IO a, Serial IO (f a), Serial IO (a -> a), Serial IO (f (a -> a)) )- => Proxy (f a) -> TestTree-testApplicative proxy = testGroup "Applicative"- [ testFunctor proxy- , testProperty "pure id <*> v ≡ v"- $ Applicative.identity (series :: Series IO (f a))- , testProperty "(.) <$> u <*> v <*> w ≡ u <*> (v <*> w)"- $ Applicative.composition+ => Series IO (f a) -> TestTree+testMono fs = testGroup "Applicative"+ [ Functor.testMono fs+ , testProperty "pure id <*> v ≡ v" $ identity fs+ , testProperty "(.) <$> u <*> v <*> w ≡ u <*> (v <*> w)" $ compositionSum (series :: Series IO (f (a -> a))) (series :: Series IO (f a)) (series :: Series IO (f (a -> a)))- , testProperty "pure f <*> pure x ≡ pure (f x)" $ Applicative.homomorphism- (Proxy :: Proxy f)+ , testProperty "pure f <*> pure x ≡ pure (f x)" $ homomorphismSum+ (Proxy :: Proxy f) (series :: Series IO a) (series :: Series IO (a -> a))- , testProperty "u <*> pure y ≡ pure ($ y) <*> u" $ Applicative.interchange+ , testProperty "u <*> pure y ≡ pure ($ y) <*> u" $ interchangeSum+ (series :: Series IO a)+ (series :: Series IO (f (a -> a)))+ ]++-- | @tasty@ 'TestTree' for 'Applicative' laws. Monomorphic product 'Series'.+testMonoExhaustive+ :: forall f a .+ ( Applicative f+ , Eq a, Eq (f a), (Eq (f (f a)))+ , Show a, Show (f a), Show (f (a -> a))+ , Serial Identity a, Serial Identity (f a)+ , Serial IO a, Serial IO (f a), Serial IO (a -> a), Serial IO (f (a -> a))+ )+ => Series IO (f a) -> TestTree+testMonoExhaustive fs = testGroup "Applicative"+ [ Functor.testMonoExhaustive fs+ , testProperty "pure id <*> v ≡ v" $ identity fs+ , testProperty "(.) <$> u <*> v <*> w ≡ u <*> (v <*> w)" $ composition+ (series :: Series IO (f (a -> a)))+ (series :: Series IO (f a))+ (series :: Series IO (f (a -> a)))+ , testProperty "pure f <*> pure x ≡ pure (f x)" $ homomorphism+ (Proxy :: Proxy f)+ (series :: Series IO a)+ (series :: Series IO (a -> a))+ , testProperty "u <*> pure y ≡ pure ($ y) <*> u" $ interchange (series :: Series IO a) (series :: Series IO (f (a -> a))) ]
Test/Tasty/Laws/Functor.hs view
@@ -1,29 +1,121 @@ {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-}-module Test.Tasty.Laws.Functor where+-- | This module is intended to be imported @qualified@, for example:+--+-- > import qualified Test.Tasty.Laws.Functor as Functor+--+module Test.Tasty.Laws.Functor+ ( test+ , testMono+ , testMonoExhaustive+ , testPoly+ , testPolyExhaustive+ , module Test.SmallCheck.Laws.Functor+ ) where -import Data.Proxy (Proxy)+import Data.Proxy import Data.Functor.Identity (Identity) import Test.Tasty (TestTree, testGroup)-import Test.Tasty.SmallCheck (testProperty)+import Test.Tasty.SmallCheck (testProperty, Testable)+import Test.SmallCheck.Laws.Functor (identity, composition, compositionSum) import Test.SmallCheck.Series (Serial(series), Series) -import qualified Test.SmallCheck.Laws.Functor as Functor+-- | @tasty@ 'TestTree' for 'Functor' laws. The type signature forces the+-- parameter to be '()' which, unless you are dealing non-total functions,+-- should be enough to test any 'Functor's.+test :: (Functor f, Eq (f ()), Show (f ())) => Series IO (f ()) -> TestTree+test = testMonoExhaustive --- | @tasty@ 'TestTree' for 'Functor' laws. You need to provide the type--- wrapped in a `Proxy` and make sure 'a' is an instance of 'Serial'.-testFunctor+-- | @tasty@ 'TestTree' for 'Functor' laws. Monomorphic sum 'Series' for @f@+-- and @g@ in the compose law.+--+-- @+-- fmap (\a -> a) . (\a -> a) == fmap (\a -> a) . fmap (\a -> a)+-- fmap (\b -> b) . (\b -> b) == fmap (\b -> b) . fmap (\b -> b)+-- ...+-- @+testMono :: forall f a .- ( Eq (f a), Eq (f (f a)), Functor f, Show a, Show (f a)- , Serial IO (f a)+ ( Eq (f a), Functor f, Show a, Show (f a)+ , Serial Identity a , Serial IO (a -> a)- , Serial Identity a, Serial Identity (f a) )- => Proxy (f a) -> TestTree-testFunctor _ = testGroup "Functor laws"- [ testProperty "fmap id ≡ id" $ Functor.identity (series :: Series IO (f a))- , testProperty "fmap (f . g) ≡ fmap f . fmap g" $ Functor.composition- (series :: Series IO (f a))- (series :: Series IO (a -> a))- (series :: Series IO (a -> a))+ => Series IO (f a) -> TestTree+testMono = testWithComp $ \fs ->+ compositionSum fs (series :: Series IO (a -> a))+ (series :: Series IO (a -> a))++-- | @tasty@ 'TestTree' for 'Functor' laws. Monomorphic product 'Series' for+-- @f@ and @g@ in the compose law.+--+-- @+-- fmap (\a -> a) . (\a -> a) == fmap (\a -> a) . fmap (\a -> a)+-- fmap (\a -> a) . (\a -> b) == fmap (\a -> a) . fmap (\a -> b)+-- fmap (\a -> a) . (\b -> b) == fmap (\a -> a) . fmap (\b -> b)+-- ...+-- @+testMonoExhaustive+ :: forall f a .+ ( Eq (f a), Functor f, Show a, Show (f a)+ , Serial Identity a+ , Serial IO (a -> a)+ )+ => Series IO (f a) -> TestTree+testMonoExhaustive = testWithComp $ \fs ->+ composition fs (series :: Series IO (a -> a))+ (series :: Series IO (a -> a))++-- | @tasty@ 'TestTree' for 'Functor' laws. Polymorphic sum 'Series' for+-- @f@ and @g@ in the compose law.+--+-- @+-- fmap (\a0 -> b0) . (\b0 -> c0) == fmap (\a0 -> b0) . fmap (\b0 -> c0)+-- fmap (\a1 -> b1) . (\b1 -> c1) == fmap (\a1 -> a1) . fmap (\b1 -> c1)+-- fmap (\a2 -> b2) . (\b2 -> c2) == fmap (\a2 -> a2) . fmap (\b2 -> c2)+-- ...+-- @+testPoly+ :: forall f a b c .+ ( Functor f+ , Eq (f a), Show a, Show (f a) , Serial Identity a+ , Eq (f b), Show b, Show (f b) , Serial Identity b+ , Eq (f c), Show c, Show (f c) , Serial Identity c+ , Serial IO (a -> b), Serial IO (b -> c)+ )+ => Proxy b -> Proxy c -> Series IO (f a) -> TestTree+testPoly _ _ = testWithComp $ \fs ->+ compositionSum fs (series :: Series IO (b -> c))+ (series :: Series IO (a -> b))++-- | @tasty@ 'TestTree' for 'Functor' laws. Polymorphic product 'Series' for+-- @f@ and @g@ in the compose law.+--+-- @+-- fmap (\a0 -> b0) . (\b0 -> c0) == fmap (\a0 -> b0) . fmap (\b0 -> c0)+-- fmap (\a0 -> b0) . (\b0 -> c1) == fmap (\a0 -> a0) . fmap (\b0 -> c1)+-- fmap (\a0 -> b0) . (\b0 -> c0) == fmap (\a0 -> a0) . fmap (\b1 -> c1)+-- ...+-- @+testPolyExhaustive+ :: forall f a b c .+ ( Functor f+ , Eq (f a), Show a, Show (f a) , Serial Identity a+ , Eq (f b), Show b, Show (f b) , Serial Identity b+ , Eq (f c), Show c, Show (f c) , Serial Identity c+ , Serial IO (a -> b), Serial IO (b -> c)+ )+ => Proxy b -> Proxy c -> Series IO (f a) -> TestTree+testPolyExhaustive _ _ = testWithComp $ \fs ->+ composition fs (series :: Series IO (b -> c))+ (series :: Series IO (a -> b))++-- * Internal++testWithComp+ :: (Eq (f a), Functor f, Show (f a), Testable IO r)+ => (Series IO (f a) -> r) -> Series IO (f a) -> TestTree+testWithComp comp fs = testGroup "Functor laws"+ [ testProperty "fmap id ≡ id" $ identity fs+ , testProperty "fmap (f . g) ≡ fmap f . fmap g"+ $ comp fs ]
Test/Tasty/Laws/Monad.hs view
@@ -1,36 +1,71 @@ {-# LANGUAGE CPP #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE ScopedTypeVariables #-}-module Test.Tasty.Laws.Monad where+-- | This module is intended to be imported @qualified@, for example:+--+-- > import qualified Test.Tasty.Laws.Monad as Monad+--+module Test.Tasty.Laws.Monad+ ( test+ , testMono+ , testMonoExhaustive+ ) where #if !MIN_VERSION_base(4,8,0) import Control.Applicative (Applicative) #endif import Data.Functor.Identity (Identity)-import Data.Proxy (Proxy(..)) import Test.SmallCheck.Series (Series, Serial(series))+import Test.SmallCheck.Laws.Monad (associativity, associativitySum) import Test.Tasty (TestTree, testGroup) import Test.Tasty.SmallCheck (testProperty)-import qualified Test.SmallCheck.Laws.Monad as Monad+import qualified Test.Tasty.Laws.Applicative as Applicative -import Test.Tasty.Laws.Applicative+-- | @tasty@ 'TestTree' for 'Monad' laws. The type signature forces the+-- parameter to be '()' which, unless you are dealing with non-total+-- functions, should be enough to test any 'Monad's.+test+ :: ( Applicative m, Monad m+ , Eq (m ()), Eq (m (m ()))+ , Show (m ()), Show (m (() -> ()))+ , Serial Identity (m ())+ , Serial IO (m ()), Serial IO (m (() -> ()))+ )+ => Series IO (m ()) -> TestTree+test = testMonoExhaustive --- | @tasty@ 'TestTree' for 'Monad' laws. You need to provide the type--- wrapped in a `Proxy` and make sure 'a' is an instance of 'Serial'.-testMonad- :: forall f a .- ( Applicative f, Monad f- , Show a, Show (f a), Show (f (a -> a))- , Eq a, Eq (f a), Eq (f (f a))+-- | @tasty@ 'TestTree' for 'Monad' laws. Monomorphic sum 'Series'.+testMono+ :: forall m a .+ ( Applicative m, Monad m+ , Eq a, Eq (m a), Eq (m (m a))+ , Show a, Show (m a), Show (m (a -> a))+ , Serial Identity a, Serial Identity (m a) , Serial IO a, Serial IO (a -> a)- , Serial IO (f a) ,Serial IO (f (a -> a)), Serial IO (a -> f a)- , Serial Identity a, Serial Identity (f a)+ , Serial IO (m a) ,Serial IO (m (a -> a)), Serial IO (a -> m a) )- => Proxy (f a) -> TestTree-testMonad proxy = testGroup "Monad laws"- [ testApplicative proxy+ => Series IO (m a) -> TestTree+testMono ms = testGroup "Monad laws"+ [ Applicative.testMono ms , testProperty "(m >>= f) >>= g ≡ m (f >=> g)"- $ Monad.associativity (series :: Series IO (f a))- (series :: Series IO (a -> f a))- (series :: Series IO (a -> f a))+ $ associativitySum ms (series :: Series IO (a -> m a))+ (series :: Series IO (a -> m a))+ ]++-- | @tasty@ 'TestTree' for 'Monad' laws. Monomorphic product 'Series'.+testMonoExhaustive+ :: forall m a .+ ( Applicative m, Monad m+ , Eq a, Eq (m a), Eq (m (m a))+ , Show a, Show (m a), Show (m (a -> a))+ , Serial Identity a, Serial Identity (m a)+ , Serial IO a, Serial IO (a -> a)+ , Serial IO (m a) ,Serial IO (m (a -> a)), Serial IO (a -> m a)+ )+ => Series IO (m a) -> TestTree+testMonoExhaustive ms = testGroup "Monad laws"+ [ Applicative.testMono ms+ , testProperty "(m >>= f) >>= g ≡ m (f >=> g)"+ $ associativity ms (series :: Series IO (a -> m a))+ (series :: Series IO (a -> m a)) ]
Test/Tasty/Laws/Monoid.hs view
@@ -1,26 +1,63 @@ {-# LANGUAGE CPP #-}-{-# LANGUAGE FlexibleContexts #-}-{-# LANGUAGE ScopedTypeVariables #-}-module Test.Tasty.Laws.Monoid where+-- | This module is intended to be imported @qualified@:+--+-- > import qualified Test.Tasty.Laws.Monoid as Monoid+--+module Test.Tasty.Laws.Monoid+ ( test+ , testExhaustive+ , testMConcat+ , module Test.SmallCheck.Laws.Monoid+ ) where #if !MIN_VERSION_base(4,8,0) import Data.Monoid (Monoid) #endif-import Data.Proxy (Proxy)-import Test.SmallCheck.Series (Series, Serial(series))++import Test.SmallCheck.Series (Series)+import Test.SmallCheck.Laws.Monoid+ ( leftIdentity+ , rightIdentity+ , associativity+ , associativitySum+ , mconcatProp+ ) import Test.Tasty (TestTree, testGroup) import Test.Tasty.SmallCheck (testProperty) -import qualified Test.SmallCheck.Laws.Monoid as Monoid+-- | @tasty@ 'TestTree' for 'Monoid' laws. Sum of series for associativity law.+--+-- @+-- ('a' <> 'a') <> 'a' == 'a' <> ('a' <> 'a')+-- ('b' <> 'b') <> 'b' == 'b' <> ('b' <> 'b')+-- ('c' <> 'c') <> 'c' == 'c' <> ('c' <> 'c')+-- ...+-- @+test :: (Eq a, Show a, Monoid a) => Series IO a -> TestTree+test ms = testGroup "Monoid laws"+ [ testProperty "mempty <> x ≡ x" $ leftIdentity ms+ , testProperty "x <> mempty ≡ x" $ rightIdentity ms+ , testProperty "x <> (y <> z) ≡ (x <> y) <> z"+ $ associativitySum ms ms ms+ ] --- | @tasty@ 'TestTree' for 'Applicative' laws. You need to provide the type--- wrapped in a `Proxy` and make sure 'a' is an instance of 'Serial'.-testMonoid :: forall a . (Show a, Eq a, Monoid a, Serial IO a) => Proxy a -> TestTree-testMonoid _ = testGroup "Monoid laws"- [ testProperty "mempty <> x ≡ x" $ Monoid.leftIdentity (series :: Series IO a)- , testProperty "x <> mempty ≡ x" $ Monoid.rightIdentity (series :: Series IO a)+-- | @tasty@ 'TestTree' for 'Monoid' laws. Product of series for associativity+-- law. Be aware of combinatorial explosion.+--+-- @+-- ('a' <> 'a') <> 'a' == 'a' <> ('a' <> 'a')+-- ('a' <> 'a') <> 'b' == 'a' <> ('a' <> 'b')+-- ('a' <> 'b') <> 'b' == 'a' <> ('b' <> 'b')+-- ...+-- @+testExhaustive :: (Eq a, Show a, Monoid a) => Series IO a -> TestTree+testExhaustive ms = testGroup "Monoid laws"+ [ testProperty "mempty <> x ≡ x" $ leftIdentity ms+ , testProperty "x <> mempty ≡ x" $ rightIdentity ms , testProperty "x <> (y <> z) ≡ (x <> y) <> z"- $ Monoid.associativity (series :: Series IO a) series series- , testProperty "mconcat ≡ foldr mappend mempty"- $ Monoid.mconcat (series :: Series IO a)+ $ associativity ms ms ms ]++-- | Use this test when implementing the 'mconcat' method.+testMConcat :: (Eq a, Show a, Monoid a) => Series IO a -> TestTree+testMConcat ms = testProperty "mconcat ≡ foldr mappend mempty" $ mconcatProp ms
stack.yaml view
@@ -2,6 +2,6 @@ packages: - '.' extra-deps:-- smallcheck-laws-0.2+- smallcheck-laws-0.3 - smallcheck-series-0.5.1 resolver: lts-3.4
tasty-laws.cabal view
@@ -1,13 +1,15 @@ name: tasty-laws-version: 0.2+version: 0.3 synopsis: Test common laws description:- Preassembled 'tasty' runners for property testing 'Monoid', 'Functor',+ Preassembled 'tasty' 'TestTree's for property testing 'Monoid', 'Functor', 'Applicative' and 'Monad' laws. license: BSD3 license-file: LICENSE author: Danny Navarro maintainer: j@dannynavarro.net+homepage: https://github.com/jdnavarro/tasty-laws+bug-reports: https://github.com/jdnavarro/tasty-laws/issues category: Testing build-type: Simple cabal-version: >=1.10@@ -26,7 +28,7 @@ Test.Tasty.Laws.Monoid build-depends: base >=4.6 && <4.9, smallcheck >=1.1.1,- smallcheck-laws >=0.1,+ smallcheck-laws >=0.3, smallcheck-series >=0.3, tasty >=0.10, tasty-smallcheck >=0.8.0.1@@ -45,7 +47,7 @@ build-depends: base >=4.6 && <4.9, smallcheck >=1.1.1, tasty >=0.10,- smallcheck-laws >=0.1,+ smallcheck-laws >=0.3, tasty-laws if impl(ghc < 7.8)
tests/tasty.hs view
@@ -8,15 +8,14 @@ import Control.Applicative ((<$>)) #endif import Data.Monoid (Sum(..), Product(..))-import Data.Proxy (Proxy(..)) -import Test.SmallCheck.Series (Serial(series))+import Test.SmallCheck.Series (Series, Serial(series)) import Test.Tasty (TestTree, defaultMain, testGroup) -import Test.Tasty.Laws.Applicative-import Test.Tasty.Laws.Functor-import Test.Tasty.Laws.Monad-import Test.Tasty.Laws.Monoid+import qualified Test.Tasty.Laws.Applicative as Applicative+import qualified Test.Tasty.Laws.Functor as Functor+import qualified Test.Tasty.Laws.Monad as Monad+import qualified Test.Tasty.Laws.Monoid as Monoid main :: IO () main = defaultMain $ testGroup "Laws"@@ -26,74 +25,90 @@ , monadTests ] +instance (Monad m, Serial m a) => Serial m (Sum a) where+ series = Sum <$> series++instance (Monad m, Serial m a) => Serial m (Product a) where+ series = Product <$> series+ monoidTests :: TestTree monoidTests = testGroup "Monoid"- [ testGroup "Sum"- [ testGroup "Int"- [ testMonoid (Proxy :: Proxy (Sum Int)) ]+ [ testGroup "Product"+ [ testGroup "Int"+ [ Monoid.test (series :: Series IO (Product Int)) ] , testGroup "Integer"- [ testMonoid (Proxy :: Proxy (Sum Integer)) ]+ [ Monoid.test (series :: Series IO (Product Integer)) ] , testGroup "Float"- [ testMonoid (Proxy :: Proxy (Sum Float)) ]+ [ Monoid.test (series :: Series IO (Product Float)) ] ]- , testGroup "Product"- [ testGroup "Int"- [ testMonoid (Proxy :: Proxy (Product Int)) ]+ , testGroup "Exhausitive Sum"+ [ testGroup "Int"+ [ Monoid.testExhaustive (series :: Series IO (Sum Int)) ] , testGroup "Integer"- [ testMonoid (Proxy :: Proxy (Product Integer)) ]+ [ Monoid.testExhaustive (series :: Series IO (Sum Integer)) ] , testGroup "Float"- [ testMonoid (Proxy :: Proxy (Product Float)) ]+ [ Monoid.testExhaustive (series :: Series IO (Sum Float)) ] ] ] functorTests :: TestTree functorTests = testGroup "Functor" [ testGroup "Maybe"- [ testGroup "Int"- [ testFunctor (Proxy :: Proxy (Maybe Int)) ]+ [ testGroup "Unit"+ [ Functor.test (series :: Series IO (Maybe ())) ]+ , testGroup "Int"+ [ Functor.testMono (series :: Series IO (Maybe Int)) ] , testGroup "Char"- [ testFunctor (Proxy :: Proxy (Maybe Char)) ]+ [ Functor.testMono (series :: Series IO (Maybe Char)) ]+ , testGroup "Bool"+ [ Functor.testMonoExhaustive (series :: Series IO (Maybe Bool)) ] ] , testGroup "[]"- [ testGroup "Bool"- [ testFunctor (Proxy :: Proxy [Bool]) ]+ [ testGroup "Unit"+ [ Functor.test (series :: Series IO [()]) ]+ , testGroup "Bool"+ [ Functor.testMono (series :: Series IO [Bool]) ] , testGroup "Int"- [ testFunctor (Proxy :: Proxy [Int]) ]+ [ Functor.testMono (series :: Series IO [Int]) ] ] ] applicativeTests :: TestTree applicativeTests = testGroup "Applicative" [ testGroup "Maybe"- [ testGroup "Int"- [ testApplicative (Proxy :: Proxy (Maybe Int)) ]+ [ testGroup "Unit"+ [ Applicative.test (series :: Series IO (Maybe ())) ]+ , testGroup "Bool"+ [ Applicative.testMonoExhaustive (series :: Series IO (Maybe Bool)) ]+ , testGroup "Int"+ [ Applicative.testMono (series :: Series IO (Maybe Int)) ] , testGroup "Float"- [ testApplicative (Proxy :: Proxy (Maybe Float)) ]+ [ Applicative.testMono (series :: Series IO (Maybe Float)) ] ] , testGroup "[]"- [ testGroup "Bool"- [ testApplicative (Proxy :: Proxy [Bool]) ]- , testGroup "Char"- [ testApplicative (Proxy :: Proxy [Char]) ]+ [ testGroup "Unit"+ [ Applicative.test (series :: Series IO [()]) ]+ , testGroup "Bool"+ [ Applicative.testMono (series :: Series IO [Bool]) ]+ -- , testGroup "Char"+ -- [ Applicative.testMono (series :: Series IO [Char]) ] ] ] monadTests :: TestTree monadTests = testGroup "Monad" [ testGroup "Maybe"- [ testGroup "()"- [ testMonad (Proxy :: Proxy (Maybe ())) ]+ [ testGroup "Unit"+ [ Monad.test (series :: Series IO (Maybe ())) ]+ , testGroup "Bool"+ [ Monad.testMonoExhaustive (series :: Series IO (Maybe Bool)) ] , testGroup "Int"- [ testMonad (Proxy :: Proxy (Maybe Int)) ]+ [ Monad.testMono (series :: Series IO (Maybe Int)) ] ] , testGroup "[]"- [ testGroup "()"- [ testMonad (Proxy :: Proxy [()]) ]+ [ testGroup "Unit"+ [ Monad.test (series :: Series IO [()]) ]+ , testGroup "Bool"+ [ Monad.testMono (series :: Series IO [Bool]) ] ] ]--instance (Monad m, Serial m a) => Serial m (Sum a) where- series = Sum <$> series--instance (Monad m, Serial m a) => Serial m (Product a) where- series = Product <$> series