Skip to content

Commit 3f605f1

Browse files
authored
Inline lambdas passed to assertDoesNotThrows to support suspending functions (#2684)
This commit adds support for suspending functions when `assertDoesNotThrow` is called from Kotlin. Closes #2674.
1 parent 56266d3 commit 3f605f1

File tree

3 files changed

+74
-5
lines changed

3 files changed

+74
-5
lines changed

documentation/src/docs/asciidoc/release-notes/release-notes-5.8.0-M2.adoc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ on GitHub.
8484

8585
==== New Features and Improvements
8686

87+
* `assertDoesNotThrow` now supports suspending functions when called from Kotlin.
8788
* `@TempDir` can now be used to create multiple temporary directories. Instead of creating
8889
a single temporary directory per context (i.e. test class or method) every declaration
8990
of the `@TempDir` annotation on a field or method parameter now results in a separate

junit-jupiter-api/src/main/kotlin/org/junit/jupiter/api/Assertions.kt

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -158,8 +158,8 @@ inline fun <reified T : Throwable> assertThrows(noinline message: () -> String,
158158
* @param R the result type of the [executable]
159159
*/
160160
@API(status = EXPERIMENTAL, since = "5.5")
161-
fun <R> assertDoesNotThrow(executable: () -> R): R =
162-
Assertions.assertDoesNotThrow(ThrowingSupplier(executable))
161+
inline fun <R> assertDoesNotThrow(executable: () -> R): R =
162+
Assertions.assertDoesNotThrow(evaluateAndWrap(executable))
163163

164164
/**
165165
* Example usage:
@@ -172,7 +172,7 @@ fun <R> assertDoesNotThrow(executable: () -> R): R =
172172
* @param R the result type of the [executable]
173173
*/
174174
@API(status = EXPERIMENTAL, since = "5.5")
175-
fun <R> assertDoesNotThrow(message: String, executable: () -> R): R =
175+
inline fun <R> assertDoesNotThrow(message: String, executable: () -> R): R =
176176
assertDoesNotThrow({ message }, executable)
177177

178178
/**
@@ -186,8 +186,19 @@ fun <R> assertDoesNotThrow(message: String, executable: () -> R): R =
186186
* @param R the result type of the [executable]
187187
*/
188188
@API(status = EXPERIMENTAL, since = "5.5")
189-
fun <R> assertDoesNotThrow(message: () -> String, executable: () -> R): R =
190-
Assertions.assertDoesNotThrow(ThrowingSupplier(executable), Supplier(message))
189+
inline fun <R> assertDoesNotThrow(noinline message: () -> String, executable: () -> R): R =
190+
Assertions.assertDoesNotThrow(
191+
evaluateAndWrap(executable),
192+
Supplier(message)
193+
)
194+
195+
@PublishedApi
196+
internal inline fun <R> evaluateAndWrap(executable: () -> R): ThrowingSupplier<R> = try {
197+
val result = executable()
198+
ThrowingSupplier { result }
199+
} catch (throwable: Throwable) {
200+
ThrowingSupplier { throw throwable }
201+
}
191202

192203
/**
193204
* Example usage:

junit-jupiter-engine/src/test/kotlin/org/junit/jupiter/api/KotlinAssertionsTests.kt

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,13 +75,31 @@ class KotlinAssertionsTests {
7575
val actual = assertDoesNotThrow { 1 }
7676
assertEquals(1, actual)
7777
},
78+
dynamicTest("for no arguments variant (suspended)") {
79+
runBlocking {
80+
val actual = assertDoesNotThrow { suspend { 1 }() }
81+
assertEquals(1, actual)
82+
}
83+
},
7884
dynamicTest("for message variant") {
7985
val actual = assertDoesNotThrow("message") { 2 }
8086
assertEquals(2, actual)
8187
},
88+
dynamicTest("for message variant (suspended)") {
89+
runBlocking {
90+
val actual = assertDoesNotThrow("message") { suspend { 2 }() }
91+
assertEquals(2, actual)
92+
}
93+
},
8294
dynamicTest("for message supplier variant") {
8395
val actual = assertDoesNotThrow({ "message" }) { 3 }
8496
assertEquals(3, actual)
97+
},
98+
dynamicTest("for message supplier variant (suspended)") {
99+
runBlocking {
100+
val actual = assertDoesNotThrow({ "message" }) { suspend { 3 }() }
101+
assertEquals(3, actual)
102+
}
85103
}
86104
)),
87105
dynamicContainer("fails when an exception is thrown", Stream.of(
@@ -94,6 +112,19 @@ class KotlinAssertionsTests {
94112
assertMessageEquals(exception,
95113
"Unexpected exception thrown: org.opentest4j.AssertionFailedError: fail")
96114
},
115+
dynamicTest("for no arguments variant (suspended)") {
116+
runBlocking {
117+
val exception = assertThrows<AssertionError> {
118+
assertDoesNotThrow {
119+
suspend { fail("fail") }()
120+
}
121+
}
122+
assertMessageEquals(
123+
exception,
124+
"Unexpected exception thrown: org.opentest4j.AssertionFailedError: fail"
125+
)
126+
}
127+
},
97128
dynamicTest("for message variant") {
98129
val exception = assertThrows<AssertionError> {
99130
assertDoesNotThrow("Does not throw") {
@@ -103,6 +134,19 @@ class KotlinAssertionsTests {
103134
assertMessageEquals(exception,
104135
"Does not throw ==> Unexpected exception thrown: org.opentest4j.AssertionFailedError: fail")
105136
},
137+
dynamicTest("for message variant (suspended)") {
138+
runBlocking {
139+
val exception = assertThrows<AssertionError> {
140+
assertDoesNotThrow("Does not throw") {
141+
suspend { fail("fail") }()
142+
}
143+
}
144+
assertMessageEquals(
145+
exception,
146+
"Does not throw ==> Unexpected exception thrown: org.opentest4j.AssertionFailedError: fail"
147+
)
148+
}
149+
},
106150
dynamicTest("for message supplier variant") {
107151
val exception = assertThrows<AssertionError> {
108152
assertDoesNotThrow({ "Does not throw" }) {
@@ -111,6 +155,19 @@ class KotlinAssertionsTests {
111155
}
112156
assertMessageEquals(exception,
113157
"Does not throw ==> Unexpected exception thrown: org.opentest4j.AssertionFailedError: fail")
158+
},
159+
dynamicTest("for message supplier variant (suspended)") {
160+
runBlocking {
161+
val exception = assertThrows<AssertionError> {
162+
assertDoesNotThrow({ "Does not throw" }) {
163+
suspend { fail("fail") }()
164+
}
165+
}
166+
assertMessageEquals(
167+
exception,
168+
"Does not throw ==> Unexpected exception thrown: org.opentest4j.AssertionFailedError: fail"
169+
)
170+
}
114171
}
115172
))
116173
)

0 commit comments

Comments
 (0)