diff --git a/cucumber-core/src/main/java/io/cucumber/core/options/Constants.java b/cucumber-core/src/main/java/io/cucumber/core/options/Constants.java index 6f314e4eea..d6ada2d7d1 100644 --- a/cucumber-core/src/main/java/io/cucumber/core/options/Constants.java +++ b/cucumber-core/src/main/java/io/cucumber/core/options/Constants.java @@ -32,7 +32,7 @@ public final class Constants { *

* Limits the number of scenarios to be executed to a specific amount. *

- * By default scenarios are executed. + * By default, scenarios are executed. */ public static final String EXECUTION_LIMIT_PROPERTY_NAME = "cucumber.execution.limit"; @@ -42,10 +42,12 @@ public final class Constants { * Valid values are {@code lexical}, {@code reverse}, {@code random} or * {@code random:[seed]}. *

- * By default features are executed in lexical file name order + * By default, features are executed in lexical file name order */ public static final String EXECUTION_ORDER_PROPERTY_NAME = "cucumber.execution.order"; + public static final String EXECUTION_SKIP_TAGS_PROPERTY_NAME = "cucumber.execution.skip.tags"; + /** * Property name used to enable wip execution: {@value} *

diff --git a/cucumber-core/src/main/java/io/cucumber/core/options/RuntimeOptions.java b/cucumber-core/src/main/java/io/cucumber/core/options/RuntimeOptions.java index 795d74b946..b3c60b5730 100644 --- a/cucumber-core/src/main/java/io/cucumber/core/options/RuntimeOptions.java +++ b/cucumber-core/src/main/java/io/cucumber/core/options/RuntimeOptions.java @@ -62,6 +62,7 @@ public final class RuntimeOptions implements // For context see: https://mattwynne.net/new-beginning private boolean publishQuiet = true; private boolean enablePublishPlugin; + private List skipTagExpressions = new ArrayList<>(); private RuntimeOptions() { @@ -174,6 +175,11 @@ public Class getUuidGeneratorClass() { return uuidGeneratorClass; } + @Override + public List getSkipTagExpressions() { + return skipTagExpressions; + } + void setUuidGeneratorClass(Class uuidGeneratorClass) { this.uuidGeneratorClass = uuidGeneratorClass; } diff --git a/cucumber-core/src/main/java/io/cucumber/core/runner/Options.java b/cucumber-core/src/main/java/io/cucumber/core/runner/Options.java index 0fe0ffb807..987246c9b7 100644 --- a/cucumber-core/src/main/java/io/cucumber/core/runner/Options.java +++ b/cucumber-core/src/main/java/io/cucumber/core/runner/Options.java @@ -3,6 +3,7 @@ import io.cucumber.core.backend.ObjectFactory; import io.cucumber.core.eventbus.UuidGenerator; import io.cucumber.core.snippets.SnippetType; +import io.cucumber.tagexpressions.Expression; import java.net.URI; import java.util.List; @@ -19,4 +20,6 @@ public interface Options { Class getUuidGeneratorClass(); + List getSkipTagExpressions(); + } diff --git a/cucumber-core/src/main/java/io/cucumber/core/runner/Runner.java b/cucumber-core/src/main/java/io/cucumber/core/runner/Runner.java index 6e560a05a1..372fcc833f 100644 --- a/cucumber-core/src/main/java/io/cucumber/core/runner/Runner.java +++ b/cucumber-core/src/main/java/io/cucumber/core/runner/Runner.java @@ -17,6 +17,7 @@ import io.cucumber.plugin.event.Location; import io.cucumber.plugin.event.SnippetsSuggestedEvent; import io.cucumber.plugin.event.SnippetsSuggestedEvent.Suggestion; +import io.cucumber.tagexpressions.Expression; import java.net.URI; import java.util.ArrayList; @@ -138,15 +139,28 @@ private void buildBackendWorlds() { } private TestCase createTestCaseForPickle(Pickle pickle) { + ExecutionMode executionMode = getExecutionMode(pickle); + if (pickle.getSteps().isEmpty()) { - return new TestCase(bus.generateId(), emptyList(), emptyList(), emptyList(), pickle, - runnerOptions.isDryRun()); + return new TestCase(bus.generateId(), emptyList(), emptyList(), emptyList(), pickle, executionMode); } List testSteps = createTestStepsForPickleSteps(pickle); List beforeHooks = createTestStepsForBeforeHooks(pickle.getTags()); List afterHooks = createTestStepsForAfterHooks(pickle.getTags()); - return new TestCase(bus.generateId(), testSteps, beforeHooks, afterHooks, pickle, runnerOptions.isDryRun()); + return new TestCase(bus.generateId(), testSteps, beforeHooks, afterHooks, pickle, executionMode); + } + + private ExecutionMode getExecutionMode(Pickle pickle) { + List skipTagExpression = runnerOptions.getSkipTagExpressions(); + if (!skipTagExpression.isEmpty() + && skipTagExpression.stream().allMatch(expression -> expression.evaluate(pickle.getTags()))) { + return ExecutionMode.SKIP; + } else if (runnerOptions.isDryRun()) { + return ExecutionMode.DRY_RUN; + } else { + return ExecutionMode.RUN; + } } private void disposeBackendWorlds() { diff --git a/cucumber-core/src/main/java/io/cucumber/core/runner/TestCase.java b/cucumber-core/src/main/java/io/cucumber/core/runner/TestCase.java index 63e2a72fc6..f67b5f2283 100644 --- a/cucumber-core/src/main/java/io/cucumber/core/runner/TestCase.java +++ b/cucumber-core/src/main/java/io/cucumber/core/runner/TestCase.java @@ -22,8 +22,6 @@ import java.util.UUID; import java.util.stream.Collectors; -import static io.cucumber.core.runner.ExecutionMode.DRY_RUN; -import static io.cucumber.core.runner.ExecutionMode.RUN; import static io.cucumber.messages.Convertor.toMessage; import static java.util.Collections.singletonList; import static java.util.stream.Collectors.toList; @@ -42,14 +40,14 @@ final class TestCase implements io.cucumber.plugin.event.TestCase { List beforeHooks, List afterHooks, Pickle pickle, - boolean dryRun + ExecutionMode executionMode ) { this.id = id; this.testSteps = testSteps; this.beforeHooks = beforeHooks; this.afterHooks = afterHooks; this.pickle = pickle; - this.executionMode = dryRun ? DRY_RUN : RUN; + this.executionMode = executionMode; } private static io.cucumber.messages.types.Group makeMessageGroup( diff --git a/cucumber-core/src/test/java/io/cucumber/core/runner/HookTestStepTest.java b/cucumber-core/src/test/java/io/cucumber/core/runner/HookTestStepTest.java index 569cf827e3..8ec6326cee 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runner/HookTestStepTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runner/HookTestStepTest.java @@ -39,7 +39,7 @@ class HookTestStepTest { Collections.emptyList(), Collections.emptyList(), feature.getPickles().get(0), - false); + ExecutionMode.RUN); private final EventBus bus = mock(EventBus.class); private final UUID testExecutionId = UUID.randomUUID(); private final TestCaseState state = new TestCaseState(bus, testExecutionId, testCase); diff --git a/cucumber-core/src/test/java/io/cucumber/core/runner/PickleStepTestStepTest.java b/cucumber-core/src/test/java/io/cucumber/core/runner/PickleStepTestStepTest.java index 60e561bde9..4f50916ab1 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runner/PickleStepTestStepTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runner/PickleStepTestStepTest.java @@ -58,7 +58,7 @@ class PickleStepTestStepTest { " Given I have 4 cukes in my belly\n"); private final Pickle pickle = feature.getPickles().get(0); private final TestCase testCase = new TestCase(UUID.randomUUID(), Collections.emptyList(), Collections.emptyList(), - Collections.emptyList(), pickle, false); + Collections.emptyList(), pickle, ExecutionMode.RUN); private final EventBus bus = mock(EventBus.class); private final UUID testExecutionId = UUID.randomUUID(); private final TestCaseState state = new TestCaseState(bus, testExecutionId, testCase); diff --git a/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseStateResultTest.java b/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseStateResultTest.java index f1082fe48e..9ed971493d 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseStateResultTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseStateResultTest.java @@ -49,7 +49,7 @@ class TestCaseStateResultTest { Collections.emptyList(), Collections.emptyList(), feature.getPickles().get(0), - false)); + ExecutionMode.RUN)); @BeforeEach void setup() { diff --git a/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseStateTest.java b/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseStateTest.java index dc13053d72..688ee3ed28 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseStateTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseStateTest.java @@ -45,7 +45,7 @@ private TestCaseState createTestCaseState(Feature feature) { Collections.emptyList(), Collections.emptyList(), feature.getPickles().get(0), - false)); + ExecutionMode.RUN)); } @Test diff --git a/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseTest.java b/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseTest.java index 04fd4c5676..463a7c3287 100644 --- a/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseTest.java +++ b/cucumber-core/src/test/java/io/cucumber/core/runner/TestCaseTest.java @@ -88,7 +88,7 @@ void run_wraps_execute_in_test_case_started_and_finished_events() throws Throwab private TestCase createTestCase(PickleStepTestStep... steps) { return new TestCase(UUID.randomUUID(), asList(steps), Collections.emptyList(), Collections.emptyList(), - pickle(), false); + pickle(), ExecutionMode.RUN); } private Pickle pickle() { diff --git a/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/Constants.java b/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/Constants.java index 06a6573e11..579583179a 100644 --- a/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/Constants.java +++ b/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/Constants.java @@ -35,6 +35,8 @@ public final class Constants { */ public static final String EXECUTION_DRY_RUN_PROPERTY_NAME = io.cucumber.core.options.Constants.EXECUTION_DRY_RUN_PROPERTY_NAME; + public static final String EXECUTION_SKIP_TAGS_PROPERTY_NAME = io.cucumber.core.options.Constants.EXECUTION_SKIP_TAGS_PROPERTY_NAME; + /** * Tag replacement pattern for the exclusive resource templates: {@value} * diff --git a/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberEngineOptions.java b/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberEngineOptions.java index f12b963b12..95a842e4d1 100644 --- a/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberEngineOptions.java +++ b/cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberEngineOptions.java @@ -28,6 +28,7 @@ import static io.cucumber.core.resource.ClasspathSupport.CLASSPATH_SCHEME_PREFIX; import static io.cucumber.junit.platform.engine.Constants.ANSI_COLORS_DISABLED_PROPERTY_NAME; import static io.cucumber.junit.platform.engine.Constants.EXECUTION_DRY_RUN_PROPERTY_NAME; +import static io.cucumber.junit.platform.engine.Constants.EXECUTION_SKIP_TAGS_PROPERTY_NAME; import static io.cucumber.junit.platform.engine.Constants.FEATURES_PROPERTY_NAME; import static io.cucumber.junit.platform.engine.Constants.FILTER_NAME_PROPERTY_NAME; import static io.cucumber.junit.platform.engine.Constants.FILTER_TAGS_PROPERTY_NAME; @@ -41,6 +42,7 @@ import static io.cucumber.junit.platform.engine.Constants.PLUGIN_PUBLISH_TOKEN_PROPERTY_NAME; import static io.cucumber.junit.platform.engine.Constants.SNIPPET_TYPE_PROPERTY_NAME; import static io.cucumber.junit.platform.engine.Constants.UUID_GENERATOR_PROPERTY_NAME; +import static java.util.Collections.emptyList; class CucumberEngineOptions implements io.cucumber.core.plugin.Options, @@ -164,6 +166,14 @@ public Class getUuidGeneratorClass() { .orElse(null); } + @Override + public List getSkipTagExpressions() { + return configurationParameters + .get(EXECUTION_SKIP_TAGS_PROPERTY_NAME, TagExpressionParser::parse) + .map(Collections::singletonList) + .orElse(emptyList()); + } + boolean isParallelExecutionEnabled() { return configurationParameters .getBoolean(PARALLEL_EXECUTION_ENABLED_PROPERTY_NAME) @@ -185,6 +195,6 @@ List featuresWithLines() { .sorted(Comparator.comparing(FeatureWithLines::uri)) .distinct() .collect(Collectors.toList())) - .orElse(Collections.emptyList()); + .orElse(emptyList()); } }