Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inline lambdas passed to assertDoesNotThrows to support suspending functions #2684

Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ on GitHub.

==== New Features and Improvements

* `assertDoesNotThrow` now supports calling suspending functions.
williamboman marked this conversation as resolved.
Show resolved Hide resolved
* `@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(getThrowingSupplier(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(
getThrowingSupplier(executable),
Supplier(message)
)

@PublishedApi
internal inline fun <R> getThrowingSupplier(executable: () -> R): ThrowingSupplier<R> = try {
Copy link
Member

Choose a reason for hiding this comment

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

Not sure about this method name which is "effectively public" due to @PublishedApi. Maybe evaluateAndWrap or sth. similar would be clearer.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah that's a good call, agreed.

742d7af

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