integer-types-0.0.0.0: test-integer-arithmetic/Main.hs
{-# language TemplateHaskell #-}
{-# options_ghc -fno-warn-missing-signatures #-}
module Main (main) where
import Integer
import Control.Applicative (pure)
import Control.Monad (Monad)
import Data.Eq (Eq)
import Data.Function (($), (.))
import Data.Maybe (Maybe (Just, Nothing))
import Hedgehog ((===))
import Integer.Gen (GenIntegral)
import Prelude (Num, fromInteger, toInteger, ($!), (*), (+), (-))
import Text.Show (Show)
import qualified Control.Exception as Exception (ArithException (Underflow))
import qualified Control.Monad.Catch as Exception (MonadCatch, try)
import qualified Data.Either as Either
import qualified Hedgehog
import qualified Hedgehog.Main as Hedgehog
import qualified Integer.Gen as Gen
main = Hedgehog.defaultMain [Hedgehog.checkSequential $$(Hedgehog.discover)]
testLimit :: Hedgehog.TestLimit
testLimit = 1000
property = Hedgehog.withTests testLimit . Hedgehog.property
-- | Assert that a closed binary 'Num' operation behaves the same
-- on a type as it does when applied via conversion with 'Integer'
checkNumOp :: forall a m. GenIntegral a => Monad m =>
(forall b. Num b => b -> b -> b) -> Hedgehog.PropertyT m ()
checkNumOp o = do
x :: a <- Hedgehog.forAll Gen.integral
y :: a <- Hedgehog.forAll Gen.integral
x `o` y === fromInteger (toInteger x `o` toInteger y)
-- | Assert that 'subtract' in @a@ gives the same result
-- as '(-)' via @b@.
checkSubtract :: forall a b m.
(GenIntegral a, Subtraction a, Subtraction' b, Num b) =>
(IntegerConvert a b, IntegerNarrow b a) =>
(Eq b, Show b) =>
Exception.MonadCatch m => Hedgehog.PropertyT m ()
checkSubtract = do
x :: a <- Hedgehog.forAll Gen.integral
y :: a <- Hedgehog.forAll Gen.integral
(subtract x y :: b) === (convert x - convert y :: b)
-- | Assert that '(-)' in @a@ gives the same result as
-- '(-)' via @Integer@ if the result is within the range
-- of @a@, and is undefined otherwise
checkPartialSubtract :: forall a m.
(GenIntegral a, Subtraction a, IntegerNarrow Integer a) =>
Exception.MonadCatch m => Hedgehog.PropertyT m ()
checkPartialSubtract = do
x :: a <- Hedgehog.forAll Gen.integral
y :: a <- Hedgehog.forAll Gen.integral
case narrow (toInteger x - toInteger y) :: Maybe a of
Just z -> x - y === z
Nothing -> do
z <- Exception.try (pure $! x - y)
z === Either.Left Exception.Underflow
prop_add_positive = property $ checkNumOp @Positive (+)
prop_add_signed = property $ checkNumOp @Signed (+)
prop_multiply_positive = property $ checkNumOp @Positive (*)
prop_multiply_signed = property $ checkNumOp @Signed (*)
prop_subtract_natural_signed = property $ checkSubtract @Natural @Signed
prop_subtract_natural_integer = property $ checkSubtract @Natural @Integer
prop_subtract_positive_signed = property $ checkSubtract @Positive @Signed
prop_subtract_positive_integer = property $ checkSubtract @Positive @Integer
prop_partial_subtract_positive = property $ checkPartialSubtract @Positive