Skip to content

Commit 81fe75d

Browse files
committed
Experimental code to filter stack traces
1 parent f3fc110 commit 81fe75d

File tree

4 files changed

+189
-5
lines changed

4 files changed

+189
-5
lines changed

src/main/java/junit/runner/BaseTestRunner.java

+4
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import junit.framework.Test;
2020
import junit.framework.TestListener;
2121
import junit.framework.TestSuite;
22+
import org.junit.internal.StackTraceFilterer;
2223

2324
/**
2425
* Base class for all test runners.
@@ -268,6 +269,9 @@ public static String getFilteredTrace(Throwable e) {
268269
PrintWriter writer = new PrintWriter(stringWriter);
269270
e.printStackTrace(writer);
270271
String trace = stringWriter.toString();
272+
if (!showStackRaw()) {
273+
return StackTraceFilterer.getFilteredTrace(e, trace);
274+
}
271275
return BaseTestRunner.getFilteredTrace(trace);
272276
}
273277

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
package org.junit.internal;
2+
3+
import java.io.BufferedReader;
4+
import java.io.IOException;
5+
import java.io.StringReader;
6+
import java.util.AbstractList;
7+
import java.util.ArrayList;
8+
import java.util.Collections;
9+
import java.util.List;
10+
11+
/**
12+
* @author [email protected] (Kevin Cooney)
13+
*
14+
*/
15+
public class StackTraceFilterer {
16+
private StackTraceFilterer() {
17+
}
18+
19+
public static String getFilteredTrace(Throwable exception, String fullTrace) {
20+
String header = exception.toString();
21+
StringBuilder filteredTrace = new StringBuilder(header);
22+
BufferedReader reader = new BufferedReader(
23+
new StringReader(fullTrace.substring(header.length())));
24+
25+
try {
26+
// Collect the stack trace lines for "exception" (but not the cause).
27+
List<String> stackTraceLines = new ArrayList<String>();
28+
String line;
29+
while ((line = reader.readLine()) != null) {
30+
if (line.startsWith("Caused by: ")) {
31+
break;
32+
}
33+
stackTraceLines.add(line);
34+
}
35+
if (stackTraceLines.isEmpty()) {
36+
// No stack trace?
37+
return fullTrace;
38+
}
39+
stackTraceLines = filterStackTraceLines(stackTraceLines);
40+
if (stackTraceLines.isEmpty()) {
41+
// Could not filter
42+
return fullTrace;
43+
}
44+
appendStackTraceLines(filteredTrace, stackTraceLines);
45+
if (line != null) {
46+
// Print remaining stacktrace
47+
do {
48+
filteredTrace.append(line).append("\n");
49+
line = reader.readLine();
50+
} while (line != null);
51+
}
52+
return filteredTrace.toString();
53+
} catch (IOException e) {
54+
}
55+
return fullTrace;
56+
}
57+
58+
private static void appendStackTraceLines(StringBuilder filteredTrace,
59+
List<String> firstExceptionStackTraceLines) {
60+
for (String firstExceptionStackTraceLine : firstExceptionStackTraceLines) {
61+
filteredTrace.append(firstExceptionStackTraceLine).append("\n");
62+
}
63+
}
64+
65+
private static List<String> filterStackTraceLines(List<String> stackTraceLines) {
66+
State state = State.ProcessingOtherCode;
67+
int linesToInclude = stackTraceLines.size();
68+
for (String stackTraceLine : asReversedList(stackTraceLines)) {
69+
state = state.processLine(stackTraceLine);
70+
if (state == State.Done) {
71+
List<String> filteredLines = new ArrayList<String>(
72+
stackTraceLines.subList(0, linesToInclude));
73+
filteredLines.add(
74+
"\t..." + (stackTraceLines.size() - filteredLines.size()) + "more");
75+
return filteredLines;
76+
}
77+
linesToInclude--;
78+
}
79+
return Collections.emptyList();
80+
}
81+
82+
private static <T> List<T> asReversedList(final List<T> list) {
83+
return new AbstractList<T>() {
84+
85+
@Override
86+
public T get(int index) {
87+
return list.get(list.size() - index - 1);
88+
}
89+
90+
@Override
91+
public int size() {
92+
return list.size();
93+
}
94+
};
95+
}
96+
97+
private enum State {
98+
ProcessingOtherCode {
99+
@Override public State processLine(String line) {
100+
if (isJunitTraceLine(line)) {
101+
return ProcessingJunitCodeState;
102+
}
103+
return this;
104+
}
105+
},
106+
ProcessingJunitCodeState {
107+
@Override public State processLine(String line) {
108+
if (isJunitTraceLine(line)) {
109+
return this;
110+
} else if (isReflectionTraceLine(line)) {
111+
return ProcessingReflectionCode;
112+
}
113+
return ProcessingOtherCode;
114+
}
115+
},
116+
ProcessingReflectionCode {
117+
@Override public State processLine(String line) {
118+
if (isReflectionTraceLine(line)) {
119+
return this;
120+
}
121+
return Done;
122+
}
123+
},
124+
Done {
125+
@Override public State processLine(String line) {
126+
return this;
127+
}
128+
};
129+
130+
/** Processes a stack trace line, possibly moving to a new state. */
131+
public abstract State processLine(String line);
132+
}
133+
134+
private static final String[] JUNIT_PACKAGE_PREFIXES = {
135+
"org.junit.",
136+
"junit.",
137+
"org.apache.maven.surefire."
138+
};
139+
140+
private static boolean isJunitTraceLine(String line) {
141+
return isTraceLine(line, JUNIT_PACKAGE_PREFIXES);
142+
}
143+
144+
private static final String[] REFLECTION_PACKAGE_PREFIXES = {
145+
"sun.reflect.",
146+
"java.lang.reflect."
147+
};
148+
149+
private static boolean isReflectionTraceLine(String line) {
150+
return isTraceLine(line, REFLECTION_PACKAGE_PREFIXES);
151+
}
152+
153+
private static boolean isTraceLine(String line, String[] packagePrefixes) {
154+
if (!line.startsWith("\tat ")) {
155+
return false;
156+
}
157+
line = line.substring(4);
158+
for (String packagePrefix : packagePrefixes) {
159+
if (line.startsWith(packagePrefix)) {
160+
return true;
161+
}
162+
}
163+
164+
return false;
165+
}
166+
}

