@@ -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())) { |
@@ -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(); |
@@ -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) { |
@@ -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); | |||
} | |||
} | |||
@@ -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(); | |||
} | |||
} | |||
} |
@@ -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) |
@@ -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)); | |||
@@ -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} | |||
*/ |
@@ -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) { |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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()); |
@@ -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. |
@@ -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. |
@@ -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(); | |||
} | |||
} |
@@ -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 |
@@ -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(); | |||
} |