diff options
Diffstat (limited to 'sonar-batch/src')
36 files changed, 899 insertions, 197 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/highlighting/DefaultHighlightingBuilder.java b/sonar-batch/src/main/java/org/sonar/batch/highlighting/DefaultHighlightingBuilder.java new file mode 100644 index 00000000000..786ad0cca68 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/highlighting/DefaultHighlightingBuilder.java @@ -0,0 +1,52 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.highlighting; + +import com.google.common.base.Preconditions; +import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; +import org.sonar.batch.index.ComponentDataCache; +import org.sonar.core.source.SnapshotDataTypes; + +public class DefaultHighlightingBuilder implements HighlightingBuilder { + + private final SyntaxHighlightingDataBuilder builder; + private String componentKey; + private ComponentDataCache cache; + private boolean done = false; + + public DefaultHighlightingBuilder(String componentKey, ComponentDataCache cache) { + this.componentKey = componentKey; + this.cache = cache; + this.builder = new SyntaxHighlightingDataBuilder(); + } + + @Override + public HighlightingBuilder highlight(int startOffset, int endOffset, TypeOfText typeOfText) { + Preconditions.checkState(!done, "done() already called"); + builder.registerHighlightingRule(startOffset, endOffset, typeOfText.cssClass()); + return this; + } + + @Override + public void done() { + Preconditions.checkState(!done, "done() already called"); + cache.setData(componentKey, SnapshotDataTypes.SYNTAX_HIGHLIGHTING, builder.build()); + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/source/SyntaxHighlightingData.java b/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingData.java index cf0dde3580f..56c9b795ac9 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/source/SyntaxHighlightingData.java +++ b/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingData.java @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.batch.source; +package org.sonar.batch.highlighting; import org.sonar.batch.index.Data; @@ -34,6 +34,10 @@ public class SyntaxHighlightingData implements Data { this.syntaxHighlightingRuleSet = syntaxHighlightingRuleSet; } + public List<SyntaxHighlightingRule> syntaxHighlightingRuleSet() { + return syntaxHighlightingRuleSet; + } + @Override public String writeString() { StringBuilder sb = new StringBuilder(); @@ -51,8 +55,4 @@ public class SyntaxHighlightingData implements Data { return sb.toString(); } - @Override - public void readString(String s) { - throw new UnsupportedOperationException(); - } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/source/SyntaxHighlightingDataBuilder.java b/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingDataBuilder.java index 58dbd717a58..38ae875af98 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/source/SyntaxHighlightingDataBuilder.java +++ b/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingDataBuilder.java @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.batch.source; +package org.sonar.batch.highlighting; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Predicate; @@ -26,6 +26,7 @@ import com.google.common.collect.Ordering; import org.slf4j.LoggerFactory; import javax.annotation.Nullable; + import java.util.Collection; import java.util.List; @@ -83,11 +84,11 @@ public class SyntaxHighlightingDataBuilder { } @VisibleForTesting - protected List<SyntaxHighlightingRule> getSortedRules() { + public List<SyntaxHighlightingRule> getSortedRules() { Ordering<SyntaxHighlightingRule> ruleOrdering = new Ordering<SyntaxHighlightingRule>() { @Override public int compare(@Nullable SyntaxHighlightingRule left, - @Nullable SyntaxHighlightingRule right) { + @Nullable SyntaxHighlightingRule right) { int result; if (left != null && right != null) { result = left.getStartPosition() - right.getStartPosition(); @@ -100,6 +101,6 @@ public class SyntaxHighlightingDataBuilder { } }; - return ruleOrdering.immutableSortedCopy(syntaxHighlightingRuleSet); + return ruleOrdering.sortedCopy(syntaxHighlightingRuleSet); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/source/SyntaxHighlightingRule.java b/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingRule.java index d8232c1ba9d..08985752d60 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/source/SyntaxHighlightingRule.java +++ b/sonar-batch/src/main/java/org/sonar/batch/highlighting/SyntaxHighlightingRule.java @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.batch.source; +package org.sonar.batch.highlighting; import java.io.Serializable; diff --git a/sonar-batch/src/main/java/org/sonar/batch/source/DefaultSymbol.java b/sonar-batch/src/main/java/org/sonar/batch/highlighting/package-info.java index 629633a05de..93b92f3e9ae 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/source/DefaultSymbol.java +++ b/sonar-batch/src/main/java/org/sonar/batch/highlighting/package-info.java @@ -17,38 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +@ParametersAreNonnullByDefault +package org.sonar.batch.highlighting; -package org.sonar.batch.source; - -import com.google.common.base.Objects; -import org.sonar.api.source.Symbol; - -public class DefaultSymbol implements Symbol { - - private final int declarationStartOffset; - private final int declarationEndOffset; - - public DefaultSymbol(int startOffset, int endOffset) { - this.declarationStartOffset = startOffset; - this.declarationEndOffset = endOffset; - } - - public int getDeclarationStartOffset() { - return declarationStartOffset; - } - - public int getDeclarationEndOffset() { - return declarationEndOffset; - } - - public String getFullyQualifiedName() { - return null; - } - - @Override - public String toString() { - return Objects.toStringHelper("Symbol") - .add("offset", String.format("%d-%d", declarationStartOffset, declarationEndOffset)) - .toString(); - } -} +import javax.annotation.ParametersAreNonnullByDefault; diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/ComponentDataCache.java b/sonar-batch/src/main/java/org/sonar/batch/index/ComponentDataCache.java index 16be9501117..0523212bf75 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/ComponentDataCache.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/ComponentDataCache.java @@ -21,6 +21,8 @@ package org.sonar.batch.index; import org.sonar.api.BatchComponent; +import javax.annotation.CheckForNull; + public class ComponentDataCache implements BatchComponent { private final Cache cache; @@ -37,10 +39,12 @@ public class ComponentDataCache implements BatchComponent { return setData(componentKey, dataType, new StringData(data)); } + @CheckForNull public <D extends Data> D getData(String componentKey, String dataType) { return (D) cache.get(componentKey, dataType); } + @CheckForNull public String getStringData(String componentKey, String dataType) { Data data = (Data) cache.get(componentKey, dataType); return data == null ? null : ((StringData) data).data(); diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/Data.java b/sonar-batch/src/main/java/org/sonar/batch/index/Data.java index 66e5b596fc4..aa47c04e799 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/Data.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/Data.java @@ -25,6 +25,4 @@ public interface Data extends Serializable { String writeString(); - void readString(String s); - } diff --git a/sonar-batch/src/main/java/org/sonar/batch/index/StringData.java b/sonar-batch/src/main/java/org/sonar/batch/index/StringData.java index 17605657112..6a88b5979b2 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/index/StringData.java +++ b/sonar-batch/src/main/java/org/sonar/batch/index/StringData.java @@ -37,9 +37,4 @@ public class StringData implements Data { public String writeString() { return data; } - - @Override - public void readString(String s) { - this.data = s; - } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java index c3aa2646c6c..c305474b7f2 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java +++ b/sonar-batch/src/main/java/org/sonar/batch/mediumtest/BatchMediumTester.java @@ -20,14 +20,19 @@ package org.sonar.batch.mediumtest; import org.apache.commons.io.IOUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sonar.api.SonarPlugin; import org.sonar.api.batch.bootstrap.ProjectReactor; import org.sonar.api.batch.debt.internal.DefaultDebtModel; 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.DefaultInputFile; +import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; import org.sonar.api.batch.sensor.issue.Issue; import org.sonar.api.batch.sensor.measure.Measure; +import org.sonar.api.batch.sensor.symbol.Symbol; import org.sonar.api.config.Settings; import org.sonar.api.measures.CoreMetrics; import org.sonar.api.measures.Metric; @@ -36,6 +41,9 @@ import org.sonar.api.resources.Languages; import org.sonar.batch.bootstrap.PluginsReferential; import org.sonar.batch.bootstrapper.Batch; import org.sonar.batch.bootstrapper.EnvironmentInformation; +import org.sonar.batch.highlighting.SyntaxHighlightingData; +import org.sonar.batch.highlighting.SyntaxHighlightingRule; +import org.sonar.batch.index.ComponentDataCache; import org.sonar.batch.protocol.input.ActiveRule; import org.sonar.batch.protocol.input.GlobalReferentials; import org.sonar.batch.protocol.input.ProjectReferentials; @@ -47,8 +55,12 @@ import org.sonar.batch.scan2.AnalyzerMeasureCache; import org.sonar.batch.scan2.ProjectScanContainer; import org.sonar.batch.scan2.ScanTaskObserver; import org.sonar.batch.settings.SettingsReferential; +import org.sonar.batch.symbol.SymbolData; import org.sonar.core.plugins.DefaultPluginMetadata; import org.sonar.core.plugins.RemotePlugin; +import org.sonar.core.source.SnapshotDataTypes; + +import javax.annotation.CheckForNull; import java.io.File; import java.io.FileReader; @@ -59,6 +71,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Properties; +import java.util.Set; public class BatchMediumTester { @@ -200,13 +213,19 @@ public class BatchMediumTester { } public static class TaskResult implements ScanTaskObserver { + + private static final Logger LOG = LoggerFactory.getLogger(BatchMediumTester.TaskResult.class); + private List<Issue> issues = new ArrayList<Issue>(); private List<Measure> measures = new ArrayList<Measure>(); private List<InputFile> inputFiles = new ArrayList<InputFile>(); private List<InputDir> inputDirs = new ArrayList<InputDir>(); + private Map<InputFile, SyntaxHighlightingData> highlightingPerFile = new HashMap<InputFile, SyntaxHighlightingData>(); + private Map<InputFile, SymbolData> symbolTablePerFile = new HashMap<InputFile, SymbolData>(); @Override public void scanTaskCompleted(ProjectScanContainer container) { + LOG.info("Store analysis results in memory for later assertions in medium test"); for (Issue issue : container.getComponentByType(AnalyzerIssueCache.class).all()) { issues.add(issue); } @@ -223,6 +242,19 @@ public class BatchMediumTester { inputDirs.add((InputDir) inputPath); } } + + ComponentDataCache componentDataCache = container.getComponentByType(ComponentDataCache.class); + for (InputFile file : inputFiles) { + SyntaxHighlightingData highlighting = componentDataCache.getData(((DefaultInputFile) file).key(), SnapshotDataTypes.SYNTAX_HIGHLIGHTING); + if (highlighting != null) { + highlightingPerFile.put(file, highlighting); + } + SymbolData symbolTable = componentDataCache.getData(((DefaultInputFile) file).key(), SnapshotDataTypes.SYMBOL_HIGHLIGHTING); + if (symbolTable != null) { + symbolTablePerFile.put(file, symbolTable); + } + } + } public List<Issue> issues() { @@ -240,6 +272,43 @@ public class BatchMediumTester { public List<InputDir> inputDirs() { return inputDirs; } + + /** + * Get highlighting type at a given position in an inputfile + * @param charIndex 0-based offset in file + */ + @CheckForNull + public HighlightingBuilder.TypeOfText highlightingTypeFor(InputFile file, int charIndex) { + SyntaxHighlightingData syntaxHighlightingData = highlightingPerFile.get(file); + if (syntaxHighlightingData == null) { + return null; + } + for (SyntaxHighlightingRule sortedRule : syntaxHighlightingData.syntaxHighlightingRuleSet()) { + if (sortedRule.getStartPosition() <= charIndex && sortedRule.getEndPosition() > charIndex) { + return HighlightingBuilder.TypeOfText.forCssClass(sortedRule.getTextType()); + } + } + return null; + } + + /** + * Get list of all positions of a symbol in an inputfile + * @param symbolStartOffset 0-based start offset for the symbol in file + * @param symbolEndOffset 0-based end offset for the symbol in file + */ + @CheckForNull + public Set<Integer> symbolReferencesFor(InputFile file, int symbolStartOffset, int symbolEndOffset) { + SymbolData data = symbolTablePerFile.get(file); + if (data == null) { + return null; + } + for (Symbol symbol : data.referencesBySymbol().keySet()) { + if (symbol.getDeclarationStartOffset() == symbolStartOffset && symbol.getDeclarationEndOffset() == symbolEndOffset) { + return data.referencesBySymbol().get(symbol); + } + } + return null; + } } private static class FakeGlobalReferentialsLoader implements GlobalReferentialsLoader { diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdaptor.java b/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdaptor.java index a0c99598d31..1de8fd7201c 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdaptor.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan/SensorContextAdaptor.java @@ -23,15 +23,18 @@ import org.sonar.api.batch.fs.FileSystem; 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.DefaultInputFile; import org.sonar.api.batch.measure.Metric; import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; import org.sonar.api.batch.sensor.issue.Issue; import org.sonar.api.batch.sensor.issue.IssueBuilder; import org.sonar.api.batch.sensor.issue.internal.DefaultIssueBuilder; import org.sonar.api.batch.sensor.measure.Measure; import org.sonar.api.batch.sensor.measure.MeasureBuilder; import org.sonar.api.batch.sensor.measure.internal.DefaultMeasureBuilder; +import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder; import org.sonar.api.component.ResourcePerspectives; import org.sonar.api.config.Settings; import org.sonar.api.issue.Issuable; @@ -46,6 +49,9 @@ import org.sonar.api.resources.Project; import org.sonar.api.resources.Resource; import org.sonar.api.resources.Scopes; import org.sonar.api.rule.RuleKey; +import org.sonar.batch.highlighting.DefaultHighlightingBuilder; +import org.sonar.batch.index.ComponentDataCache; +import org.sonar.batch.symbol.DefaultSymbolTableBuilder; import java.io.Serializable; @@ -62,9 +68,10 @@ public class SensorContextAdaptor implements SensorContext { private Settings settings; private FileSystem fs; private ActiveRules activeRules; + private ComponentDataCache componentDataCache; public SensorContextAdaptor(org.sonar.api.batch.SensorContext sensorContext, MetricFinder metricFinder, Project project, ResourcePerspectives perspectives, - Settings settings, FileSystem fs, ActiveRules activeRules) { + Settings settings, FileSystem fs, ActiveRules activeRules, ComponentDataCache componentDataCache) { this.sensorContext = sensorContext; this.metricFinder = metricFinder; this.project = project; @@ -72,6 +79,7 @@ public class SensorContextAdaptor implements SensorContext { this.settings = settings; this.fs = fs; this.activeRules = activeRules; + this.componentDataCache = componentDataCache; } @Override @@ -236,4 +244,14 @@ public class SensorContextAdaptor implements SensorContext { .build(); } + @Override + public HighlightingBuilder highlightingBuilder(InputFile inputFile) { + return new DefaultHighlightingBuilder(((DefaultInputFile) inputFile).key(), componentDataCache); + } + + @Override + public SymbolTableBuilder symbolTableBuilder(InputFile inputFile) { + return new DefaultSymbolTableBuilder(((DefaultInputFile) inputFile).key(), componentDataCache); + } + } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalysisPublisher.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalysisPublisher.java index 757f320f559..7fb7dacf375 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalysisPublisher.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalysisPublisher.java @@ -44,9 +44,11 @@ public final class AnalysisPublisher { private final FileSystem fs; private final AnalyzerMeasureCache measureCache; private final ProjectDefinition def; - private AnalyzerIssueCache issueCache; + private final AnalyzerIssueCache issueCache; - public AnalysisPublisher(ProjectDefinition def, Settings settings, FileSystem fs, AnalyzerMeasureCache measureCache, AnalyzerIssueCache analyzerIssueCache) { + public AnalysisPublisher(ProjectDefinition def, Settings settings, FileSystem fs, + AnalyzerMeasureCache measureCache, + AnalyzerIssueCache analyzerIssueCache) { this.def = def; this.settings = settings; this.fs = fs; @@ -132,8 +134,9 @@ public final class AnalysisPublisher { for (Measure<?> measure : measureCache.byModule(def.getKey())) { jsonWriter.beginObject() .prop("metricKey", measure.metric().key()); - if (measure.inputFile() != null) { - jsonWriter.prop("filePath", measure.inputFile().relativePath()); + InputFile inputFile = measure.inputFile(); + if (inputFile != null) { + jsonWriter.prop("filePath", inputFile.relativePath()); } jsonWriter.prop("value", String.valueOf(measure.value())) .endObject(); diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerOptimizer.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerOptimizer.java index fb461854c69..4ae3ddfce09 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerOptimizer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerOptimizer.java @@ -19,16 +19,19 @@ */ package org.sonar.batch.scan2; -import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor; - +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.sonar.api.BatchComponent; import org.sonar.api.batch.fs.FilePredicate; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.rule.ActiveRules; +import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor; public class AnalyzerOptimizer implements BatchComponent { + private static final Logger LOG = LoggerFactory.getLogger(AnalyzerOptimizer.class); + private final FileSystem fs; private final ActiveRules activeRules; @@ -41,10 +44,15 @@ public class AnalyzerOptimizer implements BatchComponent { * Decide if the given Analyzer should be executed. */ public boolean shouldExecute(DefaultSensorDescriptor descriptor) { - // FS Conditions - boolean fsCondition = fsCondition(descriptor); - boolean activeRulesCondition = activeRulesCondition(descriptor); - return fsCondition && activeRulesCondition; + if (!fsCondition(descriptor)) { + LOG.debug("'{}' skipped because there is no related file in current project", descriptor.name()); + return false; + } + if (!activeRulesCondition(descriptor)) { + LOG.debug("'{}' skipped because there is no related rule activated in the quality profile", descriptor.name()); + return false; + } + return true; } private boolean activeRulesCondition(DefaultSensorDescriptor descriptor) { diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java index 6f4b2bdec70..dcd6efd1ca4 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultSensorContext.java @@ -23,10 +23,12 @@ import com.google.common.base.Strings; import org.sonar.api.batch.bootstrap.ProjectDefinition; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.measure.Metric; import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.batch.rule.internal.DefaultActiveRule; import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; import org.sonar.api.batch.sensor.issue.Issue; import org.sonar.api.batch.sensor.issue.IssueBuilder; import org.sonar.api.batch.sensor.issue.internal.DefaultIssue; @@ -35,11 +37,15 @@ import org.sonar.api.batch.sensor.measure.Measure; import org.sonar.api.batch.sensor.measure.MeasureBuilder; import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; import org.sonar.api.batch.sensor.measure.internal.DefaultMeasureBuilder; +import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder; import org.sonar.api.config.Settings; import org.sonar.api.rule.RuleKey; import org.sonar.api.utils.MessageException; +import org.sonar.batch.highlighting.DefaultHighlightingBuilder; +import org.sonar.batch.index.ComponentDataCache; import org.sonar.batch.issue.IssueFilters; import org.sonar.batch.scan.SensorContextAdaptor; +import org.sonar.batch.symbol.DefaultSymbolTableBuilder; import org.sonar.core.component.ComponentKeys; import java.io.Serializable; @@ -53,9 +59,10 @@ public class DefaultSensorContext implements SensorContext { private final FileSystem fs; private final ActiveRules activeRules; private final IssueFilters issueFilters; + private final ComponentDataCache componentDataCache; public DefaultSensorContext(ProjectDefinition def, AnalyzerMeasureCache measureCache, AnalyzerIssueCache issueCache, - Settings settings, FileSystem fs, ActiveRules activeRules, IssueFilters issueFilters) { + Settings settings, FileSystem fs, ActiveRules activeRules, IssueFilters issueFilters, ComponentDataCache componentDataCache) { this.def = def; this.measureCache = measureCache; this.issueCache = issueCache; @@ -63,6 +70,7 @@ public class DefaultSensorContext implements SensorContext { this.fs = fs; this.activeRules = activeRules; this.issueFilters = issueFilters; + this.componentDataCache = componentDataCache; } @Override @@ -155,7 +163,16 @@ public class DefaultSensorContext implements SensorContext { if (issue.severity() == null) { issue.setSeverity(activeRule.severity()); } + } + @Override + public HighlightingBuilder highlightingBuilder(InputFile inputFile) { + return new DefaultHighlightingBuilder(((DefaultInputFile) inputFile).key(), componentDataCache); + } + + @Override + public SymbolTableBuilder symbolTableBuilder(InputFile inputFile) { + return new DefaultSymbolTableBuilder(((DefaultInputFile) inputFile).key(), componentDataCache); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java index b0738e420e4..e13fca37d28 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java @@ -34,6 +34,7 @@ import org.sonar.batch.bootstrap.ExtensionInstaller; import org.sonar.batch.bootstrap.ExtensionMatcher; import org.sonar.batch.bootstrap.ExtensionUtils; import org.sonar.batch.index.Caches; +import org.sonar.batch.index.ComponentDataCache; import org.sonar.batch.languages.DefaultLanguagesReferential; import org.sonar.batch.profiling.PhasesSumUpTimeProfiler; import org.sonar.batch.referential.DefaultProjectReferentialsLoader; @@ -104,6 +105,8 @@ public class ProjectScanContainer extends ComponentContainer { // issues AnalyzerIssueCache.class, + ComponentDataCache.class, + ScanTaskObservers.class); } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/SensorsExecutor.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/SensorsExecutor.java index 14b6326b150..d437eadb6fd 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/SensorsExecutor.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/SensorsExecutor.java @@ -19,13 +19,12 @@ */ package org.sonar.batch.scan2; -import org.sonar.api.batch.sensor.Sensor; -import org.sonar.api.batch.sensor.SensorContext; -import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor; - import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.sonar.api.BatchComponent; +import org.sonar.api.batch.sensor.Sensor; +import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.internal.DefaultSensorDescriptor; import org.sonar.batch.bootstrap.BatchExtensionDictionnary; import java.util.Collection; @@ -51,7 +50,6 @@ public class SensorsExecutor implements BatchComponent { analyzer.describe(descriptor); if (!optimizer.shouldExecute(descriptor)) { - LOG.debug("Analyzer skipped: " + descriptor.name()); continue; } diff --git a/sonar-batch/src/main/java/org/sonar/batch/source/DefaultHighlightable.java b/sonar-batch/src/main/java/org/sonar/batch/source/DefaultHighlightable.java index 249450fad15..5b15a3abcd8 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/source/DefaultHighlightable.java +++ b/sonar-batch/src/main/java/org/sonar/batch/source/DefaultHighlightable.java @@ -21,12 +21,15 @@ package org.sonar.batch.source; import org.sonar.api.component.Component; import org.sonar.api.source.Highlightable; +import org.sonar.batch.highlighting.SyntaxHighlightingDataBuilder; import org.sonar.batch.index.ComponentDataCache; import org.sonar.core.source.SnapshotDataTypes; /** * @since 3.6 + * @deprecated since 4.5 no more used in batch 2.0 */ +@Deprecated public class DefaultHighlightable implements Highlightable { private final Component component; @@ -41,7 +44,7 @@ public class DefaultHighlightable implements Highlightable { @Override public HighlightingBuilder newHighlighting() { - return new DefaultHighlightingBuilder(); + return new DefaultHighlightingBuilder(component.key(), cache, builder); } @Override @@ -53,7 +56,17 @@ public class DefaultHighlightable implements Highlightable { return builder; } - private class DefaultHighlightingBuilder implements HighlightingBuilder { + private static class DefaultHighlightingBuilder implements HighlightingBuilder { + + private final SyntaxHighlightingDataBuilder builder; + private String componentKey; + private ComponentDataCache cache; + + public DefaultHighlightingBuilder(String componentKey, ComponentDataCache cache, SyntaxHighlightingDataBuilder builder) { + this.componentKey = componentKey; + this.cache = cache; + this.builder = builder; + } @Override public HighlightingBuilder highlight(int startOffset, int endOffset, String typeOfText) { @@ -63,7 +76,7 @@ public class DefaultHighlightable implements Highlightable { @Override public void done() { - cache.setStringData(component().key(), SnapshotDataTypes.SYNTAX_HIGHLIGHTING, builder.build().writeString()); + cache.setData(componentKey, SnapshotDataTypes.SYNTAX_HIGHLIGHTING, builder.build()); } } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/source/DefaultSymbolTable.java b/sonar-batch/src/main/java/org/sonar/batch/source/DefaultSymbolTable.java index 0d66c31b8f1..ee8997c259c 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/source/DefaultSymbolTable.java +++ b/sonar-batch/src/main/java/org/sonar/batch/source/DefaultSymbolTable.java @@ -20,35 +20,35 @@ package org.sonar.batch.source; -import com.google.common.collect.Multimap; +import com.google.common.collect.SortedSetMultimap; import com.google.common.collect.TreeMultimap; +import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbol; import org.sonar.api.source.Symbol; import org.sonar.api.source.Symbolizable; +import org.sonar.batch.symbol.DefaultSymbolTableBuilder; -import java.io.Serializable; import java.util.ArrayList; -import java.util.Comparator; import java.util.List; public class DefaultSymbolTable implements Symbolizable.SymbolTable { - private Multimap<Symbol, Integer> referencesBySymbol; + private SortedSetMultimap<org.sonar.api.batch.sensor.symbol.Symbol, Integer> referencesBySymbol; - private DefaultSymbolTable(Multimap<Symbol, Integer> referencesBySymbol) { + private DefaultSymbolTable(SortedSetMultimap<org.sonar.api.batch.sensor.symbol.Symbol, Integer> referencesBySymbol) { this.referencesBySymbol = referencesBySymbol; } - public static Builder builder() { - return new Builder(); - } - - public Multimap<Symbol, Integer> getReferencesBySymbol() { + public SortedSetMultimap<org.sonar.api.batch.sensor.symbol.Symbol, Integer> getReferencesBySymbol() { return referencesBySymbol; } @Override public List<Symbol> symbols() { - return new ArrayList<Symbol>(referencesBySymbol.keySet()); + List<Symbol> result = new ArrayList<Symbol>(); + for (org.sonar.api.batch.sensor.symbol.Symbol symbol : referencesBySymbol.keySet()) { + result.add((Symbol) symbol); + } + return result; } @Override @@ -58,15 +58,17 @@ public class DefaultSymbolTable implements Symbolizable.SymbolTable { public static class Builder implements Symbolizable.SymbolTableBuilder { - private final Multimap<Symbol, Integer> referencesBySymbol; + private final SortedSetMultimap<org.sonar.api.batch.sensor.symbol.Symbol, Integer> referencesBySymbol; + private final String componentKey; - public Builder() { - referencesBySymbol = TreeMultimap.create(new SymbolComparator(), new ReferenceComparator()); + public Builder(String componentKey) { + this.componentKey = componentKey; + referencesBySymbol = TreeMultimap.create(new DefaultSymbolTableBuilder.SymbolComparator(), new DefaultSymbolTableBuilder.ReferenceComparator()); } @Override public Symbol newSymbol(int fromOffset, int toOffset) { - Symbol symbol = new DefaultSymbol(fromOffset, toOffset); + Symbol symbol = new DefaultSymbol(componentKey, fromOffset, toOffset); referencesBySymbol.put(symbol, symbol.getDeclarationStartOffset()); return symbol; } @@ -84,24 +86,5 @@ public class DefaultSymbolTable implements Symbolizable.SymbolTable { return new DefaultSymbolTable(referencesBySymbol); } - private static class SymbolComparator implements Comparator<Symbol>, Serializable { - @Override - public int compare(Symbol left, Symbol right) { - return left.getDeclarationStartOffset() - right.getDeclarationStartOffset(); - } - } - - private static class ReferenceComparator implements Comparator<Integer>, Serializable { - @Override - public int compare(Integer left, Integer right) { - int result; - if (left != null & right != null) { - result = left - right; - } else { - result = left == null ? -1 : 1; - } - return result; - } - } } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/source/DefaultSymbolizable.java b/sonar-batch/src/main/java/org/sonar/batch/source/DefaultSymbolizable.java index 1e3b33d939e..de073e50629 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/source/DefaultSymbolizable.java +++ b/sonar-batch/src/main/java/org/sonar/batch/source/DefaultSymbolizable.java @@ -23,6 +23,7 @@ package org.sonar.batch.source; import org.sonar.api.component.Component; import org.sonar.api.source.Symbolizable; import org.sonar.batch.index.ComponentDataCache; +import org.sonar.batch.symbol.SymbolData; import org.sonar.core.source.SnapshotDataTypes; public class DefaultSymbolizable implements Symbolizable { @@ -42,12 +43,12 @@ public class DefaultSymbolizable implements Symbolizable { @Override public SymbolTableBuilder newSymbolTableBuilder() { - return new DefaultSymbolTable.Builder(); + return new DefaultSymbolTable.Builder(component.key()); } @Override public void setSymbolTable(SymbolTable symbolTable) { - SymbolData symbolData = new SymbolData(symbolTable); + SymbolData symbolData = new SymbolData(((DefaultSymbolTable) symbolTable).getReferencesBySymbol()); cache.setStringData(component().key(), SnapshotDataTypes.SYMBOL_HIGHLIGHTING, symbolData.writeString()); } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/source/HighlightableBuilder.java b/sonar-batch/src/main/java/org/sonar/batch/source/HighlightableBuilder.java index 82f5c8dd213..d20fbebb147 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/source/HighlightableBuilder.java +++ b/sonar-batch/src/main/java/org/sonar/batch/source/HighlightableBuilder.java @@ -28,11 +28,14 @@ import org.sonar.core.component.PerspectiveBuilder; import org.sonar.core.component.ResourceComponent; import javax.annotation.CheckForNull; + import java.util.Set; /** * @since 3.6 + * @deprecated since 4.5 no more used in batch 2.0 */ +@Deprecated public class HighlightableBuilder extends PerspectiveBuilder<Highlightable> { private static final Set<String> SUPPORTED_QUALIFIERS = ImmutableSet.of(Qualifiers.FILE, Qualifiers.UNIT_TEST_FILE); diff --git a/sonar-batch/src/main/java/org/sonar/batch/symbol/DefaultSymbolTableBuilder.java b/sonar-batch/src/main/java/org/sonar/batch/symbol/DefaultSymbolTableBuilder.java new file mode 100644 index 00000000000..ed347e60bd0 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/symbol/DefaultSymbolTableBuilder.java @@ -0,0 +1,90 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.batch.symbol; + +import com.google.common.collect.SortedSetMultimap; +import com.google.common.collect.TreeMultimap; +import org.sonar.api.batch.sensor.symbol.Symbol; +import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder; +import org.sonar.api.batch.sensor.symbol.internal.DefaultSymbol; +import org.sonar.batch.index.ComponentDataCache; +import org.sonar.core.source.SnapshotDataTypes; + +import java.io.Serializable; +import java.util.Comparator; + +public class DefaultSymbolTableBuilder implements SymbolTableBuilder { + + private final String componentKey; + private final ComponentDataCache cache; + private final SortedSetMultimap<Symbol, Integer> referencesBySymbol; + + public DefaultSymbolTableBuilder(String componentKey, ComponentDataCache cache) { + this.componentKey = componentKey; + this.cache = cache; + this.referencesBySymbol = TreeMultimap.create(new SymbolComparator(), new ReferenceComparator()); + } + + @Override + public Symbol newSymbol(int fromOffset, int toOffset) { + Symbol symbol = new DefaultSymbol(componentKey, fromOffset, toOffset); + referencesBySymbol.put(symbol, symbol.getDeclarationStartOffset()); + return symbol; + } + + @Override + public void newReference(Symbol symbol, int fromOffset) { + String otherComponentKey = ((DefaultSymbol) symbol).componentKey(); + if (!otherComponentKey.equals(componentKey)) { + throw new UnsupportedOperationException("Cannot add reference from (" + componentKey + ") to another file (" + otherComponentKey + ")"); + } + if (fromOffset >= symbol.getDeclarationStartOffset() && fromOffset < symbol.getDeclarationEndOffset()) { + throw new UnsupportedOperationException("Cannot add reference (" + fromOffset + ") overlapping " + symbol); + } + referencesBySymbol.put(symbol, fromOffset); + } + + @Override + public void done() { + SymbolData symbolData = new SymbolData(referencesBySymbol); + cache.setData(componentKey, SnapshotDataTypes.SYMBOL_HIGHLIGHTING, symbolData); + } + + public static class SymbolComparator implements Comparator<Symbol>, Serializable { + @Override + public int compare(Symbol left, Symbol right) { + return left.getDeclarationStartOffset() - right.getDeclarationStartOffset(); + } + } + + public static class ReferenceComparator implements Comparator<Integer>, Serializable { + @Override + public int compare(Integer left, Integer right) { + int result; + if (left != null & right != null) { + result = left - right; + } else { + result = left == null ? -1 : 1; + } + return result; + } + } +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/source/SymbolData.java b/sonar-batch/src/main/java/org/sonar/batch/symbol/SymbolData.java index 38ed3ed42f9..11ab5cca7e5 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/source/SymbolData.java +++ b/sonar-batch/src/main/java/org/sonar/batch/symbol/SymbolData.java @@ -18,11 +18,10 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.batch.source; +package org.sonar.batch.symbol; -import com.google.common.collect.Multimap; -import org.sonar.api.source.Symbol; -import org.sonar.api.source.Symbolizable; +import com.google.common.collect.SortedSetMultimap; +import org.sonar.api.batch.sensor.symbol.Symbol; import org.sonar.batch.index.Data; import java.util.Collection; @@ -32,19 +31,21 @@ public class SymbolData implements Data { private static final String FIELD_SEPARATOR = ","; private static final String SYMBOL_SEPARATOR = ";"; - private final Symbolizable.SymbolTable symbolTable; + private final SortedSetMultimap<Symbol, Integer> referencesBySymbol; - public SymbolData(Symbolizable.SymbolTable symbolTable) { - this.symbolTable = symbolTable; + public SymbolData(SortedSetMultimap<Symbol, Integer> referencesBySymbol) { + this.referencesBySymbol = referencesBySymbol; + } + + public SortedSetMultimap<Symbol, Integer> referencesBySymbol() { + return referencesBySymbol; } @Override public String writeString() { StringBuilder sb = new StringBuilder(); - Multimap<Symbol, Integer> referencesBySymbol = ((DefaultSymbolTable)symbolTable).getReferencesBySymbol(); - - for (Symbol symbol : ((DefaultSymbolTable)symbolTable).getReferencesBySymbol().keySet()) { + for (Symbol symbol : referencesBySymbol.keySet()) { sb.append(symbol.getDeclarationStartOffset()) .append(FIELD_SEPARATOR) @@ -59,8 +60,4 @@ public class SymbolData implements Data { return sb.toString(); } - @Override - public void readString(String s) { - throw new UnsupportedOperationException(); - } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/highlighting/DefaultHighlightingBuilderTest.java b/sonar-batch/src/test/java/org/sonar/batch/highlighting/DefaultHighlightingBuilderTest.java new file mode 100644 index 00000000000..aefc5afd732 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/highlighting/DefaultHighlightingBuilderTest.java @@ -0,0 +1,50 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.highlighting; + +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder.TypeOfText; +import org.sonar.batch.index.ComponentDataCache; +import org.sonar.core.source.SnapshotDataTypes; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +public class DefaultHighlightingBuilderTest { + + @Test + public void should_apply_registered_highlighting() throws Exception { + + ComponentDataCache cache = mock(ComponentDataCache.class); + + DefaultHighlightingBuilder highlightable = new DefaultHighlightingBuilder("myComponent", cache); + highlightable + .highlight(0, 10, TypeOfText.KEYWORD) + .highlight(20, 30, TypeOfText.CPP_DOC) + .done(); + + ArgumentCaptor<SyntaxHighlightingData> argCaptor = ArgumentCaptor.forClass(SyntaxHighlightingData.class); + verify(cache).setData(eq("myComponent"), eq(SnapshotDataTypes.SYNTAX_HIGHLIGHTING), argCaptor.capture()); + assertThat(argCaptor.getValue().writeString()).isEqualTo("0,10,k;20,30,cppd;"); + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/source/SyntaxHighlightingDataBuilderTest.java b/sonar-batch/src/test/java/org/sonar/batch/highlighting/SyntaxHighlightingDataBuilderTest.java index c190edc3ac7..6fad264c831 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/source/SyntaxHighlightingDataBuilderTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/highlighting/SyntaxHighlightingDataBuilderTest.java @@ -17,9 +17,10 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.batch.source; +package org.sonar.batch.highlighting; +import org.sonar.batch.highlighting.SyntaxHighlightingDataBuilder; import org.junit.Before; import org.junit.Rule; import org.junit.Test; diff --git a/sonar-batch/src/test/java/org/sonar/batch/source/SyntaxHighlightingDataTest.java b/sonar-batch/src/test/java/org/sonar/batch/highlighting/SyntaxHighlightingDataTest.java index 8a9ece89ef3..59de88ca848 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/source/SyntaxHighlightingDataTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/highlighting/SyntaxHighlightingDataTest.java @@ -17,7 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.sonar.batch.source; +package org.sonar.batch.highlighting; import com.google.common.collect.Lists; import org.junit.Test; @@ -38,7 +38,7 @@ public class SyntaxHighlightingDataTest { SyntaxHighlightingRule.create(24, 38, "k"), SyntaxHighlightingRule.create(24, 65, "cppd"), SyntaxHighlightingRule.create(42, 50, "k") - ); + ); String serializedRules = new SyntaxHighlightingData(orderedHighlightingRules).writeString(); assertThat(serializedRules).isEqualTo("0,10,cd;10,12,k;12,20,cd;24,38,k;24,65,cppd;42,50,k;"); diff --git a/sonar-batch/src/test/java/org/sonar/batch/index/ComponentDataCacheTest.java b/sonar-batch/src/test/java/org/sonar/batch/index/ComponentDataCacheTest.java index ff0e7eed20d..3a8835e7a3c 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/index/ComponentDataCacheTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/index/ComponentDataCacheTest.java @@ -83,9 +83,5 @@ public class ComponentDataCacheTest { return String.valueOf(data); } - @Override - public void readString(String s) { - data = Long.parseLong(s); - } } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/highlighting/HighlightingMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/highlighting/HighlightingMediumTest.java new file mode 100644 index 00000000000..259b2ffcec0 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/highlighting/HighlightingMediumTest.java @@ -0,0 +1,92 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.mediumtest.highlighting; + +import com.google.common.collect.ImmutableMap; +import org.apache.commons.io.FileUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; +import org.sonar.batch.mediumtest.BatchMediumTester; +import org.sonar.batch.mediumtest.BatchMediumTester.TaskResult; +import org.sonar.batch.mediumtest.xoo.plugin.XooPlugin; + +import java.io.File; +import java.io.IOException; + +import static org.fest.assertions.Assertions.assertThat; + +public class HighlightingMediumTest { + + @org.junit.Rule + public TemporaryFolder temp = new TemporaryFolder(); + + public BatchMediumTester tester = BatchMediumTester.builder() + .registerPlugin("xoo", new XooPlugin()) + .addDefaultQProfile("xoo", "Sonar Way") + .bootstrapProperties(ImmutableMap.of("sonar.analysis.mode", "sensor")) + .build(); + + @Before + public void prepare() { + tester.start(); + } + + @After + public void stop() { + tester.stop(); + } + + @Test + public void computeSyntaxHighlightingOnTempProject() throws IOException { + + File baseDir = temp.newFolder(); + File srcDir = new File(baseDir, "src"); + srcDir.mkdir(); + + File xooFile = new File(srcDir, "sample.xoo"); + File xoohighlightingFile = new File(srcDir, "sample.xoo.highlighting"); + FileUtils.write(xooFile, "Sample xoo\ncontent"); + FileUtils.write(xoohighlightingFile, "0:10:s\n11:18:k"); + + TaskResult result = tester.newTask() + .properties(ImmutableMap.<String, String>builder() + .put("sonar.task", "scan") + .put("sonar.projectBaseDir", baseDir.getAbsolutePath()) + .put("sonar.projectKey", "com.foo.project") + .put("sonar.projectName", "Foo Project") + .put("sonar.projectVersion", "1.0-SNAPSHOT") + .put("sonar.projectDescription", "Description of Foo Project") + .put("sonar.sources", "src") + .build()) + .start(); + + InputFile file = result.inputFiles().get(0); + assertThat(result.highlightingTypeFor(file, 0)).isEqualTo(HighlightingBuilder.TypeOfText.STRING); + assertThat(result.highlightingTypeFor(file, 9)).isEqualTo(HighlightingBuilder.TypeOfText.STRING); + assertThat(result.highlightingTypeFor(file, 10)).isNull(); + assertThat(result.highlightingTypeFor(file, 11)).isEqualTo(HighlightingBuilder.TypeOfText.KEYWORD); + + } + +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java new file mode 100644 index 00000000000..c3875c625f3 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/symbol/SymbolMediumTest.java @@ -0,0 +1,87 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.mediumtest.symbol; + +import com.google.common.collect.ImmutableMap; +import org.apache.commons.io.FileUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.batch.mediumtest.BatchMediumTester; +import org.sonar.batch.mediumtest.BatchMediumTester.TaskResult; +import org.sonar.batch.mediumtest.xoo.plugin.XooPlugin; + +import java.io.File; +import java.io.IOException; + +import static org.fest.assertions.Assertions.assertThat; + +public class SymbolMediumTest { + + @org.junit.Rule + public TemporaryFolder temp = new TemporaryFolder(); + + public BatchMediumTester tester = BatchMediumTester.builder() + .registerPlugin("xoo", new XooPlugin()) + .addDefaultQProfile("xoo", "Sonar Way") + .bootstrapProperties(ImmutableMap.of("sonar.analysis.mode", "sensor")) + .build(); + + @Before + public void prepare() { + tester.start(); + } + + @After + public void stop() { + tester.stop(); + } + + @Test + public void computeSyntaxHighlightingOnTempProject() throws IOException { + + File baseDir = temp.newFolder(); + File srcDir = new File(baseDir, "src"); + srcDir.mkdir(); + + File xooFile = new File(srcDir, "sample.xoo"); + File xooSymbolFile = new File(srcDir, "sample.xoo.symbol"); + FileUtils.write(xooFile, "Sample xoo\ncontent\nanother xoo"); + FileUtils.write(xooSymbolFile, "7,10,27"); + + TaskResult result = tester.newTask() + .properties(ImmutableMap.<String, String>builder() + .put("sonar.task", "scan") + .put("sonar.projectBaseDir", baseDir.getAbsolutePath()) + .put("sonar.projectKey", "com.foo.project") + .put("sonar.projectName", "Foo Project") + .put("sonar.projectVersion", "1.0-SNAPSHOT") + .put("sonar.projectDescription", "Description of Foo Project") + .put("sonar.sources", "src") + .build()) + .start(); + + InputFile file = result.inputFiles().get(0); + assertThat(result.symbolReferencesFor(file, 7, 10)).containsOnly(7, 27); + } + +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/XooPlugin.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/XooPlugin.java index f281ea09899..78718da3682 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/XooPlugin.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/XooPlugin.java @@ -23,6 +23,8 @@ import org.sonar.api.SonarPlugin; import org.sonar.batch.mediumtest.xoo.plugin.base.Xoo; import org.sonar.batch.mediumtest.xoo.plugin.lang.MeasureSensor; import org.sonar.batch.mediumtest.xoo.plugin.lang.ScmActivitySensor; +import org.sonar.batch.mediumtest.xoo.plugin.lang.SymbolReferencesSensor; +import org.sonar.batch.mediumtest.xoo.plugin.lang.SyntaxHighlightingSensor; import org.sonar.batch.mediumtest.xoo.plugin.rule.CreateIssueByInternalKeySensor; import org.sonar.batch.mediumtest.xoo.plugin.rule.OneIssueOnDirPerFileSensor; import org.sonar.batch.mediumtest.xoo.plugin.rule.OneIssuePerLineSensor; @@ -38,6 +40,8 @@ public final class XooPlugin extends SonarPlugin { // language MeasureSensor.class, ScmActivitySensor.class, + SyntaxHighlightingSensor.class, + SymbolReferencesSensor.class, Xoo.class, // sensors diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/MeasureSensor.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/MeasureSensor.java index 9a4b46afd1a..c28ebd5a05c 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/MeasureSensor.java +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/MeasureSensor.java @@ -104,7 +104,7 @@ public class MeasureSensor implements Sensor { @Override public void describe(SensorDescriptor descriptor) { descriptor - .name("Xoo Measure Analyzer") + .name("Xoo Measure Sensor") .provides(CoreMetrics.LINES) .workOnLanguages(Xoo.KEY) .workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST); diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/SymbolReferencesSensor.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/SymbolReferencesSensor.java new file mode 100644 index 00000000000..91fa61e5c78 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/SymbolReferencesSensor.java @@ -0,0 +1,98 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.mediumtest.xoo.plugin.lang; + +import com.google.common.base.Splitter; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.sensor.Sensor; +import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.SensorDescriptor; +import org.sonar.api.batch.sensor.symbol.Symbol; +import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.batch.mediumtest.xoo.plugin.base.Xoo; +import org.sonar.batch.mediumtest.xoo.plugin.base.XooConstants; + +import java.io.File; +import java.io.IOException; +import java.util.Iterator; +import java.util.List; + +/** + * Parse files *.xoo.symbol + */ +public class SymbolReferencesSensor implements Sensor { + + private static final String SYMBOL_EXTENSION = ".symbol"; + + private void processFileHighlighting(InputFile inputFile, SensorContext context) { + File ioFile = inputFile.file(); + File symbolFile = new File(ioFile.getParentFile(), ioFile.getName() + SYMBOL_EXTENSION); + if (symbolFile.exists()) { + XooConstants.LOG.debug("Processing " + symbolFile.getAbsolutePath()); + try { + List<String> lines = FileUtils.readLines(symbolFile, context.fileSystem().encoding().name()); + int lineNumber = 0; + SymbolTableBuilder symbolTableBuilder = context.symbolTableBuilder(inputFile); + for (String line : lines) { + lineNumber++; + if (StringUtils.isBlank(line)) { + continue; + } + if (line.startsWith("#")) { + continue; + } + try { + Iterator<String> split = Splitter.on(",").split(line).iterator(); + int startOffset = Integer.parseInt(split.next()); + int endOffset = Integer.parseInt(split.next()); + Symbol s = symbolTableBuilder.newSymbol(startOffset, endOffset); + while (split.hasNext()) { + symbolTableBuilder.newReference(s, Integer.parseInt(split.next())); + } + } catch (Exception e) { + throw new IllegalStateException("Error processing line " + lineNumber + " of file " + symbolFile.getAbsolutePath(), e); + } + } + symbolTableBuilder.done(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + @Override + public void describe(SensorDescriptor descriptor) { + descriptor + .name("Xoo Highlighting Sensor") + .provides(CoreMetrics.LINES) + .workOnLanguages(Xoo.KEY) + .workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST); + } + + @Override + public void execute(SensorContext context) { + for (InputFile file : context.fileSystem().inputFiles(context.fileSystem().predicates().hasLanguages(Xoo.KEY))) { + processFileHighlighting(file, context); + } + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/SyntaxHighlightingSensor.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/SyntaxHighlightingSensor.java new file mode 100644 index 00000000000..5b78759dbb9 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/SyntaxHighlightingSensor.java @@ -0,0 +1,95 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +package org.sonar.batch.mediumtest.xoo.plugin.lang; + +import com.google.common.base.Splitter; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.sensor.Sensor; +import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.SensorDescriptor; +import org.sonar.api.batch.sensor.highlighting.HighlightingBuilder; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.batch.mediumtest.xoo.plugin.base.Xoo; +import org.sonar.batch.mediumtest.xoo.plugin.base.XooConstants; + +import java.io.File; +import java.io.IOException; +import java.util.Iterator; +import java.util.List; + +/** + * Parse files *.xoo.highlighting + */ +public class SyntaxHighlightingSensor implements Sensor { + + private static final String HIGHLIGHTING_EXTENSION = ".highlighting"; + + private void processFileHighlighting(InputFile inputFile, SensorContext context) { + File ioFile = inputFile.file(); + File highlightingFile = new File(ioFile.getParentFile(), ioFile.getName() + HIGHLIGHTING_EXTENSION); + if (highlightingFile.exists()) { + XooConstants.LOG.debug("Processing " + highlightingFile.getAbsolutePath()); + try { + List<String> lines = FileUtils.readLines(highlightingFile, context.fileSystem().encoding().name()); + int lineNumber = 0; + HighlightingBuilder highlightingBuilder = context.highlightingBuilder(inputFile); + for (String line : lines) { + lineNumber++; + if (StringUtils.isBlank(line)) { + continue; + } + if (line.startsWith("#")) { + continue; + } + try { + Iterator<String> split = Splitter.on(":").split(line).iterator(); + int startOffset = Integer.parseInt(split.next()); + int endOffset = Integer.parseInt(split.next()); + HighlightingBuilder.TypeOfText type = HighlightingBuilder.TypeOfText.forCssClass(split.next()); + highlightingBuilder.highlight(startOffset, endOffset, type); + } catch (Exception e) { + throw new IllegalStateException("Error processing line " + lineNumber + " of file " + highlightingFile.getAbsolutePath(), e); + } + } + highlightingBuilder.done(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + @Override + public void describe(SensorDescriptor descriptor) { + descriptor + .name("Xoo Highlighting Sensor") + .provides(CoreMetrics.LINES) + .workOnLanguages(Xoo.KEY) + .workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST); + } + + @Override + public void execute(SensorContext context) { + for (InputFile file : context.fileSystem().inputFiles(context.fileSystem().predicates().hasLanguages(Xoo.KEY))) { + processFileHighlighting(file, context); + } + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan/SensorContextAdapterTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan/SensorContextAdapterTest.java index b4a8fdab7f0..7b7eb21ee58 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/scan/SensorContextAdapterTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/scan/SensorContextAdapterTest.java @@ -42,6 +42,7 @@ import org.sonar.api.measures.MetricFinder; import org.sonar.api.resources.File; import org.sonar.api.resources.Project; import org.sonar.api.rule.RuleKey; +import org.sonar.batch.index.ComponentDataCache; import static org.fest.assertions.Assertions.assertThat; import static org.mockito.Matchers.eq; @@ -69,8 +70,9 @@ public class SensorContextAdapterTest { sensorContext = mock(SensorContext.class); settings = new Settings(); resourcePerspectives = mock(ResourcePerspectives.class); + ComponentDataCache componentDataCache = mock(ComponentDataCache.class); adaptor = new SensorContextAdaptor(sensorContext, metricFinder, new Project("myProject"), - resourcePerspectives, settings, fs, activeRules); + resourcePerspectives, settings, fs, activeRules, componentDataCache); } @Test diff --git a/sonar-batch/src/test/java/org/sonar/batch/source/DefaultHighlightableTest.java b/sonar-batch/src/test/java/org/sonar/batch/source/DefaultHighlightableTest.java index 421f5d87679..2f98e07cc79 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/source/DefaultHighlightableTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/source/DefaultHighlightableTest.java @@ -22,12 +22,17 @@ package org.sonar.batch.source; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.mockito.ArgumentCaptor; import org.sonar.api.component.Component; +import org.sonar.batch.highlighting.SyntaxHighlightingData; import org.sonar.batch.index.ComponentDataCache; import org.sonar.core.source.SnapshotDataTypes; import static org.fest.assertions.Assertions.assertThat; -import static org.mockito.Mockito.*; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; public class DefaultHighlightableTest { @@ -36,7 +41,7 @@ public class DefaultHighlightableTest { @Test public void should_store_highlighting_rules() throws Exception { - DefaultHighlightable highlightablePerspective = new DefaultHighlightable(null, null); + DefaultHighlightable highlightablePerspective = new DefaultHighlightable(mock(Component.class), null); highlightablePerspective.newHighlighting().highlight(0, 10, "k").highlight(20, 30, "cppd"); assertThat(highlightablePerspective.getHighlightingRules().getSortedRules()).hasSize(2); @@ -55,6 +60,8 @@ public class DefaultHighlightableTest { .highlight(20, 30, "cppd") .done(); - verify(cache).setStringData("myComponent", SnapshotDataTypes.SYNTAX_HIGHLIGHTING, "0,10,k;20,30,cppd;"); + ArgumentCaptor<SyntaxHighlightingData> argCaptor = ArgumentCaptor.forClass(SyntaxHighlightingData.class); + verify(cache).setData(eq("myComponent"), eq(SnapshotDataTypes.SYNTAX_HIGHLIGHTING), argCaptor.capture()); + assertThat(argCaptor.getValue().writeString()).isEqualTo("0,10,k;20,30,cppd;"); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/source/DefaultSymbolTableTest.java b/sonar-batch/src/test/java/org/sonar/batch/source/DefaultSymbolTableTest.java index 2e65c12473b..a1058b27d64 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/source/DefaultSymbolTableTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/source/DefaultSymbolTableTest.java @@ -35,7 +35,7 @@ public class DefaultSymbolTableTest { @Test public void should_order_symbol_and_references() throws Exception { - Symbolizable.SymbolTableBuilder symbolTableBuilder = new DefaultSymbolTable.Builder(); + Symbolizable.SymbolTableBuilder symbolTableBuilder = new DefaultSymbolTable.Builder("foo"); Symbol firstSymbol = symbolTableBuilder.newSymbol(10, 20); symbolTableBuilder.newReference(firstSymbol, 32); Symbol secondSymbol = symbolTableBuilder.newSymbol(84, 92); @@ -54,16 +54,16 @@ public class DefaultSymbolTableTest { public void should_reject_reference_conflicting_with_declaration() throws Exception { throwable.expect(UnsupportedOperationException.class); - Symbolizable.SymbolTableBuilder symbolTableBuilder = new DefaultSymbolTable.Builder(); + Symbolizable.SymbolTableBuilder symbolTableBuilder = new DefaultSymbolTable.Builder("foo"); Symbol symbol = symbolTableBuilder.newSymbol(10, 20); symbolTableBuilder.newReference(symbol, 15); } @Test public void test_toString() throws Exception { - Symbolizable.SymbolTableBuilder symbolTableBuilder = new DefaultSymbolTable.Builder(); + Symbolizable.SymbolTableBuilder symbolTableBuilder = new DefaultSymbolTable.Builder("foo"); Symbol symbol = symbolTableBuilder.newSymbol(10, 20); - assertThat(symbol.toString()).isEqualTo("Symbol{offset=10-20}"); + assertThat(symbol.toString()).isEqualTo("Symbol{component=foo, offset=10-20}"); } } diff --git a/sonar-batch/src/test/java/org/sonar/batch/source/SymbolDataTest.java b/sonar-batch/src/test/java/org/sonar/batch/source/SymbolDataTest.java deleted file mode 100644 index 8dfdd1cccd5..00000000000 --- a/sonar-batch/src/test/java/org/sonar/batch/source/SymbolDataTest.java +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SonarQube, open source software quality management tool. - * Copyright (C) 2008-2014 SonarSource - * mailto:contact AT sonarsource DOT com - * - * SonarQube is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * SonarQube is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -package org.sonar.batch.source; - -import org.junit.Test; -import org.sonar.api.source.Symbol; -import org.sonar.api.source.Symbolizable; - -import static org.fest.assertions.Assertions.assertThat; - -public class SymbolDataTest { - - @Test - public void should_serialize_symbols_in_natural_order() throws Exception { - - Symbolizable.SymbolTableBuilder symbolTableBuilder = new DefaultSymbolTable.Builder(); - Symbol firstSymbol = symbolTableBuilder.newSymbol(10, 20); - symbolTableBuilder.newReference(firstSymbol, 32); - Symbol secondSymbol = symbolTableBuilder.newSymbol(84, 92); - symbolTableBuilder.newReference(secondSymbol, 124); - Symbol thirdSymbol = symbolTableBuilder.newSymbol(55, 62); - symbolTableBuilder.newReference(thirdSymbol, 70); - Symbolizable.SymbolTable symbolTable = symbolTableBuilder.build(); - - SymbolData dataRepository = new SymbolData(symbolTable); - String serializedSymbolData = dataRepository.writeString(); - - assertThat(serializedSymbolData).isEqualTo("10,20,10,32;55,62,55,70;84,92,84,124;"); - } - - @Test - public void should_serialize_unused_symbol() throws Exception { - - Symbolizable.SymbolTableBuilder symbolTableBuilder = new DefaultSymbolTable.Builder(); - symbolTableBuilder.newSymbol(10, 20); - - SymbolData dataRepository = new SymbolData(symbolTableBuilder.build()); - String serializedSymbolData = dataRepository.writeString(); - - assertThat(serializedSymbolData).isEqualTo("10,20,10;"); - } -} diff --git a/sonar-batch/src/test/java/org/sonar/batch/symbol/DefaultSymbolTableBuilderTest.java b/sonar-batch/src/test/java/org/sonar/batch/symbol/DefaultSymbolTableBuilderTest.java new file mode 100644 index 00000000000..c661da30af1 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/symbol/DefaultSymbolTableBuilderTest.java @@ -0,0 +1,108 @@ +/* + * SonarQube, open source software quality management tool. + * Copyright (C) 2008-2014 SonarSource + * mailto:contact AT sonarsource DOT com + * + * SonarQube is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * SonarQube is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +package org.sonar.batch.symbol; + +import com.google.common.collect.SortedSetMultimap; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.ArgumentCaptor; +import org.sonar.api.batch.sensor.symbol.Symbol; +import org.sonar.api.batch.sensor.symbol.SymbolTableBuilder; +import org.sonar.batch.index.ComponentDataCache; +import org.sonar.core.source.SnapshotDataTypes; + +import java.util.ArrayList; + +import static org.fest.assertions.Assertions.assertThat; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; + +public class DefaultSymbolTableBuilderTest { + + @Rule + public ExpectedException throwable = ExpectedException.none(); + + @Test + public void should_order_symbol_and_references() throws Exception { + ComponentDataCache componentDataCache = mock(ComponentDataCache.class); + SymbolTableBuilder symbolTableBuilder = new DefaultSymbolTableBuilder("foo", componentDataCache); + Symbol firstSymbol = symbolTableBuilder.newSymbol(10, 20); + symbolTableBuilder.newReference(firstSymbol, 32); + Symbol secondSymbol = symbolTableBuilder.newSymbol(84, 92); + symbolTableBuilder.newReference(secondSymbol, 124); + Symbol thirdSymbol = symbolTableBuilder.newSymbol(55, 62); + symbolTableBuilder.newReference(thirdSymbol, 70); + symbolTableBuilder.done(); + + ArgumentCaptor<SymbolData> argCaptor = ArgumentCaptor.forClass(SymbolData.class); + verify(componentDataCache).setData(eq("foo"), eq(SnapshotDataTypes.SYMBOL_HIGHLIGHTING), argCaptor.capture()); + + SortedSetMultimap<Symbol, Integer> referencesBySymbol = argCaptor.getValue().referencesBySymbol(); + + assertThat(new ArrayList<Symbol>(referencesBySymbol.keySet())).containsExactly(firstSymbol, thirdSymbol, secondSymbol); + assertThat(new ArrayList<Integer>(referencesBySymbol.get(firstSymbol))).containsExactly(10, 32); + assertThat(new ArrayList<Integer>(referencesBySymbol.get(secondSymbol))).containsExactly(84, 124); + assertThat(new ArrayList<Integer>(referencesBySymbol.get(thirdSymbol))).containsExactly(55, 70); + + assertThat(argCaptor.getValue().writeString()).isEqualTo("10,20,10,32;55,62,55,70;84,92,84,124;"); + } + + @Test + public void should_serialize_unused_symbol() throws Exception { + + ComponentDataCache componentDataCache = mock(ComponentDataCache.class); + SymbolTableBuilder symbolTableBuilder = new DefaultSymbolTableBuilder("foo", componentDataCache); + symbolTableBuilder.newSymbol(10, 20); + symbolTableBuilder.done(); + + ArgumentCaptor<SymbolData> argCaptor = ArgumentCaptor.forClass(SymbolData.class); + verify(componentDataCache).setData(eq("foo"), eq(SnapshotDataTypes.SYMBOL_HIGHLIGHTING), argCaptor.capture()); + + assertThat(argCaptor.getValue().writeString()).isEqualTo("10,20,10;"); + } + + @Test + public void should_reject_reference_conflicting_with_declaration() throws Exception { + throwable.expect(UnsupportedOperationException.class); + + ComponentDataCache componentDataCache = mock(ComponentDataCache.class); + SymbolTableBuilder symbolTableBuilder = new DefaultSymbolTableBuilder("foo", componentDataCache); + Symbol symbol = symbolTableBuilder.newSymbol(10, 20); + symbolTableBuilder.newReference(symbol, 15); + } + + @Test + public void should_reject_reference_from_another_file() throws Exception { + throwable.expect(UnsupportedOperationException.class); + + ComponentDataCache componentDataCache = mock(ComponentDataCache.class); + SymbolTableBuilder symbolTableBuilder = new DefaultSymbolTableBuilder("foo", componentDataCache); + Symbol symbol = symbolTableBuilder.newSymbol(10, 20); + + SymbolTableBuilder symbolTableBuilder2 = new DefaultSymbolTableBuilder("foo2", componentDataCache); + Symbol symbol2 = symbolTableBuilder2.newSymbol(30, 40); + + symbolTableBuilder.newReference(symbol2, 15); + } + +} |