cucumber.runtime.RuntimeGlue Maven / Gradle / Ivy
package cucumber.runtime;
import io.cucumber.stepexpression.Argument;
import cucumber.api.StepDefinitionReporter;
import gherkin.pickles.PickleStep;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
public class RuntimeGlue implements Glue {
final Map stepDefinitionsByPattern = new TreeMap();
final List beforeHooks = new ArrayList();
final List beforeStepHooks = new ArrayList();
final List afterHooks = new ArrayList();
final List afterStepHooks = new ArrayList();
final Map matchedStepDefinitionsCache = new HashMap();
@Override
public void addStepDefinition(StepDefinition stepDefinition) {
StepDefinition previous = stepDefinitionsByPattern.get(stepDefinition.getPattern());
if (previous != null) {
throw new DuplicateStepDefinitionException(previous, stepDefinition);
}
stepDefinitionsByPattern.put(stepDefinition.getPattern(), stepDefinition);
}
@Override
public void addBeforeHook(HookDefinition hookDefinition) {
beforeHooks.add(hookDefinition);
Collections.sort(beforeHooks, new HookComparator(true));
}
@Override
public void addBeforeStepHook(HookDefinition hookDefinition) {
beforeStepHooks.add(hookDefinition);
Collections.sort(beforeStepHooks, new HookComparator(true));
}
@Override
public void addAfterHook(HookDefinition hookDefinition) {
afterHooks.add(hookDefinition);
Collections.sort(afterHooks, new HookComparator(false));
}
@Override
public void addAfterStepHook(HookDefinition hookDefinition) {
afterStepHooks.add(hookDefinition);
Collections.sort(afterStepHooks, new HookComparator(false));
}
@Override
public List getBeforeHooks() {
return beforeHooks;
}
@Override
public List getBeforeStepHooks() {
return beforeStepHooks;
}
@Override
public List getAfterHooks() {
return afterHooks;
}
@Override
public List getAfterStepHooks() {
return afterStepHooks;
}
@Override
public PickleStepDefinitionMatch stepDefinitionMatch(String featurePath, PickleStep step) {
String stepText = step.getText();
CacheEntry cacheEntry = matchedStepDefinitionsCache.get(stepText);
if (cacheEntry != null) {
return new PickleStepDefinitionMatch(Collections.emptyList(), cacheEntry.stepDefinition, featurePath, step);
}
List matches = stepDefinitionMatches(featurePath, step);
if (matches.isEmpty()) {
return null;
}
if (matches.size() > 1) {
throw new AmbiguousStepDefinitionsException(step, matches);
}
PickleStepDefinitionMatch match = matches.get(0);
// We can only cache step definitions without arguments.
// DocString and TableArguments are not included in the stepText used as the cache key.
if(match.getArguments().isEmpty()) {
matchedStepDefinitionsCache.put(stepText, new CacheEntry(match.getStepDefinition()));
}
return match;
}
private List stepDefinitionMatches(String featurePath, PickleStep step) {
List result = new ArrayList();
for (StepDefinition stepDefinition : stepDefinitionsByPattern.values()) {
List arguments = stepDefinition.matchedArguments(step);
if (arguments != null) {
result.add(new PickleStepDefinitionMatch(arguments, stepDefinition, featurePath, step));
}
}
return result;
}
@Override
public void reportStepDefinitions(StepDefinitionReporter stepDefinitionReporter) {
for (StepDefinition stepDefinition : stepDefinitionsByPattern.values()) {
stepDefinitionReporter.stepDefinition(stepDefinition);
}
}
@Override
public void removeScenarioScopedGlue() {
removeScenarioScopedHooks(beforeHooks);
removeScenarioScopedHooks(beforeStepHooks);
removeScenarioScopedHooks(afterHooks);
removeScenarioScopedHooks(afterStepHooks);
removeScenarioScopedStepdefs();
}
private void removeScenarioScopedHooks(List beforeHooks1) {
Iterator hookIterator = beforeHooks1.iterator();
while (hookIterator.hasNext()) {
HookDefinition hook = hookIterator.next();
if (hook.isScenarioScoped()) {
hookIterator.remove();
}
}
}
private void removeScenarioScopedStepdefs() {
Iterator> stepdefs = stepDefinitionsByPattern.entrySet().iterator();
while (stepdefs.hasNext()) {
StepDefinition stepDefinition = stepdefs.next().getValue();
if (stepDefinition.isScenarioScoped()) {
stepdefs.remove();
}
}
Iterator> cachedStepDefs = matchedStepDefinitionsCache.entrySet().iterator();
while(cachedStepDefs.hasNext()){
StepDefinition stepDefinition = cachedStepDefs.next().getValue().stepDefinition;
if(stepDefinition.isScenarioScoped()){
cachedStepDefs.remove();
}
}
}
static final class CacheEntry {
StepDefinition stepDefinition;
private CacheEntry(StepDefinition stepDefinition) {
this.stepDefinition = stepDefinition;
}
}
}