1 /*
2 * The MIT License
3 *
4 * Copyright (c) 2018 Niek Haarman
5 * Copyright (c) 2007 Mockito contributors
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
26 package org.mockito.kotlin
27
28 import org.mockito.kotlin.internal.createInstance
29 import org.mockito.ArgumentCaptor
30 import kotlin.reflect.KClass
31
32 /**
33 * Creates a [KArgumentCaptor] for given type.
34 */
argumentCaptornull35 inline fun <reified T : Any> argumentCaptor(): KArgumentCaptor<T> {
36 return KArgumentCaptor(ArgumentCaptor.forClass(T::class.java), T::class)
37 }
38
39 /**
40 * Creates 2 [KArgumentCaptor]s for given types.
41 */
argumentCaptornull42 inline fun <reified A : Any, reified B : Any> argumentCaptor(
43 a: KClass<A> = A::class,
44 b: KClass<B> = B::class
45 ): Pair<KArgumentCaptor<A>, KArgumentCaptor<B>> {
46 return Pair(
47 KArgumentCaptor(ArgumentCaptor.forClass(a.java), a),
48 KArgumentCaptor(ArgumentCaptor.forClass(b.java), b)
49 )
50 }
51
52 /**
53 * Creates 3 [KArgumentCaptor]s for given types.
54 */
argumentCaptornull55 inline fun <reified A : Any, reified B : Any, reified C : Any> argumentCaptor(
56 a: KClass<A> = A::class,
57 b: KClass<B> = B::class,
58 c: KClass<C> = C::class
59 ): Triple<KArgumentCaptor<A>, KArgumentCaptor<B>, KArgumentCaptor<C>> {
60 return Triple(
61 KArgumentCaptor(ArgumentCaptor.forClass(a.java), a),
62 KArgumentCaptor(ArgumentCaptor.forClass(b.java), b),
63 KArgumentCaptor(ArgumentCaptor.forClass(c.java), c)
64 )
65 }
66
67 class ArgumentCaptorHolder4<out A, out B, out C, out D>(
68 val first: A,
69 val second: B,
70 val third: C,
71 val fourth: D
72 ) {
73
component1null74 operator fun component1() = first
75 operator fun component2() = second
76 operator fun component3() = third
77 operator fun component4() = fourth
78 }
79
80 class ArgumentCaptorHolder5<out A, out B, out C, out D, out E>(
81 val first: A,
82 val second: B,
83 val third: C,
84 val fourth: D,
85 val fifth: E
86 ) {
87
88 operator fun component1() = first
89 operator fun component2() = second
90 operator fun component3() = third
91 operator fun component4() = fourth
92 operator fun component5() = fifth
93 }
94
95
96 /**
97 * Creates 4 [KArgumentCaptor]s for given types.
98 */
argumentCaptornull99 inline fun <reified A : Any, reified B : Any, reified C : Any, reified D : Any> argumentCaptor(
100 a: KClass<A> = A::class,
101 b: KClass<B> = B::class,
102 c: KClass<C> = C::class,
103 d: KClass<D> = D::class
104 ): ArgumentCaptorHolder4<KArgumentCaptor<A>, KArgumentCaptor<B>, KArgumentCaptor<C>, KArgumentCaptor<D>> {
105 return ArgumentCaptorHolder4(
106 KArgumentCaptor(ArgumentCaptor.forClass(a.java), a),
107 KArgumentCaptor(ArgumentCaptor.forClass(b.java), b),
108 KArgumentCaptor(ArgumentCaptor.forClass(c.java), c),
109 KArgumentCaptor(ArgumentCaptor.forClass(d.java), d)
110 )
111 }
112
113 /**
114 * Creates 4 [KArgumentCaptor]s for given types.
115 */
argumentCaptornull116 inline fun <reified A : Any, reified B : Any, reified C : Any, reified D : Any, reified E : Any> argumentCaptor(
117 a: KClass<A> = A::class,
118 b: KClass<B> = B::class,
119 c: KClass<C> = C::class,
120 d: KClass<D> = D::class,
121 e: KClass<E> = E::class
122 ): ArgumentCaptorHolder5<KArgumentCaptor<A>, KArgumentCaptor<B>, KArgumentCaptor<C>, KArgumentCaptor<D>, KArgumentCaptor<E>> {
123 return ArgumentCaptorHolder5(
124 KArgumentCaptor(ArgumentCaptor.forClass(a.java), a),
125 KArgumentCaptor(ArgumentCaptor.forClass(b.java), b),
126 KArgumentCaptor(ArgumentCaptor.forClass(c.java), c),
127 KArgumentCaptor(ArgumentCaptor.forClass(d.java), d),
128 KArgumentCaptor(ArgumentCaptor.forClass(e.java), e)
129 )
130 }
131
132 /**
133 * Creates a [KArgumentCaptor] for given type, taking in a lambda to allow fast verification.
134 */
argumentCaptornull135 inline fun <reified T : Any> argumentCaptor(f: KArgumentCaptor<T>.() -> Unit): KArgumentCaptor<T> {
136 return argumentCaptor<T>().apply(f)
137 }
138
139 /**
140 * Creates a [KArgumentCaptor] for given nullable type.
141 */
nullableArgumentCaptornull142 inline fun <reified T : Any> nullableArgumentCaptor(): KArgumentCaptor<T?> {
143 return KArgumentCaptor(ArgumentCaptor.forClass(T::class.java), T::class)
144 }
145
146 /**
147 * Creates a [KArgumentCaptor] for given nullable type, taking in a lambda to allow fast verification.
148 */
nullableArgumentCaptornull149 inline fun <reified T : Any> nullableArgumentCaptor(f: KArgumentCaptor<T?>.() -> Unit): KArgumentCaptor<T?> {
150 return nullableArgumentCaptor<T>().apply(f)
151 }
152
153 /**
154 * Alias for [ArgumentCaptor.capture].
155 */
capturenull156 inline fun <reified T : Any> capture(captor: ArgumentCaptor<T>): T {
157 return captor.capture() ?: createInstance()
158 }
159
160 class KArgumentCaptor<out T : Any?>(
161 private val captor: ArgumentCaptor<T>,
162 private val tClass: KClass<*>
163 ) {
164
165 /**
166 * The first captured value of the argument.
167 * @throws IndexOutOfBoundsException if the value is not available.
168 */
169 val firstValue: T
170 get() = captor.firstValue
171
172 /**
173 * The second captured value of the argument.
174 * @throws IndexOutOfBoundsException if the value is not available.
175 */
176 val secondValue: T
177 get() = captor.secondValue
178
179 /**
180 * The third captured value of the argument.
181 * @throws IndexOutOfBoundsException if the value is not available.
182 */
183 val thirdValue: T
184 get() = captor.thirdValue
185
186 /**
187 * The last captured value of the argument.
188 * @throws IndexOutOfBoundsException if the value is not available.
189 */
190 val lastValue: T
191 get() = captor.lastValue
192
193 val allValues: List<T>
194 get() = captor.allValues
195
196 @Suppress("UNCHECKED_CAST")
capturenull197 fun capture(): T {
198 return captor.capture() ?: createInstance(tClass) as T
199 }
200 }
201
202 val <T> ArgumentCaptor<T>.firstValue: T
203 get() = allValues[0]
204
205 val <T> ArgumentCaptor<T>.secondValue: T
206 get() = allValues[1]
207
208 val <T> ArgumentCaptor<T>.thirdValue: T
209 get() = allValues[2]
210
211 val <T> ArgumentCaptor<T>.lastValue: T
212 get() = allValues.last()
213