All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.mockk.impl.recording.SignatureMatcherDetector.kt Maven / Gradle / Ivy

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()
    val log = safeToString(Logger())

    fun detect(callRounds: List) {
        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 matcherMap = hashMapOf, Matcher<*>>()
        val allCompositeMatchers = mutableListOf>>()

        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<*>
                    })
                }

                matcherMap[signature] = matcher
            }

            log.trace { "Matcher map: $matcherMap" }
        }

        @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" }

                    matcherMap.remove(signature)
                            ?: ChainedCallDetector.eqOrNullMatcher(matcher.operandValues[nOp])
                } as List>?
            }
        }

        checkAllSameNumberOfCalls()
        checkAllSameNumberOfMatchers()

        gatherMatchers()

        repeat(nCalls) { callN ->
            val detector = chainedCallDetectorFactory()
            detector.detect(callRounds, callN, matcherMap)
            calls.add(detector.call)
        }

        processCompositeMatchers()
        if (matcherMap.isNotEmpty()) {
            throw MockKException("Failed matching mocking signature for\n${callRounds[0].calls.joinToString("\n")}\nleft matchers: ${matcherMap.values}")
        }
    }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy