{- |
Properties for testing that instances of the 'Eq' class perform
correctly.
'p_reflexive', 'p_symmetric' and 'p_transitive' check the basic
properties of an equity relation. In other words, they test the
'==' method. 'p_not_equal' checks for the extraordinarily unlikely
case of '==' and '/=' not agreeing on equity. (The default
implementation of '/=' automatically guarantees that this test
will pass, and that's what most people presumably use.)
-}
module Test.AC.Class.Eq where
import Test.AC.Test
-- | Check that @x == x@.
p_reflexive :: (Show x, Eq x) => x -> Test
p_reflexive x =
title "x == x" $
x ?= x
-- | Check that if @x == y@ then @y == x@ as well.
p_symmetric :: (Show x, Eq x) => x -> x -> Test
p_symmetric x y =
title "if x == y then y == x" $
argument "x" x $
argument "y" y $
temporary "x == y" (x == y) $
(y == x) ?= (x == y)
-- | Check that if @x == y@ and @y == z@ then @x == z@.
p_transitive :: (Show x, Eq x) => x -> x -> x -> Test
p_transitive x y z =
title "if x == y and y == z then x == z" $
argument "x" x $
argument "y" y $
argument "z" z $
temporary "x == y" (x == y) $
temporary "y == z" (y == z) $
if (x /= y) && (y /= z)
then inapplicable
else (x == z) ?= ((x == y) && (y == z))
-- | Check that @x /= y@ is the same as @not (x == y)@.
p_not_equal :: (Show x, Eq x) => x -> x -> Test
p_not_equal x y =
title "x /= y is not(x == y)" $
argument "x" x $
argument "y" y $
temporary "x == y" (x == y) $
(x /= y) ?= not (x == y)
{- |
Given a list of /distinct/ values, perform all applicable tests
on all possible combinations of inputs. (If the inputs are not
distinct, some redundant tests are performed.)
-}
p_Eq :: (Show x, Eq x) => [x] -> Test
p_Eq xs =
title "p_Eq" $
argument "xs" xs $
tests
[
title "p_reflexive" $ tests [ p_reflexive x | x <- xs ],
title "p_symmetric" $ tests [ p_symmetric x y | x <- xs, y <- xs ],
title "p_transitive" $ tests [ p_transitive x y z | x <- xs, y <- xs, z <- xs ],
title "p_not_equal" $ tests [ p_not_equal x y | x <- xs, y <- xs ]
]