/******************************************************************************* * Copyright Technophobia Ltd 2012 * * This file is part of the Substeps Eclipse Plugin. * * The Substeps Eclipse Plugin is free software: you can redistribute it and/or modify * it under the terms of the Eclipse Public License v1.0. * * The Substeps Eclipse Plugin is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * Eclipse Public License for more details. * * You should have received a copy of the Eclipse Public License * along with the Substeps Eclipse Plugin. If not, see <http://www.eclipse.org/legal/epl-v10.html>. ******************************************************************************/ package com.technophobia.substeps.junit.ui; import java.io.BufferedReader; import java.io.IOException; import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import com.technophobia.substeps.table.LineType; public class TextualTrace { public static final int LINE_TYPE_EXCEPTION = 1; public static final int LINE_TYPE_NORMAL = 0; public static final int LINE_TYPE_STACKFRAME = 2; private final String fTrace; public TextualTrace(final String trace, final String[] filterPatterns) { super(); fTrace = filterStack(trace, filterPatterns); } public void display(final TraceDisplay display, final int maxLabelLength) { final StringReader stringReader = new StringReader(fTrace); final BufferedReader bufferedReader = new BufferedReader(stringReader); String line; try { // first line contains the thrown exception line = readLine(bufferedReader); if (line == null) return; displayWrappedLine(display, maxLabelLength, line, LineType.EXCEPTION); // the stack frames of the trace while ((line = readLine(bufferedReader)) != null) { final LineType type = isAStackFrame(line) ? LineType.STACK : LineType.NORMAL; displayWrappedLine(display, maxLabelLength, line, type); } } catch (final IOException e) { display.addTraceLine(LineType.NORMAL, fTrace); } } private void displayWrappedLine(final TraceDisplay display, final int maxLabelLength, final String line, final LineType type) { final int labelLength = line.length(); if (labelLength < maxLabelLength) { display.addTraceLine(type, line); } else { // workaround for bug 74647: JUnit view truncates // failure message display.addTraceLine(type, line.substring(0, maxLabelLength)); int offset = maxLabelLength; while (offset < labelLength) { final int nextOffset = Math.min(labelLength, offset + maxLabelLength); display.addTraceLine(LineType.NORMAL, line.substring(offset, nextOffset)); offset = nextOffset; } } } private boolean filterLine(final String[] patterns, final String line) { String pattern; int len; for (int i = (patterns.length - 1); i >= 0; --i) { pattern = patterns[i]; len = pattern.length() - 1; if (pattern.length() > 0) { if (pattern.charAt(len) == '*') { // strip trailing * from a package filter pattern = pattern.substring(0, len); } else if (Character.isUpperCase(pattern.charAt(0))) { // class in the default package pattern = FailureTrace.FRAME_PREFIX + pattern + '.'; } else { // class names start w/ an uppercase letter after the . final int lastDotIndex = pattern.lastIndexOf('.'); if ((lastDotIndex != -1) && (lastDotIndex != len) && Character.isUpperCase(pattern.charAt(lastDotIndex + 1))) pattern += '.'; // append . to a class filter } if (line.indexOf(pattern) > 0) return true; } } return false; } private String filterStack(final String stackTrace, final String[] filterPatterns) { if (filterPatterns.length == 0 || stackTrace == null) return stackTrace; final StringWriter stringWriter = new StringWriter(); final PrintWriter printWriter = new PrintWriter(stringWriter); final StringReader stringReader = new StringReader(stackTrace); final BufferedReader bufferedReader = new BufferedReader(stringReader); String line; final String[] patterns = filterPatterns; try { while ((line = bufferedReader.readLine()) != null) { if (!filterLine(patterns, line)) printWriter.println(line); } } catch (final IOException e) { return stackTrace; // return the stack unfiltered } return stringWriter.toString(); } private boolean isAStackFrame(final String itemLabel) { // heuristic for detecting a stack frame - works for JDK return itemLabel.indexOf(" at ") >= 0; //$NON-NLS-1$ } private String readLine(final BufferedReader bufferedReader) throws IOException { final String readLine = bufferedReader.readLine(); return readLine == null ? null : readLine.replace('\t', ' '); } }