ganfra
6 months ago
committed by
GitHub
3 changed files with 234 additions and 0 deletions
@ -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") |
||||
} |
||||
} |
||||
} |
@ -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) |
||||
} |
||||
} |
@ -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…
Reference in new issue