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

io.cucumber.junit.JUnitReporter Maven / Gradle / Ivy

There is a newer version: 7.20.1
Show newest version
package io.cucumber.junit;

import io.cucumber.core.eventbus.EventBus;
import io.cucumber.junit.PickleRunners.PickleRunner;
import io.cucumber.plugin.event.EventHandler;
import io.cucumber.plugin.event.PickleStepTestStep;
import io.cucumber.plugin.event.Result;
import io.cucumber.plugin.event.SnippetsSuggestedEvent;
import io.cucumber.plugin.event.SnippetsSuggestedEvent.Suggestion;
import io.cucumber.plugin.event.TestCaseFinished;
import io.cucumber.plugin.event.TestCaseStarted;
import io.cucumber.plugin.event.TestStep;
import io.cucumber.plugin.event.TestStepFinished;
import io.cucumber.plugin.event.TestStepStarted;
import org.junit.runner.Description;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.model.MultipleFailureException;

import java.net.URI;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import static io.cucumber.junit.SkippedThrowable.NotificationLevel.SCENARIO;
import static io.cucumber.junit.SkippedThrowable.NotificationLevel.STEP;

final class JUnitReporter {

    private final JUnitOptions junitOptions;
    private final EventBus bus;
    private final Collection suggestions = new ArrayList<>();
    private final EventHandler snippetsSuggestedEventEventHandler = this::handleSnippetSuggested;
    private List stepErrors;
    private final EventHandler testCaseStartedHandler = this::handleTestCaseStarted;
    private TestNotifier stepNotifier;
    private final EventHandler testStepFinishedHandler = this::handleTestStepFinished;
    private PickleRunner pickleRunner;
    private RunNotifier runNotifier;
    private final EventHandler testStepStartedHandler = this::handTestStepStarted;
    private TestNotifier pickleRunnerNotifier;
    private final EventHandler testCaseFinishedHandler = this::handleTestCaseResult;

    JUnitReporter(EventBus bus, JUnitOptions junitOption) {
        this.junitOptions = junitOption;
        this.bus = bus;
        bus.registerHandlerFor(TestCaseStarted.class, testCaseStartedHandler);
        bus.registerHandlerFor(TestStepStarted.class, testStepStartedHandler);
        bus.registerHandlerFor(TestStepFinished.class, testStepFinishedHandler);
        bus.registerHandlerFor(TestCaseFinished.class, testCaseFinishedHandler);
        bus.registerHandlerFor(SnippetsSuggestedEvent.class, snippetsSuggestedEventEventHandler);
    }

    private void handleSnippetSuggested(SnippetsSuggestedEvent snippetsSuggestedEvent) {
        suggestions.add(snippetsSuggestedEvent.getSuggestion());
    }

    void finishExecutionUnit() {
        bus.removeHandlerFor(TestCaseStarted.class, testCaseStartedHandler);
        bus.removeHandlerFor(TestStepStarted.class, testStepStartedHandler);
        bus.removeHandlerFor(TestStepFinished.class, testStepFinishedHandler);
        bus.removeHandlerFor(TestCaseFinished.class, testCaseFinishedHandler);
        bus.removeHandlerFor(SnippetsSuggestedEvent.class, snippetsSuggestedEventEventHandler);
    }

    void startExecutionUnit(PickleRunner pickleRunner, RunNotifier runNotifier) {
        this.pickleRunner = pickleRunner;
        this.runNotifier = runNotifier;
        this.stepNotifier = null;

        pickleRunnerNotifier = new EachTestNotifier(runNotifier, pickleRunner.getDescription());
    }

    private void handleTestCaseStarted(TestCaseStarted testCaseStarted) {
        stepErrors = new ArrayList<>();
    }

    private void handTestStepStarted(TestStepStarted event) {
        TestStep testStep = event.getTestStep();
        if (testStep instanceof PickleStepTestStep) {
            PickleStepTestStep pickleStep = (PickleStepTestStep) testStep;
            if (junitOptions.stepNotifications()) {
                Description description = pickleRunner.describeChild(pickleStep.getStep());
                stepNotifier = new EachTestNotifier(runNotifier, description);
            } else {
                stepNotifier = new NoTestNotifier();
            }
            stepNotifier.fireTestStarted();
        }
    }

