• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 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.intentresolver
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  * Cloned from frameworks/base/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
25  */
26 
27 import org.mockito.ArgumentCaptor
28 import org.mockito.ArgumentMatcher
29 import org.mockito.ArgumentMatchers
30 import org.mockito.Mockito
31 import org.mockito.stubbing.OngoingStubbing
32 
33 /**
34  * Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when
35  * null is returned.
36  *
37  * Generic T is nullable because implicitly bounded by Any?.
38  */
eqnull39 fun <T> eq(obj: T): T = Mockito.eq<T>(obj)
40 
41 /**
42  * Returns Mockito.any() as nullable type to avoid java.lang.IllegalStateException when
43  * null is returned.
44  *
45  * Generic T is nullable because implicitly bounded by Any?.
46  */
47 fun <T> any(type: Class<T>): T = Mockito.any<T>(type)
48 inline fun <reified T> any(): T = any(T::class.java)
49 
50 /**
51  * Returns Mockito.argThat() as nullable type to avoid java.lang.IllegalStateException when
52  * null is returned.
53  *
54  * Generic T is nullable because implicitly bounded by Any?.
55  */
56 fun <T> argThat(matcher: ArgumentMatcher<T>): T = Mockito.argThat(matcher)
57 
58 /**
59  * Kotlin type-inferred version of Mockito.nullable()
60  */
61 inline fun <reified T> nullable(): T? = Mockito.nullable(T::class.java)
62 
63 /**
64  * Returns ArgumentCaptor.capture() as nullable type to avoid java.lang.IllegalStateException
65  * when null is returned.
66  *
67  * Generic T is nullable because implicitly bounded by Any?.
68  */
69 fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
70 
71 /**
72  * Helper function for creating an argumentCaptor in kotlin.
73  *
74  * Generic T is nullable because implicitly bounded by Any?.
75  */
76 inline fun <reified T : Any> argumentCaptor(): ArgumentCaptor<T> =
77     ArgumentCaptor.forClass(T::class.java)
78 
79 /**
80  * Helper function for creating new mocks, without the need to pass in a [Class] instance.
81  *
82  * Generic T is nullable because implicitly bounded by Any?.
83  *
84  * @param apply builder function to simplify stub configuration by improving type inference.
85  */
86 inline fun <reified T : Any> mock(apply: T.() -> Unit = {}): T = Mockito.mock(T::class.java)
87     .apply(apply)
88 
89 /**
90  * Helper function for stubbing methods without the need to use backticks.
91  *
92  * @see Mockito.when
93  */
whenevernull94 fun <T> whenever(methodCall: T): OngoingStubbing<T> = Mockito.`when`(methodCall)
95 
96 /**
97  * A kotlin implemented wrapper of [ArgumentCaptor] which prevents the following exception when
98  * kotlin tests are mocking kotlin objects and the methods take non-null parameters:
99  *
100  *     java.lang.NullPointerException: capture() must not be null
101  */
102 class KotlinArgumentCaptor<T> constructor(clazz: Class<T>) {
103     private val wrapped: ArgumentCaptor<T> = ArgumentCaptor.forClass(clazz)
104     fun capture(): T = wrapped.capture()
105     val value: T
106         get() = wrapped.value
107     val allValues: List<T>
108         get() = wrapped.allValues
109 }
110 
111 /**
112  * Helper function for creating an argumentCaptor in kotlin.
113  *
114  * Generic T is nullable because implicitly bounded by Any?.
115  */
kotlinArgumentCaptornull116 inline fun <reified T : Any> kotlinArgumentCaptor(): KotlinArgumentCaptor<T> =
117     KotlinArgumentCaptor(T::class.java)
118 
119 /**
120  * Helper function for creating and using a single-use ArgumentCaptor in kotlin.
121  *
122  *    val captor = argumentCaptor<Foo>()
123  *    verify(...).someMethod(captor.capture())
124  *    val captured = captor.value
125  *
126  * becomes:
127  *
128  *    val captured = withArgCaptor<Foo> { verify(...).someMethod(capture()) }
129  *
130  * NOTE: this uses the KotlinArgumentCaptor to avoid the NullPointerException.
131  */
132 inline fun <reified T : Any> withArgCaptor(block: KotlinArgumentCaptor<T>.() -> Unit): T =
133     kotlinArgumentCaptor<T>().apply { block() }.value
134 
135 /**
136  * Variant of [withArgCaptor] for capturing multiple arguments.
137  *
138  *    val captor = argumentCaptor<Foo>()
139  *    verify(...).someMethod(captor.capture())
140  *    val captured: List<Foo> = captor.allValues
141  *
142  * becomes:
143  *
144  *    val capturedList = captureMany<Foo> { verify(...).someMethod(capture()) }
145  */
captureManynull146 inline fun <reified T : Any> captureMany(block: KotlinArgumentCaptor<T>.() -> Unit): List<T> =
147     kotlinArgumentCaptor<T>().apply{ block() }.allValues
148 
<lambda>null149 inline fun <reified T> anyOrNull() = ArgumentMatchers.argThat(ArgumentMatcher<T?> { true })
150