diff options
author | Julien HENRY <julien.henry@sonarsource.com> | 2014-06-19 17:10:01 +0200 |
---|---|---|
committer | Julien HENRY <julien.henry@sonarsource.com> | 2014-06-19 17:12:09 +0200 |
commit | 3bd4ce6a6c0010e272b55656ae62cc2f0f20b9f7 (patch) | |
tree | 7385c15b6edf1f3c768ca22368b116fe6af6517a /sonar-batch | |
parent | ba05cbc35820e64d70642615525377c9aa1b3069 (diff) | |
download | sonarqube-3bd4ce6a6c0010e272b55656ae62cc2f0f20b9f7.tar.gz sonarqube-3bd4ce6a6c0010e272b55656ae62cc2f0f20b9f7.zip |
SONAR-5389 Add medium tests
Diffstat (limited to 'sonar-batch')
22 files changed, 1009 insertions, 90 deletions
diff --git a/sonar-batch/src/main/java/org/sonar/batch/rule/ActiveRulesProvider.java b/sonar-batch/src/main/java/org/sonar/batch/rule/ActiveRulesProvider.java index 49f762ef811..ca90e38d01c 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/rule/ActiveRulesProvider.java +++ b/sonar-batch/src/main/java/org/sonar/batch/rule/ActiveRulesProvider.java @@ -19,14 +19,13 @@ */ package org.sonar.batch.rule; -import org.sonar.api.batch.rules.QProfile; - import com.google.common.collect.ArrayListMultimap; import com.google.common.collect.ListMultimap; import org.picocontainer.injectors.ProviderAdapter; import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; import org.sonar.api.batch.rule.internal.NewActiveRule; +import org.sonar.api.batch.rules.QProfile; import org.sonar.api.rules.Rule; import org.sonar.api.rules.RuleFinder; import org.sonar.api.rules.RuleParam; @@ -62,7 +61,7 @@ public class ActiveRulesProvider extends ProviderAdapter { for (ActiveRuleDto activeDto : dao.selectByProfileId(qProfileWithId.id())) { Rule rule = ruleFinder.findById(activeDto.getRulId()); if (rule != null) { - NewActiveRule newActiveRule = builder.activate(rule.ruleKey()); + NewActiveRule newActiveRule = builder.create(rule.ruleKey()); newActiveRule.setSeverity(activeDto.getSeverityString()); newActiveRule.setLanguage(rule.getLanguage()); Rule template = rule.getTemplate(); @@ -83,6 +82,7 @@ public class ActiveRulesProvider extends ProviderAdapter { newActiveRule.setParam(param.getKey(), param.getDefaultValue()); } } + newActiveRule.activate(); } } } diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerIssueCache.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerIssueCache.java new file mode 100644 index 00000000000..613507de041 --- /dev/null +++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerIssueCache.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.scan2; + +import org.sonar.api.BatchComponent; +import org.sonar.api.batch.analyzer.issue.internal.DefaultAnalyzerIssue; +import org.sonar.batch.index.Cache; +import org.sonar.batch.index.Caches; + +/** + * Shared issues among all project modules + */ +public class AnalyzerIssueCache implements BatchComponent { + + // component key -> issue key -> issue + private final Cache<DefaultAnalyzerIssue> cache; + + public AnalyzerIssueCache(Caches caches) { + cache = caches.createCache("issues"); + } + + public Iterable<DefaultAnalyzerIssue> byComponent(String resourceKey) { + return cache.values(resourceKey); + } + + public Iterable<DefaultAnalyzerIssue> all() { + return cache.values(); + } + + public AnalyzerIssueCache put(String resourceKey, DefaultAnalyzerIssue issue) { + cache.put(resourceKey, issue.key(), issue); + return this; + } + +} diff --git a/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultAnalyzerContext.java b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultAnalyzerContext.java index 1ec141ada84..d9f03c17e50 100644 --- a/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultAnalyzerContext.java +++ b/sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultAnalyzerContext.java @@ -19,11 +19,10 @@ */ package org.sonar.batch.scan2; -import org.sonar.api.batch.measure.Metric; - import org.sonar.api.batch.analyzer.AnalyzerContext; import org.sonar.api.batch.analyzer.issue.AnalyzerIssue; import org.sonar.api.batch.analyzer.issue.AnalyzerIssueBuilder; +import org.sonar.api.batch.analyzer.issue.internal.DefaultAnalyzerIssue; import org.sonar.api.batch.analyzer.issue.internal.DefaultAnalyzerIssueBuilder; import org.sonar.api.batch.analyzer.measure.AnalyzerMeasure; import org.sonar.api.batch.analyzer.measure.AnalyzerMeasureBuilder; @@ -32,30 +31,27 @@ import org.sonar.api.batch.analyzer.measure.internal.DefaultAnalyzerMeasureBuild 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.measure.Metric; import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.config.Settings; -import org.sonar.api.issue.internal.DefaultIssue; -import org.sonar.api.rule.RuleKey; -import org.sonar.batch.issue.ModuleIssues; import org.sonar.core.component.ComponentKeys; -import org.sonar.core.issue.DefaultIssueBuilder; import java.io.Serializable; public class DefaultAnalyzerContext implements AnalyzerContext { private final AnalyzerMeasureCache measureCache; + private final AnalyzerIssueCache issueCache; private ProjectDefinition def; - private ModuleIssues moduleIssues; private Settings settings; private FileSystem fs; private ActiveRules activeRules; - public DefaultAnalyzerContext(ProjectDefinition def, AnalyzerMeasureCache measureCache, - ModuleIssues moduleIssues, Settings settings, FileSystem fs, ActiveRules activeRules) { + public DefaultAnalyzerContext(ProjectDefinition def, AnalyzerMeasureCache measureCache, AnalyzerIssueCache issueCache, + Settings settings, FileSystem fs, ActiveRules activeRules) { this.def = def; this.measureCache = measureCache; - this.moduleIssues = moduleIssues; + this.issueCache = issueCache; this.settings = settings; this.fs = fs; this.activeRules = activeRules; @@ -117,20 +113,14 @@ public class DefaultAnalyzerContext implements AnalyzerContext { @Override public void addIssue(AnalyzerIssue issue) { - DefaultIssueBuilder builder = new DefaultIssueBuilder() - .projectKey(def.getKey()); + String resourceKey; if (issue.inputFile() != null) { - builder.componentKey(ComponentKeys.createEffectiveKey(def.getKey(), issue.inputFile())); + resourceKey = ComponentKeys.createEffectiveKey(def.getKey(), issue.inputFile()); } else { - builder.componentKey(def.getKey()); + resourceKey = def.getKey(); } - moduleIssues.initAndAddIssue((DefaultIssue) builder - .ruleKey(RuleKey.of(issue.ruleKey().repository(), issue.ruleKey().rule())) - .message(issue.message()) - .line(issue.line()) - .effortToFix(issue.effortToFix()) - .build()); + issueCache.put(resourceKey, (DefaultAnalyzerIssue) issue); } } 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 f5dd041678e..8dad42fd7e6 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 @@ -29,38 +29,15 @@ import org.sonar.api.batch.bootstrap.ProjectReactor; import org.sonar.api.config.Settings; import org.sonar.api.platform.ComponentContainer; import org.sonar.api.scan.filesystem.PathResolver; -import org.sonar.api.utils.SonarException; import org.sonar.batch.bootstrap.ExtensionInstaller; import org.sonar.batch.bootstrap.ExtensionMatcher; import org.sonar.batch.bootstrap.ExtensionUtils; -import org.sonar.batch.debt.IssueChangelogDebtCalculator; import org.sonar.batch.index.Caches; -import org.sonar.batch.index.ComponentDataCache; -import org.sonar.batch.index.ComponentDataPersister; -import org.sonar.batch.index.ResourceCache; -import org.sonar.batch.index.SnapshotCache; -import org.sonar.batch.issue.DefaultProjectIssues; -import org.sonar.batch.issue.DeprecatedViolations; -import org.sonar.batch.issue.IssueCache; -import org.sonar.batch.issue.IssuePersister; -import org.sonar.batch.issue.ScanIssueStorage; -import org.sonar.batch.phases.GraphPersister; import org.sonar.batch.profiling.PhasesSumUpTimeProfiler; import org.sonar.batch.scan.ProjectReactorBuilder; import org.sonar.batch.scan.filesystem.InputFileCache; import org.sonar.batch.scan.maven.FakeMavenPluginExecutor; import org.sonar.batch.scan.maven.MavenPluginExecutor; -import org.sonar.batch.source.HighlightableBuilder; -import org.sonar.batch.source.SymbolizableBuilder; -import org.sonar.core.component.ScanGraph; -import org.sonar.core.issue.IssueNotifications; -import org.sonar.core.issue.IssueUpdater; -import org.sonar.core.issue.workflow.FunctionExecutor; -import org.sonar.core.issue.workflow.IssueWorkflow; -import org.sonar.core.test.TestPlanBuilder; -import org.sonar.core.test.TestPlanPerspectiveLoader; -import org.sonar.core.test.TestableBuilder; -import org.sonar.core.test.TestablePerspectiveLoader; public class ProjectScanContainer extends ComponentContainer { public ProjectScanContainer(ComponentContainer taskContainer) { @@ -93,7 +70,7 @@ public class ProjectScanContainer extends ComponentContainer { reactor = bootstrapper.bootstrap(); } if (reactor == null) { - throw new SonarException(bootstrapper + " has returned null as ProjectReactor"); + throw new IllegalStateException(bootstrapper + " has returned null as ProjectReactor"); } add(reactor); } @@ -101,10 +78,8 @@ public class ProjectScanContainer extends ComponentContainer { private void addBatchComponents() { add( Caches.class, - SnapshotCache.class, - ResourceCache.class, - ComponentDataCache.class, - ComponentDataPersister.class, + + // Measures AnalyzerMeasureCache.class, // file system @@ -112,28 +87,7 @@ public class ProjectScanContainer extends ComponentContainer { PathResolver.class, // issues - IssueUpdater.class, - FunctionExecutor.class, - IssueWorkflow.class, - DeprecatedViolations.class, - IssueCache.class, - ScanIssueStorage.class, - IssuePersister.class, - IssueNotifications.class, - DefaultProjectIssues.class, - IssueChangelogDebtCalculator.class, - - // tests - TestPlanPerspectiveLoader.class, - TestablePerspectiveLoader.class, - TestPlanBuilder.class, - TestableBuilder.class, - ScanGraph.create(), - GraphPersister.class, - - // lang - HighlightableBuilder.class, - SymbolizableBuilder.class, + AnalyzerIssueCache.class, ScanTaskObservers.class); } diff --git a/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java b/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java index bacfe55be16..ef507f38001 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java @@ -47,7 +47,9 @@ import static org.fest.assertions.Assertions.assertThat; import static org.fest.assertions.Fail.fail; import static org.mockito.Matchers.any; import static org.mockito.Matchers.eq; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class ModuleIssuesTest { @@ -122,7 +124,7 @@ public class ModuleIssuesTest { @Test public void ignore_null_rule_of_active_rule() throws Exception { ruleBuilder.add(SQUID_RULE_KEY).setName(SQUID_RULE_NAME); - activeRulesBuilder.activate(SQUID_RULE_KEY); + activeRulesBuilder.create(SQUID_RULE_KEY).activate(); initModuleIssues(); DefaultIssue issue = new DefaultIssue().setRuleKey(SQUID_RULE_KEY); @@ -135,7 +137,7 @@ public class ModuleIssuesTest { @Test public void add_issue_to_cache() throws Exception { ruleBuilder.add(SQUID_RULE_KEY).setName(SQUID_RULE_NAME); - activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO); + activeRulesBuilder.create(SQUID_RULE_KEY).setSeverity(Severity.INFO).activate(); initModuleIssues(); Date analysisDate = new Date(); @@ -159,7 +161,7 @@ public class ModuleIssuesTest { @Test public void use_severity_from_active_rule_if_no_severity_on_issue() throws Exception { ruleBuilder.add(SQUID_RULE_KEY).setName(SQUID_RULE_NAME); - activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO); + activeRulesBuilder.create(SQUID_RULE_KEY).setSeverity(Severity.INFO).activate(); initModuleIssues(); Date analysisDate = new Date(); @@ -178,7 +180,7 @@ public class ModuleIssuesTest { @Test public void use_rule_name_if_no_message() throws Exception { ruleBuilder.add(SQUID_RULE_KEY).setName(SQUID_RULE_NAME); - activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO); + activeRulesBuilder.create(SQUID_RULE_KEY).setSeverity(Severity.INFO).activate(); initModuleIssues(); Date analysisDate = new Date(); @@ -202,7 +204,7 @@ public class ModuleIssuesTest { @Test public void add_deprecated_violation() throws Exception { ruleBuilder.add(SQUID_RULE_KEY).setName(SQUID_RULE_NAME); - activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO); + activeRulesBuilder.create(SQUID_RULE_KEY).setSeverity(Severity.INFO).activate(); initModuleIssues(); org.sonar.api.rules.Rule rule = org.sonar.api.rules.Rule.create("squid", "AvoidCycle", "Avoid Cycle"); @@ -232,7 +234,7 @@ public class ModuleIssuesTest { @Test public void filter_issue() throws Exception { ruleBuilder.add(SQUID_RULE_KEY).setName(SQUID_RULE_NAME); - activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO); + activeRulesBuilder.create(SQUID_RULE_KEY).setSeverity(Severity.INFO).activate(); initModuleIssues(); DefaultIssue issue = new DefaultIssue() @@ -254,7 +256,7 @@ public class ModuleIssuesTest { .setName(SQUID_RULE_NAME) .setDebtSubCharacteristic("COMPILER_RELATED_PORTABILITY") .setDebtRemediationFunction(DebtRemediationFunction.createLinear(Duration.create(10L))); - activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO); + activeRulesBuilder.create(SQUID_RULE_KEY).setSeverity(Severity.INFO).activate(); initModuleIssues(); Date analysisDate = new Date(); @@ -280,7 +282,7 @@ public class ModuleIssuesTest { .setName(SQUID_RULE_NAME) .setDebtSubCharacteristic("COMPILER_RELATED_PORTABILITY") .setDebtRemediationFunction(DebtRemediationFunction.createLinearWithOffset(Duration.create(10L), Duration.create(25L))); - activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO); + activeRulesBuilder.create(SQUID_RULE_KEY).setSeverity(Severity.INFO).activate(); initModuleIssues(); Date analysisDate = new Date(); @@ -306,7 +308,7 @@ public class ModuleIssuesTest { .setName(SQUID_RULE_NAME) .setDebtSubCharacteristic("COMPILER_RELATED_PORTABILITY") .setDebtRemediationFunction(DebtRemediationFunction.createConstantPerIssue(Duration.create(10L))); - activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO); + activeRulesBuilder.create(SQUID_RULE_KEY).setSeverity(Severity.INFO).activate(); initModuleIssues(); Date analysisDate = new Date(); @@ -332,7 +334,7 @@ public class ModuleIssuesTest { .setName(SQUID_RULE_NAME) .setDebtSubCharacteristic("COMPILER_RELATED_PORTABILITY") .setDebtRemediationFunction(DebtRemediationFunction.createConstantPerIssue(Duration.create(25L))); - activeRulesBuilder.activate(SQUID_RULE_KEY).setSeverity(Severity.INFO); + activeRulesBuilder.create(SQUID_RULE_KEY).setSeverity(Severity.INFO).activate(); initModuleIssues(); DefaultIssue issue = new DefaultIssue() diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/AnalyzerMediumTester.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/AnalyzerMediumTester.java new file mode 100644 index 00000000000..c8dc898b823 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/AnalyzerMediumTester.java @@ -0,0 +1,417 @@ +/* + * 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; + +import com.google.common.collect.BiMap; +import com.google.common.collect.HashBiMap; +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import org.apache.commons.io.IOUtils; +import org.junit.rules.ExternalResource; +import org.sonar.api.SonarPlugin; +import org.sonar.api.batch.analyzer.issue.AnalyzerIssue; +import org.sonar.api.batch.analyzer.measure.AnalyzerMeasure; +import org.sonar.api.batch.debt.internal.DefaultDebtModel; +import org.sonar.api.batch.rule.internal.ActiveRulesBuilder; +import org.sonar.api.batch.rule.internal.RulesBuilder; +import org.sonar.api.batch.rules.QProfile; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Metric; +import org.sonar.api.measures.MetricFinder; +import org.sonar.api.platform.PluginMetadata; +import org.sonar.api.rule.RuleKey; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RuleFinder; +import org.sonar.api.rules.RuleQuery; +import org.sonar.batch.bootstrap.PluginsReferential; +import org.sonar.batch.bootstrapper.Batch; +import org.sonar.batch.bootstrapper.EnvironmentInformation; +import org.sonar.batch.languages.Language; +import org.sonar.batch.languages.LanguagesReferential; +import org.sonar.batch.rules.QProfilesReferential; +import org.sonar.batch.scan2.AnalyzerIssueCache; +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.core.plugins.DefaultPluginMetadata; +import org.sonar.core.plugins.RemotePlugin; + +import java.io.File; +import java.io.FileReader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; + +public class AnalyzerMediumTester extends ExternalResource { + + private Batch batch; + + public static AnalyzerMediumTesterBuilder builder() { + return new AnalyzerMediumTesterBuilder().registerCoreMetrics(); + } + + public static class AnalyzerMediumTesterBuilder { + private final FakeSettingsReferential settingsReferential = new FakeSettingsReferential(); + private final FackPluginsReferential pluginsReferential = new FackPluginsReferential(); + private final FakeMetricFinder metricFinder = new FakeMetricFinder(); + private final FakeRuleFinder ruleFinder = new FakeRuleFinder(); + private final FakeQProfileReferential qProfileReferential = new FakeQProfileReferential(); + private final FakeLanguageReferential languageReferential = new FakeLanguageReferential(); + private final Map<String, String> bootstrapProperties = new HashMap<String, String>(); + private final RulesBuilder rulesBuilder = new RulesBuilder(); + private final ActiveRulesBuilder activeRulesBuilder = new ActiveRulesBuilder(); + private int metricId = 1; + + public AnalyzerMediumTester build() { + return new AnalyzerMediumTester(this); + } + + public AnalyzerMediumTesterBuilder registerPlugin(String pluginKey, File location) { + pluginsReferential.addPlugin(pluginKey, location); + return this; + } + + public AnalyzerMediumTesterBuilder registerPlugin(String pluginKey, SonarPlugin instance) { + pluginsReferential.addPlugin(pluginKey, instance); + return this; + } + + public AnalyzerMediumTesterBuilder registerCoreMetrics() { + for (Metric<?> m : CoreMetrics.getMetrics()) { + registerMetric(m); + } + return this; + } + + public AnalyzerMediumTesterBuilder registerMetric(Metric<?> metric) { + metricFinder.add(metricId++, metric); + return this; + } + + public AnalyzerMediumTesterBuilder addQProfile(String language, String name) { + qProfileReferential.add(new QProfile(name, language, 1)); + return this; + } + + public AnalyzerMediumTesterBuilder addDefaultQProfile(String language, String name) { + qProfileReferential.add(new QProfile(name, language, 1)); + settingsReferential.globalSettings().put("sonar.profile." + language, name); + return this; + } + + public AnalyzerMediumTesterBuilder registerLanguage(org.sonar.api.resources.Language... languages) { + languageReferential.register(languages); + return this; + } + + public AnalyzerMediumTesterBuilder bootstrapProperties(Map<String, String> props) { + bootstrapProperties.putAll(props); + return this; + } + + public AnalyzerMediumTesterBuilder activateRule(RuleKey key) { + rulesBuilder.add(key); + activeRulesBuilder.create(key).activate(); + return this; + } + + public AnalyzerMediumTesterBuilder registerInactiveRule(RuleKey key) { + rulesBuilder.add(key); + return this; + } + + } + + @Override + protected void before() throws Throwable { + batch.start(); + } + + @Override + protected void after() { + batch.stop(); + } + + private AnalyzerMediumTester(AnalyzerMediumTesterBuilder builder) { + batch = Batch.builder() + .setEnableLoggingConfiguration(true) + .addComponents( + new EnvironmentInformation("mediumTest", "1.0"), + builder.settingsReferential, + builder.pluginsReferential, + builder.metricFinder, + builder.ruleFinder, + builder.qProfileReferential, + builder.rulesBuilder.build(), + builder.activeRulesBuilder.build(), + new DefaultDebtModel(), + builder.languageReferential) + .setBootstrapProperties(builder.bootstrapProperties) + .build(); + } + + public TaskBuilder newTask() { + return new TaskBuilder(this); + } + + public TaskBuilder newScanTask(File sonarProps) { + Properties prop = new Properties(); + FileReader reader = null; + try { + reader = new FileReader(sonarProps); + prop.load(reader); + } catch (Exception e) { + throw new IllegalStateException("Unable to read configuration file", e); + } finally { + if (reader != null) { + IOUtils.closeQuietly(reader); + } + } + TaskBuilder builder = new TaskBuilder(this); + builder.property("sonar.task", "scan"); + builder.property("sonar.projectBaseDir", sonarProps.getParentFile().getAbsolutePath()); + for (Map.Entry entry : prop.entrySet()) { + builder.property(entry.getKey().toString(), entry.getValue().toString()); + } + return builder; + } + + public static class TaskBuilder { + private final Map<String, String> taskProperties = new HashMap<String, String>(); + private AnalyzerMediumTester tester; + + public TaskBuilder(AnalyzerMediumTester tester) { + this.tester = tester; + } + + public TaskResult start() { + TaskResult result = new TaskResult(); + tester.batch.executeTask(taskProperties, + result + ); + return result; + } + + public TaskBuilder properties(Map<String, String> props) { + taskProperties.putAll(props); + return this; + } + + public TaskBuilder property(String key, String value) { + taskProperties.put(key, value); + return this; + } + } + + public static class TaskResult implements ScanTaskObserver { + private List<AnalyzerIssue> issues = new ArrayList<AnalyzerIssue>(); + private List<AnalyzerMeasure> measures = new ArrayList<AnalyzerMeasure>(); + + @Override + public void scanTaskCompleted(ProjectScanContainer container) { + for (AnalyzerIssue issue : container.getComponentByType(AnalyzerIssueCache.class).all()) { + issues.add(issue); + } + + for (AnalyzerMeasure<?> measure : container.getComponentByType(AnalyzerMeasureCache.class).all()) { + measures.add(measure); + } + } + + public List<AnalyzerIssue> issues() { + return issues; + } + + public List<AnalyzerMeasure> measures() { + return measures; + } + + } + + private static class FakeSettingsReferential implements SettingsReferential { + + private Map<String, String> globalSettings = new HashMap<String, String>(); + private Map<String, Map<String, String>> projectSettings = new HashMap<String, Map<String, String>>(); + + @Override + public Map<String, String> globalSettings() { + return globalSettings; + } + + @Override + public Map<String, String> projectSettings(String projectKey) { + return projectSettings.containsKey(projectKey) ? projectSettings.get(projectKey) : Collections.<String, String>emptyMap(); + } + + } + + private static class FackPluginsReferential implements PluginsReferential { + + private List<RemotePlugin> pluginList = new ArrayList<RemotePlugin>(); + private Map<RemotePlugin, File> pluginFiles = new HashMap<RemotePlugin, File>(); + Map<PluginMetadata, SonarPlugin> localPlugins = new HashMap<PluginMetadata, SonarPlugin>(); + + @Override + public List<RemotePlugin> pluginList() { + return pluginList; + } + + @Override + public File pluginFile(RemotePlugin remote) { + return pluginFiles.get(remote); + } + + public FackPluginsReferential addPlugin(String pluginKey, File location) { + RemotePlugin plugin = new RemotePlugin(pluginKey, false); + pluginList.add(plugin); + pluginFiles.put(plugin, location); + return this; + } + + public FackPluginsReferential addPlugin(String pluginKey, SonarPlugin pluginInstance) { + localPlugins.put(DefaultPluginMetadata.create(null).setKey(pluginKey), pluginInstance); + return this; + } + + @Override + public Map<PluginMetadata, SonarPlugin> localPlugins() { + return localPlugins; + } + + } + + private static class FakeMetricFinder implements MetricFinder { + + private Map<String, Metric> metricsByKey = Maps.newLinkedHashMap(); + private Map<Integer, Metric> metricsById = Maps.newLinkedHashMap(); + + public FakeMetricFinder add(int id, Metric metric) { + metricsByKey.put(metric.getKey(), metric); + metricsById.put(id, metric); + return this; + } + + @Override + public Metric findById(int metricId) { + return metricsById.get(metricId); + } + + @Override + public Metric findByKey(String key) { + return metricsByKey.get(key); + } + + @Override + public Collection<Metric> findAll(List<String> metricKeys) { + List<Metric> result = Lists.newLinkedList(); + for (String metricKey : metricKeys) { + Metric metric = findByKey(metricKey); + if (metric != null) { + result.add(metric); + } + } + return result; + } + + @Override + public Collection<Metric> findAll() { + return metricsByKey.values(); + } + + } + + private static class FakeRuleFinder implements RuleFinder { + private BiMap<Integer, Rule> rulesById = HashBiMap.create(); + private Map<String, Map<String, Rule>> rulesByRepoKeyAndRuleKey = Maps.newHashMap(); + + @Override + public Rule findById(int ruleId) { + return rulesById.get(ruleId); + } + + @Override + public Rule findByKey(String repositoryKey, String ruleKey) { + Map<String, Rule> repository = rulesByRepoKeyAndRuleKey.get(repositoryKey); + return repository != null ? repository.get(ruleKey) : null; + } + + @Override + public Rule findByKey(RuleKey key) { + return findByKey(key.repository(), key.rule()); + } + + @Override + public Rule find(RuleQuery query) { + throw new UnsupportedOperationException(); + } + + @Override + public Collection<Rule> findAll(RuleQuery query) { + throw new UnsupportedOperationException(); + } + } + + private static class FakeQProfileReferential implements QProfilesReferential { + + private Map<String, Map<String, QProfile>> profiles = new HashMap<String, Map<String, QProfile>>(); + + @Override + public QProfile get(String language, String name) { + return profiles.get(language).get(name); + } + + public void add(QProfile qprofile) { + if (!profiles.containsKey(qprofile.language())) { + profiles.put(qprofile.language(), new HashMap<String, QProfile>()); + } + profiles.get(qprofile.language()).put(qprofile.name(), qprofile); + } + + } + + private static class FakeLanguageReferential implements LanguagesReferential { + + private Map<String, Language> languages = new HashMap<String, Language>(); + + public FakeLanguageReferential register(org.sonar.api.resources.Language... languages) { + for (org.sonar.api.resources.Language language : languages) { + this.languages.put(language.getKey(), new Language(language.getKey(), language.getName(), language.getFileSuffixes())); + } + return this; + } + + @Override + public Language get(String languageKey) { + return languages.get(languageKey); + } + + @Override + public Collection<Language> all() { + return languages.values(); + } + + } + +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/XooMediumTest.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/XooMediumTest.java new file mode 100644 index 00000000000..73c2b563639 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/XooMediumTest.java @@ -0,0 +1,113 @@ +/* + * 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; + +import com.google.common.collect.ImmutableMap; +import org.apache.commons.io.FileUtils; +import org.junit.Test; +import org.junit.rules.TemporaryFolder; +import org.sonar.api.batch.analyzer.issue.AnalyzerIssue; +import org.sonar.api.batch.analyzer.measure.internal.DefaultAnalyzerMeasureBuilder; +import org.sonar.api.batch.fs.internal.DefaultInputFile; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.rule.RuleKey; +import org.sonar.batch.mediumtest.AnalyzerMediumTester; +import org.sonar.batch.mediumtest.AnalyzerMediumTester.TaskResult; +import org.sonar.batch.mediumtest.xoo.plugin.XooPlugin; +import org.sonar.batch.mediumtest.xoo.plugin.base.Xoo; + +import java.io.File; +import java.io.IOException; + +import static org.fest.assertions.Assertions.assertThat; + +public class XooMediumTest { + + @org.junit.Rule + public TemporaryFolder temp = new TemporaryFolder(); + + @org.junit.Rule + public AnalyzerMediumTester tester = AnalyzerMediumTester.builder() + // .registerPlugin("xoo", new File("target/sonar-xoo-plugin-2.0-SNAPSHOT.jar")) + .registerPlugin("xoo", new XooPlugin()) + .registerLanguage(new Xoo()) + .addDefaultQProfile("xoo", "Sonar Way") + .activateRule(RuleKey.of("xoo", "OneIssuePerLine")) + .bootstrapProperties(ImmutableMap.of("sonar.analysis.mode", "sensor")) + .build(); + + @Test + public void mediumTestOfSample() throws Exception { + File projectDir = new File(XooMediumTest.class.getResource("/org/sonar/batch/mediumtest/xoo/sample").toURI()); + + TaskResult result = tester + .newScanTask(new File(projectDir, "sonar-project.properties")) + .start(); + + assertThat(result.measures()).hasSize(13); + assertThat(result.issues()).hasSize(24); + } + + @Test + public void mediumTest() throws IOException { + + File baseDir = temp.newFolder(); + File srcDir = new File(baseDir, "src"); + srcDir.mkdir(); + + File xooFile = new File(srcDir, "sample.xoo"); + File xooMeasureFile = new File(srcDir, "sample.xoo.measures"); + FileUtils.write(xooFile, "Sample xoo\ncontent"); + FileUtils.write(xooMeasureFile, "lines:20"); + + 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(); + + assertThat(result.measures()).hasSize(1); + assertThat(result.issues()).hasSize(20); + + assertThat(result.measures()).contains(new DefaultAnalyzerMeasureBuilder<Integer>() + .forMetric(CoreMetrics.LINES) + .onFile(new DefaultInputFile("src/sample.xoo")) + .withValue(20) + .build()); + + boolean foundIssueAtLine1 = false; + for (AnalyzerIssue issue : result.issues()) { + if (issue.line() == 1) { + foundIssueAtLine1 = true; + assertThat(issue.inputFile()).isEqualTo(new DefaultInputFile("src/sample.xoo")); + assertThat(issue.message()).isEqualTo("This issue is generated on each line"); + assertThat(issue.effortToFix()).isNull(); + } + } + assertThat(foundIssueAtLine1).isTrue(); + } + +} 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 new file mode 100644 index 00000000000..a93cdbf6b22 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/XooPlugin.java @@ -0,0 +1,43 @@ +/* + * 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; + +import org.sonar.api.SonarPlugin; +import org.sonar.batch.mediumtest.xoo.plugin.base.Xoo; +import org.sonar.batch.mediumtest.xoo.plugin.lang.MeasureAnalyzer; +import org.sonar.batch.mediumtest.xoo.plugin.rule.OneIssuePerLineAnalyzer; + +import java.util.Arrays; +import java.util.List; + +public final class XooPlugin extends SonarPlugin { + + @Override + public List getExtensions() { + return Arrays.asList( + // language + MeasureAnalyzer.class, + Xoo.class, + + // rules + OneIssuePerLineAnalyzer.class + ); + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/base/Xoo.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/base/Xoo.java new file mode 100644 index 00000000000..1922fd7aa35 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/base/Xoo.java @@ -0,0 +1,40 @@ +/* + * 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.base; + +import org.sonar.api.resources.AbstractLanguage; + +public class Xoo extends AbstractLanguage { + + public static final String KEY = "xoo"; + public static final String NAME = "Xoo"; + + public Xoo() { + super(KEY, NAME); + } + + /** + * ${@inheritDoc} + */ + public String[] getFileSuffixes() { + return XooConstants.FILE_SUFFIXES; + } + +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/base/XooConstants.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/base/XooConstants.java new file mode 100644 index 00000000000..c59091fb0f6 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/base/XooConstants.java @@ -0,0 +1,36 @@ +/* + * 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.base; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public interface XooConstants { + + String PLUGIN_KEY = "xoo"; + String PLUGIN_NAME = "Xoo"; + + String REPOSITORY_KEY = PLUGIN_KEY; + String REPOSITORY_NAME = PLUGIN_NAME; + + String[] FILE_SUFFIXES = {"xoo"}; + + Logger LOG = LoggerFactory.getLogger("xoo"); +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/MeasureAnalyzer.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/MeasureAnalyzer.java new file mode 100644 index 00000000000..8da7690333f --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/MeasureAnalyzer.java @@ -0,0 +1,138 @@ +/* + * 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 org.apache.commons.io.FileUtils; +import org.apache.commons.lang.StringUtils; +import org.sonar.api.batch.analyzer.Analyzer; +import org.sonar.api.batch.analyzer.AnalyzerContext; +import org.sonar.api.batch.analyzer.AnalyzerDescriptor; +import org.sonar.api.batch.analyzer.measure.AnalyzerMeasure; +import org.sonar.api.batch.analyzer.measure.AnalyzerMeasureBuilder; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.measures.Metric; +import org.sonar.api.measures.MetricFinder; +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.io.Serializable; +import java.util.List; + +/** + * Parse files *.xoo.measures + */ +public class MeasureAnalyzer implements Analyzer { + + private static final String MEASURES_EXTENSION = ".measures"; + + private MetricFinder metricFinder; + + public MeasureAnalyzer(MetricFinder metricFinder) { + this.metricFinder = metricFinder; + } + + private void processFileMeasures(InputFile inputFile, AnalyzerContext context) { + File ioFile = inputFile.file(); + File measureFile = new File(ioFile.getParentFile(), ioFile.getName() + MEASURES_EXTENSION); + if (measureFile.exists()) { + XooConstants.LOG.debug("Processing " + measureFile.getAbsolutePath()); + try { + List<String> lines = FileUtils.readLines(measureFile, context.fileSystem().encoding().name()); + int lineNumber = 0; + for (String line : lines) { + lineNumber++; + if (StringUtils.isBlank(line)) { + continue; + } + if (line.startsWith("#")) { + continue; + } + try { + String metricKey = StringUtils.substringBefore(line, ":"); + String value = line.substring(metricKey.length() + 1); + context.addMeasure(createMeasure(context, inputFile, metricKey, value)); + } catch (Exception e) { + throw new IllegalStateException("Error processing line " + lineNumber + " of file " + measureFile.getAbsolutePath(), e); + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + private AnalyzerMeasure<?> createMeasure(AnalyzerContext context, InputFile xooFile, String metricKey, String value) { + Metric metric = metricFinder.findByKey(metricKey); + AnalyzerMeasureBuilder<Serializable> builder = context.measureBuilder() + .forMetric(metric) + .onFile(xooFile); + switch (metric.getType()) { + case BOOL: + builder.withValue(Boolean.parseBoolean(value)); + break; + case INT: + case MILLISEC: + builder.withValue(Integer.valueOf(value)); + break; + case FLOAT: + case PERCENT: + case RATING: + builder.withValue(Double.valueOf(value)); + break; + case STRING: + case LEVEL: + case DATA: + case DISTRIB: + builder.withValue(value); + break; + case WORK_DUR: + builder.withValue(Long.valueOf(value)); + break; + default: + if (metric.isNumericType()) { + builder.withValue(Double.valueOf(value)); + } else if (metric.isDataType()) { + builder.withValue(value); + } else { + throw new UnsupportedOperationException("Unsupported type :" + metric.getType()); + } + } + return builder.build(); + } + + @Override + public void describe(AnalyzerDescriptor descriptor) { + descriptor + .name("Xoo Measure Analyzer") + .provides(CoreMetrics.LINES) + .workOnLanguages(Xoo.KEY) + .workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST); + } + + @Override + public void analyse(AnalyzerContext context) { + for (InputFile file : context.fileSystem().inputFiles(context.fileSystem().predicates().hasLanguages(Xoo.KEY))) { + processFileMeasures(file, context); + } + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssuePerLineAnalyzer.java b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssuePerLineAnalyzer.java new file mode 100644 index 00000000000..522ad3b6b53 --- /dev/null +++ b/sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssuePerLineAnalyzer.java @@ -0,0 +1,71 @@ +/* + * 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.rule; + +import org.slf4j.LoggerFactory; +import org.sonar.api.batch.analyzer.Analyzer; +import org.sonar.api.batch.analyzer.AnalyzerContext; +import org.sonar.api.batch.analyzer.AnalyzerDescriptor; +import org.sonar.api.batch.analyzer.measure.AnalyzerMeasure; +import org.sonar.api.batch.fs.InputFile; +import org.sonar.api.measures.CoreMetrics; +import org.sonar.api.rule.RuleKey; +import org.sonar.batch.mediumtest.xoo.plugin.base.Xoo; +import org.sonar.batch.mediumtest.xoo.plugin.base.XooConstants; + +public class OneIssuePerLineAnalyzer implements Analyzer { + + public static final String RULE_KEY = "OneIssuePerLine"; + private static final String EFFORT_TO_FIX_PROPERTY = "sonar.oneIssuePerLine.effortToFix"; + + @Override + public void describe(AnalyzerDescriptor descriptor) { + descriptor + .name("One Issue Per Line") + .dependsOn(CoreMetrics.LINES) + .workOnLanguages(Xoo.KEY) + .workOnFileTypes(InputFile.Type.MAIN, InputFile.Type.TEST); + } + + @Override + public void analyse(AnalyzerContext context) { + for (InputFile file : context.fileSystem().inputFiles(context.fileSystem().predicates().hasLanguages(Xoo.KEY))) { + createIssues(file, context); + } + } + + private void createIssues(InputFile file, AnalyzerContext context) { + RuleKey ruleKey = RuleKey.of(XooConstants.REPOSITORY_KEY, RULE_KEY); + AnalyzerMeasure<Integer> linesMeasure = context.getMeasure(file, CoreMetrics.LINES); + if (linesMeasure == null) { + LoggerFactory.getLogger(getClass()).warn("Missing measure " + CoreMetrics.LINES_KEY + " on " + file); + } else { + for (int line = 1; line <= (Integer) linesMeasure.value(); line++) { + context.addIssue(context.issueBuilder() + .ruleKey(ruleKey) + .onFile(file) + .atLine(line) + .effortToFix(context.settings().getDouble(EFFORT_TO_FIX_PROPERTY)) + .message("This issue is generated on each line") + .build()); + } + } + } +} diff --git a/sonar-batch/src/test/java/org/sonar/batch/scan2/AnalyzerOptimizerTest.java b/sonar-batch/src/test/java/org/sonar/batch/scan2/AnalyzerOptimizerTest.java index 1384950b99d..8940c3dd2fc 100644 --- a/sonar-batch/src/test/java/org/sonar/batch/scan2/AnalyzerOptimizerTest.java +++ b/sonar-batch/src/test/java/org/sonar/batch/scan2/AnalyzerOptimizerTest.java @@ -98,18 +98,18 @@ public class AnalyzerOptimizerTest { assertThat(optimizer.shouldExecute(descriptor)).isFalse(); ActiveRules activeRules = new ActiveRulesBuilder() - .activate(RuleKey.of("repo1", "foo")) - .end() + .create(RuleKey.of("repo1", "foo")) + .activate() .build(); optimizer = new AnalyzerOptimizer(fs, activeRules); assertThat(optimizer.shouldExecute(descriptor)).isFalse(); activeRules = new ActiveRulesBuilder() - .activate(RuleKey.of("repo1", "foo")) - .end() - .activate(RuleKey.of("squid", "rule")) - .end() + .create(RuleKey.of("repo1", "foo")) + .activate() + .create(RuleKey.of("squid", "rule")) + .activate() .build(); optimizer = new AnalyzerOptimizer(fs, activeRules); assertThat(optimizer.shouldExecute(descriptor)).isTrue(); diff --git a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/sonar-project.properties b/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/sonar-project.properties new file mode 100644 index 00000000000..8810e376701 --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/sonar-project.properties @@ -0,0 +1,6 @@ +sonar.projectKey=sample +sonar.projectName=Sample +sonar.projectVersion=0.1-SNAPSHOT +sonar.sources=xources +sonar.tests=testx +sonar.language=xoo diff --git a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo b/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo new file mode 100644 index 00000000000..8c0967e496f --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo @@ -0,0 +1,11 @@ +package org.sonar.tests; + +import org.junit.Test; + +public class ClassOneTest { + + @Test + public void nothing() { + + } +} diff --git a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo.measures b/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo.measures new file mode 100644 index 00000000000..23b08dc0e0e --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo.measures @@ -0,0 +1,7 @@ +lines:11 +ncloc:7 +tests:1 +test_execution_time:1 +skipped_tests:0 +test_errors:0 +test_failures:0 diff --git a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo.scm b/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo.scm new file mode 100644 index 00000000000..2cec35b8a72 --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo.scm @@ -0,0 +1,11 @@ +1,user1,2013-01-04 +1,user1,2013-01-04 +1,user1,2013-01-04 +1,user1,2013-01-04 +2,user2,2013-01-05 +2,user2,2013-01-05 +3,user3,2013-01-06 +4,user4,2013-01-07 +4,user4,2013-01-07 +4,user4,2013-01-07 +4,user4,2013-01-07
\ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo b/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo new file mode 100644 index 00000000000..1d9c60d56b7 --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo @@ -0,0 +1,8 @@ +package hello; + +public class HelloJava { + + public static void main(String[] args) { + System.out.println("Hello"); + } +}
\ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.measures b/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.measures new file mode 100644 index 00000000000..388d08b58a8 --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.measures @@ -0,0 +1,3 @@ +lines:8 +ncloc:3 +complexity:1 diff --git a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.scm b/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.scm new file mode 100644 index 00000000000..03a9de2f486 --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.scm @@ -0,0 +1,8 @@ +1,user1,2013-01-04 +1,user1,2013-01-04 +1,user1,2013-01-04 +1,user1,2013-01-04 +2,user2,2013-01-05 +2,user2,2013-01-05 +3,user3,2013-01-06 +4,user4,2013-01-07
\ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/helloscala.xoo b/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/helloscala.xoo new file mode 100644 index 00000000000..53cb085156c --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/helloscala.xoo @@ -0,0 +1,6 @@ + object HelloWorld { + def main(args: Array[String]) { + println("Hello, world of xoo!") + } + } +
\ No newline at end of file diff --git a/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/helloscala.xoo.measures b/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/helloscala.xoo.measures new file mode 100644 index 00000000000..c47948fc955 --- /dev/null +++ b/sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/helloscala.xoo.measures @@ -0,0 +1,3 @@ +lines:5 +ncloc:5 +complexity:2 |