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

cucumber.runtime.ExtendedRuntime Maven / Gradle / Ivy

Go to download

The part of Cucumber Reports library which contains extended Cucumber-JVM runners and all relevant functionality.

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

import gherkin.I18n;
import gherkin.formatter.Argument;
import gherkin.formatter.Reporter;
import gherkin.formatter.model.Match;
import gherkin.formatter.model.Result;
import gherkin.formatter.model.Scenario;
import gherkin.formatter.model.Step;
import gherkin.formatter.model.Tag;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import com.github.mkolisnyk.cucumber.assertions.LazyAssertionError;

import cucumber.api.Pending;
import cucumber.runtime.io.ResourceLoader;
import cucumber.runtime.xstream.LocalizedXStreams;
//import cucumber.runtime.Stats;

public class ExtendedRuntime extends Runtime {
    private static final String[] PENDING_EXCEPTIONS = {
            "org.junit.AssumptionViolatedException",
            "org.junit.internal.AssumptionViolatedException" };

    static {
        Arrays.sort(PENDING_EXCEPTIONS);
    }

    private static final Object DUMMY_ARG = new Object();
    private static final byte ERRORS = 0x1;

    private final Stats stats;
    private final UndefinedStepsTracker undefinedStepsTracker = new UndefinedStepsTracker();

    private final Glue glue;
    private final RuntimeOptions runtimeOptions;

    private final List errors = new ArrayList();
    private final Collection backends;
    //private final ResourceLoader resourceLoader;
    //private final ClassLoader classLoader;
    private final StopWatch stopWatch;

    private boolean skipNextStep = false;
    private ScenarioImpl scenarioResult = null;

    public ExtendedRuntime(ResourceLoader resourceLoaderValue,
            ClassFinder classFinder, ClassLoader classLoaderValue,
            RuntimeOptions runtimeOptionsValue) {
        this(resourceLoaderValue, classLoaderValue, loadBackends(resourceLoaderValue,
                classFinder), runtimeOptionsValue);
    }

    public ExtendedRuntime(ResourceLoader resourceLoaderValue,
            ClassLoader classLoaderValue, Collection backendsValue,
            RuntimeOptions runtimeOptionsValue) {
        this(resourceLoaderValue, classLoaderValue, backendsValue, runtimeOptionsValue,
                StopWatch.SYSTEM, null);
    }

    public ExtendedRuntime(ResourceLoader resourceLoaderValue,
            ClassLoader classLoaderValue, Collection backendsValue,
            RuntimeOptions runtimeOptionsValue, RuntimeGlue optionalGlueValue) {
        this(resourceLoaderValue, classLoaderValue, backendsValue, runtimeOptionsValue,
                StopWatch.SYSTEM, optionalGlueValue);
    }

    public ExtendedRuntime(ResourceLoader resourceLoaderValue,
            ClassLoader classLoaderValue, Collection backendsValue,
            RuntimeOptions runtimeOptionsValue, StopWatch stopWatchValue,
            RuntimeGlue optionalGlueValue) {
        super(resourceLoaderValue, classLoaderValue, backendsValue, runtimeOptionsValue, stopWatchValue,
                optionalGlueValue);
        if (backendsValue.isEmpty()) {
            throw new CucumberException(
                    "No backends were found. Please make sure you have a backend module on your CLASSPATH.");
        }
        //this.resourceLoader = resourceLoaderValue;
        //this.classLoader = classLoaderValue;
        this.backends = backendsValue;
        this.runtimeOptions = runtimeOptionsValue;
        this.stopWatch = stopWatchValue;
        if (optionalGlueValue != null) {
            this.glue = optionalGlueValue;
        } else {
            this.glue = new RuntimeGlue(
                    undefinedStepsTracker, new LocalizedXStreams(classLoaderValue));
        }
        this.stats = new Stats(runtimeOptionsValue.isMonochrome());

        for (Backend backend : backends) {
            backend.loadGlue(glue, runtimeOptions.getGlue());
            backend.setUnreportedStepExecutor(this);
        }
    }

