Using "contains" matcher on Scala lists in Scala test

scala, scala-collections, scalatest

Solution

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:

- Change the return type of `def square_node: Parser[List[Instruction]]`

- Supply a `contain` method yourself that returns the 'correct' type of `Matcher`

- Use another Scala specification library

Problem

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?

Original source