Browse Source

Merge pull request #2615 from element-hq/feature/fga/lambda_recorder

Tests : create lambda recorder
pull/2621/head
ganfra 6 months ago committed by GitHub
parent
commit
bd5c6ea20c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 80
      tests/testutils/src/main/kotlin/io/element/android/tests/testutils/lambda/Assertions.kt
  2. 111
      tests/testutils/src/main/kotlin/io/element/android/tests/testutils/lambda/LambdaRecorder.kt
  3. 43
      tests/testutils/src/main/kotlin/io/element/android/tests/testutils/lambda/ParameterMatcher.kt

80
tests/testutils/src/main/kotlin/io/element/android/tests/testutils/lambda/Assertions.kt

@ -0,0 +1,80 @@ @@ -0,0 +1,80 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.tests.testutils.lambda
fun assert(lambdaRecorder: LambdaRecorder): LambdaRecorderAssertions {
return lambdaRecorder.assertions()
}
class LambdaRecorderAssertions internal constructor(
private val parametersSequence: List<List<Any?>>,
) {
fun isCalledOnce(): CalledOnceParametersAssertions {
return CalledOnceParametersAssertions(
assertions = isCalledExactly(1)
)
}
fun isNeverCalled() {
isCalledExactly(0)
}
fun isCalledExactly(times: Int): ParametersAssertions {
if (parametersSequence.size != times) {
throw AssertionError("Expected to be called $times, but was called ${parametersSequence.size} times")
}
return ParametersAssertions(parametersSequence)
}
}
class CalledOnceParametersAssertions internal constructor(private val assertions: ParametersAssertions) {
fun with(vararg matchers: ParameterMatcher) {
assertions.withSequence(matchers.toList())
}
fun withNoParameter() {
assertions.withNoParameter()
}
}
class ParametersAssertions internal constructor(
private val parametersSequence: List<List<Any?>>
) {
fun withSequence(vararg matchersSequence: List<ParameterMatcher>) {
if (parametersSequence.size != matchersSequence.size) {
throw AssertionError("Lambda was called ${parametersSequence.size} times, but only ${matchersSequence.size} assertions were provided")
}
parametersSequence.zip(matchersSequence).forEachIndexed { invocationIndex, (parameters, matchers) ->
if (parameters.size != matchers.size) {
throw AssertionError("Expected ${matchers.size} parameters, but got ${parameters.size} parameters during invocation #$invocationIndex")
}
parameters.zip(matchers).forEachIndexed { paramIndex, (param, matcher) ->
if (!matcher.match(param)) {
throw AssertionError(
"Parameter #$paramIndex does not match the expected value (actual=$param,expected=$matcher) during invocation #$invocationIndex"
)
}
}
}
}
fun withNoParameter() {
if (parametersSequence.any { it.isNotEmpty() }) {
throw AssertionError("Expected no parameters, but got some")
}
}
}

111
tests/testutils/src/main/kotlin/io/element/android/tests/testutils/lambda/LambdaRecorder.kt

@ -0,0 +1,111 @@ @@ -0,0 +1,111 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.tests.testutils.lambda
/**
* A recorder that can be used to record the parameters of lambda invocation.
*/
abstract class LambdaRecorder internal constructor(
private val assertNoInvocation: Boolean,
) {
private val parametersSequence: MutableList<List<Any?>> = mutableListOf()
internal fun onInvoke(vararg params: Any?) {
if (assertNoInvocation) {
throw AssertionError("This lambda should never be called.")
}
parametersSequence.add(params.toList())
}
fun assertions(): LambdaRecorderAssertions {
return LambdaRecorderAssertions(parametersSequence = parametersSequence)
}
}
inline fun <reified R> lambdaRecorder(
ensureNeverCalled: Boolean = false,
noinline block: () -> R
): LambdaNoParamRecorder<R> {
return LambdaNoParamRecorder(ensureNeverCalled, block)
}
inline fun <reified T, reified R> lambdaRecorder(
ensureNeverCalled: Boolean = false,
noinline block: (T) -> R
): LambdaOneParamRecorder<T, R> {
return LambdaOneParamRecorder(ensureNeverCalled, block)
}
inline fun <reified T1, reified T2, reified R> lambdaRecorder(
ensureNeverCalled: Boolean = false,
noinline block: (T1, T2) -> R
): LambdaTwoParamsRecorder<T1, T2, R> {
return LambdaTwoParamsRecorder(ensureNeverCalled, block)
}
inline fun <reified T1, reified T2, reified T3, reified R> lambdaRecorder(
ensureNeverCalled: Boolean = false,
noinline block: (T1, T2, T3) -> R
): LambdaThreeParamsRecorder<T1, T2, T3, R> {
return LambdaThreeParamsRecorder(ensureNeverCalled, block)
}
inline fun <reified T1, reified T2, reified T3, reified T4, reified R> lambdaRecorder(
ensureNeverCalled: Boolean = false,
noinline block: (T1, T2, T3, T4) -> R
): LambdaFourParamsRecorder<T1, T2, T3, T4, R> {
return LambdaFourParamsRecorder(ensureNeverCalled, block)
}
class LambdaNoParamRecorder<out R>(ensureNeverCalled: Boolean, val block: () -> R) : LambdaRecorder(ensureNeverCalled), () -> R {
override fun invoke(): R {
onInvoke()
return block()
}
}
class LambdaOneParamRecorder<in T, out R>(ensureNeverCalled: Boolean, val block: (T) -> R) : LambdaRecorder(ensureNeverCalled), (T) -> R {
override fun invoke(p: T): R {
onInvoke(p)
return block(p)
}
}
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 {
onInvoke(p1, p2)
return block(p1, p2)
}
}
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 {
onInvoke(p1, p2, p3)
return block(p1, p2, p3)
}
}
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 {
onInvoke(p1, p2, p3, p4)
return block(p1, p2, p3, p4)
}
}

43
tests/testutils/src/main/kotlin/io/element/android/tests/testutils/lambda/ParameterMatcher.kt

@ -0,0 +1,43 @@ @@ -0,0 +1,43 @@
/*
* Copyright (c) 2024 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.element.android.tests.testutils.lambda
/**
* A matcher that can be used to match parameters in lambda calls.
* This is useful to assert that a lambda has been called with specific parameters.
*/
interface ParameterMatcher {
fun match(param: Any?): Boolean
}
/**
* A matcher that matches a specific value.
* Can be used to assert that a lambda has been called with a specific value.
*/
fun <T> value(expectedValue: T) = object : ParameterMatcher {
override fun match(param: Any?) = param == expectedValue
override fun toString(): String = "value($expectedValue)"
}
/**
* A matcher that matches any value.
* Can be used when we don't care about the value of a parameter.
*/
fun any() = object : ParameterMatcher {
override fun match(param: Any?) = true
override fun toString(): String = "any()"
}
Loading…
Cancel
Save