Skip to content

Commit

Permalink
Feature/kotlin fail methods (#1254)
Browse files Browse the repository at this point in the history
Add Kotlin "fail" methods to org.junit.jupiter.api

Closes #1209
  • Loading branch information
sormuras authored Jan 20, 2018
1 parent 7f6b2cd commit c93d0aa
Show file tree
Hide file tree
Showing 5 changed files with 156 additions and 14 deletions.
11 changes: 7 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,9 @@ subprojects { subproj ->
options.addStringOption('tag', 'implSpec:a:Implementation Requirements:')
options.addStringOption('tag', 'implNote:a:Implementation Note:')
options.encoding = 'UTF-8'
// Remove Kotlin classes from classpath due to "bad" class file: AssertionsKt$sam$Supplier$44378ebd.class
// see https://bugs.openjdk.java.net/browse/JDK-8187422
if (gradle.ext.kotlinIsSupported) classpath = classpath - files(compileKotlin.destinationDir)
}

task sourcesJar(type: Jar, dependsOn: classes) {
Expand Down Expand Up @@ -592,10 +595,10 @@ configure(rootProject) {

maxMemory = "1024m"
destinationDir = new File(buildDir, "docs/javadoc")

doFirst {
classpath = files(subprojects.collect { it.sourceSets.main.compileClasspath })
}
// Remove Kotlin classes from classpath due to "bad" class file
// see https://bugs.openjdk.java.net/browse/JDK-8187422
classpath = files(subprojects.collect { it.sourceSets.main.compileClasspath })
.filter { !it.path.contains('kotlin') }
}

spotless {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,13 @@ _@API Guardian_ JAR _mandatory_ again.
without running the complete test factory or test template. This allows to rerun single
or selected parameterized, repeated or dynamic tests by selecting their unique IDs in
subsequent discovery requests.

* New Kotlin friendly `fail` methods added as _top-level functions_ in the
`org.junit.jupiter.api` package.
** When calling the original methods from Kotlin the compiler required the generic return
type of `fail` to be declared explicitly calling it.
Eg: `fail<Nothing>("Some message")`.
These new methods all return
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/-nothing.html[`Nothing`].

[[release-notes-5.1.0-M2-junit-vintage]]
=== JUnit Vintage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* http://www.eclipse.org/legal/epl-v20.html
*/
@file:API(status = EXPERIMENTAL, since = "5.1")

package org.junit.jupiter.api

import org.apiguardian.api.API
Expand All @@ -16,6 +17,24 @@ import org.junit.jupiter.api.function.Executable
import java.util.function.Supplier
import java.util.stream.Stream

/**
* @see Assertions.fail
*/
fun fail(message: String?, throwable: Throwable? = null): Nothing =
Assertions.fail<Nothing>(message, throwable)

/**
* @see Assertions.fail
*/
fun fail(message: (() -> String)?): Nothing =
Assertions.fail<Nothing>(message)

/**
* @see Assertions.fail
*/
fun fail(throwable: Throwable?): Nothing =
Assertions.fail<Nothing>(throwable)

/**
* [Stream] of functions to be executed.
*/
Expand Down Expand Up @@ -101,11 +120,4 @@ inline fun <reified T : Throwable> assertThrows(message: String, noinline execut
* @see Assertions.assertThrows
*/
inline fun <reified T : Throwable> assertThrows(noinline message: () -> String, noinline executable: () -> Unit): T =
Assertions.assertThrows(T::class.java, Executable(executable), Supplier {
/*
* This is a hacky workaround due to a bug in how the JDK 9 JavaDoc code generator interacts with the
* generated Kotlin Bytecode.
* https://youtrack.jetbrains.com/issue/KT-20025
*/
message()
})
Assertions.assertThrows(T::class.java, Executable(executable), Supplier(message))
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ void failWithStringAndThrowable() {
@Test
void failWithThrowable() {
try {
fail((String) null, new Throwable("cause"));
fail(new Throwable("cause"));
expectAssertionFailedError();
}
catch (AssertionFailedError ex) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
/*
* Copyright 2015-2018 the original author or authors.
*
* All rights reserved. This program and the accompanying materials are
* made available under the terms of the Eclipse Public License v2.0 which
* accompanies this distribution and is available at
*
* http://www.eclipse.org/legal/epl-v20.html
*/
package org.junit.jupiter.api

import org.junit.jupiter.api.AssertEquals.assertEquals
import org.junit.jupiter.api.AssertionTestUtils.assertMessageContains
import org.junit.jupiter.api.AssertionTestUtils.assertMessageEquals
import org.opentest4j.AssertionFailedError
import java.util.stream.Stream

class KotlinFailAssertionsTests {

@Test
fun `fail with string`() {
val message = "test"
val ex = assertThrows<AssertionFailedError> {
fail(message)
}
assertMessageEquals(ex, message)
}

@Test
fun `fail with message supplier`() {
val message = "test"
val ex = assertThrows<AssertionFailedError> {
fail { message }
}
assertMessageEquals(ex, message)
}

@Test
fun `fail with null string`() {
val ex = assertThrows<AssertionFailedError> {
fail(null as String?)
}
assertMessageEquals(ex, "")
}

@Test
fun `fail with null message supplier`() {
val ex = assertThrows<AssertionFailedError> {
fail(null as (() -> String)?)
}
assertMessageEquals(ex, "")
}

@Test
fun `fail with string and throwable`() {
val message = "message"
val throwableCause = "cause"
val ex = assertThrows<AssertionFailedError> {
fail(message, Throwable(throwableCause))
}
assertMessageEquals(ex, message)
val cause = ex.cause
assertMessageContains(cause, throwableCause)
}

@Test
fun `fail with throwable`() {
val throwableCause = "cause"
val ex = assertThrows<AssertionFailedError> {
fail(Throwable(throwableCause))
}
assertMessageEquals(ex, "")
val cause = ex.cause
assertMessageContains(cause, throwableCause)
}

@Test
fun `fail with string and null throwable`() {
val message = "message"
val ex = assertThrows<AssertionFailedError> {
fail(message, null)
}
assertMessageEquals(ex, message)
if (ex.cause != null) {
throw AssertionError("Cause should have been null")
}
}

@Test
fun `fail with null string and throwable`() {
val throwableCause = "cause"
val ex = assertThrows<AssertionFailedError> {
fail(null, Throwable(throwableCause))
}
assertMessageEquals(ex, "")
val cause = ex.cause
assertMessageContains(cause, throwableCause)
}

@Test
fun `fail usable as a stream expression`() {
val count = Stream.empty<Any>()
.peek { _ -> fail("peek should never be called") }
.filter { _ -> fail("filter should never be called", Throwable("cause")) }
.map { _ -> fail(Throwable("map should never be called")) }
.sorted { _, _ -> fail { "sorted should never be called" } }
.count()
assertEquals(0L, count)
}

@Test
fun `fail usable as a sequence expression`() {
val count = emptyList<Any>()
.asSequence()
.onEach { _ -> fail("peek should never be called") }
.filter { _ -> fail("filter should never be called", Throwable("cause")) }
.map { _ -> fail(Throwable("map should never be called")) }
.count()
assertEquals(0, count)
}
}

2 comments on commit c93d0aa

@sormuras
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kudos to @JLLeitschuh for the code -- my git-fu failed to preserve your initial commit!

@JLLeitschuh
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah well, at least it's now checked in. Thanks @sormuras. I didn't have the time to do this myself.

Please sign in to comment.