-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
Foreward
First off, I want to thank the Junit 5 team from being so willing to officially support Kotlin as a first-class citizen in the Junit 5 library. It has been absolutely wonderful being able to use my own contributions in all of my Kotlin projects.
Feature Request
I believe that this API can be further enhanced with the new Kotlin 1.3 feature, Contracts.
Contracts are making guarantees to the compiler that various methods have certain characteristics.
Here's an example from the Kotlin Std-Lib:
/**
* Throws an [IllegalStateException] if the [value] is null. Otherwise
* returns the not null value.
*
* @sample samples.misc.Preconditions.failCheckWithLazyMessage
*/
@kotlin.internal.InlineOnly
public inline fun <T : Any> checkNotNull(value: T?): T {
contract {
returns() implies (value != null)
}
return checkNotNull(value) { "Required value was null." }
}
Before Kotlin Contracts, the following code wouldn't have compiled:
fun validateString(aString: String?): String {
checkNotNull(aString)
return aString
}
I believe that JUnit 5 has a few places where these contracts would be valuable.
Examples
assertNotNull
@ExperimentalContracts
fun <T: Any> assertNonNull(actual: T?, message: String): T {
contract {
returns() implies (actual != null)
}
Assertions.assertNotNull(actual, message)
return actual!!
}
The above would allow something like this:
val exception = assertThrows<IllegalStateException { /** whatever **/}
val message = exception.message
assertNotNull(message)
assertTrue(message.contains("some expected substring"))
Alternatively, it would also allow for this sort of use case:
val message = assertNotNull(exception.message)
assertThrows
/ assertDoesNotThrow
Since the callable
passed to assertThrows
is only ever called once, we can expose that in the contract.
@ExperimentalContracts
inline fun <reified T : Throwable> assertThrows(noinline message: () -> String, noinline executable: () -> Unit): T {
contract {
callsInPlace(executable, InvocationKind.EXACTLY_ONCE)
}
return Assertions.assertThrows(T::class.java, Executable(executable), Supplier(message))
}
Similar
This would for something like this:
val something: Int
val somethingElse: String
assertDoesNotThrow {
something = somethingThatDoesntThrow()
somethingElse = gettingSomethingElse()
}
Caveats
Kotlin Contracts are only supported in Kotlin 1.3 and higher.
This would require a discussion regarding what version of Kotlin the Junit 5 team want's to officially support.
Deliverables
- Add Kotlin method
assertNotNull
- Add Contracts to Kotlin method
assertNotNull
- Add Contracts to Kotlin method
assertThrows
- Add Contracts to Kotlin method
assertDoesNotThrow
Metadata
Metadata
Assignees
Type
Projects
Status