diff --git a/mockito-kotlin/src/main/kotlin/com/nhaarman/mockito_kotlin/Mockito.kt b/mockito-kotlin/src/main/kotlin/com/nhaarman/mockito_kotlin/Mockito.kt index 86b97135..935bed7f 100644 --- a/mockito-kotlin/src/main/kotlin/com/nhaarman/mockito_kotlin/Mockito.kt +++ b/mockito-kotlin/src/main/kotlin/com/nhaarman/mockito_kotlin/Mockito.kt @@ -52,9 +52,39 @@ inline fun anyVararg(): T = Mockito.any() ?: createInstance /** Matches any array of type T. */ inline fun anyArray(): Array = Mockito.any(Array::class.java) ?: arrayOf() -inline fun argThat(noinline predicate: T.() -> Boolean) = Mockito.argThat { it -> (it as T).predicate() } ?: createInstance(T::class) +/** + * 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 argThat(noinline predicate: T.() -> Boolean) = Mockito.argThat { arg -> arg?.predicate() ?: false } ?: createInstance(T::class) + +/** + * 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 argForWhich(noinline predicate: T.() -> Boolean) = argThat(predicate) -inline fun check(noinline predicate: (T) -> Unit) = Mockito.argThat { it -> predicate(it); true } ?: createInstance(T::class) + +/** + * 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 check(noinline predicate: (T) -> Unit) = Mockito.argThat { arg -> + 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()) + predicate(arg) + true +} ?: createInstance(T::class) fun atLeast(numInvocations: Int): VerificationMode = Mockito.atLeast(numInvocations)!! fun atLeastOnce(): VerificationMode = Mockito.atLeastOnce()!! diff --git a/mockito-kotlin/src/test/kotlin/test/Classes.kt b/mockito-kotlin/src/test/kotlin/test/Classes.kt index eca8c1cd..58dc9958 100644 --- a/mockito-kotlin/src/test/kotlin/test/Classes.kt +++ b/mockito-kotlin/src/test/kotlin/test/Classes.kt @@ -1,4 +1,6 @@ -package test/* +package test + +/* * The MIT License * * Copyright (c) 2016 Niek Haarman @@ -55,6 +57,7 @@ interface Methods { fun nullableString(s: String?) fun stringResult(): String + fun stringResult(s: String): String fun nullableStringResult(): String? fun builderMethod(): Methods } diff --git a/mockito-kotlin/src/test/kotlin/test/MockitoTest.kt b/mockito-kotlin/src/test/kotlin/test/MockitoTest.kt index 1514a1ea..d348b1ae 100644 --- a/mockito-kotlin/src/test/kotlin/test/MockitoTest.kt +++ b/mockito-kotlin/src/test/kotlin/test/MockitoTest.kt @@ -138,6 +138,17 @@ class MockitoTest : TestBase() { } } + @Test + fun checkWithNullArgument_throwsError() { + mock().apply { + nullableString(null) + + expectErrorWithMessage("null").on { + verify(this).nullableString(check {}) + } + } + } + @Test fun atLeastXInvocations() { mock().apply { @@ -458,6 +469,30 @@ class MockitoTest : TestBase() { } } + @Test + fun stubbingTwiceWithArgumentMatchers() { + /* When */ + val mock = mock { + on { stringResult(argThat { this == "A" }) } doReturn "A" + on { stringResult(argThat { this == "B" }) } doReturn "B" + } + + /* Then */ + expect(mock.stringResult("A")).toBe("A") + expect(mock.stringResult("B")).toBe("B") + } + + @Test + fun stubbingTwiceWithCheckArgumentMatchers_throwsException() { + /* Expect */ + expectErrorWithMessage("null").on { + mock { + on { stringResult(check { }) } doReturn "A" + on { stringResult(check { }) } doReturn "B" + } + } + } + @Test fun doReturn_withSingleItemList() { /* Given */ @@ -500,6 +535,7 @@ class MockitoTest : TestBase() { verify(this).string(isA()) } } + @Test fun isA_withNullableString() { mock().apply {