diff options
Diffstat (limited to 'mockito-kotlin/src/main/kotlin/org')
13 files changed, 1416 insertions, 0 deletions
diff --git a/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/ArgumentCaptor.kt b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/ArgumentCaptor.kt new file mode 100644 index 0000000..253a58c --- /dev/null +++ b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/ArgumentCaptor.kt @@ -0,0 +1,212 @@ +/* + * The MIT License + * + * Copyright (c) 2018 Niek Haarman + * Copyright (c) 2007 Mockito contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.mockito.kotlin + +import org.mockito.kotlin.internal.createInstance +import org.mockito.ArgumentCaptor +import kotlin.reflect.KClass + +/** + * Creates a [KArgumentCaptor] for given type. + */ +inline fun <reified T : Any> argumentCaptor(): KArgumentCaptor<T> { + return KArgumentCaptor(ArgumentCaptor.forClass(T::class.java), T::class) +} + +/** + * Creates 2 [KArgumentCaptor]s for given types. + */ +inline fun <reified A : Any, reified B : Any> argumentCaptor( + a: KClass<A> = A::class, + b: KClass<B> = B::class +): Pair<KArgumentCaptor<A>, KArgumentCaptor<B>> { + return Pair( + KArgumentCaptor(ArgumentCaptor.forClass(a.java), a), + KArgumentCaptor(ArgumentCaptor.forClass(b.java), b) + ) +} + +/** + * Creates 3 [KArgumentCaptor]s for given types. + */ +inline fun <reified A : Any, reified B : Any, reified C : Any> argumentCaptor( + a: KClass<A> = A::class, + b: KClass<B> = B::class, + c: KClass<C> = C::class +): Triple<KArgumentCaptor<A>, KArgumentCaptor<B>, KArgumentCaptor<C>> { + return Triple( + KArgumentCaptor(ArgumentCaptor.forClass(a.java), a), + KArgumentCaptor(ArgumentCaptor.forClass(b.java), b), + KArgumentCaptor(ArgumentCaptor.forClass(c.java), c) + ) +} + +class ArgumentCaptorHolder4<out A, out B, out C, out D>( + 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 +} + +class ArgumentCaptorHolder5<out A, out B, out C, out D, out E>( + 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 +} + + +/** + * Creates 4 [KArgumentCaptor]s for given types. + */ +inline fun <reified A : Any, reified B : Any, reified C : Any, reified D : Any> argumentCaptor( + a: KClass<A> = A::class, + b: KClass<B> = B::class, + c: KClass<C> = C::class, + d: KClass<D> = D::class +): ArgumentCaptorHolder4<KArgumentCaptor<A>, KArgumentCaptor<B>, KArgumentCaptor<C>, KArgumentCaptor<D>> { + return ArgumentCaptorHolder4( + 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 <reified A : Any, reified B : Any, reified C : Any, reified D : Any, reified E : Any> argumentCaptor( + a: KClass<A> = A::class, + b: KClass<B> = B::class, + c: KClass<C> = C::class, + d: KClass<D> = D::class, + e: KClass<E> = E::class +): ArgumentCaptorHolder5<KArgumentCaptor<A>, KArgumentCaptor<B>, KArgumentCaptor<C>, KArgumentCaptor<D>, KArgumentCaptor<E>> { + return ArgumentCaptorHolder5( + 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. + */ +inline fun <reified T : Any> argumentCaptor(f: KArgumentCaptor<T>.() -> Unit): KArgumentCaptor<T> { + return argumentCaptor<T>().apply(f) +} + +/** + * Creates a [KArgumentCaptor] for given nullable type. + */ +inline fun <reified T : Any> nullableArgumentCaptor(): KArgumentCaptor<T?> { + return KArgumentCaptor(ArgumentCaptor.forClass(T::class.java), T::class) +} + +/** + * Creates a [KArgumentCaptor] for given nullable type, taking in a lambda to allow fast verification. + */ +inline fun <reified T : Any> nullableArgumentCaptor(f: KArgumentCaptor<T?>.() -> Unit): KArgumentCaptor<T?> { + return nullableArgumentCaptor<T>().apply(f) +} + +/** + * Alias for [ArgumentCaptor.capture]. + */ +inline fun <reified T : Any> capture(captor: ArgumentCaptor<T>): T { + return captor.capture() ?: createInstance() +} + +class KArgumentCaptor<out T : Any?>( + private val captor: ArgumentCaptor<T>, + private val tClass: KClass<*> +) { + + /** + * The first captured value of the argument. + * @throws IndexOutOfBoundsException if the value is not available. + */ + val firstValue: T + get() = captor.firstValue + + /** + * The second captured value of the argument. + * @throws IndexOutOfBoundsException if the value is not available. + */ + val secondValue: T + get() = captor.secondValue + + /** + * The third captured value of the argument. + * @throws IndexOutOfBoundsException if the value is not available. + */ + val thirdValue: T + get() = captor.thirdValue + + /** + * The last captured value of the argument. + * @throws IndexOutOfBoundsException if the value is not available. + */ + val lastValue: T + get() = captor.lastValue + + val allValues: List<T> + get() = captor.allValues + + @Suppress("UNCHECKED_CAST") + fun capture(): T { + return captor.capture() ?: createInstance(tClass) as T + } +} + +val <T> ArgumentCaptor<T>.firstValue: T + get() = allValues[0] + +val <T> ArgumentCaptor<T>.secondValue: T + get() = allValues[1] + +val <T> ArgumentCaptor<T>.thirdValue: T + get() = allValues[2] + +val <T> ArgumentCaptor<T>.lastValue: T + get() = allValues.last() diff --git a/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/BDDMockito.kt b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/BDDMockito.kt new file mode 100644 index 0000000..867f4c1 --- /dev/null +++ b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/BDDMockito.kt @@ -0,0 +1,81 @@ +/* + * The MIT License + * + * Copyright (c) 2018 Niek Haarman + * Copyright (c) 2007 Mockito contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.mockito.kotlin + +import org.mockito.BDDMockito +import org.mockito.BDDMockito.BDDMyOngoingStubbing +import org.mockito.invocation.InvocationOnMock +import org.mockito.stubbing.Answer + +/** + * Alias for [BDDMockito.given]. + */ +fun <T> given(methodCall: T): BDDMockito.BDDMyOngoingStubbing<T> { + return BDDMockito.given(methodCall) +} + +/** + * Alias for [BDDMockito.given] with a lambda. + */ +fun <T> given(methodCall: () -> T): BDDMyOngoingStubbing<T> { + return given(methodCall()) +} + +/** + * Alias for [BDDMockito.then]. + */ +fun <T> then(mock: T): BDDMockito.Then<T> { + return BDDMockito.then(mock) +} + +/** + * Alias for [BDDMyOngoingStubbing.will] + * */ +infix fun <T> BDDMyOngoingStubbing<T>.will(value: Answer<T>): BDDMockito.BDDMyOngoingStubbing<T> { + return will(value) +} + +/** + * Alias for [BBDMyOngoingStubbing.willAnswer], accepting a lambda. + */ +infix fun <T> BDDMyOngoingStubbing<T>.willAnswer(value: (InvocationOnMock) -> T?): BDDMockito.BDDMyOngoingStubbing<T> { + return willAnswer { value(it) } +} + +/** + * Alias for [BBDMyOngoingStubbing.willReturn]. + */ +infix fun <T> BDDMyOngoingStubbing<T>.willReturn(value: () -> T): BDDMockito.BDDMyOngoingStubbing<T> { + return willReturn(value()) +} + +/** + * Alias for [BBDMyOngoingStubbing.willThrow]. + */ +infix fun <T> BDDMyOngoingStubbing<T>.willThrow(value: () -> Throwable): BDDMockito.BDDMyOngoingStubbing<T> { + return willThrow(value()) +} + diff --git a/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/KStubbing.kt b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/KStubbing.kt new file mode 100644 index 0000000..bbf36bf --- /dev/null +++ b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/KStubbing.kt @@ -0,0 +1,84 @@ +/* + * The MIT License + * + * Copyright (c) 2018 Niek Haarman + * Copyright (c) 2007 Mockito contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.mockito.kotlin + +import org.mockito.kotlin.internal.createInstance +import kotlinx.coroutines.runBlocking +import org.mockito.Mockito +import org.mockito.stubbing.OngoingStubbing +import kotlin.reflect.KClass + + +inline fun <T> stubbing( + mock: T, + stubbing: KStubbing<T>.(T) -> Unit +) { + KStubbing(mock).stubbing(mock) +} + +inline fun <T : Any> T.stub(stubbing: KStubbing<T>.(T) -> Unit): T { + return apply { KStubbing(this).stubbing(this) } +} + +class KStubbing<out T>(val mock: T) { + + fun <R> on(methodCall: R): OngoingStubbing<R> = Mockito.`when`(methodCall) + + fun <R : Any> onGeneric(methodCall: T.() -> R?, c: KClass<R>): OngoingStubbing<R> { + val r = try { + mock.methodCall() + } catch (e: NullPointerException) { + // An NPE may be thrown by the Kotlin type system when the MockMethodInterceptor returns a + // null value for a non-nullable generic type. + // We catch this NPE to return a valid instance. + // The Mockito state has already been modified at this point to reflect + // the wanted changes. + createInstance(c) + } + return Mockito.`when`(r) + } + + inline fun <reified R : Any> onGeneric(noinline methodCall: T.() -> R?): OngoingStubbing<R> { + return onGeneric(methodCall, R::class) + } + + fun <R> on(methodCall: T.() -> R): OngoingStubbing<R> { + return try { + Mockito.`when`(mock.methodCall()) + } catch (e: NullPointerException) { + throw MockitoKotlinException( + "NullPointerException thrown when stubbing.\nThis may be due to two reasons:\n\t- The method you're trying to stub threw an NPE: look at the stack trace below;\n\t- You're trying to stub a generic method: try `onGeneric` instead.", + e + ) + } + } + + fun <T : Any, R> KStubbing<T>.onBlocking( + m: suspend T.() -> R + ): OngoingStubbing<R> { + return runBlocking { Mockito.`when`(mock.m()) } + } +}
\ No newline at end of file diff --git a/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Matchers.kt b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Matchers.kt new file mode 100644 index 0000000..a17da95 --- /dev/null +++ b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Matchers.kt @@ -0,0 +1,139 @@ +/* + * The MIT License + * + * Copyright (c) 2018 Niek Haarman + * Copyright (c) 2007 Mockito contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.mockito.kotlin + +import org.mockito.kotlin.internal.createInstance +import org.mockito.ArgumentMatcher +import org.mockito.Mockito + +/** Object argument that is equal to the given value. */ +fun <T> eq(value: T): T { + return Mockito.eq(value) ?: value +} + +/** Object argument that is the same as the given value. */ +fun <T> same(value: T): T { + return Mockito.same(value) ?: value +} + +/** Matches any object, excluding nulls. */ +inline fun <reified T : Any> any(): T { + return Mockito.any(T::class.java) ?: createInstance() +} + +/** Matches anything, including nulls. */ +inline fun <reified T : Any> anyOrNull(): T { + return Mockito.any<T>() ?: createInstance() +} + +/** Matches any vararg object, including nulls. */ +inline fun <reified T : Any> anyVararg(): T { + return Mockito.any<T>() ?: createInstance() +} + +/** Matches any array of type T. */ +inline fun <reified T : Any?> anyArray(): Array<T> { + return Mockito.any(Array<T>::class.java) ?: arrayOf() +} + +/** + * Creates a custom argument matcher. + * `null` values will never evaluate to `true`. + * + * @param predicate An extension function on [T] that returns `true` when a [T] matches the predicate. + */ +inline fun <reified T : Any> argThat(noinline predicate: T.() -> Boolean): T { + return Mockito.argThat { arg: T? -> arg?.predicate() ?: false } ?: createInstance( + T::class + ) +} + +/** + * Registers a custom ArgumentMatcher. The original Mockito function registers the matcher and returns null, + * here the required type is returned. + * + * @param matcher The ArgumentMatcher on [T] to be registered. + */ +inline fun <reified T : Any> argThat(matcher: ArgumentMatcher<T>): T { + return Mockito.argThat(matcher) ?: createInstance() +} + +/** + * Alias for [argThat]. + * + * Creates a custom argument matcher. + * `null` values will never evaluate to `true`. + * + * @param predicate An extension function on [T] that returns `true` when a [T] matches the predicate. + */ +inline fun <reified T : Any> argForWhich(noinline predicate: T.() -> Boolean): T { + return argThat(predicate) +} + +/** + * Creates a custom argument matcher. + * `null` values will never evaluate to `true`. + * + * @param predicate A function that returns `true` when given [T] matches the predicate. + */ +inline fun <reified T : Any> argWhere(noinline predicate: (T) -> Boolean): T { + return argThat(predicate) +} + +/** + * Argument that implements the given class. + */ +inline fun <reified T : Any> isA(): T { + return Mockito.isA(T::class.java) ?: createInstance() +} + +/** + * `null` argument. + */ +fun <T : Any> isNull(): T? = Mockito.isNull() + +/** + * Not `null` argument. + */ +fun <T : Any> isNotNull(): T? { + return Mockito.isNotNull() +} + +/** + * Not `null` argument. + */ +fun <T : Any> notNull(): T? { + return Mockito.notNull() +} + +/** + * Object argument that is reflection-equal to the given value with support for excluding + * selected fields from a class. + */ +inline fun <reified T : Any> refEq(value: T, vararg excludeFields: String): T { + return Mockito.refEq<T>(value, *excludeFields) ?: createInstance() +} + diff --git a/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Mocking.kt b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Mocking.kt new file mode 100644 index 0000000..9f6acd2 --- /dev/null +++ b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Mocking.kt @@ -0,0 +1,211 @@ +/* + * The MIT License + * + * Copyright (c) 2018 Niek Haarman + * Copyright (c) 2007 Mockito contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.mockito.kotlin + +import org.mockito.Incubating +import org.mockito.MockSettings +import org.mockito.Mockito +import org.mockito.listeners.InvocationListener +import org.mockito.mock.SerializableMode +import org.mockito.stubbing.Answer +import kotlin.DeprecationLevel.ERROR +import kotlin.reflect.KClass + +/** + * Creates a mock for [T]. + * + * @param extraInterfaces Specifies extra interfaces the mock should implement. + * @param name Specifies mock name. Naming mocks can be helpful for debugging - the name is used in all verification errors. + * @param spiedInstance Specifies the instance to spy on. Makes sense only for spies/partial mocks. + * @param defaultAnswer Specifies default answers to interactions. + * @param serializable Configures the mock to be serializable. + * @param serializableMode Configures the mock to be serializable with a specific serializable mode. + * @param verboseLogging Enables real-time logging of method invocations on this mock. + * @param invocationListeners Registers a listener for method invocations on this mock. The listener is notified every time a method on this mock is called. + * @param stubOnly A stub-only mock does not record method invocations, thus saving memory but disallowing verification of invocations. + * @param useConstructor Mockito attempts to use constructor when creating instance of the mock. + * @param outerInstance Makes it possible to mock non-static inner classes in conjunction with [useConstructor]. + * @param lenient Lenient mocks bypass "strict stubbing" validation. + */ +inline fun <reified T : Any> mock( + extraInterfaces: Array<out KClass<out Any>>? = null, + name: String? = null, + spiedInstance: Any? = null, + defaultAnswer: Answer<Any>? = null, + serializable: Boolean = false, + serializableMode: SerializableMode? = null, + verboseLogging: Boolean = false, + invocationListeners: Array<InvocationListener>? = null, + stubOnly: Boolean = false, + @Incubating useConstructor: UseConstructor? = null, + @Incubating outerInstance: Any? = null, + @Incubating lenient: Boolean = false +): T { + return Mockito.mock( + T::class.java, + withSettings( + extraInterfaces = extraInterfaces, + name = name, + spiedInstance = spiedInstance, + defaultAnswer = defaultAnswer, + serializable = serializable, + serializableMode = serializableMode, + verboseLogging = verboseLogging, + invocationListeners = invocationListeners, + stubOnly = stubOnly, + useConstructor = useConstructor, + outerInstance = outerInstance, + lenient = lenient + ) + )!! +} + +/** + * Creates a mock for [T], allowing for immediate stubbing. + * + * @param extraInterfaces Specifies extra interfaces the mock should implement. + * @param name Specifies mock name. Naming mocks can be helpful for debugging - the name is used in all verification errors. + * @param spiedInstance Specifies the instance to spy on. Makes sense only for spies/partial mocks. + * @param defaultAnswer Specifies default answers to interactions. + * @param serializable Configures the mock to be serializable. + * @param serializableMode Configures the mock to be serializable with a specific serializable mode. + * @param verboseLogging Enables real-time logging of method invocations on this mock. + * @param invocationListeners Registers a listener for method invocations on this mock. The listener is notified every time a method on this mock is called. + * @param stubOnly A stub-only mock does not record method invocations, thus saving memory but disallowing verification of invocations. + * @param useConstructor Mockito attempts to use constructor when creating instance of the mock. + * @param outerInstance Makes it possible to mock non-static inner classes in conjunction with [useConstructor]. + * @param lenient Lenient mocks bypass "strict stubbing" validation. + */ +inline fun <reified T : Any> mock( + extraInterfaces: Array<out KClass<out Any>>? = null, + name: String? = null, + spiedInstance: Any? = null, + defaultAnswer: Answer<Any>? = null, + serializable: Boolean = false, + serializableMode: SerializableMode? = null, + verboseLogging: Boolean = false, + invocationListeners: Array<InvocationListener>? = null, + stubOnly: Boolean = false, + @Incubating useConstructor: UseConstructor? = null, + @Incubating outerInstance: Any? = null, + @Incubating lenient: Boolean = false, + stubbing: KStubbing<T>.(T) -> Unit +): T { + return Mockito.mock( + T::class.java, + withSettings( + extraInterfaces = extraInterfaces, + name = name, + spiedInstance = spiedInstance, + defaultAnswer = defaultAnswer, + serializable = serializable, + serializableMode = serializableMode, + verboseLogging = verboseLogging, + invocationListeners = invocationListeners, + stubOnly = stubOnly, + useConstructor = useConstructor, + outerInstance = outerInstance, + lenient = lenient + ) + ).apply { KStubbing(this).stubbing(this) }!! +} + +/** + * Allows mock creation with additional mock settings. + * See [MockSettings]. + * + * @param extraInterfaces Specifies extra interfaces the mock should implement. + * @param name Specifies mock name. Naming mocks can be helpful for debugging - the name is used in all verification errors. + * @param spiedInstance Specifies the instance to spy on. Makes sense only for spies/partial mocks. + * @param defaultAnswer Specifies default answers to interactions. + * @param serializable Configures the mock to be serializable. + * @param serializableMode Configures the mock to be serializable with a specific serializable mode. + * @param verboseLogging Enables real-time logging of method invocations on this mock. + * @param invocationListeners Registers a listener for method invocations on this mock. The listener is notified every time a method on this mock is called. + * @param stubOnly A stub-only mock does not record method invocations, thus saving memory but disallowing verification of invocations. + * @param useConstructor Mockito attempts to use constructor when creating instance of the mock. + * @param outerInstance Makes it possible to mock non-static inner classes in conjunction with [useConstructor]. + * @param lenient Lenient mocks bypass "strict stubbing" validation. + */ +fun withSettings( + extraInterfaces: Array<out KClass<out Any>>? = null, + name: String? = null, + spiedInstance: Any? = null, + defaultAnswer: Answer<Any>? = null, + serializable: Boolean = false, + serializableMode: SerializableMode? = null, + verboseLogging: Boolean = false, + invocationListeners: Array<InvocationListener>? = null, + stubOnly: Boolean = false, + @Incubating useConstructor: UseConstructor? = null, + @Incubating outerInstance: Any? = null, + @Incubating lenient: Boolean = false +): MockSettings = Mockito.withSettings().apply { + extraInterfaces?.let { extraInterfaces(*it.map { it.java }.toTypedArray()) } + name?.let { name(it) } + spiedInstance?.let { spiedInstance(it) } + defaultAnswer?.let { defaultAnswer(it) } + if (serializable) serializable() + serializableMode?.let { serializable(it) } + if (verboseLogging) verboseLogging() + invocationListeners?.let { invocationListeners(*it) } + if (stubOnly) stubOnly() + useConstructor?.let { useConstructor(*it.args) } + outerInstance?.let { outerInstance(it) } + if (lenient) lenient() +} + +class UseConstructor private constructor(val args: Array<Any>) { + + companion object { + + /** Invokes the parameterless constructor. */ + fun parameterless() = UseConstructor(emptyArray()) + + /** Invokes a constructor with given arguments. */ + fun withArguments(vararg arguments: Any): UseConstructor { + return UseConstructor(arguments.asList().toTypedArray()) + } + } +} + +@Deprecated( + "Use mock() with optional arguments instead.", + ReplaceWith("mock<T>(defaultAnswer = a)"), + level = ERROR +) +inline fun <reified T : Any> mock(a: Answer<Any>): T = mock(defaultAnswer = a) + +@Deprecated( + "Use mock() with optional arguments instead.", + ReplaceWith("mock<T>(name = s)"), + level = ERROR +) +inline fun <reified T : Any> mock(s: String): T = mock(name = s) + +@Suppress("DeprecatedCallableAddReplaceWith") +@Deprecated("Use mock() with optional arguments instead.", level = ERROR) +inline fun <reified T : Any> mock(s: MockSettings): T = Mockito.mock(T::class.java, s)!!
\ No newline at end of file diff --git a/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Mockito.kt b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Mockito.kt new file mode 100644 index 0000000..0f80e0c --- /dev/null +++ b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Mockito.kt @@ -0,0 +1,41 @@ +/* + * The MIT License + * + * Copyright (c) 2018 Niek Haarman + * Copyright (c) 2007 Mockito contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.mockito.kotlin + +import org.mockito.MockingDetails +import org.mockito.Mockito + +fun validateMockitoUsage() { + Mockito.validateMockitoUsage() +} + +fun <T> reset(vararg mocks: T) { + Mockito.reset(*mocks) +} + +fun mockingDetails(toInspect: Any): MockingDetails { + return Mockito.mockingDetails(toInspect)!! +}
\ No newline at end of file diff --git a/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/MockitoKotlinException.kt b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/MockitoKotlinException.kt new file mode 100644 index 0000000..3e209ae --- /dev/null +++ b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/MockitoKotlinException.kt @@ -0,0 +1,28 @@ +/* + * The MIT License + * + * Copyright (c) 2018 Niek Haarman + * Copyright (c) 2007 Mockito contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.mockito.kotlin + +class MockitoKotlinException(message: String?, cause: Throwable?) : RuntimeException(message, cause) diff --git a/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/OngoingStubbing.kt b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/OngoingStubbing.kt new file mode 100644 index 0000000..3d97ce1 --- /dev/null +++ b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/OngoingStubbing.kt @@ -0,0 +1,126 @@ +/* + * The MIT License + * + * Copyright (c) 2018 Niek Haarman + * Copyright (c) 2007 Mockito contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.mockito.kotlin + +import org.mockito.Mockito +import org.mockito.invocation.InvocationOnMock +import org.mockito.stubbing.Answer +import org.mockito.stubbing.OngoingStubbing +import kotlin.DeprecationLevel.ERROR +import kotlin.reflect.KClass + + +/** + * Enables stubbing methods. Use it when you want the mock to return particular value when particular method is called. + * + * Alias for [Mockito.when]. + */ +@Suppress("NOTHING_TO_INLINE") +inline fun <T> whenever(methodCall: T): OngoingStubbing<T> { + return Mockito.`when`(methodCall)!! +} + +/** + * Sets a return value to be returned when the method is called. + * + * Alias for [OngoingStubbing.thenReturn]. + */ +infix fun <T> OngoingStubbing<T>.doReturn(t: T): OngoingStubbing<T> { + return thenReturn(t) +} + +/** + * Sets consecutive return values to be returned when the method is called. + * + * Alias for [OngoingStubbing.thenReturn]. + */ +fun <T> OngoingStubbing<T>.doReturn(t: T, vararg ts: T): OngoingStubbing<T> { + return thenReturn(t, *ts) +} + +/** + * Sets consecutive return values to be returned when the method is called. + */ +inline infix fun <reified T> OngoingStubbing<T>.doReturnConsecutively(ts: List<T>): OngoingStubbing<T> { + return thenReturn( + ts[0], + *ts.drop(1).toTypedArray() + ) +} + +/** + * Sets Throwable objects to be thrown when the method is called. + * + * Alias for [OngoingStubbing.thenThrow]. + */ +infix fun <T> OngoingStubbing<T>.doThrow(t: Throwable): OngoingStubbing<T> { + return thenThrow(t) +} + +/** + * Sets Throwable objects to be thrown when the method is called. + * + * Alias for [OngoingStubbing.doThrow]. + */ +fun <T> OngoingStubbing<T>.doThrow( + t: Throwable, + vararg ts: Throwable +): OngoingStubbing<T> { + return thenThrow(t, *ts) +} + +/** + * Sets a Throwable type to be thrown when the method is called. + */ +infix fun <T> OngoingStubbing<T>.doThrow(t: KClass<out Throwable>): OngoingStubbing<T> { + return thenThrow(t.java) +} + +/** + * Sets Throwable classes to be thrown when the method is called. + */ +fun <T> OngoingStubbing<T>.doThrow( + t: KClass<out Throwable>, + vararg ts: KClass<out Throwable> +): OngoingStubbing<T> { + return thenThrow(t.java, *ts.map { it.java }.toTypedArray()) +} + +/** + * Sets a generic Answer for the method. + * + * Alias for [OngoingStubbing.thenAnswer]. + */ +infix fun <T> OngoingStubbing<T>.doAnswer(answer: Answer<*>): OngoingStubbing<T> { + return thenAnswer(answer) +} + +/** + * Sets a generic Answer for the method using a lambda. + */ +infix fun <T> OngoingStubbing<T>.doAnswer(answer: (InvocationOnMock) -> T?): OngoingStubbing<T> { + return thenAnswer(answer) +} diff --git a/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Spying.kt b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Spying.kt new file mode 100644 index 0000000..55fa9c0 --- /dev/null +++ b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Spying.kt @@ -0,0 +1,62 @@ +/* + * The MIT License + * + * Copyright (c) 2018 Niek Haarman + * Copyright (c) 2007 Mockito contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.mockito.kotlin + +import org.mockito.Mockito + + +/** + * Creates a spy of the real object. + * The spy calls <b>real</b> methods unless they are stubbed. + */ +inline fun <reified T : Any> spy(): T { + return Mockito.spy(T::class.java)!! +} + +/** + * Creates a spy of the real object, allowing for immediate stubbing. + * The spy calls <b>real</b> methods unless they are stubbed. + */ +inline fun <reified T : Any> spy(stubbing: KStubbing<T>.(T) -> Unit): T { + return Mockito.spy(T::class.java) + .apply { KStubbing(this).stubbing(this) }!! +} + +/** + * Creates a spy of the real object. The spy calls <b>real</b> methods unless they are stubbed. + */ +fun <T> spy(value: T): T { + return Mockito.spy(value)!! +} + +/** + * Creates a spy of the real object, allowing for immediate stubbing. + * The spy calls <b>real</b> methods unless they are stubbed. + */ +inline fun <reified T> spy(value: T, stubbing: KStubbing<T>.(T) -> Unit): T { + return spy(value) + .apply { KStubbing(this).stubbing(this) }!! +}
\ No newline at end of file diff --git a/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Stubber.kt b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Stubber.kt new file mode 100644 index 0000000..fb417fc --- /dev/null +++ b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Stubber.kt @@ -0,0 +1,65 @@ +/* + * The MIT License + * + * Copyright (c) 2018 Niek Haarman + * Copyright (c) 2007 Mockito contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.mockito.kotlin + +import org.mockito.Mockito +import org.mockito.invocation.InvocationOnMock +import org.mockito.stubbing.Stubber +import kotlin.reflect.KClass + + +fun <T> doAnswer(answer: (InvocationOnMock) -> T?): Stubber { + return Mockito.doAnswer { answer(it) }!! +} + +fun doCallRealMethod(): Stubber { + return Mockito.doCallRealMethod()!! +} + +fun doNothing(): Stubber { + return Mockito.doNothing()!! +} + +fun doReturn(value: Any?): Stubber { + return Mockito.doReturn(value)!! +} + +fun doReturn(toBeReturned: Any?, vararg toBeReturnedNext: Any?): Stubber { + return Mockito.doReturn( + toBeReturned, + *toBeReturnedNext + )!! +} + +fun doThrow(toBeThrown: KClass<out Throwable>): Stubber { + return Mockito.doThrow(toBeThrown.java)!! +} + +fun doThrow(vararg toBeThrown: Throwable): Stubber { + return Mockito.doThrow(*toBeThrown)!! +} + +fun <T> Stubber.whenever(mock: T) = `when`(mock)
\ No newline at end of file diff --git a/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Verification.kt b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Verification.kt new file mode 100644 index 0000000..e79dd92 --- /dev/null +++ b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/Verification.kt @@ -0,0 +1,263 @@ +/* + * The MIT License + * + * Copyright (c) 2018 Niek Haarman + * Copyright (c) 2007 Mockito contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.mockito.kotlin + +import org.mockito.kotlin.internal.createInstance +import kotlinx.coroutines.runBlocking +import org.mockito.InOrder +import org.mockito.Mockito +import org.mockito.verification.VerificationAfterDelay +import org.mockito.verification.VerificationMode +import org.mockito.verification.VerificationWithTimeout + +/** + * Verifies certain behavior <b>happened once</b>. + * + * Alias for [Mockito.verify]. + */ +fun <T> verify(mock: T): T { + return Mockito.verify(mock)!! +} + +/** + * Verifies certain suspending behavior <b>happened once</b>. + * + * Warning: Only one method call can be verified in the function. + * Subsequent method calls are ignored! + */ +fun <T> verifyBlocking(mock: T, f: suspend T.() -> Unit) { + val m = Mockito.verify(mock) + runBlocking { m.f() } +} + +/** + * Verifies certain behavior happened at least once / exact number of times / never. + * + * Warning: Only one method call can be verified in the function. + * Subsequent method calls are ignored! + */ +fun <T> verifyBlocking(mock: T, mode: VerificationMode, f: suspend T.() -> Unit) { + val m = Mockito.verify(mock, mode) + runBlocking { m.f() } +} +/** + * Verifies certain behavior happened at least once / exact number of times / never. + * + * Alias for [Mockito.verify]. + */ +fun <T> verify(mock: T, mode: VerificationMode): T { + return Mockito.verify(mock, mode)!! +} + +/** + * Checks if any of given mocks has any unverified interaction. + * + * Alias for [Mockito.verifyNoMoreInteractions]. + */ +fun <T> verifyNoMoreInteractions(vararg mocks: T) { + Mockito.verifyNoMoreInteractions(*mocks) +} + +/** + * Verifies that no interactions happened on given mocks beyond the previously verified interactions. + * + * Alias for [Mockito.verifyZeroInteractions]. + */ +fun verifyZeroInteractions(vararg mocks: Any) { + Mockito.verifyZeroInteractions(*mocks) +} + +/** + * Allows verifying exact number of invocations. + * + * Alias for [Mockito.times]. + */ +fun times(numInvocations: Int): VerificationMode { + return Mockito.times(numInvocations)!! +} + +/** + * Allows at-least-x verification. + * + * Alias for [Mockito.atLeast]. + */ +fun atLeast(numInvocations: Int): VerificationMode { + return Mockito.atLeast(numInvocations)!! +} + +/** + * Allows at-least-once verification. + * + * Alias for [Mockito.atLeastOnce]. + */ +fun atLeastOnce(): VerificationMode { + return Mockito.atLeastOnce()!! +} + +/** + * Allows at-most-x verification. + * + * Alias for [Mockito.atMost]. + */ +fun atMost(maxNumberOfInvocations: Int): VerificationMode { + return Mockito.atMost(maxNumberOfInvocations)!! +} + +/** + * Allows non-greedy verification in order. + * + * Alias for [Mockito.calls]. + */ +fun calls(wantedNumberOfInvocations: Int): VerificationMode { + return Mockito.calls(wantedNumberOfInvocations)!! +} + +/** + * Alias for [times] with parameter `0`. + */ +fun never(): VerificationMode { + return Mockito.never()!! +} + +/** + * Use this method in order to only clear invocations, when stubbing is non-trivial. + * + * Alias for [Mockito.clearInvocations]. + */ +fun <T> clearInvocations(vararg mocks: T) { + Mockito.clearInvocations(*mocks) +} + +/** + * Adds a description to be printed if verification fails. + * + * Alias for [Mockito.description]. + */ +fun description(description: String): VerificationMode { + return Mockito.description(description) +} + +/** + * Allows verifying over a given period. It causes a verify to wait for a specified period of time for a desired + * interaction rather than failing immediately if has not already happened. May be useful for testing in concurrent + * conditions. + */ +fun after(millis: Long): VerificationAfterDelay { + return Mockito.after(millis)!! +} + +/** + * Allows verifying with timeout. It causes a verify to wait for a specified period of time for a desired + * interaction rather than fails immediately if has not already happened. May be useful for testing in concurrent + * conditions. + */ +fun timeout(millis: Long): VerificationWithTimeout { + return Mockito.timeout(millis)!! +} + +/** + * Ignores stubbed methods of given mocks for the sake of verification. + * + * Alias for [Mockito.ignoreStubs]. + */ +fun ignoreStubs(vararg mocks: Any): Array<out Any> { + return Mockito.ignoreStubs(*mocks)!! +} + +/** + * Creates [InOrder] object that allows verifying mocks in order. + * + * Alias for [Mockito.inOrder]. + */ +fun inOrder(vararg mocks: Any): InOrder { + return Mockito.inOrder(*mocks)!! +} + +/** + * Creates [InOrder] object that allows verifying mocks in order. + * Accepts a lambda to allow easy evaluation. + * + * Alias for [Mockito.inOrder]. + */ +inline fun inOrder( + vararg mocks: Any, + evaluation: InOrder.() -> Unit +) { + Mockito.inOrder(*mocks).evaluation() +} + +/** + * Allows [InOrder] verification for a single mocked instance: + * + * mock.inOrder { + * verify().foo() + * } + * + */ +inline fun <T> T.inOrder(block: InOrderOnType<T>.() -> Any) { + block.invoke(InOrderOnType(this)) +} + +class InOrderOnType<T>(private val t: T) : InOrder by inOrder(t as Any) { + + fun verify(): T = verify(t) +} + +/** + * Allows checking if given method was the only one invoked. + */ +fun only(): VerificationMode { + return Mockito.only()!! +} + + +/** + * For usage with verification only. + * + * For example: + * verify(myObject).doSomething(check { assertThat(it, is("Test")) }) + * + * @param predicate A function that performs actions to verify an argument [T]. + */ +inline fun <reified T : Any> check(noinline predicate: (T) -> Unit): T { + return Mockito.argThat { arg: T? -> + if (arg == null) error( + """The argument passed to the predicate was null. + +If you are trying to verify an argument to be null, use `isNull()`. +If you are using `check` as part of a stubbing, use `argThat` or `argForWhich` instead. +""".trimIndent() + ) + + try { + predicate(arg) + true + } catch (e: Error) { + e.printStackTrace() + false + } + } ?: createInstance(T::class) +} diff --git a/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/VerifyScope.kt b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/VerifyScope.kt new file mode 100644 index 0000000..72ac6e2 --- /dev/null +++ b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/VerifyScope.kt @@ -0,0 +1,48 @@ +/* + * The MIT License + * + * Copyright (c) 2018 Niek Haarman + * Copyright (c) 2007 Mockito contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.mockito.kotlin + + +/** + * Verify multiple calls on mock + * Supports an easier to read style of + * + * ``` + * verify(mock) { + * 2 * { call() } + * } + * ``` + */ +inline fun <T> verify(mock: T, block: VerifyScope<T>.() -> Unit) { + VerifyScope(mock).block() +} + +class VerifyScope<out T>(val mock: T) { + + operator inline fun Int.times(call: T.() -> Unit) { + verify(mock, org.mockito.kotlin.times(this)).call() + } +}
\ No newline at end of file diff --git a/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/internal/CreateInstance.kt b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/internal/CreateInstance.kt new file mode 100644 index 0000000..59ede91 --- /dev/null +++ b/mockito-kotlin/src/main/kotlin/org/mockito/kotlin/internal/CreateInstance.kt @@ -0,0 +1,56 @@ +/* + * The MIT License + * + * Copyright (c) 2018 Niek Haarman + * Copyright (c) 2007 Mockito contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +package org.mockito.kotlin.internal + +import kotlin.reflect.KClass +import java.lang.reflect.Array as JavaArray + +inline fun <reified T : Any> createInstance(): T { + return when (T::class) { + Boolean::class -> false as T + Byte::class -> 0.toByte() as T + Char::class -> 0.toChar() as T + Short::class -> 0.toShort() as T + Int::class -> 0 as T + Long::class -> 0L as T + Float::class -> 0f as T + Double::class -> 0.0 as T + else -> createInstance(T::class) + } +} + +fun <T : Any> createInstance(kClass: KClass<T>): T { + return castNull() +} + +/** + * Uses a quirk in the bytecode generated by Kotlin + * to cast [null] to a non-null type. + * + * See https://youtrack.jetbrains.com/issue/KT-8135. + */ +@Suppress("UNCHECKED_CAST") +private fun <T> castNull(): T = null as T |