diff --git a/mockito-kotlin/build.gradle b/mockito-kotlin/build.gradle index a00aaac3..795d7779 100644 --- a/mockito-kotlin/build.gradle +++ b/mockito-kotlin/build.gradle @@ -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.1.0" -task sourcesJar(type: Jar) { - from sourceSets.main.allSource - classifier = 'sources' + /* Tests */ + testCompile "junit:junit:4.12" + testCompile "com.nhaarman:expect.kt:0.6.0" } diff --git a/mockito-kotlin/publishing.gradle b/mockito-kotlin/publishing.gradle new file mode 100644 index 00000000..4fa06572 --- /dev/null +++ b/mockito-kotlin/publishing.gradle @@ -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' +} \ No newline at end of file diff --git a/mockito-kotlin/src/main/kotlin/com/nhaarman/mockito_kotlin/CreateInstance.kt b/mockito-kotlin/src/main/kotlin/com/nhaarman/mockito_kotlin/CreateInstance.kt index 0ce613c9..f6c5017e 100644 --- a/mockito-kotlin/src/main/kotlin/com/nhaarman/mockito_kotlin/CreateInstance.kt +++ b/mockito-kotlin/src/main/kotlin/com/nhaarman/mockito_kotlin/CreateInstance.kt @@ -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 @@ -46,6 +47,18 @@ import kotlin.reflect.jvm.jvmName * 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): 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 createArrayInstance() = arrayOf() inline fun createInstance() = createInstance(T::class) @@ -81,7 +94,10 @@ private fun List>.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") @@ -168,10 +184,10 @@ private fun KType.createNullableInstance(): T? { * Creates a mock instance of given class, without modifying or checking any internal Mockito state. */ @Suppress("UNCHECKED_CAST") -private fun Class.uncheckedMock(): T { +fun Class.uncheckedMock(): T { val impl = MockSettingsImpl().defaultAnswer(Answers.RETURNS_DEFAULTS) as MockSettingsImpl val creationSettings = impl.confirm(this) return MockUtil.createMock(creationSettings).apply { - (this as MockAccess).mockitoInterceptor = null + (this as? MockAccess)?.mockitoInterceptor = null } } diff --git a/mockito-kotlin/src/test/kotlin/MockitoTest.kt b/mockito-kotlin/src/test/kotlin/MockitoTest.kt index c40f9525..75d7cbda 100644 --- a/mockito-kotlin/src/test/kotlin/MockitoTest.kt +++ b/mockito-kotlin/src/test/kotlin/MockitoTest.kt @@ -132,6 +132,7 @@ class MockitoTest { } } + /** https://github.com/nhaarman/mockito-kotlin/issues/27 */ @Test fun anyThrowableWithSingleThrowableConstructor() { mock().apply { diff --git a/mockito-kotlin/src/testInlineMockito/kotlin/CreateInstanceOfImmutableTest.kt b/mockito-kotlin/src/testInlineMockito/kotlin/CreateInstanceOfImmutableTest.kt new file mode 100644 index 00000000..a5abaf8f --- /dev/null +++ b/mockito-kotlin/src/testInlineMockito/kotlin/CreateInstanceOfImmutableTest.kt @@ -0,0 +1,106 @@ +/* + * The MIT License + * + * Copyright (c) 2016 Ian J. De Silva + * + * 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. + */ + +import com.nhaarman.expect.expect +import com.nhaarman.mockito_kotlin.* +import org.junit.Test +import java.io.IOException +import java.math.BigInteger + +class CreateInstanceOfImmutableTest { + + class ClassToBeMocked { + + fun doSomething(c: ClassToBeMocked) { + } + + fun doSomethingElse(value: BigInteger): BigInteger { + return value.plus(BigInteger.ONE) + } + } + + @Test + fun mockClosedClass() { + /* When */ + val result = mock() + + /* Then */ + expect(result).toNotBeNull() + } + + @Test + fun anyClosedClass() { + /* Given */ + val mock = mock() + + /* When */ + mock.doSomething(mock) + + /* Then */ + verify(mock).doSomething(any()) + } + + @Test + fun mockClosedFunction_mockStubbing() { + /* Given */ + val mock = mock { + on { doSomethingElse(any()) } doReturn (BigInteger.ONE) + } + + /* When */ + val result = mock.doSomethingElse(BigInteger.TEN) + + /* Then */ + expect(result).toBe(BigInteger.ONE) + } + + @Test + fun mockClosedFunction_whenever() { + /* Given */ + val mock = mock() + whenever(mock.doSomethingElse(any())).doReturn(BigInteger.ONE) + + /* When */ + val result = mock.doSomethingElse(BigInteger.TEN) + + /* Then */ + expect(result).toBe(BigInteger.ONE) + } + + /** https://github.com/nhaarman/mockito-kotlin/issues/27 */ + @Test + fun anyThrowableWithSingleThrowableConstructor() { + mock().apply { + throwableClass(ThrowableClass(IOException())) + verify(this).throwableClass(any()) + } + } + + interface Methods { + + fun throwableClass(t: ThrowableClass) + } + + class ThrowableClass(cause: Throwable) : Throwable(cause) +} diff --git a/mockito-kotlin/src/testInlineMockito/resources/mockito-extensions/org.mockito.plugins.MockMaker b/mockito-kotlin/src/testInlineMockito/resources/mockito-extensions/org.mockito.plugins.MockMaker new file mode 100644 index 00000000..ca6ee9ce --- /dev/null +++ b/mockito-kotlin/src/testInlineMockito/resources/mockito-extensions/org.mockito.plugins.MockMaker @@ -0,0 +1 @@ +mock-maker-inline \ No newline at end of file