diff --git a/pom.xml b/pom.xml index 8bf7537..ece64dd 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ com.google.pdsl pdsl - 1.9.0 + 1.10.0 pdsl http://www.github.com/google/polymorphicDSL diff --git a/src/main/java/com/pdsl/gherkin/DefaultGherkinTestSpecificationFactory.java b/src/main/java/com/pdsl/gherkin/DefaultGherkinTestSpecificationFactory.java index 7192a25..00ce0f6 100644 --- a/src/main/java/com/pdsl/gherkin/DefaultGherkinTestSpecificationFactory.java +++ b/src/main/java/com/pdsl/gherkin/DefaultGherkinTestSpecificationFactory.java @@ -4,10 +4,10 @@ import com.pdsl.exceptions.SentenceNotFoundException; import com.pdsl.gherkin.filter.GherkinTagsVisitorImpl; import com.pdsl.gherkin.models.GherkinBackground; +import com.pdsl.gherkin.models.GherkinScenario; import com.pdsl.gherkin.models.GherkinStep; import com.pdsl.gherkin.specifications.GherkinTestSpecification; import com.pdsl.gherkin.specifications.GherkinTestSpecificationFactory; -import com.pdsl.gherkin.testcases.GherkinTestCaseSpecification; import com.pdsl.logging.AnsiTerminalColorHelper; import com.pdsl.runners.PdslTest; import com.pdsl.runners.RecognizedBy; @@ -24,6 +24,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.net.URI; +import java.net.URISyntaxException; import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Collection; @@ -230,7 +231,7 @@ public Optional> getTestSpecifications(Set te featureBuilder.withMetaData( new ByteArrayInputStream(featureMetaData.toByteArray())); } catch(IOException e){ - //TODO Y + throw new IllegalStateException("There was an issue processing a feature file!", e); } List pickles = getGherkinStepSpecificationScenarios(pickleJar.getScenarios(), @@ -241,7 +242,7 @@ public Optional> getTestSpecifications(Set te pickles.addAll(transformRulesToTestSpecifications(pickleJar.getRules(), pickleJar.getLocation())); } featureBuilder.withChildTestSpecifications(pickles); - featureTestSpecifications.add(new GherkinTestCaseSpecification(allTagsForTestCase, featureBuilder.build())); + featureTestSpecifications.add(new GherkinTestSpecification(featureBuilder.build(), allTagsForTestCase)); } return Optional.of(featureTestSpecifications); } @@ -249,10 +250,30 @@ public Optional> getTestSpecifications(Set te private List transformScenariosToTestSpecifications(List scenarios, Set parentTags, URI originalSourceLocation) { List gherkinTestSpecifications = new ArrayList<>(); for (PickleJar.PickleJarScenario pickleJarScenario : scenarios) { + var position = pickleJarScenario.getScenarioPosition(); + URI processedUri = null; + try { + processedUri = new URI( + originalSourceLocation.getScheme(), + originalSourceLocation.getRawUserInfo(), // Use raw to preserve encoding + originalSourceLocation.getHost(), + originalSourceLocation.getPort(), + originalSourceLocation.getRawPath(), // Use raw to preserve encoding + // Provide the line number using the rfc 5147 standard for 'text/plain' + // Also provide positional data as params so that test frameworks can group them together + // Preserve existing fragment + String.format("%s=%d&%s=%d&%s=%d", + GherkinScenario.ScenarioPosition.RULE_INDEX, position.ruleIndex(), + GherkinScenario.ScenarioPosition.ORDINAL, position.ordinal(), + GherkinScenario.ScenarioPosition.TABLE_INDEX, position.testIndex()), // Use the query string to provide position information + String.format("line=%d", pickleJarScenario.getLineNumber())); + } catch (URISyntaxException e) { + processedUri = originalSourceLocation; + } DefaultTestSpecification.Builder topLevelScenario = new DefaultTestSpecification.Builder( - pickleJarScenario.getTitleWithSubstitutions(), - // Provide the line number using the rfc 5147 standard for 'text/plain' - originalSourceLocation.resolve("#line=" + pickleJarScenario.getLineNumber())); + pickleJarScenario.getTitleWithSubstitutions(), processedUri + + ); // Provide metadata topLevelScenario.withMetaData(new ByteArrayInputStream(extractMetaData(pickleJarScenario).toByteArray())); // Process step body @@ -316,7 +337,9 @@ private Optional processStepBody(String title, List s private List transformRulesToTestSpecifications(List rules, URI originalSourceLocation) { List testSpecifications = new ArrayList<>(); + int ruleIndex = 0; for (PickleJar.PickleJarRule rule : rules) { + ruleIndex++; DefaultTestSpecification.Builder ruleBuilder = new DefaultTestSpecification.Builder(rule.getTitle(),originalSourceLocation); ByteArrayOutputStream ruleMetaData = new ByteArrayOutputStream(); if (rule.getLongDescription().isPresent()) { @@ -327,7 +350,7 @@ private List transformRulesToTestSpecifications(List> filteredBackgroundStepBody = processStepBodyContent(bg.getSteps().orElseThrow()); filteredBackgroundStepBody.ifPresent(ruleBuilder::withTestPhrases); } diff --git a/src/main/java/com/pdsl/gherkin/PickleJar.java b/src/main/java/com/pdsl/gherkin/PickleJar.java index 1a0037f..5ec105e 100644 --- a/src/main/java/com/pdsl/gherkin/PickleJar.java +++ b/src/main/java/com/pdsl/gherkin/PickleJar.java @@ -2,6 +2,7 @@ import com.google.common.base.Preconditions; import com.pdsl.gherkin.models.GherkinBackground; +import com.pdsl.gherkin.models.GherkinScenario; import java.net.URI; import java.util.*; @@ -201,6 +202,8 @@ static class PickleJarScenario { private final List stepsWithParameterSubstitutionsIfNeeded; private Optional> tags; private final int lineNumber; + private final GherkinScenario.ScenarioPosition scenarioPosition; + private PickleJarScenario(Builder builder) { this.tags = builder.tags; this.longDescription = builder.longDescription; @@ -208,9 +211,14 @@ private PickleJarScenario(Builder builder) { this.lineNumber = builder.lineNumber; this.scenarioTitleWithParameterSubstitutionsIfNeeded = builder.titleWithSubstitutions; this.stepsWithParameterSubstitutionsIfNeeded = builder.stepsWithSubstitutions; + this.scenarioPosition = builder.scenarioPosition.orElseThrow(); } public int getLineNumber() { return lineNumber; } + + public GherkinScenario.ScenarioPosition getScenarioPosition() { + return scenarioPosition; + } public Optional> getTags() { return tags; } @@ -233,6 +241,7 @@ public static class Builder { private Optional> tags = Optional.empty(); private Optional longDescription = Optional.empty(); private int lineNumber = -1; + private Optional scenarioPosition; public Builder(String titleWithSubstitutions, List stepsWithSubstitutions) { this.titleWithSubstitutions = titleWithSubstitutions; @@ -248,6 +257,11 @@ public Builder withLineNumber(int lineNumber) { return this; } + public Builder withScenarioPosition(int depth, int ordinal, int tableIndex) { + this.scenarioPosition = Optional.of(new GherkinScenario.ScenarioPosition(depth, ordinal, tableIndex)); + return this; + } + public Builder withLongDescription(String longDescription) { this.longDescription = Optional.ofNullable(longDescription); return this; diff --git a/src/main/java/com/pdsl/gherkin/PickleJarFactory.java b/src/main/java/com/pdsl/gherkin/PickleJarFactory.java index f886cb4..16b83b7 100644 --- a/src/main/java/com/pdsl/gherkin/PickleJarFactory.java +++ b/src/main/java/com/pdsl/gherkin/PickleJarFactory.java @@ -84,7 +84,7 @@ public List getPickleJars(Set testResources) { // Top level scenarios if (feature.getOptionalGherkinScenarios().isPresent()) { List topLevelPickles = - convertScenariosToPickleJarScenarios(feature.getOptionalGherkinScenarios().get()); + convertScenariosToPickleJarScenarios(feature.getOptionalGherkinScenarios().get(), 0); pickleJarBuilder.withFeatureLevelScenarios(topLevelPickles); } // Add all rules @@ -97,15 +97,18 @@ public List getPickleJars(Set testResources) { } - private List convertScenariosToPickleJarScenarios(List scenarios) { + private List convertScenariosToPickleJarScenarios(List scenarios, int depth) { + int nextOrdinal = 0; List pickleJarScenarios = new ArrayList<>(); for (GherkinScenario scenario : scenarios) { + nextOrdinal++; // If the scenario has an examples table the tags will need to be combined with the scenario level Set tags = new HashSet<>(); if (scenario.getTags().isPresent()) { tags.addAll(processTags(scenario.getTags().get())); } if (scenario.getExamples().isPresent()) { + int tableIndex = 1; for (GherkinExamplesTable table : scenario.getExamples().get()) { Set tableTags = new HashSet<>(tags); for (Map substitutions : table.getRowsWithCell()) { @@ -120,7 +123,8 @@ private List convertScenariosToPickleJarScenarios(L scenario.getTitle().orElseThrow().getStringWithSubstitutions(substitutionsAsStrings), substitutedSteps) // All parameters should have the same line number, so just get the number from the first one - .withLineNumber(substitutions.values().stream().findFirst().orElseThrow().lineNumber()); + .withLineNumber(substitutions.values().stream().findFirst().orElseThrow().lineNumber()) + .withScenarioPosition(depth, nextOrdinal, tableIndex++); if (scenario.getLongDescription().isPresent()) { builder.withLongDescription(scenario.getLongDescription().get().getStringWithSubstitutions(substitutionsAsStrings)); } @@ -147,7 +151,8 @@ private List convertScenariosToPickleJarScenarios(L PickleJar.PickleJarScenario.Builder builder = new PickleJar.PickleJarScenario.Builder( scenario.getTitle().orElseThrow().getRawString(), stepBody) - .withLineNumber(scenario.getLineNumber()); + .withLineNumber(scenario.getLineNumber()) + .withScenarioPosition(depth,nextOrdinal, 0); if (!tags.isEmpty()) { builder.withTags(processTags(tags)); } @@ -163,9 +168,9 @@ private List convertScenariosToPickleJarScenarios(L private List convertRulesToPickles(List rules) { List pickleJarRules = new ArrayList<>(); - for (GherkinRule rule : rules) { - - List scenarios = convertScenariosToPickleJarScenarios(rule.getScenarios().orElseThrow()); + for (int i=0; i < rules.size(); i++) { + GherkinRule rule = rules.get(i); + List scenarios = convertScenariosToPickleJarScenarios(rule.getScenarios().orElseThrow(), i+1); PickleJar.PickleJarRule.Builder builder = new PickleJar.PickleJarRule.Builder(rule.getTitle().orElseThrow(), scenarios); if (rule.getBackground().isPresent()) { builder.withBackground(rule.getBackground().get()); diff --git a/src/main/java/com/pdsl/gherkin/models/GherkinScenario.java b/src/main/java/com/pdsl/gherkin/models/GherkinScenario.java index 13a981f..7a862da 100644 --- a/src/main/java/com/pdsl/gherkin/models/GherkinScenario.java +++ b/src/main/java/com/pdsl/gherkin/models/GherkinScenario.java @@ -1,8 +1,8 @@ package com.pdsl.gherkin.models; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; +import java.net.URI; +import java.util.*; +import java.util.stream.Collectors; public class GherkinScenario { private final Optional> tags; @@ -10,6 +10,7 @@ public class GherkinScenario { private final Optional longDescription; private final Optional> stepsList; private final Optional> examples; + private final Optional scenarioPosition; private final int lineNumber; public GherkinScenario(Builder builder) { @@ -22,8 +23,118 @@ public GherkinScenario(Builder builder) { this.examples = builder.examples.isEmpty() ? Optional.empty() : Optional.of(builder.examples); this.lineNumber = builder.lineNumber; + this.scenarioPosition = builder.scenarioPosition; } + /** + * A specification of the hierarchical position this scenario appeared in with relation to other scenarios. + *

