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();
}
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();
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;
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 {
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
@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);
}
}
@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
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();
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;
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();
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();
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();
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();
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();
+ }
}
import org.sonar.duplications.index.PackedMemoryCloneIndex;
import org.sonar.duplications.index.PackedMemoryCloneIndex.ResourceBlocks;
import org.sonar.scanner.index.BatchComponentCache;
+import org.sonar.scanner.protocol.output.FileStructure;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.report.ReportPublisher;
public void insert(InputFile inputFile, Collection<Block> blocks) {
if (isCrossProjectDuplicationEnabled(settings)) {
int id = batchComponentCache.get(inputFile).batchId();
+ if (publisher.getWriter().hasComponentData(FileStructure.Domain.CPD_TEXT_BLOCKS, id)) {
+ throw new UnsupportedOperationException("Trying to save CPD tokens twice for the same file is not supported: " + inputFile.absolutePath());
+ }
final ScannerReport.CpdTextBlock.Builder builder = ScannerReport.CpdTextBlock.newBuilder();
publisher.getWriter().writeCpdTextBlocks(id, Iterables.transform(blocks, new Function<Block, ScannerReport.CpdTextBlock>() {
@Override
public Iterator<ResourceBlocks> iterator() {
return mem.iterator();
}
-
+
@Override
public int noResources() {
return mem.noResources();
import org.sonar.scanner.index.BatchComponent;
import org.sonar.scanner.index.BatchComponentCache;
import org.sonar.scanner.issue.ModuleIssues;
+import org.sonar.scanner.protocol.output.FileStructure;
import org.sonar.scanner.protocol.output.ScannerReport;
import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.report.ReportPublisher;
public void store(DefaultHighlighting highlighting) {
ScannerReportWriter writer = reportPublisher.getWriter();
DefaultInputFile inputFile = (DefaultInputFile) highlighting.inputFile();
- writer.writeComponentSyntaxHighlighting(componentCache.get(inputFile).batchId(),
+ int componentRef = componentCache.get(inputFile).batchId();
+ if (writer.hasComponentData(FileStructure.Domain.SYNTAX_HIGHLIGHTINGS, componentRef)) {
+ throw new UnsupportedOperationException("Trying to save highlighting twice for the same file is not supported: " + inputFile.absolutePath());
+ }
+ writer.writeComponentSyntaxHighlighting(componentRef,
Iterables.transform(highlighting.getSyntaxHighlightingRuleSet(), new BuildSyntaxHighlighting()));
}
@Override
public void store(DefaultSymbolTable symbolTable) {
ScannerReportWriter writer = reportPublisher.getWriter();
- writer.writeComponentSymbols(componentCache.get(symbolTable.inputFile()).batchId(),
+ int componentRef = componentCache.get(symbolTable.inputFile()).batchId();
+ if (writer.hasComponentData(FileStructure.Domain.SYMBOLS, componentRef)) {
+ throw new UnsupportedOperationException("Trying to save symbol table twice for the same file is not supported: " + symbolTable.inputFile().absolutePath());
+ }
+ writer.writeComponentSymbols(componentRef,
Iterables.transform(symbolTable.getReferencesBySymbol().entrySet(), new Function<Map.Entry<TextRange, Set<TextRange>>, ScannerReport.Symbol>() {
private ScannerReport.Symbol.Builder builder = ScannerReport.Symbol.newBuilder();
private ScannerReport.TextRange.Builder rangeBuilder = ScannerReport.TextRange.newBuilder();
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.sensor.highlighting.internal.DefaultHighlighting;
import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure;
+import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbolTable;
import org.sonar.api.config.Settings;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.api.measures.Measure;
import org.sonar.scanner.cpd.index.SonarCpdBlockIndex;
import org.sonar.scanner.index.BatchComponentCache;
import org.sonar.scanner.issue.ModuleIssues;
+import org.sonar.scanner.protocol.output.ScannerReportWriter;
import org.sonar.scanner.report.ReportPublisher;
import org.sonar.scanner.scan.measure.MeasureCache;
-import org.sonar.scanner.sensor.DefaultSensorStorage;
import org.sonar.scanner.sensor.coverage.CoverageExclusions;
import static org.assertj.core.api.Assertions.assertThat;
private BatchComponentCache resourceCache;
@Before
- public void prepare() {
+ public void prepare() throws Exception {
MetricFinder metricFinder = mock(MetricFinder.class);
when(metricFinder.<Integer>findByKey(CoreMetrics.NCLOC_KEY)).thenReturn(CoreMetrics.NCLOC);
when(metricFinder.<String>findByKey(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION_KEY)).thenReturn(CoreMetrics.FUNCTION_COMPLEXITY_DISTRIBUTION);
CoverageExclusions coverageExclusions = mock(CoverageExclusions.class);
when(coverageExclusions.accept(any(Resource.class), any(Measure.class))).thenReturn(true);
resourceCache = new BatchComponentCache();
+ ReportPublisher reportPublisher = mock(ReportPublisher.class);
+ when(reportPublisher.getWriter()).thenReturn(new ScannerReportWriter(temp.newFolder()));
underTest = new DefaultSensorStorage(metricFinder,
- moduleIssues, settings, coverageExclusions, resourceCache, mock(ReportPublisher.class), measureCache, mock(SonarCpdBlockIndex.class));
+ moduleIssues, settings, coverageExclusions, resourceCache, reportPublisher, measureCache, mock(SonarCpdBlockIndex.class));
}
@Test
assertThat(m.getMetric()).isEqualTo(CoreMetrics.NCLOC);
}
+ @Test(expected = UnsupportedOperationException.class)
+ public void duplicateHighlighting() throws Exception {
+ Resource sonarFile = File.create("src/Foo.java").setEffectiveKey("foo:src/Foo.java");
+ DefaultInputFile inputFile = new DefaultInputFile("foo", "src/Foo.java")
+ .setModuleBaseDir(temp.newFolder().toPath());
+ resourceCache.add(sonarFile, null).setInputComponent(inputFile);
+ DefaultHighlighting h = new DefaultHighlighting(null)
+ .onFile(inputFile);
+ underTest.store(h);
+ underTest.store(h);
+ }
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void duplicateSymbolTable() throws Exception {
+ Resource sonarFile = File.create("src/Foo.java").setEffectiveKey("foo:src/Foo.java");
+ DefaultInputFile inputFile = new DefaultInputFile("foo", "src/Foo.java")
+ .setModuleBaseDir(temp.newFolder().toPath());
+ resourceCache.add(sonarFile, null).setInputComponent(inputFile);
+ DefaultSymbolTable st = new DefaultSymbolTable(null)
+ .onFile(inputFile);
+ underTest.store(st);
+ underTest.store(st);
+ }
+
}