data-msgpack-types-0.0.2: test/Data/MessagePack/ResultSpec.hs
{-# LANGUAGE Trustworthy #-}
module Data.MessagePack.ResultSpec where
import Test.Hspec
import Test.QuickCheck
import Control.Applicative (empty, pure, (<$>), (<*>),
(<|>))
import qualified Data.MessagePack.Types.Result as R
newtype F = F (Int -> R.Result Int)
instance Show F where
show = const "<function>"
instance Arbitrary F where
arbitrary = F <$> arbitrary
-- | Checks that 'R.Result' satisfies the laws described in the 'Monad' and
-- 'Applicative' documentation.
--
-- Also see:
-- https://wiki.haskell.org/Monad_laws
-- https://hackage.haskell.org/package/base-4.9.0.0/docs/Prelude.html#t:Applicative
spec :: Spec
spec = do
describe "Monad" $ do
it "satisfies left identity" $
property $ \a (F f) ->
(return' a `bind'` f) `shouldBe` f a
it "satisfies right identity" $
property $ \m ->
(m `bind'` return') `shouldBe` m
it "satisfies associativity" $
property $ \m (F f) (F g) ->
((m `bind'` f) `bind'` g) `shouldBe` (m `bind'` (\x -> f x `bind'` g))
it "supports 'fail'" $
fail' "nope" `shouldBe` R.Failure "nope"
describe "Applicative" $ do
it "satisfies identity" $
property identity
it "satisfies composition" $
property $ \x y w -> do
composition (R.Failure "nope") (R.Failure "no way") w
composition (R.Failure "nope") (pure (y *) ) w
composition (pure (x *) ) (R.Failure "no way") w
composition (pure (x *) ) (pure (y *) ) w
it "satisfies homomorphism" $
property $ \x -> homomorphism (x *)
it "satisfies interchange" $
property $ \x y -> do
interchange (R.Failure "nope") y
interchange (pure (x *) ) y
describe "Alternative" $ do
it "chooses the left-most success" $ do
R.Success "a" <|> R.Success "b" `shouldBe` R.Success "a"
R.Success "a" <|> R.Failure "b" `shouldBe` R.Success "a"
R.Failure "a" <|> R.Success "b" `shouldBe` R.Success "b"
it "chooses the right-most failure" $
R.Failure "a" <|> R.Failure "b" `shouldBe` (R.Failure "b" :: R.Result ())
describe "empty" $
it "is a failure" $
empty <|> R.Success "a" `shouldBe` R.Success "a"
where
--
-- Aliases constrained to the Result monad. These also help avoid lint
-- warnings about using monad laws.
--
return' :: Int -> R.Result Int
return' = return
bind' :: R.Result Int -> (Int -> R.Result Int) -> R.Result Int
bind' = (>>=)
fail' :: String -> R.Result Int
fail' = fail
pure' :: a -> R.Result a
pure' = pure
--
-- Applicative laws.
--
identity :: R.Result Int -> Expectation
identity v =
(pure' id <*> v) `shouldBe` v
composition :: R.Result (Int -> Int) -> R.Result (Int -> Int) -> R.Result Int -> Expectation
composition u v w =
(pure' (.) <*> u <*> v <*> w) `shouldBe` (u <*> (v <*> w))
homomorphism :: (Int -> Int) -> Int -> Expectation
homomorphism h x =
(pure' h <*> pure' x) `shouldBe` pure' (h x)
interchange :: R.Result (Int -> Int) -> Int -> Expectation
interchange u y =
(u <*> pure' y) `shouldBe` (pure' ($ y) <*> u)