-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Include pickle name if parameterized (#44)
Cucumber originally only had Features with Scenarios. When Scenario Outlines were added, it became hard to distinguish which example failed. To work around this Scenario Outline may have placeholders in their name. These placeholders are replaced when creating a pickle name. This helps ensure that each scenario is unique. ``` Feature: Examples Tables Scenario Outline: Eating <eat> cucumbers Given there are <start> cucumbers When I eat <eat> cucumbers Then I should have <left> cucumbers Examples: These are passing | start | eat | left | | 12 | 5 | 7 | ``` This would be rendered as: ``` Examples Tables └── Eating 5 cucumbers ``` But with the addition of the Rule element and test frameworks supporting hierarchical test structures it also becomes desirable to include the structure of a feature file in the test name. So we would now render: ``` Examples Tables └── Eating cucumbers └──These are passing └── #1.1 ``` And while this hierarchy is sufficient to identify a failed example, it is not very easy to do so when there are many. So by including the pickle name when the Scenario Outline is parameterized we can render: ``` Examples Tables └── Eating <eat> cucumbers └──These are passing └── #1.1: Eating 5 cucumbers ```
- Loading branch information
1 parent
2f6f474
commit f37e42b
Showing
14 changed files
with
921 additions
and
332 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
45 changes: 45 additions & 0 deletions
45
java/src/main/java/io/cucumber/query/LineageCollector.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package io.cucumber.query; | ||
|
||
import io.cucumber.messages.types.Examples; | ||
import io.cucumber.messages.types.Feature; | ||
import io.cucumber.messages.types.GherkinDocument; | ||
import io.cucumber.messages.types.Pickle; | ||
import io.cucumber.messages.types.Rule; | ||
import io.cucumber.messages.types.Scenario; | ||
import io.cucumber.messages.types.TableRow; | ||
|
||
/** | ||
* Collect the {@link Lineage} of a | ||
* {@linkplain io.cucumber.messages.types.GherkinDocument GherkinDocument element} | ||
* or {@link Pickle} and reduce it to a single result. | ||
* | ||
* @param <T> the type reduced to. | ||
*/ | ||
interface LineageCollector<T> { | ||
default void add(GherkinDocument document) { | ||
|
||
} | ||
|
||
default void add(Feature feature) { | ||
|
||
} | ||
|
||
default void add(Rule rule) { | ||
|
||
} | ||
|
||
default void add(Scenario scenario) { | ||
|
||
} | ||
|
||
default void add(Examples examples, int index) { | ||
} | ||
|
||
default void add(TableRow example, int index) { | ||
} | ||
|
||
default void add(Pickle pickle) { | ||
} | ||
|
||
T finish(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package io.cucumber.query; | ||
|
||
import io.cucumber.messages.types.Pickle; | ||
|
||
import java.util.function.Supplier; | ||
|
||
import static java.util.Objects.requireNonNull; | ||
|
||
/** | ||
* Visit the {@link Lineage} of a {@linkplain io.cucumber.messages.types.GherkinDocument GherkinDocument element} | ||
* or {@link Pickle} and reduce it. | ||
* <p> | ||
* Because we are using messages we can not express the hierarchy of elements in | ||
* a {@link io.cucumber.messages.types.GherkinDocument} programmatically as a | ||
* tree of nodes. But we can still express the operations that would be typically | ||
* done this way as an operation on the lineage of those messages. | ||
* | ||
* @param <T> the type reduced to. | ||
*/ | ||
interface LineageReducer<T> { | ||
|
||
static <T> LineageReducer<T> descending(Supplier<? extends LineageCollector<T>> collector) { | ||
return new LineageReducerDescending<>(collector); | ||
} | ||
|
||
T reduce(Lineage lineage); | ||
|
||
T reduce(Lineage lineage, Pickle pickle); | ||
|
||
} |
45 changes: 45 additions & 0 deletions
45
java/src/main/java/io/cucumber/query/LineageReducerDescending.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package io.cucumber.query; | ||
|
||
import io.cucumber.messages.types.Pickle; | ||
|
||
import java.util.function.Supplier; | ||
|
||
import static java.util.Objects.requireNonNull; | ||
|
||
/** | ||
* Reduces the lineage of a Gherkin document element in descending order. | ||
* | ||
* @param <T> type to which the lineage is reduced. | ||
*/ | ||
class LineageReducerDescending<T> implements LineageReducer<T> { | ||
|
||
private final Supplier<? extends LineageCollector<T>> reducerSupplier; | ||
|
||
LineageReducerDescending(Supplier<? extends LineageCollector<T>> reducerSupplier) { | ||
this.reducerSupplier = requireNonNull(reducerSupplier); | ||
} | ||
|
||
@Override | ||
public T reduce(Lineage lineage) { | ||
LineageCollector<T> reducer = reducerSupplier.get(); | ||
reduceAddLineage(reducer, lineage); | ||
return reducer.finish(); | ||
} | ||
|
||
@Override | ||
public T reduce(Lineage lineage, Pickle pickle) { | ||
LineageCollector<T> reducer = reducerSupplier.get(); | ||
reduceAddLineage(reducer, lineage); | ||
reducer.add(pickle); | ||
return reducer.finish(); | ||
} | ||
|
||
private static <T> void reduceAddLineage(LineageCollector<T> reducer, Lineage lineage) { | ||
reducer.add(lineage.document()); | ||
lineage.feature().ifPresent(reducer::add); | ||
lineage.rule().ifPresent(reducer::add); | ||
lineage.scenario().ifPresent(reducer::add); | ||
lineage.examples().ifPresent(examples -> reducer.add(examples, lineage.examplesIndex().orElse(0))); | ||
lineage.example().ifPresent(example -> reducer.add(example, lineage.exampleIndex().orElse(0))); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package io.cucumber.query; | ||
|
||
import io.cucumber.messages.types.Examples; | ||
import io.cucumber.messages.types.Feature; | ||
import io.cucumber.messages.types.FeatureChild; | ||
import io.cucumber.messages.types.GherkinDocument; | ||
import io.cucumber.messages.types.Rule; | ||
import io.cucumber.messages.types.RuleChild; | ||
import io.cucumber.messages.types.Scenario; | ||
import io.cucumber.messages.types.TableRow; | ||
|
||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Optional; | ||
import java.util.function.BiConsumer; | ||
import java.util.function.Consumer; | ||
import java.util.function.Supplier; | ||
|
||
class Lineages { | ||
|
||
/** | ||
* Create map of a {@link GherkinDocument} element to its {@link Lineage} in that document. | ||
* <p> | ||
* @param document to create the lineage of | ||
* @return a map of the document elements to their lineage. | ||
*/ | ||
static Map<String, Lineage> of(GherkinDocument document) { | ||
Map<String, Lineage> elements = new HashMap<>(); | ||
Lineage lineage = new Lineage(document); | ||
String uri = document.getUri() | ||
.orElseThrow(() -> new IllegalArgumentException("document.uri must not be null")); | ||
elements.put(uri, lineage); | ||
document.getFeature().ifPresent(ofFeature(lineage, elements)); | ||
return elements; | ||
} | ||
|
||
private static Consumer<Feature> ofFeature(Lineage parent, Map<String, Lineage> elements) { | ||
return feature -> { | ||
Lineage lineage = new Lineage(parent, feature); | ||
feature.getChildren().forEach(ofFeatureChild(lineage, elements)); | ||
}; | ||
} | ||
|
||
private static Consumer<FeatureChild> ofFeatureChild(Lineage parent, Map<String, Lineage> elements) { | ||
return featureChild -> { | ||
featureChild.getScenario().ifPresent(ofScenario(parent, elements)); | ||
featureChild.getRule().ifPresent(ofRule(parent, elements)); | ||
}; | ||
} | ||
|
||
private static Consumer<Rule> ofRule(Lineage parent, Map<String, Lineage> elements) { | ||
return rule -> { | ||
Lineage lineage = new Lineage(parent, rule); | ||
elements.put(rule.getId(), lineage); | ||
rule.getChildren().forEach(ofRuleChild(lineage, elements)); | ||
}; | ||
} | ||
|
||
private static Consumer<RuleChild> ofRuleChild(Lineage parent, Map<String, Lineage> elements) { | ||
return ruleChild -> ruleChild.getScenario().ifPresent(ofScenario(parent, elements)); | ||
} | ||
|
||
private static Consumer<Scenario> ofScenario(Lineage parent, Map<String, Lineage> elements) { | ||
return scenario -> { | ||
Lineage lineage = new Lineage(parent, scenario); | ||
elements.put(scenario.getId(), lineage); | ||
forEachIndexed(scenario.getExamples(), ofExamples(lineage, elements)); | ||
}; | ||
} | ||
|
||
private static BiConsumer<Examples, Integer> ofExamples(Lineage parent, Map<String, Lineage> elements) { | ||
return (examples, examplesIndex) -> { | ||
Lineage lineage = new Lineage(parent, examples, examplesIndex); | ||
elements.put(examples.getId(), lineage); | ||
forEachIndexed(examples.getTableBody(), ofExample(lineage, elements)); | ||
}; | ||
} | ||
|
||
private static BiConsumer<TableRow, Integer> ofExample(Lineage parent, Map<String, Lineage> elements) { | ||
return (example, exampleIndex) -> { | ||
Lineage lineage = new Lineage(parent, example, exampleIndex); | ||
elements.put(example.getId(), lineage); | ||
}; | ||
} | ||
|
||
private static <T> void forEachIndexed(List<T> items, BiConsumer<T, Integer> consumer) { | ||
for (int i = 0; i < items.size(); i++) { | ||
consumer.accept(items.get(i), i); | ||
} | ||
} | ||
} |
Oops, something went wrong.