| /******************************************************************************* |
| * Copyright (c) 2009, 2017 Mountainminds GmbH & Co. KG and Contributors |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Marc R. Hoffmann - initial API and implementation |
| * |
| *******************************************************************************/ |
| package org.jacoco.report.check; |
| |
| import java.math.BigDecimal; |
| import java.math.RoundingMode; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| import org.jacoco.core.analysis.ICounter.CounterValue; |
| import org.jacoco.core.analysis.ICoverageNode; |
| import org.jacoco.core.analysis.ICoverageNode.CounterEntity; |
| |
| /** |
| * Descriptor for a limit which is given by a {@link Rule}. |
| */ |
| public class Limit { |
| |
| private static final Map<CounterValue, String> VALUE_NAMES; |
| private static final Map<CounterEntity, String> ENTITY_NAMES; |
| |
| static { |
| final Map<CounterValue, String> values = new HashMap<CounterValue, String>(); |
| values.put(CounterValue.TOTALCOUNT, "total count"); |
| values.put(CounterValue.MISSEDCOUNT, "missed count"); |
| values.put(CounterValue.COVEREDCOUNT, "covered count"); |
| values.put(CounterValue.MISSEDRATIO, "missed ratio"); |
| values.put(CounterValue.COVEREDRATIO, "covered ratio"); |
| VALUE_NAMES = Collections.unmodifiableMap(values); |
| |
| final Map<CounterEntity, String> entities = new HashMap<CounterEntity, String>(); |
| entities.put(CounterEntity.INSTRUCTION, "instructions"); |
| entities.put(CounterEntity.BRANCH, "branches"); |
| entities.put(CounterEntity.COMPLEXITY, "complexity"); |
| entities.put(CounterEntity.LINE, "lines"); |
| entities.put(CounterEntity.METHOD, "methods"); |
| entities.put(CounterEntity.CLASS, "classes"); |
| ENTITY_NAMES = Collections.unmodifiableMap(entities); |
| } |
| |
| private CounterEntity entity; |
| |
| private CounterValue value; |
| |
| private BigDecimal minimum; |
| |
| private BigDecimal maximum; |
| |
| /** |
| * Creates a new instance with the following defaults: |
| * <ul> |
| * <li>counter entity: {@link CounterEntity#INSTRUCTION} |
| * <li>counter value: {@link CounterValue#COVEREDRATIO} |
| * <li>minimum: no limit |
| * <li>maximum: no limit |
| * </ul> |
| */ |
| public Limit() { |
| this.entity = CounterEntity.INSTRUCTION; |
| this.value = CounterValue.COVEREDRATIO; |
| } |
| |
| /** |
| * @return the configured counter entity to check |
| */ |
| public CounterEntity getEntity() { |
| return entity; |
| } |
| |
| /** |
| * Sets the counter entity to check. |
| * |
| * @param entity |
| * counter entity to check |
| * TODO: use CounterEntity directly once Maven 3 is required. |
| */ |
| public void setCounter(final String entity) { |
| this.entity = CounterEntity.valueOf(entity); |
| } |
| |
| /** |
| * @return the configured value to check |
| */ |
| public CounterValue getValue() { |
| return value; |
| } |
| |
| /** |
| * Sets the value to check. |
| * |
| * @param value |
| * value to check |
| * TODO: use CounterValue directly once Maven 3 is required. |
| */ |
| public void setValue(final String value) { |
| this.value = CounterValue.valueOf(value); |
| } |
| |
| /** |
| * @return configured minimum value, or <code>null</code> if no minimum is |
| * given |
| */ |
| public String getMinimum() { |
| return minimum == null ? null : minimum.toPlainString(); |
| } |
| |
| /** |
| * Sets allowed maximum value as decimal string or percent representation. |
| * The given precision is also considered in error messages. Coverage ratios |
| * are given in the range from 0.0 to 1.0. |
| * |
| * @param minimum |
| * allowed minimum or <code>null</code>, if no minimum should be |
| * checked |
| */ |
| public void setMinimum(final String minimum) { |
| this.minimum = parseValue(minimum); |
| } |
| |
| /** |
| * @return configured maximum value, or <code>null</code> if no maximum is |
| * given |
| */ |
| public String getMaximum() { |
| return maximum == null ? null : maximum.toPlainString(); |
| } |
| |
| /** |
| * Sets allowed maximum value as decimal string or percent representation. |
| * The given precision is also considered in error messages. Coverage ratios |
| * are given in the range from 0.0 to 1.0. |
| * |
| * @param maximum |
| * allowed maximum or <code>null</code>, if no maximum should be |
| * checked |
| */ |
| public void setMaximum(final String maximum) { |
| this.maximum = parseValue(maximum); |
| } |
| |
| private static BigDecimal parseValue(final String value) { |
| if (value == null) { |
| return null; |
| } |
| |
| final String trimmedValue = value.trim(); |
| if (trimmedValue.endsWith("%")) { |
| final String percent = trimmedValue.substring(0, trimmedValue.length() - 1); |
| return new BigDecimal(percent).movePointLeft(2); |
| } |
| |
| return new BigDecimal(trimmedValue); |
| } |
| |
| String check(final ICoverageNode node) { |
| final double d = node.getCounter(entity).getValue(value); |
| if (Double.isNaN(d)) { |
| return null; |
| } |
| final BigDecimal bd = BigDecimal.valueOf(d); |
| if (minimum != null && minimum.compareTo(bd) > 0) { |
| return message("minimum", bd, minimum, RoundingMode.FLOOR); |
| } |
| if (maximum != null && maximum.compareTo(bd) < 0) { |
| return message("maximum", bd, maximum, RoundingMode.CEILING); |
| } |
| return null; |
| } |
| |
| private String message(final String minmax, final BigDecimal v, |
| final BigDecimal ref, final RoundingMode mode) { |
| final BigDecimal rounded = v.setScale(ref.scale(), mode); |
| return String.format("%s %s is %s, but expected %s is %s", |
| ENTITY_NAMES.get(entity), VALUE_NAMES.get(value), |
| rounded.toPlainString(), minmax, ref.toPlainString()); |
| } |
| |
| } |