5
votes

Does Scalatest provide a matcher for NaN and infinities?

I would like to make these assertions a bit more descriptive if there's a way:

Double.NaN.isNaN shouldBe true
Double.NegativeInfinity.isInfinite shouldBe true
2

2 Answers

7
votes

The most flexible way to handle this is probably using ScalaTest's support for symbols to handle boolean matches on properties. So, the following tests all work and give a pretty useful error message on failure:

class DoubleSpec extends FreeSpec with Matchers {

  "NaN should be NaN" in {
    Double.box(Double.NaN) shouldBe 'NaN
  }

  "1 should not be NaN" in {
    Double.box(1d) should not be 'NaN
  }

  "Infinity should be infinite" in {
    Double.box(Double.PositiveInfinity) shouldBe 'Infinite
  }

  "1 should not be infinite" in {
    Double.box(1d) should not be 'Infinite
  }
}

Unfortunately, symbol support only exists for reference types - there's an implicit parameter T <:< AnyRef required. I welcome suggestions for handling this without needing to call Double.box every single time.

You can also write your own matchers for this:

  val NaN : BeMatcher[Double] = (left: Double) => MatchResult(
    left.isNaN,
    s"$left is not NaN",
    s"$left is NaN"
  )

  "NaN should be NaN" in {
    Double.NaN shouldBe NaN
  }

  "1 should not be NaN" in {
    1d should not be NaN
  }

Avoids the boxing problem and is more type-safe, but does require a few extra lines of code.

1
votes

By definition, NaN is not equal to anything (https://en.wikipedia.org/w/index.php?title=NaN#Comparison_with_NaN).

For this reason I don't think any scalatest matcher would and should exist for NaN and you would better use .isNaN as you already done.

As for infinite values, you may equally use :

val value = -1.0/0.0
value.isNegInfinity shouldBe true
value.isInfinite shouldBe true
value should equal (Double.NegativeInfinity)