Skip to content

Commit 2bfc4f7

Browse files
committed
#474 Fix vararg argument matcher
1 parent d92b616 commit 2bfc4f7

3 files changed

Lines changed: 56 additions & 1 deletion

File tree

mockito-kotlin/src/main/kotlin/org/mockito/kotlin/ArgumentCaptor.kt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,18 @@ class KArgumentCaptor<out T : Any?>(
195195

196196
@Suppress("UNCHECKED_CAST")
197197
fun capture(): T {
198-
return captor.capture() ?: createInstance(tClass) as T
198+
// Special handling for arrays to make it work for varargs
199+
// In Kotlin we want have to capture vararg like this `verify(m).methodName(*captor.capture())` to make the types work
200+
// If we return null for array types, the spread `*` operator will fail with NPE
201+
// If we return empty array, it will fail in MatchersBinder.validateMatchers
202+
// In Java, `captor.capture` returns null and so the method is called with `[null]`
203+
// In Kotlin, we have to create `[null]` explicitly.
204+
// This code-path is applied for non-vararg array arguments as well, but it seems to work fine.
205+
return if (tClass.java.isArray) {
206+
captor.capture() ?: java.lang.reflect.Array.newInstance(tClass.java.componentType, 1) as T
207+
} else {
208+
captor.capture() ?: createInstance(tClass) as T
209+
}
199210
}
200211
}
201212

tests/src/test/kotlin/test/ArgumentCaptorTest.kt

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,4 +226,46 @@ class ArgumentCaptorTest : TestBase() {
226226
}
227227
}
228228
}
229+
230+
@Test
231+
fun argumentCaptor_vararg() {
232+
/* Given */
233+
val m: Methods = mock()
234+
235+
/* When */
236+
m.varargBooleanResult("a", "b", "c")
237+
238+
/* Then */
239+
val captor = argumentCaptor<Array<String>>()
240+
verify(m).varargBooleanResult(*captor.capture())
241+
expect(captor.firstValue.toList()).toBe(listOf("a", "b", "c"))
242+
}
243+
244+
@Test
245+
fun argumentCaptor_arg_vararg() {
246+
/* Given */
247+
val m: Methods = mock()
248+
249+
/* When */
250+
m.argAndVararg("first", "a", "b", "c")
251+
252+
/* Then */
253+
val captor = argumentCaptor<Array<String>>()
254+
verify(m).argAndVararg(any(), *captor.capture())
255+
expect(captor.firstValue.toList()).toBe(listOf("a", "b", "c"))
256+
}
257+
258+
@Test
259+
fun argumentCaptor_array() {
260+
/* Given */
261+
val m: Methods = mock()
262+
263+
/* When */
264+
m.stringArray(arrayOf("a", "b", "c"))
265+
266+
/* Then */
267+
val captor = argumentCaptor<Array<String>>()
268+
verify(m).stringArray(captor.capture())
269+
expect(captor.firstValue.toList()).toBe(listOf("a", "b", "c"))
270+
}
229271
}

tests/src/test/kotlin/test/Classes.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ interface Methods {
7070
fun nullableStringResult(): String?
7171
fun builderMethod(): Methods
7272
fun varargBooleanResult(vararg values: String): Boolean
73+
fun stringArray(a: Array<String>)
74+
fun argAndVararg(s: String, vararg a: String)
7375

7476
fun nonDefaultReturnType(): ExtraInterface
7577
}

0 commit comments

Comments
 (0)