Browse Source

Rework new measure API

tags/5.2-RC1
Julien HENRY 8 years ago
parent
commit
15ec53105c
16 changed files with 105 additions and 174 deletions
  1. 5
    6
      plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/MeasureSensor.java
  2. 3
    3
      sonar-batch/src/main/java/org/sonar/batch/cpd/JavaCpdEngine.java
  3. 3
    8
      sonar-batch/src/main/java/org/sonar/batch/index/BatchComponentCache.java
  4. 6
    12
      sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java
  5. 7
    7
      sonar-batch/src/main/java/org/sonar/batch/source/LinesSensor.java
  6. 16
    17
      sonar-batch/src/test/java/org/sonar/batch/cpd/JavaCpdEngineTest.java
  7. 7
    4
      sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java
  8. 5
    0
      sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputComponent.java
  9. 0
    2
      sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputComponent.java
  10. 11
    46
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java
  11. 2
    2
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocation.java
  12. 4
    9
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/Measure.java
  13. 5
    11
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/NewMeasure.java
  14. 13
    32
      sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/internal/DefaultMeasure.java
  15. 6
    5
      sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java
  16. 12
    10
      sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/measure/internal/DefaultMeasureTest.java

+ 5
- 6
plugins/sonar-xoo-plugin/src/main/java/org/sonar/xoo/lang/MeasureSensor.java View File

@@ -19,6 +19,10 @@
*/
package org.sonar.xoo.lang;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.sonar.api.batch.fs.InputFile;
@@ -31,11 +35,6 @@ import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
import org.sonar.xoo.Xoo;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.List;

/**
* Parse files *.xoo.measures
*/
@@ -89,7 +88,7 @@ public class MeasureSensor implements Sensor {
}
NewMeasure<Serializable> newMeasure = context.newMeasure()
.forMetric(metric)
.onFile(xooFile);
.on(xooFile);
if (Boolean.class.equals(metric.valueType())) {
newMeasure.withValue(Boolean.parseBoolean(value));
} else if (Integer.class.equals(metric.valueType())) {

+ 3
- 3
sonar-batch/src/main/java/org/sonar/batch/cpd/JavaCpdEngine.java View File

@@ -207,19 +207,19 @@ public class JavaCpdEngine extends CpdEngine {
// Save
((DefaultMeasure<Integer>) context.<Integer>newMeasure()
.forMetric(CoreMetrics.DUPLICATED_FILES)
.onFile(inputFile)
.on(inputFile)
.withValue(1))
.setFromCore()
.save();
((DefaultMeasure<Integer>) context.<Integer>newMeasure()
.forMetric(CoreMetrics.DUPLICATED_LINES)
.onFile(inputFile)
.on(inputFile)
.withValue(duplicatedLines))
.setFromCore()
.save();
((DefaultMeasure<Integer>) context.<Integer>newMeasure()
.forMetric(CoreMetrics.DUPLICATED_BLOCKS)
.onFile(inputFile)
.on(inputFile)
.withValue(duplicatedBlocks))
.setFromCore()
.save();

+ 3
- 8
sonar-batch/src/main/java/org/sonar/batch/index/BatchComponentCache.java View File

@@ -27,9 +27,7 @@ import java.util.Map;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.batch.BatchSide;
import org.sonar.api.batch.fs.InputPath;
import org.sonar.api.batch.fs.internal.DefaultInputDir;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.resources.Resource;

@BatchSide
@@ -48,11 +46,8 @@ public class BatchComponentCache {
return components.get(resource.getEffectiveKey());
}

public BatchComponent get(InputPath inputPath) {
if (inputPath instanceof DefaultInputFile) {
return components.get(((DefaultInputFile) inputPath).key());
}
return components.get(((DefaultInputDir) inputPath).key());
public BatchComponent get(InputComponent inputComponent) {
return components.get(inputComponent.key());
}

public BatchComponent add(Resource resource, @Nullable Resource parentResource) {

+ 6
- 12
sonar-batch/src/main/java/org/sonar/batch/sensor/DefaultSensorStorage.java View File

@@ -29,6 +29,7 @@ import javax.annotation.Nonnull;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.fs.FileSystem;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.TextRange;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
@@ -48,7 +49,6 @@ import org.sonar.api.config.Settings;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Metric;
import org.sonar.api.resources.File;
import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.api.source.Symbol;
import org.sonar.api.utils.KeyValueFormat;
@@ -92,7 +92,6 @@ public class DefaultSensorStorage implements SensorStorage {
CoreMetrics.DUPLICATIONS_DATA_KEY);

private final MetricFinder metricFinder;
private final Project project;
private final ModuleIssues moduleIssues;
private final CoverageExclusions coverageExclusions;
private final DuplicationCache duplicationCache;
@@ -100,11 +99,10 @@ public class DefaultSensorStorage implements SensorStorage {
private final ReportPublisher reportPublisher;
private final MeasureCache measureCache;

public DefaultSensorStorage(MetricFinder metricFinder, Project project, ModuleIssues moduleIssues,
public DefaultSensorStorage(MetricFinder metricFinder, ModuleIssues moduleIssues,
Settings settings, FileSystem fs, ActiveRules activeRules, DuplicationCache duplicationCache,
CoverageExclusions coverageExclusions, BatchComponentCache resourceCache, ReportPublisher reportPublisher, MeasureCache measureCache) {
this.metricFinder = metricFinder;
this.project = project;
this.moduleIssues = moduleIssues;
this.coverageExclusions = coverageExclusions;
this.duplicationCache = duplicationCache;
@@ -128,14 +126,10 @@ public class DefaultSensorStorage implements SensorStorage {
org.sonar.api.measures.Measure measureToSave = new org.sonar.api.measures.Measure(m);
setValueAccordingToMetricType(newMeasure, m, measureToSave);
measureToSave.setFromCore(measure.isFromCore());
InputFile inputFile = newMeasure.inputFile();
if (inputFile != null) {
File sonarFile = getFile(inputFile);
if (coverageExclusions.accept(sonarFile, measureToSave)) {
saveMeasure(sonarFile, measureToSave);
}
} else {
saveMeasure(project, measureToSave);
InputComponent inputComponent = newMeasure.inputComponent();
Resource resource = resourceCache.get(inputComponent).resource();
if (coverageExclusions.accept(resource, measureToSave)) {
saveMeasure(resource, measureToSave);
}
}


+ 7
- 7
sonar-batch/src/main/java/org/sonar/batch/source/LinesSensor.java View File

@@ -43,24 +43,24 @@ public final class LinesSensor implements Sensor {
FileSystem fs = context.fileSystem();
for (InputFile f : fs.inputFiles(fs.predicates().hasType(Type.MAIN))) {
((DefaultMeasure<Integer>) context.<Integer>newMeasure()
.onFile(f)
.on(f)
.forMetric(CoreMetrics.LINES)
.withValue(f.lines()))
.setFromCore()
.save();
.setFromCore()
.save();
if (f.language() == null) {
// As an approximation for files with no language plugin we consider every non blank line as ncloc
((DefaultMeasure<Integer>) context.<Integer>newMeasure()
.onFile(f)
.on(f)
.forMetric(CoreMetrics.NCLOC)
.withValue(((DefaultInputFile) f).nonBlankLines()))
.save();
.save();
// No test and no coverage on those files
((DefaultMeasure<Integer>) context.<Integer>newMeasure()
.onFile(f)
.on(f)
.forMetric(CoreMetrics.LINES_TO_COVER)
.withValue(0))
.save();
.save();
}
}
}

+ 16
- 17
sonar-batch/src/test/java/org/sonar/batch/cpd/JavaCpdEngineTest.java View File

@@ -19,6 +19,10 @@
*/
package org.sonar.batch.cpd;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
@@ -36,11 +40,6 @@ import org.sonar.api.measures.CoreMetrics;
import org.sonar.duplications.index.CloneGroup;
import org.sonar.duplications.index.ClonePart;

import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
@@ -88,9 +87,9 @@ public class JavaCpdEngineTest {
List<CloneGroup> groups = Arrays.asList(newCloneGroup(new ClonePart("key1", 0, 2, 4), new ClonePart("key2", 0, 15, 17)));
JavaCpdEngine.save(context, inputFile, groups);

verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_FILES).onFile(inputFile).withValue(1));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_BLOCKS).onFile(inputFile).withValue(1));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_LINES).onFile(inputFile).withValue(3));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_FILES).on(inputFile).withValue(1));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_BLOCKS).on(inputFile).withValue(1));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_LINES).on(inputFile).withValue(3));

