Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fixed tag handling #169

Merged
merged 1 commit into from
Aug 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

Back to [Readme](README.md).

## [1.8.0] - 2020-08-15

### Fixed

* Correct handling of feature tags in combination with multiple tagged example tables (#168)

## [1.7.2] - 2020-04-03

### Fixed
Expand Down Expand Up @@ -304,6 +310,7 @@ Back to [Readme](README.md).

Initial project version on GitHub and Maven Central.

[1.8.0]: https://github.com/trivago/cucable-plugin/compare/1.7.2...1.8.0
[1.7.2]: https://github.com/trivago/cucable-plugin/compare/1.7.1...1.7.2
[1.7.1]: https://github.com/trivago/cucable-plugin/compare/1.7.0...1.7.1
[1.7.0]: https://github.com/trivago/cucable-plugin/compare/1.6.0...1.7.0
Expand Down
2 changes: 1 addition & 1 deletion example-project/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

<groupId>com.trivago.rta</groupId>
<artifactId>cucable-test-project</artifactId>
<version>1.7.2</version>
<version>1.8.0</version>
<packaging>jar</packaging>

<properties>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
@us1
Feature: My feature with tags and tagged examples

Scenario Outline: Tag test
Given this is a given step
When I do something
Then I am on a page with text '<text>'

@env
Examples:
| text |
| one |
| two |

@env2
Examples:
| text |
| three |
| four |

@env3:
Examples:
| text |
| five |
| six |
2 changes: 1 addition & 1 deletion plugin-code/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

<groupId>com.trivago.rta</groupId>
<artifactId>cucable-plugin</artifactId>
<version>1.7.2</version>
<version>1.8.0</version>
<url>https://github.com/trivago/cucable-plugin</url>

<name>Cucable Maven Plugin</name>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,13 @@
import gherkin.AstBuilder;
import gherkin.Parser;
import gherkin.ParserException;
import gherkin.ast.*;
import gherkin.ast.Background;
import gherkin.ast.Examples;
import gherkin.ast.Feature;
import gherkin.ast.GherkinDocument;
import gherkin.ast.Scenario;
import gherkin.ast.ScenarioDefinition;
import gherkin.ast.ScenarioOutline;
import io.cucumber.tagexpressions.Expression;
import io.cucumber.tagexpressions.TagExpressionException;
import io.cucumber.tagexpressions.TagExpressionParser;
Expand All @@ -38,6 +44,7 @@
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

@Singleton
public class GherkinDocumentParser {
Expand Down Expand Up @@ -143,6 +150,7 @@ public List<SingleScenario> getSingleScenariosFromFeature(
featureTags,
backgroundSteps
);

for (SingleScenario singleScenario : outlineScenarios) {
if (scenarioShouldBeIncluded(singleScenario)) {
singleScenarioFeatures.add(singleScenario);
Expand All @@ -151,6 +159,7 @@ public List<SingleScenario> getSingleScenariosFromFeature(
}
}
}

return singleScenarioFeatures;
}

Expand Down Expand Up @@ -186,7 +195,7 @@ private List<SingleScenario> getSingleScenariosFromOutline(
List<Step> steps = gherkinToCucableConverter.convertGherkinStepsToCucableSteps(scenarioOutline.getSteps());

if (scenarioOutline.getExamples().isEmpty()) {
cucableLogger.warn("Scenario outline without example table!");
cucableLogger.warn("Scenario outline '" + scenarioOutline.getName() + "' without example table!");
return outlineScenarios;
}

Expand Down Expand Up @@ -214,6 +223,7 @@ private List<SingleScenario> getSingleScenariosFromOutline(
List<Step> substitutedSteps = substituteStepExamplePlaceholders(steps, exampleMap, rowIndex);
singleScenario.setSteps(substitutedSteps);
singleScenario.setScenarioTags(scenarioTags);

singleScenario.setExampleTags(
gherkinToCucableConverter.convertGherkinTagsToCucableTags(exampleTable.getTags())
);
Expand Down Expand Up @@ -327,30 +337,31 @@ private GherkinDocument getGherkinDocumentFromFeatureFileContent(final String fe
* scenarioNames settings.
*
* @param singleScenario a single scenario object.
* @return true if an include tag and no exclude tags are included in the source tag list and scenario name
* (if specified) matches.
* @return true if the combined tags match the given tag expression and the scenario name (if specified) matches.
*/
private boolean scenarioShouldBeIncluded(SingleScenario singleScenario) throws CucablePluginException {
private boolean scenarioShouldBeIncluded(final SingleScenario singleScenario) throws CucablePluginException {

String includeScenarioTags = propertyManager.getIncludeScenarioTags();
String language = singleScenario.getFeatureLanguage();
String scenarioName = singleScenario.getScenarioName();
boolean scenarioNameMatchExists = matchScenarioWithScenarioNames(language, scenarioName) >= 0;

List<String> combinedScenarioTags = singleScenario.getScenarioTags();
List<String> combinedScenarioTags = new ArrayList<>(singleScenario.getScenarioTags());
combinedScenarioTags.addAll(singleScenario.getFeatureTags());
combinedScenarioTags.addAll(singleScenario.getExampleTags());
combinedScenarioTags = combinedScenarioTags.stream().distinct().collect(Collectors.toList());

if (includeScenarioTags == null || includeScenarioTags.isEmpty()) {
return scenarioNameMatchExists;
}

Expression tagExpression;
try {
tagExpression = tagExpressionParser.parse(includeScenarioTags);
Expression tagExpression = tagExpressionParser.parse(includeScenarioTags);
return tagExpression.evaluate(combinedScenarioTags) && scenarioNameMatchExists;
} catch (TagExpressionException e) {
throw new CucablePluginException("The tag expression '" + includeScenarioTags + "' is invalid: " + e.getMessage());
}
return tagExpression.evaluate(combinedScenarioTags) && scenarioNameMatchExists;

}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@Singleton
class GherkinToCucableConverter {
Expand Down Expand Up @@ -72,14 +74,9 @@ private com.trivago.vo.DataTable convertGherkinDataTableToCucableDataTable(
final DataTable gherkinDataTable) {

com.trivago.vo.DataTable dataTable = new com.trivago.vo.DataTable();
for (TableRow row : gherkinDataTable.getRows()) {
List<TableCell> cells = row.getCells();
List<String> rowValues = new ArrayList<>();
for (TableCell cell : cells) {
rowValues.add(cell.getValue());
}
dataTable.addRow(rowValues);
}
gherkinDataTable.getRows().stream().map(TableRow::getCells)
.map(cells -> cells.stream().map(TableCell::getValue).collect(Collectors.toList()))
.forEachOrdered(dataTable::addRow);
return dataTable;
}

Expand All @@ -90,11 +87,7 @@ private com.trivago.vo.DataTable convertGherkinDataTableToCucableDataTable(
* @return a {@link String} list of tags.
*/
List<String> convertGherkinTagsToCucableTags(final List<Tag> gherkinTags) {
List<String> tags = new ArrayList<>();
for (Tag gherkinTag : gherkinTags) {
tags.add(gherkinTag.getName());
}
return tags;
return gherkinTags.stream().map(Tag::getName).collect(Collectors.toList());
}

/**
Expand All @@ -106,23 +99,21 @@ List<String> convertGherkinTagsToCucableTags(final List<Tag> gherkinTags) {
Map<String, List<String>> convertGherkinExampleTableToCucableExampleMap(
final Examples exampleTable
) {
Map<String, List<String>> exampleMap = new LinkedHashMap<>();
Map<String, List<String>> exampleMap;

List<TableCell> headerCells = exampleTable.getTableHeader().getCells();
for (TableCell headerCell : headerCells) {
exampleMap.put("<" + headerCell.getValue() + ">", new ArrayList<>());
}
exampleMap = headerCells.stream().collect(
Collectors.toMap(headerCell -> "<" + headerCell.getValue() + ">",
headerCell -> new ArrayList<>(), (a, b) -> b, LinkedHashMap::new));
Object[] columnKeys = exampleMap.keySet().toArray();

List<TableRow> tableBody = exampleTable.getTableBody();
for (TableRow tableRow : tableBody) {
List<TableCell> cells = tableRow.getCells();
for (int i = 0; i < cells.size(); i++) {
String columnKey = (String) columnKeys[i];
List<String> values = exampleMap.get(columnKey);
values.add(cells.get(i).getValue());
}
}
tableBody.stream().map(TableRow::getCells).forEachOrdered(
cells -> IntStream.range(0, cells.size()).forEachOrdered(i -> {
String columnKey = (String) columnKeys[i];
List<String> values = exampleMap.get(columnKey);
values.add(cells.get(i).getValue());
}));
return exampleMap;
}
}
24 changes: 21 additions & 3 deletions plugin-code/src/main/java/com/trivago/vo/SingleScenario.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package com.trivago.vo;

import java.util.ArrayList;
import java.util.List;

/**
Expand All @@ -31,9 +32,9 @@ public final class SingleScenario {
private final String scenarioDescription;
private final List<String> featureTags;
private final List<Step> backgroundSteps;
private List<String> scenarioTags;
private List<String> exampleTags;
private List<Step> steps;
private List<String> scenarioTags = new ArrayList<>();
private List<String> exampleTags = new ArrayList<>();
private List<Step> steps = new ArrayList<>();

public SingleScenario(
final String featureName,
Expand Down Expand Up @@ -110,4 +111,21 @@ public List<String> getExampleTags() {
public void setExampleTags(final List<String> exampleTags) {
this.exampleTags = exampleTags;
}

@Override
public String toString() {
return "SingleScenario{" +
"featureName='" + featureName + '\'' +
", featureFilePath='" + featureFilePath + '\'' +
", featureLanguage='" + featureLanguage + '\'' +
", featureDescription='" + featureDescription + '\'' +
", scenarioName='" + scenarioName + '\'' +
", scenarioDescription='" + scenarioDescription + '\'' +
", featureTags=" + featureTags +
", backgroundSteps=" + backgroundSteps +
", scenarioTags=" + scenarioTags +
", exampleTags=" + exampleTags +
", steps=" + steps +
'}';
}
}
9 changes: 9 additions & 0 deletions plugin-code/src/main/java/com/trivago/vo/Step.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,13 @@ public DataTable getDataTable() {
public String getDocString() {
return docString;
}

@Override
public String toString() {
return "Step{" +
"dataTable=" + dataTable +
", docString='" + docString + '\'' +
", name='" + name + '\'' +
'}';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -441,6 +441,65 @@ public void replaceDataTableExamplePlaceholderTest() throws Exception {
assertThat(firstRow.get(2), is("one"));
}

@Test
public void taggedFeatureAndExamplesTest() throws Exception {
String featureContent = getScenarioWithFeatureAndExampleTags();
List<SingleScenario> singleScenariosFromFeature = gherkinDocumentParser.getSingleScenariosFromFeature(featureContent, "", null);
assertThat(singleScenariosFromFeature.size(), is(3));
assertThat(singleScenariosFromFeature.get(0).getSteps().size(), is(2));
assertThat(singleScenariosFromFeature.get(1).getSteps().size(), is(2));
assertThat(singleScenariosFromFeature.get(2).getSteps().size(), is(2));

}

@Test
public void taggedFeatureAndExamplesRequestedExampleTagTest() throws Exception {
String featureContent = getScenarioWithFeatureAndExampleTags();
when(propertyManager.getIncludeScenarioTags()).thenReturn("@exampleTag1");
List<SingleScenario> singleScenariosFromFeature = gherkinDocumentParser.getSingleScenariosFromFeature(featureContent, "", null);
assertThat(singleScenariosFromFeature.size(), is(1));
assertThat(singleScenariosFromFeature.get(0).getSteps().size(), is(2));
}

@Test
public void taggedFeatureAndExamplesRequestedFeatureAndExampleTagTest() throws Exception {
String featureContent = getScenarioWithFeatureAndExampleTags();
when(propertyManager.getIncludeScenarioTags()).thenReturn("@featureTag and @exampleTag1");
List<SingleScenario> singleScenariosFromFeature = gherkinDocumentParser.getSingleScenariosFromFeature(featureContent, "", null);
assertThat(singleScenariosFromFeature.size(), is(1));
assertThat(singleScenariosFromFeature.get(0).getSteps().size(), is(2));
}

@Test
public void taggedFeatureAndExamplesRequestedInvalidExampleTagTest() throws Exception {
String featureContent = getScenarioWithFeatureAndExampleTags();
when(propertyManager.getIncludeScenarioTags()).thenReturn("@exampleTag1 and @exampleTag2");
List<SingleScenario> singleScenariosFromFeature = gherkinDocumentParser.getSingleScenariosFromFeature(featureContent, "", null);
assertThat(singleScenariosFromFeature.size(), is(0));
}

private String getScenarioWithFeatureAndExampleTags() {
return "@featureTag\n" +
"Feature: test feature 3\n" +
"\n" +
" Scenario Outline: This is a scenario outline\n" +
" When I search for key <key>\n" +
" Then I get <value>\n" +
"\n" +
"@exampleTag1\n" +
"Examples:\n" +
" | key | value |\n" +
" | 1 | one |\n" +
"@exampleTag2\n" +
"Examples:\n" +
" | key | value |\n" +
" | 2 | two |\n" +
"@exampleTag3\n" +
"Examples:\n" +
" | key | value |\n" +
" | 3 | three |\n";
}

private String getTwoScenariosWithTags() {
return "@featureTag\n" +
"Feature: test feature\n" +
Expand Down