Reputation: 893
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?
Upvotes: 3
Views: 3176
Reputation: 11244
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 Matcher
Upvotes: 6