integer-types-0.1.4.0: test/Spec/Subtraction.hs
module Spec.Subtraction where
import Control.Exception (ArithException (Underflow))
import Control.Monad.Catch (MonadCatch, try)
import Data.Either qualified as Either
import Essentials
import Integer
( Integer,
IntegerConvert (..),
IntegerNarrow (..),
Natural,
Positive,
Signed,
Subtraction,
Subtraction' (..),
)
import Integer.Gen (GenIntegral)
import Integer.Gen qualified as Gen
import Test.Hspec (Spec, context, it)
import Test.Hspec.Hedgehog
( PropertyT,
forAll,
hedgehog,
modifyMaxSuccess,
(===),
)
import Prelude (Num, toInteger, ($!), (-))
spec :: Spec
spec = do
context "subtract in A behaves the same as (-) in B" do
modifyMaxSuccess (\_ -> 1000) do
it "A = Natural, B = Signed" $ hedgehog $ checkSubtract @Natural @Signed
it "A = Natural, B = Integer" $ hedgehog $ checkSubtract @Natural @Integer
it "A = Positive, B = Signed" $ hedgehog $ checkSubtract @Positive @Signed
it "A = Positive, B = Integer" $ hedgehog $ checkSubtract @Positive @Integer
context "(-) in A behaves the same as (-) in Integer if the result is in A, undefined otherwise" do
modifyMaxSuccess (\_ -> 1000) do
it "A = Positive" $ hedgehog $ checkNumMinus @Positive
checkSubtract ::
forall a b m.
(GenIntegral a, Subtraction a, Subtraction' b, Num b) =>
(IntegerConvert a b, IntegerNarrow b a) =>
(Eq b, Show b) =>
MonadCatch m =>
PropertyT m ()
checkSubtract = do
x :: a <- forAll Gen.integral
y :: a <- forAll Gen.integral
(subtract x y :: b) === (convert x - convert y :: b)
checkNumMinus ::
forall a m.
(GenIntegral a, Subtraction a, IntegerNarrow Integer a) =>
MonadCatch m =>
PropertyT m ()
checkNumMinus = do
x :: a <- forAll Gen.integral
y :: a <- forAll Gen.integral
case narrow (toInteger x - toInteger y) :: Maybe a of
Just z -> x - y === z
Nothing -> do
z <- try (pure $! x - y)
z === Either.Left Underflow