    private static Collection loadBackends(
            ResourceLoader resourceLoader, ClassFinder classFinder) {
        Reflections reflections = new Reflections(classFinder);
        return reflections.instantiateSubclasses(Backend.class,
                "cucumber.runtime", new Class[] {ResourceLoader.class},
                new Object[] {resourceLoader});
    }

    private void addStepToCounterAndResult(Result result) {
        scenarioResult.add(result);
        stats.addStep(result);
    }

    public void addError(Throwable error) {
        errors.add(error);
    }

    /*
    public void run() throws IOException {
        // Make sure all features parse before initialising any reporters/formatters
        List features = runtimeOptions.cucumberFeatures(resourceLoader);

        Formatter formatter = runtimeOptions.formatter(classLoader);
        Reporter reporter = runtimeOptions.reporter(classLoader);
        StepDefinitionReporter stepDefinitionReporter = runtimeOptions.stepDefinitionReporter(classLoader);

        glue.reportStepDefinitions(stepDefinitionReporter);

        for (CucumberFeature cucumberFeature : features) {
            cucumberFeature.run(formatter, reporter, this);
        }

        formatter.done();
        formatter.close();
        printSummary();
    }

    public void printSummary() {
        SummaryPrinter summaryPrinter = runtimeOptions.summaryPrinter(classLoader);
        summaryPrinter.print(this);
    }

    void printStats(PrintStream out) {
        stats.printStats(out, runtimeOptions.isStrict());
    }*/

    public void buildBackendWorlds(Reporter reporter, Set tags, Scenario gherkinScenario) {
        for (Backend backend : backends) {
            backend.buildWorld();
        }
        undefinedStepsTracker.reset();
        skipNextStep = false;
        scenarioResult = new ScenarioImpl(reporter, tags, gherkinScenario);
    }

    public void disposeBackendWorlds(String scenarioDesignation) {
        stats.addScenario(scenarioResult.getStatus(), scenarioDesignation);
        for (Backend backend : backends) {
            backend.disposeWorld();
        }
    }

    public List getErrors() {
        return errors;
    }

    public byte exitStatus() {
        byte result = 0x0;
        if (hasErrors() || hasUndefinedOrPendingStepsAndIsStrict()) {
            result |= ERRORS;
        }
        return result;
    }

    private boolean hasUndefinedOrPendingStepsAndIsStrict() {
        return runtimeOptions.isStrict() && hasUndefinedOrPendingSteps();
    }

    private boolean hasUndefinedOrPendingSteps() {
        return hasUndefinedSteps() || hasPendingSteps();
    }

    private boolean hasUndefinedSteps() {
        return undefinedStepsTracker.hasUndefinedSteps();
    }

    private boolean hasPendingSteps() {
        return !errors.isEmpty() && !hasErrors();
    }

    private boolean hasErrors() {
        for (Throwable error : errors) {
            if (!isPending(error)) {
                return true;
            }
        }
        return false;
    }

    public List getSnippets() {
        return undefinedStepsTracker.getSnippets(backends, runtimeOptions.getSnippetType().getFunctionNameGenerator());
    }

    public Glue getGlue() {
        return glue;
    }

    public void runBeforeHooks(Reporter reporter, Set tags) {
        runHooks(glue.getBeforeHooks(), reporter, tags, true);
    }

    public void runAfterHooks(Reporter reporter, Set tags) {
        runHooks(glue.getAfterHooks(), reporter, tags, false);
    }

    private void runHooks(List hooks, Reporter reporter, Set tags, boolean isBefore) {
        if (!runtimeOptions.isDryRun()) {
            for (HookDefinition hook : hooks) {
                runHookIfTagsMatch(hook, reporter, tags, isBefore);
            }
        }
    }

