@@ -199,16 +199,16 @@ class LegacyXmlResultFormatter extends AbstractJUnitResultFormatter implements T
// write the testsuite element
writer.writeStartElement(ELEM_TESTSUITE);
final String testsuiteName = determineTestSuiteName();
writer.write Attribute(ATTR_NAME, testsuiteName);
writeAttribute(writer, ATTR_NAME, testsuiteName);
// time taken for the tests execution
writer.write Attribute(ATTR_TIME, String.valueOf((testPlanEndedAt - testPlanStartedAt) / ONE_SECOND));
writeAttribute(writer, ATTR_TIME, String.valueOf((testPlanEndedAt - testPlanStartedAt) / ONE_SECOND));
// add the timestamp of report generation
final String timestamp = DateUtils.format(new Date(), DateUtils.ISO8601_DATETIME_PATTERN);
writer.write Attribute(ATTR_TIMESTAMP, timestamp);
writer.write Attribute(ATTR_NUM_TESTS, String.valueOf(numTestsRun.longValue()));
writer.write Attribute(ATTR_NUM_FAILURES, String.valueOf(numTestsFailed.longValue()));
writer.write Attribute(ATTR_NUM_SKIPPED, String.valueOf(numTestsSkipped.longValue()));
writer.write Attribute(ATTR_NUM_ABORTED, String.valueOf(numTestsAborted.longValue()));
writeAttribute(writer, ATTR_TIMESTAMP, timestamp);
writeAttribute(writer, ATTR_NUM_TESTS, String.valueOf(numTestsRun.longValue()));
writeAttribute(writer, ATTR_NUM_FAILURES, String.valueOf(numTestsFailed.longValue()));
writeAttribute(writer, ATTR_NUM_SKIPPED, String.valueOf(numTestsSkipped.longValue()));
writeAttribute(writer, ATTR_NUM_ABORTED, String.valueOf(numTestsAborted.longValue()));
// write the properties
writeProperties(writer);
@@ -228,8 +228,8 @@ class LegacyXmlResultFormatter extends AbstractJUnitResultFormatter implements T
writer.writeStartElement(ELEM_PROPERTIES);
for (final String prop : properties.stringPropertyNames()) {
writer.writeStartElement(ELEM_PROPERTY);
writer.write Attribute(ATTR_NAME, prop);
writer.write Attribute(ATTR_VALUE, properties.getProperty(prop));
writeAttribute(writer, ATTR_NAME, prop);
writeAttribute(writer, ATTR_VALUE, properties.getProperty(prop));
writer.writeEndElement();
}
writer.writeEndElement();
@@ -257,11 +257,11 @@ class LegacyXmlResultFormatter extends AbstractJUnitResultFormatter implements T
}
final String classname = (parentClassSource.get()).getClassName();
writer.writeStartElement(ELEM_TESTCASE);
writer.write Attribute(ATTR_CLASSNAME, classname);
writer.write Attribute(ATTR_NAME, useLegacyReportingName ? testId.getLegacyReportingName()
writeAttribute(writer, ATTR_CLASSNAME, classname);
writeAttribute(writer, ATTR_NAME, useLegacyReportingName ? testId.getLegacyReportingName()
: testId.getDisplayName());
final Stats stats = entry.getValue();
writer.write Attribute(ATTR_TIME, String.valueOf((stats.endedAt - stats.startedAt) / ONE_SECOND));
writeAttribute(writer, ATTR_TIME, String.valueOf((stats.endedAt - stats.startedAt) / ONE_SECOND));
// skipped element if the test was skipped
writeSkipped(writer, testId);
// failed element if the test failed
@@ -280,7 +280,7 @@ class LegacyXmlResultFormatter extends AbstractJUnitResultFormatter implements T
writer.writeStartElement(ELEM_SKIPPED);
final Optional<String> reason = skipped.get(testIdentifier);
if (reason.isPresent()) {
writer.write Attribute(ATTR_MESSAGE, reason.get());
writeAttribute(writer, ATTR_MESSAGE, reason.get());
}
writer.writeEndElement();
}
@@ -295,9 +295,9 @@ class LegacyXmlResultFormatter extends AbstractJUnitResultFormatter implements T
final Throwable t = cause.get();
final String message = t.getMessage();
if (message != null && !message.trim().isEmpty()) {
writer.write Attribute(ATTR_MESSAGE, message);
writeAttribute(writer, ATTR_MESSAGE, message);
}
writer.write Attribute(ATTR_TYPE, t.getClass().getName());
writeAttribute(writer, ATTR_TYPE, t.getClass().getName());
// write out the stacktrace
writer.writeCData(StringUtils.getStackTrace(t));
}
@@ -314,9 +314,9 @@ class LegacyXmlResultFormatter extends AbstractJUnitResultFormatter implements T
final Throwable t = cause.get();
final String message = t.getMessage();
if (message != null && !message.trim().isEmpty()) {
writer.write Attribute(ATTR_MESSAGE, message);
writeAttribute(writer, ATTR_MESSAGE, message);
}
writer.write Attribute(ATTR_TYPE, t.getClass().getName());
writeAttribute(writer, ATTR_TYPE, t.getClass().getName());
// write out the stacktrace
writer.writeCData(StringUtils.getStackTrace(t));
}
@@ -349,15 +349,29 @@ class LegacyXmlResultFormatter extends AbstractJUnitResultFormatter implements T
final char[] chars = new char[1024];
int numRead = -1;
while ((numRead = reader.read(chars)) != -1) {
// although it's called a DOMElementWriter, the encode method is just a
// straight forward XML util method which doesn't concern about whether
// DOM, SAX, StAX semantics.
// TODO: Perhaps make it a static method
final String encoded = new DOMElementWriter().encode(new String(chars, 0, numRead));
writer.writeCharacters(encoded);
writer.writeCharacters(encode(new String(chars, 0, numRead)));
}
}
private void writeAttribute(final XMLStreamWriter writer, final String name, final String value)
throws XMLStreamException {
writer.writeAttribute(name, encode(value));
}
private String encode(final String s) {
boolean changed = false;
final StringBuilder sb = new StringBuilder();
for (char c : s.toCharArray()) {
if (!DOMElementWriter.isLegalXmlCharacter(c)) {
changed = true;
sb.append("&#").append((int) c).append(';');
} else {
sb.append(c);
}
}
return changed ? sb.toString() : s;
}
private String determineTestSuiteName() {
// this is really a hack to try and match the expectations of the XML report in JUnit4.x
// world. In JUnit5, the TestPlan doesn't have a name and a TestPlan (for which this is a