Skip to content

Commit

Permalink
Inline lambdas passed to assertDoesNotThrows to support suspending fu…
Browse files Browse the repository at this point in the history
…nctions (junit-team#2684)

This commit adds support for suspending functions when `assertDoesNotThrow` is called from Kotlin.

Closes junit-team#2674.
  • Loading branch information
williamboman authored and runningcode committed Feb 15, 2023
1 parent e9e8193 commit c0519a5
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ on GitHub.

==== New Features and Improvements

* `assertDoesNotThrow` now supports suspending functions when called from Kotlin.
* `@TempDir` can now be used to create multiple temporary directories. Instead of creating
a single temporary directory per context (i.e. test class or method) every declaration
of the `@TempDir` annotation on a field or method parameter now results in a separate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,8 @@ inline fun <reified T : Throwable> assertThrows(noinline message: () -> String,
* @param R the result type of the [executable]
*/
@API(status = EXPERIMENTAL, since = "5.5")
fun <R> assertDoesNotThrow(executable: () -> R): R =
Assertions.assertDoesNotThrow(ThrowingSupplier(executable))
inline fun <R> assertDoesNotThrow(executable: () -> R): R =
Assertions.assertDoesNotThrow(evaluateAndWrap(executable))

/**
* Example usage:
Expand All @@ -172,7 +172,7 @@ fun <R> assertDoesNotThrow(executable: () -> R): R =
* @param R the result type of the [executable]
*/
@API(status = EXPERIMENTAL, since = "5.5")
fun <R> assertDoesNotThrow(message: String, executable: () -> R): R =
inline fun <R> assertDoesNotThrow(message: String, executable: () -> R): R =
assertDoesNotThrow({ message }, executable)

/**
Expand All @@ -186,8 +186,19 @@ fun <R> assertDoesNotThrow(message: String, executable: () -> R): R =
* @param R the result type of the [executable]
*/
@API(status = EXPERIMENTAL, since = "5.5")
fun <R> assertDoesNotThrow(message: () -> String, executable: () -> R): R =
Assertions.assertDoesNotThrow(ThrowingSupplier(executable), Supplier(message))
inline fun <R> assertDoesNotThrow(noinline message: () -> String, executable: () -> R): R =
Assertions.assertDoesNotThrow(
evaluateAndWrap(executable),
Supplier(message)
)

@PublishedApi
internal inline fun <R> evaluateAndWrap(executable: () -> R): ThrowingSupplier<R> = try {
val result = executable()
ThrowingSupplier { result }
} catch (throwable: Throwable) {
ThrowingSupplier { throw throwable }
}

/**
* Example usage:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,31 @@ class KotlinAssertionsTests {
val actual = assertDoesNotThrow { 1 }
assertEquals(1, actual)
},
dynamicTest("for no arguments variant (suspended)") {
runBlocking {
val actual = assertDoesNotThrow { suspend { 1 }() }
assertEquals(1, actual)
}
},
dynamicTest("for message variant") {
val actual = assertDoesNotThrow("message") { 2 }
assertEquals(2, actual)
},
dynamicTest("for message variant (suspended)") {
runBlocking {
val actual = assertDoesNotThrow("message") { suspend { 2 }() }
assertEquals(2, actual)
}
},
dynamicTest("for message supplier variant") {
val actual = assertDoesNotThrow({ "message" }) { 3 }
assertEquals(3, actual)
},
dynamicTest("for message supplier variant (suspended)") {
runBlocking {
val actual = assertDoesNotThrow({ "message" }) { suspend { 3 }() }
assertEquals(3, actual)
}
}
)),
dynamicContainer("fails when an exception is thrown", Stream.of(
Expand All @@ -94,6 +112,19 @@ class KotlinAssertionsTests {
assertMessageEquals(exception,
"Unexpected exception thrown: org.opentest4j.AssertionFailedError: fail")
},
dynamicTest("for no arguments variant (suspended)") {
runBlocking {
val exception = assertThrows<AssertionError> {
assertDoesNotThrow {
suspend { fail("fail") }()
}
}
assertMessageEquals(
exception,
"Unexpected exception thrown: org.opentest4j.AssertionFailedError: fail"
)
}
},
dynamicTest("for message variant") {
val exception = assertThrows<AssertionError> {
assertDoesNotThrow("Does not throw") {
Expand All @@ -103,6 +134,19 @@ class KotlinAssertionsTests {
assertMessageEquals(exception,
"Does not throw ==> Unexpected exception thrown: org.opentest4j.AssertionFailedError: fail")
},
dynamicTest("for message variant (suspended)") {
runBlocking {
val exception = assertThrows<AssertionError> {
assertDoesNotThrow("Does not throw") {
suspend { fail("fail") }()
}
}
assertMessageEquals(
exception,
"Does not throw ==> Unexpected exception thrown: org.opentest4j.AssertionFailedError: fail"
)
}
},
dynamicTest("for message supplier variant") {
val exception = assertThrows<AssertionError> {
assertDoesNotThrow({ "Does not throw" }) {
Expand All @@ -111,6 +155,19 @@ class KotlinAssertionsTests {
}
assertMessageEquals(exception,
"Does not throw ==> Unexpected exception thrown: org.opentest4j.AssertionFailedError: fail")
},
dynamicTest("for message supplier variant (suspended)") {
runBlocking {
val exception = assertThrows<AssertionError> {
assertDoesNotThrow({ "Does not throw" }) {
suspend { fail("fail") }()
}
}
assertMessageEquals(
exception,
"Does not throw ==> Unexpected exception thrown: org.opentest4j.AssertionFailedError: fail"
)
}
}
))
)
Expand Down

0 comments on commit c0519a5

Please sign in to comment.