diff --git a/CHANGELOG.md b/CHANGELOG.md
index 895b5d204b..94ecdacdec 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Removed
### Fixed
+ * [Core] Mark pending steps as failed in teamcity plugin ([#2264](https://github.com/cucumber/cucumber-jvm/pull/2264)) M.P. Korstanje)
## [6.10.1] (2021-03-08)
diff --git a/core/src/main/java/io/cucumber/core/plugin/TeamCityPlugin.java b/core/src/main/java/io/cucumber/core/plugin/TeamCityPlugin.java
index 1af941d9a7..f9929323ce 100644
--- a/core/src/main/java/io/cucumber/core/plugin/TeamCityPlugin.java
+++ b/core/src/main/java/io/cucumber/core/plugin/TeamCityPlugin.java
@@ -48,6 +48,13 @@
import static java.util.Collections.emptyList;
import static java.util.stream.Collectors.joining;
+/**
+ * Outputs Teamcity services messages to std out.
+ *
+ * @see TeamCity
+ * - Service Messages
+ */
public class TeamCityPlugin implements EventListener {
private static final DateTimeFormatter DATE_FORMAT = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'hh:mm:ss.SSSZ");
@@ -230,7 +237,7 @@ private String extractSourceLocation(TestStep testStep) {
if (java8Matcher.matches()) {
String fqDeclaringClassName = java8Matcher.group(1);
String declaringClassName;
- int indexOfPackageSeparator = fqDeclaringClassName.indexOf(".");
+ int indexOfPackageSeparator = fqDeclaringClassName.lastIndexOf(".");
if (indexOfPackageSeparator != -1) {
declaringClassName = fqDeclaringClassName.substring(indexOfPackageSeparator + 1);
} else {
@@ -250,22 +257,27 @@ private void printTestStepFinished(TestStepFinished event) {
Throwable error = event.getResult().getError();
Status status = event.getResult().getStatus();
switch (status) {
- case SKIPPED:
- print(TEMPLATE_TEST_IGNORED, timeStamp, duration, error == null ? "Step skipped" : error.getMessage(),
- name);
+ case SKIPPED: {
+ String message = error == null ? "Step skipped" : error.getMessage();
+ print(TEMPLATE_TEST_IGNORED, timeStamp, duration, message, name);
break;
- case PENDING:
- print(TEMPLATE_TEST_IGNORED, timeStamp, duration, error == null ? "Step pending" : error.getMessage(),
- name);
+ }
+ case PENDING: {
+ String details = error == null ? "" : error.getMessage();
+ print(TEMPLATE_TEST_FAILED, timeStamp, duration, "Step pending", details, name);
break;
- case UNDEFINED:
- print(TEMPLATE_TEST_FAILED, timeStamp, duration, "Step undefined", getSnippets(currentTestCase), name);
+ }
+ case UNDEFINED: {
+ String snippets = getSnippets(currentTestCase);
+ print(TEMPLATE_TEST_FAILED, timeStamp, duration, "Step undefined", snippets, name);
break;
+ }
case AMBIGUOUS:
- case FAILED:
+ case FAILED: {
String details = extractStackTrace(error);
print(TEMPLATE_TEST_FAILED, timeStamp, duration, "Step failed", details, name);
break;
+ }
default:
break;
}
@@ -307,8 +319,8 @@ private String getSnippets(TestCase testCase) {
URI uri = testCase.getUri();
Location location = testCase.getLocation();
List suggestionForTestCase = suggestions.stream()
- .filter(suggestions -> suggestions.getUri().equals(uri) &&
- suggestions.getTestCaseLocation().equals(location))
+ .filter(suggestion -> suggestion.getUri().equals(uri) &&
+ suggestion.getTestCaseLocation().equals(location))
.map(SnippetsSuggestedEvent::getSuggestion)
.collect(Collectors.toList());
return createMessage(suggestionForTestCase);
@@ -322,7 +334,7 @@ private static String createMessage(Collection suggestions) {
if (suggestions.size() > 1) {
sb.append(" and ").append(suggestions.size() - 1).append(" other step(s)");
}
- sb.append("using the snippet(s) below:\n\n");
+ sb.append(" using the snippet(s) below:\n\n");
String snippets = suggestions
.stream()
.map(Suggestion::getSnippets)
@@ -379,7 +391,7 @@ private String formatCommand(String command, Object... parameters) {
escapedParameters[i] = escape(parameters[i].toString());
}
- return String.format(command, escapedParameters);
+ return String.format(command, (Object[]) escapedParameters);
}
private String escape(String source) {
diff --git a/core/src/test/java/io/cucumber/core/plugin/TeamCityPluginTest.java b/core/src/test/java/io/cucumber/core/plugin/TeamCityPluginTest.java
index 04c1c47bc2..159f866b77 100755
--- a/core/src/test/java/io/cucumber/core/plugin/TeamCityPluginTest.java
+++ b/core/src/test/java/io/cucumber/core/plugin/TeamCityPluginTest.java
@@ -1,6 +1,7 @@
package io.cucumber.core.plugin;
import io.cucumber.core.backend.StubHookDefinition;
+import io.cucumber.core.backend.StubPendingException;
import io.cucumber.core.backend.StubStepDefinition;
import io.cucumber.core.backend.TestCaseState;
import io.cucumber.core.feature.TestFeatureParser;
@@ -212,7 +213,29 @@ void should_print_error_message_for_undefined_steps() {
.run();
assertThat(out, bytesContainsString("" +
- "##teamcity[testFailed timestamp = '1970-01-01T12:00:00.000+0000' duration = '0' message = 'Step undefined' details = 'You can implement this step and 1 other step(s)using the snippet(s) below:|n|ntest snippet 0|ntest snippet 1|n' name = 'first step']"));
+ "##teamcity[testFailed timestamp = '1970-01-01T12:00:00.000+0000' duration = '0' message = 'Step undefined' details = 'You can implement this step and 1 other step(s) using the snippet(s) below:|n|ntest snippet 0|ntest snippet 1|n' name = 'first step']"));
+ }
+
+ @Test
+ void should_print_error_message_for_pending_steps() {
+ Feature feature = TestFeatureParser.parse("path/test.feature", "" +
+ "Feature: feature name\n" +
+ " Scenario: scenario name\n" +
+ " Given first step\n" +
+ " Given second step\n");
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ Runtime.builder()
+ .withFeatureSupplier(new StubFeatureSupplier(feature))
+ .withAdditionalPlugins(new TeamCityPlugin(new PrintStream(out)))
+ .withEventBus(new TimeServiceEventBus(fixed(EPOCH, of("UTC")), UUID::randomUUID))
+ .withBackendSupplier(
+ new StubBackendSupplier(new StubStepDefinition("first step", new StubPendingException())))
+ .build()
+ .run();
+
+ assertThat(out, bytesContainsString("" +
+ "##teamcity[testFailed timestamp = '1970-01-01T12:00:00.000+0000' duration = '0' message = 'Step pending' details = 'TODO: implement me' name = 'first step']"));
}
@Test
@@ -241,7 +264,7 @@ void should_print_error_message_for_before_hooks() {
}
@Test
- void should_print_location_hint_for_hooks() {
+ void should_print_location_hint_for_java_hooks() {
Feature feature = TestFeatureParser.parse("path/test.feature", "" +
"Feature: feature name\n" +
" Scenario: scenario name\n" +
@@ -263,4 +286,27 @@ void should_print_location_hint_for_hooks() {
"##teamcity[testStarted timestamp = '1970-01-01T12:00:00.000+0000' locationHint = 'java:test://com.example.HookDefinition/beforeHook' captureStandardOutput = 'true' name = 'Before']\n"));
}
+ @Test
+ void should_print_location_hint_for_lambda_hooks() {
+ Feature feature = TestFeatureParser.parse("path/test.feature", "" +
+ "Feature: feature name\n" +
+ " Scenario: scenario name\n" +
+ " Given first step\n");
+
+ ByteArrayOutputStream out = new ByteArrayOutputStream();
+ Runtime.builder()
+ .withFeatureSupplier(new StubFeatureSupplier(feature))
+ .withAdditionalPlugins(new TeamCityPlugin(new PrintStream(out)))
+ .withEventBus(new TimeServiceEventBus(fixed(EPOCH, of("UTC")), UUID::randomUUID))
+ .withBackendSupplier(new StubBackendSupplier(
+ singletonList(new StubHookDefinition("com.example.HookDefinition.(HookDefinition.java:12)")),
+ singletonList(new StubStepDefinition("first step")),
+ emptyList()))
+ .build()
+ .run();
+
+ assertThat(out, bytesContainsString("" +
+ "##teamcity[testStarted timestamp = '1970-01-01T12:00:00.000+0000' locationHint = 'java:test://com.example.HookDefinition/HookDefinition' captureStandardOutput = 'true' name = 'Before']\n"));
+ }
+
}