Skip to content
Draft
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
10 changes: 10 additions & 0 deletions java/.mvn/jvm.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
--add-exports jdk.compiler/com.sun.tools.javac.api=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.file=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.main=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.model=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.parser=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.processing=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.tree=ALL-UNNAMED
--add-exports jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED
--add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED
--add-opens jdk.compiler/com.sun.tools.javac.comp=ALL-UNNAMED
28 changes: 23 additions & 5 deletions java/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,18 @@
<parent>
<groupId>io.cucumber</groupId>
<artifactId>cucumber-parent</artifactId>
<version>4.5.0</version>
<version>5.0.0-SNAPSHOT</version>
</parent>

<artifactId>teamcity-formatter</artifactId>
<version>0.2.1-SNAPSHOT</version>
<version>0.3.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>TeamCity Formatter</name>
<description>Interspaces Cucumbers output with TeamCity Service Messages</description>
<url>https://github.com/cucumber/teamcity-formatter</url>

<properties>
<project.Automatic-Module-Name>io.cucumber.teamcityformatter</project.Automatic-Module-Name>
<osgi.bundle-symbolic-name>io.cucumber.teamcityformatter</osgi.bundle-symbolic-name>
<project.build.outputTimestamp>1761578982</project.build.outputTimestamp>
</properties>

Expand Down Expand Up @@ -60,12 +60,12 @@
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>messages</artifactId>
<version>[29.0.1,31.0.0)</version>
<version>[32.0.0-SNAPSHOT,33.0.0)</version>
</dependency>
<dependency>
<groupId>io.cucumber</groupId>
<artifactId>query</artifactId>
<version>[14.0.1,15.0.0)</version>
<version>[15.0.0-SNAPSHOT,16.0.0)</version>
</dependency>

<dependency>
Expand Down Expand Up @@ -132,4 +132,22 @@
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.cucumber.teamcityformatter;

import org.jspecify.annotations.Nullable;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

Expand All @@ -25,6 +27,7 @@ final class ComparisonFailure {
Pattern.DOTALL | Pattern.CASE_INSENSITIVE),
};