+ * The ruleIndex specifies which rule the scenario was found. [e.g. which rule it was found in] + * If the test was not nested in a rule the value will be 0 + *

+ * The ordinal specifies which order this test showed up in relation to the others in the same rule index. + *

+ * The testIndex specifies is the test was derived from an examples table. If it was, it is the + * nth row it appeared in starting from one. If it was not in an examples table the number will be 0. + *

+ * This encoding CANNOT guarantee whether an arbitrary scenario was declared before another as it is possible + * to intersperse rule nodes between root level scenarios. If you want to know the prceise order the test + * was declared in the original source file use #getLineNumber() and compare using the + * {@see com.pdsl.testcases.DefaultTestCase.PdslTestCaseComparator} + *

+ * For example: + *

+ *

+     *     {@code
+     *     Feature:
+     *      Scenario:
+     *      # First part is "0" because it is a root node. Last part is "0" because it is not in a table.
+     *        Then this group ordinal is 0.1.0
+     *      Scenario:
+     *        Then this group ordinal is 0.2.0 # The second test in the root, se we increment to 2.
+     *      Scenario:
+     *        Then this group ordinal is 
+     *      Examples:
+     *        |ORDINAL|
+     *        | 0.3.1 | # Second test in the root, so we increment the second value to 2
+     *        | 0.3.2 | # Increment last digit as it comes from the same group
+     *        | 0.3.3 |
+     *
+     *      Rule: First rule (1)
+     *        Scenario:
+     *         Then this group ordinal is 1.1.0
+     *        Scenario:
+     *         Then this group ordinal is 1.2.0
+     *        Scenario:
+     *          Then this group oridinal is 
+     *          Examples:
+     *          |ORDINAL|
+     *          | 1.3.1 |
+     *          | 1.3.2 |
+     *
+     *          # Multi-tables continue from the index used in the last table
+     *          Examples:
+     *          |ORDINAL|
+     *          | 1.3.3 |
+     *          | 1.3.4
+     *
+     *      Scenario:
+     *        Then this group ordinal is 0.4.0 # Note we're back at root and continue from the last testPosition
+     *
+     *      Rule: Second rule (2)
+     *        Scenario:
+     *          Then this group ordinal is 2.1.0
+     * }
+     * 
+ * + * @param ruleIndex the nth rule this scenario was derived from, 0 if not in a rule + * @param ordinal the nth position of this scenario relative to others in the same depth + * @param testIndex 0 if not derived from an examples table, otherwise the nth row starting from 1 + */ + public record ScenarioPosition(int ruleIndex, int ordinal, int testIndex) implements Comparable { + + public static String RULE_INDEX= "ruleIndex"; + public static String ORDINAL = "ordinal"; + public static String TABLE_INDEX = "tableIndex"; + private static final ScenarioPositionComparator SINGLETON = new ScenarioPositionComparator(); + + private static class ScenarioPositionComparator implements Comparator { + @Override + public int compare(ScenarioPosition p1, ScenarioPosition p2) { + if (p1.ruleIndex != p2.ruleIndex) { + return Integer.compare(p1.ruleIndex, p2.ruleIndex); + } + if (p1.ordinal != p2.ordinal) { + return Integer.compare(p1.ordinal, p2.ordinal); + } + return Integer.compare(p1.testIndex, p2.testIndex); + } + } + + @Override + public int compareTo(ScenarioPosition scenarioPosition) { + return SINGLETON.compare(this, scenarioPosition); + } + + public static Optional from(URI uri) { + Map params = Arrays.stream(uri.getQuery().split("&")) + .map(param -> param.split("=")) + .filter(arr -> arr.length == 2) + .collect(Collectors.toMap(arr -> arr[0], arr -> arr[1])); + try { + int ruleIndex = Integer.parseInt(params.get(RULE_INDEX)); + int ordinal = Integer.parseInt(params.get(ORDINAL)); + int tableIndex = Integer.parseInt(params.get(TABLE_INDEX)); + return Optional.of(new ScenarioPosition(ruleIndex, ordinal, tableIndex)); + } catch(RuntimeException e) { + return Optional.empty(); + } + } + } + + + public Optional getScenarioPositition() { return scenarioPosition; } + public Optional> getTags() { return tags; } @@ -55,11 +166,17 @@ public static class Builder { private String longDescription = ""; private Optional> stepsList = Optional.empty(); private int lineNumber = -1; + private Optional scenarioPosition = Optional.empty(); public GherkinScenario build() { return new GherkinScenario(this); } + public Builder withScenarioPosition(ScenarioPosition scenarioPosition) { + this.scenarioPosition = Optional.ofNullable(scenarioPosition); + return this; + } + public Builder addExamples(GherkinExamplesTable examples) { this.examples.add(examples); return this; diff --git a/src/main/java/com/pdsl/gherkin/testcases/GherkinTestCaseSpecification.java b/src/main/java/com/pdsl/gherkin/testcases/GherkinTestCaseSpecification.java deleted file mode 100644 index 93046d6..0000000 --- a/src/main/java/com/pdsl/gherkin/testcases/GherkinTestCaseSpecification.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.pdsl.gherkin.testcases; - -import com.pdsl.specifications.DefaultTestSpecification; -import com.pdsl.specifications.FilteredPhrase; -import com.pdsl.specifications.TaggedTestSpecification; -import com.pdsl.specifications.TestSpecification; - -import java.io.InputStream; -import java.net.URI; -import java.util.ArrayList; -import java.util.List; -import java.util.Optional; -import java.util.Set; - -public class GherkinTestCaseSpecification implements TaggedTestSpecification { - - private final Set tags; - private final TestSpecification testSpecification; - - public GherkinTestCaseSpecification(Set tags, TestSpecification testSpecification) { - this.testSpecification = testSpecification; - this.tags = tags; - } - - public GherkinTestCaseSpecification(List childFeatures, URI originalTestResource) { - this.testSpecification = new DefaultTestSpecification.Builder("Gherkin Test Container", originalTestResource) - .withChildTestSpecifications(new ArrayList<>(childFeatures)) - .build(); - this.tags = Set.of(); - } - - @Override - public Set getTags() { - return tags; - } - - @Override - public Optional getMetaData() { - return testSpecification.getMetaData(); - } - - @Override - public Optional> nestedTestSpecifications() { - return testSpecification.nestedTestSpecifications(); - } - - @Override - public String getName() { - return testSpecification.getName(); - } - - @Override - public Optional> getFilteredPhrases() { - return testSpecification.getFilteredPhrases(); - } - - @Override - public URI getOriginalTestResource() { - return testSpecification.getOriginalTestResource(); - } -} diff --git a/src/main/java/com/pdsl/testcases/DefaultPdslTestCase.java b/src/main/java/com/pdsl/testcases/DefaultPdslTestCase.java index ec274e6..2b602ad 100644 --- a/src/main/java/com/pdsl/testcases/DefaultPdslTestCase.java +++ b/src/main/java/com/pdsl/testcases/DefaultPdslTestCase.java @@ -110,12 +110,12 @@ public List getFilteredPhrases() { public static class PdslTestCaseComparator implements Comparator { private static final int NUMBER_INDEX = "line=".length(); + @Override public int compare(TestCase source1, TestCase source2) { - int compareUris = source1.getOriginalSource().getRawSchemeSpecificPart().compareTo( - source2.getOriginalSource().getRawSchemeSpecificPart()); + int compareUris = source1.getOriginalSource().getPath().compareTo( + source2.getOriginalSource().getPath()); // If the scenarios came from the same file have the most recent scenario first via line number - if (compareUris == 0) { String fragment1 = source1.getOriginalSource().getFragment(); String fragment2 = source2.getOriginalSource().getFragment(); diff --git a/src/test/java/com/pdsl/api/ScenarioPositionTest.java b/src/test/java/com/pdsl/api/ScenarioPositionTest.java new file mode 100644 index 0000000..4ed8b5c --- /dev/null +++ b/src/test/java/com/pdsl/api/ScenarioPositionTest.java @@ -0,0 +1,122 @@ +package com.pdsl.api; + +import com.pdsl.executors.DefaultPolymorphicDslTestExecutor; +import com.pdsl.executors.PolymorphicDslTestExecutor; +import com.pdsl.gherkin.DefaultGherkinTestSpecificationFactory; +import com.pdsl.gherkin.models.GherkinScenario; +import com.pdsl.grammars.AllGrammarsLexer; +import com.pdsl.grammars.AllGrammarsParser; +import com.pdsl.reports.DefaultTestResult; +import com.pdsl.reports.PolymorphicDslTestRunResults; +import com.pdsl.reports.proto.TechnicalReportData; +import com.pdsl.specifications.TestSpecification; +import com.pdsl.testcases.PreorderTestCaseFactory; +import com.pdsl.testcases.TestCase; +import com.pdsl.transformers.DefaultPolymorphicDslPhraseFilter; +import org.junit.Test; +import org.mockito.Mockito; + +import java.io.OutputStream; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.util.*; + +import static com.google.common.truth.Truth.assertThat; + +public class ScenarioPositionTest { + + + + private static final DefaultGherkinTestSpecificationFactory specificationFactory = new DefaultGherkinTestSpecificationFactory.Builder( + new DefaultPolymorphicDslPhraseFilter(AllGrammarsParser.class, AllGrammarsLexer.class)).build(); + private static final PolymorphicDslTestExecutor executor = DefaultPolymorphicDslTestExecutor + .ofWithoutDuplicateFiltering(List.of()); + private static final PreorderTestCaseFactory testCaseFactory = new PreorderTestCaseFactory(); + + private static URI getURI(URL url) throws URISyntaxException { + return Objects.requireNonNull(url).toURI(); + } + + @Test + public void veryLongResultsLocationInformation_groupedProperlyInNavigableSet() throws URISyntaxException { + // ARRANGE + final URI complexBackground = getURI(getClass().getClassLoader() + .getResource("testdata/good/very_long.feature")); + Collection specs = specificationFactory.getTestSpecifications(Set.of(complexBackground)) + .orElseThrow(); + Collection testCases = testCaseFactory.processTestSpecification(specs); + PolymorphicDslTestRunResults results = new PolymorphicDslTestRunResults(List.of(Mockito.mock(OutputStream.class)), "API"); + + // ACT + testCases.forEach(tc -> + results.addTestResult(new DefaultTestResult(1, tc, TechnicalReportData.Status.PASSED))); + List positions = results.getTestResults().stream() + .map(r -> r.getTestCase().getOriginalSource()) + .sorted(new Comparator(){ + + @Override + public int compare(URI u1, URI u2) { + return u1.getFragment().split("=")[1].compareTo(u2.getFragment().split("=")[1]); + } + }) + .map(GherkinScenario.ScenarioPosition::from) + .map(Optional::orElseThrow) + .toList(); + // ASSERT + + for (int i=1; i <= positions.size(); i++) { + GherkinScenario.ScenarioPosition position = positions.get(i - 1); + assertThat(position.ruleIndex()).isEqualTo(0); + assertThat(position.ordinal()).isEqualTo(i); + assertThat(position.testIndex()).isEqualTo(0); + } + + } + + @Test + public void featureTreeStructure_groupedProperlyInNavigableSet() throws URISyntaxException { + // ARRANGE + final URI complexBackground = getURI(getClass().getClassLoader() + .getResource("framework_specifications/features/ScenarioPositionData.feature")); + Collection specs = specificationFactory.getTestSpecifications(Set.of(complexBackground)) + .orElseThrow(); + Collection testCases = testCaseFactory.processTestSpecification(specs); + PolymorphicDslTestRunResults results = new PolymorphicDslTestRunResults(List.of(Mockito.mock(OutputStream.class)), "API"); + testCases.forEach(tc -> + results.addTestResult(new DefaultTestResult(1, tc, TechnicalReportData.Status.PASSED))); + List actualPositions = results.getTestResults().stream() + .map(r -> r.getTestCase().getOriginalSource()) + .sorted(new Comparator(){ + + @Override + public int compare(URI u1, URI u2) { + return u1.getFragment().split("=")[1].compareTo(u2.getFragment().split("=")[1]); + } + }) + .map(GherkinScenario.ScenarioPosition::from) + .map(Optional::orElseThrow) + .toList(); + // ASSERT + List expectedPositions = List.of( + new GherkinScenario.ScenarioPosition(0,1,0), + new GherkinScenario.ScenarioPosition(0,2,0), + new GherkinScenario.ScenarioPosition(0,3,1), + new GherkinScenario.ScenarioPosition(0,3,2), + new GherkinScenario.ScenarioPosition(0,4,0), + new GherkinScenario.ScenarioPosition(0,5,1), + new GherkinScenario.ScenarioPosition(0,5,2), + new GherkinScenario.ScenarioPosition(0,5,3), + new GherkinScenario.ScenarioPosition(0,5,4), + new GherkinScenario.ScenarioPosition(1,1,0), + new GherkinScenario.ScenarioPosition(2,1,1), + new GherkinScenario.ScenarioPosition(2,1,2) + ); + + assertThat(actualPositions.size()).isEqualTo(expectedPositions.size()); + for (int i=0; i < expectedPositions.size(); i++) { + assertThat(actualPositions.get(i)).isEqualTo(expectedPositions.get(i)); + } + } + +} diff --git a/src/test/resources/framework_specifications/features/ScenarioPositionData.feature b/src/test/resources/framework_specifications/features/ScenarioPositionData.feature new file mode 100644 index 0000000..3eea23a --- /dev/null +++ b/src/test/resources/framework_specifications/features/ScenarioPositionData.feature @@ -0,0 +1,56 @@ +Feature: Scenario Locations + Some test frameworks behave better when the test cases are grouped together based on how they originally showed + up in the feature file. Some PDSL implementations support a "ScenarioPostion" which provide: + - Rule Index: The nth rule it was assotiated with [0 if not part of any rule] + - Ordinal: The nth test case in the rule index [Always greater than or equal to 1] + - Table Index: The nth test case from examples tables [0 if there was no table] + + The position is notated as .. + Examples of proper usage of this notation are shown in the below tests. + + + Scenario: + Then the position is 0.1.0 + + Scenario: + Then the position is 0.2.0 + + Scenario Outline: : + Then the position is + + Examples: + |POSITION| + | 0.3.1 | + | 0.3.2 | + + Scenario: Position counter continues from the same depth + Then the position is 0.4.0 + + Scenario Outline: + Then the postion is + + Examples: + |POSITION| + | 0.5.1 | + | 0.5.2 | + + Examples: + |POSITION| + | 0.5.3 | + | 0.5.4 | + + + Rule: + Scenario: + Then the position is 1.1.0 + + Rule: + Scenario: + Then the position is + Examples: + |POSITION| + | 2.1.1 | + + Examples: + | POSITION | + | 2.1.2 |