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

commonMain.io.mockk.impl.verify.LCSMatchingAlgo.kt Maven / Gradle / Ivy

package io.mockk.impl.verify

import io.mockk.Invocation
import io.mockk.RecordedCall

class LCSMatchingAlgo(
    val allCalls: List,
    private val verificationSequence: List,
    private val captureBlocks: MutableList<() -> Unit>? = null
) {
    private val nEdits = Array(allCalls.size) { Array(verificationSequence.size) { 0 } }
    private val path = Array(allCalls.size) { Array(verificationSequence.size) { '?' } }

    val verifiedMatchers = mutableListOf()
    val verifiedCalls = mutableListOf()

    fun lcs(): Boolean {

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

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

        // match only if all matchers present
        return nEdits.getOrNull(allCalls.size - 1)?.getOrNull(verificationSequence.size -1) == verificationSequence.size
    }

    private 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) }
                verifiedCalls.add(invocation)
                verifiedMatchers.add(verificationSequence[matcherIdx])
                backTrackCalls(callIdx - 1, matcherIdx - 1)
            }
            '^' -> {
                backTrackCalls(callIdx - 1, matcherIdx)
            }
            '<' -> {
                backTrackCalls(callIdx, matcherIdx - 1)
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy