Tests : improve lambda recorder

This commit is contained in:
ganfra 2024-03-28 14:59:22 +01:00
parent 00613da64c
commit 13aa578e11
3 changed files with 34 additions and 30 deletions

View file

@ -56,29 +56,17 @@ class ParametersAssertions internal constructor(
) { ) {
fun withSequence(vararg matchersSequence: List<ParameterMatcher>) { fun withSequence(vararg matchersSequence: List<ParameterMatcher>) {
if (parametersSequence.size != matchersSequence.size) { if (parametersSequence.size != matchersSequence.size) {
throw AssertionError("Expected ${matchersSequence.size} parameters, but got ${parametersSequence.size} parameters") throw AssertionError("Lambda was called ${parametersSequence.size} times, but only ${matchersSequence.size} assertions were provided")
} }
parametersSequence.zip(matchersSequence).forEach { (parameters, matchers) -> parametersSequence.zip(matchersSequence).forEachIndexed { invocationIndex, (parameters, matchers) ->
if (parameters.size != matchers.size) { if (parameters.size != matchers.size) {
throw AssertionError("Expected ${matchers.size} parameters, but got ${parameters.size} parameters") throw AssertionError("Expected ${matchers.size} parameters, but got ${parameters.size} parameters during invocation #$invocationIndex")
} }
parameters.zip(matchers).forEachIndexed { j, (param, matcher) -> parameters.zip(matchers).forEachIndexed { paramIndex, (param, matcher) ->
if (!matcher.match(param)) { if (!matcher.match(param)) {
throw AssertionError("Parameter $j does not match the expected value") throw AssertionError(
} "Parameter #$paramIndex does not match the expected value (actual=$param,expected=$matcher) during invocation #$invocationIndex"
} )
}
for (i in parametersSequence.indices) {
val params = parametersSequence[i]
val checker = matchersSequence[i]
if (params.size != checker.size) {
throw AssertionError("Expected ${checker.size} parameters, but got ${params.size} parameters")
}
for (j in params.indices) {
val param = params[j]
val check = checker[j]
if (!check.match(param)) {
throw AssertionError("Parameter $j does not match the expected value")
} }
} }
} }

View file

@ -19,10 +19,15 @@ package io.element.android.tests.testutils.lambda
/** /**
* A recorder that can be used to record the parameters of lambda invocation. * A recorder that can be used to record the parameters of lambda invocation.
*/ */
abstract class LambdaRecorder internal constructor() { abstract class LambdaRecorder internal constructor(
private val assertNoInvocation: Boolean,
) {
private val parametersSequence: MutableList<List<Any?>> = mutableListOf() private val parametersSequence: MutableList<List<Any?>> = mutableListOf()
internal fun onInvoke(vararg params: Any?) { internal fun onInvoke(vararg params: Any?) {
if (assertNoInvocation) {
throw AssertionError("This lambda should never be called.")
}
parametersSequence.add(params.toList()) parametersSequence.add(params.toList())
} }
@ -32,64 +37,73 @@ abstract class LambdaRecorder internal constructor() {
} }
inline fun <reified R> lambdaRecorder( inline fun <reified R> lambdaRecorder(
ensureNeverCalled: Boolean = false,
noinline block: () -> R noinline block: () -> R
): LambdaNoParamRecorder<R> { ): LambdaNoParamRecorder<R> {
return LambdaNoParamRecorder(block) return LambdaNoParamRecorder(ensureNeverCalled, block)
} }
inline fun <reified T, reified R> lambdaRecorder( inline fun <reified T, reified R> lambdaRecorder(
ensureNeverCalled: Boolean = false,
noinline block: (T) -> R noinline block: (T) -> R
): LambdaOneParamRecorder<T, R> { ): LambdaOneParamRecorder<T, R> {
return LambdaOneParamRecorder(block) return LambdaOneParamRecorder(ensureNeverCalled, block)
} }
inline fun <reified T1, reified T2, reified R> lambdaRecorder( inline fun <reified T1, reified T2, reified R> lambdaRecorder(
ensureNeverCalled: Boolean = false,
noinline block: (T1, T2) -> R noinline block: (T1, T2) -> R
): LambdaTwoParamsRecorder<T1, T2, R> { ): LambdaTwoParamsRecorder<T1, T2, R> {
return LambdaTwoParamsRecorder(block) return LambdaTwoParamsRecorder(ensureNeverCalled, block)
} }
inline fun <reified T1, reified T2, reified T3, reified R> lambdaRecorder( inline fun <reified T1, reified T2, reified T3, reified R> lambdaRecorder(
ensureNeverCalled: Boolean = false,
noinline block: (T1, T2, T3) -> R noinline block: (T1, T2, T3) -> R
): LambdaThreeParamsRecorder<T1, T2, T3, R> { ): LambdaThreeParamsRecorder<T1, T2, T3, R> {
return LambdaThreeParamsRecorder(block) return LambdaThreeParamsRecorder(ensureNeverCalled, block)
} }
inline fun <reified T1, reified T2, reified T3, reified T4, reified R> lambdaRecorder( inline fun <reified T1, reified T2, reified T3, reified T4, reified R> lambdaRecorder(
ensureNeverCalled: Boolean = false,
noinline block: (T1, T2, T3, T4) -> R noinline block: (T1, T2, T3, T4) -> R
): LambdaFourParamsRecorder<T1, T2, T3, T4, R> { ): LambdaFourParamsRecorder<T1, T2, T3, T4, R> {
return LambdaFourParamsRecorder(block) return LambdaFourParamsRecorder(ensureNeverCalled, block)
} }
class LambdaNoParamRecorder<out R>(val block: () -> R) : LambdaRecorder(), () -> R { class LambdaNoParamRecorder<out R>(ensureNeverCalled: Boolean, val block: () -> R) : LambdaRecorder(ensureNeverCalled), () -> R {
override fun invoke(): R { override fun invoke(): R {
onInvoke() onInvoke()
return block() return block()
} }
} }
class LambdaOneParamRecorder<in T, out R>(val block: (T) -> R) : LambdaRecorder(), (T) -> R { class LambdaOneParamRecorder<in T, out R>(ensureNeverCalled: Boolean, val block: (T) -> R) : LambdaRecorder(ensureNeverCalled), (T) -> R {
override fun invoke(p: T): R { override fun invoke(p: T): R {
onInvoke(p) onInvoke(p)
return block(p) return block(p)
} }
} }
class LambdaTwoParamsRecorder<in T1, in T2, out R>(val block: (T1, T2) -> R) : LambdaRecorder(), (T1, T2) -> R { class LambdaTwoParamsRecorder<in T1, in T2, out R>(ensureNeverCalled: Boolean, val block: (T1, T2) -> R) : LambdaRecorder(ensureNeverCalled), (T1, T2) -> R {
override fun invoke(p1: T1, p2: T2): R { override fun invoke(p1: T1, p2: T2): R {
onInvoke(p1, p2) onInvoke(p1, p2)
return block(p1, p2) return block(p1, p2)
} }
} }
class LambdaThreeParamsRecorder<in T1, in T2, in T3, out R>(val block: (T1, T2, T3) -> R) : LambdaRecorder(), (T1, T2, T3) -> R { class LambdaThreeParamsRecorder<in T1, in T2, in T3, out R>(ensureNeverCalled: Boolean, val block: (T1, T2, T3) -> R) : LambdaRecorder(
ensureNeverCalled
), (T1, T2, T3) -> R {
override fun invoke(p1: T1, p2: T2, p3: T3): R { override fun invoke(p1: T1, p2: T2, p3: T3): R {
onInvoke(p1, p2, p3) onInvoke(p1, p2, p3)
return block(p1, p2, p3) return block(p1, p2, p3)
} }
} }
class LambdaFourParamsRecorder<in T1, in T2, in T3, in T4, out R>(val block: (T1, T2, T3, T4) -> R) : LambdaRecorder(), (T1, T2, T3, T4) -> R { class LambdaFourParamsRecorder<in T1, in T2, in T3, in T4, out R>(ensureNeverCalled: Boolean, val block: (T1, T2, T3, T4) -> R) : LambdaRecorder(
ensureNeverCalled
), (T1, T2, T3, T4) -> R {
override fun invoke(p1: T1, p2: T2, p3: T3, p4: T4): R { override fun invoke(p1: T1, p2: T2, p3: T3, p4: T4): R {
onInvoke(p1, p2, p3, p4) onInvoke(p1, p2, p3, p4)
return block(p1, p2, p3, p4) return block(p1, p2, p3, p4)

View file

@ -30,6 +30,7 @@ interface ParameterMatcher {
*/ */
fun <T> value(expectedValue: T) = object : ParameterMatcher { fun <T> value(expectedValue: T) = object : ParameterMatcher {
override fun match(param: Any?) = param == expectedValue override fun match(param: Any?) = param == expectedValue
override fun toString(): String = "value($expectedValue)"
} }
/** /**
@ -38,4 +39,5 @@ fun <T> value(expectedValue: T) = object : ParameterMatcher {
*/ */
fun any() = object : ParameterMatcher { fun any() = object : ParameterMatcher {
override fun match(param: Any?) = true override fun match(param: Any?) = true
override fun toString(): String = "any()"
} }