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; package org.sonar.server.computation.task.projectanalysis.formula;


import com.google.common.base.Optional; import com.google.common.base.Optional;
import com.google.common.base.Predicate;
import javax.annotation.CheckForNull; import javax.annotation.CheckForNull;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import org.sonar.server.computation.task.projectanalysis.component.CrawlerDepthLimit; 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.formula.counter.DoubleVariationValue;
import org.sonar.server.computation.task.projectanalysis.measure.Measure; 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 java.util.Objects.requireNonNull;
import static org.sonar.server.computation.task.projectanalysis.measure.Measure.newMeasureBuilder; import static org.sonar.server.computation.task.projectanalysis.measure.Measure.newMeasureBuilder;


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


public VariationSumFormula(String metricKey, Predicate<Period> supportedPeriods) { public VariationSumFormula(String metricKey) {
this(metricKey, supportedPeriods, null); 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.metricKey = requireNonNull(metricKey, "Metric key cannot be null");
this.supportedPeriods = requireNonNull(supportedPeriods, "Period predicate cannot be null");
this.defaultInputValue = defaultInputValue; this.defaultInputValue = defaultInputValue;
} }


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


@Override @Override
public Optional<Measure> createMeasure(VariationSumCounter counter, CreateMeasureContext context) { 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(); return Optional.absent();
} }
MeasureVariations.Builder variations = createAndPopulateBuilder(counter.array, context); return Optional.of(newMeasureBuilder().setVariation(counter.doubleValue.getValue()).createNoValue());
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;
} }


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


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


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


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


import com.google.common.base.Optional; 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.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.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.measure.Measure.newMeasureBuilder;
import static org.sonar.server.computation.task.projectanalysis.period.PeriodPredicates.viewsRestrictedPeriods;


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


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


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

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());
} }


} }
Expand Up @@ -24,11 +24,8 @@
import org.sonar.server.computation.task.projectanalysis.formula.Formula; 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.formula.counter.LongVariationValue;
import org.sonar.server.computation.task.projectanalysis.measure.Measure; 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.calculateCoverage;
import static org.sonar.server.computation.task.projectanalysis.formula.coverage.CoverageUtils.supportedPeriods;
import static org.sonar.server.computation.task.projectanalysis.measure.Measure.newMeasureBuilder; 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 @Override
public Optional<Measure> createMeasure(T counter, CreateMeasureContext context) { public Optional<Measure> createMeasure(T counter, CreateMeasureContext context) {
MeasureVariations.Builder builder = createAndPopulateBuilder(counter, context); LongVariationValue elements = counter.elements;
if (!builder.isEmpty()) { if (elements.isSet() && elements.getValue() > 0d) {
return Optional.of(newMeasureBuilder().setVariations(builder.build()).createNoValue()); LongVariationValue coveredElements = counter.coveredElements;
double variation = calculateCoverage(coveredElements.getValue(), elements.getValue());
return Optional.of(newMeasureBuilder().setVariation(variation).createNoValue());
} }

return Optional.absent(); 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. * A counter used to create measure variations which are based on a count of elements and coveredElements.
*/ */
public abstract class ElementsAndCoveredElementsVariationCounter implements Counter<ElementsAndCoveredElementsVariationCounter> { public abstract class ElementsAndCoveredElementsVariationCounter implements Counter<ElementsAndCoveredElementsVariationCounter> {
protected final LongVariationValue.Array elements = LongVariationValue.newArray(); protected final LongVariationValue elements = new LongVariationValue();
protected final LongVariationValue.Array coveredElements = LongVariationValue.newArray(); protected final LongVariationValue coveredElements = new LongVariationValue();


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


@Override @Override
Expand Down
Expand Up @@ -22,11 +22,6 @@
import com.google.common.base.Optional; import com.google.common.base.Optional;
import org.sonar.server.computation.task.projectanalysis.formula.CounterInitializationContext; 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.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 { public final class LinesAndConditionsWithUncoveredVariationCounter extends ElementsAndCoveredElementsVariationCounter {
private final LinesAndConditionsWithUncoveredMetricKeys metricKeys; private final LinesAndConditionsWithUncoveredMetricKeys metricKeys;
Expand All @@ -38,23 +33,16 @@ public LinesAndConditionsWithUncoveredVariationCounter(LinesAndConditionsWithUnc
@Override @Override
public void initializeForSupportedLeaf(CounterInitializationContext counterContext) { public void initializeForSupportedLeaf(CounterInitializationContext counterContext) {
Optional<Measure> newLinesMeasure = counterContext.getMeasure(metricKeys.getLines()); Optional<Measure> newLinesMeasure = counterContext.getMeasure(metricKeys.getLines());
if (!newLinesMeasure.isPresent() || !newLinesMeasure.get().hasVariations()) { if (!newLinesMeasure.isPresent() || !newLinesMeasure.get().hasVariation()) {
return; 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(); long elements = (long) newLines + newConditions;
MeasureVariations newConditions = CoverageUtils.getMeasureVariations(counterContext, metricKeys.getConditions()); this.elements.increment(elements);
MeasureVariations uncoveredLines = CoverageUtils.getMeasureVariations(counterContext, metricKeys.getUncoveredLines()); coveredElements.increment(elements - uncoveredConditions - uncoveredLines);
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));
}
} }
} }
Expand Up @@ -20,13 +20,9 @@
package org.sonar.server.computation.task.projectanalysis.formula.coverage; 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.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 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.getMeasureVariations;
import static org.sonar.server.computation.task.projectanalysis.formula.coverage.CoverageUtils.supportedPeriods;


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


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

0 comments on commit 0876f2b

Please sign in to comment.