Eric
05/18/2022, 1:00 PMget { value }.isA<List<FooBar>>()
But isA
doesn’t (and can’t, I think until Valhalla give us reified generics natively in Java?) check the type of the entries of the List
that they are all an instance of FooBar
. So this will also pass:
get { value }.isA<List<LiterallyAnyClassYouWant>>()
Something like this will do that:
@Suppress("UNCHECKED_CAST")
inline fun <reified T> Assertion.Builder<*>.isCollectionOf(): Assertion.Builder<Collection<T>> =
assert("is a collection of %s", T::class.java) {
val collection = it as? Collection<*>
val wronglyTypedEntries = collection?.mapIndexedNotNull { index, entry ->
when (entry) {
is T -> null
null -> "null @ index $index"
else -> "${entry::class} @ index $index"
}
} ?: emptyList()
when {
it == null -> fail(actual = null)
collection == null -> fail(actual = it::class.java)
wronglyTypedEntries.isEmpty() -> pass()
else -> fail(actual = wronglyTypedEntries)
}
} as Assertion.Builder<Collection<T>>
val numbers = listOf(1, 2f)
expectThat(numbers).isA<List<*>>() // passes
expectThat(numbers).isA<List<Any>>() // passes
expectThat(numbers).isA<List<String>>() // passes!!!
expectThat(numbers).isCollectionOf<Number>() // passes
expectThat(numbers).isCollectionOf<Int>() // fails with:
// ▼ Expect that [1, 2.0]:
// ✗ is a collection of java.lang.Integer
// found ["class kotlin.Float @ index 1"]
but devs still need to know to avoid using isA
on Collections
.