packages feed

range-1.0.0.0: Test/RangeLaws.hs

module Test.RangeLaws
   ( rangeLawTestCases
   ) where

import Test.Framework (Test, testGroup)
import Test.QuickCheck ()
import Test.Framework.Providers.QuickCheck2

import Data.Ranges
import Test.Generators ()

-- ---------------------------------------------------------------------------
-- Helpers
-- ---------------------------------------------------------------------------

-- Ranges is always in canonical form; compare the underlying lists.
eq :: Ord a => Ranges a -> Ranges a -> Bool
eq a b = unRanges a == unRanges b

-- ---------------------------------------------------------------------------
-- Idempotency
-- ---------------------------------------------------------------------------

prop_mergeRanges_idempotent :: Ranges Integer -> Bool
prop_mergeRanges_idempotent xs =
   mergeRanges (unRanges xs) `eq` xs

prop_union_idempotent :: Ranges Integer -> Bool
prop_union_idempotent xs =
   union xs xs `eq` xs

prop_intersection_idempotent :: Ranges Integer -> Bool
prop_intersection_idempotent xs =
   intersection xs xs `eq` xs

test_idempotency :: Test
test_idempotency = testGroup "idempotency"
   [ testProperty "mergeRanges is idempotent"       prop_mergeRanges_idempotent
   , testProperty "union with self is self"          prop_union_idempotent
   , testProperty "intersection with self is self"   prop_intersection_idempotent
   ]

-- ---------------------------------------------------------------------------
-- Commutativity
-- ---------------------------------------------------------------------------

prop_union_commutative :: (Ranges Integer, Ranges Integer) -> Bool
prop_union_commutative (a, b) =
   union a b `eq` union b a

prop_intersection_commutative :: (Ranges Integer, Ranges Integer) -> Bool
prop_intersection_commutative (a, b) =
   intersection a b `eq` intersection b a

test_commutativity :: Test
test_commutativity = testGroup "commutativity"
   [ testProperty "union is commutative"         prop_union_commutative
   , testProperty "intersection is commutative"  prop_intersection_commutative
   ]

-- ---------------------------------------------------------------------------
-- Associativity
-- ---------------------------------------------------------------------------

prop_union_associative :: (Ranges Integer, Ranges Integer, Ranges Integer) -> Bool
prop_union_associative (a, b, c) =
   union (union a b) c `eq` union a (union b c)

prop_intersection_associative :: (Ranges Integer, Ranges Integer, Ranges Integer) -> Bool
prop_intersection_associative (a, b, c) =
   intersection (intersection a b) c `eq` intersection a (intersection b c)

test_associativity :: Test
test_associativity = testGroup "associativity"
   [ testProperty "union is associative"         prop_union_associative
   , testProperty "intersection is associative"  prop_intersection_associative
   ]

-- ---------------------------------------------------------------------------
-- Distributivity
-- ---------------------------------------------------------------------------

prop_intersection_distributes_over_union
   :: (Ranges Integer, Ranges Integer, Ranges Integer) -> Bool
prop_intersection_distributes_over_union (a, b, c) =
   intersection a (union b c) `eq` union (intersection a b) (intersection a c)

prop_union_distributes_over_intersection
   :: (Ranges Integer, Ranges Integer, Ranges Integer) -> Bool
prop_union_distributes_over_intersection (a, b, c) =
   union a (intersection b c) `eq` intersection (union a b) (union a c)

test_distributivity :: Test
test_distributivity = testGroup "distributivity"
   [ testProperty "intersection distributes over union"
         prop_intersection_distributes_over_union
   , testProperty "union distributes over intersection"
         prop_union_distributes_over_intersection
   ]

-- ---------------------------------------------------------------------------
-- Identity laws
-- ---------------------------------------------------------------------------

prop_union_identity_empty :: Ranges Integer -> Bool
prop_union_identity_empty xs =
   union xs mempty `eq` xs

prop_intersection_identity_infinite :: Ranges Integer -> Bool
prop_intersection_identity_infinite xs =
   intersection xs inf `eq` xs

prop_union_absorb_infinite :: Ranges Integer -> Bool
prop_union_absorb_infinite xs =
   union xs inf `eq` inf

prop_intersection_absorb_empty :: Ranges Integer -> Bool
prop_intersection_absorb_empty xs =
   intersection xs mempty `eq` mempty

test_identity_absorption :: Test
test_identity_absorption = testGroup "identity and absorption"
   [ testProperty "union with mempty is identity"                prop_union_identity_empty
   , testProperty "intersection with inf is identity"            prop_intersection_identity_infinite
   , testProperty "union with inf absorbs"                       prop_union_absorb_infinite
   , testProperty "intersection with mempty absorbs"             prop_intersection_absorb_empty
   ]

-- ---------------------------------------------------------------------------
-- Difference as intersection with complement
-- ---------------------------------------------------------------------------

prop_difference_eq_intersection_invert
   :: (Ranges Integer, Ranges Integer) -> Bool
prop_difference_eq_intersection_invert (a, b) =
   difference a b `eq` intersection a (invert b)

test_difference :: Test
test_difference = testGroup "difference"
   [ testProperty "difference a b == intersection a (invert b)"
         prop_difference_eq_intersection_invert
   ]

-- ---------------------------------------------------------------------------
-- Double inversion
-- ---------------------------------------------------------------------------

prop_invert_twice_identity :: Ranges Integer -> Bool
prop_invert_twice_identity xs =
   invert (invert xs) `eq` xs

test_invert :: Test
test_invert = testGroup "invert"
   [ testProperty "inverting twice is identity"  prop_invert_twice_identity
   ]

-- ---------------------------------------------------------------------------
-- Export
-- ---------------------------------------------------------------------------

rangeLawTestCases :: [Test]
rangeLawTestCases =
   [ test_idempotency
   , test_commutativity
   , test_associativity
   , test_distributivity
   , test_identity_absorption
   , test_difference
   , test_invert
   ]