From 5a303f67f56c1931fc851bcf2f73c9545a04887e Mon Sep 17 00:00:00 2001 From: Clint Checketts Date: Fri, 12 Oct 2018 22:03:26 -0600 Subject: [PATCH 1/3] Add argumentCaptor that create many at once for easy destructuring --- .../nhaarman/mockitokotlin2/ArgumentCaptor.kt | 48 ++++++++++++ .../test/kotlin/test/ArgumentCaptorTest.kt | 76 +++++++++++++++++++ 2 files changed, 124 insertions(+) diff --git a/mockito-kotlin/src/main/kotlin/com/nhaarman/mockitokotlin2/ArgumentCaptor.kt b/mockito-kotlin/src/main/kotlin/com/nhaarman/mockitokotlin2/ArgumentCaptor.kt index 9542446f..426eb321 100644 --- a/mockito-kotlin/src/main/kotlin/com/nhaarman/mockitokotlin2/ArgumentCaptor.kt +++ b/mockito-kotlin/src/main/kotlin/com/nhaarman/mockitokotlin2/ArgumentCaptor.kt @@ -36,6 +36,54 @@ inline fun argumentCaptor(): KArgumentCaptor { return KArgumentCaptor(ArgumentCaptor.forClass(T::class.java), T::class) } +/** + * Creates 2 [KArgumentCaptor]s for given types. + */ +inline fun argumentCaptor2(): Pair, KArgumentCaptor> { + return Pair(KArgumentCaptor(ArgumentCaptor.forClass(A::class.java), A::class), + KArgumentCaptor(ArgumentCaptor.forClass(B::class.java), B::class)) +} + +/** + * Creates 3 [KArgumentCaptor]s for given types. + */ +inline fun argumentCaptor3(): Triple, KArgumentCaptor, KArgumentCaptor> { + return Triple( + KArgumentCaptor(ArgumentCaptor.forClass(A::class.java), A::class), + KArgumentCaptor(ArgumentCaptor.forClass(B::class.java), B::class), + KArgumentCaptor(ArgumentCaptor.forClass(C::class.java), C::class)) +} + +data class ArgumentCaptorHolder4( + val first: A, val second: B, val third: C, val fourth: D) +data class ArgumentCaptorHolder5( + val first: A, val second: B, val third: C, val fourth: D, val fifth: E) + + +/** + * Creates 4 [KArgumentCaptor]s for given types. + */ +inline fun argumentCaptor4(): ArgumentCaptorHolder4, KArgumentCaptor, KArgumentCaptor, KArgumentCaptor> { + return ArgumentCaptorHolder4( + KArgumentCaptor(ArgumentCaptor.forClass(A::class.java), A::class), + KArgumentCaptor(ArgumentCaptor.forClass(B::class.java), B::class), + KArgumentCaptor(ArgumentCaptor.forClass(C::class.java), C::class), + KArgumentCaptor(ArgumentCaptor.forClass(D::class.java), D::class)) +} +/** + * Creates 4 [KArgumentCaptor]s for given types. + */ +inline fun argumentCaptor5(): ArgumentCaptorHolder5, KArgumentCaptor, KArgumentCaptor, KArgumentCaptor, KArgumentCaptor> { + return ArgumentCaptorHolder5( + KArgumentCaptor(ArgumentCaptor.forClass(A::class.java), A::class), + KArgumentCaptor(ArgumentCaptor.forClass(B::class.java), B::class), + KArgumentCaptor(ArgumentCaptor.forClass(C::class.java), C::class), + KArgumentCaptor(ArgumentCaptor.forClass(D::class.java), D::class), + KArgumentCaptor(ArgumentCaptor.forClass(E::class.java), E::class)) +} + + + /** * Creates a [KArgumentCaptor] for given type, taking in a lambda to allow fast verification. */ diff --git a/tests/src/test/kotlin/test/ArgumentCaptorTest.kt b/tests/src/test/kotlin/test/ArgumentCaptorTest.kt index b79227b2..6f64f13c 100644 --- a/tests/src/test/kotlin/test/ArgumentCaptorTest.kt +++ b/tests/src/test/kotlin/test/ArgumentCaptorTest.kt @@ -22,6 +22,82 @@ class ArgumentCaptorTest : TestBase() { expect(captor.lastValue).toBe(5L) } + @Test + fun argumentCaptor_destructuring2() { + /* Given */ + val date: Date = mock() + + /* When */ + date.time = 5L + + /* Then */ + val (captor1, captor2) = argumentCaptor2() + verify(date).time = captor1.capture() + verify(date).time = captor2.capture() + expect(captor1.lastValue).toBe(5L) + expect(captor2.lastValue).toBe(5L) + } + + @Test + fun argumentCaptor_destructuring3() { + /* Given */ + val date: Date = mock() + + /* When */ + date.time = 5L + + /* Then */ + val (captor1, captor2, captor3) = argumentCaptor3() + val verifyCaptor:KArgumentCaptor.() ->Unit = { + verify(date).time = capture() + expect(lastValue).toBe(5L) + } + captor1.apply(verifyCaptor) + captor2.apply(verifyCaptor) + captor3.apply(verifyCaptor) + } + + @Test + fun argumentCaptor_destructuring4() { + /* Given */ + val date: Date = mock() + + /* When */ + date.time = 5L + + /* Then */ + val (captor1, captor2, captor3, captor4) = argumentCaptor4() + val verifyCaptor:KArgumentCaptor.() ->Unit = { + verify(date).time = capture() + expect(lastValue).toBe(5L) + } + captor1.apply(verifyCaptor) + captor2.apply(verifyCaptor) + captor3.apply(verifyCaptor) + captor4.apply(verifyCaptor) + } + + @Test + fun argumentCaptor_destructuring5() { + /* Given */ + val date: Date = mock() + + /* When */ + date.time = 5L + + /* Then */ + val (captor1, captor2, captor3, captor4, captor5) = argumentCaptor5() + val verifyCaptor:KArgumentCaptor.() ->Unit = { + verify(date).time = capture() + expect(lastValue).toBe(5L) + } + captor1.apply(verifyCaptor) + captor2.apply(verifyCaptor) + captor3.apply(verifyCaptor) + captor4.apply(verifyCaptor) + captor5.apply(verifyCaptor) + } + @Test fun argumentCaptor_withNullValue_usingNonNullable() { /* Given */ From f4405832a866e7f18cda90796b5c5e593cf68be1 Mon Sep 17 00:00:00 2001 From: Niek Haarman Date: Wed, 19 Jun 2019 20:19:19 +0200 Subject: [PATCH 2/3] Include class parameters to avoid numbers in argumentCaptor signatures --- .../nhaarman/mockitokotlin2/ArgumentCaptor.kt | 69 +++++++++++++------ .../test/kotlin/test/ArgumentCaptorTest.kt | 14 ++-- 2 files changed, 54 insertions(+), 29 deletions(-) diff --git a/mockito-kotlin/src/main/kotlin/com/nhaarman/mockitokotlin2/ArgumentCaptor.kt b/mockito-kotlin/src/main/kotlin/com/nhaarman/mockitokotlin2/ArgumentCaptor.kt index 426eb321..ce069753 100644 --- a/mockito-kotlin/src/main/kotlin/com/nhaarman/mockitokotlin2/ArgumentCaptor.kt +++ b/mockito-kotlin/src/main/kotlin/com/nhaarman/mockitokotlin2/ArgumentCaptor.kt @@ -39,51 +39,76 @@ inline fun argumentCaptor(): KArgumentCaptor { /** * Creates 2 [KArgumentCaptor]s for given types. */ -inline fun argumentCaptor2(): Pair, KArgumentCaptor> { - return Pair(KArgumentCaptor(ArgumentCaptor.forClass(A::class.java), A::class), - KArgumentCaptor(ArgumentCaptor.forClass(B::class.java), B::class)) +inline fun argumentCaptor( + a: KClass = A::class, + b: KClass = B::class +): Pair, KArgumentCaptor> { + return Pair( + KArgumentCaptor(ArgumentCaptor.forClass(a.java), a), + KArgumentCaptor(ArgumentCaptor.forClass(b.java), b) + ) } /** * Creates 3 [KArgumentCaptor]s for given types. */ -inline fun argumentCaptor3(): Triple, KArgumentCaptor, KArgumentCaptor> { +inline fun argumentCaptor( + a: KClass = A::class, + b: KClass = B::class, + c: KClass = C::class +): Triple, KArgumentCaptor, KArgumentCaptor> { return Triple( - KArgumentCaptor(ArgumentCaptor.forClass(A::class.java), A::class), - KArgumentCaptor(ArgumentCaptor.forClass(B::class.java), B::class), - KArgumentCaptor(ArgumentCaptor.forClass(C::class.java), C::class)) + KArgumentCaptor(ArgumentCaptor.forClass(a.java), a), + KArgumentCaptor(ArgumentCaptor.forClass(b.java), b), + KArgumentCaptor(ArgumentCaptor.forClass(c.java), c) + ) } data class ArgumentCaptorHolder4( - val first: A, val second: B, val third: C, val fourth: D) + val first: A, val second: B, val third: C, val fourth: D +) + data class ArgumentCaptorHolder5( - val first: A, val second: B, val third: C, val fourth: D, val fifth: E) + val first: A, val second: B, val third: C, val fourth: D, val fifth: E +) /** * Creates 4 [KArgumentCaptor]s for given types. */ -inline fun argumentCaptor4(): ArgumentCaptorHolder4, KArgumentCaptor, KArgumentCaptor, KArgumentCaptor> { +inline fun argumentCaptor( + a: KClass = A::class, + b: KClass = B::class, + c: KClass = C::class, + d: KClass = D::class +): ArgumentCaptorHolder4, KArgumentCaptor, KArgumentCaptor, KArgumentCaptor> { return ArgumentCaptorHolder4( - KArgumentCaptor(ArgumentCaptor.forClass(A::class.java), A::class), - KArgumentCaptor(ArgumentCaptor.forClass(B::class.java), B::class), - KArgumentCaptor(ArgumentCaptor.forClass(C::class.java), C::class), - KArgumentCaptor(ArgumentCaptor.forClass(D::class.java), D::class)) + KArgumentCaptor(ArgumentCaptor.forClass(a.java), a), + KArgumentCaptor(ArgumentCaptor.forClass(b.java), b), + KArgumentCaptor(ArgumentCaptor.forClass(c.java), c), + KArgumentCaptor(ArgumentCaptor.forClass(d.java), d) + ) } + /** * Creates 4 [KArgumentCaptor]s for given types. */ -inline fun argumentCaptor5(): ArgumentCaptorHolder5, KArgumentCaptor, KArgumentCaptor, KArgumentCaptor, KArgumentCaptor> { +inline fun argumentCaptor( + a: KClass = A::class, + b: KClass = B::class, + c: KClass = C::class, + d: KClass = D::class, + e: KClass = E::class +): ArgumentCaptorHolder5, KArgumentCaptor, KArgumentCaptor, KArgumentCaptor, KArgumentCaptor> { return ArgumentCaptorHolder5( - KArgumentCaptor(ArgumentCaptor.forClass(A::class.java), A::class), - KArgumentCaptor(ArgumentCaptor.forClass(B::class.java), B::class), - KArgumentCaptor(ArgumentCaptor.forClass(C::class.java), C::class), - KArgumentCaptor(ArgumentCaptor.forClass(D::class.java), D::class), - KArgumentCaptor(ArgumentCaptor.forClass(E::class.java), E::class)) + KArgumentCaptor(ArgumentCaptor.forClass(a.java), a), + KArgumentCaptor(ArgumentCaptor.forClass(b.java), b), + KArgumentCaptor(ArgumentCaptor.forClass(c.java), c), + KArgumentCaptor(ArgumentCaptor.forClass(d.java), d), + KArgumentCaptor(ArgumentCaptor.forClass(e.java), e) + ) } - - /** * Creates a [KArgumentCaptor] for given type, taking in a lambda to allow fast verification. */ diff --git a/tests/src/test/kotlin/test/ArgumentCaptorTest.kt b/tests/src/test/kotlin/test/ArgumentCaptorTest.kt index 6f64f13c..10ddb5e0 100644 --- a/tests/src/test/kotlin/test/ArgumentCaptorTest.kt +++ b/tests/src/test/kotlin/test/ArgumentCaptorTest.kt @@ -31,7 +31,7 @@ class ArgumentCaptorTest : TestBase() { date.time = 5L /* Then */ - val (captor1, captor2) = argumentCaptor2() + val (captor1, captor2) = argumentCaptor() verify(date).time = captor1.capture() verify(date).time = captor2.capture() expect(captor1.lastValue).toBe(5L) @@ -47,8 +47,8 @@ class ArgumentCaptorTest : TestBase() { date.time = 5L /* Then */ - val (captor1, captor2, captor3) = argumentCaptor3() - val verifyCaptor:KArgumentCaptor.() ->Unit = { + val (captor1, captor2, captor3) = argumentCaptor() + val verifyCaptor: KArgumentCaptor.() -> Unit = { verify(date).time = capture() expect(lastValue).toBe(5L) } @@ -66,8 +66,8 @@ class ArgumentCaptorTest : TestBase() { date.time = 5L /* Then */ - val (captor1, captor2, captor3, captor4) = argumentCaptor4() - val verifyCaptor:KArgumentCaptor.() ->Unit = { + val (captor1, captor2, captor3, captor4) = argumentCaptor() + val verifyCaptor: KArgumentCaptor.() -> Unit = { verify(date).time = capture() expect(lastValue).toBe(5L) } @@ -86,8 +86,8 @@ class ArgumentCaptorTest : TestBase() { date.time = 5L /* Then */ - val (captor1, captor2, captor3, captor4, captor5) = argumentCaptor5() - val verifyCaptor:KArgumentCaptor.() ->Unit = { + val (captor1, captor2, captor3, captor4, captor5) = argumentCaptor() + val verifyCaptor: KArgumentCaptor.() -> Unit = { verify(date).time = capture() expect(lastValue).toBe(5L) } From 9c90f0fde4fcda8e51c9d92874af49ea2b606837 Mon Sep 17 00:00:00 2001 From: Niek Haarman Date: Wed, 19 Jun 2019 20:23:08 +0200 Subject: [PATCH 3/3] Manually provide component functions for captor holder classes This tightens the public API for these classes. --- .../nhaarman/mockitokotlin2/ArgumentCaptor.kt | 32 +++++++++++++++---- 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/mockito-kotlin/src/main/kotlin/com/nhaarman/mockitokotlin2/ArgumentCaptor.kt b/mockito-kotlin/src/main/kotlin/com/nhaarman/mockitokotlin2/ArgumentCaptor.kt index ce069753..be69337a 100644 --- a/mockito-kotlin/src/main/kotlin/com/nhaarman/mockitokotlin2/ArgumentCaptor.kt +++ b/mockito-kotlin/src/main/kotlin/com/nhaarman/mockitokotlin2/ArgumentCaptor.kt @@ -64,13 +64,33 @@ inline fun argumentCaptor( ) } -data class ArgumentCaptorHolder4( - val first: A, val second: B, val third: C, val fourth: D -) +class ArgumentCaptorHolder4( + val first: A, + val second: B, + val third: C, + val fourth: D +) { + + operator fun component1() = first + operator fun component2() = second + operator fun component3() = third + operator fun component4() = fourth +} -data class ArgumentCaptorHolder5( - val first: A, val second: B, val third: C, val fourth: D, val fifth: E -) +class ArgumentCaptorHolder5( + val first: A, + val second: B, + val third: C, + val fourth: D, + val fifth: E +) { + + operator fun component1() = first + operator fun component2() = second + operator fun component3() = third + operator fun component4() = fourth + operator fun component5() = fifth +} /**