Skip to content

Commit a75d16f

Browse files
committed
Prune org.junit.start from exceptions
When using `JUnit.start` the `pruneStackTrace` algorithm immediately sees the `TestClass.main` frame and assumes that this is the test method because the test class name matches. ``` org.opentest4j.AssertionFailedError: expected: <11> but was: <12> at org.junit.jupiter.api@6.1.0-SNAPSHOT/org.junit.jupiter.api.AssertionFailureBuilder.build(AssertionFailureBuilder.java:158) at org.junit.jupiter.api@6.1.0-SNAPSHOT/org.junit.jupiter.api.AssertionFailureBuilder.buildAndThrow(AssertionFailureBuilder.java:139) at org.junit.jupiter.api@6.1.0-SNAPSHOT/org.junit.jupiter.api.AssertEquals.failNotEqual(AssertEquals.java:201) at org.junit.jupiter.api@6.1.0-SNAPSHOT/org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:152) at org.junit.jupiter.api@6.1.0-SNAPSHOT/org.junit.jupiter.api.AssertEquals.assertEquals(AssertEquals.java:147) at org.junit.jupiter.api@6.1.0-SNAPSHOT/org.junit.jupiter.api.Assertions.assertEquals(Assertions.java:558) at com.examp.project/com.example.project.HelloTest.stringLength(HelloTest.java:14) at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104) ... at org.junit.platform.launcher@6.1.0-SNAPSHOT/org.junit.platform.launcher.core.SessionPerRequestLauncher.execute(SessionPerRequestLauncher.java:81) at org.junit.start@6.1.0-SNAPSHOT/org.junit.start.JUnit.run(JUnit.java:63) at org.junit.start@6.1.0-SNAPSHOT/org.junit.start.JUnit.run(JUnit.java:37) at com.examp.project/com.example.project.HelloTest.main(HelloTest.java:9) ``` By checking if `org.junit.start` is involved further down the stack we exclude this scenario.
1 parent 49ba3f2 commit a75d16f

File tree

2 files changed

+28
-1
lines changed

2 files changed

+28
-1
lines changed

junit-platform-commons/src/main/java/org/junit/platform/commons/util/ExceptionUtils.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,7 @@ public static void pruneStackTrace(Throwable throwable, List<String> classNames)
133133
StackTraceElement element = stackTrace.get(i);
134134
String className = element.getClassName();
135135

136-
if (classNames.contains(className)) {
136+
if (classNames.contains(className) && !includesJunitStart(stackTrace, i + 1)) {
137137
// We found the test
138138
// everything before that is not informative.
139139
prunedStackTrace.clear();
@@ -156,6 +156,13 @@ else if (STACK_TRACE_ELEMENT_FILTER.test(className)) {
156156
throwable.setStackTrace(prunedStackTrace.toArray(new StackTraceElement[0]));
157157
}
158158

159+
private static boolean includesJunitStart(List<StackTraceElement> stackTrace, int fromIndex) {
160+
return stackTrace.stream() //
161+
.skip(fromIndex) //
162+
.map(StackTraceElement::getClassName) //
163+
.anyMatch(className -> className.startsWith(JUNIT_START_PACKAGE_PREFIX));
164+
}
165+
159166
/**
160167
* Find all causes and suppressed exceptions in the stack trace of the
161168
* supplied {@link Throwable}.

platform-tests/src/test/java/org/junit/platform/commons/util/ExceptionUtilsTests.java

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import static org.junit.platform.commons.util.ExceptionUtils.throwAsUncheckedException;
2020

2121
import java.io.IOException;
22+
import java.util.Arrays;
2223
import java.util.List;
2324

2425
import org.junit.jupiter.api.Test;
@@ -104,6 +105,25 @@ void pruneStackTraceOfEverythingPriorToFirstLauncherCall() {
104105
.noneMatch(element -> element.toString().contains("org.example.Class.method(file:123)"));
105106
}
106107

108+
@Test
109+
void pruneStackTraceOfJUnitStart() {
110+
var testClassName = ExceptionUtilsTests.class.getCanonicalName();
111+
112+
var exception = new JUnitException("expected");
113+
var stackTrace = exception.getStackTrace();
114+
115+
var extendedStacktrace = Arrays.copyOfRange(stackTrace, 0, stackTrace.length + 2);
116+
extendedStacktrace[stackTrace.length] = new StackTraceElement("org.junit.start.JUnit", "run", "JUnit.class", 3);
117+
extendedStacktrace[stackTrace.length + 1] = new StackTraceElement(testClassName, "main",
118+
"ExceptionUtilsTest.class", 5);
119+
exception.setStackTrace(extendedStacktrace);
120+
121+
pruneStackTrace(exception, List.of(testClassName));
122+
123+
assertThat(exception.getStackTrace()) //
124+
.noneMatch(element -> element.toString().contains(testClassName + ".main(file:5)"));
125+
}
126+
107127
@Test
108128
void findSuppressedExceptionsAndCausesOfThrowable() {
109129
Throwable t1 = new Throwable("#1");

0 commit comments

Comments
 (0)