would it make sense to restrict `T` to being a sub...
# strikt
r
would it make sense to restrict
T
to being a subtype of whatever the current subject is?
c
i guess so. why does the isA matcher not do it?
(i think it doesnt)
r
good question
c
i have wondered about that when working with sealed classes. from the code completion it did not think like it did
r
ah, because if
isA
has 2 type parameters you can’t call it with
isA<Whatever>
c
ah makes sense!
r
I think that may not be the case with the suggestion here though, because it’s able to infer all its type parameters
c
maybe the normal get method could just work like that?
(instead of giving it a new name)
r
right. The only downside being that you’d end up with an
isA
in the assertion tree. Might be possible to optimize that out tho
d
And I need all this every time:
Copy code
inline fun <reified T, R> Assertion.Builder<*>.getFromA(noinline function: T.() -> R): Assertion.Builder<R> =
    isA<T>().get(function.describe(), function)

fun <Receiver, Result> (Receiver.() -> Result).describe(): String =
    when (this) {
        is KProperty<*> ->
            "value of property $name"
        is KFunction<*> ->
            "return value of $name"
        is CallableReference -> "value of $propertyName"
        else -> { "%s" }
    }

val CallableReference.propertyName: String
    get() = "^get(.+)$".toRegex().find(name).let { match ->
        return when (match) {
            null -> name
            else -> match.groupValues[1].replaceFirstChar { it.lowercase(Locale.getDefault()) }
        }
    }
Since those are private or internal...
(the describe and propertyName functions...)
e
i added this to our testing project
Copy code
@Suppress("UNCHECKED_CAST")
inline fun <reified T> Assertion.Builder<*>.isCollectionOf(): Assertion.Builder<Collection<T>> =
    compose("is a Collection<${T::class.java.name}>") { subject ->
        val collection = subject as? Collection<*>
        assertThat("is a Collection") { collection != null }
        if (collection == null) return@compose
        assert("all elements are ${T::class.java.name}") {
            val wronglyTypedElements = collection.mapIndexedNotNull { index, element ->
                when (element) {
                    is T -> null
                    null -> "null @ index $index"
                    else -> "${element::class.java.name} @ index $index"
                }
            }
            if (wronglyTypedElements.isEmpty()) {
                pass()
            } else {
                fail(description = "incorrect elements: $wronglyTypedElements")
            }
        }
    }.assertAllPassed() as Assertion.Builder<Collection<T>>
not sure if this is the ideal implementation
d
I have a single object that I need to test a property on. I suppose your implementation is for a collection...