diff options
author | Julien HENRY <julien.henry@sonarsource.com> | 2015-02-20 14:57:39 +0100 |
---|---|---|
committer | Julien HENRY <julien.henry@sonarsource.com> | 2015-02-20 15:05:18 +0100 |
commit | ee09741a99176e635b310ab295dd898533828d69 (patch) | |
tree | ccb54de1e5373e54e9a9feffc2adde4d81ac1a05 /sonar-plugin-api/src | |
parent | 38357bb24905509dd775e40bdf09e40aec6af39c (diff) | |
download | sonarqube-ee09741a99176e635b310ab295dd898533828d69.tar.gz sonarqube-ee09741a99176e635b310ab295dd898533828d69.zip |
SONAR-5931 Add a tester class for SensorContext
Diffstat (limited to 'sonar-plugin-api/src')
2 files changed, 461 insertions, 0 deletions
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java new file mode 100644 index 00000000000..1a41ccefe44 --- /dev/null +++ b/sonar-plugin-api/src/main/java/org/sonar/api/batch/sensor/internal/SensorContextTester.java @@ -0,0 +1,303 @@ +/* + * 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.internal; + +import com.google.common.annotations.Beta; +import org.sonar.api.batch.AnalysisMode; +import org.sonar.api.batch.fs.InputDir; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.batch.fs.InputPath; +import org.sonar.api.batch.fs.internal.DefaultFileSystem; +import org.sonar.api.batch.fs.internal.DefaultInputDir; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.rule.ActiveRules; +import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; +import org.sonar.api.batch.sensor.Sensor; +import org.sonar.api.batch.sensor.SensorContext; +import org.sonar.api.batch.sensor.dependency.Dependency; +import org.sonar.api.batch.sensor.dependency.NewDependency; +import org.sonar.api.batch.sensor.dependency.internal.DefaultDependency; +import org.sonar.api.batch.sensor.duplication.Duplication; +import org.sonar.api.batch.sensor.duplication.NewDuplication; +import org.sonar.api.batch.sensor.duplication.internal.DefaultDuplication; +import org.sonar.api.batch.sensor.highlighting.NewHighlighting; +import org.sonar.api.batch.sensor.highlighting.TypeOfText; +import org.sonar.api.batch.sensor.highlighting.internal.DefaultHighlighting; +import org.sonar.api.batch.sensor.highlighting.internal.SyntaxHighlightingRule; +import org.sonar.api.batch.sensor.issue.Issue; +import org.sonar.api.batch.sensor.issue.NewIssue; +import org.sonar.api.batch.sensor.issue.internal.DefaultIssue; +import org.sonar.api.batch.sensor.measure.Measure; +import org.sonar.api.batch.sensor.measure.NewMeasure; +import org.sonar.api.batch.sensor.measure.internal.DefaultMeasure; +import org.sonar.api.config.Settings; +import org.sonar.api.measures.Metric; + +import javax.annotation.CheckForNull; +import javax.annotation.Nullable; + +import java.io.File; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Utility class to help testing {@link Sensor} + * @since 5.1 + */ +@Beta +public class SensorContextTester implements SensorContext { + + private Settings settings; + private DefaultFileSystem fs; + private ActiveRules activeRules; + private MockAnalysisMode analysisMode; + private InMemorySensorStorage sensorStorage; + + private SensorContextTester(File moduleBaseDir) { + this.settings = new Settings(); + this.fs = new DefaultFileSystem(moduleBaseDir); + this.activeRules = new ActiveRulesBuilder().build(); + this.analysisMode = new MockAnalysisMode(); + this.sensorStorage = new InMemorySensorStorage(); + } + + public static SensorContextTester create(File moduleBaseDir) { + return new SensorContextTester(moduleBaseDir); + } + + @Override + public Settings settings() { + return settings; + } + + public void setSettings(Settings settings) { + this.settings = settings; + } + + @Override + public DefaultFileSystem fileSystem() { + return fs; + } + + public void setFileSystem(DefaultFileSystem fs) { + this.fs = fs; + } + + @Override + public ActiveRules activeRules() { + return activeRules; + } + + public void setActiveRules(ActiveRules activeRules) { + this.activeRules = activeRules; + } + + @Override + public MockAnalysisMode analysisMode() { + return analysisMode; + } + + @Override + public <G extends Serializable> NewMeasure<G> newMeasure() { + return new DefaultMeasure<>(sensorStorage); + } + + public Collection<Measure> measures(@Nullable String componetKey) { + if (componetKey == null) { + return sensorStorage.projectMeasuresByMetric.values(); + } + Map<String, Measure> measures = sensorStorage.measuresByComponentAndMetric.get(componetKey); + return measures != null ? measures.values() : Collections.<Measure>emptyList(); + } + + public <G extends Serializable> Measure<G> measure(String componetKey, Metric<G> metric) { + return measure(componetKey, metric.key()); + } + + public Measure measure(String componetKey, String metricKey) { + if (componetKey == null) { + return sensorStorage.projectMeasuresByMetric.get(metricKey); + } + Map<String, Measure> measures = sensorStorage.measuresByComponentAndMetric.get(componetKey); + return measures != null ? measures.get(metricKey) : null; + } + + @Override + public NewIssue newIssue() { + return new DefaultIssue(sensorStorage); + } + + public Collection<Issue> allIssues() { + List<Issue> result = new ArrayList<>(); + result.addAll(sensorStorage.projectIssues); + for (String key : sensorStorage.issuesByComponent.keySet()) { + result.addAll(sensorStorage.issuesByComponent.get(key)); + } + return result; + } + + /** + * @param componentKey null for project issues + */ + public Collection<Issue> issues(@Nullable String componentKey) { + if (componentKey != null) { + List<Issue> list = sensorStorage.issuesByComponent.get(componentKey); + return list != null ? list : Collections.<Issue>emptyList(); + } else { + return sensorStorage.projectIssues; + } + } + + @Override + public NewHighlighting newHighlighting() { + return new DefaultHighlighting(sensorStorage); + } + + public List<TypeOfText> highlightingTypeFor(String componentKey, int charIndex) { + DefaultHighlighting syntaxHighlightingData = sensorStorage.highlightingByComponent.get(componentKey); + if (syntaxHighlightingData == null) { + return Collections.emptyList(); + } + List<TypeOfText> result = new ArrayList<TypeOfText>(); + for (SyntaxHighlightingRule sortedRule : syntaxHighlightingData.getSyntaxHighlightingRuleSet()) { + if (sortedRule.getStartPosition() <= charIndex && sortedRule.getEndPosition() > charIndex) { + result.add(sortedRule.getTextType()); + } + } + return result; + } + + @Override + public NewDuplication newDuplication() { + return new DefaultDuplication(sensorStorage); + } + + public Collection<Duplication> duplications() { + return sensorStorage.duplications; + } + + @Override + public NewDependency newDependency() { + return new DefaultDependency(sensorStorage); + } + + public Collection<Dependency> dependencies() { + return sensorStorage.dependencies; + } + + public static class MockAnalysisMode implements AnalysisMode { + private boolean isIncremental = false; + private boolean isPreview = false; + + @Override + public boolean isIncremental() { + return isIncremental; + } + + public void setIncremental(boolean value) { + this.isIncremental = value; + } + + @Override + public boolean isPreview() { + return isPreview; + } + + public void setPreview(boolean value) { + this.isPreview = value; + } + } + + private static class InMemorySensorStorage implements SensorStorage { + + private Map<String, Measure> projectMeasuresByMetric = new HashMap<>(); + private Map<String, Map<String, Measure>> measuresByComponentAndMetric = new HashMap<>(); + + private Collection<Issue> projectIssues = new ArrayList<>(); + private Map<String, List<Issue>> issuesByComponent = new HashMap<>(); + + private Map<String, DefaultHighlighting> highlightingByComponent = new HashMap<>(); + + private List<Duplication> duplications = new ArrayList<>(); + private List<Dependency> dependencies = new ArrayList<>(); + + @Override + public void store(Measure measure) { + String key = getKey(measure.inputFile()); + if (key == null) { + projectMeasuresByMetric.put(measure.metric().key(), measure); + } else { + if (!measuresByComponentAndMetric.containsKey(key)) { + measuresByComponentAndMetric.put(key, new HashMap<String, Measure>()); + } + measuresByComponentAndMetric.get(key).put(measure.metric().key(), measure); + } + } + + @Override + public void store(Issue issue) { + String key = getKey(issue.inputPath()); + if (key == null) { + projectIssues.add(issue); + } else { + if (!issuesByComponent.containsKey(key)) { + issuesByComponent.put(key, new ArrayList<Issue>()); + } + issuesByComponent.get(key).add(issue); + } + } + + @Override + public void store(Duplication duplication) { + duplications.add(duplication); + } + + @Override + public void store(Dependency dependency) { + dependencies.add(dependency); + } + + @Override + public void store(DefaultHighlighting highlighting) { + highlightingByComponent.put(getKey(highlighting.inputFile()), highlighting); + } + + @CheckForNull + private String getKey(@Nullable InputPath inputPath) { + if (inputPath == null) { + return null; + } + if (inputPath instanceof InputFile) { + return ((DefaultInputFile) inputPath).key(); + } + if (inputPath instanceof InputDir) { + return ((DefaultInputDir) inputPath).key(); + } + throw new IllegalStateException("Unknow component " + inputPath); + } + + } + +} diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java new file mode 100644 index 00000000000..090e487ddfe --- /dev/null +++ b/sonar-plugin-api/src/test/java/org/sonar/api/batch/sensor/internal/SensorContextTesterTest.java @@ -0,0 +1,158 @@ +package org.sonar.api.batch.sensor.internal; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.batch.fs.internal.DefaultFileSystem; +import org.sonar.api.batch.fs.internal.DefaultInputDir; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.batch.rule.ActiveRules; +import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; +import org.sonar.api.batch.sensor.highlighting.TypeOfText; +import org.sonar.api.config.Settings; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.rule.RuleKey; + +import java.io.File; + +import static org.assertj.core.api.Assertions.assertThat; + +public class SensorContextTesterTest { + + @Rule + public TemporaryFolder temp = new TemporaryFolder(); + private SensorContextTester tester; + private File baseDir; + + @Before + public void prepare() throws Exception { + baseDir = temp.newFolder(); + tester = SensorContextTester.create(baseDir); + } + + @Test + public void testSettings() { + Settings settings = new Settings(); + settings.setProperty("foo", "bar"); + tester.setSettings(settings); + assertThat(tester.settings().getString("foo")).isEqualTo("bar"); + } + + @Test + public void testActiveRules() { + ActiveRules activeRules = new ActiveRulesBuilder().create(RuleKey.of("repo", "rule")).activate().build(); + tester.setActiveRules(activeRules); + assertThat(tester.activeRules().findAll()).hasSize(1); + } + + @Test + public void testFs() throws Exception { + DefaultFileSystem fs = new DefaultFileSystem(temp.newFolder()); + tester.setFileSystem(fs); + assertThat(tester.fileSystem().baseDir()).isNotEqualTo(baseDir); + } + + @Test + public void testAnalysisMode() { + assertThat(tester.analysisMode().isIncremental()).isFalse(); + assertThat(tester.analysisMode().isPreview()).isFalse(); + tester.analysisMode().setIncremental(true); + assertThat(tester.analysisMode().isIncremental()).isTrue(); + tester.analysisMode().setPreview(true); + assertThat(tester.analysisMode().isPreview()).isTrue(); + } + + @Test + public void testIssues() { + assertThat(tester.issues("foo:src/Foo.java")).isEmpty(); + assertThat(tester.allIssues()).isEmpty(); + tester.newIssue() + .onFile(new DefaultInputFile("foo", "src/Foo.java")) + .forRule(RuleKey.of("repo", "rule")) + .atLine(1) + .save(); + tester.newIssue() + .onFile(new DefaultInputFile("foo", "src/Foo.java")) + .forRule(RuleKey.of("repo", "rule")) + .atLine(3) + .save(); + assertThat(tester.issues("foo:src/Foo.java")).hasSize(2); + assertThat(tester.allIssues()).hasSize(2); + tester.newIssue() + .onDir(new DefaultInputDir("foo", "src")) + .forRule(RuleKey.of("repo", "rule")) + .save(); + assertThat(tester.issues("foo:src")).hasSize(1); + assertThat(tester.allIssues()).hasSize(3); + tester.newIssue() + .onProject() + .forRule(RuleKey.of("repo", "rule")) + .save(); + assertThat(tester.issues(null)).hasSize(1); + assertThat(tester.allIssues()).hasSize(4); + } + + @Test + public void testMeasures() { + assertThat(tester.measures("foo:src/Foo.java")).isEmpty(); + assertThat(tester.measure("foo:src/Foo.java", "ncloc")).isNull(); + tester.<Integer>newMeasure() + .onFile(new DefaultInputFile("foo", "src/Foo.java")) + .forMetric(CoreMetrics.NCLOC) + .withValue(2) + .save(); + assertThat(tester.measures("foo:src/Foo.java")).hasSize(1); + assertThat(tester.measure("foo:src/Foo.java", "ncloc")).isNotNull(); + tester.<Integer>newMeasure() + .onFile(new DefaultInputFile("foo", "src/Foo.java")) + .forMetric(CoreMetrics.LINES) + .withValue(4) + .save(); + assertThat(tester.measures("foo:src/Foo.java")).hasSize(2); + assertThat(tester.measure("foo:src/Foo.java", "ncloc")).isNotNull(); + assertThat(tester.measure("foo:src/Foo.java", "lines")).isNotNull(); + tester.<Integer>newMeasure() + .onProject() + .forMetric(CoreMetrics.DIRECTORIES) + .withValue(4) + .save(); + assertThat(tester.measures(null)).hasSize(1); + assertThat(tester.measure(null, "directories")).isNotNull(); + } + + @Test + public void testHighlighting() { + assertThat(tester.highlightingTypeFor("foo:src/Foo.java", 3)).isEmpty(); + tester.newHighlighting() + .onFile(new DefaultInputFile("foo", "src/Foo.java")) + .highlight(0, 4, TypeOfText.ANNOTATION) + .highlight(8, 10, TypeOfText.CONSTANT) + .highlight(9, 10, TypeOfText.COMMENT) + .save(); + assertThat(tester.highlightingTypeFor("foo:src/Foo.java", 3)).containsExactly(TypeOfText.ANNOTATION); + assertThat(tester.highlightingTypeFor("foo:src/Foo.java", 9)).containsExactly(TypeOfText.CONSTANT, TypeOfText.COMMENT); + } + + @Test + public void testDuplication() { + assertThat(tester.duplications()).isEmpty(); + tester.newDuplication() + .originBlock(new DefaultInputFile("foo", "src/Foo.java").setLines(40), 1, 30) + .isDuplicatedBy(new DefaultInputFile("foo", "src/Foo2.java").setLines(40), 3, 33) + .isDuplicatedBy(new DefaultInputFile("foo", "src/Foo3.java").setLines(40), 4, 34) + .save(); + assertThat(tester.duplications()).hasSize(1); + } + + @Test + public void testDependencies() { + assertThat(tester.dependencies()).isEmpty(); + tester.newDependency() + .from(new DefaultInputFile("foo", "src/Foo.java")) + .to(new DefaultInputFile("foo", "src/Foo2.java")) + .weight(3) + .save(); + assertThat(tester.dependencies()).hasSize(1); + } +} |