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

io.mockk.impl.verify.OrderedCallVerifier.kt Maven / Gradle / Ivy

package io.mockk.impl.verify

import io.mockk.MockKGateway
import io.mockk.RecordedCall
import io.mockk.impl.log.SafeLog
import io.mockk.impl.stub.StubRepository
import io.mockk.impl.verify.VerificationHelpers.allInvocations
import io.mockk.impl.verify.VerificationHelpers.reportCalls

class OrderedCallVerifier(
    val stubRepo: StubRepository,
    val safeLog: SafeLog
) : MockKGateway.CallVerifier {
    private val captureBlocks = mutableListOf<() -> Unit>()

    override fun verify(verificationSequence: List, min: Int, max: Int): MockKGateway.VerificationResult {
        val allCalls = verificationSequence.allInvocations(stubRepo)

        if (verificationSequence.size > allCalls.size) {
            return MockKGateway.VerificationResult(false, safeLog.exec {
                "less calls happened then demanded by order verification sequence. " +
                        reportCalls(verificationSequence, allCalls)
            })
        }

        // LCS algorithm
        val nEdits = Array(allCalls.size, { Array(verificationSequence.size, { 0 }) })
        val path = Array(allCalls.size, { Array(verificationSequence.size, { '?' }) })

        fun maxOf(a: Pair, b: Pair) =
            if (a.first > b.first) a else b

        for ((callIdx, call) in allCalls.withIndex()) {
            for ((matcherIdx, matcher) in verificationSequence.map { it.matcher }.withIndex()) {

                val result = if (matcher.match(call)) {
                    if (matcherIdx == 0 || callIdx == 0)
                        Pair(1, '=')
                    else
                        Pair(nEdits[callIdx - 1][matcherIdx - 1] + 1, '=')
                } else {
                    maxOf(
                        if (callIdx == 0)
                            Pair(0, '^')
                        else
                            Pair(nEdits[callIdx - 1][matcherIdx], '='),

                        if (matcherIdx == 0)
                            Pair(0, '<')
                        else
                            Pair(nEdits[callIdx][matcherIdx - 1], '<')
                    )
                }

                nEdits[callIdx][matcherIdx] = result.first
                path[callIdx][matcherIdx] = result.second
            }
        }

        // match only if all matchers present
        if (nEdits[allCalls.size - 1][verificationSequence.size - 1] == verificationSequence.size) {

            tailrec fun backTrackCalls(callIdx: Int, matcherIdx: Int) {
                if (callIdx < 0 || matcherIdx < 0) return

                when (path[callIdx][matcherIdx]) {
                    '=' -> {
                        val matcher = verificationSequence[matcherIdx].matcher
                        val invocation = allCalls[callIdx]
                        captureBlocks.add { matcher.captureAnswer(invocation) }
                        backTrackCalls(callIdx - 1, matcherIdx - 1)
                    }
                    '^' -> {
                        backTrackCalls(callIdx - 1, matcherIdx)
                    }
                    '<' -> {
                        backTrackCalls(callIdx, matcherIdx - 1)
                    }
                }
            }

            backTrackCalls(allCalls.size - 1, verificationSequence.size - 1)

            return MockKGateway.VerificationResult(true)
        } else {
            return MockKGateway.VerificationResult(false, safeLog.exec {
                "calls are not in verification order" + reportCalls(verificationSequence, allCalls)
            })
        }
    }

    override fun captureArguments() {
        captureBlocks.forEach { it() }
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy