Synesso
Synesso

Reputation: 39018

Converting a foreach into contains forall matcher

I have the following expression in a spec, with the intention of ensuring that each element has a value distanceToEnd that is very close to the sum of the distanceFromPrevious values of the elements following it.

foo.tails.foreach {
  case h +: t => h.distanceToEnd.miles must
    beCloseTo(t.map(_.distanceFromPrevious.miles).sum, 10e-10)
  case _ => ok
}

Ideally, this should be in the form foo.tails must contain { ... }.forall, but I have trouble understanding how to create the necessary ValueCheck parameter for contains. How would I convert this particular example?

Upvotes: 1

Views: 133

Answers (2)

Eric
Eric

Reputation: 15557

Unfortunately type inference doesn't work with partial functions so you need to match explicitly:

 foo.tails must contain { ts: List[Foo] =>
   ts match {
     case h +: t => h.distanceToEnd.miles must
       beCloseTo(t.map(_.distanceFromPrevious.miles).sum, 10e-10)
     case _ => ok
   }
}.forall

Upvotes: 1

heenenee
heenenee

Reputation: 20135

You can use forall if you calculate the partial sums of distanceFromPrevious and subtract distanceToEnd before using any specs2 matchers. Then you can just use one of the beCloseTo matchers to compare with 0, as follows:

foo.tail.scanRight(0.0)(_.distanceFromPrevious.miles + _).init  // calculate partial sums of previous distances
    .zip(foo.init.map(_.distanceToEnd.miles))                   // combine with end distances
    .map(t => t._1 - t._2)                                      // take difference of summed and end distances
    .must(contain(be ~(0.0 +/- 10e-10)).forall)                 // all differences should be effectively 0

Upvotes: 0

Related Questions