Skip to content

Commit

Permalink
Merge pull request #951 from m-burst/issue-774
Browse files Browse the repository at this point in the history
Fix verifier logic for slots and different matchers
  • Loading branch information
Raibaz committed Oct 24, 2022
2 parents 098b3aa + fb51171 commit a2421bf
Show file tree
Hide file tree
Showing 3 changed files with 106 additions and 6 deletions.
Expand Up @@ -55,15 +55,17 @@ open class UnorderedCallVerifier(
val allCallsForMock = stub.allRecordedCalls()
val allCallsForMockMethod = stub.allRecordedCalls(matcher.method)

if(allCallsForMockMethod.size > 1 && matcher.args.any { it is CapturingSlotMatcher<*> }) {
val matchedCalls = allCallsForMockMethod.filter(matcher::match)

if(matchedCalls.size > 1 && matcher.args.any { it is CapturingSlotMatcher<*> }) {
val msg = "$matcher execution is being verified more than once and its arguments are being captured with a slot.\n" +
"This will store only the argument of the last invocation in the slot.\n" +
"If you want to store all the arguments, use a mutableList to capture arguments."
throw MockKException(msg)
}

val result = if (min == 0 && max == 0) {
if (!allCallsForMockMethod.any(matcher::match)) {
if (matchedCalls.isEmpty()) {
VerificationResult.OK(listOf())
} else {
VerificationResult.Failure(
Expand Down Expand Up @@ -127,7 +129,6 @@ open class UnorderedCallVerifier(
}
}
else -> {
val matchedCalls = allCallsForMockMethod.filter(matcher::match)
val n = matchedCalls.count()
if (n in min..max) {
VerificationResult.OK(matchedCalls)
Expand Down Expand Up @@ -162,7 +163,7 @@ open class UnorderedCallVerifier(
}

captureBlocks.add {
for (call in allCallsForMockMethod) {
for (call in matchedCalls) {
matcher.captureAnswer(call)
}
}
Expand Down
@@ -0,0 +1,80 @@
package io.mockk.it

import io.mockk.Runs
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.slot
import io.mockk.verify
import io.mockk.verifyOrder
import io.mockk.verifySequence
import kotlin.test.Test
import kotlin.test.assertIs
import kotlin.test.assertTrue

/**
* See issue #774.
*/
class CaptureSubclassVerificationTest {

interface Interface

class Subclass1 : Interface

class Subclass2 : Interface

interface Service {
fun method(obj: Interface)
}

@Test
fun `test unordered`() {
val service = mockk<Service> {
every { method(any()) } just Runs
}

service.method(Subclass1())
service.method(Subclass2())

val slot = slot<Subclass2>()
verify(exactly = 1) { service.method(capture(slot)) }
assertTrue(slot.isCaptured)
assertIs<Subclass2>(slot.captured)
}

@Test
fun `test ordered`() {
val service = mockk<Service> {
every { method(any()) } just Runs
}

service.method(Subclass1())
service.method(Subclass2())

val slot = slot<Subclass2>()
verifyOrder {
service.method(any())
service.method(capture(slot))
}
assertTrue(slot.isCaptured)
assertIs<Subclass2>(slot.captured)
}

@Test
fun `test sequence`() {
val service = mockk<Service> {
every { method(any()) } just Runs
}

service.method(Subclass1())
service.method(Subclass2())

val slot = slot<Subclass2>()
verifySequence {
service.method(any())
service.method(capture(slot))
}
assertTrue(slot.isCaptured)
assertIs<Subclass2>(slot.captured)
}
}
23 changes: 21 additions & 2 deletions modules/mockk/src/commonTest/kotlin/io/mockk/it/CapturingTest.kt
Expand Up @@ -85,8 +85,8 @@ class CapturingTest {

assertFailsWith<MockKException> {
verify {
mock.doSomething("1", capture(dataSlotId1))
mock.doSomething("2", capture(dataSlotId2))
mock.doSomething(any(), capture(dataSlotId1))
mock.doSomething(any(), capture(dataSlotId2))
}
}
}
Expand Down Expand Up @@ -136,6 +136,8 @@ class CapturingTest {
mock.doSomething("2", capture(slotList))
}

// Each capture should have happened once because of different matchers for `id` argument
assertEquals(slotList.size, 2)
assertEquals("data1", slotList[0])
assertEquals("data2", slotList[1])
}
Expand All @@ -158,6 +160,23 @@ class CapturingTest {
assertEquals(args, list)
}

@Test
fun itDoesNotThrowAMockkExceptionWhenVerifyingTheSameFunctionTwiceWithSlotsWithDifferentMatchers() {
mock.doSomething("1", "data1")
mock.doSomething("2", "data2")

val dataSlotId1 = slot<String>()
val dataSlotId2 = slot<String>()

verify {
mock.doSomething("1", capture(dataSlotId1))
mock.doSomething("2", capture(dataSlotId2))
}

assertEquals("data1", dataSlotId1.captured)
assertEquals("data2", dataSlotId2.captured)
}

class MockNullableCls {
fun call(unused: String?) {
println(unused)
Expand Down

0 comments on commit a2421bf

Please sign in to comment.