io.cucumber.cucumberexpressions.CucumberExpressionGenerator Maven / Gradle / Ivy
package io.cucumber.cucumberexpressions;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CucumberExpressionGenerator {
private final ParameterTypeRegistry parameterTypeRegistry;
public CucumberExpressionGenerator(ParameterTypeRegistry parameterTypeRegistry) {
this.parameterTypeRegistry = parameterTypeRegistry;
}
public List generateExpressions(String text) {
List>> parameterTypeCombinations = new ArrayList<>();
List parameterTypeMatchers = createParameterTypeMatchers(text);
StringBuilder expressionTemplate = new StringBuilder();
int pos = 0;
while (true) {
List matchingParameterTypeMatchers = new ArrayList<>();
for (ParameterTypeMatcher parameterTypeMatcher : parameterTypeMatchers) {
ParameterTypeMatcher advancedParameterTypeMatcher = parameterTypeMatcher.advanceTo(pos);
if (advancedParameterTypeMatcher.find()) {
matchingParameterTypeMatchers.add(advancedParameterTypeMatcher);
}
}
if (!matchingParameterTypeMatchers.isEmpty()) {
Collections.sort(matchingParameterTypeMatchers);
// Find all the best parameter type matchers, they are all candidates.
ParameterTypeMatcher bestParameterTypeMatcher = matchingParameterTypeMatchers.get(0);
List bestParameterTypeMatchers = new ArrayList<>();
for (ParameterTypeMatcher m : matchingParameterTypeMatchers) {
if (m.compareTo(bestParameterTypeMatcher) == 0) {
bestParameterTypeMatchers.add(m);
}
}
// Build a list of parameter types without duplicates. The reason there
// might be duplicates is that some parameter types have more than one regexp,
// which means multiple ParameterTypeMatcher objects will have a reference to the
// same ParameterType.
// We're sorting the list so preferential parameter types are listed first.
// Users are most likely to want these, so they should be listed at the top.
SortedSet> parameterTypes = new TreeSet<>();
Set> set = new HashSet<>();
for (ParameterTypeMatcher parameterTypeMatcher : bestParameterTypeMatchers) {
ParameterType> parameterType = parameterTypeMatcher.getParameterType();
set.add(parameterType);
}
parameterTypes.addAll(set);
parameterTypeCombinations.add(new ArrayList<>(parameterTypes));
expressionTemplate
.append(escapeForStringFormat(text.substring(pos, bestParameterTypeMatcher.start())))
.append("{%s}");
pos = bestParameterTypeMatcher.start() + bestParameterTypeMatcher.group().length();
} else {
break;
}
if (pos >= text.length()) {
break;
}
}
expressionTemplate.append(escapeForStringFormat(text.substring(pos)));
return new CombinatorialGeneratedExpressionFactory(expressionTemplate.toString(), parameterTypeCombinations).generateExpressions();
}
private String escapeForStringFormat(String s) {
return s.replaceAll("%", "%%");
}
/**
* @param text the text (step) to generate an expression for
* @return the first of the generated expressions
* @deprecated use {@link #generateExpressions(String)}
*/
@Deprecated
public GeneratedExpression generateExpression(String text) {
List generatedExpressions = generateExpressions(text);
return generatedExpressions.get(0);
}
private List createParameterTypeMatchers(String text) {
Collection> parameterTypes = parameterTypeRegistry.getParameterTypes();
List parameterTypeMatchers = new ArrayList<>();
for (ParameterType> parameterType : parameterTypes) {
if (parameterType.useForSnippets()) {
parameterTypeMatchers.addAll(createParameterTypeMatchers(parameterType, text));
}
}
return parameterTypeMatchers;
}
private static List createParameterTypeMatchers(ParameterType> parameterType, String text) {
List result = new ArrayList<>();
List captureGroupRegexps = parameterType.getRegexps();
for (String captureGroupRegexp : captureGroupRegexps) {
Pattern regexp = Pattern.compile("(" + captureGroupRegexp + ")");
Matcher matcher = regexp.matcher(text);
result.add(new ParameterTypeMatcher(parameterType, matcher, text.length()));
}
return result;
}
}