    private void handleTestStepFinished(TestStepFinished event) {
        if (event.getTestStep() instanceof PickleStepTestStep) {
            PickleStepTestStep testStep = (PickleStepTestStep) event.getTestStep();
            handleStepResult(testStep, event.getResult());
        } else {
            handleHookResult(event.getResult());
        }
    }

    private void handleStepResult(PickleStepTestStep testStep, Result result) {
        Throwable error = result.getError();
        switch (result.getStatus()) {
            case PASSED:
                // do nothing
                break;
            case SKIPPED:
                if (error == null) {
                    error = new SkippedThrowable(STEP);
                } else {
                    stepErrors.add(error);
                }
                stepNotifier.addFailedAssumption(error);
                break;
            case PENDING:
            case AMBIGUOUS:
            case FAILED:
                stepErrors.add(error);
                stepNotifier.addFailure(error);
                break;
            case UNDEFINED:
                stepErrors.add(new UndefinedStepException(suggestions));
                stepNotifier.addFailure(error == null ? new UndefinedStepException(suggestions) : error);
                break;
            default:
                throw new IllegalStateException("Unexpected result status: " + result.getStatus());
        }
        stepNotifier.fireTestFinished();
    }

    private void handleHookResult(Result result) {
        if (result.getError() != null) {
            stepErrors.add(result.getError());
        }
    }

    private void handleTestCaseResult(TestCaseFinished event) {
        Result result = event.getResult();
        switch (result.getStatus()) {
            case PASSED:
                // do nothing
                break;
            case SKIPPED:
                if (stepErrors.isEmpty()) {
                    stepErrors.add(new SkippedThrowable(SCENARIO));
                }
                stepErrors.stream()
                        .findFirst()
                        .ifPresent(pickleRunnerNotifier::addFailedAssumption);
                break;
            case PENDING:
            case UNDEFINED:
                stepErrors.stream()
                        .findFirst()
                        .ifPresent(pickleRunnerNotifier::addFailure);
                break;
            case AMBIGUOUS:
            case FAILED:
                stepErrors.forEach(pickleRunnerNotifier::addFailure);
                break;
        }
    }

    private interface TestNotifier {

        void fireTestStarted();

        void addFailure(Throwable error);

        void addFailedAssumption(Throwable error);

        void fireTestFinished();

    }

    private static final class StepLocation implements Comparable {

        private final URI uri;
        private final int line;

        private StepLocation(URI uri, int line) {
            this.uri = uri;
            this.line = line;
        }

        @Override
        public int compareTo(StepLocation o) {
            int order = uri.compareTo(o.uri);
            return order != 0 ? order : Integer.compare(line, o.line);
        }

    }

    static final class NoTestNotifier implements TestNotifier {

        @Override
        public void fireTestStarted() {
            // Does nothing
        }

        @Override
        public void addFailure(Throwable error) {
            // Does nothing
        }

        @Override
        public void addFailedAssumption(Throwable error) {
            // Does nothing
        }

        @Override
        public void fireTestFinished() {
            // Does nothing
        }

    }

    static class EachTestNotifier implements TestNotifier {

        private final RunNotifier notifier;

        private final Description description;

        EachTestNotifier(RunNotifier notifier, Description description) {
            this.notifier = notifier;
            this.description = description;
        }

        private void addMultipleFailureException(MultipleFailureException mfe) {
            for (Throwable each : mfe.getFailures()) {
                addFailure(each);
            }
        }

        public void fireTestStarted() {
            notifier.fireTestStarted(description);
        }

        public void addFailure(Throwable targetException) {
            if (targetException instanceof MultipleFailureException) {
                addMultipleFailureException((MultipleFailureException) targetException);
            } else {
                notifier.fireTestFailure(new Failure(description, targetException));
            }
        }

        public void addFailedAssumption(Throwable e) {
            notifier.fireTestAssumptionFailed(new Failure(description, e));
        }

        public void fireTestFinished() {
            notifier.fireTestFinished(description);
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy