package test_util;
import test_util.StringUtils;
import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.BlockJUnit4ClassRunner;
import org.junit.runners.Suite;
import org.junit.runners.model.FrameworkMethod;
import org.junit.runners.model.InitializationError;
import org.junit.runners.model.Statement;
import org.junit.runners.model.TestClass;
import java.lang.annotation.Annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
// Modified version of
// https://github.com/dynacron-group/parallel-webtest/blob/master/src/main/java/com/dynacrongroup/webtest/DescriptivelyParameterized.java
/**
* This is modification of org.junit.runners.Parameterized to descriptively
* parameterize tests. The purpose of this modification is to use parameters in
* the test names instead of set number, so that failures can be traced back to
* the parameters used.
* <p/>
* Note that this class must be used with String parameters; it's not intended
* for general use, only for use with ParallelRunner and WebDriverBase.
*
* To back out the inclusion of this class, you'll need to change the extension
* for ParallelRunner back to "Parameterized" and change the annotation in
* WebDriverBase back to "Parameterized".
*/
@SuppressWarnings("all")
public class DescriptivelyParameterized extends Suite {
/**
* Annotation for a method which provides parameters to be injected into the
* test class constructor by <code>DescriptivelyParameterized</code>
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public static @interface Parameters {
}
private class TestClassRunnerForParameters extends BlockJUnit4ClassRunner {
private final int fParameterSetNumber;
private final List<Object[]> fParameterList;
private final String fParameterDescription;
TestClassRunnerForParameters(Class<?> type,
List<Object[]> parameterList, int i) throws InitializationError {
super(type);
fParameterList = parameterList;
fParameterSetNumber = i;
fParameterDescription = describeParams();
}
@Override
public Object createTest() throws Exception {
return getTestClass().getOnlyConstructor().newInstance(
computeParams());
}
private Object[] computeParams() throws Exception {
try {
return fParameterList.get(fParameterSetNumber);
} catch (ClassCastException e) {
throw new Exception(String.format(
"%s.%s() must return a Collection of arrays.",
getTestClass().getName(),
getParametersMethod(getTestClass()).getName()));
}
}
/*
* Try to describe the parameters by converting to String; if this
* fails, fall back to describing using fParameterSetNumber
*/
private String describeParams() {
String returnValue;
try {
Object[] params = computeParams();
returnValue = formatParams(params);
} catch (Exception e) {
returnValue = null;
}
if (returnValue == null) {
returnValue = ((Integer) fParameterSetNumber).toString();
}
return returnValue;
}
/**
* Override this method to provide custom parameter formatting.
*
* @param params
* @return A formatted string to be appended to the test name.
*/
public String formatParams(Object[] params) {
String formattedParams;
String[] stringParams = (String[]) params;
if (stringParams[1].contains("Driver")) {
String driver = stringParams[1];
formattedParams = driver.substring(driver.lastIndexOf(".") + 1,
driver.lastIndexOf("Driver"));
} else {
// Use undersocre instead of pipe.
formattedParams = StringUtils.join(stringParams, "_");
}
return formattedParams;
}
@Override
protected String getName() {
return String.format("[%s]", fParameterDescription);
}
@Override
protected String testName(final FrameworkMethod method) {
return String.format("%s[%s]", method.getName(),
fParameterDescription);
}
@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];
// }
}
private final ArrayList<Runner> runners = new ArrayList<Runner>();
/**
* Only called reflectively. Do not use programmatically.
*/
public DescriptivelyParameterized(Class<?> klass) throws Throwable {
super(klass, Collections.<Runner> emptyList());
List<Object[]> parametersList = getParametersList(getTestClass());
for (int i = 0; i < parametersList.size(); i++)
runners.add(new TestClassRunnerForParameters(getTestClass()
.getJavaClass(), parametersList, i));
}
@Override
protected List<Runner> getChildren() {
return runners;
}
@SuppressWarnings("unchecked")
private List<Object[]> getParametersList(TestClass klass) throws Throwable {
return (List<Object[]>) getParametersMethod(klass).invokeExplosively(
null);
}
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());
}
}