1 package src.com.android.dream.lowlight.utils 2 3 import org.mockito.ArgumentCaptor 4 import org.mockito.ArgumentMatcher 5 import org.mockito.Mockito 6 import org.mockito.Mockito.`when` 7 import org.mockito.stubbing.OngoingStubbing 8 import org.mockito.stubbing.Stubber 9 10 /** 11 * Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when 12 * null is returned. 13 * 14 * Generic T is nullable because implicitly bounded by Any?. 15 */ eqnull16fun <T> eq(obj: T): T = Mockito.eq<T>(obj) 17 18 /** 19 * Returns Mockito.any() as nullable type to avoid java.lang.IllegalStateException when 20 * null is returned. 21 * 22 * Generic T is nullable because implicitly bounded by Any?. 23 */ 24 fun <T> any(type: Class<T>): T = Mockito.any<T>(type) 25 inline fun <reified T> any(): T = any(T::class.java) 26 27 /** 28 * Returns Mockito.argThat() as nullable type to avoid java.lang.IllegalStateException when 29 * null is returned. 30 * 31 * Generic T is nullable because implicitly bounded by Any?. 32 */ 33 fun <T> argThat(matcher: ArgumentMatcher<T>): T = Mockito.argThat(matcher) 34 35 /** 36 * Kotlin type-inferred version of Mockito.nullable() 37 */ 38 inline fun <reified T> nullable(): T? = Mockito.nullable(T::class.java) 39 40 /** 41 * Returns ArgumentCaptor.capture() as nullable type to avoid java.lang.IllegalStateException 42 * when null is returned. 43 * 44 * Generic T is nullable because implicitly bounded by Any?. 45 */ 46 fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture() 47 48 /** 49 * Helper function for creating an argumentCaptor in kotlin. 50 * 51 * Generic T is nullable because implicitly bounded by Any?. 52 */ 53 inline fun <reified T : Any> argumentCaptor(): ArgumentCaptor<T> = 54 ArgumentCaptor.forClass(T::class.java) 55 56 /** 57 * Helper function for creating new mocks, without the need to pass in a [Class] instance. 58 * 59 * Generic T is nullable because implicitly bounded by Any?. 60 * 61 * @param apply builder function to simplify stub configuration by improving type inference. 62 */ 63 inline fun <reified T : Any> mock(apply: T.() -> Unit = {}): T = Mockito.mock(T::class.java) 64 .apply(apply) 65 66 /** 67 * Helper function for stubbing methods without the need to use backticks. 68 * 69 * @see Mockito.when 70 */ whenevernull71fun <T> whenever(methodCall: T): OngoingStubbing<T> = `when`(methodCall) 72 fun <T> Stubber.whenever(mock: T): T = `when`(mock) 73 74 /** 75 * A kotlin implemented wrapper of [ArgumentCaptor] which prevents the following exception when 76 * kotlin tests are mocking kotlin objects and the methods take non-null parameters: 77 * 78 * java.lang.NullPointerException: capture() must not be null 79 */ 80 class KotlinArgumentCaptor<T> constructor(clazz: Class<T>) { 81 private val wrapped: ArgumentCaptor<T> = ArgumentCaptor.forClass(clazz) 82 fun capture(): T = wrapped.capture() 83 val value: T 84 get() = wrapped.value 85 val allValues: List<T> 86 get() = wrapped.allValues 87 } 88 89 /** 90 * Helper function for creating an argumentCaptor in kotlin. 91 * 92 * Generic T is nullable because implicitly bounded by Any?. 93 */ kotlinArgumentCaptornull94inline fun <reified T : Any> kotlinArgumentCaptor(): KotlinArgumentCaptor<T> = 95 KotlinArgumentCaptor(T::class.java) 96 97 /** 98 * Helper function for creating and using a single-use ArgumentCaptor in kotlin. 99 * 100 * val captor = argumentCaptor<Foo>() 101 * verify(...).someMethod(captor.capture()) 102 * val captured = captor.value 103 * 104 * becomes: 105 * 106 * val captured = withArgCaptor<Foo> { verify(...).someMethod(capture()) } 107 * 108 * NOTE: this uses the KotlinArgumentCaptor to avoid the NullPointerException. 109 */ 110 inline fun <reified T : Any> withArgCaptor(block: KotlinArgumentCaptor<T>.() -> Unit): T = 111 kotlinArgumentCaptor<T>().apply { block() }.value 112 113 /** 114 * Variant of [withArgCaptor] for capturing multiple arguments. 115 * 116 * val captor = argumentCaptor<Foo>() 117 * verify(...).someMethod(captor.capture()) 118 * val captured: List<Foo> = captor.allValues 119 * 120 * becomes: 121 * 122 * val capturedList = captureMany<Foo> { verify(...).someMethod(capture()) } 123 */ captureManynull124inline fun <reified T : Any> captureMany(block: KotlinArgumentCaptor<T>.() -> Unit): List<T> = 125 kotlinArgumentCaptor<T>().apply{ block() }.allValues 126