package org.junit.runners;
/** This class is a minor modification of org.junit.runners.Parameterized. The changes are (1) to log
* tests whose assumptions are false as ignored instead of failed, and (2) to allow
* inserting the parameter values instead of an index as the name of a test.
* <BR>
* The class still uses org.junit.runners.Parameterized.Parameters to identify the data method.
* <BR>
* The inner class TestClassRunnerForParameters would better be an extension of
* org.junit.runner.Parameterized.TestClassRunnerForParameters, but that class is private to Parameterized.
* Also, we would prefer to inherit from Parameterized instead of from Suite, but all the methods
* of Parameterized are private and we need to use ParameterizedWithNames.TestClassRunnerForParameters
* in the ParameterizedWithNames constructor, so we have to copy all the methods from Parameterized
* into this class.
*/
import java.lang.annotation.Annotation;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.junit.Ignore;
import org.junit.internal.AssumptionViolatedException;
import org.junit.internal.runners.model.EachTestNotifier;
import org.junit.runner.Description;
import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.Parameterized.Parameters;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import org.junit.runners.model.TestClass;
public class ParameterizedWithNames extends Suite
{
protected Class<?> klass; // DRC - a change to the original to make it easy to refer to this input
private final ArrayList<Runner> runners = new ArrayList<Runner>();
public ParameterizedWithNames(Class<?> klass) throws Throwable {
super(klass, Collections.<Runner>emptyList());
this.klass = klass; // DRC - a change to the original
List<Object[]> parametersList = getParametersList(getTestClass());
for (int i = 0; i < parametersList.size(); ++i)
this.runners.add(new TestClassRunnerForParameters(parametersList, i));
}
@Override
protected List<Runner> getChildren() {
return this.runners;
}
@SuppressWarnings("unchecked")
private List<Object[]> getParametersList(TestClass klass) throws Throwable {
return ((List<Object[]>)getParametersMethod(klass).invokeExplosively(null, new Object[0]));
}
private FrameworkMethod getParametersMethod(TestClass testClass) throws Exception {
List<FrameworkMethod> methods = testClass.getAnnotatedMethods(Parameters.class);
for (FrameworkMethod each : methods) {
int modifiers = each.getMethod().getModifiers();
if ((Modifier.isStatic(modifiers)) && (Modifier.isPublic(modifiers))) {
return each;
}
}
throw new Exception("No public static parameters method on class " + testClass.getName()); //$NON-NLS-1$
}
private class TestClassRunnerForParameters extends BlockJUnit4ClassRunner {
private final int fParameterSetNumber;
private final List<Object[]> fParameterList;
TestClassRunnerForParameters(List<Object[]> parameterList, int i) throws InitializationError {
super(klass);
this.fParameterList = parameterList;
this.fParameterSetNumber = i;
}
@Override
public Object createTest() throws Exception {
return getTestClass().getOnlyConstructor().newInstance(computeParams());
}
private Object[] computeParams() throws Exception {
try {
return (this.fParameterList.get(this.fParameterSetNumber));
} catch (ClassCastException e) {
throw new Exception(String.format("%s.%s() must return a Collection of arrays.", new Object[] { getTestClass().getName(), getTestClass().getName() })); //$NON-NLS-1$
}
}
// This method is changed to have the name be a combination of the parameters
// (This is the whole purpose of this revision of Parameterized)
public String name() {
Object[] params = (this.fParameterList.get(this.fParameterSetNumber));
String s = "";
boolean first = true;
for (Object o: params) {
if (first) first = false; else s = s + ",";
s = s + toString(o);
}
return s;
}
String toString(Object o) {
if (o == null) {
return "null";
} else if (o.getClass().isArray()) {
return arrayToString((Object[])o);
} else if (o instanceof String) {
return o.toString();
//return "\"" + o.toString() + "\"";
} else {
return o.toString();
}
}
String arrayToString(Object[] array) {
String s = "[";
boolean first = true;
for (Object o: (Object[])array) {
if (first) first = false; else s = s + ",";
s = s + toString(o);
}
s = s + "]";
return s;
}
@Override
protected String getName() {
// DRC - changed to use the parameter list, rather than the index
return String.format("[%s]", new Object[] { name() }); //$NON-NLS-1$
}
@Override
protected String testName(FrameworkMethod method) {
// DRC - changed to use the parameter list, rather than the index
return String.format("%s[%s]", new Object[] { method.getName(), name() }); //$NON-NLS-1$
}
@Override
protected void validateConstructor(List<Throwable> errors) {
validateOnlyOneConstructor(errors);
}
@Override
protected Statement classBlock(RunNotifier notifier) {
return childrenInvoker(notifier);
}
@Override
protected Annotation[] getRunnerAnnotations() {
return new Annotation[0];
}
@Override
protected void runChild(final FrameworkMethod method, RunNotifier notifier) {
Description description= describeChild(method);
if (method.getAnnotation(Ignore.class) != null) {
notifier.fireTestIgnored(description);
} else {
//runLeaf(methodBlock(method), description, notifier);
Statement statement = methodBlock(method);
EachTestNotifier eachNotifier= new EachTestNotifier(notifier, description);
eachNotifier.fireTestStarted();
try {
statement.evaluate();
} catch (AssumptionViolatedException e) {
eachNotifier.fireTestIgnored();
} catch (Throwable e) {
eachNotifier.addFailure(e);
} finally {
eachNotifier.fireTestFinished();
}
}
}
}
}