tasty-quickcheck-laws-0.0.2: src/Test/Tasty/QuickCheck/Laws/ReaderMonad.hs
{- |
Module : Test.Tasty.QuickCheck.Laws.ReaderMonad
Description : Prefab tasty trees of quickcheck properties for the reader monad laws
Copyright : 2018, Automattic, Inc.
License : BSD3
Maintainer : Nathan Bloomfield (nbloomf@gmail.com)
Stability : experimental
Portability : POSIX
-}
{-# LANGUAGE Rank2Types #-}
module Test.Tasty.QuickCheck.Laws.ReaderMonad (
testReaderMonadLaws
-- * Reader Monad Laws
, testReaderMonadLawLocalAsk
, testReaderMonadLawLocalLocal
, testReaderMonadLawLocalThenAsk
, testReaderMonadLawLocalReturn
, testReaderMonadLawLocalBind
) where
import Data.Proxy
( Proxy(..) )
import Data.Typeable
( Typeable, typeRep )
import Test.Tasty
( TestTree, testGroup )
import Test.Tasty.QuickCheck
( testProperty, Property, Arbitrary(..), CoArbitrary(..) )
import Text.Show.Functions
()
import Test.Tasty.QuickCheck.Laws.Class
-- | Constructs a @TestTree@ checking that the reader monad laws hold for @m@ with reader type @r@ and value types @a@ and @b@, using a given equality test for values of type @forall u. m u@. The equality context type @t@ is for constructors @m@ from which we can only extract a value within a context, such as reader-like constructors.
testReaderMonadLaws
:: ( Monad m
, Eq r, Eq a, Eq b
, Show t, Show a
, Show (m a)
, Arbitrary t, Arbitrary r, Arbitrary a
, Arbitrary (m a), Arbitrary (m b)
, CoArbitrary r, CoArbitrary a
, Typeable m, Typeable r, Typeable a
)
=> Proxy m -- ^ Type constructor under test
-> Proxy t -- ^ Equality context for @m@
-> Proxy r -- ^ Reader type
-> Proxy a -- ^ Value type
-> Proxy b -- ^ Value type
-> (forall u. (Eq u) => t -> m u -> m u -> Bool) -- ^ Equality test
-> m r -- ^ @ask@
-> (forall u. (r -> r) -> m u -> m u) -- ^ @local@
-> TestTree
testReaderMonadLaws pm pt pr pa pb eq ask local =
let
label = "Reader Monad Laws for " ++ (show $ typeRep pm) ++ " with " ++
"r :: " ++ (show $ typeRep pr) ++ ", " ++
"a :: " ++ (show $ typeRep pa)
in
testGroup label
[ testReaderMonadLawLocalAsk pm pt pr eq ask local
, testReaderMonadLawLocalLocal pm pt pr pa eq local
, testReaderMonadLawLocalThenAsk pm pt pr pa eq ask local
, testReaderMonadLawLocalReturn pm pt pr pa eq local
, testReaderMonadLawLocalBind pm pt pr pa pb eq local
]
-- | @local u ask === fmap u ask@
testReaderMonadLawLocalAsk
:: ( Monad m
, Eq r
, Show t
, Arbitrary t, Arbitrary r
, CoArbitrary r
)
=> Proxy m -- ^ Type constructor under test
-> Proxy t -- ^ Equality context for @m@
-> Proxy r -- ^ Reader type
-> (forall u. (Eq u) => t -> m u -> m u -> Bool) -- ^ Equality test
-> m r -- ^ @ask@
-> (forall u. (r -> r) -> m u -> m u) -- ^ @local@
-> TestTree
testReaderMonadLawLocalAsk pm pt pr eq ask local =
testProperty "local u ask === fmap u ask" $
readerMonadLawLocalAsk pm pt pr eq ask local
readerMonadLawLocalAsk
:: (Monad m, Eq r)
=> Proxy m -> Proxy t -> Proxy r
-> (forall u. (Eq u) => t -> m u -> m u -> Bool) -- ^ Equality test
-> m r -- ^ ask
-> (forall u. (r -> r) -> m u -> m u) -- ^ local
-> t -> (r -> r) -> Bool
readerMonadLawLocalAsk _ _ _ eq ask local t u =
(eq t) (local u ask) (fmap u ask)
-- | @local u (local v x) === local (v . u) x@
testReaderMonadLawLocalLocal
:: ( Monad m
, Eq a
, Show t
, Show (m a)
, Arbitrary t, Arbitrary r
, Arbitrary (m a)
, CoArbitrary r
)
=> Proxy m -- ^ Type constructor under test
-> Proxy t -- ^ Equality context for @m@
-> Proxy r -- ^ Reader type
-> Proxy a -- ^ Value type
-> (forall u. (Eq u) => t -> m u -> m u -> Bool) -- ^ Equality test
-> (forall u. (r -> r) -> m u -> m u) -- ^ @local@
-> TestTree
testReaderMonadLawLocalLocal pm pt pr pa eq local =
testProperty "local u (local v x) === local (v . u) x" $
readerMonadLawLocalLocal pm pt pr pa eq local
readerMonadLawLocalLocal
:: (Monad m, Eq a)
=> Proxy m -> Proxy t -> Proxy r -> Proxy a
-> (forall u. (Eq u) => t -> m u -> m u -> Bool) -- ^ Equality test
-> (forall u. (r -> r) -> m u -> m u) -- ^ local
-> t -> (r -> r) -> (r -> r) -> m a -> Bool
readerMonadLawLocalLocal _ _ _ _ eq local t u v x =
(eq t) (local u (local v x)) (local (v . u) x)
-- | @local u ask === fmap u ask@
testReaderMonadLawLocalThenAsk
:: ( Monad m
, Eq r
, Show t
, Show (m a)
, Arbitrary t, Arbitrary r
, Arbitrary (m a)
, CoArbitrary r
)
=> Proxy m -- ^ Type constructor under test
-> Proxy t -- ^ Equality context for @m@
-> Proxy r -- ^ Reader type
-> Proxy a -- ^ Value type
-> (forall u. (Eq u) => t -> m u -> m u -> Bool) -- ^ Equality test
-> m r -- ^ @ask@
-> (forall u. (r -> r) -> m u -> m u) -- ^ @local@
-> TestTree
testReaderMonadLawLocalThenAsk pm pt pr pa eq ask local =
testProperty "local u ask === fmap u ask" $
readerMonadLawLocalThenAsk pm pt pr pa eq ask local
readerMonadLawLocalThenAsk
:: (Monad m, Eq r)
=> Proxy m -> Proxy t -> Proxy r -> Proxy a
-> (forall u. (Eq u) => t -> m u -> m u -> Bool) -- ^ Equality test
-> m r -- ^ ask
-> (forall u. (r -> r) -> m u -> m u) -- ^ local
-> t -> (r -> r) -> m a -> Bool
readerMonadLawLocalThenAsk _ _ _ _ eq ask local t u x =
(eq t) (local u x >> ask) (ask >>= \r -> local u x >> return r)
-- | @local u (return a) === return a@
testReaderMonadLawLocalReturn
:: ( Monad m
, Eq a
, Show t, Show a
, Arbitrary t, Arbitrary r, Arbitrary a
, CoArbitrary r
)
=> Proxy m -- ^ Type constructor under test
-> Proxy t -- ^ Equality context for @m@
-> Proxy r -- ^ Reader type
-> Proxy a -- ^ Value type
-> (forall u. (Eq u) => t -> m u -> m u -> Bool) -- ^ Equality test
-> (forall u. (r -> r) -> m u -> m u) -- ^ @local@
-> TestTree
testReaderMonadLawLocalReturn pm pt pr pa eq local =
testProperty "local u (return a) === return a" $
readerMonadLawLocalReturn pm pt pr pa eq local
readerMonadLawLocalReturn
:: (Monad m, Eq a)
=> Proxy m -> Proxy t -> Proxy r -> Proxy a
-> (forall u. (Eq u) => t -> m u -> m u -> Bool) -- ^ Equality test
-> (forall u. (r -> r) -> m u -> m u) -- ^ local
-> t -> (r -> r) -> a -> Bool
readerMonadLawLocalReturn _ _ _ _ eq local t u a =
(eq t) (local u (return a)) (return a)
-- | @local u (x >>= f) === local u x >>= (local u . f)@
testReaderMonadLawLocalBind
:: ( Monad m
, Eq b
, Show t, Show a
, Show (m a)
, Arbitrary t, Arbitrary r, Arbitrary a
, Arbitrary (m a), Arbitrary (m b)
, CoArbitrary r, CoArbitrary a
)
=> Proxy m -- ^ Type constructor under test
-> Proxy t -- ^ Equality context for @m@
-> Proxy r -- ^ Reader type
-> Proxy a -- ^ Value type
-> Proxy b -- ^ Value type
-> (forall u. (Eq u) => t -> m u -> m u -> Bool) -- ^ Equality test
-> (forall u. (r -> r) -> m u -> m u) -- ^ local
-> TestTree
testReaderMonadLawLocalBind pm pt pr pa pb eq local =
testProperty "local u (x >>= f) === local u x >>= (local u . f)" $
readerMonadLawLocalBind pm pt pr pa pb eq local
readerMonadLawLocalBind
:: (Monad m, Eq b)
=> Proxy m -> Proxy t -> Proxy r -> Proxy a -> Proxy b
-> (forall u. (Eq u) => t -> m u -> m u -> Bool) -- ^ Equality test
-> (forall u. (r -> r) -> m u -> m u) -- ^ local
-> t -> (r -> r) -> m a -> (a -> m b) -> Bool
readerMonadLawLocalBind _ _ _ _ _ eq local t u x f =
(eq t) (local u (x >>= f)) (local u x >>= (local u . f))