Skip to content

Commit 81a3947

Browse files
Pretty-Print DocStringArgument Step Arguments (#2953)
The pretty formatter now also prints docstring step arguments, in addition to datatable step arguments I use the pretty formatter to print out my test results, and I noticed that everything gets printed except for docstring step arguments. It felt like this was a missing or incomplete feature. Regardless, I want to have my formatted test results include the contents of the step docstrings. --------- Signed-off-by: Daniel Miladinov <[email protected]> Co-authored-by: M.P. Korstanje <[email protected]>
1 parent 6467a75 commit 81a3947

File tree

8 files changed

+197
-20
lines changed

8 files changed

+197
-20
lines changed

CHANGELOG.md

+2
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1313

1414
### Changed
1515
- [JUnit Platform Engine] Use JUnit Platform 1.11.3 (JUnit Jupiter 5.11.3)
16+
### Added
17+
- [Core] Pretty-Print DocStringArgument Step Arguments([#2953](https://github.com/cucumber/cucumber-jvm/pull/2953) Daniel Miladinov)
1618

1719
## [7.20.1] - 2024-10-09
1820
### Fixed

cucumber-core/src/main/java/io/cucumber/core/plugin/PrettyFormatter.java

+19-2
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22

33
import io.cucumber.core.exception.CucumberException;
44
import io.cucumber.core.gherkin.DataTableArgument;
5+
import io.cucumber.core.gherkin.DocStringArgument;
56
import io.cucumber.datatable.DataTable;
67
import io.cucumber.datatable.DataTableFormatter;
8+
import io.cucumber.docstring.DocString;
9+
import io.cucumber.docstring.DocStringFormatter;
710
import io.cucumber.plugin.ColorAware;
811
import io.cucumber.plugin.ConcurrentEventListener;
912
import io.cucumber.plugin.event.Argument;
@@ -141,15 +144,29 @@ private void printStep(TestStepFinished event) {
141144
String locationComment = formatLocationComment(event, testStep, keyword, stepText);
142145
out.println(STEP_INDENT + formattedStepText + locationComment);
143146
StepArgument stepArgument = testStep.getStep().getArgument();
144-
if (DataTableArgument.class.isInstance(stepArgument)) {
147+
if (stepArgument instanceof DataTableArgument) {
145148
DataTableFormatter tableFormatter = DataTableFormatter
146149
.builder()
147150
.prefixRow(STEP_SCENARIO_INDENT)
148151
.escapeDelimiters(false)
149152
.build();
150153
DataTableArgument dataTableArgument = (DataTableArgument) stepArgument;
154+
DataTable table = DataTable.create(dataTableArgument.cells());
151155
try {
152-
tableFormatter.formatTo(DataTable.create(dataTableArgument.cells()), out);
156+
tableFormatter.formatTo(table, out);
157+
} catch (IOException e) {
158+
throw new CucumberException(e);
159+
}
160+
} else if (stepArgument instanceof DocStringArgument) {
161+
DocStringFormatter docStringFormatter = DocStringFormatter
162+
.builder()
163+
.indentation(STEP_SCENARIO_INDENT)
164+
.build();
165+
DocStringArgument docStringArgument = (DocStringArgument) stepArgument;
166+
DocString docString = DocString.create(docStringArgument.getContent(),
167+
docStringArgument.getContentType());
168+
try {
169+
docStringFormatter.formatTo(docString, out);
153170
} catch (IOException e) {
154171
throw new CucumberException(e);
155172
}

cucumber-core/src/test/java/io/cucumber/core/plugin/PrettyFormatterTest.java

+33
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import io.cucumber.core.stepexpression.StepExpressionFactory;
1717
import io.cucumber.core.stepexpression.StepTypeRegistry;
1818
import io.cucumber.datatable.DataTable;
19+
import io.cucumber.docstring.DocString;
1920
import org.junit.jupiter.api.Test;
2021

2122
import java.io.ByteArrayOutputStream;
@@ -611,4 +612,36 @@ void should_print_system_failure_for_failed_hooks() {
611612
" " + AnsiEscapes.RED + "the stack trace" + AnsiEscapes.RESET)));
612613
}
613614

615+
@Test
616+
void should_print_docstring_including_content_type() {
617+
Feature feature = TestFeatureParser.parse("path/test.feature", "" +
618+
"Feature: Test feature\n" +
619+
" Scenario: Test Scenario\n" +
620+
" Given first step\n" +
621+
" \"\"\"json\n" +
622+
" {\"key1\": \"value1\",\n" +
623+
" \"key2\": \"value2\",\n" +
624+
" \"another1\": \"another2\"}\n" +
625+
" \"\"\"\n");
626+
627+
ByteArrayOutputStream out = new ByteArrayOutputStream();
628+
Runtime.builder()
629+
.withFeatureSupplier(new StubFeatureSupplier(feature))
630+
.withAdditionalPlugins(new PrettyFormatter(out))
631+
.withRuntimeOptions(new RuntimeOptionsBuilder().setMonochrome().build())
632+
.withBackendSupplier(new StubBackendSupplier(
633+
new StubStepDefinition("first step", "path/step_definitions.java:7", DocString.class)))
634+
.build()
635+
.run();
636+
637+
assertThat(out, bytes(equalToCompressingWhiteSpace("" +
638+
"\n" +
639+
"Scenario: Test Scenario # path/test.feature:2\n" +
640+
" Given first step # path/step_definitions.java:7\n" +
641+
" \"\"\"json\n" +
642+
" {\"key1\": \"value1\",\n" +
643+
" \"key2\": \"value2\",\n" +
644+
" \"another1\": \"another2\"}\n" +
645+
" \"\"\"\n")));
646+
}
614647
}

docstring/src/main/java/io/cucumber/docstring/DocString.java

+3-7
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,7 @@
55
import java.lang.reflect.Type;
66
import java.util.Objects;
77

8-
import static java.util.Arrays.stream;
98
import static java.util.Objects.requireNonNull;
10-
import static java.util.stream.Collectors.joining;
119

1210
/**
1311
* A doc string. For example:
@@ -81,11 +79,9 @@ public boolean equals(Object o) {
8179

8280
@Override
8381
public String toString() {
84-
return stream(content.split("\n"))
85-
.collect(joining(
86-
"\n ",
87-
" \"\"\"" + contentType + "\n ",
88-
"\n \"\"\""));
82+
return DocStringFormatter.builder()
83+
.build()
84+
.format(this);
8985
}
9086

9187
public interface DocStringConverter {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package io.cucumber.docstring;
2+
3+
import org.apiguardian.api.API;
4+
5+
import java.io.IOException;
6+
7+
import static java.util.Objects.requireNonNull;
8+
9+
@API(status = API.Status.EXPERIMENTAL)
10+
public final class DocStringFormatter {
11+
12+
private final String indentation;
13+
14+
private DocStringFormatter(String indentation) {
15+
this.indentation = indentation;
16+
}
17+
18+
public static DocStringFormatter.Builder builder() {
19+
return new Builder();
20+
}
21+
22+
public String format(DocString docString) {
23+
StringBuilder result = new StringBuilder();
24+
formatTo(docString, result);
25+
return result.toString();
26+
}
27+
28+
public void formatTo(DocString docString, StringBuilder appendable) {
29+
requireNonNull(docString, "docString may not be null");
30+
requireNonNull(appendable, "appendable may not be null");
31+
try {
32+
formatTo(docString, (Appendable) appendable);
33+
} catch (IOException e) {
34+
throw new CucumberDocStringException(e.getMessage(), e);
35+
}
36+
}
37+
38+
public void formatTo(DocString docString, Appendable out) throws IOException {
39+
String printableContentType = docString.getContentType() == null ? "" : docString.getContentType();
40+
out.append(indentation).append("\"\"\"").append(printableContentType).append("\n");
41+
for (String l : docString.getContent().split("\\n")) {
42+
out.append(indentation).append(l).append("\n");
43+
}
44+
out.append(indentation).append("\"\"\"").append("\n");
45+
}
46+
47+
public static final class Builder {
48+
49+
private String indentation = "";
50+
51+
private Builder() {
52+
53+
}
54+
55+
public Builder indentation(String indentation) {
56+
requireNonNull(indentation, "indentation may not be null");
57+
this.indentation = indentation;
58+
return this;
59+
}
60+
61+
public DocStringFormatter build() {
62+
return new DocStringFormatter(indentation);
63+
}
64+
}
65+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package io.cucumber.docstring;
2+
3+
import org.junit.jupiter.api.Test;
4+
5+
import static org.hamcrest.CoreMatchers.equalTo;
6+
import static org.hamcrest.MatcherAssert.assertThat;
7+
8+
class DocStringFormatterTest {
9+
10+
@Test
11+
void should_print_docstring_with_content_type() {
12+
DocString docString = DocString.create("{\n" +
13+
" \"key1\": \"value1\",\n" +
14+
" \"key2\": \"value2\",\n" +
15+
" \"another1\": \"another2\"\n" +
16+
"}\n",
17+
"application/json");
18+
19+
DocStringFormatter formatter = DocStringFormatter.builder().build();
20+
String format = formatter.format(docString);
21+
assertThat(format, equalTo(
22+
"\"\"\"application/json\n" +
23+
"{\n" +
24+
" \"key1\": \"value1\",\n" +
25+
" \"key2\": \"value2\",\n" +
26+
" \"another1\": \"another2\"\n" +
27+
"}\n" +
28+
"\"\"\"\n"));
29+
}
30+
31+
@Test
32+
void should_print_docstring_without_content_type() {
33+
DocString docString = DocString.create("{\n" +
34+
" \"key1\": \"value1\",\n" +
35+
" \"key2\": \"value2\",\n" +
36+
" \"another1\": \"another2\"\n" +
37+
"}\n");
38+
39+
DocStringFormatter formatter = DocStringFormatter.builder().build();
40+
String format = formatter.format(docString);
41+
assertThat(format, equalTo(
42+
"\"\"\"\n" +
43+
"{\n" +
44+
" \"key1\": \"value1\",\n" +
45+
" \"key2\": \"value2\",\n" +
46+
" \"another1\": \"another2\"\n" +
47+
"}\n" +
48+
"\"\"\"\n"));
49+
}
50+
51+
@Test
52+
void should_print_docstring_with_indentation() {
53+
DocString docString = DocString.create("Hello",
54+
"text/plain");
55+
56+
DocStringFormatter formatter = DocStringFormatter.builder().indentation(" ").build();
57+
String format = formatter.format(docString);
58+
assertThat(format, equalTo(
59+
" \"\"\"text/plain\n" +
60+
" Hello\n" +
61+
" \"\"\"\n"));
62+
}
63+
64+
}

docstring/src/test/java/io/cucumber/docstring/DocStringTest.java

+8-8
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@ void pretty_prints_doc_string_objects() {
2828
"application/json");
2929

3030
assertThat(docString.toString(), is("" +
31-
" \"\"\"application/json\n" +
32-
" {\n" +
33-
" \"hello\":\"world\"\n" +
34-
" }\n" +
35-
" \"\"\""));
31+
"\"\"\"application/json\n" +
32+
"{\n" +
33+
" \"hello\":\"world\"\n" +
34+
"}\n" +
35+
"\"\"\"\n"));
3636
}
3737

3838
@Test
@@ -60,9 +60,9 @@ void pretty_prints_empty_doc_string_objects() {
6060
"application/json");
6161

6262
assertThat(docString.toString(), is("" +
63-
" \"\"\"application/json\n" +
64-
" \n" +
65-
" \"\"\""));
63+
"\"\"\"application/json\n" +
64+
"\n" +
65+
"\"\"\"\n"));
6666
}
6767

6868
}

docstring/src/test/java/io/cucumber/docstring/DocStringTypeRegistryDocStringConverterTest.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,9 @@ void throws_when_conversion_fails() {
151151
() -> converter.convert(docString, JsonNode.class));
152152
assertThat(exception.getMessage(), is(equalToCompressingWhiteSpace("" +
153153
"'json' could not transform\n" +
154-
" \"\"\"json\n" +
155-
" {\"hello\":\"world\"}\n" +
156-
" \"\"\"")));
154+
" \"\"\"json\n" +
155+
" {\"hello\":\"world\"}\n" +
156+
" \"\"\"")));
157157
}
158158

159159
@Test

0 commit comments

Comments
 (0)