assertj icon indicating copy to clipboard operation
assertj copied to clipboard

Using withComparatorForType with Kotlin

Open jamesmudd opened this issue 6 months ago • 3 comments

Describe the bug When trying to override the comaprator used in a recursive comparison the overriden one is setup but not used. This is probably because of Kotlin mapped types https://kotlinlang.org/docs/java-interop.html#mapped-types

It also appears nearly impossible to override the java.lang.Double comparator via Kotlin, not sure if this should be possible or not.

  • assertj core version: 3.24.1
  • java version: 21
  • test framework version: junit 5.10.1 - not relevant
  • os (if relevant): macOS - not relevant

Test case reproducing the bug

This can run as a .kts Kotlin script

import org.assertj.core.api.Assertions.assertThat
import org.assertj.core.util.DoubleComparator

data class Item(val name: String, val price: Double)

val hat = Item("hat", 12.34)
val otherHat = Item("hat", 12.34000000000001)

assertThat(hat).usingRecursiveComparison()
    .withComparatorForType(DoubleComparator(0.0005), Double::class.java)
    .isEqualTo(otherHat)

Here is the output

Exception in thread "main" java.lang.AssertionError: 
Expecting actual:
  Item(name=hat, price=12.34)
to be equal to:
  Item(name=hat, price=12.34000000000001)
when recursively comparing field by field, but found the following difference:

field/property 'price' differ:
- actual value  : 12.34
- expected value: 12.34000000000001

The recursive comparison was performed with this configuration:
- no overridden equals methods were used in the comparison (except for java types)
- these types were compared with the following comparators:
  - double -> DoubleComparator[precision=5.0E-4]
  - java.lang.Double -> DoubleComparator[precision=1.0E-15]
  - java.lang.Float -> FloatComparator[precision=1.0E-6]
  - java.nio.file.Path -> lexicographic comparator (Path natural order)
- actual and expected objects and their fields were compared field by field recursively even if they were not of the same type, this allows for example to compare a Person to a PersonDto (call strictTypeChecking(true) to change that behavior).
- the introspection strategy used was: DefaultRecursiveComparisonIntrospectionStrategy

So it appears that while the comparator was added double -> DoubleComparator[precision=5.0E-4] it was not used for the comparison?

jamesmudd avatar Aug 27 '24 10:08 jamesmudd