From c8fecf02ab38ae3effa06309ddeed1be0b933395 Mon Sep 17 00:00:00 2001 From: Niek Haarman Date: Thu, 3 Nov 2016 12:43:06 +0100 Subject: [PATCH] Try to use constructor when mocking fails --- .../nhaarman/mockito_kotlin/CreateInstance.kt | 32 ++++++++++++++----- .../src/test/kotlin/CreateInstanceTest.kt | 22 +++++++++++++ .../kotlin/CreateInstanceInlineTest.kt | 26 ++++++++++++++- 3 files changed, 71 insertions(+), 9 deletions(-) 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 72ceb6af..4897ec27 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 @@ -64,15 +64,31 @@ inline fun createInstance() = createInstance(T::class) @Suppress("UNCHECKED_CAST") fun createInstance(kClass: KClass): T { + var cause: Throwable? = null return MockitoKotlin.instanceCreator(kClass)?.invoke() as T? ?: - when { - kClass.hasObjectInstance() -> kClass.objectInstance!! - kClass.isPrimitive() -> kClass.toDefaultPrimitiveValue() - kClass.isMockable() -> kClass.java.uncheckedMock() - kClass.isEnum() -> kClass.java.enumConstants.first() - kClass.isArray() -> kClass.toArrayInstance() - kClass.isClassObject() -> kClass.toClassObject() - else -> kClass.easiestConstructor().newInstance() + try { + when { + kClass.hasObjectInstance() -> kClass.objectInstance!! + kClass.isPrimitive() -> kClass.toDefaultPrimitiveValue() + kClass.isEnum() -> kClass.java.enumConstants.first() + kClass.isArray() -> kClass.toArrayInstance() + kClass.isClassObject() -> kClass.toClassObject() + kClass.isMockable() -> try { + kClass.java.uncheckedMock() + } catch(e: Throwable) { + cause = e + kClass.easiestConstructor().newInstance() + } + else -> kClass.easiestConstructor().newInstance() + } + } catch(e: Exception) { + if (e is MockitoKotlinException) throw e + + cause?.let { + @Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") + (e as java.lang.Throwable).initCause(it) + } + throw MockitoKotlinException("Could not create an instance for $kClass.", e) } } diff --git a/mockito-kotlin/src/test/kotlin/CreateInstanceTest.kt b/mockito-kotlin/src/test/kotlin/CreateInstanceTest.kt index 991bf735..2fc7e657 100644 --- a/mockito-kotlin/src/test/kotlin/CreateInstanceTest.kt +++ b/mockito-kotlin/src/test/kotlin/CreateInstanceTest.kt @@ -476,6 +476,24 @@ class CreateInstanceTest { expect(result.second).toBe(2) } + @Test + fun sealedClass() { + /* When */ + val result = createInstance(MySealedClass::class) + + /* Then */ + expect(result).toNotBeNull() + } + + @Test + fun sealedClassMember() { + /* When */ + val result = createInstance(MySealedClass.MySealedClassMember::class) + + /* Then */ + expect(result).toNotBeNull() + } + private class PrivateClass private constructor(val data: String) class ClosedClass @@ -537,4 +555,8 @@ class CreateInstanceTest { } enum class MyEnum { VALUE, ANOTHER_VALUE } + + sealed class MySealedClass { + class MySealedClassMember : MySealedClass() + } } diff --git a/mockito-kotlin/src/testInlineMockito/kotlin/CreateInstanceInlineTest.kt b/mockito-kotlin/src/testInlineMockito/kotlin/CreateInstanceInlineTest.kt index 47e35211..e7cf038a 100644 --- a/mockito-kotlin/src/testInlineMockito/kotlin/CreateInstanceInlineTest.kt +++ b/mockito-kotlin/src/testInlineMockito/kotlin/CreateInstanceInlineTest.kt @@ -23,6 +23,7 @@ */ import com.nhaarman.expect.expect +import com.nhaarman.expect.expectErrorWithMessage import com.nhaarman.mockito_kotlin.* import org.junit.Test import java.io.IOException @@ -105,7 +106,7 @@ class CreateInstanceInlineTest { /* Then */ expect(i).toBe(0) } - + @Test fun createStringInstance() { /* When */ @@ -115,10 +116,33 @@ class CreateInstanceInlineTest { expect(s).toBe("") } + @Test + fun sealedClass_fails() { + /* Expect */ + expectErrorWithMessage("Could not create") on { + + /* When */ + createInstance(MySealedClass::class) + } + } + + @Test + fun sealedClassMember() { + /* When */ + val result = createInstance(MySealedClass.MySealedClassMember::class) + + /* Then */ + expect(result).toNotBeNull() + } + interface Methods { fun throwableClass(t: ThrowableClass) } class ThrowableClass(cause: Throwable) : Throwable(cause) + + sealed class MySealedClass { + class MySealedClassMember : MySealedClass() + } }