Hi Matthew,
If you haven't ported to specs2 yet, you may also want to take a look at ScalaTest, which I believe has what you're asking for. You can customize the meaning of equality for Weighting so that it will compare the Double values in the nested maps with a tolerance. An example of that is shown on the documentation page for Equality:
http://www.artima.com/docs-scalatest-2.0.M8/#org.scalautils.EqualityIn your case, I whipped up:
case class InputNode(c: Char)
case class HiddenNode(i: Int)
case class OutputNode(c: Char)
case class Weighting(inMap: Map[InputNode, Double], hidMap: Map[HiddenNode, Double], outMap: Map[OutputNode, Double])
val x = Weighting(Map(InputNode('a') -> 0.1), Map(HiddenNode(1) -> 0.29000000000000004), Map(OutputNode('X') -> 0.78))
val y = Weighting(Map(InputNode('a') -> 0.1), Map(HiddenNode(1) -> 0.29), Map(OutputNode('X') -> 0.78))
import org.scalautils._
import org.scalatest._
import Matchers._
x should equal (y)
If you paste this into the REPL you'll get a similar error message to your specs one:
scala> x should equal (y)
org.scalatest.exceptions.TestFailedException: Weighting(Map(InputNode(a) -> 0.1),Map(HiddenNode(1) -> 0.29000000000000004),Map(OutputNode(X) -> 0.78)) did not equal Weighting(Map(InputNode(a) -> 0.1),Map(HiddenNode(1) -> 0.29),Map(OutputNode(X) -> 0.78))
What you can do to soften that is to define an implicit Equality[Weighting], so it will be picked up by the equal matcher:
implicit val WeightingEquality = {
new Equality[Weighting] {
val Tol = 0.00001
// Helper method to tolerantly compare Maps with Double values
def approxEquals[K](leftMap: Map[K, Double], rightMap: Map[K, Double]): Boolean =
(leftMap.size == rightMap.size) && {
try {
leftMap forall {
case (k, leftV) =>
rightMap.get(k) match {
case Some(rightV) => leftV === rightV +- Tol
case _ => false
}
}
}
}
// Custom equals method for Weighting
override def areEqual(left: Weighting, r: Any): Boolean =
r match {
case right: Weighting =>
approxEquals(left.inMap, right.inMap) &&
approxEquals(left.hidMap, right.hidMap) &&
approxEquals(left.outMap, right.outMap)
case _ => false
}
}
}