diff --git a/CHANGELOG.md b/CHANGELOG.md
index 64f193a..0734518 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,7 +6,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
Back to [Readme](README.md).
-## [1.5.3] - UNRELEASED
+## [1.6.0] - 2019-12-10
+
+### Changed
+
+* Cucable is now more resilient when trying to deal with unparsable features - these are skipped instead of stopping the overall execution.
+
+### Fixed
+
+* Utf-8 encoding error on linux (#150)
+* Scenarios had too many tags when there were also feature tags (#145)
+
+## [1.5.3] - 2019-09-09
### Added
@@ -271,6 +282,7 @@ Back to [Readme](README.md).
Initial project version on GitHub and Maven Central.
+[1.6.0]: https://github.com/trivago/cucable-plugin/compare/1.5.3...1.6.0
[1.5.3]: https://github.com/trivago/cucable-plugin/compare/1.5.2...1.5.3
[1.5.2]: https://github.com/trivago/cucable-plugin/compare/1.5.1...1.5.2
[1.5.1]: https://github.com/trivago/cucable-plugin/compare/1.5.0...1.5.1
diff --git a/README.md b/README.md
index 3a35b4b..a7b9bca 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,17 @@
[![codecov](https://codecov.io/gh/trivago/cucable-plugin/branch/master/graph/badge.svg)](https://codecov.io/gh/trivago/cucable-plugin)
[![Twitter URL](https://img.shields.io/twitter/url/http/shields.io.svg?style=social)](https://twitter.com/bischoffdev)
+---
+
+### Note:
+
+This project is feature-complete. Expect only bug fixes at this time.
+For new projects, you should consider using Cucumber's native parallelization feature instead.
+
+Thanks to everyone using, testing and improving Cucable over the last years!
+
+---
+
![Cucumber compatible](documentation/img/cucumber-compatible-black-64.png)
@@ -16,6 +27,7 @@
- [Cucable Maven Plugin](#cucable-maven-plugin)
- [Cucumber 4](#cucumber-4)
+ - [Cucumber 5](#cucumber-5)
- [Repository Structure](#repository-structure)
- [Changelog](#changelog)
- [Maven dependency](#maven-dependency)
@@ -84,6 +96,10 @@ Even though Cucumber 4 supports basic parallel runs, Cucable has more options th
* You don't need any test framework changes because Cucable runs before the framework invocations
* You have full control over your runners because of template variables and custom placeholders
+## Cucumber 5
+
+* Cucumber 5 (using testng or junit 5) can natively run features and scenarios in parallel. Cucable __can__ be used but does not __have__ to be.
+
## Repository Structure
* [plugin-code](plugin-code) contains the full plugin source code.
diff --git a/example-project/pom.xml b/example-project/pom.xml
index d163801..d2a04c0 100644
--- a/example-project/pom.xml
+++ b/example-project/pom.xml
@@ -7,7 +7,7 @@
com.trivago.rta
cucable-test-project
- 1.5.2
+ 1.6.0
jar
diff --git a/example-project/src/test/resources/features/testfeature2/MyTest1InTestFeature2.feature b/example-project/src/test/resources/features/testfeature2/MyTest1InTestFeature2.feature
index 264ee09..2edefef 100644
--- a/example-project/src/test/resources/features/testfeature2/MyTest1InTestFeature2.feature
+++ b/example-project/src/test/resources/features/testfeature2/MyTest1InTestFeature2.feature
@@ -4,4 +4,9 @@ Feature: MyTest1InTestFeature2
@scenario1Tag1
@scenario1Tag2
Scenario: Scenario 1 in MyTest1InTestFeature2
- Given I do something
\ No newline at end of file
+ Given I do something
+
+ @Login
+ Scenario: Login
+ Given this is a given step
+ Given I am on a page with text 'İ'
\ No newline at end of file
diff --git a/plugin-code/pom.xml b/plugin-code/pom.xml
index 625363e..29bddf6 100644
--- a/plugin-code/pom.xml
+++ b/plugin-code/pom.xml
@@ -6,7 +6,7 @@
com.trivago.rta
cucable-plugin
- 1.5.3
+ 1.6.0
https://github.com/trivago/cucable-plugin
Cucable Maven Plugin
@@ -80,9 +80,9 @@
2.0.2
3.9
- 3.0.0
- 5.5.1
- 0.8.12
+ 3.2.0
+ 5.6.0-M1
+ 0.8.13
diff --git a/plugin-code/src/main/java/com/trivago/features/FeatureFileContentRenderer.java b/plugin-code/src/main/java/com/trivago/features/FeatureFileContentRenderer.java
index 4d9160c..c12bc95 100644
--- a/plugin-code/src/main/java/com/trivago/features/FeatureFileContentRenderer.java
+++ b/plugin-code/src/main/java/com/trivago/features/FeatureFileContentRenderer.java
@@ -49,7 +49,11 @@ private String getRenderedFeatureFileContent(List singleScenario
for (SingleScenario singleScenario : singleScenarios) {
renderedContent.append(LINE_SEPARATOR);
- addTags(renderedContent, singleScenario.getScenarioTags());
+ List scenarioTags = singleScenario.getScenarioTags();
+ if (scenarioTags != null && firstScenario.getFeatureTags() != null) {
+ scenarioTags.removeAll(firstScenario.getFeatureTags());
+ }
+ addTags(renderedContent, scenarioTags);
addTags(renderedContent, singleScenario.getExampleTags());
addNameAndDescription(
diff --git a/plugin-code/src/main/java/com/trivago/features/FeatureFileConverter.java b/plugin-code/src/main/java/com/trivago/features/FeatureFileConverter.java
index e4267c0..8f4aaea 100644
--- a/plugin-code/src/main/java/com/trivago/features/FeatureFileConverter.java
+++ b/plugin-code/src/main/java/com/trivago/features/FeatureFileConverter.java
@@ -405,7 +405,6 @@ private int generateRunnerClassesWithDesiredNumberOfFeatures(
* @throws CucablePluginException see {@link CucablePluginException}.
*/
private void generateRunnerClass(final List generatedFeatureFileNames) throws CucablePluginException {
-
// The runner class name will be equal to the feature name if there is only one feature to run.
// Otherwise, a generated runner class name is used.
String runnerClassName;
diff --git a/plugin-code/src/main/java/com/trivago/files/FileIO.java b/plugin-code/src/main/java/com/trivago/files/FileIO.java
index 581badd..8dc0c5f 100644
--- a/plugin-code/src/main/java/com/trivago/files/FileIO.java
+++ b/plugin-code/src/main/java/com/trivago/files/FileIO.java
@@ -38,7 +38,7 @@ public class FileIO {
*/
public void writeContentToFile(String content, String filePath) throws FileCreationException {
try {
- FileUtils.fileWrite(filePath, content);
+ FileUtils.fileWrite(filePath, "UTF-8", content);
} catch (IOException e) {
throw new FileCreationException(filePath);
}
@@ -53,7 +53,7 @@ public void writeContentToFile(String content, String filePath) throws FileCreat
*/
public String readContentFromFile(String filePath) throws MissingFileException {
try {
- return FileUtils.fileRead(filePath);
+ return FileUtils.fileRead(filePath, "UTF-8");
} catch (IOException e) {
throw new MissingFileException(filePath);
}
diff --git a/plugin-code/src/main/java/com/trivago/gherkin/GherkinDocumentParser.java b/plugin-code/src/main/java/com/trivago/gherkin/GherkinDocumentParser.java
index 8f533f1..60fcedc 100644
--- a/plugin-code/src/main/java/com/trivago/gherkin/GherkinDocumentParser.java
+++ b/plugin-code/src/main/java/com/trivago/gherkin/GherkinDocumentParser.java
@@ -17,6 +17,7 @@
package com.trivago.gherkin;
import com.trivago.exceptions.CucablePluginException;
+import com.trivago.logging.CucableLogger;
import com.trivago.properties.PropertyManager;
import com.trivago.vo.DataTable;
import com.trivago.vo.SingleScenario;
@@ -24,13 +25,7 @@
import gherkin.AstBuilder;
import gherkin.Parser;
import gherkin.ParserException;
-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 gherkin.ast.*;
import io.cucumber.tagexpressions.Expression;
import io.cucumber.tagexpressions.TagExpressionException;
import io.cucumber.tagexpressions.TagExpressionParser;
@@ -38,6 +33,7 @@
import javax.inject.Inject;
import javax.inject.Singleton;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
@@ -52,16 +48,18 @@ public class GherkinDocumentParser {
private final GherkinToCucableConverter gherkinToCucableConverter;
private final GherkinTranslations gherkinTranslations;
private final PropertyManager propertyManager;
+ private final CucableLogger cucableLogger;
@Inject
GherkinDocumentParser(
final GherkinToCucableConverter gherkinToCucableConverter,
final GherkinTranslations gherkinTranslations,
- final PropertyManager propertyManager
- ) {
+ final PropertyManager propertyManager,
+ final CucableLogger logger) {
this.gherkinToCucableConverter = gherkinToCucableConverter;
this.gherkinTranslations = gherkinTranslations;
this.propertyManager = propertyManager;
+ this.cucableLogger = logger;
}
/**
@@ -81,6 +79,10 @@ public List getSingleScenariosFromFeature(
GherkinDocument gherkinDocument = getGherkinDocumentFromFeatureFileContent(escapedFeatureContent);
Feature feature = gherkinDocument.getFeature();
+ if (feature == null) {
+ return Collections.emptyList();
+ }
+
String featureName = feature.getKeyword() + ": " + feature.getName();
String featureLanguage = feature.getLanguage();
String featureDescription = feature.getDescription();
@@ -161,7 +163,6 @@ public List getSingleScenariosFromFeature(
* @param featureLanguage The feature language this scenario outline belongs to.
* @param featureTags The feature tags of the parent feature.
* @param backgroundSteps Return a Cucable {@link SingleScenario} list.
- * @throws CucablePluginException Thrown when the scenario outline does not contain an example table.
*/
private List getSingleScenariosFromOutline(
final ScenarioOutline scenarioOutline,
@@ -171,7 +172,7 @@ private List getSingleScenariosFromOutline(
final String featureDescription,
final List featureTags,
final List backgroundSteps
- ) throws CucablePluginException {
+ ) {
// Retrieve the translation of "Scenario" in the target language and add it to the scenario
String translatedScenarioKeyword = gherkinTranslations.getScenarioKeyword(featureLanguage);
@@ -185,7 +186,8 @@ private List getSingleScenariosFromOutline(
List steps = gherkinToCucableConverter.convertGherkinStepsToCucableSteps(scenarioOutline.getSteps());
if (scenarioOutline.getExamples().isEmpty()) {
- throw new CucablePluginException("Scenario outline without examples table!");
+ cucableLogger.warn("Scenario outline without example table!");
+ return outlineScenarios;
}
for (Examples exampleTable : scenarioOutline.getExamples()) {
@@ -314,7 +316,7 @@ private GherkinDocument getGherkinDocumentFromFeatureFileContent(final String fe
}
if (gherkinDocument == null || gherkinDocument.getFeature() == null) {
- throw new CucablePluginException("Could not parse features from gherkin document!");
+ cucableLogger.warn("No parsable gherkin.");
}
return gherkinDocument;
@@ -326,7 +328,7 @@ private GherkinDocument getGherkinDocumentFromFeatureFileContent(final String fe
*
* @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.
+ * (if specified) matches.
*/
private boolean scenarioShouldBeIncluded(SingleScenario singleScenario) throws CucablePluginException {
@@ -354,10 +356,10 @@ private boolean scenarioShouldBeIncluded(SingleScenario singleScenario) throws C
/**
* Checks if a scenarioName value matches with the scenario name.
*
- * @param language Feature file language ("en", "ro" etc).
+ * @param language Feature file language ("en", "ro" etc).
* @param stringToMatch the string that will be matched with the scenarioName value.
* @return index of the scenarioName value in the scenarioNames list if a match exists.
- * -1 if no match exists.
+ * -1 if no match exists.
*/
public int matchScenarioWithScenarioNames(String language, String stringToMatch) {
List scenarioNames = propertyManager.getScenarioNames();
diff --git a/plugin-code/src/test/java/com/trivago/gherkin/GherkinDocumentParserTest.java b/plugin-code/src/test/java/com/trivago/gherkin/GherkinDocumentParserTest.java
index 42ea097..584f6ff 100644
--- a/plugin-code/src/test/java/com/trivago/gherkin/GherkinDocumentParserTest.java
+++ b/plugin-code/src/test/java/com/trivago/gherkin/GherkinDocumentParserTest.java
@@ -1,6 +1,7 @@
package com.trivago.gherkin;
import com.trivago.exceptions.CucablePluginException;
+import com.trivago.logging.CucableLogger;
import com.trivago.properties.PropertyManager;
import com.trivago.vo.DataTable;
import com.trivago.vo.SingleScenario;
@@ -15,25 +16,28 @@
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
+import static org.mockito.Mockito.*;
+import static org.mockito.Mockito.times;
public class GherkinDocumentParserTest {
private GherkinDocumentParser gherkinDocumentParser;
private PropertyManager propertyManager;
+ private CucableLogger mockedLogger;
@Before
public void setup() {
GherkinToCucableConverter gherkinToCucableConverter = new GherkinToCucableConverter();
GherkinTranslations gherkinTranslations = new GherkinTranslations();
propertyManager = mock(PropertyManager.class);
- gherkinDocumentParser = new GherkinDocumentParser(gherkinToCucableConverter, gherkinTranslations, propertyManager);
+ mockedLogger = mock(CucableLogger.class);
+ gherkinDocumentParser = new GherkinDocumentParser(gherkinToCucableConverter, gherkinTranslations, propertyManager, mockedLogger);
}
- @Test(expected = CucablePluginException.class)
+ @Test
public void invalidFeatureTest() throws Exception {
gherkinDocumentParser.getSingleScenariosFromFeature("", "", null);
+ verify(mockedLogger, times(1)).warn("No parsable gherkin.");
}
@Test