/**
* This repository contains issues for only one component at a time. It's populated by {@link IntegrateIssuesVisitor} and
- * it's mainly used by {@link org.sonar.server.computation.measure.api.MeasureComputerImplementationContext} in order for a {@link MeasureComputer}
+ * it's mainly used by {@link org.sonar.api.ce.measure.MeasureComputer.MeasureComputerContext} in order for a {@link MeasureComputer}
* to access to the issues of a component.
*
* This repository must NEVER contains more issues than in issues from one component order to not consume to much memory.
package org.sonar.server.computation.measure;
-import org.sonar.api.ce.measure.MeasureComputer;
+import org.sonar.server.computation.measure.api.MeasureComputerWrapper;
public interface MeasureComputersHolder {
*
* @throws IllegalStateException if the measure computers haven't been initialized
*/
- Iterable<MeasureComputer> getMeasureComputers();
+ Iterable<MeasureComputerWrapper> getMeasureComputers();
}
import com.google.common.base.Predicates;
import javax.annotation.CheckForNull;
-import org.sonar.api.ce.measure.MeasureComputer;
+import org.sonar.server.computation.measure.api.MeasureComputerWrapper;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.FluentIterable.from;
public class MeasureComputersHolderImpl implements MutableMeasureComputersHolder {
@CheckForNull
- private Iterable<MeasureComputer> measureComputers;
+ private Iterable<MeasureComputerWrapper> measureComputers;
@Override
- public Iterable<MeasureComputer> getMeasureComputers() {
+ public Iterable<MeasureComputerWrapper> getMeasureComputers() {
checkState(this.measureComputers != null, "Measure computers have not been initialized yet");
return measureComputers;
}
@Override
- public void setMeasureComputers(Iterable<MeasureComputer> measureComputers) {
+ public void setMeasureComputers(Iterable<MeasureComputerWrapper> measureComputers) {
requireNonNull(measureComputers, "Measure computers cannot be null");
checkState(this.measureComputers == null, "Measure computers have already been initialized");
this.measureComputers = from(measureComputers).filter(Predicates.notNull()).toList();
import org.sonar.server.computation.component.SettingsRepository;
import org.sonar.server.computation.component.TypeAwareVisitorAdapter;
import org.sonar.server.computation.issue.ComponentIssuesRepository;
-import org.sonar.server.computation.measure.api.MeasureComputerImplementationContext;
+import org.sonar.server.computation.measure.api.MeasureComputerContextImpl;
+import org.sonar.server.computation.measure.api.MeasureComputerWrapper;
import org.sonar.server.computation.metric.MetricRepository;
import static org.sonar.server.computation.component.ComponentVisitor.Order.POST_ORDER;
@Override
public void visitAny(org.sonar.server.computation.component.Component component) {
- for (MeasureComputer computer : measureComputersHolder.getMeasureComputers()) {
- LOGGER.trace("Measure computer '{}' is computing component {}", computer.getImplementation(), component);
- MeasureComputerImplementationContext measureComputerContext = new MeasureComputerImplementationContext(component, computer,
- settings, measureRepository, metricRepository, componentIssuesRepository);
- computer.getImplementation().compute(measureComputerContext);
+ MeasureComputerContextImpl context = new MeasureComputerContextImpl(component, settings, measureRepository, metricRepository, componentIssuesRepository);
+ for (MeasureComputerWrapper measureComputerWrapper : measureComputersHolder.getMeasureComputers()) {
+ context.setDefinition(measureComputerWrapper.getDefinition());
+ MeasureComputer measureComputer = measureComputerWrapper.getComputer();
+ LOGGER.trace("Measure computer '{}' is computing component {}", measureComputer, component);
+ measureComputer.compute(context);
}
}
}
*/
package org.sonar.server.computation.measure;
-import org.sonar.api.ce.measure.MeasureComputer;
+import org.sonar.server.computation.measure.api.MeasureComputerWrapper;
/**
* A {@link MeasureComputersHolder} which value can be set only once.
* @throws NullPointerException if the specified Iterable is {@code null}
* @throws IllegalStateException if the holder has already been initialized
*/
- void setMeasureComputers(Iterable<MeasureComputer> measureComputers);
+ void setMeasureComputers(Iterable<MeasureComputerWrapper> measureComputers);
}
--- /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.measure.api;
+
+import com.google.common.base.Function;
+import com.google.common.base.Optional;
+import com.google.common.base.Predicates;
+import com.google.common.collect.FluentIterable;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import org.sonar.api.ce.measure.Component;
+import org.sonar.api.ce.measure.Issue;
+import org.sonar.api.ce.measure.Measure;
+import org.sonar.api.ce.measure.Settings;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.server.computation.component.SettingsRepository;
+import org.sonar.server.computation.issue.ComponentIssuesRepository;
+import org.sonar.server.computation.measure.MeasureRepository;
+import org.sonar.server.computation.metric.Metric;
+import org.sonar.server.computation.metric.MetricRepository;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static org.sonar.api.ce.measure.MeasureComputer.MeasureComputerContext;
+import static org.sonar.api.ce.measure.MeasureComputer.MeasureComputerDefinition;
+import static org.sonar.server.computation.measure.Measure.newMeasureBuilder;
+
+public class MeasureComputerContextImpl implements MeasureComputerContext {
+
+ private final SettingsRepository settings;
+ private final MeasureRepository measureRepository;
+ private final MetricRepository metricRepository;
+
+ private final org.sonar.server.computation.component.Component internalComponent;
+ private final Component component;
+ private final List<DefaultIssue> componentIssues;
+
+ private MeasureComputerDefinition definition;
+ private Set<String> allowedMetrics;
+
+ public MeasureComputerContextImpl(org.sonar.server.computation.component.Component component, SettingsRepository settings,
+ MeasureRepository measureRepository, MetricRepository metricRepository, ComponentIssuesRepository componentIssuesRepository) {
+ this.settings = settings;
+ this.internalComponent = component;
+ this.measureRepository = measureRepository;
+ this.metricRepository = metricRepository;
+ this.component = newComponent(component);
+ this.componentIssues = componentIssuesRepository.getIssues(component);
+ }
+
+ private Component newComponent(org.sonar.server.computation.component.Component component) {
+ return new ComponentImpl(
+ component.getKey(),
+ Component.Type.valueOf(component.getType().name()),
+ component.getType() == org.sonar.server.computation.component.Component.Type.FILE ?
+ new ComponentImpl.FileAttributesImpl(component.getFileAttributes().getLanguageKey(), component.getFileAttributes().isUnitTest()) :
+ null);
+ }
+
+ /**
+ * Definition needs to be reset each time a new computer is processed.
+ * Defining it by a setter allows to reduce the number of this class to be created (one per component instead of one per component and per computer).
+ */
+ public MeasureComputerContextImpl setDefinition(MeasureComputerDefinition definition) {
+ this.definition = definition;
+ this.allowedMetrics = allowedMetric(definition);
+ return this;
+ }
+
+ private static Set<String> allowedMetric(MeasureComputerDefinition definition) {
+ Set<String> allowedMetrics = new HashSet<>();
+ allowedMetrics.addAll(definition.getInputMetrics());
+ allowedMetrics.addAll(definition.getOutputMetrics());
+ return allowedMetrics;
+ }
+
+ @Override
+ public Component getComponent() {
+ return component;
+ }
+
+ @Override
+ public Settings getSettings() {
+ return new Settings() {
+ @Override
+ @CheckForNull
+ public String getString(String key) {
+ return getComponentSettings().getString(key);
+ }
+
+ @Override
+ public String[] getStringArray(String key) {
+ return getComponentSettings().getStringArray(key);
+ }
+ };
+ }
+
+ private org.sonar.api.config.Settings getComponentSettings() {
+ return settings.getSettings(internalComponent);
+ }
+
+ @Override
+ @CheckForNull
+ public Measure getMeasure(String metric) {
+ validateInputMetric(metric);
+ Optional<org.sonar.server.computation.measure.Measure> measure = measureRepository.getRawMeasure(internalComponent, metricRepository.getByKey(metric));
+ if (measure.isPresent()) {
+ return new MeasureImpl(measure.get());
+ }
+ return null;
+ }
+
+ @Override
+ public Iterable<Measure> getChildrenMeasures(String metric) {
+ validateInputMetric(metric);
+ return FluentIterable.from(internalComponent.getChildren())
+ .transform(new ComponentToMeasure(metricRepository.getByKey(metric)))
+ .transform(ToMeasureAPI.INSTANCE)
+ .filter(Predicates.notNull());
+ }
+
+ @Override
+ public void addMeasure(String metricKey, int value) {
+ Metric metric = metricRepository.getByKey(metricKey);
+ validateAddMeasure(metric);
+ measureRepository.add(internalComponent, metric, newMeasureBuilder().create(value));
+ }
+
+ @Override
+ public void addMeasure(String metricKey, double value) {
+ Metric metric = metricRepository.getByKey(metricKey);
+ validateAddMeasure(metric);
+ measureRepository.add(internalComponent, metric, newMeasureBuilder().create(value));
+ }
+
+ @Override
+ public void addMeasure(String metricKey, long value) {
+ Metric metric = metricRepository.getByKey(metricKey);
+ validateAddMeasure(metric);
+ measureRepository.add(internalComponent, metric, newMeasureBuilder().create(value));
+ }
+
+ @Override
+ public void addMeasure(String metricKey, String value) {
+ Metric metric = metricRepository.getByKey(metricKey);
+ validateAddMeasure(metric);
+ measureRepository.add(internalComponent, metric, newMeasureBuilder().create(value));
+ }
+
+ private void validateInputMetric(String metric) {
+ checkArgument(allowedMetrics.contains(metric), "Only metrics in %s can be used to load measures", definition.getInputMetrics());
+ }
+
+ private void validateAddMeasure(Metric metric) {
+ checkArgument(definition.getOutputMetrics().contains(metric.getKey()), "Only metrics in %s can be used to add measures. Metric '%s' is not allowed.",
+ definition.getOutputMetrics(), metric.getKey());
+ if (measureRepository.getRawMeasure(internalComponent, metric).isPresent()) {
+ throw new UnsupportedOperationException(String.format("A measure on metric '%s' already exists on component '%s'", metric.getKey(), internalComponent.getKey()));
+ }
+ }
+
+ @Override
+ public List<? extends Issue> getIssues() {
+ return componentIssues;
+ }
+
+ private class ComponentToMeasure implements Function<org.sonar.server.computation.component.Component, Optional<org.sonar.server.computation.measure.Measure>> {
+
+ private final Metric metric;
+
+ public ComponentToMeasure(Metric metric) {
+ this.metric = metric;
+ }
+
+ @Override
+ public Optional<org.sonar.server.computation.measure.Measure> apply(@Nonnull org.sonar.server.computation.component.Component input) {
+ return measureRepository.getRawMeasure(input, metric);
+ }
+ }
+
+ private enum ToMeasureAPI implements Function<Optional<org.sonar.server.computation.measure.Measure>, Measure> {
+ INSTANCE;
+
+ @Nullable
+ @Override
+ public Measure apply(@Nonnull Optional<org.sonar.server.computation.measure.Measure> input) {
+ return input.isPresent() ? new MeasureImpl(input.get()) : null;
+ }
+ }
+
+}
--- /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.measure.api;
+
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.sonar.api.ce.measure.MeasureComputer;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static java.util.Objects.requireNonNull;
+
+public class MeasureComputerDefinitionImpl implements MeasureComputer.MeasureComputerDefinition {
+
+ private final Set<String> inputMetricKeys;
+ private final Set<String> outputMetrics;
+
+ private MeasureComputerDefinitionImpl(BuilderImpl builder) {
+ this.inputMetricKeys = ImmutableSet.copyOf(builder.inputMetricKeys);
+ this.outputMetrics = ImmutableSet.copyOf(builder.outputMetrics);
+ }
+
+ @Override
+ public Set<String> getInputMetrics() {
+ return inputMetricKeys;
+ }
+
+ @Override
+ public Set<String> getOutputMetrics() {
+ return outputMetrics;
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ MeasureComputerDefinitionImpl that = (MeasureComputerDefinitionImpl) o;
+
+ if (!inputMetricKeys.equals(that.inputMetricKeys)) {
+ return false;
+ }
+ return outputMetrics.equals(that.outputMetrics);
+ }
+
+ @Override
+ public int hashCode() {
+ int result = inputMetricKeys.hashCode();
+ result = 31 * result + outputMetrics.hashCode();
+ return result;
+ }
+
+ @Override
+ public String toString() {
+ return "MeasureComputerDefinitionImpl{" +
+ "inputMetricKeys=" + inputMetricKeys +
+ ", outputMetrics=" + outputMetrics +
+ '}';
+ }
+
+ public static class BuilderImpl implements Builder {
+
+ private String[] inputMetricKeys = new String[] {};
+ @CheckForNull
+ private String[] outputMetrics;
+
+ @Override
+ public Builder setInputMetrics(String... inputMetrics) {
+ this.inputMetricKeys = validateInputMetricKeys(inputMetrics);
+ return this;
+ }
+
+ @Override
+ public Builder setOutputMetrics(String... outputMetrics) {
+ this.outputMetrics = validateOutputMetricKeys(outputMetrics);
+ return this;
+ }
+
+ @Override
+ public MeasureComputer.MeasureComputerDefinition build() {
+ validateInputMetricKeys(this.inputMetricKeys);
+ validateOutputMetricKeys(this.outputMetrics);
+ return new MeasureComputerDefinitionImpl(this);
+ }
+
+ private static String[] validateInputMetricKeys(@Nullable String[] inputMetrics) {
+ requireNonNull(inputMetrics, "Input metrics cannot be null");
+ checkNotNull(inputMetrics);
+ return inputMetrics;
+ }
+
+ private static String[] validateOutputMetricKeys(@Nullable String[] outputMetrics) {
+ requireNonNull(outputMetrics, "Output metrics cannot be null");
+ checkArgument(outputMetrics.length > 0, "At least one output metric must be defined");
+ checkNotNull(outputMetrics);
+ return outputMetrics;
+ }
+ }
+
+ private static void checkNotNull(String[] metrics) {
+ for (String metric : metrics) {
+ requireNonNull(metric, "Null metric is not allowed");
+ }
+ }
+}
+++ /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.measure.api;
-
-import com.google.common.collect.ImmutableSet;
-import java.util.Set;
-import javax.annotation.Nullable;
-import org.sonar.api.ce.measure.MeasureComputer;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static java.util.Objects.requireNonNull;
-
-public class MeasureComputerImpl implements MeasureComputer {
-
- private final Set<String> inputMetricKeys;
- private final Set<String> outputMetrics;
- private final Implementation implementation;
-
- public MeasureComputerImpl(MeasureComputerBuilderImpl builder) {
- this.inputMetricKeys = ImmutableSet.copyOf(builder.inputMetricKeys);
- this.outputMetrics = ImmutableSet.copyOf(builder.outputMetrics);
- this.implementation = builder.measureComputerImplementation;
- }
-
- @Override
- public Set<String> getInputMetrics() {
- return inputMetricKeys;
- }
-
- @Override
- public Set<String> getOutputMetrics() {
- return outputMetrics;
- }
-
- @Override
- public Implementation getImplementation() {
- return implementation;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
-
- MeasureComputerImpl that = (MeasureComputerImpl) o;
-
- if (!inputMetricKeys.equals(that.inputMetricKeys)) {
- return false;
- }
- return outputMetrics.equals(that.outputMetrics);
- }
-
- @Override
- public int hashCode() {
- int result = inputMetricKeys.hashCode();
- result = 31 * result + outputMetrics.hashCode();
- return result;
- }
-
- @Override
- public String toString() {
- return "MeasureComputerImpl{" +
- "inputMetricKeys=" + inputMetricKeys +
- ", outputMetrics=" + outputMetrics +
- ", implementation=" + implementation +
- '}';
- }
-
- public static class MeasureComputerBuilderImpl implements MeasureComputerBuilder {
-
- private String[] inputMetricKeys = new String[] {};
- private String[] outputMetrics;
- private Implementation measureComputerImplementation;
-
- @Override
- public MeasureComputerBuilder setInputMetrics(String... inputMetrics) {
- this.inputMetricKeys = validateInputMetricKeys(inputMetrics);
- return this;
- }
-
- @Override
- public MeasureComputerBuilder setOutputMetrics(String... outputMetrics) {
- this.outputMetrics = validateOutputMetricKeys(outputMetrics);
- return this;
- }
-
- @Override
- public MeasureComputerBuilder setImplementation(Implementation impl) {
- this.measureComputerImplementation = validateImplementation(impl);
- return this;
- }
-
- @Override
- public MeasureComputer build() {
- validateInputMetricKeys(this.inputMetricKeys);
- validateOutputMetricKeys(this.outputMetrics);
- validateImplementation(this.measureComputerImplementation);
- return new MeasureComputerImpl(this);
- }
-
- private static String[] validateInputMetricKeys(@Nullable String[] inputMetrics) {
- requireNonNull(inputMetrics, "Input metrics cannot be null");
- checkNotNull(inputMetrics);
- return inputMetrics;
- }
-
- private static String[] validateOutputMetricKeys(@Nullable String[] outputMetrics) {
- checkArgument(outputMetrics != null && outputMetrics.length > 0, "At least one output metric must be defined");
- checkNotNull(outputMetrics);
- return outputMetrics;
- }
-
- private static Implementation validateImplementation(Implementation impl) {
- return requireNonNull(impl, "The implementation is missing");
- }
- }
-
- private static void checkNotNull(String[] metrics){
- for (String metric : metrics) {
- requireNonNull(metric, "Null metric is not allowed");
- }
- }
-
-}
+++ /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.measure.api;
-
-import com.google.common.base.Function;
-import com.google.common.base.Optional;
-import com.google.common.base.Predicates;
-import com.google.common.collect.FluentIterable;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-import org.sonar.api.ce.measure.Component;
-import org.sonar.api.ce.measure.Issue;
-import org.sonar.api.ce.measure.Measure;
-import org.sonar.api.ce.measure.MeasureComputer;
-import org.sonar.api.ce.measure.Settings;
-import org.sonar.core.issue.DefaultIssue;
-import org.sonar.server.computation.component.SettingsRepository;
-import org.sonar.server.computation.issue.ComponentIssuesRepository;
-import org.sonar.server.computation.measure.MeasureRepository;
-import org.sonar.server.computation.metric.Metric;
-import org.sonar.server.computation.metric.MetricRepository;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static org.sonar.server.computation.measure.Measure.newMeasureBuilder;
-
-public class MeasureComputerImplementationContext implements MeasureComputer.Implementation.Context {
-
- private final MeasureComputer measureComputer;
- private final SettingsRepository settings;
- private final MeasureRepository measureRepository;
- private final MetricRepository metricRepository;
-
- private final org.sonar.server.computation.component.Component internalComponent;
- private final Component component;
- private final List<DefaultIssue> componentIssues;
-
- private final Set<String> allowedMetrics;
-
- public MeasureComputerImplementationContext(org.sonar.server.computation.component.Component component, MeasureComputer measureComputer,
- SettingsRepository settings, MeasureRepository measureRepository, MetricRepository metricRepository, ComponentIssuesRepository componentIssuesRepository) {
- this.measureComputer = measureComputer;
- this.settings = settings;
- this.internalComponent = component;
- this.measureRepository = measureRepository;
- this.metricRepository = metricRepository;
- this.component = newComponent(component);
- this.componentIssues = componentIssuesRepository.getIssues(component);
- this.allowedMetrics = allowedMetric(measureComputer);
- }
-
- private Component newComponent(org.sonar.server.computation.component.Component component) {
- return new ComponentImpl(
- component.getKey(),
- Component.Type.valueOf(component.getType().name()),
- component.getType() == org.sonar.server.computation.component.Component.Type.FILE ?
- new ComponentImpl.FileAttributesImpl(component.getFileAttributes().getLanguageKey(), component.getFileAttributes().isUnitTest()) :
- null);
- }
-
- private static Set<String> allowedMetric(MeasureComputer measureComputer) {
- Set<String> allowedMetrics = new HashSet<>();
- allowedMetrics.addAll(measureComputer.getInputMetrics());
- allowedMetrics.addAll(measureComputer.getOutputMetrics());
- return allowedMetrics;
- }
-
- @Override
- public Component getComponent() {
- return component;
- }
-
- @Override
- public Settings getSettings() {
- return new Settings() {
- @Override
- @CheckForNull
- public String getString(String key) {
- return getComponentSettings().getString(key);
- }
-
- @Override
- public String[] getStringArray(String key) {
- return getComponentSettings().getStringArray(key);
- }
- };
- }
-
- private org.sonar.api.config.Settings getComponentSettings() {
- return settings.getSettings(internalComponent);
- }
-
- @Override
- @CheckForNull
- public Measure getMeasure(String metric) {
- validateInputMetric(metric);
- Optional<org.sonar.server.computation.measure.Measure> measure = measureRepository.getRawMeasure(internalComponent, metricRepository.getByKey(metric));
- if (measure.isPresent()) {
- return new MeasureImpl(measure.get());
- }
- return null;
- }
-
- @Override
- public Iterable<Measure> getChildrenMeasures(String metric) {
- validateInputMetric(metric);
- return FluentIterable.from(internalComponent.getChildren())
- .transform(new ComponentToMeasure(metricRepository.getByKey(metric)))
- .transform(ToMeasureAPI.INSTANCE)
- .filter(Predicates.notNull());
- }
-
- @Override
- public void addMeasure(String metricKey, int value) {
- Metric metric = metricRepository.getByKey(metricKey);
- validateAddMeasure(metric);
- measureRepository.add(internalComponent, metric, newMeasureBuilder().create(value));
- }
-
- @Override
- public void addMeasure(String metricKey, double value) {
- Metric metric = metricRepository.getByKey(metricKey);
- validateAddMeasure(metric);
- measureRepository.add(internalComponent, metric, newMeasureBuilder().create(value));
- }
-
- @Override
- public void addMeasure(String metricKey, long value) {
- Metric metric = metricRepository.getByKey(metricKey);
- validateAddMeasure(metric);
- measureRepository.add(internalComponent, metric, newMeasureBuilder().create(value));
- }
-
- @Override
- public void addMeasure(String metricKey, String value) {
- Metric metric = metricRepository.getByKey(metricKey);
- validateAddMeasure(metric);
- measureRepository.add(internalComponent, metric, newMeasureBuilder().create(value));
- }
-
- private void validateInputMetric(String metric) {
- checkArgument(allowedMetrics.contains(metric), "Only metrics in %s can be used to load measures", measureComputer.getInputMetrics());
- }
-
- private void validateAddMeasure(Metric metric) {
- checkArgument(measureComputer.getOutputMetrics().contains(metric.getKey()), "Only metrics in %s can be used to add measures. Metric '%s' is not allowed.",
- measureComputer.getOutputMetrics(), metric.getKey());
- if (measureRepository.getRawMeasure(internalComponent, metric).isPresent()) {
- throw new UnsupportedOperationException(String.format("A measure on metric '%s' already exists on component '%s'", metric.getKey(), internalComponent.getKey()));
- }
- }
-
- @Override
- public List<? extends Issue> getIssues() {
- return componentIssues;
- }
-
- private class ComponentToMeasure implements Function<org.sonar.server.computation.component.Component, Optional<org.sonar.server.computation.measure.Measure>> {
-
- private final Metric metric;
-
- public ComponentToMeasure(Metric metric) {
- this.metric = metric;
- }
-
- @Override
- public Optional<org.sonar.server.computation.measure.Measure> apply(@Nonnull org.sonar.server.computation.component.Component input) {
- return measureRepository.getRawMeasure(input, metric);
- }
- }
-
- private enum ToMeasureAPI implements Function<Optional<org.sonar.server.computation.measure.Measure>, Measure> {
- INSTANCE;
-
- @Nullable
- @Override
- public Measure apply(@Nonnull Optional<org.sonar.server.computation.measure.Measure> input) {
- return input.isPresent() ? new MeasureImpl(input.get()) : null;
- }
- }
-
-}
+++ /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.measure.api;
-
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Sets;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import org.sonar.api.ce.measure.MeasureComputer;
-import org.sonar.api.ce.measure.MeasureComputerProvider;
-
-public class MeasureComputerProviderContext implements MeasureComputerProvider.Context {
-
- private final List<MeasureComputer> measureComputers = new ArrayList<>();
- private final Map<String, MeasureComputer> computerByOutputMetrics = new HashMap<>();
-
- @Override
- public MeasureComputerProvider.Context add(MeasureComputer inputMeasureComputer) {
- MeasureComputer measureComputer = validateMeasureComputer(inputMeasureComputer);
- checkOutputMetricsNotAlreadyDefinedByAnotherComputer(measureComputer);
- this.measureComputers.add(measureComputer);
- for (String metric : measureComputer.getOutputMetrics()) {
- computerByOutputMetrics.put(metric, measureComputer);
- }
- return this;
- }
-
- private MeasureComputer validateMeasureComputer(MeasureComputer measureComputer) {
- if (measureComputer instanceof MeasureComputerImpl) {
- return measureComputer;
- }
- // If the computer has not been created by the builder, we recreate it to make sure it's valid
- Set<String> inputMetrics = measureComputer.getInputMetrics();
- Set<String> outputMetrics = measureComputer.getOutputMetrics();
- return newMeasureComputerBuilder()
- .setInputMetrics(inputMetrics.toArray(new String[inputMetrics.size()]))
- .setOutputMetrics(outputMetrics.toArray(new String[outputMetrics.size()]))
- .setImplementation(measureComputer.getImplementation())
- .build();
- }
-
- public List<MeasureComputer> getMeasureComputers() {
- return measureComputers;
- }
-
- private void checkOutputMetricsNotAlreadyDefinedByAnotherComputer(MeasureComputer measureComputer) {
- Set<String> duplicated = ImmutableSet.copyOf(Sets.intersection(computerByOutputMetrics.keySet(), measureComputer.getOutputMetrics()));
- if (!duplicated.isEmpty()) {
- throw new UnsupportedOperationException(generateErrorMsg(duplicated));
- }
- }
-
- private String generateErrorMsg(Set<String> duplicated){
- StringBuilder errorMsg = new StringBuilder();
- for (String duplicationMetric : duplicated) {
- MeasureComputer otherComputer = computerByOutputMetrics.get(duplicationMetric);
- errorMsg.append(String.format(
- "The output metric '%s' is already declared by another computer. This computer has these input metrics '%s' and these output metrics '%s'. ",
- duplicationMetric, otherComputer.getInputMetrics(), otherComputer.getOutputMetrics()));
- }
- return errorMsg.toString();
- }
-
- @Override
- public MeasureComputer.MeasureComputerBuilder newMeasureComputerBuilder() {
- return new MeasureComputerImpl.MeasureComputerBuilderImpl();
- }
-}
--- /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.measure.api;
+
+import javax.annotation.concurrent.Immutable;
+import org.sonar.api.ce.measure.MeasureComputer;
+import org.sonar.api.ce.measure.MeasureComputer.MeasureComputerDefinition;
+
+import static java.util.Objects.requireNonNull;
+
+@Immutable
+public class MeasureComputerWrapper {
+
+ private final MeasureComputer computer;
+ private final MeasureComputerDefinition definition;
+
+ public MeasureComputerWrapper(MeasureComputer computer, MeasureComputerDefinition definition) {
+ this.computer = requireNonNull(computer);
+ this.definition = requireNonNull(definition);
+ }
+
+ public MeasureComputer getComputer() {
+ return computer;
+ }
+
+ public MeasureComputerDefinition getDefinition() {
+ return definition;
+ }
+
+ @Override
+ public String toString() {
+ return computer.toString();
+ }
+}
package org.sonar.server.computation.step;
import com.google.common.base.Function;
+import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
-import com.google.common.collect.FluentIterable;
import java.util.Arrays;
+import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import org.sonar.api.ce.measure.MeasureComputer;
-import org.sonar.api.ce.measure.MeasureComputerProvider;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Metric;
import org.sonar.api.measures.Metrics;
import org.sonar.api.utils.dag.DirectAcyclicGraph;
import org.sonar.server.computation.measure.MutableMeasureComputersHolder;
-import org.sonar.server.computation.measure.api.MeasureComputerProviderContext;
+import org.sonar.server.computation.measure.api.MeasureComputerDefinitionImpl;
+import org.sonar.server.computation.measure.api.MeasureComputerWrapper;
+
+import static com.google.common.collect.FluentIterable.from;
+import static org.sonar.api.ce.measure.MeasureComputer.MeasureComputerDefinition;
+import static org.sonar.api.ce.measure.MeasureComputer.MeasureComputerDefinitionContext;
public class FeedMeasureComputers implements ComputationStep {
- private static final Set<String> CORE_METRIC_KEYS = FluentIterable.from(CoreMetrics.getMetrics()).transform(MetricToKey.INSTANCE).toSet();
+ private static final Set<String> CORE_METRIC_KEYS = from(CoreMetrics.getMetrics()).transform(MetricToKey.INSTANCE).toSet();
+ private Set<String> pluginMetricKeys;
private final MutableMeasureComputersHolder measureComputersHolder;
- private final Metrics[] metricsRepositories;
- private final MeasureComputerProvider[] measureComputerProviders;
+ private final MeasureComputer[] measureComputers;
- public FeedMeasureComputers(MutableMeasureComputersHolder measureComputersHolder, Metrics[] metricsRepositories, MeasureComputerProvider[] measureComputerProviders) {
+ public FeedMeasureComputers(MutableMeasureComputersHolder measureComputersHolder, Metrics[] metricsRepositories, MeasureComputer[] measureComputers) {
this.measureComputersHolder = measureComputersHolder;
- this.measureComputerProviders = measureComputerProviders;
- this.metricsRepositories = metricsRepositories;
+ this.measureComputers = measureComputers;
+ this.pluginMetricKeys = from(Arrays.asList(metricsRepositories))
+ .transformAndConcat(MetricsToMetricList.INSTANCE)
+ .transform(MetricToKey.INSTANCE)
+ .toSet();
}
/**
* Constructor override used by Pico to instantiate the class when no plugin is defining metrics
*/
- public FeedMeasureComputers(MutableMeasureComputersHolder measureComputersHolder, MeasureComputerProvider[] measureComputerProviders) {
- this(measureComputersHolder, new Metrics[] {}, measureComputerProviders);
+ public FeedMeasureComputers(MutableMeasureComputersHolder measureComputersHolder, MeasureComputer[] measureComputers) {
+ this(measureComputersHolder, new Metrics[] {}, measureComputers);
}
/**
* Constructor override used by Pico to instantiate the class when no plugin is defining measure computers
*/
public FeedMeasureComputers(MutableMeasureComputersHolder measureComputersHolder, Metrics[] metricsRepositories) {
- this(measureComputersHolder, metricsRepositories, new MeasureComputerProvider[] {});
+ this(measureComputersHolder, metricsRepositories, new MeasureComputer[]{});
}
/**
* Constructor override used by Pico to instantiate the class when no plugin is defining metrics neither measure computers
*/
public FeedMeasureComputers(MutableMeasureComputersHolder measureComputersHolder) {
- this(measureComputersHolder, new Metrics[] {}, new MeasureComputerProvider[] {});
+ this(measureComputersHolder, new Metrics[] {}, new MeasureComputer[] {});
}
@Override
public void execute() {
- MeasureComputerProviderContext context = new MeasureComputerProviderContext();
- for (MeasureComputerProvider provider : measureComputerProviders) {
- provider.register(context);
- }
- validateInputMetrics(context.getMeasureComputers());
- measureComputersHolder.setMeasureComputers(sortComputers(context.getMeasureComputers()));
+ List<MeasureComputerWrapper> wrappers = from(Arrays.asList(measureComputers)).transform(ToMeasureWrapper.INSTANCE).toList();
+ validateMetrics(wrappers);
+ measureComputersHolder.setMeasureComputers(sortComputers(wrappers));
}
- private static Iterable<MeasureComputer> sortComputers(List<MeasureComputer> computers) {
- Map<String, MeasureComputer> computersByOutputMetric = new HashMap<>();
- Map<String, MeasureComputer> computersByInputMetric = new HashMap<>();
- feedComputersByMetric(computers, computersByOutputMetric, computersByInputMetric);
+ private static Iterable<MeasureComputerWrapper> sortComputers(List<MeasureComputerWrapper> wrappers) {
+ Map<String, MeasureComputerWrapper> computersByOutputMetric = new HashMap<>();
+ Map<String, MeasureComputerWrapper> computersByInputMetric = new HashMap<>();
+ feedComputersByMetric(wrappers, computersByOutputMetric, computersByInputMetric);
ToComputerByKey toComputerByOutputMetricKey = new ToComputerByKey(computersByOutputMetric);
ToComputerByKey toComputerByInputMetricKey = new ToComputerByKey(computersByInputMetric);
DirectAcyclicGraph dag = new DirectAcyclicGraph();
- for (MeasureComputer computer : computers) {
+ for (MeasureComputerWrapper computer : wrappers) {
dag.add(computer);
- for (MeasureComputer dependency : getDependencies(computer, toComputerByOutputMetricKey)) {
+ for (MeasureComputerWrapper dependency : getDependencies(computer, toComputerByOutputMetricKey)) {
dag.add(computer, dependency);
}
- for (MeasureComputer generates : getDependents(computer, toComputerByInputMetricKey)) {
+ for (MeasureComputerWrapper generates : getDependents(computer, toComputerByInputMetricKey)) {
dag.add(generates, computer);
}
}
return dag.sort();
}
- private static void feedComputersByMetric(List<MeasureComputer> computers, Map<String, MeasureComputer> computersByOutputMetric,
- Map<String, MeasureComputer> computersByInputMetric) {
- for (MeasureComputer computer : computers) {
- for (String outputMetric : computer.getOutputMetrics()) {
+ private static void feedComputersByMetric(List<MeasureComputerWrapper> wrappers, Map<String, MeasureComputerWrapper> computersByOutputMetric,
+ Map<String, MeasureComputerWrapper> computersByInputMetric) {
+ for (MeasureComputerWrapper computer : wrappers) {
+ for (String outputMetric : computer.getDefinition().getOutputMetrics()) {
computersByOutputMetric.put(outputMetric, computer);
}
- for (String inputMetric : computer.getInputMetrics()) {
+ for (String inputMetric : computer.getDefinition().getInputMetrics()) {
computersByInputMetric.put(inputMetric, computer);
}
}
}
- private void validateInputMetrics(List<MeasureComputer> computers) {
- Set<String> pluginMetricKeys = FluentIterable.from(Arrays.asList(metricsRepositories))
- .transformAndConcat(MetricsToMetricList.INSTANCE)
- .transform(MetricToKey.INSTANCE)
- .toSet();
- // TODO would be nice to generate an error containing all bad input metrics
- for (MeasureComputer computer : computers) {
- for (String metric : computer.getInputMetrics()) {
- if (!pluginMetricKeys.contains(metric) && !CORE_METRIC_KEYS.contains(metric)) {
- throw new IllegalStateException(String.format("Metric '%s' cannot be used as an input metric as it's no a core metric and no plugin declare this metric", metric));
- }
- }
- }
+ private void validateMetrics(List<MeasureComputerWrapper> wrappers) {
+ from(wrappers).transformAndConcat(ToInputMetrics.INSTANCE).filter(new ValidateInputMetric()).size();
+ from(wrappers).transformAndConcat(ToOutputMetrics.INSTANCE).filter(new ValidateOutputMetric()).size();
}
- private static Iterable<MeasureComputer> getDependencies(MeasureComputer measureComputer, ToComputerByKey toComputerByOutputMetricKey) {
+ private static Iterable<MeasureComputerWrapper> getDependencies(MeasureComputerWrapper measureComputer, ToComputerByKey toComputerByOutputMetricKey) {
// Remove null computer because a computer can depend on a metric that is only generated by a sensor or on a core metrics
- return FluentIterable.from(measureComputer.getInputMetrics()).transform(toComputerByOutputMetricKey).filter(Predicates.notNull());
+ return from(measureComputer.getDefinition().getInputMetrics()).transform(toComputerByOutputMetricKey).filter(Predicates.notNull());
}
- private static Iterable<MeasureComputer> getDependents(MeasureComputer measureComputer, ToComputerByKey toComputerByInputMetricKey) {
- return FluentIterable.from(measureComputer.getInputMetrics()).transform(toComputerByInputMetricKey);
+ private static Iterable<MeasureComputerWrapper> getDependents(MeasureComputerWrapper measureComputer, ToComputerByKey toComputerByInputMetricKey) {
+ return from(measureComputer.getDefinition().getInputMetrics()).transform(toComputerByInputMetricKey);
}
- private static class ToComputerByKey implements Function<String, MeasureComputer> {
- private final Map<String, MeasureComputer> computersByMetric;
+ private static class ToComputerByKey implements Function<String, MeasureComputerWrapper> {
+ private final Map<String, MeasureComputerWrapper> computersByMetric;
- private ToComputerByKey(Map<String, MeasureComputer> computersByMetric) {
+ private ToComputerByKey(Map<String, MeasureComputerWrapper> computersByMetric) {
this.computersByMetric = computersByMetric;
}
@Override
- public MeasureComputer apply(@Nonnull String metricKey) {
+ public MeasureComputerWrapper apply(@Nonnull String metricKey) {
return computersByMetric.get(metricKey);
}
}
}
}
+ private enum ToMeasureWrapper implements Function<MeasureComputer, MeasureComputerWrapper> {
+ INSTANCE;
+
+ private final MeasureComputerDefinitionContextImpl context = new MeasureComputerDefinitionContextImpl();
+
+ @Override
+ public MeasureComputerWrapper apply(@Nonnull MeasureComputer measureComputer) {
+ MeasureComputerDefinition def = measureComputer.define(context);
+ // If the computer has not been created by the builder, we recreate it to make sure it's valid
+ Set<String> inputMetrics = def.getInputMetrics();
+ Set<String> outputMetrics = def.getOutputMetrics();
+ MeasureComputerDefinition validateDef = new MeasureComputerDefinitionImpl.BuilderImpl()
+ .setInputMetrics(from(inputMetrics).toArray(String.class))
+ .setOutputMetrics(from(outputMetrics).toArray(String.class))
+ .build();
+ return new MeasureComputerWrapper(measureComputer, validateDef);
+ }
+ }
+
+ private enum ToInputMetrics implements Function<MeasureComputerWrapper, Collection<String>> {
+ INSTANCE;
+
+ @Override
+ public Collection<String> apply(@Nonnull MeasureComputerWrapper input) {
+ return input.getDefinition().getInputMetrics();
+ }
+ }
+
+ private class ValidateInputMetric implements Predicate<String> {
+ @Override
+ public boolean apply(@Nullable String metric) {
+ if (!pluginMetricKeys.contains(metric) && !CORE_METRIC_KEYS.contains(metric)) {
+ throw new IllegalStateException(String.format("Metric '%s' cannot be used as an input metric as it's not a core metric and no plugin declare this metric", metric));
+ }
+ return true;
+ }
+ }
+
+ private enum ToOutputMetrics implements Function<MeasureComputerWrapper, Collection<String>> {
+ INSTANCE;
+
+ @Override
+ public Collection<String> apply(@Nonnull MeasureComputerWrapper input) {
+ return input.getDefinition().getOutputMetrics();
+ }
+ }
+
+ private class ValidateOutputMetric implements Predicate<String> {
+ @Override
+ public boolean apply(@Nullable String metric) {
+ if (CORE_METRIC_KEYS.contains(metric)) {
+ throw new IllegalStateException(String.format("Metric '%s' cannot be used as an output metric as it's a core metric", metric));
+ }
+ if (!pluginMetricKeys.contains(metric)) {
+ throw new IllegalStateException(String.format("Metric '%s' cannot be used as an output metric as no plugin declare this metric", metric));
+ }
+ return true;
+ }
+ }
+
+ private static class MeasureComputerDefinitionContextImpl implements MeasureComputerDefinitionContext {
+ @Override
+ public MeasureComputerDefinition.Builder newDefinitionBuilder() {
+ return new MeasureComputerDefinitionImpl.BuilderImpl();
+ }
+ }
+
@Override
public String getDescription() {
return "Feed measure computers";
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
-import org.sonar.api.ce.measure.MeasureComputer;
+import org.sonar.server.computation.measure.api.MeasureComputerWrapper;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@Test
public void get_measure_computers() throws Exception {
- MeasureComputer measureComputer = mock(MeasureComputer.class);
+ MeasureComputerWrapper measureComputer = mock(MeasureComputerWrapper.class);
underTest.setMeasureComputers(Collections.singletonList(measureComputer));
assertThat(underTest.getMeasureComputers()).containsOnly(measureComputer);
@Test
public void set_measure_computers_supports_empty_arg_is_empty() {
- underTest.setMeasureComputers(ImmutableList.<MeasureComputer>of());
+ underTest.setMeasureComputers(ImmutableList.<MeasureComputerWrapper>of());
assertThat(underTest.getMeasureComputers()).isEmpty();
}
thrown.expect(IllegalStateException.class);
thrown.expectMessage("Measure computers have already been initialized");
- MeasureComputer measureComputer = mock(MeasureComputer.class);
+ MeasureComputerWrapper measureComputer = mock(MeasureComputerWrapper.class);
underTest.setMeasureComputers(Collections.singletonList(measureComputer));
underTest.setMeasureComputers(Collections.singletonList(measureComputer));
}
import org.sonar.server.computation.component.ComponentVisitor;
import org.sonar.server.computation.component.VisitorsCrawler;
import org.sonar.server.computation.issue.ComponentIssuesRepository;
-import org.sonar.server.computation.measure.api.MeasureComputerImpl;
+import org.sonar.server.computation.measure.api.MeasureComputerDefinitionImpl;
+import org.sonar.server.computation.measure.api.MeasureComputerWrapper;
import org.sonar.server.computation.metric.MetricRepositoryRule;
import static com.google.common.collect.Lists.newArrayList;
measureRepository.addRawMeasure(ROOT_REF, NCLOC_KEY, newMeasureBuilder().create(50));
measureRepository.addRawMeasure(ROOT_REF, COMMENT_LINES_KEY, newMeasureBuilder().create(7));
+ final MeasureComputer.MeasureComputerDefinition definition = new MeasureComputerDefinitionImpl.BuilderImpl()
+ .setInputMetrics(NCLOC_KEY, COMMENT_LINES_KEY)
+ .setOutputMetrics(NEW_METRIC_KEY)
+ .build();
measureComputersHolder.setMeasureComputers(newArrayList(
- new MeasureComputerImpl.MeasureComputerBuilderImpl()
- .setInputMetrics(NCLOC_KEY, COMMENT_LINES_KEY)
- .setOutputMetrics(NEW_METRIC_KEY)
- .setImplementation(
- new MeasureComputer.Implementation() {
- @Override
- public void compute(Context ctx) {
- org.sonar.api.ce.measure.Measure ncloc = ctx.getMeasure(NCLOC_KEY);
- org.sonar.api.ce.measure.Measure comment = ctx.getMeasure(COMMENT_LINES_KEY);
- if (ncloc != null && comment != null) {
- ctx.addMeasure(NEW_METRIC_KEY, ncloc.getIntValue() + comment.getIntValue());
- }
+ new MeasureComputerWrapper(
+ new MeasureComputer() {
+ @Override
+ public MeasureComputerDefinition define(MeasureComputerDefinitionContext defContext) {
+ return definition;
+ }
+
+ @Override
+ public void compute(MeasureComputerContext context) {
+ org.sonar.api.ce.measure.Measure ncloc = context.getMeasure(NCLOC_KEY);
+ org.sonar.api.ce.measure.Measure comment = context.getMeasure(COMMENT_LINES_KEY);
+ if (ncloc != null && comment != null) {
+ context.addMeasure(NEW_METRIC_KEY, ncloc.getIntValue() + comment.getIntValue());
}
}
- )
- .build()
- ));
+ },
+ definition
+ )));
- VisitorsCrawler visitorsCrawler = new VisitorsCrawler(Arrays.<ComponentVisitor>asList(new MeasureComputersVisitor(metricRepository, measureRepository, null, measureComputersHolder, componentIssuesRepository)));
+ VisitorsCrawler visitorsCrawler = new VisitorsCrawler(Arrays.<ComponentVisitor>asList(new MeasureComputersVisitor(metricRepository, measureRepository, null,
+ measureComputersHolder, componentIssuesRepository)));
visitorsCrawler.visit(ROOT);
assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_1_REF))).containsOnly(entryOf(NEW_METRIC_KEY, newMeasureBuilder().create(12)));
measureRepository.addRawMeasure(ROOT_REF, NCLOC_KEY, newMeasureBuilder().create(50));
measureRepository.addRawMeasure(ROOT_REF, COMMENT_LINES_KEY, newMeasureBuilder().create(7));
- measureComputersHolder.setMeasureComputers(Collections.<MeasureComputer>emptyList());
- VisitorsCrawler visitorsCrawler = new VisitorsCrawler(Arrays.<ComponentVisitor>asList(new MeasureComputersVisitor(metricRepository, measureRepository, null, measureComputersHolder, componentIssuesRepository)));
+ measureComputersHolder.setMeasureComputers(Collections.<MeasureComputerWrapper>emptyList());
+ VisitorsCrawler visitorsCrawler = new VisitorsCrawler(Arrays.<ComponentVisitor>asList(new MeasureComputersVisitor(metricRepository, measureRepository, null,
+ measureComputersHolder, componentIssuesRepository)));
visitorsCrawler.visit(ROOT);
assertThat(toEntries(measureRepository.getAddedRawMeasures(FILE_1_REF))).isEmpty();
--- /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.measure.api;
+
+import com.google.common.base.Optional;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.ce.measure.Component;
+import org.sonar.api.ce.measure.MeasureComputer;
+import org.sonar.api.measures.CoreMetrics;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.Duration;
+import org.sonar.core.issue.DefaultIssue;
+import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.component.SettingsRepository;
+import org.sonar.server.computation.issue.ComponentIssuesRepositoryRule;
+import org.sonar.server.computation.measure.Measure;
+import org.sonar.server.computation.measure.MeasureRepositoryRule;
+import org.sonar.server.computation.metric.Metric;
+import org.sonar.server.computation.metric.MetricImpl;
+import org.sonar.server.computation.metric.MetricRepositoryRule;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.guava.api.Assertions.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import static org.sonar.api.measures.CoreMetrics.COMMENT_LINES_KEY;
+import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
+import static org.sonar.server.computation.component.ReportComponent.builder;
+import static org.sonar.server.computation.measure.Measure.newMeasureBuilder;
+
+public class MeasureComputerContextImplTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ private static final String INT_METRIC_KEY = "int_metric_key";
+ private static final String DOUBLE_METRIC_KEY = "double_metric_key";
+ private static final String LONG_METRIC_KEY = "long_metric_key";
+ private static final String STRING_METRIC_KEY = "string_metric_key";
+
+ private static final int PROJECT_REF = 1;
+ private static final int FILE_1_REF = 12341;
+ private static final String FILE_1_KEY = "fileKey";
+ private static final int FILE_2_REF = 12342;
+
+ private static final org.sonar.server.computation.component.Component FILE_1 = builder(org.sonar.server.computation.component.Component.Type.FILE, FILE_1_REF)
+ .setKey(FILE_1_KEY)
+ .build();
+
+ @Rule
+ public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule()
+ .setRoot(builder(org.sonar.server.computation.component.Component.Type.PROJECT, PROJECT_REF).setKey("project")
+ .addChildren(
+ FILE_1,
+ builder(org.sonar.server.computation.component.Component.Type.FILE, FILE_2_REF).setKey("fileKey2").build()
+ ).build());
+
+ @Rule
+ public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
+ .add(1, CoreMetrics.NCLOC)
+ .add(new MetricImpl(2, INT_METRIC_KEY, "int metric", Metric.MetricType.INT))
+ .add(new MetricImpl(3, DOUBLE_METRIC_KEY, "double metric", Metric.MetricType.FLOAT))
+ .add(new MetricImpl(4, LONG_METRIC_KEY, "long metric", Metric.MetricType.MILLISEC))
+ .add(new MetricImpl(5, STRING_METRIC_KEY, "string metric", Metric.MetricType.STRING));
+
+ @Rule
+ public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
+
+ @Rule
+ public ComponentIssuesRepositoryRule componentIssuesRepository = new ComponentIssuesRepositoryRule(treeRootHolder);
+
+ SettingsRepository settingsRepository = mock(SettingsRepository.class);
+
+ @Test
+ public void get_component() throws Exception {
+ MeasureComputerContextImpl underTest = newContext(FILE_1_REF);
+ assertThat(underTest.getComponent().getType()).isEqualTo(Component.Type.FILE);
+ }
+
+ @Test
+ public void get_string_settings() throws Exception {
+ org.sonar.api.config.Settings serverSettings = new org.sonar.api.config.Settings();
+ serverSettings.setProperty("prop", "value");
+ when(settingsRepository.getSettings(FILE_1)).thenReturn(serverSettings);
+
+ MeasureComputerContextImpl underTest = newContext(FILE_1_REF);
+ assertThat(underTest.getSettings().getString("prop")).isEqualTo("value");
+ assertThat(underTest.getSettings().getString("unknown")).isNull();
+ }
+
+ @Test
+ public void get_string_array_settings() throws Exception {
+ org.sonar.api.config.Settings serverSettings = new org.sonar.api.config.Settings();
+ serverSettings.setProperty("prop", "1,3.4,8,50");
+ when(settingsRepository.getSettings(FILE_1)).thenReturn(serverSettings);
+
+ MeasureComputerContextImpl underTest = newContext(FILE_1_REF);
+ assertThat(underTest.getSettings().getStringArray("prop")).containsExactly("1", "3.4", "8", "50");
+ assertThat(underTest.getSettings().getStringArray("unknown")).isEmpty();
+ }
+
+ @Test
+ public void get_measure() throws Exception {
+ measureRepository.addRawMeasure(FILE_1_REF, NCLOC_KEY, newMeasureBuilder().create(10));
+
+ MeasureComputerContextImpl underTest = newContext(FILE_1_REF, NCLOC_KEY, COMMENT_LINES_KEY);
+ assertThat(underTest.getMeasure(NCLOC_KEY).getIntValue()).isEqualTo(10);
+ }
+
+ @Test
+ public void fail_with_IAE_when_get_measure_is_called_on_metric_not_in_input_list() throws Exception {
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("Only metrics in [another metric] can be used to load measures");
+
+ MeasureComputerContextImpl underTest = newContext(PROJECT_REF, "another metric", "debt");
+ underTest.getMeasure(NCLOC_KEY);
+ }
+
+ @Test
+ public void get_children_measures() throws Exception {
+ measureRepository.addRawMeasure(FILE_1_REF, NCLOC_KEY, newMeasureBuilder().create(10));
+ measureRepository.addRawMeasure(FILE_2_REF, NCLOC_KEY, newMeasureBuilder().create(12));
+
+ MeasureComputerContextImpl underTest = newContext(PROJECT_REF, NCLOC_KEY, COMMENT_LINES_KEY);
+ assertThat(underTest.getChildrenMeasures(NCLOC_KEY)).hasSize(2);
+ assertThat(underTest.getChildrenMeasures(NCLOC_KEY)).extracting("intValue").containsOnly(10, 12);
+ }
+
+ @Test
+ public void get_children_measures_when_one_child_has_no_value() throws Exception {
+ measureRepository.addRawMeasure(FILE_1_REF, NCLOC_KEY, newMeasureBuilder().create(10));
+ // No data on file 2
+
+ MeasureComputerContextImpl underTest = newContext(PROJECT_REF, NCLOC_KEY, COMMENT_LINES_KEY);
+ assertThat(underTest.getChildrenMeasures(NCLOC_KEY)).extracting("intValue").containsOnly(10);
+ }
+
+ @Test
+ public void not_fail_to_get_children_measures_on_output_metric() throws Exception {
+ measureRepository.addRawMeasure(FILE_1_REF, INT_METRIC_KEY, newMeasureBuilder().create(10));
+
+ MeasureComputerContextImpl underTest = newContext(PROJECT_REF, NCLOC_KEY, INT_METRIC_KEY);
+ assertThat(underTest.getChildrenMeasures(INT_METRIC_KEY)).hasSize(1);
+ assertThat(underTest.getChildrenMeasures(INT_METRIC_KEY)).extracting("intValue").containsOnly(10);
+ }
+
+ @Test
+ public void fail_with_IAE_when_get_children_measures_is_called_on_metric_not_in_input_list() throws Exception {
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("Only metrics in [another metric] can be used to load measures");
+
+ MeasureComputerContextImpl underTest = newContext(PROJECT_REF, "another metric", "debt");
+ underTest.getChildrenMeasures(NCLOC_KEY);
+ }
+
+ @Test
+ public void add_int_measure_create_measure_of_type_int_with_right_value() throws Exception {
+ MeasureComputerContextImpl underTest = newContext(PROJECT_REF, NCLOC_KEY, INT_METRIC_KEY);
+ underTest.addMeasure(INT_METRIC_KEY, 10);
+
+ Optional<Measure> measure = measureRepository.getAddedRawMeasure(PROJECT_REF, INT_METRIC_KEY);
+ assertThat(measure).isPresent();
+ assertThat(measure.get().getIntValue()).isEqualTo(10);
+ }
+
+ @Test
+ public void add_double_measure_create_measure_of_type_double_with_right_value() throws Exception {
+ MeasureComputerContextImpl underTest = newContext(PROJECT_REF, NCLOC_KEY, DOUBLE_METRIC_KEY);
+ underTest.addMeasure(DOUBLE_METRIC_KEY, 10d);
+
+ Optional<Measure> measure = measureRepository.getAddedRawMeasure(PROJECT_REF, DOUBLE_METRIC_KEY);
+ assertThat(measure).isPresent();
+ assertThat(measure.get().getDoubleValue()).isEqualTo(10d);
+ }
+
+ @Test
+ public void add_long_measure_create_measure_of_type_long_with_right_value() throws Exception {
+ MeasureComputerContextImpl underTest = newContext(PROJECT_REF, NCLOC_KEY, LONG_METRIC_KEY);
+ underTest.addMeasure(LONG_METRIC_KEY, 10L);
+
+ Optional<Measure> measure = measureRepository.getAddedRawMeasure(PROJECT_REF, LONG_METRIC_KEY);
+ assertThat(measure).isPresent();
+ assertThat(measure.get().getLongValue()).isEqualTo(10L);
+ }
+
+ @Test
+ public void add_string_measure_create_measure_of_type_string_with_right_value() throws Exception {
+ MeasureComputerContextImpl underTest = newContext(PROJECT_REF, NCLOC_KEY, STRING_METRIC_KEY);
+ underTest.addMeasure(STRING_METRIC_KEY, "data");
+
+ Optional<Measure> measure = measureRepository.getAddedRawMeasure(PROJECT_REF, STRING_METRIC_KEY);
+ assertThat(measure).isPresent();
+ assertThat(measure.get().getStringValue()).isEqualTo("data");
+ }
+
+ @Test
+ public void fail_with_IAE_when_add_measure_is_called_on_metric_not_in_output_list() throws Exception {
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("Only metrics in [int_metric_key] can be used to add measures. Metric 'double_metric_key' is not allowed.");
+
+ MeasureComputerContextImpl underTest = newContext(PROJECT_REF, NCLOC_KEY, INT_METRIC_KEY);
+ underTest.addMeasure(DOUBLE_METRIC_KEY, 10);
+ }
+
+ @Test
+ public void fail_with_unsupported_operation_when_adding_measure_that_already_exists() throws Exception {
+ thrown.expect(UnsupportedOperationException.class);
+ thrown.expectMessage("A measure on metric 'int_metric_key' already exists on component 'fileKey'");
+
+ measureRepository.addRawMeasure(FILE_1_REF, INT_METRIC_KEY, newMeasureBuilder().create(20));
+
+ MeasureComputerContextImpl underTest = newContext(FILE_1_REF, NCLOC_KEY, INT_METRIC_KEY);
+ underTest.addMeasure(INT_METRIC_KEY, 10);
+ }
+
+ @Test
+ public void get_issues() throws Exception {
+ DefaultIssue issue = new DefaultIssue()
+ .setKey("KEY")
+ .setRuleKey(RuleKey.of("xoo", "S01"))
+ .setSeverity("MAJOR")
+ .setStatus("CLOSED")
+ .setResolution("FIXED")
+ .setDebt(Duration.create(10l));
+
+ MeasureComputerContextImpl underTest = newContext(PROJECT_REF, Arrays.asList(issue));
+
+ assertThat(underTest.getIssues()).hasSize(1);
+ org.sonar.api.ce.measure.Issue result = underTest.getIssues().get(0);
+ assertThat(result.key()).isEqualTo("KEY");
+ assertThat(result.ruleKey()).isEqualTo(RuleKey.of("xoo", "S01"));
+ assertThat(result.severity()).isEqualTo("MAJOR");
+ assertThat(result.status()).isEqualTo("CLOSED");
+ assertThat(result.resolution()).isEqualTo("FIXED");
+ assertThat(result.debt()).isEqualTo(Duration.create(10l));
+ }
+
+ private MeasureComputerContextImpl newContext(int componentRef) {
+ return newContext(componentRef, NCLOC_KEY, COMMENT_LINES_KEY, Collections.<DefaultIssue>emptyList());
+ }
+
+ private MeasureComputerContextImpl newContext(int componentRef, List<DefaultIssue> issues) {
+ return newContext(componentRef, NCLOC_KEY, COMMENT_LINES_KEY, issues);
+ }
+
+ private MeasureComputerContextImpl newContext(int componentRef, String inputMetric, String outputMetric) {
+ return newContext(componentRef, inputMetric, outputMetric, Collections.<DefaultIssue>emptyList());
+ }
+
+ private MeasureComputerContextImpl newContext(int componentRef, String inputMetric, String outputMetric, List<DefaultIssue> issues) {
+ componentIssuesRepository.setIssues(componentRef, issues);
+
+ MeasureComputer.MeasureComputerDefinition definition = new MeasureComputerDefinitionImpl.BuilderImpl()
+ .setInputMetrics(new String[] {inputMetric})
+ .setOutputMetrics(new String[] {outputMetric})
+ .build();
+
+ MeasureComputerContextImpl context = new MeasureComputerContextImpl(treeRootHolder.getComponentByRef(componentRef),
+ settingsRepository, measureRepository, metricRepository, componentIssuesRepository);
+ context.setDefinition(definition);
+ return context;
+ }
+}
--- /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.measure.api;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.sonar.api.ce.measure.MeasureComputer;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class MeasureComputerDefinitionImplTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ @Test
+ public void build_measure_computer_definition() throws Exception {
+ String inputMetric = "ncloc";
+ String outputMetric = "comment_density";
+ MeasureComputer.MeasureComputerDefinition measureComputer = new MeasureComputerDefinitionImpl.BuilderImpl()
+ .setInputMetrics(inputMetric)
+ .setOutputMetrics(outputMetric)
+ .build();
+
+ assertThat(measureComputer.getInputMetrics()).containsOnly(inputMetric);
+ assertThat(measureComputer.getOutputMetrics()).containsOnly(outputMetric);
+ }
+
+ @Test
+ public void build_measure_computer_with_multiple_metrics() throws Exception {
+ String[] inputMetrics = {"ncloc", "comment"};
+ String[] outputMetrics = {"comment_density_1", "comment_density_2"};
+ MeasureComputer.MeasureComputerDefinition measureComputer = new MeasureComputerDefinitionImpl.BuilderImpl()
+ .setInputMetrics(inputMetrics)
+ .setOutputMetrics(outputMetrics)
+ .build();
+
+ assertThat(measureComputer.getInputMetrics()).containsOnly(inputMetrics);
+ assertThat(measureComputer.getOutputMetrics()).containsOnly(outputMetrics);
+ }
+
+ @Test
+ public void input_metrics_can_be_empty() throws Exception {
+ MeasureComputer.MeasureComputerDefinition measureComputer = new MeasureComputerDefinitionImpl.BuilderImpl()
+ .setInputMetrics()
+ .setOutputMetrics("comment_density_1", "comment_density_2")
+ .build();
+
+ assertThat(measureComputer.getInputMetrics()).isEmpty();
+ }
+
+ @Test
+ public void input_metrics_is_empty_when_not_set() throws Exception {
+ MeasureComputer.MeasureComputerDefinition measureComputer = new MeasureComputerDefinitionImpl.BuilderImpl()
+ .setOutputMetrics("comment_density_1", "comment_density_2")
+ .build();
+
+ assertThat(measureComputer.getInputMetrics()).isEmpty();
+ }
+
+ @Test
+ public void fail_with_NPE_when_null_input_metrics() throws Exception {
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("Input metrics cannot be null");
+
+ new MeasureComputerDefinitionImpl.BuilderImpl()
+ .setInputMetrics(null)
+ .setOutputMetrics("comment_density_1", "comment_density_2");
+ }
+
+ @Test
+ public void fail_with_NPE_when_one_input_metric_is_null() throws Exception {
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("Null metric is not allowed");
+
+ new MeasureComputerDefinitionImpl.BuilderImpl()
+ .setInputMetrics("ncloc", null)
+ .setOutputMetrics("comment_density_1", "comment_density_2");
+ }
+
+ @Test
+ public void fail_with_NPE_when_no_output_metrics() throws Exception {
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("Output metrics cannot be null");
+
+ new MeasureComputerDefinitionImpl.BuilderImpl()
+ .setInputMetrics("ncloc", "comment")
+ .build();
+ }
+
+ @Test
+ public void fail_with_NPE_when_null_output_metrics() throws Exception {
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("Output metrics cannot be null");
+
+ new MeasureComputerDefinitionImpl.BuilderImpl()
+ .setInputMetrics("ncloc", "comment")
+ .setOutputMetrics(null);
+ }
+
+ @Test
+ public void fail_with_NPE_when_one_output_metric_is_null() throws Exception {
+ thrown.expect(NullPointerException.class);
+ thrown.expectMessage("Null metric is not allowed");
+
+ new MeasureComputerDefinitionImpl.BuilderImpl()
+ .setInputMetrics("ncloc", "comment")
+ .setOutputMetrics("comment_density_1", null);
+ }
+
+ @Test
+ public void fail_with_IAE_with_empty_output_metrics() throws Exception {
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("At least one output metric must be defined");
+
+ new MeasureComputerDefinitionImpl.BuilderImpl()
+ .setInputMetrics("ncloc", "comment")
+ .setOutputMetrics();
+ }
+
+ @Test
+ public void test_equals_and_hashcode() throws Exception {
+ MeasureComputer.MeasureComputerDefinition computer = new MeasureComputerDefinitionImpl.BuilderImpl()
+ .setInputMetrics("ncloc", "comment")
+ .setOutputMetrics("comment_density_1", "comment_density_2")
+ .build();
+
+ MeasureComputer.MeasureComputerDefinition sameComputer = new MeasureComputerDefinitionImpl.BuilderImpl()
+ .setInputMetrics("comment", "ncloc")
+ .setOutputMetrics("comment_density_2", "comment_density_1")
+ .build();
+
+ MeasureComputer.MeasureComputerDefinition anotherComputer = new MeasureComputerDefinitionImpl.BuilderImpl()
+ .setInputMetrics("comment")
+ .setOutputMetrics("debt")
+ .build();
+
+ assertThat(computer).isEqualTo(computer);
+ assertThat(computer).isEqualTo(sameComputer);
+ assertThat(computer).isNotEqualTo(anotherComputer);
+ assertThat(computer).isNotEqualTo(null);
+
+ assertThat(computer.hashCode()).isEqualTo(computer.hashCode());
+ assertThat(computer.hashCode()).isEqualTo(sameComputer.hashCode());
+ assertThat(computer.hashCode()).isNotEqualTo(anotherComputer.hashCode());
+ }
+
+ @Test
+ public void test_to_string() throws Exception {
+ assertThat(new MeasureComputerDefinitionImpl.BuilderImpl()
+ .setInputMetrics("ncloc", "comment")
+ .setOutputMetrics("comment_density_1", "comment_density_2")
+ .build().toString())
+ .isEqualTo("MeasureComputerDefinitionImpl{inputMetricKeys=[ncloc, comment], outputMetrics=[comment_density_1, comment_density_2]}");
+ }
+
+}
+++ /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.measure.api;
-
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.ce.measure.MeasureComputer;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class MeasureComputerImplTest {
-
- private static final MeasureComputer.Implementation DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION = new MeasureComputer.Implementation() {
- @Override
- public void compute(MeasureComputer.Implementation.Context ctx) {
- // Nothing here for this test
- }
-
- @Override
- public String toString() {
- return "Test implementation";
- }
- };
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- @Test
- public void build_measure_computer() throws Exception {
- String inputMetric = "ncloc";
- String outputMetric = "comment_density";
- MeasureComputer measureComputer = new MeasureComputerImpl.MeasureComputerBuilderImpl()
- .setInputMetrics(inputMetric)
- .setOutputMetrics(outputMetric)
- .setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION)
- .build();
-
- assertThat(measureComputer.getInputMetrics()).containsOnly(inputMetric);
- assertThat(measureComputer.getOutputMetrics()).containsOnly(outputMetric);
- assertThat(measureComputer.getImplementation()).isEqualTo(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION);
- }
-
- @Test
- public void build_measure_computer_with_multiple_metrics() throws Exception {
- String[] inputMetrics = {"ncloc", "comment"};
- String[] outputMetrics = {"comment_density_1", "comment_density_2"};
- MeasureComputer measureComputer = new MeasureComputerImpl.MeasureComputerBuilderImpl()
- .setInputMetrics(inputMetrics)
- .setOutputMetrics(outputMetrics)
- .setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION)
- .build();
-
- assertThat(measureComputer.getInputMetrics()).containsOnly(inputMetrics);
- assertThat(measureComputer.getOutputMetrics()).containsOnly(outputMetrics);
- assertThat(measureComputer.getImplementation()).isEqualTo(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION);
- }
-
- @Test
- public void input_metrics_can_be_empty() throws Exception {
- MeasureComputer measureComputer = new MeasureComputerImpl.MeasureComputerBuilderImpl()
- .setInputMetrics()
- .setOutputMetrics("comment_density_1", "comment_density_2")
- .setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION)
- .build();
-
- assertThat(measureComputer.getInputMetrics()).isEmpty();
- }
-
- @Test
- public void input_metrics_is_empty_when_not_set() throws Exception {
- MeasureComputer measureComputer = new MeasureComputerImpl.MeasureComputerBuilderImpl()
- .setOutputMetrics("comment_density_1", "comment_density_2")
- .setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION)
- .build();
-
- assertThat(measureComputer.getInputMetrics()).isEmpty();
- }
-
- @Test
- public void fail_with_NPE_when_null_input_metrics() throws Exception {
- thrown.expect(NullPointerException.class);
- thrown.expectMessage("Input metrics cannot be null");
-
- new MeasureComputerImpl.MeasureComputerBuilderImpl()
- .setInputMetrics(null)
- .setOutputMetrics("comment_density_1", "comment_density_2")
- .setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION);
- }
-
- @Test
- public void fail_with_NPE_when_one_input_metric_is_null() throws Exception {
- thrown.expect(NullPointerException.class);
- thrown.expectMessage("Null metric is not allowed");
-
- new MeasureComputerImpl.MeasureComputerBuilderImpl()
- .setInputMetrics("ncloc", null)
- .setOutputMetrics("comment_density_1", "comment_density_2")
- .setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION);
- }
-
- @Test
- public void fail_with_IAE_when_no_output_metrics() throws Exception {
- thrown.expect(IllegalArgumentException.class);
- thrown.expectMessage("At least one output metric must be defined");
-
- new MeasureComputerImpl.MeasureComputerBuilderImpl()
- .setInputMetrics("ncloc", "comment")
- .setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION)
- .build();
- }
-
- @Test
- public void fail_with_IAE_when_null_output_metrics() throws Exception {
- thrown.expect(IllegalArgumentException.class);
- thrown.expectMessage("At least one output metric must be defined");
-
- new MeasureComputerImpl.MeasureComputerBuilderImpl()
- .setInputMetrics("ncloc", "comment")
- .setOutputMetrics(null)
- .setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION);
- }
-
- @Test
- public void fail_with_NPE_when_one_output_metric_is_null() throws Exception {
- thrown.expect(NullPointerException.class);
- thrown.expectMessage("Null metric is not allowed");
-
- new MeasureComputerImpl.MeasureComputerBuilderImpl()
- .setInputMetrics("ncloc", "comment")
- .setOutputMetrics("comment_density_1", null)
- .setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION);
- }
-
- @Test
- public void fail_with_IAE_with_empty_output_metrics() throws Exception {
- thrown.expect(IllegalArgumentException.class);
- thrown.expectMessage("At least one output metric must be defined");
-
- new MeasureComputerImpl.MeasureComputerBuilderImpl()
- .setInputMetrics("ncloc", "comment")
- .setOutputMetrics()
- .setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION);
- }
-
- @Test
- public void fail_with_IAE_when_no_implementation() throws Exception {
- thrown.expect(NullPointerException.class);
- thrown.expectMessage("The implementation is missing");
-
- new MeasureComputerImpl.MeasureComputerBuilderImpl()
- .setInputMetrics("ncloc", "comment")
- .setOutputMetrics("comment_density_1", "comment_density_2")
- .build();
- }
-
- @Test
- public void fail_with_IAE_when_null_implementation() throws Exception {
- thrown.expect(NullPointerException.class);
- thrown.expectMessage("The implementation is missing");
-
- new MeasureComputerImpl.MeasureComputerBuilderImpl()
- .setInputMetrics("ncloc", "comment")
- .setOutputMetrics("comment_density_1", "comment_density_2")
- .setImplementation(null);
- }
-
- @Test
- public void test_equals_and_hashcode() throws Exception {
- MeasureComputer computer = new MeasureComputerImpl.MeasureComputerBuilderImpl()
- .setInputMetrics("ncloc", "comment")
- .setOutputMetrics("comment_density_1", "comment_density_2")
- .setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION)
- .build();
-
- MeasureComputer sameComputer = new MeasureComputerImpl.MeasureComputerBuilderImpl()
- .setInputMetrics("comment", "ncloc")
- .setOutputMetrics("comment_density_2", "comment_density_1")
- .setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION)
- .build();
-
- MeasureComputer anotherComputer = new MeasureComputerImpl.MeasureComputerBuilderImpl()
- .setInputMetrics("comment")
- .setOutputMetrics("debt")
- .setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION)
- .build();
-
- assertThat(computer).isEqualTo(computer);
- assertThat(computer).isEqualTo(sameComputer);
- assertThat(computer).isNotEqualTo(anotherComputer);
- assertThat(computer).isNotEqualTo(null);
-
- assertThat(computer.hashCode()).isEqualTo(computer.hashCode());
- assertThat(computer.hashCode()).isEqualTo(sameComputer.hashCode());
- assertThat(computer.hashCode()).isNotEqualTo(anotherComputer.hashCode());
- }
-
- @Test
- public void test_to_string() throws Exception {
- assertThat(new MeasureComputerImpl.MeasureComputerBuilderImpl()
- .setInputMetrics("ncloc", "comment")
- .setOutputMetrics("comment_density_1", "comment_density_2")
- .setImplementation(DEFAULT_MEASURE_COMPUTER_IMPLEMENTATION)
- .build().toString())
- .isEqualTo("MeasureComputerImpl{inputMetricKeys=[ncloc, comment], outputMetrics=[comment_density_1, comment_density_2], implementation=Test implementation}");
- }
-}
+++ /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.measure.api;
-
-import com.google.common.base.Optional;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
-import java.util.Set;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.ce.measure.Component;
-import org.sonar.api.ce.measure.MeasureComputer;
-import org.sonar.api.measures.CoreMetrics;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.Duration;
-import org.sonar.core.issue.DefaultIssue;
-import org.sonar.server.computation.batch.TreeRootHolderRule;
-import org.sonar.server.computation.component.SettingsRepository;
-import org.sonar.server.computation.issue.ComponentIssuesRepositoryRule;
-import org.sonar.server.computation.measure.Measure;
-import org.sonar.server.computation.measure.MeasureRepositoryRule;
-import org.sonar.server.computation.metric.Metric;
-import org.sonar.server.computation.metric.MetricImpl;
-import org.sonar.server.computation.metric.MetricRepositoryRule;
-
-import static com.google.common.collect.ImmutableSet.of;
-import static org.assertj.core.api.Assertions.assertThat;
-import static org.assertj.guava.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
-import static org.sonar.api.measures.CoreMetrics.COMMENT_LINES_KEY;
-import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
-import static org.sonar.server.computation.component.ReportComponent.builder;
-import static org.sonar.server.computation.measure.Measure.newMeasureBuilder;
-
-public class MeasureComputerImplementationContextTest {
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- private static final String INT_METRIC_KEY = "int_metric_key";
- private static final String DOUBLE_METRIC_KEY = "double_metric_key";
- private static final String LONG_METRIC_KEY = "long_metric_key";
- private static final String STRING_METRIC_KEY = "string_metric_key";
-
- private static final int PROJECT_REF = 1;
- private static final int FILE_1_REF = 12341;
- private static final String FILE_1_KEY = "fileKey";
- private static final int FILE_2_REF = 12342;
-
- private static final org.sonar.server.computation.component.Component FILE_1 = builder(org.sonar.server.computation.component.Component.Type.FILE, FILE_1_REF)
- .setKey(FILE_1_KEY)
- .build();
-
- @Rule
- public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule()
- .setRoot(builder(org.sonar.server.computation.component.Component.Type.PROJECT, PROJECT_REF).setKey("project")
- .addChildren(
- FILE_1,
- builder(org.sonar.server.computation.component.Component.Type.FILE, FILE_2_REF).setKey("fileKey2").build()
- ).build());
-
- @Rule
- public MetricRepositoryRule metricRepository = new MetricRepositoryRule()
- .add(1, CoreMetrics.NCLOC)
- .add(new MetricImpl(2, INT_METRIC_KEY, "int metric", Metric.MetricType.INT))
- .add(new MetricImpl(3, DOUBLE_METRIC_KEY, "double metric", Metric.MetricType.FLOAT))
- .add(new MetricImpl(4, LONG_METRIC_KEY, "long metric", Metric.MetricType.MILLISEC))
- .add(new MetricImpl(5, STRING_METRIC_KEY, "string metric", Metric.MetricType.STRING));
-
- @Rule
- public MeasureRepositoryRule measureRepository = MeasureRepositoryRule.create(treeRootHolder, metricRepository);
-
- @Rule
- public ComponentIssuesRepositoryRule componentIssuesRepository = new ComponentIssuesRepositoryRule(treeRootHolder);
-
- SettingsRepository settingsRepository = mock(SettingsRepository.class);
-
- @Test
- public void get_component() throws Exception {
- MeasureComputer.Implementation.Context underTest = newContext(FILE_1_REF);
- assertThat(underTest.getComponent().getType()).isEqualTo(Component.Type.FILE);
- }
-
- @Test
- public void get_string_settings() throws Exception {
- org.sonar.api.config.Settings serverSettings = new org.sonar.api.config.Settings();
- serverSettings.setProperty("prop", "value");
- when(settingsRepository.getSettings(FILE_1)).thenReturn(serverSettings);
-
- MeasureComputer.Implementation.Context underTest = newContext(FILE_1_REF);
- assertThat(underTest.getSettings().getString("prop")).isEqualTo("value");
- assertThat(underTest.getSettings().getString("unknown")).isNull();
- }
-
- @Test
- public void get_string_array_settings() throws Exception {
- org.sonar.api.config.Settings serverSettings = new org.sonar.api.config.Settings();
- serverSettings.setProperty("prop", "1,3.4,8,50");
- when(settingsRepository.getSettings(FILE_1)).thenReturn(serverSettings);
-
- MeasureComputer.Implementation.Context underTest = newContext(FILE_1_REF);
- assertThat(underTest.getSettings().getStringArray("prop")).containsExactly("1", "3.4", "8", "50");
- assertThat(underTest.getSettings().getStringArray("unknown")).isEmpty();
- }
-
- @Test
- public void get_measure() throws Exception {
- measureRepository.addRawMeasure(FILE_1_REF, NCLOC_KEY, newMeasureBuilder().create(10));
-
- MeasureComputer.Implementation.Context underTest = newContext(FILE_1_REF, of(NCLOC_KEY), of(COMMENT_LINES_KEY));
- assertThat(underTest.getMeasure(NCLOC_KEY).getIntValue()).isEqualTo(10);
- }
-
- @Test
- public void fail_with_IAE_when_get_measure_is_called_on_metric_not_in_input_list() throws Exception {
- thrown.expect(IllegalArgumentException.class);
- thrown.expectMessage("Only metrics in [another metric] can be used to load measures");
-
- MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of("another metric"), of("debt"));
- underTest.getMeasure(NCLOC_KEY);
- }
-
- @Test
- public void get_children_measures() throws Exception {
- measureRepository.addRawMeasure(FILE_1_REF, NCLOC_KEY, newMeasureBuilder().create(10));
- measureRepository.addRawMeasure(FILE_2_REF, NCLOC_KEY, newMeasureBuilder().create(12));
-
- MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of(NCLOC_KEY), of(COMMENT_LINES_KEY));
- assertThat(underTest.getChildrenMeasures(NCLOC_KEY)).hasSize(2);
- assertThat(underTest.getChildrenMeasures(NCLOC_KEY)).extracting("intValue").containsOnly(10, 12);
- }
-
- @Test
- public void get_children_measures_when_one_child_has_no_value() throws Exception {
- measureRepository.addRawMeasure(FILE_1_REF, NCLOC_KEY, newMeasureBuilder().create(10));
- // No data on file 2
-
- MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of(NCLOC_KEY), of(COMMENT_LINES_KEY));
- assertThat(underTest.getChildrenMeasures(NCLOC_KEY)).extracting("intValue").containsOnly(10);
- }
-
- @Test
- public void not_fail_to_get_children_measures_on_output_metric() throws Exception {
- measureRepository.addRawMeasure(FILE_1_REF, INT_METRIC_KEY, newMeasureBuilder().create(10));
-
- MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of(NCLOC_KEY), of(INT_METRIC_KEY));
- assertThat(underTest.getChildrenMeasures(INT_METRIC_KEY)).hasSize(1);
- assertThat(underTest.getChildrenMeasures(INT_METRIC_KEY)).extracting("intValue").containsOnly(10);
- }
-
- @Test
- public void fail_with_IAE_when_get_children_measures_is_called_on_metric_not_in_input_list() throws Exception {
- thrown.expect(IllegalArgumentException.class);
- thrown.expectMessage("Only metrics in [another metric] can be used to load measures");
-
- MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of("another metric"), of("debt"));
- underTest.getChildrenMeasures(NCLOC_KEY);
- }
-
- @Test
- public void add_int_measure_create_measure_of_type_int_with_right_value() throws Exception {
- MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of(NCLOC_KEY), of(INT_METRIC_KEY));
- underTest.addMeasure(INT_METRIC_KEY, 10);
-
- Optional<Measure> measure = measureRepository.getAddedRawMeasure(PROJECT_REF, INT_METRIC_KEY);
- assertThat(measure).isPresent();
- assertThat(measure.get().getIntValue()).isEqualTo(10);
- }
-
- @Test
- public void add_double_measure_create_measure_of_type_double_with_right_value() throws Exception {
- MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of(NCLOC_KEY), of(DOUBLE_METRIC_KEY));
- underTest.addMeasure(DOUBLE_METRIC_KEY, 10d);
-
- Optional<Measure> measure = measureRepository.getAddedRawMeasure(PROJECT_REF, DOUBLE_METRIC_KEY);
- assertThat(measure).isPresent();
- assertThat(measure.get().getDoubleValue()).isEqualTo(10d);
- }
-
- @Test
- public void add_long_measure_create_measure_of_type_long_with_right_value() throws Exception {
- MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of(NCLOC_KEY), of(LONG_METRIC_KEY));
- underTest.addMeasure(LONG_METRIC_KEY, 10L);
-
- Optional<Measure> measure = measureRepository.getAddedRawMeasure(PROJECT_REF, LONG_METRIC_KEY);
- assertThat(measure).isPresent();
- assertThat(measure.get().getLongValue()).isEqualTo(10L);
- }
-
- @Test
- public void add_string_measure_create_measure_of_type_string_with_right_value() throws Exception {
- MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of(NCLOC_KEY), of(STRING_METRIC_KEY));
- underTest.addMeasure(STRING_METRIC_KEY, "data");
-
- Optional<Measure> measure = measureRepository.getAddedRawMeasure(PROJECT_REF, STRING_METRIC_KEY);
- assertThat(measure).isPresent();
- assertThat(measure.get().getStringValue()).isEqualTo("data");
- }
-
- @Test
- public void fail_with_IAE_when_add_measure_is_called_on_metric_not_in_output_list() throws Exception {
- thrown.expect(IllegalArgumentException.class);
- thrown.expectMessage("Only metrics in [int_metric_key] can be used to add measures. Metric 'double_metric_key' is not allowed.");
-
- MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, of(NCLOC_KEY), of(INT_METRIC_KEY));
- underTest.addMeasure(DOUBLE_METRIC_KEY, 10);
- }
-
- @Test
- public void fail_with_unsupported_operation_when_adding_measure_that_already_exists() throws Exception {
- thrown.expect(UnsupportedOperationException.class);
- thrown.expectMessage("A measure on metric 'int_metric_key' already exists on component 'fileKey'");
-
- measureRepository.addRawMeasure(FILE_1_REF, INT_METRIC_KEY, newMeasureBuilder().create(20));
-
- MeasureComputer.Implementation.Context underTest = newContext(FILE_1_REF, of(NCLOC_KEY), of(INT_METRIC_KEY));
- underTest.addMeasure(INT_METRIC_KEY, 10);
- }
-
- @Test
- public void get_issues() throws Exception {
- DefaultIssue issue = new DefaultIssue()
- .setKey("KEY")
- .setRuleKey(RuleKey.of("xoo", "S01"))
- .setSeverity("MAJOR")
- .setStatus("CLOSED")
- .setResolution("FIXED")
- .setDebt(Duration.create(10l));
-
- MeasureComputer.Implementation.Context underTest = newContext(PROJECT_REF, Arrays.asList(issue));
-
- assertThat(underTest.getIssues()).hasSize(1);
- org.sonar.api.ce.measure.Issue result = underTest.getIssues().get(0);
- assertThat(result.key()).isEqualTo("KEY");
- assertThat(result.ruleKey()).isEqualTo(RuleKey.of("xoo", "S01"));
- assertThat(result.severity()).isEqualTo("MAJOR");
- assertThat(result.status()).isEqualTo("CLOSED");
- assertThat(result.resolution()).isEqualTo("FIXED");
- assertThat(result.debt()).isEqualTo(Duration.create(10l));
- }
-
- private MeasureComputer.Implementation.Context newContext(int componentRef) {
- return newContext(componentRef, Collections.<String>emptySet(), Collections.<String>emptySet());
- }
-
- private MeasureComputer.Implementation.Context newContext(int componentRef, List<DefaultIssue> issues) {
- return newContext(componentRef, Collections.<String>emptySet(), Collections.<String>emptySet(), issues);
- }
-
- private MeasureComputer.Implementation.Context newContext(int componentRef, final Set<String> inputMetrics, final Set<String> outputMetrics) {
- return newContext(componentRef, inputMetrics, outputMetrics, Collections.<DefaultIssue>emptyList());
- }
-
- private MeasureComputer.Implementation.Context newContext(int componentRef, final Set<String> inputMetrics, final Set<String> outputMetrics, List<DefaultIssue> issues) {
- componentIssuesRepository.setIssues(componentRef, issues);
- MeasureComputer measureComputer = new MeasureComputer() {
- @Override
- public Set<String> getInputMetrics() {
- return inputMetrics;
- }
-
- @Override
- public Set<String> getOutputMetrics() {
- return outputMetrics;
- }
-
- @Override
- public Implementation getImplementation() {
- return null;
- }
- };
- return new MeasureComputerImplementationContext(treeRootHolder.getComponentByRef(componentRef), measureComputer,
- settingsRepository, measureRepository, metricRepository, componentIssuesRepository);
- }
-}
+++ /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.measure.api;
-
-import com.google.common.collect.ImmutableSet;
-import java.util.Collections;
-import java.util.Set;
-import org.junit.Rule;
-import org.junit.Test;
-import org.junit.rules.ExpectedException;
-import org.sonar.api.ce.measure.MeasureComputer;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-public class MeasureComputerProviderContextTest {
-
- @Rule
- public ExpectedException thrown = ExpectedException.none();
-
- MeasureComputerProviderContext underTest = new MeasureComputerProviderContext();
-
- @Test
- public void return_empty_list() throws Exception {
- assertThat(underTest.getMeasureComputers()).isEmpty();
- }
-
- @Test
- public void add_measure_computer() throws Exception {
- underTest.add(newMeasureComputer("debt_density"));
-
- assertThat(underTest.getMeasureComputers()).hasSize(1);
- }
-
- @Test
- public void add_measure_computers_sharing_same_input_metrics() throws Exception {
- underTest.add(newMeasureComputer(new String[]{"ncloc"}, new String[]{"debt_density"}));
- underTest.add(newMeasureComputer(new String[]{"ncloc"}, new String[]{"comment"}));
-
- assertThat(underTest.getMeasureComputers()).hasSize(2);
- }
-
- @Test
- public void fail_with_unsupported_operation_exception_when_output_metric_have_already_been_registered() throws Exception {
- thrown.expect(UnsupportedOperationException.class);
- thrown.expectMessage("The output metric 'debt_density' is already declared by another computer. This computer has these input metrics '[ncloc, debt]' and these output metrics '[debt_by_line, debt_density]");
-
- underTest.add(newMeasureComputer("debt_by_line","debt_density"));
- underTest.add(newMeasureComputer("total_debt", "debt_density"));
- }
-
- @Test
- public void fail_with_unsupported_operation_exception_when_multiple_output_metrics_have_already_been_registered() throws Exception {
- thrown.expect(UnsupportedOperationException.class);
- thrown.expectMessage("The output metric 'debt_density' is already declared by another computer. This computer has these input metrics '[ncloc, debt]' and these output metrics '[debt_density]'. " +
- "The output metric 'debt_by_line' is already declared by another computer. This computer has these input metrics '[ncloc, debt]' and these output metrics '[debt_by_line]");
-
- underTest.add(newMeasureComputer("debt_by_line"));
- underTest.add(newMeasureComputer("debt_density"));
- underTest.add(newMeasureComputer("debt_by_line", "debt_density"));
- }
-
- @Test
- public void create_measure_computer_without_using_the_builder() throws Exception {
- // Create a instance of MeasureComputer without using the builder
- MeasureComputer measureComputer = new MeasureComputer() {
- @Override
- public Set<String> getInputMetrics() {
- return ImmutableSet.of("ncloc", "debt");
- }
-
- @Override
- public Set<String> getOutputMetrics() {
- return ImmutableSet.of("debt_density");
- }
-
- @Override
- public Implementation getImplementation() {
- return new MeasureComputer.Implementation() {
- @Override
- public void compute(Context ctx) {
- }
- };
- }
- };
-
- underTest.add(measureComputer);
- assertThat(underTest.getMeasureComputers()).hasSize(1);
- }
-
- @Test
- public void fail_with_IAE_when_creating_measure_computer_without_using_the_builder_but_with_invalid_output_metrics() throws Exception {
- thrown.expect(IllegalArgumentException.class);
- thrown.expectMessage("At least one output metric must be defined");
-
- MeasureComputer measureComputer = new MeasureComputer() {
- @Override
- public Set<String> getInputMetrics() {
- return ImmutableSet.of("ncloc", "debt");
- }
-
- @Override
- public Set<String> getOutputMetrics() {
- return Collections.emptySet();
- }
-
- @Override
- public Implementation getImplementation() {
- return new MeasureComputer.Implementation() {
- @Override
- public void compute(Context ctx) {}
- };
- }
- };
-
- underTest.add(measureComputer);
- }
-
- private MeasureComputer newMeasureComputer(String... outputMetrics) {
- return newMeasureComputer(new String[]{"ncloc", "debt"}, outputMetrics);
- }
-
- private MeasureComputer newMeasureComputer(String[] inputMetrics, String[] outputMetrics) {
- return new MeasureComputerImpl.MeasureComputerBuilderImpl()
- .setInputMetrics(inputMetrics)
- .setOutputMetrics(outputMetrics)
- .setImplementation(new MeasureComputer.Implementation() {
- @Override
- public void compute(Context ctx) {
- // Nothing to do here for this test
- }
- })
- .build();
- }
-
-}
package org.sonar.server.computation.step;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
+import java.util.Collections;
import java.util.List;
+import java.util.Set;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.ce.measure.MeasureComputer;
-import org.sonar.api.ce.measure.MeasureComputerProvider;
-import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Metric;
import org.sonar.api.measures.Metrics;
import org.sonar.server.computation.measure.MeasureComputersHolderImpl;
+import org.sonar.server.computation.measure.api.MeasureComputerWrapper;
import static com.google.common.collect.Lists.newArrayList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.util.Arrays.array;
-import static org.mockito.Mockito.mock;
+import static org.sonar.api.measures.CoreMetrics.NCLOC_KEY;
import static org.sonar.api.measures.Metric.ValueType.DATA;
import static org.sonar.api.measures.Metric.ValueType.FLOAT;
import static org.sonar.api.measures.Metric.ValueType.INT;
@Test
public void support_core_metrics_as_input_metrics() throws Exception {
- MeasureComputer.Implementation implementation = mock(MeasureComputer.Implementation.class);
- MeasureComputerProvider[] providers = new MeasureComputerProvider[] {
- new NewMeasureComputerProvider(
- array(CoreMetrics.NCLOC_KEY),
- array(NEW_METRIC_1),
- implementation),
- };
- ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), providers);
+ MeasureComputer[] computers = new MeasureComputer[] {newMeasureComputer(array(NCLOC_KEY), array(NEW_METRIC_1))};
+ ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), computers);
underTest.execute();
assertThat(holder.getMeasureComputers()).hasSize(1);
@Test
public void support_plugin_metrics_as_input_metrics() throws Exception {
- MeasureComputer.Implementation implementation = mock(MeasureComputer.Implementation.class);
- MeasureComputerProvider[] providers = new MeasureComputerProvider[] {
- new NewMeasureComputerProvider(
- array(NEW_METRIC_1),
- array(NEW_METRIC_2),
- implementation),
- };
- ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), providers);
+ MeasureComputer[] computers = new MeasureComputer[] {newMeasureComputer(array(NEW_METRIC_1), array(NEW_METRIC_2))};
+ ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), computers);
underTest.execute();
assertThat(holder.getMeasureComputers()).hasSize(1);
@Test
public void sort_computers() throws Exception {
- MeasureComputer.Implementation implementation1 = mock(MeasureComputer.Implementation.class);
- MeasureComputer.Implementation implementation2 = mock(MeasureComputer.Implementation.class);
- MeasureComputer.Implementation implementation3 = mock(MeasureComputer.Implementation.class);
-
- MeasureComputerProvider[] providers = new MeasureComputerProvider[] {
- // Should be the last to be executed
- new NewMeasureComputerProvider(
- array(NEW_METRIC_3),
- array(NEW_METRIC_4),
- implementation3),
- // Should be the first to be executed
- new NewMeasureComputerProvider(
- array(NEW_METRIC_1),
- array(NEW_METRIC_2),
- implementation1),
- // Should be the second to be executed
- new NewMeasureComputerProvider(
- array(NEW_METRIC_2),
- array(NEW_METRIC_3),
- implementation2)
- };
+ // Should be the last to be executed
+ MeasureComputer measureComputer1 = newMeasureComputer(array(NEW_METRIC_3), array(NEW_METRIC_4));
+ // Should be the first to be executed
+ MeasureComputer measureComputer2 = newMeasureComputer(array(NEW_METRIC_1), array(NEW_METRIC_2));
+ // Should be the second to be executed
+ MeasureComputer measureComputer3 = newMeasureComputer(array(NEW_METRIC_2), array(NEW_METRIC_3));
+ MeasureComputer[] computers = new MeasureComputer[] {measureComputer1, measureComputer2, measureComputer3};
+
+ ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), computers);
+ underTest.execute();
+
+ List<MeasureComputerWrapper> result = newArrayList(holder.getMeasureComputers());
+ assertThat(result).hasSize(3);
+ assertThat(result.get(0).getComputer()).isEqualTo(measureComputer2);
+ assertThat(result.get(1).getComputer()).isEqualTo(measureComputer3);
+ assertThat(result.get(2).getComputer()).isEqualTo(measureComputer1);
+ }
- ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), providers);
+ @Test
+ public void sort_computers_when_one_computer_has_no_input_metric() throws Exception {
+ // Should be the last to be executed
+ MeasureComputer measureComputer1 = newMeasureComputer(array(NEW_METRIC_3), array(NEW_METRIC_4));
+ // Should be the first to be executed
+ MeasureComputer measureComputer2 = newMeasureComputer(new String[] {}, array(NEW_METRIC_2));
+ // Should be the second to be executed
+ MeasureComputer measureComputer3 = newMeasureComputer(array(NEW_METRIC_2), array(NEW_METRIC_3));
+ MeasureComputer[] computers = new MeasureComputer[] {measureComputer1, measureComputer2, measureComputer3};
+
+ ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), computers);
underTest.execute();
- List<MeasureComputer> computers = newArrayList(holder.getMeasureComputers());
- assertThat(computers).hasSize(3);
- assertThat(computers.get(0).getImplementation()).isEqualTo(implementation1);
- assertThat(computers.get(1).getImplementation()).isEqualTo(implementation2);
- assertThat(computers.get(2).getImplementation()).isEqualTo(implementation3);
+ List<MeasureComputerWrapper> result = newArrayList(holder.getMeasureComputers());
+ assertThat(result).hasSize(3);
+ assertThat(result.get(0).getComputer()).isEqualTo(measureComputer2);
+ assertThat(result.get(1).getComputer()).isEqualTo(measureComputer3);
+ assertThat(result.get(2).getComputer()).isEqualTo(measureComputer1);
}
@Test
public void fail_with_ISE_when_input_metric_is_unknown() throws Exception {
thrown.expect(IllegalStateException.class);
- thrown.expectMessage("Metric 'unknown' cannot be used as an input metric as it's no a core metric and no plugin declare this metric");
+ thrown.expectMessage("Metric 'unknown' cannot be used as an input metric as it's not a core metric and no plugin declare this metric");
- MeasureComputerProvider[] providers = new MeasureComputerProvider[] {
- new NewMeasureComputerProvider(
- array("unknown"),
- array(NEW_METRIC_4),
- mock(MeasureComputer.Implementation.class)),
- };
+ MeasureComputer[] computers = new MeasureComputer[] {newMeasureComputer(array("unknown"), array(NEW_METRIC_4))};
+ ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), computers);
+ underTest.execute();
+ }
- ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), providers);
+ @Test
+ public void fail_with_ISE_when_output_metric_is_not_define_by_plugin() throws Exception {
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("Metric 'unknown' cannot be used as an output metric as no plugin declare this metric");
+
+ MeasureComputer[] computers = new MeasureComputer[] {newMeasureComputer(array(NEW_METRIC_4), array("unknown"))};
+ ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), computers);
+ underTest.execute();
+ }
+
+ @Test
+ public void fail_with_ISE_when_output_metric_is_a_core_metric() throws Exception {
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("Metric 'ncloc' cannot be used as an output metric as it's a core metric");
+
+ MeasureComputer[] computers = new MeasureComputer[] {newMeasureComputer(array(NEW_METRIC_4), array(NCLOC_KEY))};
+ ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), computers);
underTest.execute();
}
@Test
public void not_fail_if_input_metrics_are_same_as_output_metrics() throws Exception {
- MeasureComputer.Implementation implementation = mock(MeasureComputer.Implementation.class);
- MeasureComputerProvider[] providers = new MeasureComputerProvider[] {
- new NewMeasureComputerProvider(
- array(NEW_METRIC_1),
- array(NEW_METRIC_1),
- implementation),
- };
- ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), providers);
+ MeasureComputer[] computers = new MeasureComputer[] {newMeasureComputer(array(NEW_METRIC_1), array(NEW_METRIC_1))};
+ ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), computers);
underTest.execute();
assertThat(holder.getMeasureComputers()).hasSize(1);
assertThat(holder.getMeasureComputers()).isEmpty();
}
- @Test
- public void support_no_plugin_metrics() throws Exception {
- MeasureComputer.Implementation implementation = mock(MeasureComputer.Implementation.class);
- MeasureComputerProvider[] providers = new MeasureComputerProvider[] {
- new NewMeasureComputerProvider(
- array(CoreMetrics.NCLOC_KEY),
- array(CoreMetrics.COMMENT_LINES_KEY),
- implementation),
- };
- ComputationStep underTest = new FeedMeasureComputers(holder, providers);
- underTest.execute();
-
- assertThat(holder.getMeasureComputers()).hasSize(1);
- }
-
@Test
public void return_empty_list_when_no_metrics_neither_measure_computers() throws Exception {
ComputationStep underTest = new FeedMeasureComputers(holder);
assertThat(holder.getMeasureComputers()).isEmpty();
}
- private static class NewMeasureComputerProvider implements MeasureComputerProvider {
+ @Test
+ public void fail_with_ISE_when_no_metrics_are_defined_by_plugin_but_measure_computer_use_a_new_metric() throws Exception {
+ thrown.expect(IllegalStateException.class);
+ thrown.expectMessage("Metric 'metric1' cannot be used as an output metric as no plugin declare this metric");
+
+ MeasureComputer[] computers = new MeasureComputer[] {newMeasureComputer(array(NCLOC_KEY), array(NEW_METRIC_1))};
+ ComputationStep underTest = new FeedMeasureComputers(holder, computers);
+ underTest.execute();
+ }
- private final String[] inputMetrics;
- private final String[] outputMetrics;
- private final MeasureComputer.Implementation measureComputerImplementation;
+ @Test
+ public void fail_with_IAE_when_creating_measure_computer_definition_without_using_the_builder_and_with_invalid_output_metrics() throws Exception {
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("At least one output metric must be defined");
+
+ MeasureComputer measureComputer = new MeasureComputer() {
+ @Override
+ public MeasureComputerDefinition define(MeasureComputerDefinitionContext defContext) {
+ // Create a instance of MeasureComputerDefinition without using the builder
+ return new MeasureComputer.MeasureComputerDefinition(){
+ @Override
+ public Set<String> getInputMetrics() {
+ return ImmutableSet.of(NCLOC_KEY);
+ }
+
+ @Override
+ public Set<String> getOutputMetrics() {
+ // Empty output metric is not allowed !
+ return Collections.emptySet();
+ }
+ };
+ }
+
+ @Override
+ public void compute(MeasureComputerContext context) {
+ // Nothing needs to be done as we're only testing metada
+ }
+ };
- public NewMeasureComputerProvider(String[] inputMetrics, String[] outputMetrics, MeasureComputer.Implementation measureComputerImplementation) {
- this.inputMetrics = inputMetrics;
- this.outputMetrics = outputMetrics;
- this.measureComputerImplementation = measureComputerImplementation;
- }
+ MeasureComputer[] computers = new MeasureComputer[] {measureComputer};
+ ComputationStep underTest = new FeedMeasureComputers(holder, array(new TestMetrics()), computers);
+ underTest.execute();
+ }
- @Override
- public void register(Context ctx) {
- ctx.add(ctx.newMeasureComputerBuilder()
- .setInputMetrics(inputMetrics)
- .setOutputMetrics(outputMetrics)
- .setImplementation(measureComputerImplementation)
- .build());
- }
+ private static MeasureComputer newMeasureComputer(final String[] inputMetrics, final String[] outputMetrics) {
+ return new MeasureComputer() {
+ @Override
+ public MeasureComputerDefinition define(MeasureComputerDefinitionContext defContext) {
+ return defContext.newDefinitionBuilder()
+ .setInputMetrics(inputMetrics)
+ .setOutputMetrics(outputMetrics)
+ .build();
+ }
+
+ @Override
+ public void compute(MeasureComputerContext context) {
+ // Nothing needs to be done as we're only testing metada
+ }
+ };
}
private static class TestMetrics implements Metrics {
/**
* @since 1.10
- * @deprecated since 5.2 there's no more decorator on batch side
- * TODO add link to new API
+ * @deprecated since 5.2 there's no more decorator on batch side. Use {@link org.sonar.api.ce.measure.MeasureComputer} instead
*/
@BatchSide
@ExtensionPoint
import javax.annotation.CheckForNull;
+/**
+ * Component that can be used in a {@link MeasureComputer}
+ *
+ * @since 5.2
+ */
public interface Component {
enum Type {
import org.sonar.api.rule.RuleKey;
import org.sonar.api.utils.Duration;
+/**
+ * Issue that can be used in a {@link MeasureComputer}
+ *
+ * @since 5.2
+ */
public interface Issue {
String key();
package org.sonar.api.ce.measure;
+/**
+ * Measure used in {@link MeasureComputer}
+ *
+ * @since 5.2
+ */
public interface Measure {
/**
import java.util.List;
import java.util.Set;
import javax.annotation.CheckForNull;
+import org.sonar.api.ExtensionPoint;
+import org.sonar.api.ce.measure.MeasureComputer.MeasureComputerDefinition.Builder;
+import org.sonar.api.server.ServerSide;
/**
- * This class is used to define which metrics are required to compute some measures on some given metrics, and to define the implementation of the measures computation
+ * Define how to compute new measures on some metrics declared by {@link org.sonar.api.measures.Metrics}.
+ * <p/>
+ * This interface replaces the deprecated class org.sonar.api.batch.Decorator.
+ * <p/>
+ * <h3>How to use</h3>
+ * <pre>
+ * public class MyMeasureComputer implements MeasureComputer {
+ *
+ * {@literal @}Override
+ * public MeasureComputerDefinition define(MeasureComputerDefinitionContext defContext) {
+ * return defContext.newDefinitionBuilder()
+ *
+ * // Input metrics can be empty, for instance if only issues will be read
+ * .setInputMetrics("ncloc")
+ *
+ * // Output metrics must contains at least one metric
+ * .setOutputMetrics("my_new_metric")
+ *
+ * .build();
+ * }
+ *
+ * {@literal @}Override
+ * public void compute(MeasureComputerContext context) {
+ * int ncloc = context.getMeasure("ncloc");
+ * List<Issue> issues = context.getIssues();
+ * if (ncloc != null && !issues.isEmpty()) {
+ * double value = issues.size() / ncloc;
+ * context.addMeasure("my_new_metric", value);
+ * }
+ * }
+ * }
+ * </pre>
+ * <p/>
+ * <h3>How to test</h3>
+ * <pre>
+ * public class MyMeasureComputerTest {
+ *
+ * MyMeasureComputer underTest = new MyMeasureComputer();
+ *
+ * @Test
+ * public void test_definition() {
+ * TestMeasureComputerDefinitionContext defContext = new TestMeasureComputerDefinitionContext();
+ * MeasureComputerDefinition def = underTest.define(defContext);
+ * assertThat(def).isNotNull();
+ * assertThat(def.getInputMetrics()).containsOnly("ncloc");
+ * assertThat(def.getOutputMetrics()).containsOnly("my_new_metric");
+ * }
+ *
+ * @Test
+ * public void sum_ncloc_and_issues() {
+ * TestMeasureComputerContext context = new TestMeasureComputerContext(underTest);
+ * context.addMeasure("ncloc", 2);
+ * context.setIssues(Arrays.asList(new TestIssue.Builder().setKey("ABCD").build()));
+ * underTest.compute(context);
+ *
+ * assertThat(context.getMeasureValue("my_new_metric")).isEqualTo(0.5);
+ * }
+ * </pre>
+ *
+ * @since 5.2
*/
+@ServerSide
+@ExtensionPoint
public interface MeasureComputer {
/**
- * Return the metric keys that can be read using {@link Implementation.Context}.
- *
- * Can never be empty as it's checked in the builder
+ * Use to define which metrics are required to compute some measures on some given metrics
*/
- Set<String> getInputMetrics();
+ MeasureComputerDefinition define(MeasureComputerDefinitionContext defContext);
/**
- * Return the metric keys that can be create using {@link Implementation.Context}.
- *
- * Can never ne empty as it's checked om the builder
+ * Context specific to the definition of the measure computer
*/
- Set<String> getOutputMetrics();
-
- Implementation getImplementation();
-
- interface MeasureComputerBuilder {
-
- /**
- * Input metrics can be empty (for instance when only issues are needed)
- * @throws NullPointerException if inputMetrics is null
- * @throws NullPointerException if the metrics contains a {@code null}
- * */
- MeasureComputerBuilder setInputMetrics(String... inputMetrics);
+ interface MeasureComputerDefinitionContext {
+ Builder newDefinitionBuilder();
+ }
+ interface MeasureComputerDefinition {
/**
- * @throws IllegalArgumentException if there's not at least one output metrics
- * @throws NullPointerException if the metrics contains a {@code null}
+ * Return the metric keys that can be read using {@link MeasureComputerContext}.
+ * Can be empty for instance when the computer only need to access to issues.
*/
- MeasureComputerBuilder setOutputMetrics(String... outMetrics);
+ Set<String> getInputMetrics();
/**
- * @throws NullPointerException if there's no implementation
+ * Return the metric keys that can be create using {@link MeasureComputerContext}.
+ * Can never ne empty.
*/
- MeasureComputerBuilder setImplementation(Implementation impl);
+ Set<String> getOutputMetrics();
- /**
- * @throws NullPointerException if inputMetrics is null
- * @throws NullPointerException if inputs metrics contains a {@code null}
- * @throws IllegalArgumentException if there's not at least one output metrics
- * @throws NullPointerException if outputs metrics contains a {@code null}
- * @throws NullPointerException if there's no implementation
- */
- MeasureComputer build();
+ interface Builder {
+ /**
+ * Input metrics can be empty (for instance when only issues are needed)
+ * @throws NullPointerException if inputMetrics is null
+ * @throws NullPointerException if the metrics contains a {@code null}
+ * */
+ Builder setInputMetrics(String... inputMetrics);
+
+ /**
+ * @throws NullPointerException if outputMetrics is null
+ * @throws IllegalArgumentException if there's not at least one output metrics
+ * @throws NullPointerException if the metrics contains a {@code null}
+ */
+ Builder setOutputMetrics(String... outputMetrics);
+
+ /**
+ * @throws NullPointerException if inputMetrics is null
+ * @throws NullPointerException if inputs metrics contains a {@code null}
+ * @throws NullPointerException if outputMetrics is null
+ * @throws IllegalArgumentException if there's not at least one output metrics
+ * @throws NullPointerException if outputs metrics contains a {@code null}
+ */
+ MeasureComputerDefinition build();
+ }
}
/**
- * This interface must be implemented to define how the measures are computed.
+ * This method will be called on each component of the projects.
*/
- interface Implementation {
+ void compute(MeasureComputerContext context);
+ /**
+ * Context specific to the computation of the measure(s) of a given component
+ */
+ interface MeasureComputerContext {
/**
- * This method will be called on each component of the projects.
+ * Returns the current component.
*/
- void compute(Context ctx);
+ Component getComponent();
/**
- * Context specific to the computation of the measure(s) of a given component
+ * Returns settings of the current component.
*/
- interface Context {
-
- /**
- * Returns the current component.
- */
- Component getComponent();
+ Settings getSettings();
- /**
- * Returns settings of the current component.
- */
- Settings getSettings();
-
- /**
- * Returns the measure from a given metric on the current component.
- *
- * @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputer#getInputMetrics()}
- */
- @CheckForNull
- Measure getMeasure(String metric);
-
- /**
- * Returns measures from a given metric on children of the current component.
- * It no measure is found for a child, this measure is ignored
- *
- * @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputer#getInputMetrics()} or in {@link MeasureComputer#getOutputMetrics()}
- */
- Iterable<Measure> getChildrenMeasures(String metric);
+ /**
+ * Returns the measure from a given metric on the current component.
+ *
+ * @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputerDefinition#getInputMetrics()}
+ */
+ @CheckForNull
+ Measure getMeasure(String metric);
- /**
- * Add a new measure of a given metric which measure type will be int
- *
- * @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputer#getOutputMetrics()}
- * @throws UnsupportedOperationException if a measure for the specified metric already exists for the current component
- */
- void addMeasure(String metric, int value);
+ /**
+ * Returns measures from a given metric on children of the current component.
+ * It no measure is found for a child, this measure is ignored
+ *
+ * @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputerDefinition#getInputMetrics()}
+ * or in {@link MeasureComputerDefinition#getOutputMetrics()}
+ */
+ Iterable<Measure> getChildrenMeasures(String metric);
- /**
- * Add a new measure of a given metric which measure type will be double
- *
- * @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputer#getOutputMetrics()}
- * @throws UnsupportedOperationException if a measure for the specified metric already exists for the current component
- */
- void addMeasure(String metric, double value);
+ /**
+ * Add a new measure of a given metric which measure type will be int
+ *
+ * @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputerDefinition#getOutputMetrics()}
+ * @throws UnsupportedOperationException if a measure for the specified metric already exists for the current component
+ */
+ void addMeasure(String metric, int value);
- /**
- * Add a new measure of a given metric which measure type will be long
- *
- * @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputer#getOutputMetrics()}
- * @throws UnsupportedOperationException if a measure for the specified metric already exists for the current component
- */
- void addMeasure(String metric, long value);
+ /**
+ * Add a new measure of a given metric which measure type will be double
+ *
+ * @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputerDefinition#getOutputMetrics()}
+ * @throws UnsupportedOperationException if a measure for the specified metric already exists for the current component
+ */
+ void addMeasure(String metric, double value);
- /**
- * Add a new measure of a given metric which measure type will be string
- *
- * @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputer#getOutputMetrics()}
- * @throws UnsupportedOperationException if a measure for the specified metric already exists for the current component
- */
- void addMeasure(String metric, String value);
+ /**
+ * Add a new measure of a given metric which measure type will be long
+ *
+ * @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputerDefinition#getOutputMetrics()}
+ * @throws UnsupportedOperationException if a measure for the specified metric already exists for the current component
+ */
+ void addMeasure(String metric, long value);
- /**
- * Return list of issues of current component.
- */
- List<? extends Issue> getIssues();
+ /**
+ * Add a new measure of a given metric which measure type will be string
+ *
+ * @throws IllegalArgumentException if the metric is not listed in {@link MeasureComputerDefinition#getOutputMetrics()}
+ * @throws UnsupportedOperationException if a measure for the specified metric already exists for the current component
+ */
+ void addMeasure(String metric, String value);
- }
+ /**
+ * Return list of all issues (open, closed, etc.) of current component.
+ */
+ List<? extends Issue> getIssues();
}
}
+++ /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.api.ce.measure;
-
-import org.sonar.api.ExtensionPoint;
-import org.sonar.api.server.ServerSide;
-
-/**
- * This extension point can be used to register {@link MeasureComputer}(s) that will be able to compute measures when a batch report is processed by the Compute Engine
- */
-@ServerSide
-@ExtensionPoint
-public interface MeasureComputerProvider {
-
- /**
- * Use this method to register a new measure computer.
- */
- void register(Context ctx);
-
- interface Context {
-
- /**
- * Add a new computer to the context.
- *
- * @throws UnsupportedOperationException when trying to add a computer providing some measures on metrics already defined by another {@link MeasureComputer}
- */
- Context add(MeasureComputer measureComputer);
-
- /**
- * Use this method to build a MeasureComputer to be used in the {@link #add(MeasureComputer)} method
- */
- MeasureComputer.MeasureComputerBuilder newMeasureComputerBuilder();
-
- }
-}
* <p>An example of usage : you wish to record the percentage of lines of code that belong to method
* with pre-defined ranges of complexity.</p>
*
+ * @since 5.2
*/
public class RangeDistributionBuilder {
import javax.annotation.CheckForNull;
/**
- * Settings of the current component.
+ * Settings of the current component used in {@link MeasureComputer}
+ *
+ * @since 5.2
*/
public interface Settings {