aboutsummaryrefslogtreecommitdiffstats
path: root/sonar-plugin-api/src
diff options
context:
space:
mode:
authorJulien HENRY <henryju@yahoo.fr>2016-07-06 16:56:56 +0200
committerJulien HENRY <henryju@yahoo.fr>2016-07-07 09:44:53 +0200
commita4e0563f753bf04f6560f7014a974d2d4f248d84 (patch)
treeb488cf1ae113f32778c69009d8f925d875d90cda /sonar-plugin-api/src
parent9cb0a45cbf5c1b2964cb7c095b9f87d94eb59c26 (diff)
downloadsonarqube-a4e0563f753bf04f6560f7014a974d2d4f248d84.tar.gz
sonarqube-a4e0563f753bf04f6560f7014a974d2d4f248d84.zip
SONAR-7783 Ensure Sensors don't save same data twice
Diffstat (limited to 'sonar-plugin-api/src')
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/NewCpdTokens.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/NewHighlighting.java2
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorage.java42
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java27
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/symbol/NewSymbolTable.java2
-rw-r--r--sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java72
6 files changed, 116 insertions, 31 deletions
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/NewCpdTokens.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/NewCpdTokens.java
index e28caa4a647..76b2ce5b021 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/NewCpdTokens.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/cpd/NewCpdTokens.java
@@ -58,7 +58,7 @@ public interface NewCpdTokens {
NewCpdTokens addToken(int startLine, int startLineOffset, int endLine, int endLineOffset, String image);
/**
- * Call this method only once when your are done with defining tokens of the file.
+ * Call this method only once when your are done with defining tokens of the file. It is not supported to save CPD tokens twice for the same file.
*/
void save();
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/NewHighlighting.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/NewHighlighting.java
index ae3dd8211d6..a959d62d78e 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/NewHighlighting.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/highlighting/NewHighlighting.java
@@ -71,7 +71,7 @@ public interface NewHighlighting {
NewHighlighting highlight(int startLine, int startLineOffset, int endLine, int endLineOffset, TypeOfText typeOfText);
/**
- * Call this method only once when your are done with defining highlighting of the file.
+ * Call this method only once when your are done with defining highlighting of the file. It is not supported to save highlighting twice for the same file.
* @throws IllegalStateException if you have defined overlapping highlighting
*/
void save();
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorage.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorage.java
index 32c91d18610..53a1364604b 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorage.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/InMemorySensorStorage.java
@@ -23,7 +23,6 @@ import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.EnumMap;
import java.util.HashMap;
import java.util.Map;
import org.sonar.api.batch.sensor.coverage.CoverageType;
@@ -33,6 +32,7 @@ import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting;
import org.sonar.api.batch.sensor.issue.Issue;
import org.sonar.api.batch.sensor.measure.Measure;
import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable;
+import org.sonar.api.utils.SonarException;
class InMemorySensorStorage implements SensorStorage {
@@ -42,12 +42,18 @@ class InMemorySensorStorage implements SensorStorage {
Map<String, DefaultHighlighting> highlightingByComponent = new HashMap<>();
Map<String, DefaultCpdTokens> cpdTokensByComponent = new HashMap<>();
- Map<String, Map<CoverageType, DefaultCoverage>> coverageByComponent = new HashMap<>();
+ Table<String, CoverageType, DefaultCoverage> coverageByComponentAndType = HashBasedTable.create();
Map<String, DefaultSymbolTable> symbolsPerComponent = new HashMap<>();
@Override
public void store(Measure measure) {
- measuresByComponentAndMetric.row(measure.inputComponent().key()).put(measure.metric().key(), measure);
+ // Emulate duplicate measure check
+ String componentKey = measure.inputComponent().key();
+ String metricKey = measure.metric().key();
+ if (measuresByComponentAndMetric.contains(componentKey, metricKey)) {
+ throw new SonarException("Can not add the same measure twice");
+ }
+ measuresByComponentAndMetric.row(componentKey).put(metricKey, measure);
}
@Override
@@ -57,26 +63,42 @@ class InMemorySensorStorage implements SensorStorage {
@Override
public void store(DefaultHighlighting highlighting) {
- highlightingByComponent.put(highlighting.inputFile().key(), highlighting);
+ String fileKey = highlighting.inputFile().key();
+ // Emulate duplicate storage check
+ if (highlightingByComponent.containsKey(fileKey)) {
+ throw new UnsupportedOperationException("Trying to save highlighting twice for the same file is not supported: " + highlighting.inputFile().relativePath());
+ }
+ highlightingByComponent.put(fileKey, highlighting);
}
@Override
public void store(DefaultCoverage defaultCoverage) {
- String key = defaultCoverage.inputFile().key();
- if (!coverageByComponent.containsKey(key)) {
- coverageByComponent.put(key, new EnumMap<CoverageType, DefaultCoverage>(CoverageType.class));
+ String fileKey = defaultCoverage.inputFile().key();
+ // Emulate duplicate storage check
+ if (coverageByComponentAndType.contains(fileKey, defaultCoverage.type())) {
+ throw new UnsupportedOperationException("Trying to save coverage twice for the same file is not supported: " + defaultCoverage.inputFile().relativePath());
}
- coverageByComponent.get(key).put(defaultCoverage.type(), defaultCoverage);
+ coverageByComponentAndType.row(fileKey).put(defaultCoverage.type(), defaultCoverage);
}
@Override
public void store(DefaultCpdTokens defaultCpdTokens) {
- cpdTokensByComponent.put(defaultCpdTokens.inputFile().key(), defaultCpdTokens);
+ String fileKey = defaultCpdTokens.inputFile().key();
+ // Emulate duplicate storage check
+ if (cpdTokensByComponent.containsKey(fileKey)) {
+ throw new UnsupportedOperationException("Trying to save CPD tokens twice for the same file is not supported: " + defaultCpdTokens.inputFile().relativePath());
+ }
+ cpdTokensByComponent.put(fileKey, defaultCpdTokens);
}
@Override
public void store(DefaultSymbolTable symbolTable) {
- symbolsPerComponent.put(symbolTable.inputFile().key(), symbolTable);
+ String fileKey = symbolTable.inputFile().key();
+ // Emulate duplicate storage check
+ if (symbolsPerComponent.containsKey(fileKey)) {
+ throw new UnsupportedOperationException("Trying to save symbol table twice for the same file is not supported: " + symbolTable.inputFile().relativePath());
+ }
+ symbolsPerComponent.put(fileKey, symbolTable);
}
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java
index 71a35021a28..12cd04842db 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java
@@ -183,38 +183,29 @@ public class SensorContextTester implements SensorContext {
@CheckForNull
public Integer lineHits(String fileKey, CoverageType type, int line) {
- Map<CoverageType, DefaultCoverage> defaultCoverageByType = sensorStorage.coverageByComponent.get(fileKey);
- if (defaultCoverageByType == null) {
+ DefaultCoverage defaultCoverage = sensorStorage.coverageByComponentAndType.get(fileKey, type);
+ if (defaultCoverage == null) {
return null;
}
- if (defaultCoverageByType.containsKey(type)) {
- return defaultCoverageByType.get(type).hitsByLine().get(line);
- }
- return null;
+ return defaultCoverage.hitsByLine().get(line);
}
@CheckForNull
public Integer conditions(String fileKey, CoverageType type, int line) {
- Map<CoverageType, DefaultCoverage> defaultCoverageByType = sensorStorage.coverageByComponent.get(fileKey);
- if (defaultCoverageByType == null) {
+ DefaultCoverage defaultCoverage = sensorStorage.coverageByComponentAndType.get(fileKey, type);
+ if (defaultCoverage == null) {
return null;
}
- if (defaultCoverageByType.containsKey(type)) {
- return defaultCoverageByType.get(type).conditionsByLine().get(line);
- }
- return null;
+ return defaultCoverage.conditionsByLine().get(line);
}
@CheckForNull
public Integer coveredConditions(String fileKey, CoverageType type, int line) {
- Map<CoverageType, DefaultCoverage> defaultCoverageByType = sensorStorage.coverageByComponent.get(fileKey);
- if (defaultCoverageByType == null) {
+ DefaultCoverage defaultCoverage = sensorStorage.coverageByComponentAndType.get(fileKey, type);
+ if (defaultCoverage == null) {
return null;
}
- if (defaultCoverageByType.containsKey(type)) {
- return defaultCoverageByType.get(type).coveredConditionsByLine().get(line);
- }
- return null;
+ return defaultCoverage.coveredConditionsByLine().get(line);
}
@CheckForNull
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/symbol/NewSymbolTable.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/symbol/NewSymbolTable.java
index af2cab645e1..a7da9ec5c40 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/symbol/NewSymbolTable.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/symbol/NewSymbolTable.java
@@ -69,7 +69,7 @@ public interface NewSymbolTable {
NewSymbol newSymbol(int startLine, int startLineOffset, int endLine, int endLineOffset);
/**
- * Call this method only once when your are done with defining all symbols of the file.
+ * Call this method only once when your are done with defining all symbols of the file. It is not permitted to save a symbol table twice for the same file.
* @throws IllegalStateException if you have defined overlapping symbols
*/
void save();
diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java
index 75d49b3a7b3..712e1eb0500 100644
--- a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java
+++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java
@@ -40,6 +40,7 @@ import org.sonar.api.batch.sensor.symbol.NewSymbolTable;
import org.sonar.api.config.Settings;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.SonarException;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.tuple;
@@ -127,6 +128,20 @@ public class SensorContextTesterTest {
assertThat(tester.measure("foo", "directories")).isNotNull();
}
+ @Test(expected = SonarException.class)
+ public void duplicateMeasures() {
+ tester.<Integer>newMeasure()
+ .on(new DefaultInputFile("foo", "src/Foo.java"))
+ .forMetric(CoreMetrics.NCLOC)
+ .withValue(2)
+ .save();
+ tester.<Integer>newMeasure()
+ .on(new DefaultInputFile("foo", "src/Foo.java"))
+ .forMetric(CoreMetrics.NCLOC)
+ .withValue(2)
+ .save();
+ }
+
@Test
public void testHighlighting() {
assertThat(tester.highlightingTypeAt("foo:src/Foo.java", 1, 3)).isEmpty();
@@ -140,6 +155,18 @@ public class SensorContextTesterTest {
assertThat(tester.highlightingTypeAt("foo:src/Foo.java", 1, 9)).containsExactly(TypeOfText.CONSTANT, TypeOfText.COMMENT);
}
+ @Test(expected = UnsupportedOperationException.class)
+ public void duplicateHighlighting() {
+ tester.newHighlighting()
+ .onFile(new DefaultInputFile("foo", "src/Foo.java").initMetadata(new FileMetadata().readMetadata(new StringReader("annot dsf fds foo bar"))))
+ .highlight(1, 0, 1, 5, TypeOfText.ANNOTATION)
+ .save();
+ tester.newHighlighting()
+ .onFile(new DefaultInputFile("foo", "src/Foo.java").initMetadata(new FileMetadata().readMetadata(new StringReader("annot dsf fds foo bar"))))
+ .highlight(1, 0, 1, 5, TypeOfText.ANNOTATION)
+ .save();
+ }
+
@Test
public void testSymbolReferences() {
assertThat(tester.referencesForSymbolAt("foo:src/Foo.java", 1, 0)).isNull();
@@ -162,6 +189,23 @@ public class SensorContextTesterTest {
tuple(1, 10, 1, 13));
}
+ @Test(expected = UnsupportedOperationException.class)
+ public void duplicateSymbolReferences() {
+ NewSymbolTable symbolTable = tester.newSymbolTable()
+ .onFile(new DefaultInputFile("foo", "src/Foo.java").initMetadata(new FileMetadata().readMetadata(new StringReader("annot dsf fds foo bar"))));
+ symbolTable
+ .newSymbol(1, 8, 1, 10);
+
+ symbolTable.save();
+
+ symbolTable = tester.newSymbolTable()
+ .onFile(new DefaultInputFile("foo", "src/Foo.java").initMetadata(new FileMetadata().readMetadata(new StringReader("annot dsf fds foo bar"))));
+ symbolTable
+ .newSymbol(1, 8, 1, 10);
+
+ symbolTable.save();
+ }
+
@Test
public void testCoverageAtLineZero() {
assertThat(tester.lineHits("foo:src/Foo.java", CoverageType.UNIT, 1)).isNull();
@@ -201,6 +245,20 @@ public class SensorContextTesterTest {
assertThat(tester.lineHits("foo:src/Foo.java", CoverageType.UNIT, 2)).isEqualTo(3);
}
+ @Test(expected = UnsupportedOperationException.class)
+ public void duplicateCoverage() {
+ tester.newCoverage()
+ .onFile(new DefaultInputFile("foo", "src/Foo.java").initMetadata(new FileMetadata().readMetadata(new StringReader("annot dsf fds foo bar\nasdas"))))
+ .ofType(CoverageType.UNIT)
+ .lineHits(1, 2)
+ .save();
+ tester.newCoverage()
+ .onFile(new DefaultInputFile("foo", "src/Foo.java").initMetadata(new FileMetadata().readMetadata(new StringReader("annot dsf fds foo bar\nasdas"))))
+ .ofType(CoverageType.UNIT)
+ .lineHits(1, 2)
+ .save();
+ }
+
@Test
public void testConditions() {
assertThat(tester.conditions("foo:src/Foo.java", CoverageType.UNIT, 1)).isNull();
@@ -234,4 +292,18 @@ public class SensorContextTesterTest {
tuple("publicclass$IDENTIFIER{", 1, 1, 4),
tuple("}", 3, 5, 5));
}
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void duplicateCpdTokens() {
+ DefaultInputFile inputFile = new DefaultInputFile("foo", "src/Foo.java").initMetadata(new FileMetadata().readMetadata(new StringReader("public class Foo {\n\n}")));
+ tester.newCpdTokens()
+ .onFile(inputFile)
+ .addToken(inputFile.newRange(0, 6), "public")
+ .save();
+
+ tester.newCpdTokens()
+ .onFile(inputFile)
+ .addToken(inputFile.newRange(0, 6), "public")
+ .save();
+ }
}