cucumber.runtime.java.Java8StepDefinition Maven / Gradle / Ivy
package cucumber.runtime.java;
import cucumber.api.java8.StepdefBody;
import cucumber.runtime.CucumberException;
import cucumber.runtime.JdkPatternArgumentMatcher;
import cucumber.runtime.ParameterInfo;
import cucumber.runtime.StepDefinition;
import cucumber.runtime.Utils;
import gherkin.I18n;
import gherkin.formatter.Argument;
import gherkin.formatter.model.Step;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;
public class Java8StepDefinition implements StepDefinition {
private final Pattern pattern;
private final long timeoutMillis;
private final StepdefBody body;
private final JdkPatternArgumentMatcher argumentMatcher;
private final StackTraceElement location;
private final List parameterInfos;
private final Method method;
public Java8StepDefinition(Pattern pattern, long timeoutMillis, StepdefBody body, TypeIntrospector typeIntrospector) throws Exception {
this.pattern = pattern;
this.timeoutMillis = timeoutMillis;
this.body = body;
this.argumentMatcher = new JdkPatternArgumentMatcher(pattern);
this.location = new Exception().getStackTrace()[3];
Class extends StepdefBody> bodyClass = body.getClass();
this.method = getAcceptMethod(bodyClass);
this.parameterInfos = getParameterInfos(bodyClass, typeIntrospector, method.getParameterTypes().length);
}
private List getParameterInfos(Class extends StepdefBody> bodyClass, TypeIntrospector typeIntrospector, int parameterCount) throws Exception {
Type genericInterface = bodyClass.getGenericInterfaces()[0];
Type[] argumentTypes;
if (genericInterface instanceof ParameterizedType) {
argumentTypes = ((ParameterizedType) genericInterface).getActualTypeArguments();
} else {
Class extends StepdefBody> interfac3 = (Class extends StepdefBody>) bodyClass.getInterfaces()[0];
argumentTypes = typeIntrospector.getGenericTypes(bodyClass, interfac3);
}
Type[] argumentTypesOfCorrectLength = new Type[parameterCount];
System.arraycopy(argumentTypes, argumentTypes.length - parameterCount, argumentTypesOfCorrectLength, 0, parameterCount);
verifyNotListOrMap(argumentTypesOfCorrectLength);
return ParameterInfo.fromTypes(argumentTypesOfCorrectLength);
}
private Method getAcceptMethod(Class extends StepdefBody> bodyClass) {
List acceptMethods = new ArrayList();
for (Method method : bodyClass.getDeclaredMethods()) {
if (!method.isBridge() && !method.isSynthetic() && "accept".equals(method.getName())) {
acceptMethods.add(method);
}
}
if (acceptMethods.size() != 1) {
throw new IllegalStateException(String.format("Expected single 'accept' method on body class, found " +
"'%s'", acceptMethods));
}
return acceptMethods.get(0);
}
private void verifyNotListOrMap(Type[] argumentTypes) {
for (Type argumentType : argumentTypes) {
if (argumentType instanceof Class) {
Class> argumentClass = (Class>) argumentType;
if (List.class.isAssignableFrom(argumentClass) || Map.class.isAssignableFrom(argumentClass)) {
throw withLocation(new CucumberException("Can't use " + argumentClass.getName() + " in lambda step definition. Declare a DataTable argument instead and convert manually with asList/asLists/asMap/asMaps"));
}
}
}
}
private CucumberException withLocation(CucumberException exception) {
exception.setStackTrace(new StackTraceElement[]{this.location});
return exception;
}
@Override
public List matchedArguments(Step step) {
return argumentMatcher.argumentsFrom(step.getName());
}
@Override
public String getLocation(boolean detail) {
return location.getFileName() + ":" + location.getLineNumber();
}
@Override
public Integer getParameterCount() {
return parameterInfos.size();
}
@Override
public ParameterInfo getParameterType(int n, Type argumentType) throws IndexOutOfBoundsException {
return parameterInfos.get(n);
}
@Override
public void execute(final I18n i18n, final Object[] args) throws Throwable {
Utils.invoke(body, method, timeoutMillis, args);
}
@Override
public boolean isDefinedAt(StackTraceElement stackTraceElement) {
return location.getFileName().equals(stackTraceElement.getFileName());
}
@Override
public String getPattern() {
return pattern.pattern();
}
@Override
public boolean isScenarioScoped() {
return true;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy