I am trying to create a custom matcher that will take into account Double.NaN and will use tolerance for non-nan values.
import org.scalactic.{Equality, TolerantNumerics}
import org.scalatest.Matchers
trait MoreMatchers extends Matchers {
implicit def doubleEqWithNaNAndTol: Equality[Double] = new Equality[Double] {
implicit val tolerance: Equality[Double] = TolerantNumerics.tolerantDoubleEquality(1e-6)
def areEqual(expected: Double, actual: Any): Boolean = actual match {
case number: Double if number.isNaN => expected.isNaN
case _: Double => actual === expected
case _ => false
}
}
Unfortunately, it doesn't work.
assert(0.00226685508536916 === 0.0022668550853691587) // failure - doesn't use tolerance
assert (Double.NaN === Double.NaN ) // success
If enter the tolerance within the assertion then it fails if there are NaN.
assert(0.00226685508536916 === 0.0022668550853691587 +- 1e-6) // success
assert (Double.NaN === Double.NaN +- 1e-6) // failure - can't use tolerance when NaN
If I just call it like the following, then it works.
implicit val tolerance: Equality[Double] = TolerantNumerics.tolerantDoubleEquality(1e-6)
def eq(expected: Double, actual: Double): Boolean = expected match {
case x if x.isNaN => actual.isNaN
case _ => actual === expected
}
And then call it as:
assert(eq(...,...))
I am wondering if it is possible to get it working using the first way. Have you come across such case before? Could you suggest any solutions? Any help will be appreciated :)
Thanks, ele
Many thanks to eirikr @d6 :), see solution in custom equality gist
Basically in the above code you need to use tolerance.areEqual(expected, number)
when comparing non-nan doubles in order to be able to use the tolerance implicit in that comparison.
import org.scalactic.{Equality, TolerantNumerics}
import org.scalatest.Matchers
trait MoreMatchers extends Matchers {
implicit def doubleEqWithNaNAndTol: Equality[Double] = new Equality[Double] {
implicit val tolerance: Equality[Double] = TolerantNumerics.tolerantDoubleEquality(1e-6)
def areEqual(expected: Double, actual: Any): Boolean = actual match {
case x: Double if x.isNaN => expected.isNaN
case x: Double => tolerance.areEqual(expected, x)
case _ => false
}
}
Regards, ele