verify(storage).store(new DefaultDuplication()
.originBlock(inputFile, 2, 4)
@@ -102,9 +101,9 @@ public class JavaCpdEngineTest {
List<CloneGroup> groups = Arrays.asList(newCloneGroup(new ClonePart("key1", 0, 5, 204), new ClonePart("key1", 0, 215, 414)));
JavaCpdEngine.save(context, inputFile, groups);

verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_FILES).onFile(inputFile).withValue(1));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_BLOCKS).onFile(inputFile).withValue(2));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_LINES).onFile(inputFile).withValue(400));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_FILES).on(inputFile).withValue(1));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_BLOCKS).on(inputFile).withValue(2));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_LINES).on(inputFile).withValue(400));

verify(storage).store(new DefaultDuplication()
.originBlock(inputFile, 5, 204)
@@ -116,9 +115,9 @@ public class JavaCpdEngineTest {
List<CloneGroup> groups = Arrays.asList(newCloneGroup(new ClonePart("key1", 0, 5, 204), new ClonePart("key2", 0, 15, 214), new ClonePart("key3", 0, 25, 224)));
JavaCpdEngine.save(context, inputFile, groups);

verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_FILES).onFile(inputFile).withValue(1));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_BLOCKS).onFile(inputFile).withValue(1));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_LINES).onFile(inputFile).withValue(200));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_FILES).on(inputFile).withValue(1));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_BLOCKS).on(inputFile).withValue(1));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_LINES).on(inputFile).withValue(200));

verify(storage).store(new DefaultDuplication()
.originBlock(inputFile, 5, 204)
@@ -133,9 +132,9 @@ public class JavaCpdEngineTest {
newCloneGroup(new ClonePart("key1", 0, 15, 214), new ClonePart("key3", 0, 15, 214)));
JavaCpdEngine.save(context, inputFile, groups);

verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_FILES).onFile(inputFile).withValue(1));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_BLOCKS).onFile(inputFile).withValue(2));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_LINES).onFile(inputFile).withValue(210));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_FILES).on(inputFile).withValue(1));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_BLOCKS).on(inputFile).withValue(2));
verify(storage).store(new DefaultMeasure().forMetric(CoreMetrics.DUPLICATED_LINES).on(inputFile).withValue(210));

