1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.systemui.util.mockito
18 
19 /**
20  * Kotlin versions of popular mockito methods that can return null in situations when Kotlin expects
21  * a non-null value. Kotlin will throw an IllegalStateException when this takes place ("x must not
22  * be null"). To fix this, we can use methods that modify the return type to be nullable. This
23  * causes Kotlin to skip the null checks.
24  */
25 import kotlin.DeprecationLevel.WARNING
26 import org.mockito.ArgumentCaptor
27 import org.mockito.ArgumentMatcher
28 import org.mockito.MockSettings
29 import org.mockito.Mockito
30 import org.mockito.Mockito.`when`
31 import org.mockito.Mockito.withSettings
32 import org.mockito.stubbing.OngoingStubbing
33 import org.mockito.stubbing.Stubber
34 
35 /**
36  * Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when null is
37  * returned.
38  *
39  * Generic T is nullable because implicitly bounded by Any?.
40  */
41 @Deprecated(
42     "Replace with mockito-kotlin. See http://go/mockito-kotlin",
43     ReplaceWith(expression = "eq", imports = ["org.mockito.kotlin.eq"]),
44     level = WARNING
45 )
eqnull46 fun <T> eq(obj: T): T = Mockito.eq<T>(obj) ?: obj
47 
48 /**
49  * Returns Mockito.any() as nullable type to avoid java.lang.IllegalStateException when null is
50  * returned.
51  *
52  * Generic T is nullable because implicitly bounded by Any?.
53  */
54 @Deprecated(
55     "Replace with mockito-kotlin. See http://go/mockito-kotlin",
56     ReplaceWith(expression = "any(type)", imports = ["org.mockito.kotlin.any"]),
57     level = WARNING
58 )
59 fun <T> any(type: Class<T>): T = Mockito.any<T>(type)
60 
61 @Deprecated(
62     "Replace with mockito-kotlin. See http://go/mockito-kotlin",
63     ReplaceWith(expression = "any()", imports = ["org.mockito.kotlin.any"]),
64     level = WARNING
65 )
66 inline fun <reified T> any(): T = any(T::class.java)
67 
68 /**
69  * Returns Mockito.argThat() as nullable type to avoid java.lang.IllegalStateException when null is
70  * returned.
71  *
72  * Generic T is nullable because implicitly bounded by Any?.
73  */
74 @Deprecated(
75     "Replace with mockito-kotlin. See http://go/mockito-kotlin",
76     ReplaceWith(expression = "argThat(matcher)", imports = ["org.mockito.kotlin.argThat"]),
77     level = WARNING
78 )
79 fun <T> argThat(matcher: ArgumentMatcher<T>): T = Mockito.argThat(matcher)
80 
81 /**
82  * Kotlin type-inferred version of Mockito.nullable()
83  *
84  * @see org.mockito.kotlin.anyOrNull
85  */
86 @Deprecated(
87     "Replace with mockito-kotlin. See http://go/mockito-kotlin",
88     ReplaceWith(expression = "anyOrNull()", imports = ["org.mockito.kotlin.anyOrNull"]),
89     level = WARNING
90 )
91 inline fun <reified T> nullable(): T? = Mockito.nullable(T::class.java)
92 
93 /**
94  * Returns ArgumentCaptor.capture() as nullable type to avoid java.lang.IllegalStateException when
95  * null is returned.
96  *
97  * Generic T is nullable because implicitly bounded by Any?.
98  *
99  * @see org.mockito.kotlin.capture
100  */
101 @Deprecated(
102     "Replace with mockito-kotlin. See http://go/mockito-kotlin",
103     ReplaceWith(expression = "capture(argumentCaptor)", imports = ["org.mockito.kotlin.capture"]),
104     level = WARNING
105 )
106 fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
107 
108 /**
109  * Helper function for creating an argumentCaptor in kotlin.
110  *
111  * Generic T is nullable because implicitly bounded by Any?.
112  *
113  * @see org.mockito.kotlin.argumentCaptor
114  */
115 @Deprecated(
116     "Replace with mockito-kotlin. See http://go/mockito-kotlin",
117     ReplaceWith(expression = "argumentCaptor()", imports = ["org.mockito.kotlin.argumentCaptor"]),
118     level = WARNING
119 )
120 inline fun <reified T : Any> argumentCaptor(): ArgumentCaptor<T> =
121     ArgumentCaptor.forClass(T::class.java)
122 
123 /**
124  * Helper function for creating new mocks, without the need to pass in a [Class] instance.
125  *
126  * Generic T is nullable because implicitly bounded by Any?.
127  *
128  * Updated kotlin-mockito usage:
129  * ```
130  * val value: Widget = mock<> {
131  *    on { status } doReturn "OK"
132  *    on { buttonPress } doNothing
133  *    on { destroy } doAnswer error("Boom!")
134  * }
135  * ```
136  *
137  * __Deprecation note__
138  *
139  * Automatic replacement is not possible due to a change in lambda receiver type to KStubbing<T>
140  *
141  * @param apply builder function to simplify stub configuration by improving type inference.
142  * @see org.mockito.kotlin.mock
143  * @see org.mockito.kotlin.KStubbing.on
144  */
145 @Suppress("DeprecatedCallableAddReplaceWith")
146 @Deprecated("Replace with mockito-kotlin. See http://go/mockito-kotlin", level = WARNING)
147 inline fun <reified T : Any> mock(settings: MockSettings? = null, apply: T.() -> Unit = {}): T =
148     Mockito.mock(T::class.java, settings ?: withSettings()).apply(apply)
149 
150 /**
151  * Helper function for stubbing methods without the need to use backticks.
152  *
153  * Avoid. It is preferable to provide stubbing at creation time using the [mock] lambda argument.
154  *
155  * @see org.mockito.kotlin.whenever
156  */
157 @Deprecated(
158     "Replace with mockito-kotlin. See http://go/mockito-kotlin",
159     ReplaceWith(expression = "whenever(methodCall)", imports = ["org.mockito.kotlin.whenever"]),
160     level = WARNING
161 )
whenevernull162 fun <T> whenever(methodCall: T): OngoingStubbing<T> = `when`(methodCall)
163 
164 /**
165  * __Deprecation note__
166  *
167  * Replace with `KStubbing<T>.on` within [org.mockito.kotlin.mock] { stubbing }
168  *
169  * @see org.mockito.kotlin.mock
170  * @see org.mockito.kotlin.KStubbing.on
171  */
172 @Deprecated(
173     "Replace with mockito-kotlin. See http://go/mockito-kotlin",
174     ReplaceWith(expression = "whenever(mock)", imports = ["org.mockito.kotlin.whenever"]),
175     level = WARNING
176 )
177 fun <T> Stubber.whenever(mock: T): T = `when`(mock)
178 
179 /**
180  * A kotlin implemented wrapper of [ArgumentCaptor] which prevents the following exception when
181  * kotlin tests are mocking kotlin objects and the methods take non-null parameters:
182  *
183  *     java.lang.NullPointerException: capture() must not be null
184  */
185 @Deprecated("Replace with mockito-kotlin. See http://go/mockito-kotlin", level = WARNING)
186 class KotlinArgumentCaptor<T> constructor(clazz: Class<T>) {
187     private val wrapped: ArgumentCaptor<T> = ArgumentCaptor.forClass(clazz)
188     fun capture(): T = wrapped.capture()
189     val value: T
190         get() = wrapped.value
191     val allValues: List<T>
192         get() = wrapped.allValues
193 }
194 
195 /**
196  * Helper function for creating an argumentCaptor in kotlin.
197  *
198  * Generic T is nullable because implicitly bounded by Any?.
199  *
200  * @see org.mockito.kotlin.argumentCaptor
201  */
202 @Deprecated(
203     "Replace with mockito-kotlin. See http://go/mockito-kotlin",
204     ReplaceWith(expression = "argumentCaptor()", imports = ["org.mockito.kotlin.argumentCaptor"]),
205     level = WARNING
206 )
kotlinArgumentCaptornull207 inline fun <reified T : Any> kotlinArgumentCaptor(): KotlinArgumentCaptor<T> =
208     KotlinArgumentCaptor(T::class.java)
209 
210 /**
211  * Helper function for creating and using a single-use ArgumentCaptor in kotlin.
212  *
213  * val captor = argumentCaptor<Foo>() verify(...).someMethod(captor.capture()) val captured =
214  * captor.value
215  *
216  * becomes:
217  *
218  * val captured = withArgCaptor<Foo> { verify(...).someMethod(capture()) }
219  *
220  * NOTE: this uses the KotlinArgumentCaptor to avoid the NullPointerException.
221  */
222 // TODO(359670968): rewrite this to use mockito-kotlin
223 inline fun <reified T : Any> withArgCaptor(block: KotlinArgumentCaptor<T>.() -> Unit): T =
224     kotlinArgumentCaptor<T>().apply { block() }.value
225 
226 /**
227  * Variant of [withArgCaptor] for capturing multiple arguments.
228  *
229  * val captor = argumentCaptor<Foo>() verify(...).someMethod(captor.capture()) val captured:
230  * List<Foo> = captor.allValues
231  *
232  * becomes:
233  *
234  * val capturedList = captureMany<Foo> { verify(...).someMethod(capture()) }
235  *
236  * @see org.mockito.kotlin.verify
237  */
238 @Suppress("DeprecatedCallableAddReplaceWith")
239 @Deprecated("Replace with mockito-kotlin. See http://go/mockito-kotlin", level = WARNING)
captureManynull240 inline fun <reified T : Any> captureMany(block: KotlinArgumentCaptor<T>.() -> Unit): List<T> =
241     kotlinArgumentCaptor<T>().apply { block() }.allValues
242