Skip to content

java: Format time as xs:float #83

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

Merged
merged 1 commit into from
Aug 13, 2025
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Fixed
- [Java] Format time as xs:float ([#83](https://github.com/cucumber/junit-xml-formatter/pull/83))

## [0.8.0] - 2025-07-07
### Added
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,17 +9,14 @@
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamException;
import java.io.Writer;
import java.text.NumberFormat;
import java.util.EnumSet;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;

import static io.cucumber.messages.types.TestStepResultStatus.PASSED;
import static io.cucumber.messages.types.TestStepResultStatus.SKIPPED;

class XmlReportWriter {
private final NumberFormat numberFormat = NumberFormat.getInstance(Locale.US);
private final XmlReportData data;

XmlReportWriter(XmlReportData data) {
Expand Down Expand Up @@ -51,7 +48,7 @@ private void writeTestsuite(EscapingXmlStreamWriter writer) throws XMLStreamExce

private void writeSuiteAttributes(EscapingXmlStreamWriter writer) throws XMLStreamException {
writer.writeAttribute("name", "Cucumber");
writer.writeAttribute("time", numberFormat.format(data.getSuiteDurationInSeconds()));
writer.writeAttribute("time", String.valueOf(data.getSuiteDurationInSeconds()));

Map<TestStepResultStatus, Long> counts = data.getTestCaseStatusCounts();

Expand Down Expand Up @@ -90,7 +87,7 @@ private void writeTestcase(EscapingXmlStreamWriter writer, TestCaseStarted testC
private void writeTestCaseAttributes(EscapingXmlStreamWriter writer, TestCaseStarted testCaseStarted) throws XMLStreamException {
writer.writeAttribute("classname", data.getFeatureName(testCaseStarted));
writer.writeAttribute("name", data.getPickleName(testCaseStarted));
writer.writeAttribute("time", numberFormat.format(data.getDurationInSeconds(testCaseStarted)));
writer.writeAttribute("time", String.valueOf(data.getDurationInSeconds(testCaseStarted)));
}

private void writeNonPassedElement(EscapingXmlStreamWriter writer, TestCaseStarted testCaseStarted) throws XMLStreamException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ void validateAgainstJenkins(TestCase testCase) throws IOException {
void validateAgainstSurefire(TestCase testCase) throws IOException {
ByteArrayOutputStream bytes = writeJunitXmlReport(testCase, new ByteArrayOutputStream());
Source actual = Input.fromByteArray(bytes.toByteArray()).build();
Source surefireSchema = Input.fromPath(Paths.get("../surefire-test-report-3.0.xsd")).build();
Source surefireSchema = Input.fromPath(Paths.get("../surefire-test-report-3.0.2.xsd")).build();

JAXPValidator validator = new JAXPValidator(Languages.W3C_XML_SCHEMA_NS_URI);
validator.setSchemaSource(surefireSchema);
Expand All @@ -88,22 +88,7 @@ void validateAgainstSurefire(TestCase testCase) throws IOException {
* We add the timestamp attribute to all reports.
*/
expectedProblems.add("cvc-complex-type.3.2.2: Attribute 'timestamp' is not allowed to appear in element 'testsuite'.");
/*
This report tries to be compatible with the Jenkins XSD. The Surefire
XSD is a bit stricter and generally assumes tests fail with an
exception. While this is true for Cucumber-JVM, this isn't true for
all Cucumber implementations.

E.g. in Cucumber-JVM a scenario would report it is pending by throwing
a PendingException. However, in Javascript this would be done by
returning the string "pending".

Since the Surefire XSD is also relatively popular we do check it and
exclude the cases that don't pass selectively.
*/
if (testCasesWithMissingException.contains(testCase.name)) {
expectedProblems.add("cvc-complex-type.4: Attribute 'type' must appear on element 'failure'.");
}
Iterable<ValidationProblem> problems = validationResult.getProblems();
Assertions.assertThat(problems).extracting(ValidationProblem::getMessage).containsAll(expectedProblems);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ void it_writes_two_messages_to_xml() throws IOException {

assertThat(html).isEqualTo("" +
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<testsuite name=\"Cucumber\" time=\"20\" tests=\"0\" skipped=\"0\" failures=\"0\" errors=\"0\" timestamp=\"1970-01-01T00:00:10Z\">\n" +
"<testsuite name=\"Cucumber\" time=\"20.0\" tests=\"0\" skipped=\"0\" failures=\"0\" errors=\"0\" timestamp=\"1970-01-01T00:00:10Z\">\n" +
"</testsuite>\n"
);
}
Expand All @@ -38,7 +38,7 @@ void it_writes_no_message_to_xml() throws IOException {
String html = renderAsJunitXml();
assertThat(html).isEqualTo("" +
"<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
"<testsuite name=\"Cucumber\" time=\"0\" tests=\"0\" skipped=\"0\" failures=\"0\" errors=\"0\">\n" +
"<testsuite name=\"Cucumber\" time=\"0.0\" tests=\"0\" skipped=\"0\" failures=\"0\" errors=\"0\">\n" +
"</testsuite>\n"
);
}
Expand Down
28 changes: 12 additions & 16 deletions surefire-test-report-3.0.xsd → surefire-test-report-3.0.2.xsd
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
From: https://maven.apache.org/surefire/maven-surefire-plugin/xsd/surefire-test-report-3.0.xsd
From: https://maven.apache.org/surefire/maven-surefire-plugin/xsd/surefire-test-report.xsd
Via: https://maven.apache.org/surefire/maven-surefire-plugin/
-->
<!--
Expand All @@ -21,16 +21,11 @@ Via: https://maven.apache.org/surefire/maven-surefire-plugin/
~ specific language governing permissions and limitations
~ under the License.
-->
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" version="3.0">
<xs:simpleType name="SUREFIRE_TIME">
<xs:restriction base="xs:string">
<xs:pattern value="(([0-9]{0,3},)*[0-9]{3}|[0-9]{0,3})*(\.[0-9]{0,3})?"/>
</xs:restriction>
</xs:simpleType>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" version="3.0.2">
<xs:element name="testsuite">
<xs:complexType>
<xs:sequence>
<xs:element name="properties" minOccurs="0" maxOccurs="unbounded">
<xs:element name="properties" minOccurs="0">
<xs:complexType>
<xs:sequence>
<xs:element name="property" minOccurs="0" maxOccurs="unbounded">
Expand All @@ -50,7 +45,7 @@ Via: https://maven.apache.org/surefire/maven-surefire-plugin/
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="message" type="xs:string"/>
<xs:attribute name="type" type="xs:string" use="required"/>
<xs:attribute name="type" type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
Expand All @@ -63,7 +58,7 @@ Via: https://maven.apache.org/surefire/maven-surefire-plugin/
<xs:element name="system-err" type="xs:string" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="message" type="xs:string"/>
<xs:attribute name="type" type="xs:string" use="required"/>
<xs:attribute name="type" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="flakyFailure" minOccurs="0" maxOccurs="unbounded">
Expand All @@ -74,7 +69,7 @@ Via: https://maven.apache.org/surefire/maven-surefire-plugin/
<xs:element name="system-err" type="xs:string" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="message" type="xs:string"/>
<xs:attribute name="type" type="xs:string" use="required"/>
<xs:attribute name="type" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="skipped" nillable="true" minOccurs="0" maxOccurs="1">
Expand All @@ -91,7 +86,7 @@ Via: https://maven.apache.org/surefire/maven-surefire-plugin/
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="message" type="xs:string"/>
<xs:attribute name="type" type="xs:string" use="required"/>
<xs:attribute name="type" type="xs:string"/>
</xs:extension>
</xs:simpleContent>
</xs:complexType>
Expand All @@ -104,7 +99,7 @@ Via: https://maven.apache.org/surefire/maven-surefire-plugin/
<xs:element name="system-err" type="xs:string" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="message" type="xs:string"/>
<xs:attribute name="type" type="xs:string" use="required"/>
<xs:attribute name="type" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="flakyError" minOccurs="0" maxOccurs="unbounded">
Expand All @@ -115,7 +110,7 @@ Via: https://maven.apache.org/surefire/maven-surefire-plugin/
<xs:element name="system-err" type="xs:string" minOccurs="0"/>
</xs:sequence>
<xs:attribute name="message" type="xs:string"/>
<xs:attribute name="type" type="xs:string" use="required"/>
<xs:attribute name="type" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="system-out" type="xs:string" minOccurs="0"/>
Expand All @@ -124,12 +119,13 @@ Via: https://maven.apache.org/surefire/maven-surefire-plugin/
<xs:attribute name="name" type="xs:string" use="required"/>
<xs:attribute name="classname" type="xs:string"/>
<xs:attribute name="group" type="xs:string"/>
<xs:attribute name="time" type="SUREFIRE_TIME" use="required"/>
<xs:attribute name="time" type="xs:float" use="required"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="version" type="xs:string"/>
<xs:attribute name="name" type="xs:string" use="required"/>
<xs:attribute name="time" type="SUREFIRE_TIME"/>
<xs:attribute name="time" type="xs:float"/>
<xs:attribute name="tests" type="xs:string" use="required"/>
<xs:attribute name="errors" type="xs:string" use="required"/>
<xs:attribute name="skipped" type="xs:string" use="required"/>
Expand Down