diff --git a/documentation/src/docs/asciidoc/release-notes/release-notes-6.0.0-RC1.adoc b/documentation/src/docs/asciidoc/release-notes/release-notes-6.0.0-RC1.adoc
index 8381557f7970..1b3a5f0a8fd7 100644
--- a/documentation/src/docs/asciidoc/release-notes/release-notes-6.0.0-RC1.adoc
+++ b/documentation/src/docs/asciidoc/release-notes/release-notes-6.0.0-RC1.adoc
@@ -26,8 +26,7 @@ repository on GitHub.
[[release-notes-6.0.0-RC1-junit-platform-new-features-and-improvements]]
==== New Features and Improvements
-* ❓
-
+* Prune stack traces up to test or lifecycle method
[[release-notes-6.0.0-RC1-junit-jupiter]]
=== JUnit Jupiter
diff --git a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ExceptionUtils.java b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ExceptionUtils.java
index cb20454d6fc1..350f443b3ad1 100644
--- a/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ExceptionUtils.java
+++ b/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ExceptionUtils.java
@@ -97,11 +97,15 @@ public static String readStackTrace(Throwable throwable) {
}
/**
- * Prune the stack trace of the supplied {@link Throwable} by removing
- * {@linkplain StackTraceElement stack trace elements} from the {@code org.junit},
- * {@code jdk.internal.reflect}, and {@code sun.reflect} packages. If a
- * {@code StackTraceElement} matching one of the supplied {@code classNames}
- * is encountered, all subsequent elements in the stack trace will be retained.
+ * Prune the stack trace of the supplied {@link Throwable}.
+ *
+ *
Prune all {@linkplain StackTraceElement stack trace elements} up one
+ * of the supplied {@code classNames} are pruned. All subsequent elements
+ * in the stack trace will be retained.
+ *
+ *
If the {@code classNames} do not match any of the stacktrace elements
+ * then the {@code org.junit}, {@code jdk.internal.reflect}, and
+ * {@code sun.reflect} packages are pruned.
*
*
Additionally, all elements prior to and including the first JUnit Platform
* Launcher call will be removed.
@@ -128,6 +132,9 @@ public static void pruneStackTrace(Throwable throwable, List classNames)
String className = element.getClassName();
if (classNames.contains(className)) {
+ // We found the test
+ // everything before that is not informative.
+ prunedStackTrace.clear();
// Include all elements called by the test
prunedStackTrace.addAll(stackTrace.subList(i, stackTrace.size()));
break;
diff --git a/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StackTracePruningEngineExecutionListener.java b/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StackTracePruningEngineExecutionListener.java
index 835a272e0af9..61354ac809b9 100644
--- a/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StackTracePruningEngineExecutionListener.java
+++ b/junit-platform-launcher/src/main/java/org/junit/platform/launcher/core/StackTracePruningEngineExecutionListener.java
@@ -13,6 +13,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Optional;
+import java.util.stream.Stream;
import org.junit.platform.commons.util.ExceptionUtils;
import org.junit.platform.engine.EngineExecutionListener;
@@ -46,8 +47,9 @@ public void executionFinished(TestDescriptor testDescriptor, TestExecutionResult
}
private static List getTestClassNames(TestDescriptor testDescriptor) {
- return testDescriptor.getAncestors() //
- .stream() //
+ Stream extends TestDescriptor> self = Stream.of(testDescriptor);
+ Stream extends TestDescriptor> ancestors = testDescriptor.getAncestors().stream();
+ return Stream.concat(self, ancestors) //
.map(TestDescriptor::getSource) //
.flatMap(Optional::stream) //
.map(source -> {
diff --git a/platform-tests/src/test/java/org/junit/platform/StackTracePruningTests.java b/platform-tests/src/test/java/org/junit/platform/StackTracePruningTests.java
index 5f7b97f88728..83e56373d509 100644
--- a/platform-tests/src/test/java/org/junit/platform/StackTracePruningTests.java
+++ b/platform-tests/src/test/java/org/junit/platform/StackTracePruningTests.java
@@ -115,7 +115,7 @@ void shouldAlwaysKeepJupiterAssumptionStackTraceElement() {
}
@Test
- void shouldKeepEverythingAfterTestCall() {
+ void shouldKeepExactlyEverythingAfterTestCall() {
EngineExecutionResults results = EngineTestKit.engine("junit-jupiter") //
.configurationParameter("junit.platform.stacktrace.pruning.enabled", "true") //
.selectors(selectMethod(FailingTestTestCase.class, "failingAssertion")) //
@@ -128,7 +128,6 @@ void shouldKeepEverythingAfterTestCall() {
\\Qorg.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:\\E.+
\\Qorg.junit.jupiter.api.Assertions.fail(Assertions.java:\\E.+
\\Qorg.junit.platform.StackTracePruningTests$FailingTestTestCase.failingAssertion(StackTracePruningTests.java:\\E.+
- >>>>
""");
}
@@ -136,7 +135,7 @@ void shouldKeepEverythingAfterTestCall() {
@ValueSource(strings = { "org.junit.platform.StackTracePruningTests$FailingBeforeEachTestCase",
"org.junit.platform.StackTracePruningTests$FailingBeforeEachTestCase$NestedTestCase",
"org.junit.platform.StackTracePruningTests$FailingBeforeEachTestCase$NestedTestCase$NestedNestedTestCase" })
- void shouldKeepEverythingAfterLifecycleMethodCall(Class> methodClass) {
+ void shouldKeepExactlyEverythingAfterLifecycleMethodCall(Class> methodClass) {
EngineExecutionResults results = EngineTestKit.engine("junit-jupiter") //
.configurationParameter("junit.platform.stacktrace.pruning.enabled", "true") //
.selectors(selectMethod(methodClass, "test")) //
@@ -149,7 +148,6 @@ void shouldKeepEverythingAfterLifecycleMethodCall(Class> methodClass) {
\\Qorg.junit.jupiter.api.AssertionUtils.fail(AssertionUtils.java:\\E.+
\\Qorg.junit.jupiter.api.Assertions.fail(Assertions.java:\\E.+
\\Qorg.junit.platform.StackTracePruningTests$FailingBeforeEachTestCase.setUp(StackTracePruningTests.java:\\E.+
- >>>>
""");
}