Eric
10/28/2022, 4:13 PMpropertiesAreEqualTo
that doesn’t require other
to be the same type as the subject. Just a couple minor tweaks.
fun <T : Any> Assertion.Builder<T>.reflectionEquals(
other: Any,
ignoredPropertyNames: List<String> = emptyList()
): Assertion.Builder<T> = compose("is equal field-by-field to %s", other) { subject ->
val otherBeanInfo = Introspector.getBeanInfo(other.javaClass)
val beanInfo = Introspector.getBeanInfo(subject.javaClass)
beanInfo.propertyDescriptors
.filter { it.name != "class" && it.name !in ignoredPropertyNames }
.forEach { property ->
val mappedAssertion = get("value of property ${property.name}") {
property.readMethod(this)
}
val otherProperty = otherBeanInfo.propertyDescriptors.firstOrNull { it.name == property.name }
val otherValue = otherProperty?.let { it.readMethod(other) }
// the rest is the same as propertiesAreEqualTo
Eric
10/28/2022, 4:14 PMrobfletcher
10/28/2022, 4:28 PMrobfletcher
10/28/2022, 4:29 PMEric
10/28/2022, 4:30 PMrobfletcher
10/28/2022, 4:30 PMEric
10/31/2022, 2:12 PMrobfletcher
10/31/2022, 4:58 PMEric
10/31/2022, 4:59 PMrobfletcher
10/31/2022, 4:59 PMrobfletcher
10/31/2022, 4:59 PMEric
11/09/2022, 4:03 PMdave08
12/07/2022, 2:01 PMEric
12/07/2022, 2:12 PM// based on <https://github.com/robfletcher/strikt/blob/main/strikt-jvm/src/main/kotlin/strikt/java/Any.kt>
fun <T : Any> Assertion.Builder<T>.reflectionEquals(
other: Any,
ignoredPropertyNames: List<String> = emptyList(),
ignoreExtraProperties: Boolean = true
): Assertion.Builder<T> = compose("is equal field-by-field to %s", other) { subject ->
val otherBeanInfo = Introspector.getBeanInfo(other.javaClass)
val beanInfo = Introspector.getBeanInfo(subject.javaClass)
beanInfo.propertyDescriptors
.filter { it.name != "class" && it.name !in ignoredPropertyNames }
.forEach { property ->
val otherProperty = otherBeanInfo.propertyDescriptors.firstOrNull { it.name == property.name }
if (otherProperty == null) {
assertThat("has property: %s", property.name) { false }
return@forEach
}
val mappedAssertion = get("value of property ${property.name}") { property.readMethod(subject) }
val otherValue = otherProperty.let { it.readMethod(other) }
@Suppress("UNCHECKED_CAST")
when {
mappedAssertion.subject != null && otherValue == null ->
mappedAssertion.assertThat("${property.name} is not null") { false }
mappedAssertion.subject == null && otherValue != null ->
mappedAssertion.assertThat("${property.name} is null") { false }
property.propertyType == BooleanArray::class.java ->
(mappedAssertion as Assertion.Builder<BooleanArray>).contentEquals(otherValue as BooleanArray)
property.propertyType == ByteArray::class.java ->
(mappedAssertion as Assertion.Builder<ByteArray>).contentEquals(otherValue as ByteArray)
property.propertyType == ShortArray::class.java ->
(mappedAssertion as Assertion.Builder<ShortArray>).contentEquals(otherValue as ShortArray)
property.propertyType == IntArray::class.java ->
(mappedAssertion as Assertion.Builder<IntArray>).contentEquals(otherValue as IntArray)
property.propertyType == LongArray::class.java ->
(mappedAssertion as Assertion.Builder<LongArray>).contentEquals(otherValue as LongArray)
property.propertyType == FloatArray::class.java ->
(mappedAssertion as Assertion.Builder<FloatArray>).contentEquals(otherValue as FloatArray)
property.propertyType == DoubleArray::class.java ->
(mappedAssertion as Assertion.Builder<DoubleArray>).contentEquals(otherValue as DoubleArray)
property.propertyType.isArray ->
(mappedAssertion as Assertion.Builder<Array<*>>).contentEquals(otherValue as Array<*>)
property.propertyType.isPrimitive -> mappedAssertion.isEqualTo(otherValue)
else -> mappedAssertion.reflectionEquals(
otherValue,
ignoredPropertyNames.map { it.substringAfter('.', "") }.filterNot { it.isEmpty() },
ignoreExtraProperties
)
}
}
if (!ignoreExtraProperties) {
val extraProperties = otherBeanInfo.propertyDescriptors.map { it.name }.toSet() -
beanInfo.propertyDescriptors.map { it.name }.toSet()
assertThat("has no extra properties; found: %s", extraProperties) { extraProperties.isEmpty() }
}
} then {
if (allPassed) pass() else fail()
}
Eric
12/20/2022, 2:05 PMEric
12/20/2022, 2:07 PMrobfletcher
12/23/2022, 12:27 AMrobfletcher
12/23/2022, 12:27 AMrobfletcher
12/23/2022, 12:28 AMrobfletcher
12/23/2022, 12:30 AMEric
12/23/2022, 12:56 AMEric
12/23/2022, 12:57 AMrobfletcher
12/23/2022, 1:03 AMrobfletcher
12/23/2022, 1:06 AM