src/main/java/org/junit/internal/TextListener.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ protected void printFailures(Result result) {
7474

7575
protected void printFailure(Failure each, String prefix) {
7676
getWriter().println(prefix + ") " + each.getTestHeader());
77-
getWriter().print(each.getTrace());
77+
getWriter().print(each.getFilteredTrace());
7878
}
7979

8080
protected void printFooter(Result result) {

src/main/java/org/junit/runner/notification/Failure.java

+18-4
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.io.Serializable;
55
import java.io.StringWriter;
66

7+
import org.junit.internal.StackTraceFilterer;
78
import org.junit.runner.Description;
89

910
/**
@@ -65,14 +66,27 @@ public String toString() {
6566
}
6667

6768
/**
68-
* Convenience method
69-
*
70-
* @return the printed form of the exception
69+
* Gets the printed form of the exception and its stacktrace.
7170
*/
7271
public String getTrace() {
72+
return getTrace(getException());
73+
}
74+
75+
/**
76+
* Gets a filtered version of the printed form of the exception and its stacktrace.
77+
* This method will attempt to filter out frames of the stack trace that are below
78+
* the method call
79+
*/
80+
public String getFilteredTrace() {
81+
Throwable exception = getException();
82+
String fullTrace = getTrace(exception);
83+
return StackTraceFilterer.getFilteredTrace(exception, fullTrace);
84+
}
85+
86+
private static String getTrace(Throwable exception) {
7387
StringWriter stringWriter = new StringWriter();
7488
PrintWriter writer = new PrintWriter(stringWriter);
75-
getException().printStackTrace(writer);
89+
exception.printStackTrace(writer);
7690
return stringWriter.toString();
7791
}
7892

0 commit comments

Comments
 (0)