@Nullable
static ComparisonFailure parse(String message) {
for (Pattern pattern : COMPARE_PATTERNS) {
ComparisonFailure result = parse(message, pattern);
Expand All @@ -35,6 +38,7 @@ static ComparisonFailure parse(String message) {
return null;
}

@Nullable
static ComparisonFailure parse(String message, Pattern pattern) {
final Matcher matcher = pattern.matcher(message);
if (!matcher.find()) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
package io.cucumber.teamcityformatter;

import org.jspecify.annotations.Nullable;

import java.util.Comparator;

import static java.util.Comparator.naturalOrder;
import static java.util.Comparator.nullsFirst;
import static java.util.Objects.requireNonNull;

final class OrderableEvent<T> implements Comparable<OrderableEvent<T>> {
private final T event;
private final String uri;
private final Long line;
private final @Nullable String uri;
private final @Nullable Integer line;

OrderableEvent(T event, String uri, Long line) {
this.event = event;
OrderableEvent(T event, @Nullable String uri, @Nullable Integer line) {
this.event = requireNonNull(event);
this.uri = uri;
this.line = line;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,25 @@
import io.cucumber.messages.types.Scenario;
import io.cucumber.messages.types.TableRow;
import io.cucumber.query.LineageReducer;
import org.jspecify.annotations.Nullable;

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

import static java.util.Objects.requireNonNull;

final class PathCollector implements LineageReducer.Collector<List<LineageNode>> {
// There are at most 5 levels to a feature file.
private final List<LineageNode> lineage = new ArrayList<>(5);
private String uri;
private String scenarioName;
private @Nullable String uri;
private @Nullable String scenarioName;
private int examplesIndex;
private boolean isExample;

private String getRequiredUri() {
return requireNonNull(uri);
}

@Override
public void add(GherkinDocument document) {
uri = document.getUri().orElse("");
Expand All @@ -28,42 +35,42 @@ public void add(GherkinDocument document) {
@Override
public void add(Feature feature) {
String name = getNameOrKeyword(feature.getName(), feature.getKeyword());
lineage.add(new LineageNode(name, uri, feature.getLocation()));
lineage.add(new LineageNode(name, getRequiredUri(), feature.getLocation()));
}

@Override
public void add(Rule rule) {
String name = getNameOrKeyword(rule.getName(), rule.getKeyword());
lineage.add(new LineageNode(name, uri, rule.getLocation()));
lineage.add(new LineageNode(name, getRequiredUri(), rule.getLocation()));
}

@Override
public void add(Scenario scenario) {
String name = getNameOrKeyword(scenario.getName(), scenario.getKeyword());
lineage.add(new LineageNode(name, uri, scenario.getLocation()));
lineage.add(new LineageNode(name, getRequiredUri(), scenario.getLocation()));
scenarioName = name;
}

@Override
public void add(Examples examples, int index) {
String name = getNameOrKeyword(examples.getName(), examples.getKeyword());
lineage.add(new LineageNode(name, uri, examples.getLocation()));
lineage.add(new LineageNode(name, getRequiredUri(), examples.getLocation()));
examplesIndex = index;
}

@Override
public void add(TableRow example, int index) {
isExample = true;
String name = "#" + (examplesIndex + 1) + "." + (index + 1);
lineage.add(new LineageNode(name, uri, example.getLocation()));
lineage.add(new LineageNode(name, getRequiredUri(), example.getLocation()));
}

@Override
public void add(Pickle pickle) {
// Case 1: Pickles from a scenario outline
if (isExample) {
String pickleName = pickle.getName();
boolean parameterized = !scenarioName.equals(pickleName);
boolean parameterized = !pickleName.equals(scenarioName);
if (parameterized) {
LineageNode example = lineage.remove(lineage.size() - 1);
String parameterizedExampleName = example.getName() + ": " + pickleName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@

final class SourceReferenceFormatter {

private SourceReferenceFormatter(){
/* no-op */
}

static Optional<String> formatLocation(SourceReference sourceReference) {
if (sourceReference.getJavaMethod().isPresent()) {
return sourceReference.getJavaMethod()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@

final class SuggestionFormatter {

private SuggestionFormatter(){
/* no-op */
}

static String format(Collection<Suggestion> suggestions) {
if (suggestions.isEmpty()) {
return "";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ private Stream<TestCaseStarted> findAllTestCaseStartedInCanonicalOrder() {
.map(testCaseStarted -> {
Optional<Pickle> pickle = query.findPickleBy(testCaseStarted);
String uri = pickle.map(Pickle::getUri).orElse(null);
Long line = pickle.flatMap(query::findLocationOf).map(Location::getLine).orElse(null);
Integer line = pickle.flatMap(query::findLocationOf).map(Location::getLine).orElse(null);
return new OrderableEvent<>(testCaseStarted, uri, line);
})
.sorted()
Expand Down Expand Up @@ -298,23 +298,19 @@ private void printTestStepFinished(TestStepFinished event) {
Optional<Exception> error = testStepResult.getException();
TestStepResultStatus status = testStepResult.getStatus();
switch (status) {
case SKIPPED: {
case SKIPPED -> {
String message = error.flatMap(Exception::getMessage).orElse("Step skipped");
out.print(TEMPLATE_TEST_IGNORED, timeStamp, duration, message, name);
break;
}
case PENDING: {
case PENDING -> {
String details = error.flatMap(Exception::getMessage).orElse("");
out.print(TEMPLATE_TEST_FAILED, timeStamp, duration, "Step pending", details, name);
break;
}
case UNDEFINED: {
case UNDEFINED -> {
String snippets = findSnippets(event).orElse("");
out.print(TEMPLATE_TEST_FAILED, timeStamp, duration, "Step undefined", snippets, name);
break;
}
case AMBIGUOUS:
case FAILED: {
case AMBIGUOUS, FAILED -> {
String details = error.flatMap(Exception::getStackTrace).orElse("");
String message = error.flatMap(Exception::getMessage).orElse(null);
if (message == null) {
Expand All @@ -328,10 +324,9 @@ private void printTestStepFinished(TestStepFinished event) {
}
out.print(TEMPLATE_TEST_COMPARISON_FAILED, timeStamp, duration, "Step failed", details,
comparisonFailure.getExpected(), comparisonFailure.getActual(), name);
break;
}
default:
break;
default -> {
}
}
out.print(TEMPLATE_TEST_FINISHED, timeStamp, duration, name);
});
Expand Down Expand Up @@ -359,23 +354,13 @@ private static String formatHookStepName(Hook hook) {

private static String getHookType(Hook hook) {
return hook.getType().map(
hookType -> {
switch (hookType) {
case BEFORE_TEST_RUN:
return "BeforeAll";
case AFTER_TEST_RUN:
return "AfterAll";
case BEFORE_TEST_CASE:
return "Before";
case AFTER_TEST_CASE:
return "After";
case BEFORE_TEST_STEP:
return "BeforeStep";
case AFTER_TEST_STEP:
return "AfterStep";
default:
return "Unknown";
}
hookType -> switch (hookType) {
case BEFORE_TEST_RUN -> "BeforeAll";
case AFTER_TEST_RUN -> "AfterAll";
case BEFORE_TEST_CASE -> "Before";
case AFTER_TEST_CASE -> "After";
case BEFORE_TEST_STEP -> "BeforeStep";
case AFTER_TEST_STEP -> "AfterStep";
}).orElse("Unknown");
}

Expand Down Expand Up @@ -417,27 +402,22 @@ private void printBeforeAfterAllResult(TestRunFinished event, String timestamp)
}

private void handleAttachment(Attachment event) {
String message = extractAttachmentMessage(event);
if (message != null) {
handleAttachment(message);
}
handleAttachment(extractAttachmentMessage(event));
}

private void handleAttachment(String message) {
out.print(TEMPLATE_ATTACH_WRITE_EVENT, message);
}

private static String extractAttachmentMessage(Attachment event) {
switch (event.getContentEncoding()) {
case IDENTITY:
return "Write event:\n" + event.getBody() + "\n";
case BASE64:
return switch (event.getContentEncoding()) {
case IDENTITY -> "Write event:\n" + event.getBody() + "\n";
case BASE64 -> {
String name = event.getFileName().map(s -> s + " ").orElse("");
return "Embed event: " + name + "[" + event.getMediaType() + " " + (event.getBody().length() / 4) * 3
yield "Embed event: " + name + "[" + event.getMediaType() + " " + (event.getBody().length() / 4) * 3
+ " bytes]\n";
default:
return null;
}
}
};
}

private static String formatTimeStamp(Timestamp timestamp) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
@NullMarked
package io.cucumber.teamcityformatter;

import org.jspecify.annotations.NullMarked;
8 changes: 8 additions & 0 deletions java/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
module io.cucumber.teamcityformatter {
requires org.jspecify;

requires io.cucumber.messages;
requires io.cucumber.query;

exports io.cucumber.teamcityformatter;
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@

import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.function.Executable;
import org.junit.jupiter.params.shadow.de.siegmar.fastcsv.util.Nullable;

import static java.util.Objects.requireNonNull;
import static org.assertj.core.api.Assertions.assertThat;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.jupiter.api.Assertions.assertThrows;
Expand Down Expand Up @@ -33,7 +35,6 @@ void junit5() {
.containsExactly("1", "42");
}

@SuppressWarnings("JUnit5AssertionsConverter")
@Test
void junit4() {
ComparisonFailure comparisonFailure = create(() -> org.junit.Assert.assertEquals(1, 42));
Expand All @@ -50,9 +51,9 @@ void testng7() {
.containsExactly("1", "42");
}

private static ComparisonFailure create(Executable executable) {
private static @Nullable ComparisonFailure create(Executable executable) {
AssertionError exception = assertThrows(AssertionError.class, executable);
return ComparisonFailure.parse(exception.getMessage());
return ComparisonFailure.parse(requireNonNull(exception.getMessage()));
}

}
2 changes: 2 additions & 0 deletions java/src/test/java/io/cucumber/teamcityformatter/Jackson.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import com.fasterxml.jackson.annotation.JsonCreator.Mode;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.cfg.ConstructorDetector;
Expand All @@ -24,6 +25,7 @@ final class Jackson {
.enable(DeserializationFeature.USE_LONG_FOR_INTS)
.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
.disable(JsonGenerator.Feature.AUTO_CLOSE_TARGET)
.disable(MapperFeature.CAN_OVERRIDE_ACCESS_MODIFIERS)
.build();

private Jackson() {
Expand Down
Loading