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

io.cucumber.junit.platform.engine.NodeDescriptor Maven / Gradle / Ivy

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

import io.cucumber.core.gherkin.Pickle;
import io.cucumber.core.resource.ClasspathSupport;
import org.junit.platform.engine.ConfigurationParameters;
import org.junit.platform.engine.TestSource;
import org.junit.platform.engine.TestTag;
import org.junit.platform.engine.UniqueId;
import org.junit.platform.engine.support.config.PrefixedConfigurationParameters;
import org.junit.platform.engine.support.descriptor.AbstractTestDescriptor;
import org.junit.platform.engine.support.descriptor.ClasspathResourceSource;
import org.junit.platform.engine.support.hierarchical.ExclusiveResource;
import org.junit.platform.engine.support.hierarchical.ExclusiveResource.LockMode;
import org.junit.platform.engine.support.hierarchical.Node;

import java.util.Arrays;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.Locale;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Stream;

import static io.cucumber.junit.platform.engine.Constants.EXECUTION_EXCLUSIVE_RESOURCES_PREFIX;
import static io.cucumber.junit.platform.engine.Constants.EXECUTION_MODE_FEATURE_PROPERTY_NAME;
import static io.cucumber.junit.platform.engine.Constants.READ_SUFFIX;
import static io.cucumber.junit.platform.engine.Constants.READ_WRITE_SUFFIX;
import static java.util.stream.Collectors.collectingAndThen;
import static java.util.stream.Collectors.toCollection;

abstract class NodeDescriptor extends AbstractTestDescriptor implements Node {

    private final ExecutionMode executionMode;

    NodeDescriptor(ConfigurationParameters parameters, UniqueId uniqueId, String name, TestSource source) {
        super(uniqueId, name, source);
        this.executionMode = parameters
                .get(EXECUTION_MODE_FEATURE_PROPERTY_NAME,
                    value -> ExecutionMode.valueOf(value.toUpperCase(Locale.US)))
                .orElse(ExecutionMode.CONCURRENT);
    }

    @Override
    public ExecutionMode getExecutionMode() {
        return executionMode;
    }

    static final class ExamplesDescriptor extends NodeDescriptor {

        ExamplesDescriptor(ConfigurationParameters parameters, UniqueId uniqueId, String name, TestSource source) {
            super(parameters, uniqueId, name, source);
        }

        @Override
        public Type getType() {
            return Type.CONTAINER;
        }

    }

    static final class RuleDescriptor extends NodeDescriptor {

        RuleDescriptor(ConfigurationParameters parameters, UniqueId uniqueId, String name, TestSource source) {
            super(parameters, uniqueId, name, source);
        }

        @Override
        public Type getType() {
            return Type.CONTAINER;
        }

    }

    static final class ScenarioOutlineDescriptor extends NodeDescriptor {

        ScenarioOutlineDescriptor(
                ConfigurationParameters parameters, UniqueId uniqueId, String name,
                TestSource source
        ) {
            super(parameters, uniqueId, name, source);
        }

        @Override
        public Type getType() {
            return Type.CONTAINER;
        }

    }

    static final class PickleDescriptor extends NodeDescriptor {

        private final Pickle pickle;
        private final Set tags;
        private final Set exclusiveResources = new LinkedHashSet<>(0);

        PickleDescriptor(
                ConfigurationParameters parameters, UniqueId uniqueId, String name, TestSource source,
                Pickle pickle
        ) {
            super(parameters, uniqueId, name, source);
            this.pickle = pickle;
            this.tags = getTags(pickle);
            this.tags.forEach(tag -> {
                ExclusiveResourceOptions exclusiveResourceOptions = new ExclusiveResourceOptions(parameters, tag);
                exclusiveResourceOptions.exclusiveReadWriteResource()
                        .map(resource -> new ExclusiveResource(resource, LockMode.READ_WRITE))
                        .forEach(exclusiveResources::add);
                exclusiveResourceOptions.exclusiveReadResource()
                        .map(resource -> new ExclusiveResource(resource, LockMode.READ))
                        .forEach(exclusiveResources::add);
            });
        }

        Pickle getPickle() {
            return pickle;
        }

        private Set getTags(Pickle pickleEvent) {
            return pickleEvent.getTags().stream()
                    .map(tag -> tag.substring(1))
                    .filter(TestTag::isValid)
                    .map(TestTag::create)
                    // Retain input order
                    .collect(collectingAndThen(toCollection(LinkedHashSet::new), Collections::unmodifiableSet));
        }

        @Override
        public Type getType() {
            return Type.TEST;
        }

        @Override
        public SkipResult shouldBeSkipped(CucumberEngineExecutionContext context) {
            return Stream.of(shouldBeSkippedByTagFilter(context), shouldBeSkippedByNameFilter(context))
                    .flatMap(skipResult -> skipResult.map(Stream::of).orElseGet(Stream::empty))
                    .filter(SkipResult::isSkipped)
                    .findFirst()
                    .orElseGet(SkipResult::doNotSkip);
        }

        private Optional shouldBeSkippedByTagFilter(CucumberEngineExecutionContext context) {
            return context.getOptions().tagFilter().map(expression -> {
                if (expression.evaluate(pickle.getTags())) {
                    return SkipResult.doNotSkip();
                }
                return SkipResult
                        .skip(
                            "'" + Constants.FILTER_TAGS_PROPERTY_NAME + "=" + expression
                                    + "' did not match this scenario");
            });
        }

        private Optional shouldBeSkippedByNameFilter(CucumberEngineExecutionContext context) {
            return context.getOptions().nameFilter().map(pattern -> {
                if (pattern.matcher(pickle.getName()).matches()) {
                    return SkipResult.doNotSkip();
                }
                return SkipResult
                        .skip("'" + Constants.FILTER_NAME_PROPERTY_NAME + "=" + pattern
                                + "' did not match this scenario");
            });
        }

        @Override
        public CucumberEngineExecutionContext execute(
                CucumberEngineExecutionContext context, DynamicTestExecutor dynamicTestExecutor
        ) {
            context.runTestCase(pickle);
            return context;
        }

        @Override
        public Set getExclusiveResources() {
            return exclusiveResources;
        }

        /**
         * Returns the set of {@linkplain TestTag tags} for a pickle.
         * 

* Note that Cucumber will remove the {code @} symbol from all Gherkin * tags. So a scenario tagged with {@code @Smoke} becomes a test tagged * with {@code Smoke}. * * @return the set of tags */ @Override public Set getTags() { return tags; } Optional getPackage() { return getSource() .filter(ClasspathResourceSource.class::isInstance) .map(ClasspathResourceSource.class::cast) .map(ClasspathResourceSource::getClasspathResourceName) .map(ClasspathSupport::packageNameOfResource); } private static final class ExclusiveResourceOptions { private final ConfigurationParameters parameters; ExclusiveResourceOptions(ConfigurationParameters parameters, TestTag tag) { this.parameters = new PrefixedConfigurationParameters( parameters, EXECUTION_EXCLUSIVE_RESOURCES_PREFIX + tag.getName()); } public Stream exclusiveReadWriteResource() { return parameters.get(READ_WRITE_SUFFIX, s -> Arrays.stream(s.split(",")) .map(String::trim)) .orElse(Stream.empty()); } public Stream exclusiveReadResource() { return parameters.get(READ_SUFFIX, s -> Arrays.stream(s.split(",")) .map(String::trim)) .orElse(Stream.empty()); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy