All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.apache.maven.surefire.report.SmartStackTraceParser Maven / Gradle / Ivy
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.maven.surefire.report;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.maven.surefire.api.report.SafeThrowable;
import static java.util.Arrays.asList;
import static java.util.Collections.reverse;
import static org.apache.maven.surefire.shared.utils.StringUtils.chompLast;
import static org.apache.maven.surefire.shared.utils.StringUtils.isNotEmpty;
/**
* @author Kristian Rosenvold
*/
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
public class SmartStackTraceParser {
private final SafeThrowable throwable;
private final StackTraceElement[] stackTrace;
private final String testClassName;
private final Class> testClass;
private final String testMethodName;
public SmartStackTraceParser(String testClassName, Throwable throwable, String testMethodName) {
this.testMethodName = testMethodName;
this.testClassName = testClassName;
testClass = toClass(testClassName);
this.throwable = new SafeThrowable(throwable);
stackTrace = throwable.getStackTrace();
}
private static Class> toClass(String name) {
try {
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
return classLoader == null ? null : classLoader.loadClass(name);
} catch (ClassNotFoundException e) {
return null;
}
}
private static String toSimpleClassName(String className) {
int i = className.lastIndexOf(".");
return className.substring(i + 1);
}
@SuppressWarnings("ThrowableResultOfMethodCallIgnored")
public String getString() {
if (testClass == null) {
return throwable.getLocalizedMessage();
}
final StringBuilder result = new StringBuilder();
final List stackTraceElements = focusOnClass(stackTrace, testClass);
reverse(stackTraceElements);
final String testClassSimpleName = toSimpleClassName(testClassName);
if (stackTraceElements.isEmpty()) {
result.append(testClassSimpleName);
if (isNotEmpty(testMethodName)) {
result.append(".").append(testMethodName);
}
} else {
for (int i = 0, size = stackTraceElements.size(); i < size; i++) {
final StackTraceElement stackTraceElement = stackTraceElements.get(i);
final boolean isTestClassName = stackTraceElement.getClassName().equals(testClassName);
if (i == 0) {
result.append(testClassSimpleName).append(isTestClassName ? '.' : '>');
}
if (!isTestClassName) {
result.append(toSimpleClassName(stackTraceElement.getClassName()))
.append('.');
}
result.append(stackTraceElement.getMethodName())
.append(':')
.append(stackTraceElement.getLineNumber())
.append("->");
}
if (result.length() >= 2) {
result.setLength(result.length() - 2);
}
}
final Throwable target = throwable.getTarget();
final Class> excType = target.getClass();
final String excClassName = excType.getName();
final String msg = throwable.getMessage();
if (!(target instanceof AssertionError
|| "junit.framework.AssertionFailedError".equals(excClassName)
|| "junit.framework.ComparisonFailure".equals(excClassName)
|| excClassName.startsWith("org.opentest4j."))) {
result.append(rootIsInclass() ? " " : " » ").append(toMinimalThrowableMiniMessage(excType));
}
if (isNotEmpty(msg)) {
result.append(' ').append(msg);
}
return result.toString();
}
private static String toMinimalThrowableMiniMessage(Class> excType) {
String name = excType.getSimpleName();
if (name.endsWith("Exception")) {
return chompLast(name, "Exception");
}
if (name.endsWith("Error")) {
return chompLast(name, "Error");
}
return name;
}
private boolean rootIsInclass() {
return stackTrace != null
&& stackTrace.length > 0
&& stackTrace[0].getClassName().equals(testClassName);
}
private static List focusOnClass(StackTraceElement[] stackTrace, Class> clazz) {
if (stackTrace == null) {
return Collections.emptyList();
}
List result = new ArrayList<>();
for (StackTraceElement element : stackTrace) {
if (element != null && isInSupers(clazz, element.getClassName())) {
result.add(element);
}
}
return result;
}
private static boolean isInSupers(Class> testClass, String lookFor) {
if (lookFor.startsWith("junit.framework.")) {
return false;
}
while (!testClass.getName().equals(lookFor) && testClass.getSuperclass() != null) {
testClass = testClass.getSuperclass();
}
return testClass.getName().equals(lookFor);
}
static Throwable findTopmostWithClass(final Throwable t, StackTraceFilter filter) {
Throwable n = t;
do {
if (containsClassName(n.getStackTrace(), filter)) {
return n;
}
n = n.getCause();
} while (n != null);
return t;
}
public static String stackTraceWithFocusOnClassAsString(Throwable t, String className) {
StackTraceFilter filter = new ClassNameStackTraceFilter(className);
Throwable topmost = findTopmostWithClass(t, filter);
List stackTraceElements = focusInsideClass(topmost.getStackTrace(), filter);
String s = causeToString(topmost.getCause(), filter);
return toString(t, stackTraceElements, filter) + s;
}
static List focusInsideClass(StackTraceElement[] stackTrace, StackTraceFilter filter) {
List result = new ArrayList<>();
for (StackTraceElement element : stackTrace) {
if (filter.matches(element)) {
result.add(element);
}
}
return result;
}
private static boolean containsClassName(StackTraceElement[] stackTrace, StackTraceFilter filter) {
for (StackTraceElement element : stackTrace) {
if (filter.matches(element)) {
return true;
}
}
return false;
}
private static String causeToString(Throwable cause, StackTraceFilter filter) {
StringBuilder resp = new StringBuilder();
while (cause != null) {
resp.append("Caused by: ");
resp.append(toString(cause, asList(cause.getStackTrace()), filter));
cause = cause.getCause();
}
return resp.toString();
}
private static String toString(Throwable t, Iterable elements, StackTraceFilter filter) {
StringBuilder result = new StringBuilder();
if (t != null) {
result.append(t.getClass().getName());
String msg = t.getMessage();
if (msg != null) {
result.append(": ");
if (isMultiLine(msg)) {
// SUREFIRE-986
result.append('\n');
}
result.append(msg);
}
result.append('\n');
}
for (StackTraceElement element : elements) {
if (filter.matches(element)) {
result.append("\tat ").append(element).append('\n');
}
}
return result.toString();
}
private static boolean isMultiLine(String msg) {
int countNewLines = 0;
for (int i = 0, length = msg.length(); i < length; i++) {
if (msg.charAt(i) == '\n') {
if (++countNewLines == 2) {
break;
}
}
}
return countNewLines > 1 || countNewLines == 1 && !msg.trim().endsWith("\n");
}
}