Skip to content

Commit 2d9a06f

Browse files
committed
Add shouldBeNear expectation
Comparing floating point numbers for equalty is a bad idea. Instead they should tested to see if they are close enough to one another.
1 parent c385076 commit 2d9a06f

File tree

1 file changed

+19
-1
lines changed

1 file changed

+19
-1
lines changed

src/Test/Hspec/Expectations.hs

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ module Test.Hspec.Expectations (
1111
Expectation
1212
, expectationFailure
1313
, shouldBe
14+
, shouldBeNear
1415
, shouldSatisfy
1516
, shouldStartWith
1617
, shouldEndWith
@@ -78,7 +79,7 @@ expectationFailure = Test.HUnit.assertFailure
7879
with_loc(expectTrue, String -> Bool -> Expectation)
7980
expectTrue msg b = unless b (expectationFailure msg)
8081

81-
infix 1 `shouldBe`, `shouldSatisfy`, `shouldStartWith`, `shouldEndWith`, `shouldContain`, `shouldMatchList`, `shouldReturn`, `shouldThrow`
82+
infix 1 `shouldBe`, `shouldBeNear`, `shouldSatisfy`, `shouldStartWith`, `shouldEndWith`, `shouldContain`, `shouldMatchList`, `shouldReturn`, `shouldThrow`
8283
infix 1 `shouldNotBe`, `shouldNotSatisfy`, `shouldNotContain`, `shouldNotReturn`
8384

8485
-- |
@@ -87,6 +88,23 @@ infix 1 `shouldNotBe`, `shouldNotSatisfy`, `shouldNotContain`, `shouldNotReturn`
8788
with_loc(shouldBe, (Show a, Eq a) => a -> a -> Expectation)
8889
actual `shouldBe` expected = expectTrue ("expected: " ++ show expected ++ "\n but got: " ++ show actual) (actual == expected)
8990

91+
-- |
92+
-- @actual \`shouldBeNear\` expected@ sets the expectation that @actual@ be a
93+
-- floating point value near @expected@. If either value is zero we check that
94+
-- the absolute difference is less than epsilon (1e-15) otherwise we check if
95+
-- the relative difference is less than epsilon.
96+
with_loc(shouldBeNear, (Show a, Ord a, Floating a) => a -> a -> Expectation)
97+
actual `shouldBeNear` expected
98+
-- Short circuit if they are actually equal.
99+
| actual == expected = reportFail (actual == expected)
100+
| actual == 0 || expected == 0 = reportFail (absoluteDifference < epsilon)
101+
| otherwise = reportFail (relativeDifference < epsilon)
102+
where
103+
epsilon = 1e-15
104+
absoluteDifference = abs (actual - expected)
105+
relativeDifference = abs (actual - expected) / (abs actual + abs expected)
106+
reportFail =
107+
expectTrue ("expected: " ++ show expected ++ "\n but got: " ++ show actual)
90108
-- |
91109
-- @v \`shouldSatisfy\` p@ sets the expectation that @p v@ is @True@.
92110
with_loc(shouldSatisfy, (Show a) => a -> (a -> Bool) -> Expectation)

0 commit comments

Comments
 (0)