    private void runHookIfTagsMatch(HookDefinition hook, Reporter reporter, Set tags, boolean isBefore) {
        if (hook.matches(tags)) {
            String status = Result.PASSED;
            Throwable error = null;
            Match match = new Match(Collections.emptyList(), hook.getLocation(false));
            stopWatch.start();
            try {
                hook.execute(scenarioResult);
            } catch (Throwable t) {
                error = t;
                if (isPending(t)) {
                    status = "pending";
                } else {
                    status = Result.FAILED;
                }
                addError(t);
                skipNextStep = true;
            } finally {
                long duration = stopWatch.stop();
                Result result = new Result(status, duration, error, DUMMY_ARG);
                addHookToCounterAndResult(result);
                if (isBefore) {
                    reporter.before(match, result);
                } else {
                    reporter.after(match, result);
                }
            }
        }
    }

    /*@Override
    public void runUnreportedStep(
            String featurePath, I18n i18n, String stepKeyword, String stepName,
            int line, List dataTableRows, DocString docString) throws Throwable {
        Step step = new Step(Collections.emptyList(), stepKeyword, stepName, line, dataTableRows, docString);

        StepDefinitionMatch match = glue.stepDefinitionMatch(featurePath, step, i18n);
        if (match == null) {
            UndefinedStepException error = new UndefinedStepException(step);

            StackTraceElement[] originalTrace = error.getStackTrace();
            StackTraceElement[] newTrace = new StackTraceElement[originalTrace.length + 1];
            newTrace[0] = new StackTraceElement("✽", "StepDefinition", featurePath, line);
            System.arraycopy(originalTrace, 0, newTrace, 1, originalTrace.length);
            error.setStackTrace(newTrace);

            throw error;
        }
        match.runStep(i18n);
    }*/

    @Override
    public void runStep(String featurePath, Step step, Reporter reporter,
            I18n i18n) {
        StepDefinitionMatch match;

        try {
            match = this.getGlue().stepDefinitionMatch(featurePath, step, i18n);
        } catch (AmbiguousStepDefinitionsException e) {
            reporter.match(e.getMatches().get(0));
            Result result = new Result(Result.FAILED, 0L, e, DUMMY_ARG);
            reporter.result(result);
            addStepToCounterAndResult(result);
            addError(e);
            skipNextStep = true;
            return;
        }

        if (match != null) {
            reporter.match(match);
        } else {
            reporter.match(Match.UNDEFINED);
            reporter.result(Result.UNDEFINED);
            addStepToCounterAndResult(Result.UNDEFINED);
            skipNextStep = true;
            return;
        }

        if (runtimeOptions.isDryRun()) {
            skipNextStep = true;
        }

        if (skipNextStep) {
            addStepToCounterAndResult(Result.SKIPPED);
            reporter.result(Result.SKIPPED);
        } else {
            String status = Result.PASSED;
            Throwable error = null;
            stopWatch.start();
            try {
                match.runStep(i18n);
            } catch (LazyAssertionError t) {
                error = t;
                status = Result.FAILED;
                addError(t);
            } catch (Throwable t) {
                error = t;
                if (isPending(t)) {
                    status = "pending";
                } else {
                    status = Result.FAILED;
                }
                addError(t);
                skipNextStep = true;
            } finally {
                long duration = stopWatch.stop();
                Result result = new Result(status, duration, error, DUMMY_ARG);
                addStepToCounterAndResult(result);
                reporter.result(result);
            }
        }
    }

    public static boolean isPending(Throwable t) {
        if (t == null) {
            return false;
        }
        return t.getClass().isAnnotationPresent(Pending.class)
                || Arrays.binarySearch(PENDING_EXCEPTIONS, t.getClass().getName()) >= 0;
    }

    private void addHookToCounterAndResult(Result result) {
        scenarioResult.add(result);
        stats.addHookTime(result.getDuration());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy