softwaremill/diffx

ScalaTest matchTo to support matching Options

Closed this issue · 2 comments

Hi, I get a compilation error when i.e.

import com.softwaremill.diffx.scalatest.DiffMatcher

callMethodThatReturnsOption(...) should matchTo(Some(x))

it works fine for sequences. Weirdly it works fine with code like
Some(5) should matchTo(Some(5)) but not if the left part is a method invocation.

On scala 2.13 and these deps:

val ScalaTest = ivy"org.scalatest::scalatest:3.2.0"
val Diffx = Seq(ivy"com.softwaremill.diffx::diffx-core:0.3.29", ivy"com.softwaremill.diffx::diffx-scalatest:0.3.29")

Hi,

The reason why it works for:
Some(5) should matchTo(Some(5))
and doesn't work for:

def method: Option[Int] = Some(5)
method should matchTo(Some(5))

Is that, in the first case both type parameters are fixed to be Some while in the second case one is Option and the other is Some. Of course Some <: Option for given T and because Diff is contravariant following is also true: Diff[Option[T] <: Diff[Some[T]]. Matcher[T] from scalatest is also contravariant so Matcher[Option[T]] <: Matcher[Some[T]], but I am guessing that compiler ins't extrapolating types here to find out that Option would be the correct supertype because the should method is overloaded and it seems that overloading has bigger priority than types' extrapolation.

TLDR: I have no idea how to fix that apart from helping compiler to choose the right method by specifying the type of the matcher explicitly:

Option(left) should matchTo[Option[Foo]](Some(right))

Alternatively if you use cats, you can do:
Option(left) should matchTo(right.some) as .some returns Option

Ok I see, thanks. So as a workaround I am using it like

myMethod(...) should matchTo(Option(5)) // Note: Option(5) not Some(5), this now compiles