@@ -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()); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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); | |||
} | |||
} |
@@ -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; | |||
@@ -0,0 +1,23 @@ | |||
/* | |||
* 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. | |||
*/ | |||
@ParametersAreNonnullByDefault | |||
package org.sonar.batch.highlighting; | |||
import javax.annotation.ParametersAreNonnullByDefault; |
@@ -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(); |
@@ -25,6 +25,4 @@ public interface Data extends Serializable { | |||
String writeString(); | |||
void readString(String s); | |||
} |
@@ -37,9 +37,4 @@ public class StringData implements Data { | |||
public String writeString() { | |||
return data; | |||
} | |||
@Override | |||
public void readString(String s) { | |||
this.data = s; | |||
} | |||
} |
@@ -20,12 +20,16 @@ | |||
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.config.Settings; | |||
@@ -36,6 +40,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; | |||
@@ -49,6 +56,9 @@ import org.sonar.batch.scan2.ScanTaskObserver; | |||
import org.sonar.batch.settings.SettingsReferential; | |||
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; | |||
@@ -200,13 +210,18 @@ 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>(); | |||
@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 +238,15 @@ 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); | |||
} | |||
} | |||
} | |||
public List<Issue> issues() { | |||
@@ -240,6 +264,20 @@ 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 highlightingTypeAt(InputFile file, int charIndex) { | |||
for (SyntaxHighlightingRule sortedRule : highlightingPerFile.get(file).syntaxHighlightingRuleSet()) { | |||
if (sortedRule.getStartPosition() <= charIndex && sortedRule.getEndPosition() > charIndex) { | |||
return HighlightingBuilder.TypeOfText.forCssClass(sortedRule.getTextType()); | |||
} | |||
} | |||
return null; | |||
} | |||
} | |||
private static class FakeGlobalReferentialsLoader implements GlobalReferentialsLoader { |
@@ -23,9 +23,11 @@ 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; | |||
@@ -46,6 +48,8 @@ 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 java.io.Serializable; | |||
@@ -62,9 +66,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 +77,7 @@ public class SensorContextAdaptor implements SensorContext { | |||
this.settings = settings; | |||
this.fs = fs; | |||
this.activeRules = activeRules; | |||
this.componentDataCache = componentDataCache; | |||
} | |||
@Override | |||
@@ -236,4 +242,9 @@ public class SensorContextAdaptor implements SensorContext { | |||
.build(); | |||
} | |||
@Override | |||
public HighlightingBuilder highlightingBuilder(InputFile inputFile) { | |||
return new DefaultHighlightingBuilder(((DefaultInputFile) inputFile).key(), componentDataCache); | |||
} | |||
} |
@@ -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; | |||
@@ -38,6 +40,8 @@ import org.sonar.api.batch.sensor.measure.internal.DefaultMeasureBuilder; | |||
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.core.component.ComponentKeys; | |||
@@ -53,9 +57,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 +68,7 @@ public class DefaultSensorContext implements SensorContext { | |||
this.fs = fs; | |||
this.activeRules = activeRules; | |||
this.issueFilters = issueFilters; | |||
this.componentDataCache = componentDataCache; | |||
} | |||
@Override | |||
@@ -155,7 +161,11 @@ 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); | |||
} | |||
} |
@@ -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); | |||
} | |||
@@ -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 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()); | |||
} | |||
} | |||
} |
@@ -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 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); |
@@ -42,9 +42,9 @@ public class SymbolData implements Data { | |||
public String writeString() { | |||
StringBuilder sb = new StringBuilder(); | |||
Multimap<Symbol, Integer> referencesBySymbol = ((DefaultSymbolTable)symbolTable).getReferencesBySymbol(); | |||
Multimap<Symbol, Integer> referencesBySymbol = ((DefaultSymbolTable) symbolTable).getReferencesBySymbol(); | |||
for (Symbol symbol : ((DefaultSymbolTable)symbolTable).getReferencesBySymbol().keySet()) { | |||
for (Symbol symbol : ((DefaultSymbolTable) symbolTable).getReferencesBySymbol().keySet()) { | |||
sb.append(symbol.getDeclarationStartOffset()) | |||
.append(FIELD_SEPARATOR) | |||
@@ -59,8 +59,4 @@ public class SymbolData implements Data { | |||
return sb.toString(); | |||
} | |||
@Override | |||
public void readString(String s) { | |||
throw new UnsupportedOperationException(); | |||
} | |||
} |
@@ -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;"); | |||
} | |||
} |
@@ -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; |
@@ -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;"); |
@@ -83,9 +83,5 @@ public class ComponentDataCacheTest { | |||
return String.valueOf(data); | |||
} | |||
@Override | |||
public void readString(String s) { | |||
data = Long.parseLong(s); | |||
} | |||
} | |||
} |
@@ -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.highlightingTypeAt(file, 0)).isEqualTo(HighlightingBuilder.TypeOfText.STRING); | |||
assertThat(result.highlightingTypeAt(file, 9)).isEqualTo(HighlightingBuilder.TypeOfText.STRING); | |||
assertThat(result.highlightingTypeAt(file, 10)).isNull(); | |||
assertThat(result.highlightingTypeAt(file, 11)).isEqualTo(HighlightingBuilder.TypeOfText.KEYWORD); | |||
} | |||
} |
@@ -23,6 +23,7 @@ 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.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 +39,7 @@ public final class XooPlugin extends SonarPlugin { | |||
// language | |||
MeasureSensor.class, | |||
ScmActivitySensor.class, | |||
SyntaxHighlightingSensor.class, | |||
Xoo.class, | |||
// sensors |
@@ -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); |
@@ -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); | |||
} | |||
} | |||
} |
@@ -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 |
@@ -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;"); | |||
} | |||
} |
@@ -24,6 +24,7 @@ import org.sonar.api.batch.fs.FileSystem; | |||
import org.sonar.api.batch.fs.InputFile; | |||
import org.sonar.api.batch.measure.Metric; | |||
import org.sonar.api.batch.rule.ActiveRules; | |||
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.measure.Measure; | |||
@@ -108,4 +109,12 @@ public interface SensorContext { | |||
*/ | |||
boolean addIssue(Issue issue); | |||
// ------------ HIGHLIGHTING ------------ | |||
/** | |||
* Builder to define highlighting of a file. | |||
* @since 4.5 | |||
*/ | |||
HighlightingBuilder highlightingBuilder(InputFile inputFile); | |||
} |
@@ -0,0 +1,78 @@ | |||
/* | |||
* 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.api.batch.sensor.highlighting; | |||
/** | |||
* This builder is used to define syntax highlighting (aka code coloration) on files. | |||
* @since 4.5 | |||
*/ | |||
public interface HighlightingBuilder { | |||
/** | |||
* See sonar-colorizer.css | |||
*/ | |||
enum TypeOfText { | |||
ANNOTATION("a"), | |||
CONSTANT("c"), | |||
JAVADOC("j"), | |||
CLASSIC_COMMENT("cd"), | |||
CPP_DOC("cppd"), | |||
KEYWORD("k"), | |||
STRING("s"), | |||
KEYWORD_LIGHT("h"), | |||
PREPROCESS_DIRECTIVE("p"); | |||
private final String cssClass; | |||
private TypeOfText(String cssClass) { | |||
this.cssClass = cssClass; | |||
} | |||
public static TypeOfText forCssClass(String cssClass) { | |||
for (TypeOfText typeOfText : TypeOfText.values()) { | |||
if (typeOfText.cssClass().equals(cssClass)) { | |||
return typeOfText; | |||
} | |||
} | |||
throw new IllegalArgumentException("No TypeOfText for CSS class " + cssClass); | |||
} | |||
/** | |||
* For internal use | |||
*/ | |||
public String cssClass() { | |||
return cssClass; | |||
} | |||
} | |||
/** | |||
* Call this method to indicate the type of text in a range. | |||
* @param startOffset Starting position in file for this type of text. Beginning of a file starts with offset '0'. | |||
* @param endOffset End position in file for this type of text. | |||
* @param typeOfText see {@link TypeOfText} values. | |||
*/ | |||
HighlightingBuilder highlight(int startOffset, int endOffset, TypeOfText typeOfText); | |||
/** | |||
* Call this method only once when your are done with defining highlighting of the file. | |||
*/ | |||
void done(); | |||
} |
@@ -0,0 +1,21 @@ | |||
/* | |||
* 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. | |||
*/ | |||
@javax.annotation.ParametersAreNonnullByDefault | |||
package org.sonar.api.batch.sensor.highlighting; |
@@ -19,11 +19,14 @@ | |||
*/ | |||
package org.sonar.api.source; | |||
import org.sonar.api.batch.sensor.SensorContext; | |||
import org.sonar.api.component.Perspective; | |||
/** | |||
* @since 3.6 | |||
* @deprecated since 4.5 use {@link SensorContext#highlightingBuilder(org.sonar.api.batch.fs.InputFile)} | |||
*/ | |||
@Deprecated | |||
public interface Highlightable extends Perspective { | |||
interface HighlightingBuilder { |