io.mockk.impl.recording.PermanentMocker.kt Maven / Gradle / Ivy
package io.mockk.impl.recording
import io.mockk.EqMatcher
import io.mockk.EquivalentMatcher
import io.mockk.RecordedCall
import io.mockk.impl.InternalPlatform
import io.mockk.impl.log.Logger
import io.mockk.impl.log.SafeLog
import io.mockk.impl.stub.StubRepository
class PermanentMocker(
val stubRepo: StubRepository,
val safeLog: SafeLog
) {
val log = safeLog(Logger())
val permanentMocks = InternalPlatform.identityMap()
val callRef = InternalPlatform.weakMap()
fun mock(calls: List): List {
val result = mutableListOf()
for (call in calls) {
val permanentCall = permamentize(call)
result.add(permanentCall)
}
val callTree = safeLog.exec { describeCallTree(result) }
if (callTree.size == 1) {
log.trace { "Mocked permanently: " + callTree[0] }
} else {
log.trace { "Mocked permanently:\n" + callTree.joinToString(", ") }
}
return result
}
private fun permamentize(call: RecordedCall): RecordedCall {
val newCall = makeCallPermanent(call)
val retValue = call.retValue
if (call.isRetValueMock && retValue != null) {
val equivalentCall = makeEquivalent(newCall)
log.trace { "Child search key: ${equivalentCall.matcher}" }
val childMock = stubRepo.stubFor(newCall.matcher.self)
.childMockK(equivalentCall.matcher, equivalentCall.retType)
val newNewCall = newCall.copy(retValue = childMock)
permanentMocks[retValue] = childMock
callRef[retValue] = newNewCall
return newNewCall
}
return newCall
}
private fun makeEquivalent(newCall: RecordedCall): RecordedCall {
val equivalentArgs = newCall.matcher.args.map {
when (it) {
is EquivalentMatcher -> it.equivalent()
else -> it
}
}
val equivalentIM = newCall.matcher.copy(args = equivalentArgs)
return newCall.copy(matcher = equivalentIM)
}
private fun makeCallPermanent(call: RecordedCall): RecordedCall {
val selfChain = callRef[call.matcher.self]
val argChains = call.matcher.args
.map {
when (it) {
is EqMatcher -> callRef[it.value] ?: it
else -> it
}
}
val newSelf = permanentMocks[call.matcher.self] ?: call.matcher.self
val newArgs = call.matcher.args.map { it.substitute(permanentMocks) }
val newMatcher = call.matcher.copy(self = newSelf, args = newArgs)
return call.copy(
matcher = newMatcher,
selfChain = selfChain,
argChains = argChains
)
}
private fun describeCallTree(calls: MutableList): List {
val callTree = linkedMapOf()
val usedCalls = hashSetOf()
for (call in calls) {
callTree[call] = formatCall(
call,
callTree,
usedCalls
)
}
return calls.filter {
it !in usedCalls
}.map {
callTree[it] ?: ""
}
}
private fun formatCall(
call: RecordedCall,
tree: Map,
usedCalls: MutableSet
): String {
val methodName = call.matcher.method.name
val args = call.argChains!!.map {
when (it) {
is RecordedCall -> {
usedCalls.add(it)
tree[it] ?: ""
}
else -> it.toString()
}
}
val selfChain = call.selfChain
val prefix = if (selfChain != null) {
usedCalls.add(selfChain)
(tree[selfChain] ?: "") + "."
} else {
call.matcher.self.toString() + "."
}
if (methodName.startsWith("get") &&
methodName.length > 3 &&
args.isEmpty()
) {
return prefix +
methodName[3].toLowerCase() +
methodName.substring(4)
}
return prefix + methodName + "(" + args.joinToString(", ") + ")"
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy