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.