diff --git a/maven-surefire-report-plugin/src/main/java/org/apache/maven/plugins/surefire/report/AbstractSurefireReportMojo.java b/maven-surefire-report-plugin/src/main/java/org/apache/maven/plugins/surefire/report/AbstractSurefireReportMojo.java index eaaf294f1f..44f107b010 100644 --- a/maven-surefire-report-plugin/src/main/java/org/apache/maven/plugins/surefire/report/AbstractSurefireReportMojo.java +++ b/maven-surefire-report-plugin/src/main/java/org/apache/maven/plugins/surefire/report/AbstractSurefireReportMojo.java @@ -126,9 +126,15 @@ public void executeReport(Locale locale) throws MavenReportException { return; } - new SurefireReportGenerator( - getReportsDirectories(), locale, showSuccess, determineXrefLocation(), getConsoleLogger()) - .doGenerateReport(getBundle(locale), getSink()); + SurefireReportRenderer r = new SurefireReportRenderer( + getSink(), + locale, + getBundle(locale), + getConsoleLogger(), + showSuccess, + getReportsDirectories(), + determineXrefLocation()); + r.render(); } @Override diff --git a/maven-surefire-report-plugin/src/main/java/org/apache/maven/plugins/surefire/report/SurefireReportGenerator.java b/maven-surefire-report-plugin/src/main/java/org/apache/maven/plugins/surefire/report/SurefireReportGenerator.java deleted file mode 100644 index 09667a06ab..0000000000 --- a/maven-surefire-report-plugin/src/main/java/org/apache/maven/plugins/surefire/report/SurefireReportGenerator.java +++ /dev/null @@ -1,697 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ -package org.apache.maven.plugins.surefire.report; - -import java.io.File; -import java.text.NumberFormat; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -import org.apache.maven.doxia.markup.HtmlMarkup; -import org.apache.maven.doxia.sink.Sink; -import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet; -import org.apache.maven.doxia.util.DoxiaUtils; -import org.apache.maven.plugin.surefire.log.api.ConsoleLogger; -import org.apache.maven.reporting.MavenReportException; - -import static org.apache.maven.doxia.markup.HtmlMarkup.A; -import static org.apache.maven.doxia.sink.Sink.JUSTIFY_LEFT; -import static org.apache.maven.doxia.sink.SinkEventAttributes.CLASS; -import static org.apache.maven.doxia.sink.SinkEventAttributes.HREF; -import static org.apache.maven.doxia.sink.SinkEventAttributes.ID; -import static org.apache.maven.doxia.sink.SinkEventAttributes.STYLE; -import static org.apache.maven.doxia.sink.SinkEventAttributes.TYPE; - -/** - * This generator creates HTML Report from Surefire and Failsafe XML Report. - */ -public final class SurefireReportGenerator { - private static final int LEFT = JUSTIFY_LEFT; - private static final Object[] TAG_TYPE_START = {HtmlMarkup.TAG_TYPE_START}; - private static final Object[] TAG_TYPE_END = {HtmlMarkup.TAG_TYPE_END}; - - private final SurefireReportParser report; - private final boolean showSuccess; - private final String xrefLocation; - private List testSuites; - - public SurefireReportGenerator( - List reportsDirectories, - Locale locale, - boolean showSuccess, - String xrefLocation, - ConsoleLogger consoleLogger) { - report = new SurefireReportParser(reportsDirectories, locale, consoleLogger); - this.showSuccess = showSuccess; - this.xrefLocation = xrefLocation; - } - - public void doGenerateReport(LocalizedProperties bundle, Sink sink) throws MavenReportException { - testSuites = report.parseXMLReportFiles(); - - sink.head(); - - sink.title(); - sink.text(bundle.getReportHeader()); - sink.title_(); - - sink.head_(); - - sink.body(); - - SinkEventAttributeSet atts = new SinkEventAttributeSet(); - atts.addAttribute(TYPE, "application/javascript"); - sink.unknown("script", new Object[] {HtmlMarkup.TAG_TYPE_START}, atts); - sink.unknown("cdata", new Object[] {HtmlMarkup.CDATA_TYPE, javascriptToggleDisplayCode()}, null); - sink.unknown("script", new Object[] {HtmlMarkup.TAG_TYPE_END}, null); - - sink.section1(); - sink.sectionTitle1(); - sink.text(bundle.getReportHeader()); - sink.sectionTitle1_(); - sink.section1_(); - - constructSummarySection(bundle, sink); - - Map> suitePackages = report.getSuitesGroupByPackage(testSuites); - if (!suitePackages.isEmpty()) { - constructPackagesSection(bundle, sink, suitePackages); - } - - if (!testSuites.isEmpty()) { - constructTestCasesSection(bundle, sink); - } - - List failureList = report.getFailureDetails(testSuites); - if (!failureList.isEmpty()) { - constructFailureDetails(sink, bundle, failureList); - } - - sink.body_(); - - sink.flush(); - - sink.close(); - } - - private void constructSummarySection(LocalizedProperties bundle, Sink sink) { - Map summary = report.getSummary(testSuites); - - sink.section1(); - sinkAnchor(sink, "Summary"); - sink.sectionTitle1(); - sink.text(bundle.getReportLabelSummary()); - sink.sectionTitle1_(); - - constructHotLinks(sink, bundle); - - sinkLineBreak(sink); - - sink.table(); - - sink.tableRows(new int[] {LEFT, LEFT, LEFT, LEFT, LEFT, LEFT}, false); - - sink.tableRow(); - - sinkHeader(sink, bundle.getReportLabelTests()); - - sinkHeader(sink, bundle.getReportLabelErrors()); - - sinkHeader(sink, bundle.getReportLabelFailures()); - - sinkHeader(sink, bundle.getReportLabelSkipped()); - - sinkHeader(sink, bundle.getReportLabelSuccessRate()); - - sinkHeader(sink, bundle.getReportLabelTime()); - - sink.tableRow_(); - - sink.tableRow(); - - sinkCell(sink, summary.get("totalTests")); - - sinkCell(sink, summary.get("totalErrors")); - - sinkCell(sink, summary.get("totalFailures")); - - sinkCell(sink, summary.get("totalSkipped")); - - sinkCell(sink, summary.get("totalPercentage") + "%"); - - sinkCell(sink, summary.get("totalElapsedTime")); - - sink.tableRow_(); - - sink.tableRows_(); - - sink.table_(); - - sink.lineBreak(); - - sink.paragraph(); - sink.text(bundle.getReportTextNode1()); - sink.paragraph_(); - - sinkLineBreak(sink); - - sink.section1_(); - } - - private void constructPackagesSection( - LocalizedProperties bundle, Sink sink, Map> suitePackages) { - NumberFormat numberFormat = report.getNumberFormat(); - - sink.section1(); - sinkAnchor(sink, "Package_List"); - sink.sectionTitle1(); - sink.text(bundle.getReportLabelPackageList()); - sink.sectionTitle1_(); - - constructHotLinks(sink, bundle); - - sinkLineBreak(sink); - - sink.table(); - - sink.tableRows(new int[] {LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT}, false); - - sink.tableRow(); - - sinkHeader(sink, bundle.getReportLabelPackage()); - - sinkHeader(sink, bundle.getReportLabelTests()); - - sinkHeader(sink, bundle.getReportLabelErrors()); - - sinkHeader(sink, bundle.getReportLabelFailures()); - - sinkHeader(sink, bundle.getReportLabelSkipped()); - - sinkHeader(sink, bundle.getReportLabelSuccessRate()); - - sinkHeader(sink, bundle.getReportLabelTime()); - - sink.tableRow_(); - - for (Map.Entry> entry : suitePackages.entrySet()) { - sink.tableRow(); - - String packageName = entry.getKey(); - - List testSuiteList = entry.getValue(); - - Map packageSummary = report.getSummary(testSuiteList); - - sinkCellLink(sink, packageName, "#" + packageName); - - sinkCell(sink, packageSummary.get("totalTests")); - - sinkCell(sink, packageSummary.get("totalErrors")); - - sinkCell(sink, packageSummary.get("totalFailures")); - - sinkCell(sink, packageSummary.get("totalSkipped")); - - sinkCell(sink, packageSummary.get("totalPercentage") + "%"); - - sinkCell(sink, packageSummary.get("totalElapsedTime")); - - sink.tableRow_(); - } - - sink.tableRows_(); - - sink.table_(); - - sink.lineBreak(); - - sink.paragraph(); - sink.text(bundle.getReportTextNode2()); - sink.paragraph_(); - - for (Map.Entry> entry : suitePackages.entrySet()) { - String packageName = entry.getKey(); - - List testSuiteList = entry.getValue(); - - sink.section2(); - sinkAnchor(sink, packageName); - sink.sectionTitle2(); - sink.text(packageName); - sink.sectionTitle2_(); - - boolean showTable = false; - - for (ReportTestSuite suite : testSuiteList) { - if (showSuccess || suite.getNumberOfErrors() != 0 || suite.getNumberOfFailures() != 0) { - showTable = true; - - break; - } - } - - if (showTable) { - sink.table(); - - sink.tableRows(new int[] {LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT, LEFT}, false); - - sink.tableRow(); - - sinkHeader(sink, ""); - - sinkHeader(sink, bundle.getReportLabelClass()); - - sinkHeader(sink, bundle.getReportLabelTests()); - - sinkHeader(sink, bundle.getReportLabelErrors()); - - sinkHeader(sink, bundle.getReportLabelFailures()); - - sinkHeader(sink, bundle.getReportLabelSkipped()); - - sinkHeader(sink, bundle.getReportLabelSuccessRate()); - - sinkHeader(sink, bundle.getReportLabelTime()); - - sink.tableRow_(); - - for (ReportTestSuite suite : testSuiteList) { - if (showSuccess || suite.getNumberOfErrors() != 0 || suite.getNumberOfFailures() != 0) { - constructTestSuiteSection(sink, numberFormat, suite); - } - } - - sink.tableRows_(); - - sink.table_(); - } - - sink.section2_(); - } - - sinkLineBreak(sink); - - sink.section1_(); - } - - private void constructTestSuiteSection(Sink sink, NumberFormat numberFormat, ReportTestSuite suite) { - sink.tableRow(); - - sink.tableCell(); - - sink.link("#" + suite.getPackageName() + '.' + suite.getName()); - - if (suite.getNumberOfErrors() > 0) { - sinkIcon("error", sink); - } else if (suite.getNumberOfFailures() > 0) { - sinkIcon("junit.framework", sink); - } else if (suite.getNumberOfSkipped() > 0) { - sinkIcon("skipped", sink); - } else { - sinkIcon("success", sink); - } - - sink.link_(); - - sink.tableCell_(); - - sinkCellLink(sink, suite.getName(), "#" + suite.getPackageName() + '.' + suite.getName()); - - sinkCell(sink, Integer.toString(suite.getNumberOfTests())); - - sinkCell(sink, Integer.toString(suite.getNumberOfErrors())); - - sinkCell(sink, Integer.toString(suite.getNumberOfFailures())); - - sinkCell(sink, Integer.toString(suite.getNumberOfSkipped())); - - String percentage = report.computePercentage( - suite.getNumberOfTests(), suite.getNumberOfErrors(), - suite.getNumberOfFailures(), suite.getNumberOfSkipped()); - sinkCell(sink, percentage + "%"); - - sinkCell(sink, numberFormat.format(suite.getTimeElapsed())); - - sink.tableRow_(); - } - - private void constructTestCasesSection(LocalizedProperties bundle, Sink sink) { - NumberFormat numberFormat = report.getNumberFormat(); - - sink.section1(); - sinkAnchor(sink, "Test_Cases"); - sink.sectionTitle1(); - sink.text(bundle.getReportLabelTestCases()); - sink.sectionTitle1_(); - - constructHotLinks(sink, bundle); - - for (ReportTestSuite suite : testSuites) { - List testCases = suite.getTestCases(); - - if (!testCases.isEmpty()) { - sink.section2(); - sinkAnchor(sink, suite.getPackageName() + '.' + suite.getName()); - sink.sectionTitle2(); - sink.text(suite.getName()); - sink.sectionTitle2_(); - - boolean showTable = false; - - for (ReportTestCase testCase : testCases) { - if (!testCase.isSuccessful() || showSuccess) { - showTable = true; - - break; - } - } - - if (showTable) { - sink.table(); - - sink.tableRows(new int[] {LEFT, LEFT, LEFT}, false); - - for (ReportTestCase testCase : testCases) { - if (!testCase.isSuccessful() || showSuccess) { - constructTestCaseSection(sink, numberFormat, testCase); - } - } - - sink.tableRows_(); - - sink.table_(); - } - - sink.section2_(); - } - } - - sinkLineBreak(sink); - - sink.section1_(); - } - - private static void constructTestCaseSection(Sink sink, NumberFormat numberFormat, ReportTestCase testCase) { - sink.tableRow(); - - sink.tableCell(); - - if (testCase.getFailureType() != null) { - sink.link("#" + toHtmlId(testCase.getFullName())); - - sinkIcon(testCase.getFailureType(), sink); - - sink.link_(); - } else { - sinkIcon("success", sink); - } - - sink.tableCell_(); - - if (!testCase.isSuccessful()) { - sink.tableCell(); - sinkAnchor(sink, "TC_" + toHtmlId(testCase.getFullName())); - - sinkLink(sink, testCase.getName(), "#" + toHtmlId(testCase.getFullName())); - - SinkEventAttributeSet atts = new SinkEventAttributeSet(); - atts.addAttribute(CLASS, "detailToggle"); - atts.addAttribute(STYLE, "display:inline"); - sink.unknown("div", TAG_TYPE_START, atts); - - sinkLink(sink, "javascript:toggleDisplay('" + toHtmlId(testCase.getFullName()) + "');"); - - atts = new SinkEventAttributeSet(); - atts.addAttribute(STYLE, "display:inline;"); - atts.addAttribute(ID, toHtmlId(testCase.getFullName()) + "-off"); - sink.unknown("span", TAG_TYPE_START, atts); - sink.text(" + "); - sink.unknown("span", TAG_TYPE_END, null); - - atts = new SinkEventAttributeSet(); - atts.addAttribute(STYLE, "display:none;"); - atts.addAttribute(ID, toHtmlId(testCase.getFullName()) + "-on"); - sink.unknown("span", TAG_TYPE_START, atts); - sink.text(" - "); - sink.unknown("span", TAG_TYPE_END, null); - - sink.text("[ Detail ]"); - sinkLink_(sink); - - sink.unknown("div", TAG_TYPE_END, null); - - sink.tableCell_(); - } else { - sinkCellAnchor(sink, testCase.getName(), "TC_" + toHtmlId(testCase.getFullName())); - } - - sinkCell(sink, numberFormat.format(testCase.getTime())); - - sink.tableRow_(); - - if (!testCase.isSuccessful()) { - sink.tableRow(); - - sinkCell(sink, ""); - sinkCell(sink, testCase.getFailureMessage()); - sinkCell(sink, ""); - sink.tableRow_(); - - String detail = testCase.getFailureDetail(); - if (detail != null) { - sink.tableRow(); - sinkCell(sink, ""); - - sink.tableCell(); - SinkEventAttributeSet atts = new SinkEventAttributeSet(); - atts.addAttribute(ID, toHtmlId(testCase.getFullName()) + toHtmlIdFailure(testCase)); - atts.addAttribute(STYLE, "display:none;"); - sink.unknown("div", TAG_TYPE_START, atts); - - sink.verbatim(null); - sink.text(detail); - sink.verbatim_(); - - sink.unknown("div", TAG_TYPE_END, null); - sink.tableCell_(); - - sinkCell(sink, ""); - - sink.tableRow_(); - } - } - } - - private static String toHtmlId(String id) { - return DoxiaUtils.isValidId(id) ? id : DoxiaUtils.encodeId(id, true); - } - - private void constructFailureDetails(Sink sink, LocalizedProperties bundle, List failures) { - sink.section1(); - sinkAnchor(sink, "Failure_Details"); - sink.sectionTitle1(); - sink.text(bundle.getReportLabelFailureDetails()); - sink.sectionTitle1_(); - - constructHotLinks(sink, bundle); - - sinkLineBreak(sink); - - sink.table(); - - sink.tableRows(new int[] {LEFT, LEFT}, false); - - for (ReportTestCase tCase : failures) { - sink.tableRow(); - - sink.tableCell(); - - String type = tCase.getFailureType(); - - sinkIcon(type, sink); - - sink.tableCell_(); - - sinkCellAnchor(sink, tCase.getName(), toHtmlId(tCase.getFullName())); - - sink.tableRow_(); - - String message = tCase.getFailureMessage(); - - sink.tableRow(); - - sinkCell(sink, ""); - - sinkCell(sink, message == null ? type : type + ": " + message); - - sink.tableRow_(); - - String detail = tCase.getFailureDetail(); - if (detail != null) { - sink.tableRow(); - - sinkCell(sink, ""); - - sink.tableCell(); - SinkEventAttributeSet atts = new SinkEventAttributeSet(); - atts.addAttribute(ID, tCase.getName() + toHtmlIdFailure(tCase)); - sink.unknown("div", TAG_TYPE_START, atts); - - String fullClassName = tCase.getFullClassName(); - String errorLineNumber = tCase.getFailureErrorLine(); - if (xrefLocation != null) { - String path = fullClassName.replace('.', '/'); - sink.link(xrefLocation + "/" + path + ".html#L" + errorLineNumber); - } - sink.text(fullClassName + ":" + errorLineNumber); - - if (xrefLocation != null) { - sink.link_(); - } - sink.unknown("div", TAG_TYPE_END, null); - - sink.tableCell_(); - - sink.tableRow_(); - } - } - - sink.tableRows_(); - - sink.table_(); - - sinkLineBreak(sink); - - sink.section1_(); - } - - private void constructHotLinks(Sink sink, LocalizedProperties bundle) { - if (!testSuites.isEmpty()) { - sink.paragraph(); - - sink.text("["); - sinkLink(sink, bundle.getReportLabelSummary(), "#Summary"); - sink.text("]"); - - sink.text(" ["); - sinkLink(sink, bundle.getReportLabelPackageList(), "#Package_List"); - sink.text("]"); - - sink.text(" ["); - sinkLink(sink, bundle.getReportLabelTestCases(), "#Test_Cases"); - sink.text("]"); - - sink.paragraph_(); - } - } - - private static String toHtmlIdFailure(ReportTestCase tCase) { - return tCase.hasError() ? "-error" : "-failure"; - } - - private static void sinkLineBreak(Sink sink) { - sink.lineBreak(); - } - - private static void sinkIcon(String type, Sink sink) { - if (type.startsWith("junit.framework") || "skipped".equals(type)) { - sink.figureGraphics("images/icon_warning_sml.gif"); - } else if (type.startsWith("success")) { - sink.figureGraphics("images/icon_success_sml.gif"); - } else { - sink.figureGraphics("images/icon_error_sml.gif"); - } - } - - private static void sinkHeader(Sink sink, String header) { - sink.tableHeaderCell(); - sink.text(header); - sink.tableHeaderCell_(); - } - - private static void sinkCell(Sink sink, String text) { - sink.tableCell(); - sink.text(text); - sink.tableCell_(); - } - - private static void sinkLink(Sink sink, String text, String link) { - sink.link(link); - sink.text(text); - sink.link_(); - } - - private static void sinkCellLink(Sink sink, String text, String link) { - sink.tableCell(); - sinkLink(sink, text, link); - sink.tableCell_(); - } - - private static void sinkCellAnchor(Sink sink, String text, String anchor) { - sink.tableCell(); - sinkAnchor(sink, anchor); - sink.text(text); - sink.tableCell_(); - } - - private static void sinkAnchor(Sink sink, String anchor) { - // Dollar '$' for nested classes is not valid character in sink.anchor() and therefore it is ignored - // https://issues.apache.org/jira/browse/SUREFIRE-1443 - sink.unknown(A.toString(), TAG_TYPE_START, new SinkEventAttributeSet(ID, anchor)); - sink.unknown(A.toString(), TAG_TYPE_END, null); - } - - private static void sinkLink(Sink sink, String href) { - // The "'" argument in this JavaScript function would be escaped to "'" - // sink.link( "javascript:toggleDisplay('" + toHtmlId( testCase.getFullName() ) + "');" ); - sink.unknown(A.toString(), TAG_TYPE_START, new SinkEventAttributeSet(HREF, href)); - } - - @SuppressWarnings("checkstyle:methodname") - private static void sinkLink_(Sink sink) { - sink.unknown(A.toString(), TAG_TYPE_END, null); - } - - private static String javascriptToggleDisplayCode() { - - // the javascript code is emitted within a commented CDATA section - // so we have to start with a newline and comment the CDATA closing in the end - - return "\n" + "function toggleDisplay(elementId) {\n" - + " var elm = document.getElementById(elementId + '-error');\n" - + " if (elm == null) {\n" - + " elm = document.getElementById(elementId + '-failure');\n" - + " }\n" - + " if (elm && typeof elm.style != \"undefined\") {\n" - + " if (elm.style.display == \"none\") {\n" - + " elm.style.display = \"\";\n" - + " document.getElementById(elementId + '-off').style.display = \"none\";\n" - + " document.getElementById(elementId + '-on').style.display = \"inline\";\n" - + " } else if (elm.style.display == \"\") {" - + " elm.style.display = \"none\";\n" - + " document.getElementById(elementId + '-off').style.display = \"inline\";\n" - + " document.getElementById(elementId + '-on').style.display = \"none\";\n" - + " } \n" - + " } \n" - + " }\n" - + "//"; - } -} diff --git a/maven-surefire-report-plugin/src/main/java/org/apache/maven/plugins/surefire/report/SurefireReportRenderer.java b/maven-surefire-report-plugin/src/main/java/org/apache/maven/plugins/surefire/report/SurefireReportRenderer.java new file mode 100644 index 0000000000..f7684c5516 --- /dev/null +++ b/maven-surefire-report-plugin/src/main/java/org/apache/maven/plugins/surefire/report/SurefireReportRenderer.java @@ -0,0 +1,600 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.maven.plugins.surefire.report; + +import java.io.File; +import java.text.NumberFormat; +import java.util.List; +import java.util.Locale; +import java.util.Map; + +import org.apache.maven.doxia.markup.HtmlMarkup; +import org.apache.maven.doxia.markup.Markup; +import org.apache.maven.doxia.sink.Sink; +import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet; +import org.apache.maven.doxia.util.DoxiaUtils; +import org.apache.maven.plugin.surefire.log.api.ConsoleLogger; +import org.apache.maven.reporting.AbstractMavenReportRenderer; + +import static org.apache.maven.doxia.markup.HtmlMarkup.A; +import static org.apache.maven.doxia.sink.SinkEventAttributes.CLASS; +import static org.apache.maven.doxia.sink.SinkEventAttributes.HREF; +import static org.apache.maven.doxia.sink.SinkEventAttributes.ID; +import static org.apache.maven.doxia.sink.SinkEventAttributes.STYLE; + +/** + * This generator creates HTML Report from Surefire and Failsafe XML Report. + */ +public class SurefireReportRenderer extends AbstractMavenReportRenderer { + private static final Object[] TAG_TYPE_START = {HtmlMarkup.TAG_TYPE_START}; + private static final Object[] TAG_TYPE_END = {HtmlMarkup.TAG_TYPE_END}; + + // Not used at the moment + private final Locale locale; + private final LocalizedProperties bundle; + + private final SurefireReportParser parser; + private final boolean showSuccess; + private final String xrefLocation; + private final List testSuites; + + public SurefireReportRenderer( + Sink sink, + Locale locale, + LocalizedProperties bundle, + ConsoleLogger consoleLogger, + boolean showSuccess, + List reportsDirectories, + String xrefLocation) { + super(sink); + this.locale = locale; + this.bundle = bundle; + parser = new SurefireReportParser(reportsDirectories, consoleLogger); + testSuites = parser.parseXMLReportFiles(); + this.showSuccess = showSuccess; + this.xrefLocation = xrefLocation; + } + + @Override + public String getTitle() { + return bundle.getReportHeader(); + } + + public void renderBody() { + javaScript(javascriptToggleDisplayCode()); + + sink.section1(); + sink.sectionTitle1(); + sink.text(getTitle()); + sink.sectionTitle1_(); + sink.section1_(); + + renderSectionSummary(); + + renderSectionPackages(); + + renderSectionTestCases(); + + renderSectionFailureDetails(); + } + + private void renderSectionSummary() { + Map summary = parser.getSummary(testSuites); + NumberFormat numberFormat = NumberFormat.getNumberInstance(locale); + NumberFormat percentFormat = NumberFormat.getPercentInstance(locale); + percentFormat.setMinimumFractionDigits(1); + + sink.section1(); + sinkAnchor("Summary"); + sink.sectionTitle1(); + sink.text(bundle.getReportLabelSummary()); + sink.sectionTitle1_(); + + constructHotLinks(); + + sink.lineBreak(); + + startTable(); + + tableHeader(new String[] { + bundle.getReportLabelTests(), + bundle.getReportLabelErrors(), + bundle.getReportLabelFailures(), + bundle.getReportLabelSkipped(), + bundle.getReportLabelSuccessRate(), + bundle.getReportLabelTime() + }); + + tableRow(new String[] { + String.valueOf(summary.get("totalTests")), + String.valueOf(summary.get("totalErrors")), + String.valueOf(summary.get("totalFailures")), + String.valueOf(summary.get("totalSkipped")), + percentFormat.format(summary.get("totalPercentage")), + numberFormat.format(summary.get("totalElapsedTime")) + " s" + }); + + endTable(); + + sink.lineBreak(); + + paragraph(bundle.getReportTextNode1()); + + sink.lineBreak(); + + sink.section1_(); + } + + private void renderSectionPackages() { + Map> suitePackages = parser.getSuitesGroupByPackage(testSuites); + if (suitePackages.isEmpty()) { + return; + } + + NumberFormat numberFormat = NumberFormat.getNumberInstance(locale); + NumberFormat percentFormat = NumberFormat.getPercentInstance(locale); + percentFormat.setMinimumFractionDigits(1); + + sink.section1(); + sinkAnchor("Package_List"); + sink.sectionTitle1(); + sink.text(bundle.getReportLabelPackageList()); + sink.sectionTitle1_(); + + constructHotLinks(); + + sink.lineBreak(); + + startTable(); + + tableHeader(new String[] { + bundle.getReportLabelPackage(), + bundle.getReportLabelTests(), + bundle.getReportLabelErrors(), + bundle.getReportLabelFailures(), + bundle.getReportLabelSkipped(), + bundle.getReportLabelSuccessRate(), + bundle.getReportLabelTime() + }); + + for (Map.Entry> entry : suitePackages.entrySet()) { + String packageName = entry.getKey(); + + List testSuiteList = entry.getValue(); + + Map packageSummary = parser.getSummary(testSuiteList); + + tableRow(new String[] { + '{' + packageName + ", #" + packageName + '}', + String.valueOf(packageSummary.get("totalTests")), + String.valueOf(packageSummary.get("totalErrors")), + String.valueOf(packageSummary.get("totalFailures")), + String.valueOf(packageSummary.get("totalSkipped")), + percentFormat.format(packageSummary.get("totalPercentage")), + numberFormat.format(packageSummary.get("totalElapsedTime")) + " s" + }); + } + + endTable(); + sink.lineBreak(); + + paragraph(bundle.getReportTextNode2()); + + for (Map.Entry> entry : suitePackages.entrySet()) { + String packageName = entry.getKey(); + + List testSuiteList = entry.getValue(); + + sink.section2(); + sinkAnchor(packageName); + sink.sectionTitle2(); + sink.text(packageName); + sink.sectionTitle2_(); + + boolean showTable = false; + + for (ReportTestSuite suite : testSuiteList) { + if (showSuccess || suite.getNumberOfErrors() != 0 || suite.getNumberOfFailures() != 0) { + showTable = true; + + break; + } + } + + if (showTable) { + startTable(); + + tableHeader(new String[] { + "", + bundle.getReportLabelClass(), + bundle.getReportLabelTests(), + bundle.getReportLabelErrors(), + bundle.getReportLabelFailures(), + bundle.getReportLabelSkipped(), + bundle.getReportLabelSuccessRate(), + bundle.getReportLabelTime() + }); + + for (ReportTestSuite suite : testSuiteList) { + if (showSuccess || suite.getNumberOfErrors() != 0 || suite.getNumberOfFailures() != 0) { + renderSectionTestSuite(suite); + } + } + + endTable(); + } + + sink.section2_(); + } + + sink.lineBreak(); + + sink.section1_(); + } + + private void renderSectionTestSuite(ReportTestSuite suite) { + NumberFormat numberFormat = NumberFormat.getNumberInstance(locale); + NumberFormat percentFormat = NumberFormat.getPercentInstance(locale); + percentFormat.setMinimumFractionDigits(1); + + sink.tableRow(); + + sink.tableCell(); + + sink.link("#" + suite.getPackageName() + '.' + suite.getName()); + + if (suite.getNumberOfErrors() > 0) { + sinkIcon("error"); + } else if (suite.getNumberOfFailures() > 0) { + sinkIcon("junit.framework"); + } else if (suite.getNumberOfSkipped() > 0) { + sinkIcon("skipped"); + } else { + sinkIcon("success"); + } + + sink.link_(); + + sink.tableCell_(); + + tableCell('{' + suite.getName() + ", #" + suite.getPackageName() + '.' + suite.getName() + '}'); + + tableCell(Integer.toString(suite.getNumberOfTests())); + + tableCell(Integer.toString(suite.getNumberOfErrors())); + + tableCell(Integer.toString(suite.getNumberOfFailures())); + + tableCell(Integer.toString(suite.getNumberOfSkipped())); + + float percentage = parser.computePercentage( + suite.getNumberOfTests(), suite.getNumberOfErrors(), + suite.getNumberOfFailures(), suite.getNumberOfSkipped()); + tableCell(percentFormat.format(percentage)); + + tableCell(numberFormat.format(suite.getTimeElapsed()) + " s"); + + sink.tableRow_(); + } + + private void renderSectionTestCases() { + if (testSuites.isEmpty()) { + return; + } + + sink.section1(); + sinkAnchor("Test_Cases"); + sink.sectionTitle1(); + sink.text(bundle.getReportLabelTestCases()); + sink.sectionTitle1_(); + + constructHotLinks(); + + for (ReportTestSuite suite : testSuites) { + List testCases = suite.getTestCases(); + + if (!testCases.isEmpty()) { + sink.section2(); + sinkAnchor(suite.getPackageName() + '.' + suite.getName()); + sink.sectionTitle2(); + sink.text(suite.getName()); + sink.sectionTitle2_(); + + boolean showTable = false; + + for (ReportTestCase testCase : testCases) { + if (!testCase.isSuccessful() || showSuccess) { + showTable = true; + + break; + } + } + + if (showTable) { + startTable(); + + for (ReportTestCase testCase : testCases) { + if (!testCase.isSuccessful() || showSuccess) { + constructTestCaseSection(testCase); + } + } + + endTable(); + } + + sink.section2_(); + } + } + + sink.lineBreak(); + + sink.section1_(); + } + + private void constructTestCaseSection(ReportTestCase testCase) { + NumberFormat numberFormat = NumberFormat.getNumberInstance(locale); + + sink.tableRow(); + + sink.tableCell(); + + if (testCase.getFailureType() != null) { + sink.link("#" + toHtmlId(testCase.getFullName())); + + sinkIcon(testCase.getFailureType()); + + sink.link_(); + } else { + sinkIcon("success"); + } + + sink.tableCell_(); + + if (!testCase.isSuccessful()) { + sink.tableCell(); + sinkAnchor("TC_" + toHtmlId(testCase.getFullName())); + + link("#" + toHtmlId(testCase.getFullName()), testCase.getName()); + + SinkEventAttributeSet atts = new SinkEventAttributeSet(); + atts.addAttribute(CLASS, "detailToggle"); + atts.addAttribute(STYLE, "display:inline"); + sink.unknown("div", TAG_TYPE_START, atts); + + sinkLink("javascript:toggleDisplay('" + toHtmlId(testCase.getFullName()) + "');"); + + atts = new SinkEventAttributeSet(); + atts.addAttribute(STYLE, "display:inline;"); + atts.addAttribute(ID, toHtmlId(testCase.getFullName()) + "-off"); + sink.unknown("span", TAG_TYPE_START, atts); + sink.text(" + "); + sink.unknown("span", TAG_TYPE_END, null); + + atts = new SinkEventAttributeSet(); + atts.addAttribute(STYLE, "display:none;"); + atts.addAttribute(ID, toHtmlId(testCase.getFullName()) + "-on"); + sink.unknown("span", TAG_TYPE_START, atts); + sink.text(" - "); + sink.unknown("span", TAG_TYPE_END, null); + + sink.text("[ Detail ]"); + sinkLink_(); + + sink.unknown("div", TAG_TYPE_END, null); + + sink.tableCell_(); + } else { + sinkCellAnchor(testCase.getName(), "TC_" + toHtmlId(testCase.getFullName())); + } + + tableCell(numberFormat.format(testCase.getTime()) + " s"); + + sink.tableRow_(); + + if (!testCase.isSuccessful()) { + String message = testCase.getFailureMessage(); + if (message != null) { + tableRow(new String[] {"", message, ""}); + } + + String detail = testCase.getFailureDetail(); + if (detail != null) { + SinkEventAttributeSet atts = new SinkEventAttributeSet(); + atts.addAttribute(ID, toHtmlId(testCase.getFullName()) + toHtmlIdFailure(testCase)); + atts.addAttribute(STYLE, "display:none;"); + sink.tableRow(atts); + + tableCell(""); + + sink.tableCell(); + + verbatimText(detail); + + sink.tableCell_(); + + tableCell(""); + + sink.tableRow_(); + } + } + } + + private String toHtmlId(String id) { + return DoxiaUtils.isValidId(id) ? id : DoxiaUtils.encodeId(id, true); + } + + private void renderSectionFailureDetails() { + List failures = parser.getFailureDetails(testSuites); + if (failures.isEmpty()) { + return; + } + + sink.section1(); + sinkAnchor("Failure_Details"); + sink.sectionTitle1(); + sink.text(bundle.getReportLabelFailureDetails()); + sink.sectionTitle1_(); + + constructHotLinks(); + + sink.lineBreak(); + + startTable(); + + for (ReportTestCase testCase : failures) { + sink.tableRow(); + + sink.tableCell(); + + String type = testCase.getFailureType(); + + sinkIcon(type); + + sink.tableCell_(); + + sinkCellAnchor(testCase.getName(), toHtmlId(testCase.getFullName())); + + sink.tableRow_(); + + String message = testCase.getFailureMessage(); + + sink.tableRow(); + + tableCell(""); + + tableCell(message == null ? type : type + ": " + message); + + sink.tableRow_(); + + String detail = testCase.getFailureDetail(); + if (detail != null) { + sink.tableRow(); + + tableCell(""); + + sink.tableCell(); + SinkEventAttributeSet atts = new SinkEventAttributeSet(); + atts.addAttribute(ID, testCase.getName() + toHtmlIdFailure(testCase)); + sink.unknown("div", TAG_TYPE_START, atts); + + String fullClassName = testCase.getFullClassName(); + String errorLineNumber = testCase.getFailureErrorLine(); + if (xrefLocation != null) { + String path = fullClassName.replace('.', '/'); + sink.link(xrefLocation + "/" + path + ".html#L" + errorLineNumber); + } + sink.text(fullClassName + ":" + errorLineNumber); + + if (xrefLocation != null) { + sink.link_(); + } + sink.unknown("div", TAG_TYPE_END, null); + + sink.tableCell_(); + + sink.tableRow_(); + } + } + + endTable(); + + sink.lineBreak(); + + sink.section1_(); + } + + private void constructHotLinks() { + if (!testSuites.isEmpty()) { + sink.paragraph(); + + sink.text("["); + link("#Summary", bundle.getReportLabelSummary()); + sink.text("]"); + + sink.text(" ["); + link("#Package_List", bundle.getReportLabelPackageList()); + sink.text("]"); + + sink.text(" ["); + link("#Test_Cases", bundle.getReportLabelTestCases()); + sink.text("]"); + + sink.paragraph_(); + } + } + + private String toHtmlIdFailure(ReportTestCase testCase) { + return testCase.hasError() ? "-error" : "-failure"; + } + + private void sinkIcon(String type) { + if (type.startsWith("junit.framework") || "skipped".equals(type)) { + sink.figureGraphics("images/icon_warning_sml.gif"); + } else if (type.startsWith("success")) { + sink.figureGraphics("images/icon_success_sml.gif"); + } else { + sink.figureGraphics("images/icon_error_sml.gif"); + } + } + + private void sinkCellAnchor(String text, String anchor) { + sink.tableCell(); + sinkAnchor(anchor); + sink.text(text); + sink.tableCell_(); + } + + private void sinkAnchor(String anchor) { + // Dollar '$' for nested classes is not valid character in sink.anchor() and therefore it is ignored + // https://issues.apache.org/jira/browse/SUREFIRE-1443 + sink.unknown(A.toString(), TAG_TYPE_START, new SinkEventAttributeSet(ID, anchor)); + sink.unknown(A.toString(), TAG_TYPE_END, null); + } + + private void sinkLink(String href) { + // The "'" argument in this JavaScript function would be escaped to "'" + // sink.link( "javascript:toggleDisplay('" + toHtmlId( testCase.getFullName() ) + "');" ); + sink.unknown(A.toString(), TAG_TYPE_START, new SinkEventAttributeSet(HREF, href)); + } + + @SuppressWarnings("checkstyle:methodname") + private void sinkLink_() { + sink.unknown(A.toString(), TAG_TYPE_END, null); + } + + private String javascriptToggleDisplayCode() { + return "function toggleDisplay(elementId) {" + Markup.EOL + + " var elm = document.getElementById(elementId + '-error');" + Markup.EOL + + " if (elm == null) {" + Markup.EOL + + " elm = document.getElementById(elementId + '-failure');" + Markup.EOL + + " }" + Markup.EOL + + " if (elm && typeof elm.style != \"undefined\") {" + Markup.EOL + + " if (elm.style.display == \"none\") {" + Markup.EOL + + " elm.style.display = \"\";" + Markup.EOL + + " document.getElementById(elementId + '-off').style.display = \"none\";" + Markup.EOL + + " document.getElementById(elementId + '-on').style.display = \"inline\";" + Markup.EOL + + " } else if (elm.style.display == \"\") {" + + " elm.style.display = \"none\";" + Markup.EOL + + " document.getElementById(elementId + '-off').style.display = \"inline\";" + Markup.EOL + + " document.getElementById(elementId + '-on').style.display = \"none\";" + Markup.EOL + + " }" + Markup.EOL + + " }" + Markup.EOL + + " }"; + } +} diff --git a/maven-surefire-report-plugin/src/test/java/org/apache/maven/plugins/surefire/report/Surefire597Test.java b/maven-surefire-report-plugin/src/test/java/org/apache/maven/plugins/surefire/report/Surefire597Test.java index e3274f5b7e..d1598a2ee7 100644 --- a/maven-surefire-report-plugin/src/test/java/org/apache/maven/plugins/surefire/report/Surefire597Test.java +++ b/maven-surefire-report-plugin/src/test/java/org/apache/maven/plugins/surefire/report/Surefire597Test.java @@ -24,11 +24,11 @@ import junit.framework.TestCase; import org.apache.maven.doxia.module.xhtml5.Xhtml5Sink; import org.apache.maven.doxia.sink.Sink; +import org.apache.maven.doxia.tools.SiteTool; import org.apache.maven.plugin.surefire.log.api.ConsoleLogger; import org.apache.maven.plugin.surefire.log.api.NullConsoleLogger; import static java.util.Collections.singletonList; -import static java.util.Locale.ENGLISH; import static org.apache.maven.plugins.surefire.report.Utils.toSystemNewLine; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.MatcherAssert.assertThat; @@ -41,11 +41,18 @@ public class Surefire597Test extends TestCase { public void testCorruptedTestCaseFailureWithMissingErrorTypeAndMessage() throws Exception { File basedir = new File(".").getCanonicalFile(); File report = new File(basedir, "target/test-classes/surefire-597"); - ConsoleLogger log = new NullConsoleLogger(); - SurefireReportGenerator gen = new SurefireReportGenerator(singletonList(report), ENGLISH, true, null, log); StringWriter writer = new StringWriter(); Sink sink = new Xhtml5Sink(writer) {}; - gen.doGenerateReport(new SurefireReportMojo().getBundle(ENGLISH), sink); + ConsoleLogger consoleLogger = new NullConsoleLogger(); + SurefireReportRenderer r = new SurefireReportRenderer( + sink, + SiteTool.DEFAULT_LOCALE, + new SurefireReportMojo().getBundle(SiteTool.DEFAULT_LOCALE), + consoleLogger, + true, + singletonList(report), + null); + r.render(); String xml = writer.toString(); assertThat( xml, @@ -59,11 +66,11 @@ public void testCorruptedTestCaseFailureWithMissingErrorTypeAndMessage() throws + "Time\n" + "\n" + "1\n" - + "1\n" - + "0\n" - + "0\n" - + "0%\n" - + "0" + + "1\n" + + "0\n" + + "0\n" + + "0.0%\n" + + "0 s" + "" + ""))); assertThat( @@ -79,17 +86,17 @@ public void testCorruptedTestCaseFailureWithMissingErrorTypeAndMessage() throws + "Time\n" + "\n" + "surefire\n" - + "1\n" - + "1\n" - + "0\n" - + "0\n" - + "0%\n" - + "0"))); + + "1\n" + + "1\n" + + "0\n" + + "0\n" + + "0.0%\n" + + "0 s"))); assertThat( xml, containsString(toSystemNewLine("\n" + "\n" - + "\n" + + "\n" + "\n" + "\n" + "\n" @@ -99,25 +106,25 @@ public void testCorruptedTestCaseFailureWithMissingErrorTypeAndMessage() throws + "\n" + "\n" + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "\n" - + "
-ClassTestsErrorsTime
\"\"MyTest11000%0
"))); + + "MyTest\n" + + "1\n" + + "1\n" + + "0\n" + + "0\n" + + "0.0%\n" + + "0 s"))); assertThat( xml, containsString(toSystemNewLine("\n" + "\n" + "\n" - + "\n" + + "\n" + "\n" - + "\n" - + "\n" + + "\n" + + "\n" + "\n" - + "\n" - + "\n" + + "
\"\"test
test
java.lang.RuntimeException: java.lang.IndexOutOfBoundsException: msg
-java.lang.RuntimeException: java.lang.IndexOutOfBoundsException: msg
\n" + + "-\n" + "
surefire.MyTest:13
"))); } } diff --git a/maven-surefire-report-plugin/src/test/java/org/apache/maven/plugins/surefire/report/SurefireReportMojoTest.java b/maven-surefire-report-plugin/src/test/java/org/apache/maven/plugins/surefire/report/SurefireReportMojoTest.java index 14c1992da9..4dfb98a512 100644 --- a/maven-surefire-report-plugin/src/test/java/org/apache/maven/plugins/surefire/report/SurefireReportMojoTest.java +++ b/maven-surefire-report-plugin/src/test/java/org/apache/maven/plugins/surefire/report/SurefireReportMojoTest.java @@ -19,26 +19,17 @@ package org.apache.maven.plugins.surefire.report; import java.io.File; -import java.io.IOException; import java.io.UnsupportedEncodingException; -import java.io.Writer; import java.net.URL; import java.net.URLDecoder; import java.util.Locale; -import org.apache.maven.doxia.site.decoration.DecorationModel; -import org.apache.maven.doxia.siterenderer.Renderer; -import org.apache.maven.doxia.siterenderer.RendererException; -import org.apache.maven.doxia.siterenderer.SiteRenderingContext; -import org.apache.maven.doxia.siterenderer.sink.SiteRendererSink; import org.apache.maven.plugin.LegacySupport; import org.apache.maven.plugin.testing.AbstractMojoTestCase; import org.apache.maven.plugin.testing.ArtifactStubFactory; import org.apache.maven.plugin.testing.stubs.MavenProjectStub; import org.apache.maven.plugins.surefire.report.stubs.DependencyArtifactStubFactory; -import org.apache.maven.shared.utils.WriterFactory; import org.apache.maven.shared.utils.io.FileUtils; -import org.apache.maven.shared.utils.io.IOUtil; import org.eclipse.aether.DefaultRepositorySystemSession; import org.eclipse.aether.internal.impl.SimpleLocalRepositoryManagerFactory; import org.eclipse.aether.repository.LocalRepository; @@ -54,15 +45,23 @@ public class SurefireReportMojoTest extends AbstractMojoTestCase { private ArtifactStubFactory artifactStubFactory; - private Renderer renderer; + // Can be removed with Doxia 2.0.0 + private Locale origLocale; @Override protected void setUp() throws Exception { super.setUp(); - renderer = (Renderer) lookup(Renderer.ROLE); - artifactStubFactory = new DependencyArtifactStubFactory(getTestFile("target"), true, false); artifactStubFactory.getWorkingDir().mkdirs(); + + origLocale = Locale.getDefault(); + Locale.setDefault(Locale.ROOT); + } + + @Override + protected void tearDown() throws Exception { + Locale.setDefault(origLocale); + super.tearDown(); } protected SurefireReportMojo createReportMojo(File pluginXmlFile) throws Exception { @@ -105,7 +104,6 @@ public void testBasicSurefireReport() throws Exception { mojo.execute(); File report = new File(getBasedir(), "target/site/unit/basic-surefire-report-test/surefire-report.html"); - renderer(mojo, report); assertTrue(report.exists()); String htmlContent = FileUtils.fileRead(report); @@ -127,7 +125,6 @@ public void testBasicSurefireReportIfShowSuccessIsFalse() throws Exception { mojo.execute(); File report = new File(getBasedir(), "target/site/unit/basic-surefire-report-success-false/surefire-report.html"); - renderer(mojo, report); assertTrue(report.exists()); String htmlContent = FileUtils.fileRead(report); @@ -142,8 +139,7 @@ public void testBasicSurefireReportIfLinkXrefIsFalse() throws Exception { assertFalse(linkXRef); mojo.execute(); File report = - new File(getBasedir(), "target/site/unit/basic-surefire-report-success-false/surefire-report.html"); - renderer(mojo, report); + new File(getBasedir(), "target/site/unit/basic-surefire-report-linkxref-false/surefire-report.html"); assertTrue(report.exists()); String htmlContent = FileUtils.fileRead(report); @@ -157,7 +153,6 @@ public void testBasicSurefireReportIfReportingIsNull() throws Exception { mojo.execute(); File report = new File(getBasedir(), "target/site/unit/basic-surefire-report-reporting-null/surefire-report.html"); - renderer(mojo, report); assertTrue(report.exists()); String htmlContent = FileUtils.fileRead(report); @@ -172,14 +167,13 @@ public void testBasicSurefireReport_AnchorTestCases() throws Exception { mojo.execute(); File report = new File(getBasedir(), "target/site/unit/basic-surefire-report-anchor-test-cases/surefire-report.html"); - renderer(mojo, report); assertTrue(report.exists()); String htmlContent = FileUtils.fileRead(report); - int idx = htmlContent.indexOf("testX"); + int idx = htmlContent.indexOf("testX"); assertTrue(idx > 0); - idx = htmlContent.indexOf("" + idx = htmlContent.indexOf("" + "testRadius"); assertTrue(idx > 0); } @@ -189,7 +183,6 @@ public void testSurefireReportSingleError() throws Exception { SurefireReportMojo mojo = createReportMojo(testPom); mojo.execute(); File report = new File(getBasedir(), "target/site/unit/surefire-report-single-error/surefire-report.html"); - renderer(mojo, report); assertTrue(report.exists()); String htmlContent = FileUtils.fileRead(report); @@ -197,22 +190,22 @@ public void testSurefireReportSingleError() throws Exception { htmlContent, containsString(toSystemNewLine("\n" + "1\n" - + "1\n" - + "0\n" - + "0\n" - + "0%\n" - + "0"))); + + "1\n" + + "0\n" + + "0\n" + + "0.0%\n" + + "0 s"))); assertThat( htmlContent, containsString(toSystemNewLine("\n" + "surefire\n" - + "1\n" - + "1\n" - + "0\n" - + "0\n" - + "0%\n" - + "0"))); + + "1\n" + + "1\n" + + "0\n" + + "0\n" + + "0.0%\n" + + "0 s"))); assertThat( htmlContent, containsString(toSystemNewLine("\n" @@ -221,13 +214,13 @@ public void testSurefireReportSingleError() throws Exception { + "\"\"" + "" + "\n" - + "MyTest\n" - + "1\n" - + "1\n" - + "0\n" - + "0\n" - + "0%\n" - + "0"))); + + "MyTest\n" + + "1\n" + + "1\n" + + "0\n" + + "0\n" + + "0.0%\n" + + "0 s"))); assertThat(htmlContent, containsString(">surefire.MyTest:13")); @@ -278,7 +271,6 @@ public void testSurefireReportNestedClassTrimStackTrace() throws Exception { mojo.execute(); File report = new File( getBasedir(), "target/site/unit/surefire-report-nestedClass-trimStackTrace/surefire-report.html"); - renderer(mojo, report); assertTrue(report.exists()); String htmlContent = FileUtils.fileRead(report); @@ -286,22 +278,22 @@ public void testSurefireReportNestedClassTrimStackTrace() throws Exception { htmlContent, containsString(toSystemNewLine("\n" + "1\n" - + "1\n" - + "0\n" - + "0\n" - + "0%\n" - + "0"))); + + "1\n" + + "0\n" + + "0\n" + + "0.0%\n" + + "0 s"))); assertThat( htmlContent, containsString(toSystemNewLine("\n" + "surefire\n" - + "1\n" - + "1\n" - + "0\n" - + "0\n" - + "0%\n" - + "0"))); + + "1\n" + + "1\n" + + "0\n" + + "0\n" + + "0.0%\n" + + "0 s"))); assertThat( htmlContent, containsString(toSystemNewLine("\n" @@ -310,13 +302,13 @@ public void testSurefireReportNestedClassTrimStackTrace() throws Exception { + "\"\"" + "" + "\n" - + "MyTest\n" - + "1\n" - + "1\n" - + "0\n" - + "0\n" - + "0%\n" - + "0"))); + + "MyTest\n" + + "1\n" + + "1\n" + + "0\n" + + "0\n" + + "0.0%\n" + + "0 s"))); assertThat(htmlContent, containsString(">surefire.MyTest:13")); assertThat(htmlContent, containsString("./xref-test/surefire/MyTest.html#L13")); @@ -342,7 +334,6 @@ public void testSurefireReportNestedClass() throws Exception { SurefireReportMojo mojo = createReportMojo(testPom); mojo.execute(); File report = new File(getBasedir(), "target/site/unit/surefire-report-nestedClass/surefire-report.html"); - renderer(mojo, report); assertTrue(report.exists()); String htmlContent = FileUtils.fileRead(report); @@ -350,22 +341,22 @@ public void testSurefireReportNestedClass() throws Exception { htmlContent, containsString(toSystemNewLine("\n" + "1\n" - + "1\n" - + "0\n" - + "0\n" - + "0%\n" - + "0"))); + + "1\n" + + "0\n" + + "0\n" + + "0.0%\n" + + "0 s"))); assertThat( htmlContent, containsString(toSystemNewLine("\n" + "surefire\n" - + "1\n" - + "1\n" - + "0\n" - + "0\n" - + "0%\n" - + "0"))); + + "1\n" + + "1\n" + + "0\n" + + "0\n" + + "0.0%\n" + + "0 s"))); assertThat( htmlContent, containsString(toSystemNewLine("\n" @@ -374,13 +365,13 @@ public void testSurefireReportNestedClass() throws Exception { + "\"\"" + "" + "\n" - + "MyTest\n" - + "1\n" - + "1\n" - + "0\n" - + "0\n" - + "0%\n" - + "0"))); + + "MyTest\n" + + "1\n" + + "1\n" + + "0\n" + + "0\n" + + "0.0%\n" + + "0 s"))); assertThat(htmlContent, containsString(">surefire.MyTest:13")); assertThat(htmlContent, containsString("./xref-test/surefire/MyTest.html#L13")); @@ -431,7 +422,6 @@ public void testSurefireReportEnclosedTrimStackTrace() throws Exception { mojo.execute(); File report = new File(getBasedir(), "target/site/unit/surefire-report-enclosed-trimStackTrace/surefire-report.html"); - renderer(mojo, report); assertTrue(report.exists()); String htmlContent = FileUtils.fileRead(report); @@ -439,22 +429,22 @@ public void testSurefireReportEnclosedTrimStackTrace() throws Exception { htmlContent, containsString(toSystemNewLine("\n" + "1\n" - + "1\n" - + "0\n" - + "0\n" - + "0%\n" - + "0"))); + + "1\n" + + "0\n" + + "0\n" + + "0.0%\n" + + "0 s"))); assertThat( htmlContent, containsString(toSystemNewLine("\n" + "surefire\n" - + "1\n" - + "1\n" - + "0\n" - + "0\n" - + "0%\n" - + "0"))); + + "1\n" + + "1\n" + + "0\n" + + "0\n" + + "0.0%\n" + + "0 s"))); assertThat( htmlContent, containsString(toSystemNewLine("\n" @@ -463,13 +453,13 @@ public void testSurefireReportEnclosedTrimStackTrace() throws Exception { + "\"\"" + "" + "\n" - + "MyTest$A\n" - + "1\n" - + "1\n" - + "0\n" - + "0\n" - + "0%\n" - + "0"))); + + "MyTest$A\n" + + "1\n" + + "1\n" + + "0\n" + + "0\n" + + "0.0%\n" + + "0 s"))); assertThat(htmlContent, containsString(">surefire.MyTest$A:45")); @@ -495,7 +485,6 @@ public void testSurefireReportEnclosed() throws Exception { SurefireReportMojo mojo = createReportMojo(testPom); mojo.execute(); File report = new File(getBasedir(), "target/site/unit/surefire-report-enclosed/surefire-report.html"); - renderer(mojo, report); assertTrue(report.exists()); String htmlContent = FileUtils.fileRead(report); @@ -503,22 +492,22 @@ public void testSurefireReportEnclosed() throws Exception { htmlContent, containsString(toSystemNewLine("\n" + "1\n" - + "1\n" - + "0\n" - + "0\n" - + "0%\n" - + "0"))); + + "1\n" + + "0\n" + + "0\n" + + "0.0%\n" + + "0 s"))); assertThat( htmlContent, containsString(toSystemNewLine("\n" + "surefire\n" - + "1\n" - + "1\n" - + "0\n" - + "0\n" - + "0%\n" - + "0"))); + + "1\n" + + "1\n" + + "0\n" + + "0\n" + + "0.0%\n" + + "0 s"))); assertThat( htmlContent, containsString(toSystemNewLine("\n" @@ -527,13 +516,13 @@ public void testSurefireReportEnclosed() throws Exception { + "\"\"" + "" + "\n" - + "MyTest$A\n" - + "1\n" - + "1\n" - + "0\n" - + "0\n" - + "0%\n" - + "0"))); + + "MyTest$A\n" + + "1\n" + + "1\n" + + "0\n" + + "0\n" + + "0.0%\n" + + "0 s"))); assertThat(htmlContent, containsString(">surefire.MyTest$A:45")); @@ -609,37 +598,11 @@ public void testCustomTitleAndDescriptionReport() throws Exception { mojo.execute(); - File report = new File(getBasedir(), "target/site/acceptance-test-report.html"); - renderer(mojo, report); + File report = new File(getBasedir(), "target/site/unit/surefire-1183/acceptance-test-report.html"); assertTrue(report.exists()); String htmlContent = FileUtils.fileRead(report); assertTrue(htmlContent.contains("

Acceptance Test

")); } - - /** - * Renderer the sink from the report mojo. - * - * @param mojo not null - * @param outputHtml not null - * @throws RendererException if any - * @throws IOException if any - */ - private void renderer(SurefireReportMojo mojo, File outputHtml) throws RendererException, IOException { - Writer writer = null; - SiteRenderingContext context = new SiteRenderingContext(); - context.setDecoration(new DecorationModel()); - context.setTemplateName("org/apache/maven/doxia/siterenderer/resources/default-site.vm"); - context.setLocale(Locale.ENGLISH); - - try { - outputHtml.getParentFile().mkdirs(); - writer = WriterFactory.newXmlWriter(outputHtml); - - renderer.generateDocument(writer, (SiteRendererSink) mojo.getSink(), context); - } finally { - IOUtil.close(writer); - } - } } diff --git a/maven-surefire-report-plugin/src/test/resources/unit/surefire-1183/plugin-config.xml b/maven-surefire-report-plugin/src/test/resources/unit/surefire-1183/plugin-config.xml index 3166e78965..75ad4abd91 100644 --- a/maven-surefire-report-plugin/src/test/resources/unit/surefire-1183/plugin-config.xml +++ b/maven-surefire-report-plugin/src/test/resources/unit/surefire-1183/plugin-config.xml @@ -31,8 +31,7 @@ acceptance-test-report ${localRepository} ${basedir}/target/site/unit/surefire-1183 - ${basedir}/src/test/resources/unit/surefire-1183/acceptancetest-reports - + ${basedir}/src/test/resources/unit/surefire-1183/acceptancetest-reports diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire260TestWithIdenticalNamesIT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire260TestWithIdenticalNamesIT.java index aca227760e..5c473af91a 100644 --- a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire260TestWithIdenticalNamesIT.java +++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire260TestWithIdenticalNamesIT.java @@ -23,8 +23,9 @@ import com.gargoylesoftware.htmlunit.WebClient; import com.gargoylesoftware.htmlunit.html.HtmlAnchor; -import com.gargoylesoftware.htmlunit.html.HtmlDivision; import com.gargoylesoftware.htmlunit.html.HtmlPage; +import com.gargoylesoftware.htmlunit.html.HtmlTableRow; + import org.apache.maven.surefire.its.fixture.OutputValidator; import org.apache.maven.surefire.its.fixture.SurefireJUnit4IntegrationTestCase; import org.apache.maven.surefire.its.fixture.TestFile; @@ -58,7 +59,7 @@ public void testWithIdenticalNames() throws IOException { HtmlAnchor a = (HtmlAnchor) page.getByXPath("//a[@href = \"javascript:toggleDisplay('surefire260.TestB.testDup');\"]") .get(0); - HtmlDivision content = (HtmlDivision) page.getElementById("surefire260.TestB.testDup-failure"); + HtmlTableRow content = (HtmlTableRow) page.getElementById("surefire260.TestB.testDup-failure"); assertNotNull(content); assertTrue(content.getAttribute("style").contains("none")); a.click(); diff --git a/surefire-report-parser/src/main/java/org/apache/maven/plugins/surefire/report/SurefireReportParser.java b/surefire-report-parser/src/main/java/org/apache/maven/plugins/surefire/report/SurefireReportParser.java index 467d78487c..2303176473 100644 --- a/surefire-report-parser/src/main/java/org/apache/maven/plugins/surefire/report/SurefireReportParser.java +++ b/surefire-report-parser/src/main/java/org/apache/maven/plugins/surefire/report/SurefireReportParser.java @@ -22,16 +22,13 @@ import java.io.File; import java.io.IOException; -import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.List; -import java.util.Locale; import java.util.Map; import org.apache.maven.plugin.surefire.log.api.ConsoleLogger; -import org.apache.maven.reporting.MavenReportException; import org.apache.maven.shared.utils.io.DirectoryScanner; import org.xml.sax.SAXException; @@ -46,23 +43,18 @@ public final class SurefireReportParser { private static final String EXCLUDES = "*.txt, testng-failed.xml, testng-failures.xml, testng-results.xml, failsafe-summary*.xml"; - private static final int PCENT = 100; - private final List testSuites = new ArrayList<>(); - private final NumberFormat numberFormat; - private final ConsoleLogger consoleLogger; private final List reportsDirectories; - public SurefireReportParser(List reportsDirectories, Locale locale, ConsoleLogger consoleLogger) { + public SurefireReportParser(List reportsDirectories, ConsoleLogger consoleLogger) { this.reportsDirectories = reportsDirectories; - numberFormat = NumberFormat.getInstance(locale); this.consoleLogger = consoleLogger; } - public List parseXMLReportFiles() throws MavenReportException { + public List parseXMLReportFiles() { final Collection xmlReportFiles = new ArrayList<>(); for (File reportsDirectory : reportsDirectories) { if (reportsDirectory.exists()) { @@ -76,19 +68,19 @@ public List parseXMLReportFiles() throws MavenReportException { try { testSuites.addAll(parser.parse(aXmlReportFileList.getAbsolutePath())); } catch (ParserConfigurationException e) { - throw new MavenReportException("Error setting up parser for JUnit XML report", e); + throw new RuntimeException("Error setting up parser for JUnit XML report", e); } catch (SAXException e) { - throw new MavenReportException("Error parsing JUnit XML report " + aXmlReportFileList, e); + throw new RuntimeException("Error parsing JUnit XML report " + aXmlReportFileList, e); } catch (IOException e) { - throw new MavenReportException("Error reading JUnit XML report " + aXmlReportFileList, e); + throw new RuntimeException("Error reading JUnit XML report " + aXmlReportFileList, e); } } return testSuites; } - public Map getSummary(List suites) { - Map totalSummary = new HashMap<>(); + public Map getSummary(List suites) { + Map totalSummary = new HashMap<>(); int totalNumberOfTests = 0; @@ -112,28 +104,24 @@ public Map getSummary(List suites) { totalElapsedTime += suite.getTimeElapsed(); } - String totalPercentage = + float totalPercentage = computePercentage(totalNumberOfTests, totalNumberOfErrors, totalNumberOfFailures, totalNumberOfSkipped); - totalSummary.put("totalTests", Integer.toString(totalNumberOfTests)); + totalSummary.put("totalTests", totalNumberOfTests); - totalSummary.put("totalErrors", Integer.toString(totalNumberOfErrors)); + totalSummary.put("totalErrors", totalNumberOfErrors); - totalSummary.put("totalFailures", Integer.toString(totalNumberOfFailures)); + totalSummary.put("totalFailures", totalNumberOfFailures); - totalSummary.put("totalSkipped", Integer.toString(totalNumberOfSkipped)); + totalSummary.put("totalSkipped", totalNumberOfSkipped); - totalSummary.put("totalElapsedTime", numberFormat.format(totalElapsedTime)); + totalSummary.put("totalElapsedTime", totalElapsedTime); totalSummary.put("totalPercentage", totalPercentage); return totalSummary; } - public NumberFormat getNumberFormat() { - return numberFormat; - } - public Map> getSuitesGroupByPackage(List testSuitesList) { Map> suitePackage = new HashMap<>(); @@ -152,9 +140,12 @@ public Map> getSuitesGroupByPackage(List getFailureDetails(List testSuites) { diff --git a/surefire-report-parser/src/test/java/org/apache/maven/plugins/surefire/report/SurefireReportParserTest.java b/surefire-report-parser/src/test/java/org/apache/maven/plugins/surefire/report/SurefireReportParserTest.java index 4596f60ab4..8a9240e11c 100644 --- a/surefire-report-parser/src/test/java/org/apache/maven/plugins/surefire/report/SurefireReportParserTest.java +++ b/surefire-report-parser/src/test/java/org/apache/maven/plugins/surefire/report/SurefireReportParserTest.java @@ -22,7 +22,6 @@ import java.io.UnsupportedEncodingException; import java.net.URL; import java.net.URLDecoder; -import java.text.NumberFormat; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -31,7 +30,6 @@ import org.apache.maven.plugin.surefire.log.api.NullConsoleLogger; import static java.util.Collections.singletonList; -import static java.util.Locale.ENGLISH; /** * @@ -39,10 +37,9 @@ @SuppressWarnings("checkstyle:magicnumber") public class SurefireReportParserTest extends TestCase { public void testParseXMLReportFiles() throws Exception { - SurefireReportParser report = - new SurefireReportParser(singletonList(getTestDir()), ENGLISH, new NullConsoleLogger()); + SurefireReportParser parser = new SurefireReportParser(singletonList(getTestDir()), new NullConsoleLogger()); - List suites = report.parseXMLReportFiles(); + List suites = parser.parseXMLReportFiles(); assertEquals(8, suites.size()); @@ -80,23 +77,21 @@ public void testGetSummary() throws Exception { suites.add(tSuite2); - SurefireReportParser report = new SurefireReportParser(null, ENGLISH, new NullConsoleLogger()); + SurefireReportParser parser = new SurefireReportParser(null, new NullConsoleLogger()); - Map testMap = report.getSummary(suites); + Map testMap = parser.getSummary(suites); - assertEquals(20, Integer.parseInt(testMap.get("totalErrors"))); + assertEquals(20, (int) testMap.get("totalErrors")); - assertEquals(40, Integer.parseInt(testMap.get("totalFailures"))); + assertEquals(40, (int) testMap.get("totalFailures")); - assertEquals(200, Integer.parseInt(testMap.get("totalTests"))); + assertEquals(200, (int) testMap.get("totalTests")); - assertEquals(4, Integer.parseInt(testMap.get("totalSkipped"))); + assertEquals(4, (int) testMap.get("totalSkipped")); - NumberFormat numberFormat = report.getNumberFormat(); + assertEquals(2.0f, (float) testMap.get("totalElapsedTime")); - assertEquals(2.0f, numberFormat.parse(testMap.get("totalElapsedTime")).floatValue(), 0.0f); - - assertEquals(68.00f, numberFormat.parse(testMap.get("totalPercentage")).floatValue(), 0); + assertEquals(0.68f, (float) testMap.get("totalPercentage")); } public void testGetSuitesGroupByPackage() { @@ -120,9 +115,9 @@ public void testGetSuitesGroupByPackage() { suites.add(tSuite3); - SurefireReportParser report = new SurefireReportParser(null, ENGLISH, new NullConsoleLogger()); + SurefireReportParser parser = new SurefireReportParser(null, new NullConsoleLogger()); - Map> groupMap = report.getSuitesGroupByPackage(suites); + Map> groupMap = parser.getSuitesGroupByPackage(suites); assertEquals(2, groupMap.size()); @@ -134,13 +129,9 @@ public void testGetSuitesGroupByPackage() { } public void testComputePercentage() throws Exception { - SurefireReportParser report = new SurefireReportParser(null, ENGLISH, new NullConsoleLogger()); - NumberFormat numberFormat = report.getNumberFormat(); + SurefireReportParser parser = new SurefireReportParser(null, new NullConsoleLogger()); - assertEquals( - 70.00f, - numberFormat.parse(report.computePercentage(100, 20, 10, 0)).floatValue(), - 0); + assertEquals(0.7f, (float) parser.computePercentage(100, 20, 10, 0)); } public void testGetFailureDetails() { @@ -178,9 +169,9 @@ public void testGetFailureDetails() { suites.add(tSuite2); - SurefireReportParser report = new SurefireReportParser(null, ENGLISH, new NullConsoleLogger()); + SurefireReportParser parser = new SurefireReportParser(null, new NullConsoleLogger()); - List failures = report.getFailureDetails(suites); + List failures = parser.getFailureDetails(suites); assertEquals(2, failures.size());