Skip to content

Commit

Permalink
Fix vararg handling
Browse files Browse the repository at this point in the history
  • Loading branch information
lukas-krecan committed May 19, 2023
1 parent 3085fd9 commit bf2d54e
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 7 deletions.
20 changes: 18 additions & 2 deletions mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Matchers.kt
Expand Up @@ -25,9 +25,10 @@

package org.mockito.kotlin

import org.mockito.kotlin.internal.createInstance
import org.mockito.ArgumentMatcher
import org.mockito.ArgumentMatchers
import org.mockito.kotlin.internal.createInstance
import kotlin.reflect.KClass

/** Object argument that is equal to the given value. */
fun <T> eq(value: T): T {
Expand All @@ -51,7 +52,22 @@ inline fun <reified T : Any> anyOrNull(): T {

/** Matches any vararg object, including nulls. */
inline fun <reified T : Any> anyVararg(): T {
return ArgumentMatchers.any<T>() ?: createInstance()
return anyVararg(T::class)
}

fun <T : Any> anyVararg(clazz: KClass<T>): T {
return ArgumentMatchers.argThat(VarargMatcher(clazz.java))?: createInstance(clazz)
}

private class VarargMatcher<T>(
private val clazz: Class<T>
) : ArgumentMatcher<T>{
override fun matches(t: T): Boolean {
return true
}

// In Java > 12 tou can do clazz.arrayClass()
override fun type(): Class<*> = java.lang.reflect.Array.newInstance(clazz, 0).javaClass
}

/** Matches any array of type T. */
Expand Down
21 changes: 16 additions & 5 deletions tests/src/test/kotlin/test/MatchersTest.kt
Expand Up @@ -8,6 +8,7 @@ import org.mockito.invocation.InvocationOnMock
import org.mockito.kotlin.*
import org.mockito.stubbing.Answer
import java.io.IOException
import kotlin.reflect.KClass

class MatchersTest : TestBase() {

Expand Down Expand Up @@ -67,6 +68,14 @@ class MatchersTest : TestBase() {
}
}

@Test
fun anyVarargMatching() {
mock<Methods>().apply {
whenever(varargBooleanResult(anyVararg())).thenReturn(true)
expect(varargBooleanResult()).toBe(true)
}
}

@Test
fun anyNull_neverVerifiesAny() {
mock<Methods>().apply {
Expand Down Expand Up @@ -275,7 +284,7 @@ class MatchersTest : TestBase() {
/* Given */
val t = mock<Methods>()
// a matcher to check if any of the varargs was equals to "b"
val matcher = VarargAnyMatcher<String, Boolean>({ "b" == it }, true, false)
val matcher = VarargAnyMatcher({ "b" == it }, String::class.java, true, false)

/* When */
whenever(t.varargBooleanResult(argThat(matcher))).thenAnswer(matcher)
Expand All @@ -289,7 +298,7 @@ class MatchersTest : TestBase() {
/* Given */
val t = mock<Methods>()
// a matcher to check if any of the varargs was equals to "d"
val matcher = VarargAnyMatcher<String, Boolean>({ "d" == it }, true, false)
val matcher = VarargAnyMatcher({ "d" == it }, String::class.java, true, false)

/* When */
whenever(t.varargBooleanResult(argThat(matcher))).thenAnswer(matcher)
Expand Down Expand Up @@ -317,18 +326,20 @@ class MatchersTest : TestBase() {
*/
private class VarargAnyMatcher<T, R>(
private val match: ((T) -> Boolean),
private val clazz: Class<T>,
private val success: R,
private val failure: R
) : ArgumentMatcher<T>, Answer<R> {
private var anyMatched = false

override fun matches(t: T): Boolean {
anyMatched = anyMatched or match(t)
return true
@Suppress("UNCHECKED_CAST") // No idea how to solve this better
anyMatched = (t as Array<T>).any(match)
return anyMatched
}

override fun answer(i: InvocationOnMock) = if (anyMatched) success else failure

override fun type(): Class<*> = Any::class.java
override fun type(): Class<*> = java.lang.reflect.Array.newInstance(clazz, 0).javaClass
}
}

0 comments on commit bf2d54e

Please sign in to comment.