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

tw.teddysoft.ezspec.keyword.Feature Maven / Gradle / Ivy

package tw.teddysoft.ezspec.keyword;


import tw.teddysoft.ezspec.keyword.visitor.SpecificationElement;
import tw.teddysoft.ezspec.keyword.visitor.SpecificationElementVisitor;

import java.util.*;

import static tw.teddysoft.ezspec.keyword.Scenario.getEnclosingMethodInfo;

/**
 * {@code Feature} is a class for representing Gherkin feature file.
 *
 * @author Teddy Chen
 * @since 1.0
 */
public class Feature implements SpecificationElement {

    public static final String KEYWORD = "Feature";
    private final String name;
    private final String description;
    private final List rules;
    private Rule defaultRule;

    public Background newBackground() {
        defaultRule.newBackground(Scenario.getEnclosingMethodName());
        return defaultRule.getBackground();
    }

    public Background newBackground(String name) {
        defaultRule.newBackground(name);
        return defaultRule.getBackground();
    }

    public Optional getRule(String ruleName){
        Objects.requireNonNull(ruleName);

        return rules.stream().filter( x-> x.getName().equals(ruleName)).findAny();
    }

    public void applyRule(String ruleName, Scenario scenario){

        var optRule = getRule(ruleName);
        if (optRule.isPresent()){
            defaultRule.removeScenario(scenario);
            optRule.get().addScenario(scenario);
        }
        else
            throw new IllegalArgumentException("Rule not found: " + ruleName);
    }

    public void initialize() {
        rules.clear();
        newDefaultRule();
    }

    /**
     * A static factory to create a feature.
     *
     * @param name the name of feature
     * @return a new feature instance
     */
    public static Feature New(String name) {
        Objects.requireNonNull(name, "name");

        return new Feature(name);
    }

    /**
     * A static factory to create a feature.
     *
     * @param name        the name of feature
     * @param description the description of feature
     * @return a new feature instance
     */
    public static Feature New(String name, String description) {
        Objects.requireNonNull(name, "name");
        Objects.requireNonNull(description, "description");

        return new Feature(name, description);
    }

    private Feature(String name) {
        this(name, "");
    }

    /**
     * Instantiates a new Feature.
     *
     * @param name        the name
     * @param description the description
     */
    private Feature(String name, String description) {
        this.name = name;
        this.description = description;
        rules = new ArrayList<>();
        newDefaultRule();
    }

    /**
     * Gets rules.
     *
     * @return the rules
     */
    public List getRules() {
        return Collections.unmodifiableList(rules);
    }

    /**
     * Gets name.
     *
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * Gets description.
     *
     * @return the description
     */
    public String getDescription() {
        return description;
    }

    /**
     * Create a new default rule in the feature. A default rule can only be
     * created when there is no any rule in the list {@code rules}. If there
     * is a default rule exist, it will be replaced by the new default rule.
     *
     * @return the rule
     */
    private Rule newDefaultRule() {
        defaultRule = new Rule("", this);
        return defaultRule;
    }

    public Scenario newScenario() {
        var methodInfo = getEnclosingMethodInfo();
        return newScenarioWithRule(methodInfo.cookedMethodName(), methodInfo.ruleName());
    }

    public Scenario newScenario(String scenarioName) {
        return newScenarioWithRule(scenarioName, getEnclosingMethodInfo().ruleName());
    }

    private Scenario newScenarioWithRule(String scenarioName, String ruleName){
        Objects.requireNonNull(scenarioName);
        Objects.requireNonNull(ruleName);

        var scenario = defaultRule.newScenario(scenarioName);
        if (!ruleName.isEmpty())
            scenario.withRule(ruleName);

        return scenario;
    }

    public ScenarioOutline newScenarioOutline() {
        var methodInfo = getEnclosingMethodInfo();
        return newScenarioOutlineWithRule(methodInfo.cookedMethodName(), "", methodInfo.ruleName());
    }

    public ScenarioOutline newScenarioOutline(String name) {
        return newScenarioOutlineWithRule(name, "", getEnclosingMethodInfo().ruleName());
    }

    public ScenarioOutline newScenarioOutline(String name, String description) {
        return newScenarioOutlineWithRule(name, description, getEnclosingMethodInfo().ruleName());
    }

    private ScenarioOutline newScenarioOutlineWithRule(String scenarioOutlineName, String description, String ruleName){
        Objects.requireNonNull(scenarioOutlineName);
        Objects.requireNonNull(description);
        Objects.requireNonNull(ruleName);

        var scenarioOutline = defaultRule.newScenarioOutline(scenarioOutlineName, description);
        if (!ruleName.isEmpty())
            scenarioOutline.withRule(ruleName);

        return scenarioOutline;
    }

    /**
     * Gets default rule.
     *
     * @return the default rule
     */
    public Rule getDefaultRule() {
        return defaultRule;
    }

    /**
     * Clear rule.
     */
    public void clearRule() {
        rules.clear();
    }

    @Override
    public void accept(SpecificationElementVisitor visitor) {
        visitor.visit(this);
        defaultRule.accept(visitor);
        rules.forEach(rule -> {
            rule.accept(visitor);
        });
    }

    /**
     * Feature text string including feature name and feature description.
     *
     * @return the string
     */
    public String featureText() {
        StringBuilder sb = new StringBuilder();
        sb.append(KEYWORD).append(": ").append(name);

        if (!description.isEmpty())
            sb.append("\n\n").append(description);

        return sb.toString();
    }

    /**
     * The text string including feature name, feature description and
     * contents of all rules.
     *
     * @return the string
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append(featureText());
        sb.append("\n\n");
        sb.append(rulesText());
        return sb.toString();
    }

    private String rulesText() {
        StringBuilder sb = new StringBuilder();
        sb.append(defaultRule.toString()).append("\n");
        for (var each : rules) {
            sb.append(each.toString()).append("\n");
        }
        return sb.toString();
    }

    /**
     * Add a rule to the feature
     *
     * @since 1.0.6
     */
    public Rule NewRule(String ruleName) {
        Objects.requireNonNull(ruleName);

        return NewRule(ruleName, "");
    }

    /**
     * Add a rule to the feature
     *
     * @since 1.0.6
     */
    public Rule NewRule(String ruleName, String description) {
        Objects.requireNonNull(ruleName);

        if (rules.stream().anyMatch( x-> x.getName().equals(ruleName)))
            throw new IllegalArgumentException("Rule name cannot be duplicated: " + ruleName);

        Rule rule = new Rule(ruleName, description, this);
        rules.add(rule);
        return rule;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy