1 /******************************************************************************* 2 * Copyright (c) 2009, 2018 Mountainminds GmbH & Co. KG and Contributors 3 * All rights reserved. This program and the accompanying materials 4 * are made available under the terms of the Eclipse Public License v1.0 5 * which accompanies this distribution, and is available at 6 * http://www.eclipse.org/legal/epl-v10.html 7 * 8 * Contributors: 9 * Marc R. Hoffmann - initial API and implementation 10 * 11 *******************************************************************************/ 12 package org.jacoco.report.html; 13 14 import java.io.IOException; 15 import java.util.Collection; 16 import java.util.List; 17 import java.util.Locale; 18 19 import org.jacoco.core.analysis.IBundleCoverage; 20 import org.jacoco.core.analysis.ICoverageNode.CounterEntity; 21 import org.jacoco.core.data.ExecutionData; 22 import org.jacoco.core.data.SessionInfo; 23 import org.jacoco.report.ILanguageNames; 24 import org.jacoco.report.IMultiReportOutput; 25 import org.jacoco.report.IReportGroupVisitor; 26 import org.jacoco.report.IReportVisitor; 27 import org.jacoco.report.ISourceFileLocator; 28 import org.jacoco.report.JavaNames; 29 import org.jacoco.report.internal.ReportOutputFolder; 30 import org.jacoco.report.internal.html.HTMLGroupVisitor; 31 import org.jacoco.report.internal.html.IHTMLReportContext; 32 import org.jacoco.report.internal.html.ILinkable; 33 import org.jacoco.report.internal.html.index.ElementIndex; 34 import org.jacoco.report.internal.html.index.IIndexUpdate; 35 import org.jacoco.report.internal.html.page.BundlePage; 36 import org.jacoco.report.internal.html.page.ReportPage; 37 import org.jacoco.report.internal.html.page.SessionsPage; 38 import org.jacoco.report.internal.html.resources.Resources; 39 import org.jacoco.report.internal.html.resources.Styles; 40 import org.jacoco.report.internal.html.table.BarColumn; 41 import org.jacoco.report.internal.html.table.CounterColumn; 42 import org.jacoco.report.internal.html.table.LabelColumn; 43 import org.jacoco.report.internal.html.table.PercentageColumn; 44 import org.jacoco.report.internal.html.table.Table; 45 46 /** 47 * Formatter for coverage reports in multiple HTML pages. 48 */ 49 public class HTMLFormatter implements IHTMLReportContext { 50 51 private ILanguageNames languageNames = new JavaNames(); 52 53 private Locale locale = Locale.getDefault(); 54 55 private String footerText = ""; 56 57 private String outputEncoding = "UTF-8"; 58 59 private Resources resources; 60 61 private ElementIndex index; 62 63 private SessionsPage sessionsPage; 64 65 private Table table; 66 67 /** 68 * New instance with default settings. 69 */ HTMLFormatter()70 public HTMLFormatter() { 71 } 72 73 /** 74 * Sets the implementation for language name display. Java language names 75 * are defined by default. 76 * 77 * @param languageNames 78 * converter for language specific names 79 */ setLanguageNames(final ILanguageNames languageNames)80 public void setLanguageNames(final ILanguageNames languageNames) { 81 this.languageNames = languageNames; 82 } 83 84 /** 85 * Sets the locale used for report rendering. The current default locale is 86 * used by default. 87 * 88 * @param locale 89 * locale used for report rendering 90 */ setLocale(final Locale locale)91 public void setLocale(final Locale locale) { 92 this.locale = locale; 93 } 94 95 /** 96 * Sets the optional text that should be included in every footer page. 97 * 98 * @param footerText 99 * footer text 100 */ setFooterText(final String footerText)101 public void setFooterText(final String footerText) { 102 this.footerText = footerText; 103 } 104 105 /** 106 * Sets the encoding used for generated HTML pages. Default is UTF-8. 107 * 108 * @param outputEncoding 109 * HTML output encoding 110 */ setOutputEncoding(final String outputEncoding)111 public void setOutputEncoding(final String outputEncoding) { 112 this.outputEncoding = outputEncoding; 113 } 114 115 // === IHTMLReportContext === 116 getLanguageNames()117 public ILanguageNames getLanguageNames() { 118 return languageNames; 119 } 120 getResources()121 public Resources getResources() { 122 return resources; 123 } 124 getTable()125 public Table getTable() { 126 if (table == null) { 127 table = createTable(); 128 } 129 return table; 130 } 131 createTable()132 private Table createTable() { 133 final Table t = new Table(); 134 t.add("Element", null, new LabelColumn(), false); 135 t.add("Missed Instructions", Styles.BAR, new BarColumn(CounterEntity.INSTRUCTION, 136 locale), true); 137 t.add("Cov.", Styles.CTR2, 138 new PercentageColumn(CounterEntity.INSTRUCTION, locale), false); 139 t.add("Missed Branches", Styles.BAR, new BarColumn(CounterEntity.BRANCH, locale), 140 false); 141 t.add("Cov.", Styles.CTR2, new PercentageColumn(CounterEntity.BRANCH, locale), 142 false); 143 addMissedTotalColumns(t, "Cxty", CounterEntity.COMPLEXITY); 144 addMissedTotalColumns(t, "Lines", CounterEntity.LINE); 145 addMissedTotalColumns(t, "Methods", CounterEntity.METHOD); 146 addMissedTotalColumns(t, "Classes", CounterEntity.CLASS); 147 return t; 148 } 149 addMissedTotalColumns(final Table table, final String label, final CounterEntity entity)150 private void addMissedTotalColumns(final Table table, final String label, 151 final CounterEntity entity) { 152 table.add("Missed", Styles.CTR1, 153 CounterColumn.newMissed(entity, locale), false); 154 table.add(label, Styles.CTR2, CounterColumn.newTotal(entity, locale), 155 false); 156 } 157 getFooterText()158 public String getFooterText() { 159 return footerText; 160 } 161 getSessionsPage()162 public ILinkable getSessionsPage() { 163 return sessionsPage; 164 } 165 getOutputEncoding()166 public String getOutputEncoding() { 167 return outputEncoding; 168 } 169 getIndexUpdate()170 public IIndexUpdate getIndexUpdate() { 171 return index; 172 } 173 getLocale()174 public Locale getLocale() { 175 return locale; 176 } 177 178 /** 179 * Creates a new visitor to write a report to the given output. 180 * 181 * @param output 182 * output to write the report to 183 * @return visitor to emit the report data to 184 * @throws IOException 185 * in case of problems with the output stream 186 */ createVisitor(final IMultiReportOutput output)187 public IReportVisitor createVisitor(final IMultiReportOutput output) 188 throws IOException { 189 final ReportOutputFolder root = new ReportOutputFolder(output); 190 resources = new Resources(root); 191 resources.copyResources(); 192 index = new ElementIndex(root); 193 return new IReportVisitor() { 194 195 private List<SessionInfo> sessionInfos; 196 private Collection<ExecutionData> executionData; 197 198 private HTMLGroupVisitor groupHandler; 199 200 public void visitInfo(final List<SessionInfo> sessionInfos, 201 final Collection<ExecutionData> executionData) 202 throws IOException { 203 this.sessionInfos = sessionInfos; 204 this.executionData = executionData; 205 } 206 207 public void visitBundle(final IBundleCoverage bundle, 208 final ISourceFileLocator locator) throws IOException { 209 final BundlePage page = new BundlePage(bundle, null, locator, 210 root, HTMLFormatter.this); 211 createSessionsPage(page); 212 page.render(); 213 } 214 215 public IReportGroupVisitor visitGroup(final String name) 216 throws IOException { 217 groupHandler = new HTMLGroupVisitor(null, root, 218 HTMLFormatter.this, name); 219 createSessionsPage(groupHandler.getPage()); 220 return groupHandler; 221 222 } 223 224 private void createSessionsPage(final ReportPage rootpage) { 225 sessionsPage = new SessionsPage(sessionInfos, executionData, 226 index, rootpage, root, HTMLFormatter.this); 227 } 228 229 public void visitEnd() throws IOException { 230 if (groupHandler != null) { 231 groupHandler.visitEnd(); 232 } 233 sessionsPage.render(); 234 output.close(); 235 } 236 }; 237 } 238 } 239