verify(storage).store(new DefaultDuplication()
.originBlock(inputFile, 5, 204)

+ 7
- 4
sonar-batch/src/test/java/org/sonar/batch/sensor/DefaultSensorStorageTest.java View File

@@ -28,6 +28,7 @@ import org.mockito.ArgumentCaptor;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.internal.DefaultFileSystem;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.measure.MetricFinder;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
@@ -83,7 +84,7 @@ public class DefaultSensorStorageTest {
CoverageExclusions coverageExclusions = mock(CoverageExclusions.class);
when(coverageExclusions.accept(any(Resource.class), any(Measure.class))).thenReturn(true);
resourceCache = new BatchComponentCache();
sensorStorage = new DefaultSensorStorage(metricFinder, project,
sensorStorage = new DefaultSensorStorage(metricFinder,
moduleIssues, settings, fs, activeRules, mock(DuplicationCache.class), coverageExclusions, resourceCache, mock(ReportPublisher.class), measureCache);
}

@@ -95,7 +96,7 @@ public class DefaultSensorStorageTest {
thrown.expectMessage("Unknow metric with key: lines");

sensorStorage.store(new DefaultMeasure()
.onFile(file)
.on(file)
.forMetric(CoreMetrics.LINES)
.withValue(10));
}
@@ -109,7 +110,7 @@ public class DefaultSensorStorageTest {
resourceCache.add(sonarFile, null).setInputComponent(file);
when(measureCache.put(eq(sonarFile), argumentCaptor.capture())).thenReturn(null);
sensorStorage.store(new DefaultMeasure()
.onFile(file)
.on(file)
.forMetric(CoreMetrics.NCLOC)
.withValue(10));

@@ -120,12 +121,14 @@ public class DefaultSensorStorageTest {

@Test
public void shouldSaveProjectMeasureToSensorContext() {
DefaultInputModule module = new DefaultInputModule(project.getEffectiveKey());
resourceCache.add(project, null).setInputComponent(module);

ArgumentCaptor<org.sonar.api.measures.Measure> argumentCaptor = ArgumentCaptor.forClass(org.sonar.api.measures.Measure.class);
when(measureCache.put(eq(project), argumentCaptor.capture())).thenReturn(null);

sensorStorage.store(new DefaultMeasure()
.onProject()
.on(module)
.forMetric(CoreMetrics.NCLOC)
.withValue(10));


+ 5
- 0
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/InputComponent.java View File

@@ -28,6 +28,11 @@ package org.sonar.api.batch.fs;
*/
public interface InputComponent {

/**
* Component key shared by all part of SonarQube (batch, server, WS...)
*/
String key();

/**
* Is the component an {@link InputFile}
*/

+ 0
- 2
sonar-plugin-api/src/main/java/org/sonar/api/batch/fs/internal/DefaultInputComponent.java View File

@@ -26,8 +26,6 @@ import org.sonar.api.batch.fs.InputComponent;
*/
public abstract class DefaultInputComponent implements InputComponent {

public abstract String key();

@Override
public boolean equals(Object o) {
if (this == o) {

+ 11
- 46
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java View File

@@ -20,6 +20,8 @@
package org.sonar.api.batch.sensor.internal;

import com.google.common.annotations.Beta;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import java.io.File;
import java.io.Serializable;
import java.util.ArrayList;
@@ -30,14 +32,8 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import org.sonar.api.batch.AnalysisMode;
import org.sonar.api.batch.fs.InputDir;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputPath;
import org.sonar.api.batch.fs.internal.DefaultFileSystem;
import org.sonar.api.batch.fs.internal.DefaultInputDir;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultTextPointer;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
@@ -128,24 +124,16 @@ public class SensorContextTester implements SensorContext {
return new DefaultMeasure<>(sensorStorage);
}

public Collection<Measure> measures(@Nullable String componetKey) {
if (componetKey == null) {
return sensorStorage.projectMeasuresByMetric.values();
}
Map<String, Measure> measures = sensorStorage.measuresByComponentAndMetric.get(componetKey);
return measures != null ? measures.values() : Collections.<Measure>emptyList();
public Collection<Measure> measures(String componentKey) {
return sensorStorage.measuresByComponentAndMetric.row(componentKey).values();
}

public <G extends Serializable> Measure<G> measure(String componetKey, Metric<G> metric) {
return measure(componetKey, metric.key());
}

public Measure measure(String componetKey, String metricKey) {
if (componetKey == null) {
return sensorStorage.projectMeasuresByMetric.get(metricKey);
}
Map<String, Measure> measures = sensorStorage.measuresByComponentAndMetric.get(componetKey);
return measures != null ? measures.get(metricKey) : null;
public <G extends Serializable> Measure<G> measure(String componentKey, String metricKey) {
return sensorStorage.measuresByComponentAndMetric.row(componentKey).get(metricKey);
}

@Override
@@ -254,7 +242,7 @@ public class SensorContextTester implements SensorContext {
public boolean isQuick() {
return this.isSingle;
}
public void setSingle(boolean single) {
this.isSingle = single;
}
@@ -262,8 +250,7 @@ public class SensorContextTester implements SensorContext {

private static class InMemorySensorStorage implements SensorStorage {

private Map<String, Measure> projectMeasuresByMetric = new HashMap<>();
private Map<String, Map<String, Measure>> measuresByComponentAndMetric = new HashMap<>();
private Table<String, String, Measure> measuresByComponentAndMetric = HashBasedTable.create();

private Collection<Issue> allIssues = new ArrayList<>();

@@ -274,15 +261,7 @@ public class SensorContextTester implements SensorContext {

@Override
public void store(Measure measure) {
String key = getKey(measure.inputFile());
if (key == null) {
projectMeasuresByMetric.put(measure.metric().key(), measure);
} else {
if (!measuresByComponentAndMetric.containsKey(key)) {
measuresByComponentAndMetric.put(key, new HashMap<String, Measure>());
}
measuresByComponentAndMetric.get(key).put(measure.metric().key(), measure);
}
measuresByComponentAndMetric.row(measure.inputComponent().key()).put(measure.metric().key(), measure);
}

@Override
@@ -297,32 +276,18 @@ public class SensorContextTester implements SensorContext {

@Override
public void store(DefaultHighlighting highlighting) {
highlightingByComponent.put(getKey(highlighting.inputFile()), highlighting);
highlightingByComponent.put(highlighting.inputFile().key(), highlighting);
}

@Override
public void store(DefaultCoverage defaultCoverage) {
String key = getKey(defaultCoverage.inputFile());
String key = defaultCoverage.inputFile().key();
if (!coverageByComponent.containsKey(key)) {
coverageByComponent.put(key, new EnumMap<CoverageType, DefaultCoverage>(CoverageType.class));
}
coverageByComponent.get(key).put(defaultCoverage.type(), defaultCoverage);
}

@CheckForNull
private static String getKey(@Nullable InputPath inputPath) {
if (inputPath == null) {
return null;
}
if (inputPath instanceof InputFile) {
return ((DefaultInputFile) inputPath).key();
}
if (inputPath instanceof InputDir) {
return ((DefaultInputDir) inputPath).key();
}
throw new IllegalStateException("Unknow component " + inputPath);
}

}

}

+ 2
- 2
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/issue/internal/DefaultIssueLocation.java View File

@@ -41,7 +41,7 @@ public class DefaultIssueLocation implements NewIssueLocation, IssueLocation {
}

@Override
public NewIssueLocation at(TextRange location) {
public DefaultIssueLocation at(TextRange location) {
Preconditions.checkState(this.component != null, "at() should be called after on()");
Preconditions.checkState(this.component.isFile(), "at() should be called only for an InputFile.");
DefaultInputFile file = (DefaultInputFile) this.component;
@@ -51,7 +51,7 @@ public class DefaultIssueLocation implements NewIssueLocation, IssueLocation {
}

@Override
public NewIssueLocation message(String message) {
public DefaultIssueLocation message(String message) {
Preconditions.checkNotNull(message, "Message can't be null");
Preconditions.checkArgument(message.length() <= MESSAGE_MAX_SIZE,
"Message of an issue can't be greater than " + MESSAGE_MAX_SIZE + ": [" + message + "] size is " + message.length());

+ 4
- 9
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/Measure.java View File

@@ -20,12 +20,9 @@
package org.sonar.api.batch.sensor.measure;

import com.google.common.annotations.Beta;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.measure.Metric;

import javax.annotation.CheckForNull;

import java.io.Serializable;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.measure.Metric;

/**
* Measure on File, Directory or Project.
@@ -36,11 +33,9 @@ import java.io.Serializable;
public interface Measure<G extends Serializable> {

/**
* The file the measure belong to.
* @return null if measure is on project
* The {@link InputComponent} this measure belongs to.
*/
@CheckForNull
InputFile inputFile();
InputComponent inputComponent();

/**
* The metric this measure belong to.

+ 5
- 11
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/NewMeasure.java View File

@@ -20,28 +20,22 @@
package org.sonar.api.batch.sensor.measure;

import com.google.common.annotations.Beta;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.measure.Metric;

import java.io.Serializable;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.measure.Metric;

/**
* Builder to create new Measure.
* Should not be implemented by client.
* @since 5.1
* @since 5.2
*/
@Beta
public interface NewMeasure<G extends Serializable> {

/**
* The file the measure belongs to.
*/
NewMeasure<G> onFile(InputFile file);

/**
* Tell that the measure is global to the project.
* The {@link InputComponent} the measure belongs to. Mandatory.
*/
NewMeasure<G> onProject();
NewMeasure<G> on(InputComponent component);

/**
* Set the metric this measure belong to.

+ 13
- 32
sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/measure/internal/DefaultMeasure.java View File

@@ -19,26 +19,21 @@
*/
package org.sonar.api.batch.sensor.measure.internal;

import org.sonar.api.batch.sensor.internal.SensorStorage;

import com.google.common.base.Preconditions;
import java.io.Serializable;
import javax.annotation.Nullable;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.fs.InputComponent;
import org.sonar.api.batch.measure.Metric;
import org.sonar.api.batch.sensor.internal.DefaultStorable;
import org.sonar.api.batch.sensor.internal.SensorStorage;
import org.sonar.api.batch.sensor.measure.Measure;
import org.sonar.api.batch.sensor.measure.NewMeasure;

import javax.annotation.CheckForNull;
import javax.annotation.Nullable;

import java.io.Serializable;

public class DefaultMeasure<G extends Serializable> extends DefaultStorable implements Measure<G>, NewMeasure<G> {

private boolean onProject = false;
private InputFile file;
private InputComponent component;
private Metric<G> metric;
private G value;
private boolean fromCore = false;
@@ -52,19 +47,10 @@ public class DefaultMeasure<G extends Serializable> extends DefaultStorable impl
}

@Override
public DefaultMeasure<G> onFile(InputFile inputFile) {
Preconditions.checkState(!this.onProject, "onProject already called");
Preconditions.checkState(this.file == null, "onFile already called");
Preconditions.checkNotNull(inputFile, "InputFile should be non null");
this.file = inputFile;
return this;
}

@Override
public DefaultMeasure<G> onProject() {
Preconditions.checkState(!this.onProject, "onProject already called");
Preconditions.checkState(this.file == null, "onFile already called");
this.onProject = true;
public DefaultMeasure<G> on(InputComponent component) {
Preconditions.checkArgument(component != null, "Component can't be null");
Preconditions.checkState(this.component == null, "on() already called");
this.component = component;
return this;
}

@@ -113,9 +99,8 @@ public class DefaultMeasure<G extends Serializable> extends DefaultStorable impl
}

@Override
@CheckForNull
public InputFile inputFile() {
return file;
public InputComponent inputComponent() {
return component;
}

@Override
@@ -138,7 +123,7 @@ public class DefaultMeasure<G extends Serializable> extends DefaultStorable impl
}
DefaultMeasure<?> rhs = (DefaultMeasure<?>) obj;
return new EqualsBuilder()
.append(file, rhs.file)
.append(component, rhs.component)
.append(metric, rhs.metric)
.append(value, rhs.value)
.isEquals();
@@ -146,11 +131,7 @@ public class DefaultMeasure<G extends Serializable> extends DefaultStorable impl

@Override
public int hashCode() {
return new HashCodeBuilder(27, 45).
append(file).
append(metric).
append(value).
toHashCode();
return new HashCodeBuilder(27, 45).append(component).append(metric).append(value).toHashCode();
}

}

+ 6
- 5
sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java View File

@@ -27,6 +27,7 @@ import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.sonar.api.batch.fs.internal.DefaultFileSystem;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.fs.internal.FileMetadata;
import org.sonar.api.batch.rule.ActiveRules;
import org.sonar.api.batch.rule.internal.ActiveRulesBuilder;
@@ -105,14 +106,14 @@ public class SensorContextTesterTest {
assertThat(tester.measures("foo:src/Foo.java")).isEmpty();
assertThat(tester.measure("foo:src/Foo.java", "ncloc")).isNull();
tester.<Integer>newMeasure()
.onFile(new DefaultInputFile("foo", "src/Foo.java"))
.on(new DefaultInputFile("foo", "src/Foo.java"))
.forMetric(CoreMetrics.NCLOC)
.withValue(2)
.save();
assertThat(tester.measures("foo:src/Foo.java")).hasSize(1);
assertThat(tester.measure("foo:src/Foo.java", "ncloc")).isNotNull();
tester.<Integer>newMeasure()
.onFile(new DefaultInputFile("foo", "src/Foo.java"))
.on(new DefaultInputFile("foo", "src/Foo.java"))
.forMetric(CoreMetrics.LINES)
.withValue(4)
.save();
@@ -120,12 +121,12 @@ public class SensorContextTesterTest {
assertThat(tester.measure("foo:src/Foo.java", "ncloc")).isNotNull();
assertThat(tester.measure("foo:src/Foo.java", "lines")).isNotNull();
tester.<Integer>newMeasure()
.onProject()
.on(new DefaultInputModule("foo"))
.forMetric(CoreMetrics.DIRECTORIES)
.withValue(4)
.save();
assertThat(tester.measures(null)).hasSize(1);
assertThat(tester.measure(null, "directories")).isNotNull();
assertThat(tester.measures("foo")).hasSize(1);
assertThat(tester.measure("foo", "directories")).isNotNull();
}

@Test

+ 12
- 10
sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/measure/internal/DefaultMeasureTest.java View File

@@ -19,13 +19,14 @@
*/
package org.sonar.api.batch.sensor.measure.internal;

import org.sonar.api.batch.sensor.internal.SensorStorage;

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.sonar.api.batch.fs.internal.DefaultInputFile;
import org.sonar.api.batch.fs.internal.DefaultInputModule;
import org.sonar.api.batch.sensor.internal.SensorStorage;
import org.sonar.api.measures.CoreMetrics;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
@@ -40,10 +41,10 @@ public class DefaultMeasureTest {
SensorStorage storage = mock(SensorStorage.class);
DefaultMeasure<Integer> newMeasure = new DefaultMeasure<Integer>(storage)
.forMetric(CoreMetrics.LINES)
.onFile(new DefaultInputFile("foo", "src/Foo.php"))
.on(new DefaultInputFile("foo", "src/Foo.php"))
.withValue(3);

assertThat(newMeasure.inputFile()).isEqualTo(new DefaultInputFile("foo", "src/Foo.php"));
assertThat(newMeasure.inputComponent()).isEqualTo(new DefaultInputFile("foo", "src/Foo.php"));
assertThat(newMeasure.metric()).isEqualTo(CoreMetrics.LINES);
assertThat(newMeasure.value()).isEqualTo(3);

@@ -55,12 +56,13 @@ public class DefaultMeasureTest {
@Test
public void build_project_measure() {
SensorStorage storage = mock(SensorStorage.class);
DefaultInputModule module = new DefaultInputModule("foo");
DefaultMeasure<Integer> newMeasure = new DefaultMeasure<Integer>(storage)
.forMetric(CoreMetrics.LINES)
.onProject()
.on(module)
.withValue(3);

assertThat(newMeasure.inputFile()).isNull();
assertThat(newMeasure.inputComponent()).isEqualTo(new DefaultInputModule("foo"));
assertThat(newMeasure.metric()).isEqualTo(CoreMetrics.LINES);
assertThat(newMeasure.value()).isEqualTo(3);

@@ -70,12 +72,12 @@ public class DefaultMeasureTest {
}

@Test
public void not_allowed_to_call_onFile_and_onProject() {
public void not_allowed_to_call_on_twice() {
thrown.expect(IllegalStateException.class);
thrown.expectMessage("onProject already called");
thrown.expectMessage("on() already called");
new DefaultMeasure<Integer>()
.onProject()
.onFile(new DefaultInputFile("foo", "src/Foo.php"))
.on(new DefaultInputModule("foo"))
.on(new DefaultInputFile("foo", "src/Foo.php"))
.withValue(3)
.save();
}

Loading…
Cancel
Save