forked from mockk/mockk
/
SignatureMatcherDetector.kt
103 lines (83 loc) · 3.73 KB
/
SignatureMatcherDetector.kt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package io.mockk.impl.recording
import io.mockk.CompositeMatcher
import io.mockk.Matcher
import io.mockk.MockKException
import io.mockk.RecordedCall
import io.mockk.impl.InternalPlatform
import io.mockk.impl.log.Logger
import io.mockk.impl.log.SafeToString
class SignatureMatcherDetector(
safeToString: SafeToString,
val chainedCallDetectorFactory: ChainedCallDetectorFactory
) {
val calls = mutableListOf<RecordedCall>()
val log = safeToString(Logger<SignatureMatcherDetector>())
fun detect(callRounds: List<CallRound>) {
calls.clear()
val nCalls = callRounds[0].calls.size
fun checkAllSameNumberOfCalls() {
if (callRounds.any { it.calls.size != nCalls }) {
throw MockKException("every/verify {} block were run several times. Recorded calls count differ between runs\n" +
callRounds.withIndex().map {
"Round ${it.index + 1}: " + it.value.calls.map { it.invocationStr }.joinToString(
", "
)
}.joinToString("\n")
)
}
}
val nMatchers = callRounds[0].matchers.size
fun checkAllSameNumberOfMatchers() {
if (callRounds.any { it.matchers.size != nMatchers }) {
throw MockKException("every/verify {} block were run several times. Recorded matchers count differ between runs\n" +
callRounds.withIndex().map {
"Round ${it.index + 1}: " + it.value.matchers.map { it }.joinToString(
", "
)
}.joinToString("\n")
)
}
}
val matchersList = SignatureMatchersList()
val allCompositeMatchers = mutableListOf<List<CompositeMatcher<*>>>()
fun gatherMatchers() {
repeat(nMatchers) { nMatcher ->
val matcher = callRounds.last().matchers[nMatcher].matcher
val signature = callRounds.map { it.matchers[nMatcher].signature }
if (matcher is CompositeMatcher<*>) {
allCompositeMatchers.add(callRounds.map {
it.matchers[nMatcher].matcher as CompositeMatcher<*>
})
}
matchersList.add(signature, matcher)
}
log.trace { "Matcher list: $matchersList" }
}
@Suppress("UNCHECKED_CAST")
fun processCompositeMatchers() {
for (compositeMatchers in allCompositeMatchers) {
val matcher = compositeMatchers.last()
matcher.subMatchers = matcher.operandValues.withIndex().map { (nOp, _) ->
val signature = compositeMatchers.map {
InternalPlatform.packRef(it.operandValues[nOp])
}.toList()
log.trace { "Signature for $nOp operand of $matcher composite matcher: $signature" }
matchersList.remove(signature)
?: ChainedCallDetector.eqOrNullMatcher(matcher.operandValues[nOp])
} as List<Matcher<Any?>>?
}
}
checkAllSameNumberOfCalls()
checkAllSameNumberOfMatchers()
gatherMatchers()
repeat(nCalls) { callN ->
val detector = chainedCallDetectorFactory()
detector.detect(callRounds, callN, matchersList)
calls.add(detector.call)
}
processCompositeMatchers()
if (matchersList.isNotEmpty()) {
throw MockKException("Failed matching mocking signature for\n${callRounds[0].calls.joinToString("\n")}\nleft matchers: $matchersList")
}
}
}