001/*
002 * SonarQube
003 * Copyright (C) 2009-2017 SonarSource SA
004 * mailto:info AT sonarsource DOT com
005 *
006 * This program 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 * This program 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.batch.sensor.coverage.internal;
021
022import com.google.common.collect.Maps;
023import java.util.Collections;
024import java.util.SortedMap;
025import javax.annotation.Nullable;
026import org.sonar.api.batch.fs.InputFile;
027import org.sonar.api.batch.sensor.coverage.CoverageType;
028import org.sonar.api.batch.sensor.coverage.NewCoverage;
029import org.sonar.api.batch.sensor.internal.DefaultStorable;
030import org.sonar.api.batch.sensor.internal.SensorStorage;
031
032import static com.google.common.base.Preconditions.checkNotNull;
033import static com.google.common.base.Preconditions.checkState;
034
035public class DefaultCoverage extends DefaultStorable implements NewCoverage {
036
037  private InputFile inputFile;
038  private CoverageType type;
039  private int totalCoveredLines = 0;
040  private int totalConditions = 0;
041  private int totalCoveredConditions = 0;
042  private SortedMap<Integer, Integer> hitsByLine = Maps.newTreeMap();
043  private SortedMap<Integer, Integer> conditionsByLine = Maps.newTreeMap();
044  private SortedMap<Integer, Integer> coveredConditionsByLine = Maps.newTreeMap();
045
046  public DefaultCoverage() {
047    super();
048  }
049
050  public DefaultCoverage(@Nullable SensorStorage storage) {
051    super(storage);
052  }
053
054  @Override
055  public DefaultCoverage onFile(InputFile inputFile) {
056    this.inputFile = inputFile;
057    return this;
058  }
059
060  public InputFile inputFile() {
061    return inputFile;
062  }
063
064  @Override
065  public NewCoverage ofType(CoverageType type) {
066    checkNotNull(type, "type can't be null");
067    this.type = type;
068    return this;
069  }
070
071  public CoverageType type() {
072    return type;
073  }
074
075  @Override
076  public NewCoverage lineHits(int line, int hits) {
077    validateFile();
078    validateLine(line);
079
080    if (!hitsByLine.containsKey(line)) {
081      hitsByLine.put(line, hits);
082      if (hits > 0) {
083        totalCoveredLines += 1;
084      }
085    }
086    return this;
087  }
088
089  private void validateLine(int line) {
090    checkState(line <= inputFile.lines(), "Line %s is out of range in the file %s (lines: %s)", line, inputFile.relativePath(), inputFile.lines());
091    checkState(line > 0, "Line number must be strictly positive: %s", line);
092  }
093
094  private void validateFile() {
095    checkNotNull(inputFile, "Call onFile() first");
096  }
097
098  @Override
099  public NewCoverage conditions(int line, int conditions, int coveredConditions) {
100    validateFile();
101    validateLine(line);
102
103    if (conditions > 0 && !conditionsByLine.containsKey(line)) {
104      totalConditions += conditions;
105      totalCoveredConditions += coveredConditions;
106      conditionsByLine.put(line, conditions);
107      coveredConditionsByLine.put(line, coveredConditions);
108    }
109    return this;
110  }
111
112  public int coveredLines() {
113    return totalCoveredLines;
114  }
115
116  public int linesToCover() {
117    return hitsByLine.size();
118  }
119
120  public int conditions() {
121    return totalConditions;
122  }
123
124  public int coveredConditions() {
125    return totalCoveredConditions;
126  }
127
128  public SortedMap<Integer, Integer> hitsByLine() {
129    return Collections.unmodifiableSortedMap(hitsByLine);
130  }
131
132  public SortedMap<Integer, Integer> conditionsByLine() {
133    return Collections.unmodifiableSortedMap(conditionsByLine);
134  }
135
136  public SortedMap<Integer, Integer> coveredConditionsByLine() {
137    return Collections.unmodifiableSortedMap(coveredConditionsByLine);
138  }
139
140  @Override
141  public void doSave() {
142    validateFile();
143    storage.store(this);
144  }
145
146}