softwaremill / diffx

Pretty diffs for scala case classes
Apache License 2.0
345 stars 30 forks source link

`modify` creates a `Diff` that fails with a `ClassCastException` when using a set for comparison #421

Closed AvaPL closed 1 year ago

AvaPL commented 1 year ago

I have a pretty basic case that fails with a ClassCastException:

  import com.softwaremill.diffx._

  case class Foo(value: String)

  object Foo {
    implicit val fooDiff: Diff[Foo] = Diff.derived
  }

  case class Bar(fooCollection: Seq[Foo])

  object Bar {
    implicit val barDiff: Diff[Bar] = Diff.derived
  }

  "modified diff" should "compare collections using the specified diff" in {
    val fooCollectionDiff = Diff[Set[Foo]].contramap[Seq[Foo]](_.toSet)
    val modifiedBarDiff = Bar.barDiff.modify(_.fooCollection).setTo(fooCollectionDiff)

    val foo1 = Foo(value = "1")
    val foo2 = Foo(value = "2")
    val bar1 = Bar(fooCollection = Seq(foo1, foo2))
    val bar2 = Bar(fooCollection = Seq(foo2, foo1))
    modifiedBarDiff(bar1, bar2).isIdentical shouldBe true
  }

Expected behaviour: the test passes.

Actual behaviour: the test fails with an exception.

class java.lang.String cannot be cast to class scala.collection.immutable.Seq (java.lang.String is in module java.base of loader 'bootstrap'; scala.collection.immutable.Seq is in unnamed module of loader 'app')
java.lang.ClassCastException: class java.lang.String cannot be cast to class scala.collection.immutable.Seq (java.lang.String is in module java.base of loader 'bootstrap'; scala.collection.immutable.Seq is in unnamed module of loader 'app')
    at com.softwaremill.diffx.Diff.com$softwaremill$diffx$Diff$$$anonfun$contramap$1(Diff.scala:12)
    at com.softwaremill.diffx.Diff$$anonfun$contramap$2.apply(Diff.scala:11)
    at com.softwaremill.diffx.generic.DiffMagnoliaDerivation.$anonfun$join$3(DiffMagnoliaDerivation.scala:22)
    at scala.collection.immutable.ArraySeq.map(ArraySeq.scala:75)
    at scala.collection.immutable.ArraySeq.map(ArraySeq.scala:35)
    at com.softwaremill.diffx.generic.DiffMagnoliaDerivation.$anonfun$join$2(DiffMagnoliaDerivation.scala:13)
    at com.softwaremill.diffx.DiffxSupport.nullGuard(DiffxSupport.scala:20)
    at com.softwaremill.diffx.DiffxSupport.nullGuard$(DiffxSupport.scala:14)
    at com.softwaremill.diffx.package$.nullGuard(package.scala:7)
    at com.softwaremill.diffx.generic.DiffMagnoliaDerivation.com$softwaremill$diffx$generic$DiffMagnoliaDerivation$$$anonfun$join$1(DiffMagnoliaDerivation.scala:12)
    at com.softwaremill.diffx.generic.DiffMagnoliaDerivation$$anonfun$join$7.apply(DiffMagnoliaDerivation.scala:11)
    at com.softwaremill.diffx.instances.DiffForSet.$anonfun$matchPairs$1(DiffForSet.scala:45)
    at scala.collection.immutable.List.map(List.scala:246)
    at com.softwaremill.diffx.instances.DiffForSet.matchPairs(DiffForSet.scala:43)
    at com.softwaremill.diffx.instances.DiffForSet.$anonfun$apply$1(DiffForSet.scala:23)
    at com.softwaremill.diffx.DiffxSupport.nullGuard(DiffxSupport.scala:20)
    at com.softwaremill.diffx.DiffxSupport.nullGuard$(DiffxSupport.scala:14)
    at com.softwaremill.diffx.package$.nullGuard(package.scala:7)
    at com.softwaremill.diffx.instances.DiffForSet.apply(DiffForSet.scala:16)
    at com.softwaremill.diffx.Diff.com$softwaremill$diffx$Diff$$$anonfun$contramap$1(Diff.scala:12)
    at com.softwaremill.diffx.Diff$$anonfun$contramap$2.apply(Diff.scala:11)
    at com.softwaremill.diffx.generic.DiffMagnoliaDerivation.$anonfun$join$3(DiffMagnoliaDerivation.scala:22)
    at scala.collection.immutable.ArraySeq.map(ArraySeq.scala:75)
    at scala.collection.immutable.ArraySeq.map(ArraySeq.scala:35)
    at com.softwaremill.diffx.generic.DiffMagnoliaDerivation.$anonfun$join$2(DiffMagnoliaDerivation.scala:13)
    at com.softwaremill.diffx.DiffxSupport.nullGuard(DiffxSupport.scala:20)
    at com.softwaremill.diffx.DiffxSupport.nullGuard$(DiffxSupport.scala:14)
    at com.softwaremill.diffx.package$.nullGuard(package.scala:7)
    at com.softwaremill.diffx.generic.DiffMagnoliaDerivation.com$softwaremill$diffx$generic$DiffMagnoliaDerivation$$$anonfun$join$1(DiffMagnoliaDerivation.scala:12)
    at com.softwaremill.diffx.generic.DiffMagnoliaDerivation$$anonfun$join$7.apply(DiffMagnoliaDerivation.scala:11)
    at com.softwaremill.diffx.Diff$$anon$1.apply(Diff.scala:22)
    at com.softwaremill.diffx.Diff.apply(Diff.scala:7)
    at com.softwaremill.diffx.Diff.apply$(Diff.scala:7)
    at com.softwaremill.diffx.Diff$$anon$1.apply(Diff.scala:16)

diffx version: 0.8.0

This seems to be specific for modify only. Defining the collection Diff inside Bar like:

  object Bar {
    implicit val fooCollectionDiff: Diff[Seq[Foo]] = Diff[Set[Foo]].contramap(_.toSet)
    implicit val barDiff: Diff[Bar] = Diff.derived
  }

doesn't cause any exceptions.

ghostbuster91 commented 1 year ago

Yes, that is a known bug that has been to some degree fixed in 0.8.1, see https://github.com/softwaremill/diffx/issues/418 for details.

AvaPL commented 1 year ago

Sorry for the duplicate then 😄