Skip to content

Commit

Permalink
Merge pull request #93 from nhaarman/release-0.8.0
Browse files Browse the repository at this point in the history
Release 0.8.0
  • Loading branch information
nhaarman authored Oct 13, 2016
2 parents ea6e64c + d556691 commit 5878bbe
Show file tree
Hide file tree
Showing 10 changed files with 345 additions and 70 deletions.
85 changes: 31 additions & 54 deletions mockito-kotlin/build.gradle
Original file line number Diff line number Diff line change
@@ -1,73 +1,50 @@
apply plugin: 'kotlin'
apply from: './publishing.gradle'

buildscript {
ext.kotlin_version = '1.0.4'
ext.kotlin_version = '1.0.4'

repositories {
mavenCentral()
}
repositories {
mavenCentral()
}

dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

repositories {
mavenCentral()
jcenter()
}

dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
compile "org.mockito:mockito-core:2.1.0"

/* Tests */
testCompile "junit:junit:4.12"
testCompile "com.nhaarman:expect.kt:0.6.0"
mavenCentral()
jcenter()
}

publishing {
publications {
MyPublication(MavenPublication) {
from components.java
artifact javadocJar
artifact sourcesJar

groupId 'com.nhaarman'
artifactId 'mockito-kotlin'
version rootProject.ext.versionName
sourceSets {
testInlineMockito {
compileClasspath += main.output + test.output
runtimeClasspath += main.output + test.output
}
}
}

bintray {
user = hasProperty('bintray_user') ? bintray_user : System.getenv('BINTRAY_USER')
key = hasProperty('bintray_key') ? bintray_key : System.getenv('BINTRAY_KEY')
publications = ['MyPublication']
configurations {
testInlineMockitoCompile.extendsFrom testCompile
testInlineMockitoRuntime.extendsFrom testRuntime
}

pkg {
repo = 'maven'
name = "Mockito-Kotlin"
desc = "Using Mockito with Kotlin"
// define custom test task for running integration tests
task testInlineMockito(type: Test) {
testClassesDir = sourceSets.testInlineMockito.output.classesDir
classpath = sourceSets.testInlineMockito.runtimeClasspath
}

licenses = ['MIT']
vcsUrl = 'https://github.com/bintray/gradle-bintray-plugin.git'
test.dependsOn testInlineMockito

version {
name = rootProject.ext.versionName
desc = 'Using Mockito with Kotlin'
vcsTag = rootProject.ext.versionName
}
}
}

task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from 'build/docs/javadoc'
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
compile "org.mockito:mockito-core:2.2.1"

task sourcesJar(type: Jar) {
from sourceSets.main.allSource
classifier = 'sources'
/* Tests */
testCompile "junit:junit:4.12"
testCompile "com.nhaarman:expect.kt:0.6.0"
}
44 changes: 44 additions & 0 deletions mockito-kotlin/publishing.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
publishing {
publications {
MyPublication(MavenPublication) {
from components.java
artifact javadocJar
artifact sourcesJar

groupId 'com.nhaarman'
artifactId 'mockito-kotlin'
version rootProject.ext.versionName
}
}
}

bintray {
user = hasProperty('bintray_user') ? bintray_user : System.getenv('BINTRAY_USER')
key = hasProperty('bintray_key') ? bintray_key : System.getenv('BINTRAY_KEY')
publications = ['MyPublication']

pkg {
repo = 'maven'
name = "Mockito-Kotlin"
desc = "Using Mockito with Kotlin"

licenses = ['MIT']
vcsUrl = 'https://github.com/bintray/gradle-bintray-plugin.git'

version {
name = rootProject.ext.versionName
desc = 'Using Mockito with Kotlin'
vcsTag = rootProject.ext.versionName
}
}
}

task javadocJar(type: Jar, dependsOn: javadoc) {
classifier = 'javadoc'
from 'build/docs/javadoc'
}

task sourcesJar(type: Jar) {
from sourceSets.main.allSource
classifier = 'sources'
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,32 @@
package com.nhaarman.mockito_kotlin

import org.mockito.ArgumentCaptor
import kotlin.reflect.KClass

inline fun <reified T : Any> argumentCaptor(): KArgumentCaptor<T> = KArgumentCaptor(ArgumentCaptor.forClass(T::class.java), T::class)

inline fun <reified T : Any> argumentCaptor() = ArgumentCaptor.forClass(T::class.java)
inline fun <reified T : Any> capture(captor: ArgumentCaptor<T>): T = captor.capture() ?: createInstance<T>()

@Deprecated("Use captor.capture() instead.", ReplaceWith("captor.capture()"))
inline fun <reified T : Any> capture(captor: KArgumentCaptor<T>): T = captor.capture()

class KArgumentCaptor<out T : Any>(private val captor: ArgumentCaptor<T>, private val tClass: KClass<T>) {

val value: T
get() = captor.value

val allValues: List<T>
get() = captor.allValues

fun capture(): T = captor.capture() ?: createInstance(tClass)
}

/**
* This method is deprecated because its behavior differs from the Java behavior.
* Instead, use [argumentCaptor] in the traditional way, or use one of
* [argThat], [argForWhich] or [check].
*/
@Deprecated("Use argumentCaptor() or argThat() instead.")
inline fun <reified T : Any> capture(noinline consumer: (T) -> Unit): T {
var times = 0
return argThat { if (++times == 1) consumer.invoke(this); true }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import org.mockito.Answers
import org.mockito.internal.creation.MockSettingsImpl
import org.mockito.internal.creation.bytebuddy.MockAccess
import org.mockito.internal.util.MockUtil
import java.io.File
import java.lang.reflect.InvocationTargetException
import java.lang.reflect.Modifier
import java.lang.reflect.ParameterizedType
Expand All @@ -40,12 +41,26 @@ import kotlin.reflect.defaultType
import kotlin.reflect.jvm.isAccessible
import kotlin.reflect.jvm.javaType
import kotlin.reflect.jvm.jvmName
import java.lang.reflect.Array as JavaArray

/**
* A collection of functions that tries to create an instance of
* classes to avoid NPE's when using Mockito with Kotlin.
*/

/**
* Checks whether the resource file to enable mocking of final classes is present.
*/
private var mockMakerInlineEnabled: Boolean? = null

private fun mockMakerInlineEnabled(jClass: Class<out Any>): Boolean {
return mockMakerInlineEnabled ?:
jClass.getResource("mockito-extensions/org.mockito.plugins.MockMaker")?.let {
mockMakerInlineEnabled = File(it.file).readLines().filter { it == "mock-maker-inline" }.isNotEmpty()
mockMakerInlineEnabled
} ?: false
}

inline fun <reified T> createArrayInstance() = arrayOf<T>()

inline fun <reified T : Any> createInstance() = createInstance(T::class)
Expand Down Expand Up @@ -81,7 +96,10 @@ private fun <T> List<KFunction<T>>.withoutArrayParameters() = filter {
@Suppress("SENSELESS_COMPARISON")
private fun KClass<*>.hasObjectInstance() = objectInstance != null

private fun KClass<*>.isMockable() = !Modifier.isFinal(java.modifiers)
private fun KClass<*>.isMockable(): Boolean {
return !Modifier.isFinal(java.modifiers) || mockMakerInlineEnabled(java)
}

private fun KClass<*>.isEnum() = java.isEnum
private fun KClass<*>.isArray() = java.isArray
private fun KClass<*>.isClassObject() = jvmName.equals("java.lang.Class")
Expand Down Expand Up @@ -121,7 +139,10 @@ private fun <T : Any> KClass<T>.toArrayInstance(): T {
"LongArray" -> longArrayOf()
"DoubleArray" -> doubleArrayOf()
"FloatArray" -> floatArrayOf()
else -> throw UnsupportedOperationException("Cannot create a generic array for $simpleName. Use createArrayInstance() or anyArray() instead.")
else -> {
val name = java.name.drop(2).dropLast(1)
return JavaArray.newInstance(Class.forName(name), 0) as T
}
} as T
}

Expand Down Expand Up @@ -168,10 +189,10 @@ private fun <T : Any> KType.createNullableInstance(): T? {
* Creates a mock instance of given class, without modifying or checking any internal Mockito state.
*/
@Suppress("UNCHECKED_CAST")
private fun <T> Class<T>.uncheckedMock(): T {
fun <T> Class<T>.uncheckedMock(): T {
val impl = MockSettingsImpl<T>().defaultAnswer(Answers.RETURNS_DEFAULTS) as MockSettingsImpl<T>
val creationSettings = impl.confirm(this)
return MockUtil.createMock(creationSettings).apply {
(this as MockAccess).mockitoInterceptor = null
(this as? MockAccess)?.mockitoInterceptor = null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ inline fun <reified T : Any?> anyArray(): Array<T> = Mockito.any(Array<T>::class

inline fun <reified T : Any> argThat(noinline predicate: T.() -> Boolean) = Mockito.argThat<T> { it -> (it as T).predicate() } ?: createInstance(T::class)
inline fun <reified T : Any> argForWhich(noinline predicate: T.() -> Boolean) = argThat(predicate)
inline fun <reified T : Any> check(noinline predicate: (T) -> Unit) = Mockito.argThat<T> { it -> predicate(it); true } ?: createInstance(T::class)

fun atLeast(numInvocations: Int): VerificationMode = Mockito.atLeast(numInvocations)!!
fun atLeastOnce(): VerificationMode = Mockito.atLeastOnce()!!
Expand Down Expand Up @@ -99,6 +100,11 @@ infix fun <T> OngoingStubbing<T>.doReturn(t: T): OngoingStubbing<T> = thenReturn
fun <T> OngoingStubbing<T>.doReturn(t: T, vararg ts: T): OngoingStubbing<T> = thenReturn(t, *ts)
inline infix fun <reified T> OngoingStubbing<T>.doReturn(ts: List<T>): OngoingStubbing<T> = thenReturn(ts[0], *ts.drop(1).toTypedArray())

infix fun <T> OngoingStubbing<T>.doThrow(t: Throwable): OngoingStubbing<T> = thenThrow(t)
fun <T> OngoingStubbing<T>.doThrow(t: Throwable, vararg ts: Throwable): OngoingStubbing<T> = thenThrow(t, *ts)
infix fun <T> OngoingStubbing<T>.doThrow(t: KClass<out Throwable>): OngoingStubbing<T> = thenThrow(t.java)
fun <T> OngoingStubbing<T>.doThrow(t: KClass<out Throwable>, vararg ts: KClass<out Throwable>): OngoingStubbing<T> = thenThrow(t.java, *ts.map { it.java }.toTypedArray())

fun mockingDetails(toInspect: Any): MockingDetails = Mockito.mockingDetails(toInspect)!!
fun never(): VerificationMode = Mockito.never()!!
fun <T : Any> notNull(): T? = Mockito.notNull()
Expand Down
26 changes: 17 additions & 9 deletions mockito-kotlin/src/test/kotlin/ArgumentCaptorTest.kt
Original file line number Diff line number Diff line change
@@ -1,31 +1,39 @@
import com.nhaarman.expect.expect
import com.nhaarman.mockito_kotlin.argumentCaptor
import com.nhaarman.mockito_kotlin.mock
import com.nhaarman.mockito_kotlin.times
import com.nhaarman.mockito_kotlin.verify
import com.nhaarman.expect.expect
import com.nhaarman.mockito_kotlin.capture
import org.junit.Test
import java.util.*

class ArgumentCaptorTest {

@Test
fun explicitCaptor() {
/* Given */
val date: Date = mock()
val time = argumentCaptor<Long>()

/* When */
date.time = 5L

verify(date).time = capture(time)
expect(time.value).toBe(5L)
/* Then */
val captor = argumentCaptor<Long>()
verify(date).time = captor.capture()
expect(captor.value).toBe(5L)
}

@Test
fun implicitCaptor() {
fun argumentCaptor_multipleValues() {
/* Given */
val date: Date = mock()

/* When */
date.time = 5L
date.time = 7L

verify(date).time = capture {
expect(it).toBe(5L)
}
/* Then */
val captor = argumentCaptor<Long>()
verify(date, times(2)).time = captor.capture()
expect(captor.allValues).toBe(listOf(5, 7))
}
}
7 changes: 5 additions & 2 deletions mockito-kotlin/src/test/kotlin/CreateInstanceTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -159,10 +159,13 @@ class CreateInstanceTest {
expect(result).toNotBeNull()
}

@Test(expected = UnsupportedOperationException::class)
@Test
fun classArray_usingAny() {
/* When */
createInstance<Array<Open>>()
val result = createInstance<Array<Open>>()

/* Then */
expect(result).toBeInstanceOf<Array<Open>>()
}

@Test
Expand Down
Loading

0 comments on commit 5878bbe

Please sign in to comment.