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 *******************************************************************************/ 12package org.jacoco.report.internal.html.table; 13 14import java.io.IOException; 15import java.math.BigDecimal; 16import java.math.RoundingMode; 17import java.text.NumberFormat; 18import java.util.Comparator; 19import java.util.List; 20import java.util.Locale; 21 22import org.jacoco.core.analysis.CounterComparator; 23import org.jacoco.core.analysis.ICounter; 24import org.jacoco.core.analysis.ICoverageNode; 25import org.jacoco.core.analysis.ICoverageNode.CounterEntity; 26import org.jacoco.report.internal.ReportOutputFolder; 27import org.jacoco.report.internal.html.HTMLElement; 28import org.jacoco.report.internal.html.resources.Resources; 29 30/** 31 * Column that prints the coverage percentage for each item and the total 32 * percentage in the footer. The implementation is stateless, instances might be 33 * used in parallel. 34 */ 35public class PercentageColumn implements IColumnRenderer { 36 37 private final CounterEntity entity; 38 39 private final NumberFormat percentageFormat; 40 41 private final Comparator<ITableItem> comparator; 42 43 /** 44 * Creates a new column that is based on the {@link ICounter} for the given 45 * entity. 46 * 47 * @param entity 48 * counter entity for this column 49 * @param locale 50 * locale for rendering numbers 51 */ 52 public PercentageColumn(final CounterEntity entity, final Locale locale) { 53 this.entity = entity; 54 this.percentageFormat = NumberFormat.getPercentInstance(locale); 55 comparator = new TableItemComparator( 56 CounterComparator.MISSEDRATIO.on(entity)); 57 } 58 59 public boolean init(final List<? extends ITableItem> items, 60 final ICoverageNode total) { 61 return true; 62 } 63 64 public void footer(final HTMLElement td, final ICoverageNode total, 65 final Resources resources, final ReportOutputFolder base) 66 throws IOException { 67 cell(td, total); 68 } 69 70 public void item(final HTMLElement td, final ITableItem item, 71 final Resources resources, final ReportOutputFolder base) 72 throws IOException { 73 cell(td, item.getNode()); 74 } 75 76 private void cell(final HTMLElement td, final ICoverageNode node) 77 throws IOException { 78 final ICounter counter = node.getCounter(entity); 79 final int total = counter.getTotalCount(); 80 if (total == 0) { 81 td.text("n/a"); 82 } else { 83 td.text(format(counter.getCoveredRatio())); 84 } 85 } 86 87 /** 88 * Ratio 199/(1+199)=0.995 must be displayed as "99%", not as "100%". 89 * Unfortunately {@link NumberFormat} uses {@link RoundingMode#HALF_EVEN} by 90 * default and ability to change available only starting from JDK 6, so 91 * perform rounding using {@link RoundingMode#FLOOR} before formatting. 92 */ 93 private String format(double ratio) { 94 return percentageFormat.format( 95 BigDecimal.valueOf(ratio).setScale(2, RoundingMode.FLOOR)); 96 } 97 98 public Comparator<ITableItem> getComparator() { 99 return comparator; 100 } 101 102} 103