I'm trying to check that a list of case classes contains a specific instance of one, however when I attempt to do so I get the following error:
[info] Compiling 1 Scala source to /home/matt/Documents/transledge/app/target/scala-2.9.2/test-classes...
[error] /home/matt/Documents/transledge/app/src/test/scala/com/transledge/drewes/parser_suite.scala:40: overloaded method value should with alternatives:
[error] (notWord: ParserSuite.this.NotWord)ParserSuite.this.ResultOfNotWordForSeq[com.transledge.Instruction,List[com.transledge.Instruction]] <and>
[error] (haveWord: ParserSuite.this.HaveWord)ParserSuite.this.ResultOfHaveWordForSeq[com.transledge.Instruction] <and>
[error] (beWord: ParserSuite.this.BeWord)ParserSuite.this.ResultOfBeWordForAnyRef[List[com.transledge.Instruction]] <and>
[error] (rightMatcher: org.scalatest.matchers.Matcher[List[com.transledge.Instruction]])Unit
[error] cannot be applied to (org.scalatest.matchers.Matcher[Traversable[com.transledge.AddNode]])
[error] parsing(square_node, input) should contain(AddNode("foo"))
[error] ^
[error] one error found
[error] (test:compile) Compilation failed
[error] Total time: 3 s, completed 21-Feb-2013 15:15:04
The test suite in question is:
import org.scalatest.FunSpec
import scala.util.parsing.combinator._
import com.transledge.drewes.{Parser => DrewesParser}
import com.transledge._
import org.scalatest.matchers.ShouldMatchers
class ParserSuite extends DrewesParser with FunSpec with ShouldMatchers {
def parsing[A](parser: Parser[A], input: String): A = parse(parser, input).get
// snipping other tests
describe("square_node") {
val input = """\squarenode{foo}(1cm, 2cm)"""
it("should create a node") {
parsing(square_node, input) should contain(AddNode("foo")) // Line 40
}
}
}
The definition of AddNode/Instruction is pretty basic:
package com.transledge
abstract class Instruction
case class AddNode(id: String) extends Instruction
And here is a cut down definition of the parser:
package com.transledge.drewes
import scala.util.parsing.combinator._
import com.transledge._
trait Parser extends RegexParsers {
def node_id: Parser[String] = "[a-zA-Z\\-_:0-9]+".r
def node_name: Parser[String] = ("{" ~> node_id <~ "}") | node_id
def point: Parser[String] = "[^,()]+".r
def position: Parser[(String, String)] = "(" ~> point ~ "," ~ point <~ ")" ^^ { case a ~ "," ~ b => (a.trim, b.trim) }
def square_node: Parser[List[Instruction]] = "\\squarenode" ~> node_name ~ position ^^ { case name ~ position => List(AddNode(name)) }
}
My understanding of this is that the Scala compiler should be using the variation should(rightMatcher: Matcher[List[T]]), but is getting an instance of Traversable instead of a List, and as Traversable is a trait that List includes, Traversable can't be used in a place that List is expected.
So how do I check that the list contains the element?
This is a simplified picture of how it's implemented:
trait Matcher[T]
implicit class ListShouldWrapper[T](a:List[T]) {
def should(rightMatcher: Matcher[List[T]]): Unit = ???
}
object contain {
def apply[T](expectedElement: T): Matcher[GenTraversable[T]] = ???
}
If you test that implementation with:
val x:List[Int] = ???
x should contain(3)
You will get a compile error telling you that GenTraversable was found and List was required. The implementation might have worked better if we implemented it something like this the following. Note that this is not the actual solution as this is just some isolated piece of code.
trait Matcher[T]
implicit class AnyToShould[T](a: T) {
def should(a: Matcher[T]) = ???
}
def contain[C[_] <: Traversable[_], T](x:T):Matcher[C[T]] = ???
The problem is solvable so I suggest you file a bug (maybe even create a patch yourself). To be able to continue now you have a few options:
def square_node: Parser[List[Instruction]]contain method yourself that returns the 'correct' type of MatcherIf you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With