HUnit-approx-1.0: Test/HUnit/Approx.hs
{-# LANGUAGE ImplicitParams, CPP #-}
#if __GLASGOW_HASKELL__ >= 707
{-# LANGUAGE Safe #-} -- Test.HUnit is not Safe in 7.6 and below
#endif
-----------------------------------------------------------------------------
-- |
-- Module : Test.HUnit.Approx
-- Copyright : (C) 2014 Richard Eisenberg
-- License : BSD-style (see LICENSE)
-- Maintainer : Richard Eisenberg (eir@cis.upenn.edu)
-- Stability : intended to be stable
-- Portability : not portable (uses implicit parameters)
--
-- This module exports combinators to allow approximate equality of
-- floating-point values in HUnit tests.
-----------------------------------------------------------------------------
module Test.HUnit.Approx (
-- * Assertions
assertApproxEqual, (@~?), (@?~),
-- * Tests
(~~?), (~?~)
) where
import Test.HUnit
import Control.Monad ( unless )
-- | Asserts that the specified actual value is approximately equal to the
-- expected value. The output message will contain the prefix, the expected
-- value, the actual value, and the maximum margin of error.
--
-- If the prefix is the empty string (i.e., @\"\"@), then the prefix is omitted
-- and only the expected and actual values are output.
assertApproxEqual :: (Ord a, Num a, Show a)
=> String -- ^ The message prefix
-> a -- ^ Maximum allowable margin of error
-> a -- ^ The expected value
-> a -- ^ The actual value
-> Assertion
assertApproxEqual preface epsilon expected actual =
unless (abs (actual - expected) <= epsilon) (assertFailure msg)
where msg = (if null preface then "" else preface ++ "\n") ++
"expected: " ++ show expected ++ "\n but got: " ++ show actual ++
"\n (maximum margin of error: " ++ show epsilon ++ ")"
-- | Asserts that the specified actual value is approximately equal to the
-- expected value (with the expected value on the right-hand side). The margin
-- of error is specified with the implicit parameter @epsilon@.
(@?~) :: (Ord a, Num a, Show a, ?epsilon :: a)
=> a -- ^ The actual value
-> a -- ^ The expected value
-> Assertion
x @?~ y = assertApproxEqual "" ?epsilon y x
infix 1 @?~
-- | Asserts that the specified actual value is approximately equal to the
-- expected value (with the expected value on the left-hand side). The margin
-- of error is specified with the implicit parameter @epsilon@.
(@~?) :: (Ord a, Num a, Show a, ?epsilon :: a)
=> a -- ^ The expected value
-> a -- ^ The actual value
-> Assertion
x @~? y = assertApproxEqual "" ?epsilon x y
infix 1 @~?
-- | Shorthand for a test case that asserts approximate equality (with the
-- expected value on the left-hand side, and the actual value on the
-- right-hand side).
(~~?) :: (Ord a, Num a, Show a, ?epsilon :: a)
=> a -- ^ The expected value
-> a -- ^ The actual value
-> Test
expected ~~? actual = TestCase (expected @~? actual)
infix 1 ~~?
-- | Shorthand for a test case that asserts approximate equality (with the
-- actual value on the left-hand side, and the expected value on the
-- right-hand side).
(~?~) :: (Ord a, Num a, Show a, ?epsilon :: a)
=> a -- ^ The actual value
-> a -- ^ The expected value
-> Test
actual ~?~ expected = TestCase (actual @?~ expected)
infix 1 ~?~