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

com.pdsl.gherkin.PickleJarFactory Maven / Gradle / Ivy

package com.pdsl.gherkin;

import com.pdsl.gherkin.models.*;
import com.pdsl.transformers.PolymorphicDslFileException;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

/**
 * A factory for producing PickleJars from Test Resources.
 *
 * @see com.pdsl.gherkin.PickleJar
 */
public class PickleJarFactory {

    public static final PickleJarFactory DEFAULT = new PickleJarFactory(new PdslGherkinInterpreterImpl(), new PdslGherkinListenerImpl(), StandardCharsets.UTF_8);
    private final Charset charset;
    private final PdslGherkinRecognizer pdslGherkinRecognizer;
    private final PdslGherkinListener listener;

    public PickleJarFactory(PdslGherkinRecognizer pdslGherkinRecognizer, PdslGherkinListener gherkinListener, Charset charset) {
        this.pdslGherkinRecognizer = pdslGherkinRecognizer;
        this.listener = gherkinListener;
        this.charset = charset;
    }

    /**
     * Converts a list of feature files into a list of {@code PickleJar}.
     * 

* The primary purpose of this is to both read all of the feature files (and making sure they exist) and * parameter substitutions on the text if needed * * @param testResources List of URIs to feature files * @return A List of PickleJars, where each pickle jar represents a processed feature */ public List getPickleJars(Set testResources) { List features = new ArrayList<>(); // Parse each gherkin file try { for (URI uri : testResources) { features.add(pdslGherkinRecognizer.interpretGherkinFileStrictly(uri, listener)); } } catch (IOException e) { throw new PolymorphicDslFileException("Could not open file!", e); } List pickleJars = new ArrayList<>(); // Process each gherkin feature into a test specification for (GherkinFeature feature : features) { PickleJar.Builder pickleJarBuilder = new PickleJar.Builder(feature.getLocation(), feature.getTitle().orElseThrow(), feature.getLanguageCode()); // Feature tags if (feature.getTags().isPresent()) { pickleJarBuilder.withFeatureTags(processTags(feature.getTags().get())); } // Feature background if (feature.getBackground().isPresent()) { pickleJarBuilder.withGherkinBackground(feature.getBackground().get()); } // Feature Description if (feature.getLongDescription().isPresent()) { pickleJarBuilder.withLongDescription(feature.getLongDescription().get()); } // Top level scenarios if (feature.getOptionalGherkinScenarios().isPresent()) { List topLevelPickles = convertScenariosToPickleJarScenarios(feature.getOptionalGherkinScenarios().get()); pickleJarBuilder.withFeatureLevelScenarios(topLevelPickles); } // Add all rules if (feature.getRules().isPresent()) { pickleJarBuilder.withRules(convertRulesToPickles(feature.getRules().get())); } pickleJars.add(pickleJarBuilder.build()); } return pickleJars; } private List convertScenariosToPickleJarScenarios(List scenarios) { List pickleJarScenarios = new ArrayList<>(); for (GherkinScenario scenario : scenarios) { // If the scenario has an examples table the tags will need to be combined with the scenario level Set tags = new HashSet<>(); if (scenario.getTags().isPresent()) { tags.addAll(processTags(scenario.getTags().get())); } if (scenario.getExamples().isPresent()) { for (GherkinExamplesTable table : scenario.getExamples().get()) { Set tableTags = new HashSet<>(); tableTags.addAll(tags); for (Map substitutions : table.getRows()) { // steps list is guaranteed to be present by the pdslGherkinInterpreter // Substitutions may need to be made on each step, docstring or gherkin table List substitutedSteps = getTextSubstitutionsForStepBody(scenario.getStepsList().orElseThrow(), substitutions); // Create a pickle with the substituted steps PickleJar.PickleJarScenario.Builder builder = new PickleJar.PickleJarScenario.Builder( scenario.getTitle().orElseThrow().getStringWithSubstitutions(substitutions), substitutedSteps); if (scenario.getLongDescription().isPresent()) { builder.withLongDescription(scenario.getLongDescription().get().getStringWithSubstitutions(substitutions)); } if (table.getTags().isPresent()) { tableTags.addAll(processTags(table.getTags().get())); } builder.withTags(processTags(tableTags)); pickleJarScenarios.add(builder.build()); } } } else { // No substitutions needed // steps list is guaranteed to be present by the pdslGherkinInterpreter // Substitutions may need to be made on each step, docstring or gherkin table List stepBody = getTextFromStepBody(scenario.getStepsList().orElseThrow()); // Create a pickle with the substituted steps PickleJar.PickleJarScenario.Builder builder = new PickleJar.PickleJarScenario.Builder( scenario.getTitle().orElseThrow().getRawString(), stepBody); if (!tags.isEmpty()) { builder.withTags(processTags(tags)); } if (scenario.getLongDescription().isPresent()) { String longDescription = scenario.getLongDescription().get().getRawString(); builder.withLongDescription(longDescription); } pickleJarScenarios.add(builder.build()); } } return pickleJarScenarios; } private List convertRulesToPickles(List rules) { List pickleJarRules = new ArrayList<>(); for (GherkinRule rule : rules) { List scenarios = convertScenariosToPickleJarScenarios(rule.getScenarios().orElseThrow()); PickleJar.PickleJarRule.Builder builder = new PickleJar.PickleJarRule.Builder(rule.getTitle().orElseThrow(), scenarios); if (rule.getBackground().isPresent()) { builder.withBackground(rule.getBackground().get()); } if (rule.getLongDescription().isPresent()) { builder.withLongDescription(rule.getLongDescription().get()); } pickleJarRules.add(builder.build()); } return pickleJarRules; } private List getTextSubstitutionsForStepBody(List stepBody, Map substitutions) { List substitutedStepBody = new ArrayList<>(); for (GherkinStep step : stepBody) { StringBuilder substitutedStep = new StringBuilder(); GherkinString stepContent = step.getStepContent(); substitutedStep.append(stepContent.getStringWithSubstitutions(substitutions)); if (step.getDocString().isPresent()) { GherkinString docString = step.getDocString().get().getGherkinString(); substitutedStep.append("\n" + docString.getStringWithSubstitutions(substitutions)); } else if (step.getDataTable().isPresent()) { //TODO: Maybe we should be storing the raw text of the data table as well to simplify this? // Perform all substitutions List> substitutedDataTable = step.getDataTable().get().stream().map(row -> row.stream().map(cell -> cell.getStringWithSubstitutions(substitutions)) .collect(Collectors.toUnmodifiableList())) .collect(Collectors.toUnmodifiableList()); // Convert to a string substitutedStep.append(getDataTableText(substitutedDataTable)); } substitutedStepBody.add(substitutedStep.toString()); } return substitutedStepBody; } private List getTextFromStepBody(List stepBody) { List substitutedStepBody = new ArrayList<>(); for (GherkinStep step : stepBody) { StringBuilder stepText = new StringBuilder(); GherkinString stepContent = step.getStepContent(); stepText.append(stepContent.getRawString()); if (step.getDocString().isPresent()) { GherkinString docString = step.getDocString().get().getGherkinString(); stepText.append(docString.getRawString()); } else if (step.getDataTable().isPresent()) { //TODO: Maybe we should be storing the raw text of the data table as well to simplify this? // Perform all substitutions List> substitutedDataTable = step.getDataTable().get().stream().map(row -> row.stream().map(GherkinString::getRawString) .collect(Collectors.toUnmodifiableList())) .collect(Collectors.toUnmodifiableList()); // Convert to a string stepText.append(getDataTableText(substitutedDataTable)); } substitutedStepBody.add(stepText.toString()); } return substitutedStepBody; } private String getDataTableText(List> substitutedDataTable) { return String.join("\n", // Separate each row by a line break substitutedDataTable.stream().map(row -> "|" + String.join("|", row) + "|") // Separate each cell with a pipe .collect(Collectors.toUnmodifiableList())) + "\n"; } private Set processTags(Collection rawTags) { Set tags = new HashSet<>(); ByteArrayOutputStream tagBuilder = new ByteArrayOutputStream(); for (String rawTag : rawTags) { String remainingTag = tagBuilder.toString(charset); if (!remainingTag.isBlank()) { tags.add(remainingTag); tagBuilder.reset(); } boolean buildingTag = false; for (int i = 0; i < rawTag.length(); i++) { char c = rawTag.charAt(i); switch (c) { case ' ': /* fall through */ case '\t': /* fall through */ case '\n': /* fall through */ if (buildingTag) { // We encountered an @ earlier, otherwise we're skipping whitespace at the start of a string tags.add(tagBuilder.toString(charset)); tagBuilder.reset(); buildingTag = false; } break; case '#': if (!buildingTag) { // Comment at end of raw tag. Ignore the rest return tags; } tagBuilder.write(c); break; case '@': if (buildingTag) { //Joined tag (e.g, @tagOne@tagTwo tags.add(tagBuilder.toString(charset)); tagBuilder.reset(); } buildingTag = true; /* fall through */ default: if (buildingTag) { tagBuilder.write(c); } else { throw new IllegalArgumentException("Illegal tags. Got confused by " + rawTag); } buildingTag = true; break; } } } String remainingTag = tagBuilder.toString(charset); if (!remainingTag.isBlank()) { tags.add(remainingTag); tagBuilder.reset(); } return tags; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy