Search code examples
scalaspecs2

Specs2: type mismatch compilation error on collection matchers


Using specs2 2.3.12, Scala 2.11.6. I'm seeing a type mismatch error on an example I feel I otherwise followed from the documentation. Code below:

val newUsers: Seq[(String, User)] = response.newUsers.toSeq
newUsers must contain((email: String, user: User) => (user.email.toString must be_==(email))).forall

I'm getting the following error:

[error] <redacted>/UserSpec.scala:561: type mismatch;
[error]  found   : org.specs2.matcher.ContainWithResult[(String, com.nitro.models.User) => org.specs2.matcher.MatchResult[String]]
[error]  required: org.specs2.matcher.Matcher[Seq[(String, com.nitro.models.User)]]
[error]       newUsers must contain((email: String, user: User) => (user.email.toString must be_==(email))).forall
[error]                                                                                                     ^
[error] one error found
[error] (api/test:compileIncremental) Compilation failed
[error] Total time: 2 s, completed Aug 3, 2015 10:07:04 AM

These are the examples I was following:

// contain matcher accepting a function
Seq(1, 2, 3) must contain((i: Int) => i must be_>=(2))
Seq(1, 2, 3) must contain(be_>(0)).forall  // this will stop after the first failure

I can definitely rewrite the test to get around this error, but I wanted to understand where I went wrong. Thanks for any pointers!


Solution

  • There's a couple of things happening here. The most important one is that your function is returning a MatchResult[String], when you're testing against a tuple, which the compiler isn't helping you realise because there would be an implicit type conversion if you returned a MatchResult[(String, User)].

    You could construct your own MatchResult, but (in my opinion) you're really going to be better off creating a Matcher[(String,User)], which is really simple.

    If you add this to your spec:

      def matchingEmail: Matcher[(String, User)] =
        (pair: (String, User)) => (pair._1  == pair._2.email, s"email ${pair._1} did not match user ${pair._2}")
    

    you can simply call it with newUsers must contain(matchingEmail).forall