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 java.util.Collections;
023import java.util.SortedMap;
024import java.util.TreeMap;
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.checkState;
033import static java.util.Objects.requireNonNull;
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 = new TreeMap<>();
043  private SortedMap<Integer, Integer> conditionsByLine = new TreeMap<>();
044  private SortedMap<Integer, Integer> coveredConditionsByLine = new TreeMap<>();
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    this.type = requireNonNull(type, "type can't be null");
067    return this;
068  }
069
070  public CoverageType type() {
071    return type;
072  }
073
074  @Override
075  public NewCoverage lineHits(int line, int hits) {
076    validateFile();
077    validateLine(line);
078
079    if (!hitsByLine.containsKey(line)) {
080      hitsByLine.put(line, hits);
081      if (hits > 0) {
082        totalCoveredLines += 1;
083      }
084    }
085    return this;
086  }
087
088  private void validateLine(int line) {
089    checkState(line <= inputFile.lines(), "Line %s is out of range in the file %s (lines: %s)", line, inputFile.relativePath(), inputFile.lines());
090    checkState(line > 0, "Line number must be strictly positive: %s", line);
091  }
092
093  private void validateFile() {
094    requireNonNull(inputFile, "Call onFile() first");
095  }
096
097  @Override
098  public NewCoverage conditions(int line, int conditions, int coveredConditions) {
099    validateFile();
100    validateLine(line);
101
102    if (conditions > 0 && !conditionsByLine.containsKey(line)) {
103      totalConditions += conditions;
104      totalCoveredConditions += coveredConditions;
105      conditionsByLine.put(line, conditions);
106      coveredConditionsByLine.put(line, coveredConditions);
107    }
108    return this;
109  }
110
111  public int coveredLines() {
112    return totalCoveredLines;
113  }
114
115  public int linesToCover() {
116    return hitsByLine.size();
117  }
118
119  public int conditions() {
120    return totalConditions;
121  }
122
123  public int coveredConditions() {
124    return totalCoveredConditions;
125  }
126
127  public SortedMap<Integer, Integer> hitsByLine() {
128    return Collections.unmodifiableSortedMap(hitsByLine);
129  }
130
131  public SortedMap<Integer, Integer> conditionsByLine() {
132    return Collections.unmodifiableSortedMap(conditionsByLine);
133  }
134
135  public SortedMap<Integer, Integer> coveredConditionsByLine() {
136    return Collections.unmodifiableSortedMap(coveredConditionsByLine);
137  }
138
139  @Override
140  public void doSave() {
141    validateFile();
142    storage.store(this);
143  }
144
145}