/*
* SonarQube
* Copyright (C) 2009-2017 SonarSource SA
* mailto:info AT sonarsource DOT com
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
package org.sonar.scanner.report;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import java.util.LinkedHashMap;
import java.util.Map;
import javax.annotation.Nonnull;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.scanner.protocol.output.ScannerReport.LineCoverage;
import org.sonar.scanner.protocol.output.ScannerReport.LineCoverage.Builder;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.scan.filesystem.InputComponentStore;
import org.sonar.scanner.scan.measure.MeasureCache;
public class CoveragePublisher implements ReportPublisherStep {
private final InputComponentStore componentStore;
private final MeasureCache measureCache;
public CoveragePublisher(InputComponentStore componentStore, MeasureCache measureCache) {
this.componentStore = componentStore;
this.measureCache = measureCache;
}
@Override
public void publish(ScannerReportWriter writer) {
for (final DefaultInputFile inputFile : componentStore.allFilesToPublish()) {
Map<Integer, LineCoverage.Builder> coveragePerLine = new LinkedHashMap<>();
int lineCount = inputFile.lines();
applyLineMeasure(inputFile.key(), lineCount, CoreMetrics.COVERAGE_LINE_HITS_DATA_KEY, coveragePerLine,
(value, builder) -> builder.setHits(Integer.parseInt(value) > 0));
applyLineMeasure(inputFile.key(), lineCount, CoreMetrics.CONDITIONS_BY_LINE_KEY, coveragePerLine,
(value, builder) -> builder.setConditions(Integer.parseInt(value)));
applyLineMeasure(inputFile.key(), lineCount, CoreMetrics.COVERED_CONDITIONS_BY_LINE_KEY, coveragePerLine,
(value, builder) -> builder.setCoveredConditions(Integer.parseInt(value)));
writer.writeComponentCoverage(inputFile.batchId(), Iterables.transform(coveragePerLine.values(), BuildCoverage.INSTANCE));
}
}
void applyLineMeasure(String inputFileKey, int lineCount, String metricKey, Map<Integer, LineCoverage.Builder> coveragePerLine, MeasureOperation op) {
DefaultMeasure<?> measure = measureCache.byMetric(inputFileKey, metricKey);
if (measure != null) {
Map<Integer, String> lineMeasures = KeyValueFormat.parseIntString((String) measure.value());
for (Map.Entry<Integer, String> lineMeasure : lineMeasures.entrySet()) {
int lineIdx = lineMeasure.getKey();
if (lineIdx <= lineCount) {
String value = lineMeasure.getValue();
if (StringUtils.isNotEmpty(value)) {
LineCoverage.Builder coverageBuilder = coveragePerLine.get(lineIdx);
if (coverageBuilder == null) {
coverageBuilder = LineCoverage.newBuilder();
coverageBuilder.setLine(lineIdx);
coveragePerLine.put(lineIdx, coverageBuilder);
}
op.apply(value, coverageBuilder);
}
}
}
}
}
interface MeasureOperation {
void apply(String value, LineCoverage.Builder builder);
}
private enum BuildCoverage implements Function<LineCoverage.Builder, LineCoverage> {
INSTANCE;
@Override
public LineCoverage apply(@Nonnull Builder input) {
return input.build();
}
}
}