blob: 38cd26f1149bcec9b349e32dca593cd33c38c843 [file] [log] [blame]
package android.icu.junit;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.manipulation.Filter;
import org.junit.runner.manipulation.Filterable;
import org.junit.runner.manipulation.NoTestsRemainException;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.model.InitializationError;
/**
* A copy of the JUnit 4.10 {@link org.junit.internal.runners.ErrorReportingRunner} class.
*
* <p>Modified as follows:</p>
*
* <ul>
* <li>allows the class in error to be specified by name rather than {@link Class} object so that it
* can be used for when the class could not be found. See
* {@link #ErrorReportingRunner(String, Throwable)} and
* {@link #fTestClassName}.
* <li>supports filtering of the individual causes. See {@link #filter(Filter)}.
* <li>uses the cause to construct the description allowing filtering on specific error messages.
* See {@link #describeCause(Throwable)}.
* </ul>
*
* See https://github.com/junit-team/junit/issues/1253
*/
// android-changed - implements Filterable
class ErrorReportingRunner extends Runner implements Filterable {
private final List<Throwable> fCauses;
// android-changed - changed type from Class<?> and renamed from fTestClass.
private final String fTestClassName;
public ErrorReportingRunner(String testClassName, Throwable cause) {
fTestClassName = testClassName;
// Take a copy so that they can be modified during filtering if necessary.
fCauses = new ArrayList<>(getCauses(cause));
}
// end android-changed
@Override
public Description getDescription() {
// android-changed - renamed from fTestClass.
Description description= Description.createSuiteDescription(fTestClassName);
// end android-changed
for (Throwable each : fCauses)
description.addChild(describeCause(each));
return description;
}
@Override
public void run(RunNotifier notifier) {
for (Throwable each : fCauses)
runCause(each, notifier);
}
// android-changed - added filtering support
@Override
public void filter(Filter filter) throws NoTestsRemainException {
Iterator<Throwable> iterator = fCauses.iterator();
while (iterator.hasNext()) {
Throwable cause = iterator.next();
Description description = describeCause(cause);
if (!filter.shouldRun(description)) {
iterator.remove();
}
}
// If there are no causes left then throw an exception to cause the parent runner, if any,
// to remove this runner from its list.
if (fCauses.isEmpty()) {
throw new NoTestsRemainException();
}
}
// end android-changed
@SuppressWarnings("deprecation")
private List<Throwable> getCauses(Throwable cause) {
if (cause instanceof InvocationTargetException)
return getCauses(cause.getCause());
if (cause instanceof InitializationError)
return ((InitializationError) cause).getCauses();
if (cause instanceof org.junit.internal.runners.InitializationError)
return ((org.junit.internal.runners.InitializationError) cause)
.getCauses();
return Arrays.asList(cause);
}
private Description describeCause(Throwable child) {
// android-changed - create a description that incorporates the cause
// Extract the first line of the message, exclude any special characters that could
// cause problems with later parsing of the description.
String message = child.getMessage();
Matcher matcher = Pattern.compile("^([^()\n]*).*").matcher(message);
if (matcher.matches()) {
message = matcher.group(1);
}
// Create a suite description (need to use that method because the createTestDescription
// methods use a class rather than a class name).
String causeClassName = child.getClass().getName();
return Description.createSuiteDescription(
String.format("initializationError[%s: %s](%s)",
causeClassName, message, fTestClassName));
// end android-changed
}
private void runCause(Throwable child, RunNotifier notifier) {
Description description= describeCause(child);
notifier.fireTestStarted(description);
notifier.fireTestFailure(new Failure(description, child));
notifier.fireTestFinished(description);
}
}