extended-reals-0.2.7.0: test/TestExtendedReal.hs
{-# LANGUAGE TemplateHaskell, ScopedTypeVariables #-}
{-# OPTIONS_GHC -Wall -fno-warn-orphans #-}
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# HLINT ignore "Avoid restricted function" #-}
{-# HLINT ignore "Functor law" #-}
{-# HLINT ignore "Redundant negate" #-}
import Prelude hiding (isInfinite)
import Control.DeepSeq
import Control.Exception (SomeException, evaluate, try)
import Data.Maybe
import Data.Ord (Down(..))
import qualified GHC.Real
import System.IO.Unsafe (unsafePerformIO)
import Test.QuickCheck.Function
import Test.Tasty.QuickCheck
import Test.Tasty.HUnit
import Test.Tasty.TH
import Data.ExtendedReal
-- ----------------------------------------------------------------------
instance Arbitrary r => Arbitrary (Extended r) where
arbitrary =
oneof
[ return NegInf
, return PosInf
, fmap Finite arbitrary
]
eval :: a -> Maybe a
eval a = unsafePerformIO $ do
ret <- try (evaluate a)
case ret of
Left (_::SomeException) -> return Nothing
Right b -> return $ Just b
isDefined :: a -> Bool
isDefined = isJust . eval
-- ----------------------------------------------------------------------
prop_add_comm :: Property
prop_add_comm =
forAll arbitrary $ \(a :: Extended Rational) ->
forAll arbitrary $ \b ->
eval (a + b) == eval (b + a)
prop_add_assoc :: Property
prop_add_assoc =
forAll arbitrary $ \(a :: Extended Rational) ->
forAll arbitrary $ \b ->
forAll arbitrary $ \c ->
eval (a + (b + c)) == eval ((a + b) + c)
prop_add_unit :: Property
prop_add_unit =
forAll arbitrary $ \(a :: Extended Rational) ->
0 + a == a
prop_add_monotone :: Property
prop_add_monotone =
forAll arbitrary $ \(a :: Extended Rational) ->
forAll arbitrary $ \b ->
forAll arbitrary $ \c ->
a <= b && isDefined (a+c) && isDefined (b+c)
==> a+c <= b+c
prop_mult_comm :: Property
prop_mult_comm =
forAll arbitrary $ \(a :: Extended Rational) ->
forAll arbitrary $ \b ->
a * b == b * a
-- PosInf + NegInf is left undefined
case_add_PosInf_NegInf :: IO ()
case_add_PosInf_NegInf =
eval (inf + (- inf) :: Extended Rational) @?= Nothing
prop_mult_assoc :: Property
prop_mult_assoc =
forAll arbitrary $ \(a :: Extended Rational) ->
forAll arbitrary $ \b ->
forAll arbitrary $ \c ->
a * (b * c) == (a * b) * c
prop_mult_unit :: Property
prop_mult_unit =
forAll arbitrary $ \(a :: Extended Rational) ->
1 * a == a
prop_mult_dist :: Property
prop_mult_dist =
forAll arbitrary $ \(a :: Extended Rational) ->
forAll arbitrary $ \b ->
forAll arbitrary $ \c ->
isDefined (a * (b + c)) && isDefined (a * b + a * c)
==> eval (a * (b + c)) == eval (a * b + a * c)
prop_mult_zero :: Property
prop_mult_zero =
forAll arbitrary $ \(a :: Extended Rational) ->
0 * a == 0
prop_mult_monotone :: Property
prop_mult_monotone =
forAll arbitrary $ \(a :: Extended Rational) ->
forAll arbitrary $ \b ->
forAll arbitrary $ \c ->
a <= b && c > 0 && isDefined (a*c) && isDefined (b*c)
==> a*c <= b*c
prop_mult_down_1 :: Property
prop_mult_down_1 = once $
fromRealFloat (sqr infinity) === sqr (fromRealFloat infinity)
where
infinity :: Down Double
infinity = Down (1 / 0)
sqr :: Num a => a -> a
sqr x = x * x
prop_mult_down_2 :: Property
prop_mult_down_2 = once $
fromRealFloat (infinity * (-infinity)) === fromRealFloat infinity * fromRealFloat (-infinity)
where
infinity :: Down Double
infinity = Down (1 / 0)
-- We define 0 * PosInf = 0
case_mult_zero_PosInf :: IO ()
case_mult_zero_PosInf =
0 * inf @?= (0 :: Extended Rational)
-- We define 0 * NegInf = 0
case_mult_zero_NegInf :: IO ()
case_mult_zero_NegInf =
0 * (- inf) @?= (0 :: Extended Rational)
prop_negate_inverse :: Property
prop_negate_inverse =
forAll arbitrary $ \(a :: Extended Rational) ->
negate (negate a) == a
prop_signum_abs :: Property
prop_signum_abs =
forAll arbitrary $ \(a :: Extended Rational) ->
signum a * abs a == a
prop_recip_inverse :: Property
prop_recip_inverse =
forAll arbitrary $ \(a :: Extended Rational) ->
isFinite a && a /= 0 ==> recip (recip a) == a
case_recip_PosInf :: IO ()
case_recip_PosInf = recip inf @?= (0 :: Extended Rational)
case_recip_NegInf :: IO ()
case_recip_NegInf = recip (- inf) @?= (0 :: Extended Rational)
prop_minBound_smallest :: Property
prop_minBound_smallest =
forAll arbitrary $ \(a :: Extended Rational) ->
minBound <= a
prop_maxBound_largest :: Property
prop_maxBound_largest =
forAll arbitrary $ \(a :: Extended Rational) ->
a <= maxBound
prop_isFinite_fromRational :: Property
prop_isFinite_fromRational =
forAll arbitrary $ \a -> isFinite (fromRational a :: Extended Rational)
prop_fromRational_PosInf :: Property
prop_fromRational_PosInf = once $
fromRational GHC.Real.infinity === (PosInf :: Extended Rational)
prop_fromRational_NegInf :: Property
prop_fromRational_NegInf = once $
fromRational (-GHC.Real.infinity) === (NegInf :: Extended Rational)
prop_fromRational_NaN :: Property
prop_fromRational_NaN = once $ ioProperty $ do
let nan :: Extended Double
nan = fromRational GHC.Real.notANumber
nan' <- try $ evaluate nan
pure $ case nan' of
Left (_ :: SomeException) -> True
Right _ -> False
prop_isInfinite_PosInf :: Property
prop_isInfinite_PosInf = property $ isInfinite PosInf
prop_isInfinite_NegInf :: Property
prop_isInfinite_NegInf = property $ isInfinite NegInf
-- ----------------------------------------------------------------------
-- Functor
prop_Functor_id :: Property
prop_Functor_id =
forAll arbitrary $ \(a :: Extended Integer) ->
fmap id a == a
prop_Functor_comp :: Property
prop_Functor_comp =
forAll arbitrary $ \(f :: Fun Integer Integer) ->
forAll arbitrary $ \(g :: Fun Integer Integer) ->
forAll arbitrary $ \(a :: Extended Integer) ->
fmap (apply f . apply g) a == fmap (apply f) (fmap (apply g) a)
-- ----------------------------------------------------------------------
-- Show / Read
prop_read_show :: Property
prop_read_show =
forAll arbitrary $ \(a :: Extended Rational) ->
read (show a) == a
-- ----------------------------------------------------------------------
-- deepseq
prop_deepseq :: Property
prop_deepseq =
forAll arbitrary $ \(a :: Extended Rational) ->
a `deepseq` () == ()
-- ----------------------------------------------------------------------
-- fromRealFloat
prop_fromRealFloat_PosInf :: Property
prop_fromRealFloat_PosInf = once $
fromRealFloat (1 / 0 :: Double) === PosInf
prop_fromRealFloat_NegInf :: Property
prop_fromRealFloat_NegInf = once $
fromRealFloat (-(1 / 0) :: Double) === NegInf
prop_fromRealFloat_NaN :: Property
prop_fromRealFloat_NaN = once $ ioProperty $ do
let nan = fromRealFloat (0 / 0 :: Double)
nan' <- try $ evaluate nan
pure $ case nan' of
Left (_ :: SomeException) -> True
Right _ -> False
prop_fromRealFloat_Down_NegInf :: Property
prop_fromRealFloat_Down_NegInf = once $
fromRealFloat (1 / 0 :: Down Double) === NegInf
prop_fromRealFloat_Down_PosInf :: Property
prop_fromRealFloat_Down_PosInf = once $
fromRealFloat (-(1 / 0) :: Down Double) === PosInf
prop_fromRealFloat_Down_NaN :: Property
prop_fromRealFloat_Down_NaN = once $ ioProperty $ do
let nan = fromRealFloat (0 / 0 :: Down Double)
nan' <- try $ evaluate nan
pure $ case nan' of
Left (_ :: SomeException) -> True
Right _ -> False
-- ----------------------------------------------------------------------
-- toRealFloat
prop_toRealFloat_PosInf :: Property
prop_toRealFloat_PosInf = once $
(1 / 0 :: Double) === toRealFloat PosInf
prop_toRealFloat_NegInf :: Property
prop_toRealFloat_NegInf = once $
(-(1 / 0) :: Double) === toRealFloat NegInf
prop_toRealFloat_Down_NegInf :: Property
prop_toRealFloat_Down_NegInf = once $
(1 / 0 :: Down Double) === toRealFloat NegInf
prop_toRealFloat_Down_PosInf :: Property
prop_toRealFloat_Down_PosInf = once $
(-(1 / 0) :: Down Double) === toRealFloat PosInf
prop_toRealFloat_fromRealFloat :: Double -> Property
prop_toRealFloat_fromRealFloat x =
toRealFloat (fromRealFloat x) === x
prop_fromRealFloat_toRealFloat :: Extended Double -> Property
prop_fromRealFloat_toRealFloat x =
fromRealFloat (toRealFloat x) === x
-- ----------------------------------------------------------------------
-- Test harness
main :: IO ()
main = $(defaultMainGenerator)