FailT-0.1.0.0: tests/Test/Control/Monad/Trans/FailSpec.hs
{-# LANGUAGE CPP #-}
{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# OPTIONS_GHC -Wno-orphans #-}
module Test.Control.Monad.Trans.FailSpec (spec) where
import Control.Monad.Reader
import Control.Monad.State
import Control.Monad.Trans.Fail
import Data.Proxy
import Data.Semigroup
import Test.Hspec
import Test.Hspec.QuickCheck
import Test.QuickCheck
import Test.QuickCheck.Classes
laws :: Laws -> Spec
laws Laws{lawsTypeclass, lawsProperties} =
describe lawsTypeclass $ mapM_ (uncurry prop) lawsProperties
instance (Applicative m, Arbitrary e, Arbitrary a) => Arbitrary (FailT e m a) where
arbitrary = FailT . pure <$> arbitrary
instance (Arbitrary e, Arbitrary1 m, Applicative m) => Arbitrary1 (FailT e m) where
liftArbitrary gen =
oneof
[ FailT . pure . Left <$> arbitrary
, FailT . pure . Right <$> gen
]
{-# INLINE liftArbitrary #-}
spec :: Spec
spec = do
describe "FailT" $ do
prop "runFail" $ \err -> runFail (fail err :: Fail String ()) `shouldBe` Left err
describe "Instance Laws" $ do
let px = Proxy :: Proxy (FailT String Maybe (Sum Int))
let px1 = Proxy :: Proxy (FailT String Maybe)
mapM_ laws $
[ eqLaws px
, ordLaws px
, showLaws px
, showReadLaws px
, monoidLaws px
, semigroupLaws px
, alternativeLaws px1
, applicativeLaws px1
, foldableLaws px1
, functorLaws px1
, monadLaws px1
, monadZipLaws px1
, traversableLaws px1
]
++ extraLaws px
describe "mtl" $ do
prop "MonadReader" $ \msg (x :: Int) -> do
let t :: FailT String (ReaderT Int IO) Int
t = do
x' <- ask
pure $ succ x'
runReaderT (runFailT t) x `shouldReturn` Right (x + 1)
runReaderT (runFailT (fail msg >> pure x)) x `shouldReturn` Left msg
prop "MonadState" $ \msg (x :: Int) -> do
let t :: FailT String (StateT Int IO) ()
t = do
x' <- get
liftIO (x' `shouldBe` x)
put (x' + 1)
modify' succ
execStateT (runFailT t) x `shouldReturn` (x + 2)
runStateT (runFailT (fail msg >> modify' succ)) x `shouldReturn` (Left msg, x)
extraLaws :: (Semigroup a, Monoid a, Eq a, Arbitrary a, Show a) => Proxy a -> [Laws]
#if MIN_VERSION_quickcheck_classes(0,6,2)
extraLaws px = [semigroupMonoidLaws px]
#else
extraLaws _px = []
#endif