--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.server.computation.formula;
+
+import com.google.common.base.Optional;
+import com.google.common.base.Predicate;
+import org.sonar.server.computation.component.CrawlerDepthLimit;
+import org.sonar.server.computation.formula.counter.DoubleVariationValue;
+import org.sonar.server.computation.measure.Measure;
+import org.sonar.server.computation.measure.MeasureVariations;
+import org.sonar.server.computation.period.Period;
+
+import static com.google.common.collect.FluentIterable.from;
+import static java.util.Objects.requireNonNull;
+import static org.sonar.server.computation.measure.Measure.newMeasureBuilder;
+
+/**
+ * A Formula which aggregates variations of a specific metric by simply making the sums of its variations. It supports
+ * make the sum of only specific periods.
+ */
+public class VariationSumFormula implements Formula<VariationSumFormula.VariationSumCounter> {
+ private final String metricKey;
+ private final Predicate<Period> supportedPeriods;
+
+ public VariationSumFormula(String metricKey, Predicate<Period> supportedPeriods) {
+ this.supportedPeriods = supportedPeriods;
+ this.metricKey = requireNonNull(metricKey, "Metric key cannot be null");
+ }
+
+ @Override
+ public VariationSumCounter createNewCounter() {
+ return new VariationSumCounter(metricKey, supportedPeriods);
+ }
+
+ @Override
+ public Optional<Measure> createMeasure(VariationSumCounter counter, CreateMeasureContext context) {
+ if (!CrawlerDepthLimit.LEAVES.isDeeperThan(context.getComponent().getType())) {
+ 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;
+ }
+
+ @Override
+ public String[] getOutputMetricKeys() {
+ return new String[] {metricKey};
+ }
+
+ public static final class VariationSumCounter implements Counter<VariationSumCounter> {
+ private final DoubleVariationValue.Array array = DoubleVariationValue.newArray();
+ private final String metricKey;
+ private final Predicate<Period> supportedPeriods;
+
+ private VariationSumCounter(String metricKey, Predicate<Period> supportedPeriods) {
+ this.metricKey = metricKey;
+ this.supportedPeriods = supportedPeriods;
+ }
+
+ @Override
+ public void aggregate(VariationSumCounter counter) {
+ array.incrementAll(counter.array);
+ }
+
+ @Override
+ public void initialize(CounterInitializationContext context) {
+ Optional<Measure> measure = context.getMeasure(metricKey);
+ if (!measure.isPresent() || !measure.get().hasVariations()) {
+ 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, variations.getVariation(period.getIndex()));
+ }
+ }
+ }
+ }
+ }
+}
package org.sonar.server.computation.formula.coverage;
import com.google.common.base.Optional;
-import com.google.common.base.Predicate;
-import java.util.List;
-import javax.annotation.Nonnull;
import org.sonar.server.computation.component.Component;
import org.sonar.server.computation.formula.CounterInitializationContext;
import org.sonar.server.computation.formula.CreateMeasureContext;
import static com.google.common.collect.FluentIterable.from;
import static org.sonar.server.computation.measure.Measure.newMeasureBuilder;
+import static org.sonar.server.computation.period.PeriodPredicates.viewsRestrictedPeriods;
public final class CoverageUtils {
private static final Measure DEFAULT_MEASURE = newMeasureBuilder().create(0L);
return supportedPeriods(context.getLeaf().getType(), context.getPeriods());
}
- private static Iterable<Period> supportedPeriods(Component.Type type, List<Period> periods) {
+ private static Iterable<Period> supportedPeriods(Component.Type type, Iterable<Period> periods) {
if (type.isReportType()) {
return periods;
}
- return from(periods).filter(ViewsSupportedPeriods.INSTANCE);
+ return from(periods).filter(viewsRestrictedPeriods());
}
- private enum ViewsSupportedPeriods implements Predicate<Period> {
- INSTANCE;
-
- @Override
- public boolean apply(@Nonnull Period input) {
- return input.getIndex() < 4;
- }
- }
}
import org.sonar.server.computation.measure.MeasureVariations;
import org.sonar.server.computation.period.Period;
+import static org.sonar.server.computation.formula.coverage.CoverageUtils.getLongVariation;
import static org.sonar.server.computation.formula.coverage.CoverageUtils.supportedPeriods;
public final class LinesAndConditionsWithUncoveredVariationCounter extends ElementsAndCoveredElementsVariationCounter {
if (!newLines.hasVariation(period.getIndex())) {
continue;
}
- long elements = (long) newLines.getVariation(period.getIndex()) + CoverageUtils.getLongVariation(newConditions, period);
+ long elements = (long) newLines.getVariation(period.getIndex()) + getLongVariation(newConditions, period);
this.elements.increment(period, elements);
coveredElements.increment(
period,
- elements - CoverageUtils.getLongVariation(uncoveredConditions, period) - CoverageUtils.getLongVariation(uncoveredLines, period));
+ elements - getLongVariation(uncoveredConditions, period) - getLongVariation(uncoveredLines, period));
}
}
}
+++ /dev/null
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube 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.
- *
- * SonarQube 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.server.computation.formula.coverage;
-
-import com.google.common.base.Optional;
-import org.sonar.server.computation.component.CrawlerDepthLimit;
-import org.sonar.server.computation.formula.Counter;
-import org.sonar.server.computation.formula.CounterInitializationContext;
-import org.sonar.server.computation.formula.CreateMeasureContext;
-import org.sonar.server.computation.formula.Formula;
-import org.sonar.server.computation.formula.counter.DoubleVariationValue;
-import org.sonar.server.computation.measure.Measure;
-import org.sonar.server.computation.measure.MeasureVariations;
-import org.sonar.server.computation.period.Period;
-
-import static java.util.Objects.requireNonNull;
-import static org.sonar.server.computation.formula.coverage.CoverageUtils.supportedPeriods;
-import static org.sonar.server.computation.measure.Measure.newMeasureBuilder;
-
-/**
- * A Formula which aggregates a new coverage measure by simply making the sums of its variations.
- */
-public class NewCoverageVariationSumFormula implements Formula<NewCoverageVariationSumFormula.VariationSumCounter> {
- private final String metricKey;
-
- public NewCoverageVariationSumFormula(String metricKey) {
- this.metricKey = requireNonNull(metricKey, "Metric key cannot be null");
- }
-
- @Override
- public VariationSumCounter createNewCounter() {
- return new VariationSumCounter(metricKey);
- }
-
- @Override
- public Optional<Measure> createMeasure(VariationSumCounter counter, CreateMeasureContext context) {
- if (!CrawlerDepthLimit.LEAVES.isDeeperThan(context.getComponent().getType())) {
- 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 static MeasureVariations.Builder createAndPopulateBuilder(DoubleVariationValue.Array array, CreateMeasureContext context) {
- MeasureVariations.Builder builder = MeasureVariations.newMeasureVariationsBuilder();
- for (Period period : supportedPeriods(context)) {
- DoubleVariationValue elements = array.get(period);
- if (elements.isSet()) {
- builder.setVariation(period, elements.getValue());
- }
- }
- return builder;
- }
-
- @Override
- public String[] getOutputMetricKeys() {
- return new String[] { metricKey };
- }
-
- public static final class VariationSumCounter implements Counter<VariationSumCounter> {
- private final DoubleVariationValue.Array array = DoubleVariationValue.newArray();
- private final String metricKey;
-
- private VariationSumCounter(String metricKey) {
- this.metricKey = metricKey;
- }
-
- @Override
- public void aggregate(VariationSumCounter counter) {
- array.incrementAll(counter.array);
- }
-
- @Override
- public void initialize(CounterInitializationContext context) {
- Optional<Measure> measure = context.getMeasure(metricKey);
- if (!measure.isPresent() || !measure.get().hasVariations()) {
- return;
- }
- MeasureVariations variations = measure.get().getVariations();
- for (Period period : supportedPeriods(context)) {
- if (variations.hasVariation(period.getIndex())) {
- double variation = variations.getVariation(period.getIndex());
- if (variation > 0) {
- array.increment(period, variations.getVariation(period.getIndex()));
- }
- }
- }
- }
- }
-}
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.server.computation.period;
+
+import com.google.common.base.Predicate;
+import javax.annotation.Nonnull;
+
+public final class PeriodPredicates {
+ private PeriodPredicates() {
+ // prevents instantiation
+ }
+
+ /**
+ * Since Periods 4 and 5 can be customized per project and/or per view/subview, aggregating variation on these periods
+ * for NEW_* metrics will only generate garbage data which will make no sense. These Periods should be ignored
+ * when processing views/subviews.
+ */
+ public static Predicate<Period> viewsRestrictedPeriods() {
+ return ViewsSupportedPeriods.INSTANCE;
+ }
+
+ private enum ViewsSupportedPeriods implements Predicate<Period> {
+ INSTANCE;
+
+ @Override
+ public boolean apply(@Nonnull Period input) {
+ return input.getIndex() < 4;
+ }
+ }
+}
@Override
public void execute() {
Metric qProfilesMetric = metricRepository.getByKey(CoreMetrics.QUALITY_PROFILES_KEY);
- new PathAwareCrawler<>(new NewCoverageAggregationComponentCrawler(qProfilesMetric))
+ new PathAwareCrawler<>(new NewCoverageAggregationComponentVisitor(qProfilesMetric))
.visit(treeRootHolder.getRoot());
}
- private class NewCoverageAggregationComponentCrawler extends PathAwareVisitorAdapter<QProfiles> {
+ private class NewCoverageAggregationComponentVisitor extends PathAwareVisitorAdapter<QProfiles> {
private final Metric qProfilesMetric;
- public NewCoverageAggregationComponentCrawler(Metric qProfilesMetric) {
+ public NewCoverageAggregationComponentVisitor(Metric qProfilesMetric) {
super(CrawlerDepthLimit.MODULE, POST_ORDER, new SimpleStackElementFactory<QProfiles>() {
@Override
public QProfiles createForAny(Component component) {
import org.sonar.server.computation.formula.CreateMeasureContext;
import org.sonar.server.computation.formula.Formula;
import org.sonar.server.computation.formula.FormulaExecutorComponentVisitor;
-import org.sonar.server.computation.formula.coverage.NewCoverageVariationSumFormula;
+import org.sonar.server.computation.formula.VariationSumFormula;
import org.sonar.server.computation.formula.counter.IntVariationValue;
import org.sonar.server.computation.formula.coverage.LinesAndConditionsWithUncoveredMetricKeys;
import org.sonar.server.computation.formula.coverage.LinesAndConditionsWithUncoveredVariationFormula;
import org.sonar.server.computation.period.PeriodsHolder;
import static org.sonar.server.computation.measure.Measure.newMeasureBuilder;
+import static org.sonar.server.computation.period.PeriodPredicates.viewsRestrictedPeriods;
/**
* Computes measures related to the New Coverage. These measures do not have values, only variations.
public class NewCoverageMeasuresStep implements ComputationStep {
private static final List<Formula> FORMULAS = ImmutableList.<Formula>of(
// UT coverage
- new NewCoverageFormula()
- ,
+ new NewCoverageFormula(),
new NewBranchCoverageFormula(),
new NewLineCoverageFormula(),
// IT File coverage
// Overall coverage
new NewOverallCodeCoverageFormula(),
new NewOverallBranchCoverageFormula(),
- new NewOverallLineCoverageFormula()
- );
+ new NewOverallLineCoverageFormula());
private final TreeRootHolder treeRootHolder;
private final PeriodsHolder periodsHolder;
private static final NewCoverageOutputMetricKeys OUTPUT_METRIC_KEYS = new NewCoverageOutputMetricKeys(
CoreMetrics.NEW_LINES_TO_COVER_KEY, CoreMetrics.NEW_UNCOVERED_LINES_KEY,
CoreMetrics.NEW_CONDITIONS_TO_COVER_KEY, CoreMetrics.NEW_UNCOVERED_CONDITIONS_KEY);
- private static final Iterable<Formula<?>> VIEWS_FORMULAS = intSumFormulas(OUTPUT_METRIC_KEYS);
+ private static final Iterable<Formula<?>> VIEWS_FORMULAS = variationSumFormulas(OUTPUT_METRIC_KEYS);
private NewLinesAndConditionsCoverageFormula(BatchReportReader batchReportReader) {
super(batchReportReader,
private static final NewCoverageOutputMetricKeys OUTPUT_METRIC_KEYS = new NewCoverageOutputMetricKeys(
CoreMetrics.NEW_IT_LINES_TO_COVER_KEY, CoreMetrics.NEW_IT_UNCOVERED_LINES_KEY,
CoreMetrics.NEW_IT_CONDITIONS_TO_COVER_KEY, CoreMetrics.NEW_IT_UNCOVERED_CONDITIONS_KEY);
- private static final Iterable<Formula<?>> VIEWS_FORMULAS = intSumFormulas(OUTPUT_METRIC_KEYS);
+ private static final Iterable<Formula<?>> VIEWS_FORMULAS = variationSumFormulas(OUTPUT_METRIC_KEYS);
private NewItLinesAndConditionsCoverageFormula(BatchReportReader batchReportReader) {
super(batchReportReader,
private static final NewCoverageOutputMetricKeys OUTPUT_METRIC_KEYS = new NewCoverageOutputMetricKeys(
CoreMetrics.NEW_OVERALL_LINES_TO_COVER_KEY, CoreMetrics.NEW_OVERALL_UNCOVERED_LINES_KEY,
CoreMetrics.NEW_OVERALL_CONDITIONS_TO_COVER_KEY, CoreMetrics.NEW_OVERALL_UNCOVERED_CONDITIONS_KEY);
- private static final Iterable<Formula<?>> VIEWS_FORMULAS = intSumFormulas(OUTPUT_METRIC_KEYS);
+ private static final Iterable<Formula<?>> VIEWS_FORMULAS = variationSumFormulas(OUTPUT_METRIC_KEYS);
private NewOverallLinesAndConditionsCoverageFormula(BatchReportReader batchReportReader) {
super(batchReportReader,
* Creates a List of {@link org.sonar.server.computation.formula.SumFormula.IntSumFormula} for each
* metric key of the specified {@link NewCoverageOutputMetricKeys} instance.
*/
- private static Iterable<Formula<?>> intSumFormulas(NewCoverageOutputMetricKeys outputMetricKeys) {
+ private static Iterable<Formula<?>> variationSumFormulas(NewCoverageOutputMetricKeys outputMetricKeys) {
return ImmutableList.<Formula<?>>of(
- new NewCoverageVariationSumFormula(outputMetricKeys.getNewLinesToCover()),
- new NewCoverageVariationSumFormula(outputMetricKeys.getNewUncoveredLines()),
- new NewCoverageVariationSumFormula(outputMetricKeys.getNewConditionsToCover()),
- new NewCoverageVariationSumFormula(outputMetricKeys.getNewUncoveredConditions()));
+ new VariationSumFormula(outputMetricKeys.getNewLinesToCover(), viewsRestrictedPeriods()),
+ new VariationSumFormula(outputMetricKeys.getNewUncoveredLines(), viewsRestrictedPeriods()),
+ new VariationSumFormula(outputMetricKeys.getNewConditionsToCover(), viewsRestrictedPeriods()),
+ new VariationSumFormula(outputMetricKeys.getNewUncoveredConditions(), viewsRestrictedPeriods()));
}
public static class NewLinesAndConditionsFormula implements Formula<NewCoverageCounter> {
--- /dev/null
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube 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.
+ *
+ * SonarQube 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.server.computation.period;
+
+import org.junit.Test;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class PeriodPredicatesTest {
+
+ @Test(expected = NullPointerException.class)
+ public void viewsRestrictedPeriods_throws_NPE_if_Period_is_null() {
+ PeriodPredicates.viewsRestrictedPeriods().apply(null);
+ }
+
+ @Test
+ public void viewsRestrictedPeriods() {
+ assertThat(PeriodPredicates.viewsRestrictedPeriods().apply(createPeriod(1))).isTrue();
+ assertThat(PeriodPredicates.viewsRestrictedPeriods().apply(createPeriod(2))).isTrue();
+ assertThat(PeriodPredicates.viewsRestrictedPeriods().apply(createPeriod(3))).isTrue();
+ assertThat(PeriodPredicates.viewsRestrictedPeriods().apply(createPeriod(4))).isFalse();
+ assertThat(PeriodPredicates.viewsRestrictedPeriods().apply(createPeriod(5))).isFalse();
+ }
+
+ private Period createPeriod(int index) {
+ return new Period(index, "don't care", null, 1l, 1l);
+ }
+}