All Downloads are FREE. Search and download functionalities are using the official Maven repository.

cucumber.runtime.UndefinedStepsTracker Maven / Gradle / Ivy

There is a newer version: 7.17.0
Show newest version
package cucumber.runtime;

import cucumber.api.event.EventHandler;
import cucumber.api.event.EventListener;
import cucumber.api.event.EventPublisher;
import cucumber.api.event.SnippetsSuggestedEvent;
import cucumber.api.event.TestSourceRead;
import gherkin.AstBuilder;
import gherkin.GherkinDialect;
import gherkin.GherkinDialectProvider;
import gherkin.IGherkinDialectProvider;
import gherkin.Parser;
import gherkin.ParserException;
import gherkin.TokenMatcher;
import gherkin.ast.Background;
import gherkin.ast.GherkinDocument;
import gherkin.ast.ScenarioDefinition;
import gherkin.ast.Step;
import gherkin.pickles.PickleLocation;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class UndefinedStepsTracker implements EventListener {
    private final List snippets = new ArrayList();
    private final IGherkinDialectProvider dialectProvider = new GherkinDialectProvider();
    private final Map pathToSourceMap = new HashMap();
    private final Map pathToStepMap = new HashMap();
    private boolean hasUndefinedSteps = false;

    private EventHandler testSourceReadHandler = new EventHandler() {
        @Override
        public void receive(TestSourceRead event) {
            pathToSourceMap.put(event.uri, event.source);
        }
    };
    private EventHandler snippetsSuggestedHandler = new EventHandler() {
        @Override
        public void receive(SnippetsSuggestedEvent event) {
            handleSnippetsSuggested(event.uri, event.stepLocations, event.snippets);
        }
    };

    @Override
    public void setEventPublisher(EventPublisher publisher) {
        publisher.registerHandlerFor(TestSourceRead.class, testSourceReadHandler);
        publisher.registerHandlerFor(SnippetsSuggestedEvent.class, snippetsSuggestedHandler);
    }

    public boolean hasUndefinedSteps() {
        return hasUndefinedSteps;
    }

    public List getSnippets() {
        return snippets;
    }

    void handleSnippetsSuggested(String uri, List stepLocations, List snippets) {
        hasUndefinedSteps = true;
        String keyword = givenWhenThenKeyword(uri, stepLocations);
        for (String rawSnippet : snippets) {
            String snippet = rawSnippet.replace("**KEYWORD**", keyword);
            if (!this.snippets.contains(snippet)) {
                this.snippets.add(snippet);
            }
        }
    }

    private String givenWhenThenKeyword(String uri, List stepLocations) {
        String keyword = null;
        if (!stepLocations.isEmpty()) {
            if (pathToSourceMap.containsKey(uri)) {
                keyword = getKeywordFromSource(uri, stepLocations);
            }
        }
        return keyword != null ? keyword : getFirstGivenKeyword(dialectProvider.getDefaultDialect());
    }

    private String getKeywordFromSource(String path, List stepLocations) {
        if (!pathToStepMap.containsKey(path)) {
            createFeatureStepMap(path);
        }
        if (!pathToStepMap.containsKey(path)) {
            return null;
        }
        GherkinDialect featureDialect = pathToStepMap.get(path).dialect;
        List givenThenWhenKeywords = getGivenWhenThenKeywords(featureDialect);
        Map stepMap = pathToStepMap.get(path).stepMap;
        for (PickleLocation stepLocation : stepLocations) {
            if (!stepMap.containsKey(stepLocation.getLine())) {
                continue;
            }
            for (StepNode stepNode = stepMap.get(stepLocation.getLine()); stepNode != null; stepNode = stepNode.previous) {
                for (String keyword : givenThenWhenKeywords) {
                    if (!keyword.equals("* ") && keyword == stepNode.step.getKeyword()) {
                        return convertToCodeKeyword(keyword);
                    }
                }
            }
        }
        return getFirstGivenKeyword(featureDialect);
    }

    private void createFeatureStepMap(String path) {
        if (!pathToSourceMap.containsKey(path)) {
            return;
        }
        Parser parser = new Parser(new AstBuilder());
        TokenMatcher matcher = new TokenMatcher();
        try {
            GherkinDocument gherkinDocument = parser.parse(pathToSourceMap.get(path), matcher);
            Map stepMap = new HashMap();
            StepNode initialPreviousNode = null;
            for (ScenarioDefinition child : gherkinDocument.getFeature().getChildren()) {
                StepNode lastStepNode = processScenarioDefinition(stepMap, initialPreviousNode, child);
                if (child instanceof Background) {
                    initialPreviousNode = lastStepNode;
                }
            }
            pathToStepMap.put(path, new FeatureStepMap(new GherkinDialectProvider(gherkinDocument.getFeature().getLanguage()).getDefaultDialect(), stepMap));
        } catch (ParserException e) {
            // Ignore exceptions
        }
    }

    private StepNode processScenarioDefinition(Map stepMap, StepNode initialPreviousNode, ScenarioDefinition child) {
        StepNode previousNode = initialPreviousNode;
        for (Step step : child.getSteps()) {
            StepNode stepNode = new StepNode(step, previousNode);
            stepMap.put(step.getLocation().getLine(), stepNode);
            previousNode = stepNode;
        }
        return previousNode;
    }

    private List getGivenWhenThenKeywords(GherkinDialect dialect) {
        List keywords = new ArrayList();
        keywords.addAll(dialect.getGivenKeywords());
        keywords.addAll(dialect.getWhenKeywords());
        keywords.addAll(dialect.getThenKeywords());
        return keywords;
    }

    private String getFirstGivenKeyword(GherkinDialect i18n) {
        for (String keyword : i18n.getGivenKeywords()) {
            if (!keyword.equals("* ")) {
                return convertToCodeKeyword(keyword);
            }
        }
        return null;
    }

    private String convertToCodeKeyword(String keyword) {
        return keyword.replaceAll("[\\s',!]", "");
    }

    private static final class FeatureStepMap {
        final GherkinDialect dialect;
        final Map stepMap;

        FeatureStepMap(GherkinDialect dialect, Map stepMap) {
            this.dialect = dialect;
            this.stepMap = stepMap;
        }
    }

    private static final class StepNode {
        final Step step;
        final StepNode previous;

        StepNode(Step step, StepNode previous) {
            this.step = step;
            this.previous = previous;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy