hedgehog-classes-0.1.0.0: src/Hedgehog/Classes/Enum.hs
{-# LANGUAGE ScopedTypeVariables #-}
module Hedgehog.Classes.Enum (enumLaws, boundedEnumLaws) where
import Hedgehog
import Hedgehog.Classes.Common
import qualified Hedgehog.Gen as Gen
-- | Tests the following 'Enum' laws:
--
-- [__Succ-Pred Identity__]: @'succ' '.' 'pred'@ ≡ @'id'@
-- [__Pred-Succ Identity__]: @'pred' '.' 'succ'@ ≡ @'id'@
enumLaws :: (Enum a, Eq a, Show a) => Gen a -> Laws
enumLaws gen = Laws "Enum"
[ ("Succ Pred Identity", succPredIdentity gen)
, ("Pred Succ Identity", predSuccIdentity gen)
]
-- | Tests the same laws as 'enumLaws', but uses the 'Bounded'
-- constraint to ensure that 'succ' and 'pred' behave as though
-- they are total. This should always be preferred if your type
-- has a 'Bounded' instance.
boundedEnumLaws :: (Bounded a, Enum a, Eq a, Show a) => Gen a -> Laws
boundedEnumLaws gen = Laws "Bounded Enum"
[ ("Succ Pred Identity", succPredBoundedIdentity gen)
, ("Pred Succ Identity", predSuccBoundedIdentity gen)
]
succPredIdentity :: forall a. (Enum a, Eq a, Show a) => Gen a -> Property
succPredIdentity gen = property $ do
x <- forAll gen
let lhs = succ (pred x); rhs = x;
let ctx = contextualise $ LawContext
{ lawContextLawName = "Succ-Pred Identity"
, lawContextLawBody = "succ . pred" `congruency` "id"
, lawContextTcName = "Enum"
, lawContextTcProp =
let showX = show x
in lawWhere
[ "succ . pred $ x" `congruency` "id x, where"
, "x = " ++ showX
]
, lawContextReduced = reduced lhs rhs
}
heqCtx lhs rhs ctx
predSuccIdentity :: forall a. (Enum a, Eq a, Show a) => Gen a -> Property
predSuccIdentity gen = property $ do
x <- forAll gen
let lhs = pred (succ x); rhs = x;
let ctx = contextualise $ LawContext
{ lawContextLawName = "Pred-Succ Identity"
, lawContextLawBody = "pred . succ" `congruency` "id"
, lawContextTcName = "Enum"
, lawContextTcProp =
let showX = show x
in lawWhere
[ "pred . succ $ x" `congruency` "id x, where"
, "x = " ++ showX
]
, lawContextReduced = reduced lhs rhs
}
heqCtx lhs rhs ctx
succPredBoundedIdentity :: forall a. (Bounded a, Enum a, Eq a, Show a) => Gen a -> Property
succPredBoundedIdentity gen = property $ do
x <- forAll $ Gen.filter (/= minBound) gen
let lhs = succ (pred x); rhs = x;
let ctx = contextualise $ LawContext
{ lawContextLawName = "Succ-Pred Identity"
, lawContextLawBody = "succ . pred" `congruency` "id"
, lawContextTcName = "Enum"
, lawContextTcProp =
let showX = show x
in lawWhere
[ "succ . pred $ x" `congruency` "id x, where"
, "x = " ++ showX
]
, lawContextReduced = reduced lhs rhs
}
heqCtx lhs rhs ctx
predSuccBoundedIdentity :: forall a. (Bounded a, Enum a, Eq a, Show a) => Gen a -> Property
predSuccBoundedIdentity gen = property $ do
x <- forAll $ Gen.filter (/= maxBound) gen
let lhs = pred (succ x); rhs = x;
let ctx = contextualise $ LawContext
{ lawContextLawName = "Pred-Succ Identity"
, lawContextLawBody = "pred . succ" `congruency` "id"
, lawContextTcName = "Enum"
, lawContextTcProp =
let showX = show x
in lawWhere
[ "pred . succ $ x" `congruency` "id x, where"
, "x = " ++ showX
]
, lawContextReduced = reduced lhs rhs
}
heqCtx lhs rhs ctx