io.mockk.impl.recording.ChainedCallDetector.kt Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of mockk-common Show documentation
Show all versions of mockk-common Show documentation
Common(JS and Java) MockK module
The newest version!
package io.mockk.impl.recording
import io.mockk.*
import io.mockk.InternalPlatformDsl.toArray
import io.mockk.InternalPlatformDsl.toStr
import io.mockk.impl.InternalPlatform
import io.mockk.impl.log.Logger
import io.mockk.impl.log.SafeToString
import kotlin.coroutines.Continuation
class ChainedCallDetector(safeToString: SafeToString) {
val log = safeToString(Logger())
val argMatchers = mutableListOf>()
lateinit var call: RecordedCall
@Suppress("CAST_NEVER_SUCCEEDS")
fun detect(
callRounds: List,
callN: Int,
matcherMap: HashMap, Matcher<*>>
) {
val callInAllRounds = callRounds.map { it.calls[callN] }
val zeroCall = callInAllRounds[0]
var allAny = false
log.trace { "Processing call #$callN: ${zeroCall.method.toStr()}" }
fun buildMatcher(isStart: Boolean, zeroCallValue: Any?, matcherBySignature: Matcher<*>?): Matcher<*> {
return if (matcherBySignature == null) {
if (allAny)
ConstantMatcher(true)
else {
eqOrNullMatcher(zeroCallValue)
}
} else {
if (isStart && matcherBySignature is AllAnyMatcher) {
allAny = true
ConstantMatcher(true)
} else {
matcherBySignature
}
}
}
fun regularArgument(nArgument: Int): Matcher<*> {
val signature = callInAllRounds.map {
InternalPlatform.packRef(it.args[nArgument])
}.toList()
log.trace { "Signature for $nArgument argument of ${zeroCall.method.toStr()}: $signature" }
val matcherBySignature = matcherMap.remove(signature)
return buildMatcher(
nArgument == 0,
zeroCall.args[nArgument],
matcherBySignature
)
}
@Suppress("UNCHECKED_CAST")
fun composeVarArgMatcher(matchers: List>): Matcher<*> {
val idx = matchers.indexOfFirst { it is VarargMatcher<*> }
val prefix = matchers.subList(0, idx) as List>
val postfix = matchers.subList(idx + 1, matchers.size) as List>
val matcher = matchers[idx] as VarargMatcher<*>
return matcher.copy(prefix = prefix, postfix = postfix)
}
@Suppress("UNCHECKED_CAST")
fun varArgArgument(nArgument: Int): Matcher<*> {
val varArgMatchers = mutableListOf>()
val zeroCallArg = zeroCall.args[nArgument]!!.toArray()
repeat(zeroCallArg.size) { nVarArg ->
val signature = callInAllRounds.map {
val arg = it.args[nArgument]!!.toArray()
InternalPlatform.packRef(arg[nVarArg])
}.toList()
log.trace { "Signature for $nArgument/$nVarArg argument of ${zeroCall.method.toStr()}: $signature" }
val matcherBySignature = matcherMap.remove(signature)
varArgMatchers.add(
buildMatcher(
nArgument == 0 && nVarArg == 0,
zeroCallArg[nVarArg],
matcherBySignature
)
)
}
val nVarArgMatchers = varArgMatchers.count { it is VarargMatcher<*> }
return when (nVarArgMatchers) {
0 -> ArrayMatcher(varArgMatchers.map { it } as List>)
1 -> composeVarArgMatcher(varArgMatchers)
else -> throw MockKException("using more then one vararg VarargMatcher in one expression is not possible: $varArgMatchers")
}
}
fun detectArgMatchers() {
allAny = false
val varArgsArg = zeroCall.method.varArgsArg
repeat(zeroCall.args.size) { nArgument ->
val matcher = if (varArgsArg == nArgument) {
varArgArgument(nArgument)
} else {
regularArgument(nArgument)
}
argMatchers.add(matcher)
}
}
@Suppress("UNCHECKED_CAST")
fun buildRecordedCall(): RecordedCall {
fun SignedCall.isSuspend() = when {
method.isSuspend -> true
method.isFnCall -> args.lastOrNull()?.let {
Continuation::class.isInstance(it)
} ?: false
else -> false
}
if (zeroCall.isSuspend()) {
log.trace { "Suspend function found. Replacing continuation with any() matcher" }
argMatchers[argMatchers.size - 1] = ConstantMatcher(true)
}
val im = InvocationMatcher(
zeroCall.self,
zeroCall.method,
argMatchers.toList() as List>,
allAny
)
log.trace { "Built matcher: $im" }
return RecordedCall(
zeroCall.retValue,
zeroCall.isRetValueMock,
zeroCall.retType,
im,
null,
null
)
}
detectArgMatchers()
call = buildRecordedCall()
}
companion object {
fun eqOrNullMatcher(arg: Any?): Matcher {
return if (arg == null) {
NullCheckMatcher(false)
} else {
EqMatcher(arg)
}
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy