001/*
002 * SonarQube, open source software quality management tool.
003 * Copyright (C) 2008-2014 SonarSource
004 * mailto:contact AT sonarsource DOT com
005 *
006 * SonarQube is free software; you can redistribute it and/or
007 * modify it under the terms of the GNU Lesser General Public
008 * License as published by the Free Software Foundation; either
009 * version 3 of the License, or (at your option) any later version.
010 *
011 * SonarQube is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014 * Lesser General Public License for more details.
015 *
016 * You should have received a copy of the GNU Lesser General Public License
017 * along with this program; if not, write to the Free Software Foundation,
018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
019 */
020package org.sonar.api.measures;
021
022import com.google.common.collect.Lists;
023import com.google.common.collect.Maps;
024import org.sonar.api.utils.KeyValueFormat;
025
026import java.util.Arrays;
027import java.util.Collection;
028import java.util.Collections;
029import java.util.List;
030import java.util.SortedMap;
031
032/**
033 * @since 2.7
034 */
035public final class CoverageMeasuresBuilder {
036
037  /**
038   * Metrics of generated measures
039   */
040  public static final List<Metric> METRICS = Arrays.<Metric>asList(
041    CoreMetrics.LINES_TO_COVER, CoreMetrics.UNCOVERED_LINES, CoreMetrics.COVERAGE_LINE_HITS_DATA,
042    CoreMetrics.CONDITIONS_TO_COVER, CoreMetrics.UNCOVERED_CONDITIONS, CoreMetrics.CONDITIONS_BY_LINE,
043    CoreMetrics.COVERED_CONDITIONS_BY_LINE);
044
045  private int totalCoveredLines = 0, totalConditions = 0, totalCoveredConditions = 0;
046  private SortedMap<Integer, Integer> hitsByLine = Maps.newTreeMap();
047  private SortedMap<Integer, Integer> conditionsByLine = Maps.newTreeMap();
048  private SortedMap<Integer, Integer> coveredConditionsByLine = Maps.newTreeMap();
049
050  private CoverageMeasuresBuilder() {
051    // use the factory
052  }
053
054  public CoverageMeasuresBuilder reset() {
055    totalCoveredLines = 0;
056    totalConditions = 0;
057    totalCoveredConditions = 0;
058    hitsByLine.clear();
059    conditionsByLine.clear();
060    coveredConditionsByLine.clear();
061    return this;
062  }
063
064  public CoverageMeasuresBuilder setHits(int lineId, int hits) {
065    if (!hitsByLine.containsKey(lineId)) {
066      hitsByLine.put(lineId, hits);
067      if (hits > 0) {
068        totalCoveredLines += 1;
069      }
070    }
071    return this;
072  }
073
074  public CoverageMeasuresBuilder setConditions(int lineId, int conditions, int coveredConditions) {
075    if (conditions > 0 && !conditionsByLine.containsKey(lineId)) {
076      totalConditions += conditions;
077      totalCoveredConditions += coveredConditions;
078      conditionsByLine.put(lineId, conditions);
079      coveredConditionsByLine.put(lineId, coveredConditions);
080    }
081    return this;
082  }
083
084  public int getCoveredLines() {
085    return totalCoveredLines;
086  }
087
088  public int getLinesToCover() {
089    return hitsByLine.size();
090  }
091
092  public int getConditions() {
093    return totalConditions;
094  }
095
096  public int getCoveredConditions() {
097    return totalCoveredConditions;
098  }
099
100  public SortedMap<Integer, Integer> getHitsByLine() {
101    return Collections.unmodifiableSortedMap(hitsByLine);
102  }
103
104  public SortedMap<Integer, Integer> getConditionsByLine() {
105    return Collections.unmodifiableSortedMap(conditionsByLine);
106  }
107
108  public SortedMap<Integer, Integer> getCoveredConditionsByLine() {
109    return Collections.unmodifiableSortedMap(coveredConditionsByLine);
110  }
111
112  public Collection<Measure> createMeasures() {
113    Collection<Measure> measures = Lists.newArrayList();
114    if (getLinesToCover() > 0) {
115      measures.add(new Measure(CoreMetrics.LINES_TO_COVER, (double) getLinesToCover()));
116      measures.add(new Measure(CoreMetrics.UNCOVERED_LINES, (double) (getLinesToCover() - getCoveredLines())));
117      measures.add(new Measure(CoreMetrics.COVERAGE_LINE_HITS_DATA).setData(KeyValueFormat.format(hitsByLine)).setPersistenceMode(PersistenceMode.DATABASE));
118    }
119    if (getConditions() > 0) {
120      measures.add(new Measure(CoreMetrics.CONDITIONS_TO_COVER, (double) getConditions()));
121      measures.add(new Measure(CoreMetrics.UNCOVERED_CONDITIONS, (double) (getConditions() - getCoveredConditions())));
122      measures.add(createConditionsByLine());
123      measures.add(createCoveredConditionsByLine());
124    }
125    return measures;
126  }
127
128  private Measure createCoveredConditionsByLine() {
129    return new Measure(CoreMetrics.COVERED_CONDITIONS_BY_LINE)
130      .setData(KeyValueFormat.format(coveredConditionsByLine))
131      .setPersistenceMode(PersistenceMode.DATABASE);
132  }
133
134  private Measure createConditionsByLine() {
135    return new Measure(CoreMetrics.CONDITIONS_BY_LINE)
136      .setData(KeyValueFormat.format(conditionsByLine))
137      .setPersistenceMode(PersistenceMode.DATABASE);
138  }
139
140  public static CoverageMeasuresBuilder create() {
141    return new CoverageMeasuresBuilder();
142  }
143
144}