Skip to content

Commit

Permalink
SONAR-8743 Handle only leak period when computing new coverage measures
Browse files Browse the repository at this point in the history
  • Loading branch information
julienlancelot committed Feb 9, 2017
1 parent 0cfc413 commit 0876f2b
Show file tree
Hide file tree
Showing 10 changed files with 204 additions and 358 deletions.
Expand Up @@ -20,16 +20,12 @@
package org.sonar.server.computation.task.projectanalysis.formula;

import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.server.computation.task.projectanalysis.component.CrawlerDepthLimit;
import org.sonar.server.computation.task.projectanalysis.formula.counter.DoubleVariationValue;
import org.sonar.server.computation.task.projectanalysis.measure.Measure;
import org.sonar.server.computation.task.projectanalysis.measure.MeasureVariations;
import org.sonar.server.computation.task.projectanalysis.period.Period;

import static com.google.common.collect.FluentIterable.from;
import static java.util.Objects.requireNonNull;
import static org.sonar.server.computation.task.projectanalysis.measure.Measure.newMeasureBuilder;

Expand All @@ -39,46 +35,29 @@
*/
public class VariationSumFormula implements Formula<VariationSumFormula.VariationSumCounter> {
private final String metricKey;
private final Predicate<Period> supportedPeriods;
@CheckForNull
private final Double defaultInputValue;

public VariationSumFormula(String metricKey, Predicate<Period> supportedPeriods) {
this(metricKey, supportedPeriods, null);
public VariationSumFormula(String metricKey) {
this(metricKey, null);
}

public VariationSumFormula(String metricKey, Predicate<Period> supportedPeriods, @Nullable Double defaultInputValue) {
public VariationSumFormula(String metricKey, @Nullable Double defaultInputValue) {
this.metricKey = requireNonNull(metricKey, "Metric key cannot be null");
this.supportedPeriods = requireNonNull(supportedPeriods, "Period predicate cannot be null");
this.defaultInputValue = defaultInputValue;
}

@Override
public VariationSumCounter createNewCounter() {
return new VariationSumCounter(metricKey, supportedPeriods, defaultInputValue);
return new VariationSumCounter(metricKey, defaultInputValue);
}

@Override
public Optional<Measure> createMeasure(VariationSumCounter counter, CreateMeasureContext context) {
if (!CrawlerDepthLimit.LEAVES.isDeeperThan(context.getComponent().getType())) {
if (!CrawlerDepthLimit.LEAVES.isDeeperThan(context.getComponent().getType()) || !counter.doubleValue.isSet()) {
return Optional.absent();
}
MeasureVariations.Builder variations = createAndPopulateBuilder(counter.array, context);
if (variations.isEmpty()) {
return Optional.absent();
}
return Optional.of(newMeasureBuilder().setVariations(variations.build()).createNoValue());
}

private MeasureVariations.Builder createAndPopulateBuilder(DoubleVariationValue.Array array, CreateMeasureContext context) {
MeasureVariations.Builder builder = MeasureVariations.newMeasureVariationsBuilder();
for (Period period : from(context.getPeriods()).filter(supportedPeriods)) {
DoubleVariationValue elements = array.get(period);
if (elements.isSet()) {
builder.setVariation(period, elements.getValue());
}
}
return builder;
return Optional.of(newMeasureBuilder().setVariation(counter.doubleValue.getValue()).createNoValue());
}

@Override
Expand All @@ -89,48 +68,39 @@ public String[] getOutputMetricKeys() {
public static final class VariationSumCounter implements Counter<VariationSumCounter> {
@CheckForNull
private final Double defaultInputValue;
private final DoubleVariationValue.Array array = DoubleVariationValue.newArray();
private final DoubleVariationValue doubleValue = new DoubleVariationValue();
private final String metricKey;
private final Predicate<Period> supportedPeriods;

private VariationSumCounter(String metricKey, Predicate<Period> supportedPeriods, @Nullable Double defaultInputValue) {
private VariationSumCounter(String metricKey, @Nullable Double defaultInputValue) {
this.metricKey = metricKey;
this.supportedPeriods = supportedPeriods;
this.defaultInputValue = defaultInputValue;
}

@Override
public void aggregate(VariationSumCounter counter) {
array.incrementAll(counter.array);
doubleValue.increment(counter.doubleValue);
}

@Override
public void initialize(CounterInitializationContext context) {
Optional<Measure> measure = context.getMeasure(metricKey);
if (!measure.isPresent() || !measure.get().hasVariations()) {
initializeWithDefaultInputValue(context);
if (!measure.isPresent() || !measure.get().hasVariation()) {
initializeWithDefaultInputValue();
return;
}
MeasureVariations variations = measure.get().getVariations();
for (Period period : from(context.getPeriods()).filter(supportedPeriods)) {
if (variations.hasVariation(period.getIndex())) {
double variation = variations.getVariation(period.getIndex());
if (variation > 0) {
array.increment(period, variation);
} else if (defaultInputValue != null) {
array.increment(period, defaultInputValue);
}
}
double variation = measure.get().getVariation();
if (variation > 0) {
doubleValue.increment(variation);
} else if (defaultInputValue != null) {
doubleValue.increment(defaultInputValue);
}
}

private void initializeWithDefaultInputValue(CounterInitializationContext context) {
private void initializeWithDefaultInputValue() {
if (defaultInputValue == null) {
return;
}
for (Period period : from(context.getPeriods()).filter(supportedPeriods)) {
array.increment(period, defaultInputValue);
}
doubleValue.increment(defaultInputValue);
}
}
}
Expand Up @@ -20,20 +20,13 @@
package org.sonar.server.computation.task.projectanalysis.formula.coverage;

import com.google.common.base.Optional;
import org.sonar.server.computation.task.projectanalysis.component.Component;
import org.sonar.server.computation.task.projectanalysis.formula.CounterInitializationContext;
import org.sonar.server.computation.task.projectanalysis.formula.CreateMeasureContext;
import org.sonar.server.computation.task.projectanalysis.measure.Measure;
import org.sonar.server.computation.task.projectanalysis.measure.MeasureVariations;
import org.sonar.server.computation.task.projectanalysis.period.Period;

import static com.google.common.collect.FluentIterable.from;
import static org.sonar.server.computation.task.projectanalysis.measure.Measure.newMeasureBuilder;
import static org.sonar.server.computation.task.projectanalysis.period.PeriodPredicates.viewsRestrictedPeriods;

public final class CoverageUtils {
private static final Measure DEFAULT_MEASURE = newMeasureBuilder().create(0L);
private static final MeasureVariations DEFAULT_VARIATIONS = new MeasureVariations(0d, 0d, 0d, 0d, 0d);

private CoverageUtils() {
// prevents instantiation
Expand All @@ -54,42 +47,12 @@ static long getLongMeasureValue(CounterInitializationContext counterContext, Str
return measure.getLongValue();
}

static MeasureVariations getMeasureVariations(CounterInitializationContext counterContext, String metricKey) {
static double getMeasureVariations(CounterInitializationContext counterContext, String metricKey) {
Optional<Measure> measure = counterContext.getMeasure(metricKey);
if (!measure.isPresent() || !measure.get().hasVariations()) {
return DEFAULT_VARIATIONS;
if (!measure.isPresent() || !measure.get().hasVariation()) {
return 0d;
}
return measure.get().getVariations();
}

static long getLongVariation(MeasureVariations variations, Period period) {
if (variations.hasVariation(period.getIndex())) {
return (long) variations.getVariation(period.getIndex());
}
return 0L;
}

/**
* Since Periods 4 and 5 can be customized per project and/or per view/subview, aggregating values on this period
* will only generate garbage data which will make no sense. These Periods should be ignored when processing views/subviews.
*/
static Iterable<Period> supportedPeriods(CreateMeasureContext context) {
return supportedPeriods(context.getComponent().getType(), context.getPeriods());
}

/**
* Since Periods 4 and 5 can be customized per project and/or per view/subview, aggregating values on this period
* will only generate garbage data which will make no sense. These Periods should be ignored when processing views/subviews.
*/
public static Iterable<Period> supportedPeriods(CounterInitializationContext context) {
return supportedPeriods(context.getLeaf().getType(), context.getPeriods());
}

private static Iterable<Period> supportedPeriods(Component.Type type, Iterable<Period> periods) {
if (type.isReportType()) {
return periods;
}
return from(periods).filter(viewsRestrictedPeriods());
return measure.get().getVariation();
}

}
Expand Up @@ -24,11 +24,8 @@
import org.sonar.server.computation.task.projectanalysis.formula.Formula;
import org.sonar.server.computation.task.projectanalysis.formula.counter.LongVariationValue;
import org.sonar.server.computation.task.projectanalysis.measure.Measure;
import org.sonar.server.computation.task.projectanalysis.measure.MeasureVariations;
import org.sonar.server.computation.task.projectanalysis.period.Period;

import static org.sonar.server.computation.task.projectanalysis.formula.coverage.CoverageUtils.calculateCoverage;
import static org.sonar.server.computation.task.projectanalysis.formula.coverage.CoverageUtils.supportedPeriods;
import static org.sonar.server.computation.task.projectanalysis.measure.Measure.newMeasureBuilder;

/**
Expand All @@ -39,23 +36,13 @@ public abstract class CoverageVariationFormula<T extends ElementsAndCoveredEleme

@Override
public Optional<Measure> createMeasure(T counter, CreateMeasureContext context) {
MeasureVariations.Builder builder = createAndPopulateBuilder(counter, context);
if (!builder.isEmpty()) {
return Optional.of(newMeasureBuilder().setVariations(builder.build()).createNoValue());
LongVariationValue elements = counter.elements;
if (elements.isSet() && elements.getValue() > 0d) {
LongVariationValue coveredElements = counter.coveredElements;
double variation = calculateCoverage(coveredElements.getValue(), elements.getValue());
return Optional.of(newMeasureBuilder().setVariation(variation).createNoValue());
}

return Optional.absent();
}

private MeasureVariations.Builder createAndPopulateBuilder(T counter, CreateMeasureContext context) {
MeasureVariations.Builder builder = MeasureVariations.newMeasureVariationsBuilder();
for (Period period : supportedPeriods(context)) {
LongVariationValue elements = counter.elements.get(period);
if (elements.isSet() && elements.getValue() > 0d) {
LongVariationValue coveredElements = counter.coveredElements.get(period);
builder.setVariation(period, calculateCoverage(coveredElements.getValue(), elements.getValue()));
}
}
return builder;
}
}
Expand Up @@ -28,13 +28,13 @@
* A counter used to create measure variations which are based on a count of elements and coveredElements.
*/
public abstract class ElementsAndCoveredElementsVariationCounter implements Counter<ElementsAndCoveredElementsVariationCounter> {
protected final LongVariationValue.Array elements = LongVariationValue.newArray();
protected final LongVariationValue.Array coveredElements = LongVariationValue.newArray();
protected final LongVariationValue elements = new LongVariationValue();
protected final LongVariationValue coveredElements = new LongVariationValue();

@Override
public void aggregate(ElementsAndCoveredElementsVariationCounter counter) {
elements.incrementAll(counter.elements);
coveredElements.incrementAll(counter.coveredElements);
elements.increment(counter.elements);
coveredElements.increment(counter.coveredElements);
}

@Override
Expand Down
Expand Up @@ -22,11 +22,6 @@
import com.google.common.base.Optional;
import org.sonar.server.computation.task.projectanalysis.formula.CounterInitializationContext;
import org.sonar.server.computation.task.projectanalysis.measure.Measure;
import org.sonar.server.computation.task.projectanalysis.measure.MeasureVariations;
import org.sonar.server.computation.task.projectanalysis.period.Period;

import static org.sonar.server.computation.task.projectanalysis.formula.coverage.CoverageUtils.getLongVariation;
import static org.sonar.server.computation.task.projectanalysis.formula.coverage.CoverageUtils.supportedPeriods;

public final class LinesAndConditionsWithUncoveredVariationCounter extends ElementsAndCoveredElementsVariationCounter {
private final LinesAndConditionsWithUncoveredMetricKeys metricKeys;
Expand All @@ -38,23 +33,16 @@ public LinesAndConditionsWithUncoveredVariationCounter(LinesAndConditionsWithUnc
@Override
public void initializeForSupportedLeaf(CounterInitializationContext counterContext) {
Optional<Measure> newLinesMeasure = counterContext.getMeasure(metricKeys.getLines());
if (!newLinesMeasure.isPresent() || !newLinesMeasure.get().hasVariations()) {
if (!newLinesMeasure.isPresent() || !newLinesMeasure.get().hasVariation()) {
return;
}
double newLines = newLinesMeasure.get().getVariation();
long newConditions = (long) CoverageUtils.getMeasureVariations(counterContext, metricKeys.getConditions());
long uncoveredLines = (long) CoverageUtils.getMeasureVariations(counterContext, metricKeys.getUncoveredLines());
long uncoveredConditions = (long) CoverageUtils.getMeasureVariations(counterContext, metricKeys.getUncoveredConditions());

MeasureVariations newLines = newLinesMeasure.get().getVariations();
MeasureVariations newConditions = CoverageUtils.getMeasureVariations(counterContext, metricKeys.getConditions());
MeasureVariations uncoveredLines = CoverageUtils.getMeasureVariations(counterContext, metricKeys.getUncoveredLines());
MeasureVariations uncoveredConditions = CoverageUtils.getMeasureVariations(counterContext, metricKeys.getUncoveredConditions());
for (Period period : supportedPeriods(counterContext)) {
if (!newLines.hasVariation(period.getIndex())) {
continue;
}
long elements = (long) newLines.getVariation(period.getIndex()) + getLongVariation(newConditions, period);
this.elements.increment(period, elements);
coveredElements.increment(
period,
elements - getLongVariation(uncoveredConditions, period) - getLongVariation(uncoveredLines, period));
}
long elements = (long) newLines + newConditions;
this.elements.increment(elements);
coveredElements.increment(elements - uncoveredConditions - uncoveredLines);
}
}
Expand Up @@ -20,13 +20,9 @@
package org.sonar.server.computation.task.projectanalysis.formula.coverage;

import org.sonar.server.computation.task.projectanalysis.formula.CounterInitializationContext;
import org.sonar.server.computation.task.projectanalysis.measure.MeasureVariations;
import org.sonar.server.computation.task.projectanalysis.period.Period;

import static java.util.Objects.requireNonNull;
import static org.sonar.server.computation.task.projectanalysis.formula.coverage.CoverageUtils.getLongVariation;
import static org.sonar.server.computation.task.projectanalysis.formula.coverage.CoverageUtils.getMeasureVariations;
import static org.sonar.server.computation.task.projectanalysis.formula.coverage.CoverageUtils.supportedPeriods;

public final class SingleWithUncoveredVariationCounter extends ElementsAndCoveredElementsVariationCounter {
private final SingleWithUncoveredMetricKeys metricKeys;
Expand All @@ -37,12 +33,9 @@ public SingleWithUncoveredVariationCounter(SingleWithUncoveredMetricKeys metricK

@Override
protected void initializeForSupportedLeaf(CounterInitializationContext counterContext) {
MeasureVariations newConditions = getMeasureVariations(counterContext, metricKeys.getCovered());
MeasureVariations uncoveredConditions = getMeasureVariations(counterContext, metricKeys.getUncovered());
for (Period period : supportedPeriods(counterContext)) {
long elements = getLongVariation(newConditions, period);
this.elements.increment(period, elements);
coveredElements.increment(period, elements - getLongVariation(uncoveredConditions, period));
}
long newConditions = (long) getMeasureVariations(counterContext, metricKeys.getCovered());
long uncoveredConditions = (long) getMeasureVariations(counterContext, metricKeys.getUncovered());
this.elements.increment(newConditions);
coveredElements.increment(newConditions - uncoveredConditions);
}
}

0 comments on commit 0876f2b

Please sign in to comment.