Browse Source

SONAR-5389 Add medium tests

tags/4.4-RC1
Julien HENRY 10 years ago
parent
commit
3bd4ce6a6c
29 changed files with 1100 additions and 124 deletions
  1. 3
    3
      sonar-batch/src/main/java/org/sonar/batch/rule/ActiveRulesProvider.java
  2. 52
    0
      sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerIssueCache.java
  3. 10
    20
      sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultAnalyzerContext.java
  4. 4
    50
      sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java
  5. 13
    11
      sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java
  6. 417
    0
      sonar-batch/src/test/java/org/sonar/batch/mediumtest/AnalyzerMediumTester.java
  7. 113
    0
      sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/XooMediumTest.java
  8. 43
    0
      sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/XooPlugin.java
  9. 40
    0
      sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/base/Xoo.java
  10. 36
    0
      sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/base/XooConstants.java
  11. 138
    0
      sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/MeasureAnalyzer.java
  12. 71
    0
      sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssuePerLineAnalyzer.java
  13. 6
    6
      sonar-batch/src/test/java/org/sonar/batch/scan2/AnalyzerOptimizerTest.java
  14. 6
    0
      sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/sonar-project.properties
  15. 11
    0
      sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo
  16. 7
    0
      sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo.measures
  17. 11
    0
      sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo.scm
  18. 8
    0
      sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo
  19. 3
    0
      sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.measures
  20. 8
    0
      sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.scm
  21. 6
    0
      sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/helloscala.xoo
  22. 3
    0
      sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/helloscala.xoo.measures
  23. 33
    0
      sonar-plugin-api/src/main/java/org/sonar/api/batch/analyzer/issue/internal/DefaultAnalyzerIssue.java
  24. 9
    0
      sonar-plugin-api/src/main/java/org/sonar/api/batch/analyzer/issue/internal/DefaultAnalyzerIssueBuilder.java
  25. 24
    12
      sonar-plugin-api/src/main/java/org/sonar/api/batch/analyzer/measure/internal/DefaultAnalyzerMeasure.java
  26. 8
    6
      sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/ActiveRulesBuilder.java
  27. 2
    1
      sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/NewActiveRule.java
  28. 9
    9
      sonar-plugin-api/src/test/java/org/sonar/api/batch/rule/CheckFactoryTest.java
  29. 6
    6
      sonar-plugin-api/src/test/java/org/sonar/api/batch/rule/internal/ActiveRulesBuilderTest.java

+ 3
- 3
sonar-batch/src/main/java/org/sonar/batch/rule/ActiveRulesProvider.java View File

@@ -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();
}
}
}

+ 52
- 0
sonar-batch/src/main/java/org/sonar/batch/scan2/AnalyzerIssueCache.java View File

@@ -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;
}

}

+ 10
- 20
sonar-batch/src/main/java/org/sonar/batch/scan2/DefaultAnalyzerContext.java View File

@@ -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);
}

}

+ 4
- 50
sonar-batch/src/main/java/org/sonar/batch/scan2/ProjectScanContainer.java View File

@@ -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);
}

+ 13
- 11
sonar-batch/src/test/java/org/sonar/batch/issue/ModuleIssuesTest.java View File

@@ -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()

+ 417
- 0
sonar-batch/src/test/java/org/sonar/batch/mediumtest/AnalyzerMediumTester.java View File

@@ -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();
}

}

}

+ 113
- 0
sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/XooMediumTest.java View File

@@ -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();
}

}

+ 43
- 0
sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/XooPlugin.java View File

@@ -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
);
}
}

+ 40
- 0
sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/base/Xoo.java View File

@@ -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;
}

}

+ 36
- 0
sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/base/XooConstants.java View File

@@ -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");
}

+ 138
- 0
sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/lang/MeasureAnalyzer.java View File

@@ -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);
}
}
}

+ 71
- 0
sonar-batch/src/test/java/org/sonar/batch/mediumtest/xoo/plugin/rule/OneIssuePerLineAnalyzer.java View File

@@ -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());
}
}
}
}

+ 6
- 6
sonar-batch/src/test/java/org/sonar/batch/scan2/AnalyzerOptimizerTest.java View File

@@ -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();

+ 6
- 0
sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/sonar-project.properties View File

@@ -0,0 +1,6 @@
sonar.projectKey=sample
sonar.projectName=Sample
sonar.projectVersion=0.1-SNAPSHOT
sonar.sources=xources
sonar.tests=testx
sonar.language=xoo

+ 11
- 0
sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo View File

@@ -0,0 +1,11 @@
package org.sonar.tests;

import org.junit.Test;

public class ClassOneTest {

@Test
public void nothing() {

}
}

+ 7
- 0
sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo.measures View File

@@ -0,0 +1,7 @@
lines:11
ncloc:7
tests:1
test_execution_time:1
skipped_tests:0
test_errors:0
test_failures:0

+ 11
- 0
sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/testx/ClassOneTest.xoo.scm View File

@@ -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

+ 8
- 0
sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo View File

@@ -0,0 +1,8 @@
package hello;

public class HelloJava {

public static void main(String[] args) {
System.out.println("Hello");
}
}

+ 3
- 0
sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.measures View File

@@ -0,0 +1,3 @@
lines:8
ncloc:3
complexity:1

+ 8
- 0
sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/HelloJava.xoo.scm View File

@@ -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

+ 6
- 0
sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/helloscala.xoo View File

@@ -0,0 +1,6 @@
object HelloWorld {
def main(args: Array[String]) {
println("Hello, world of xoo!")
}
}

+ 3
- 0
sonar-batch/src/test/resources/org/sonar/batch/mediumtest/xoo/sample/xources/hello/helloscala.xoo.measures View File

@@ -0,0 +1,3 @@
lines:5
ncloc:5
complexity:2

+ 33
- 0
sonar-plugin-api/src/main/java/org/sonar/api/batch/analyzer/issue/internal/DefaultAnalyzerIssue.java View File

@@ -20,6 +20,9 @@
package org.sonar.api.batch.analyzer.issue.internal;

import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.sonar.api.batch.analyzer.issue.AnalyzerIssue;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.rule.RuleKey;
@@ -27,9 +30,11 @@ import org.sonar.api.rule.RuleKey;
import javax.annotation.Nullable;

import java.io.Serializable;
import java.util.UUID;

public class DefaultAnalyzerIssue implements AnalyzerIssue, Serializable {

private final String key;
private final InputFile inputFile;
private final RuleKey ruleKey;
private final String message;
@@ -43,6 +48,12 @@ public class DefaultAnalyzerIssue implements AnalyzerIssue, Serializable {
this.message = builder.message;
this.line = builder.line;
this.effortToFix = builder.effortToFix;
this.key = builder.key == null ? UUID.randomUUID().toString() : builder.key;
Preconditions.checkState(!Strings.isNullOrEmpty(key), "Fail to generate issue key");
}

public String key() {
return key;
}

@Override
@@ -72,4 +83,26 @@ public class DefaultAnalyzerIssue implements AnalyzerIssue, Serializable {
return effortToFix;
}

@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
DefaultAnalyzerIssue that = (DefaultAnalyzerIssue) o;
return !key.equals(that.key);
}

@Override
public int hashCode() {
return key.hashCode();
}

@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}

}

+ 9
- 0
sonar-plugin-api/src/main/java/org/sonar/api/batch/analyzer/issue/internal/DefaultAnalyzerIssueBuilder.java View File

@@ -29,6 +29,7 @@ import javax.annotation.Nullable;

public class DefaultAnalyzerIssueBuilder implements AnalyzerIssueBuilder {

String key;
Boolean onProject = null;
InputFile file;
RuleKey ruleKey;
@@ -80,6 +81,14 @@ public class DefaultAnalyzerIssueBuilder implements AnalyzerIssueBuilder {
return this;
}

/**
* For testing only.
*/
public DefaultAnalyzerIssueBuilder withKey(String key) {
this.key = key;
return this;
}

@Override
public AnalyzerIssue build() {
return new DefaultAnalyzerIssue(this);

+ 24
- 12
sonar-plugin-api/src/main/java/org/sonar/api/batch/analyzer/measure/internal/DefaultAnalyzerMeasure.java View File

@@ -19,11 +19,14 @@
*/
package org.sonar.api.batch.analyzer.measure.internal;

import org.sonar.api.batch.measure.Metric;

import com.google.common.base.Preconditions;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.sonar.api.batch.analyzer.measure.AnalyzerMeasure;
import org.sonar.api.batch.fs.InputFile;
import org.sonar.api.batch.measure.Metric;

import javax.annotation.Nullable;

@@ -62,26 +65,35 @@ public class DefaultAnalyzerMeasure<G extends Serializable> implements AnalyzerM

@Override
public boolean equals(Object obj) {
if (!(obj instanceof DefaultAnalyzerMeasure)) {
if (obj == null) {
return false;
}
if (obj == this) {
return true;
}
if (obj.getClass() != getClass()) {
return false;
}
DefaultAnalyzerMeasure<?> other = (DefaultAnalyzerMeasure<?>) obj;
return metric.equals(other.metric)
&& value.equals(other.value)
&& (inputFile == null ? other.inputFile == null : inputFile.equals(other.inputFile));
DefaultAnalyzerMeasure rhs = (DefaultAnalyzerMeasure) obj;
return new EqualsBuilder()
.append(inputFile, rhs.inputFile)
.append(metric, rhs.metric)
.append(value, rhs.value)
.isEquals();
}

@Override
public int hashCode() {
return metric.hashCode()
+ value.hashCode()
+ (inputFile != null ? inputFile.hashCode() : 0);
return new HashCodeBuilder(27, 45).
append(inputFile).
append(metric).
append(value).
toHashCode();
}

@Override
public String toString() {
return "AnalyzerMeasure[" + (inputFile != null ? "inputFile=" + inputFile.toString() : "onProject")
+ ",metric=" + metric + ",value=" + value + "]";
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
}

}

+ 8
- 6
sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/ActiveRulesBuilder.java View File

@@ -35,13 +35,15 @@ public class ActiveRulesBuilder {

private final Map<RuleKey, NewActiveRule> map = Maps.newHashMap();

public NewActiveRule activate(RuleKey ruleKey) {
if (map.containsKey(ruleKey)) {
throw new IllegalStateException(String.format("Rule '%s' is already activated", ruleKey));
public NewActiveRule create(RuleKey ruleKey) {
return new NewActiveRule(this, ruleKey);
}

void activate(NewActiveRule newActiveRule) {
if (map.containsKey(newActiveRule.ruleKey)) {
throw new IllegalStateException(String.format("Rule '%s' is already activated", newActiveRule.ruleKey));
}
NewActiveRule newActiveRule = new NewActiveRule(this, ruleKey);
map.put(ruleKey, newActiveRule);
return newActiveRule;
map.put(newActiveRule.ruleKey, newActiveRule);
}

public ActiveRules build() {

+ 2
- 1
sonar-plugin-api/src/main/java/org/sonar/api/batch/rule/internal/NewActiveRule.java View File

@@ -72,7 +72,8 @@ public class NewActiveRule {
return params;
}

public ActiveRulesBuilder end() {
public ActiveRulesBuilder activate() {
builder.activate(this);
return builder;
}
}

+ 9
- 9
sonar-plugin-api/src/test/java/org/sonar/api/batch/rule/CheckFactoryTest.java View File

@@ -46,7 +46,7 @@ public class CheckFactoryTest {
@Test
public void class_name_as_check_key() {
RuleKey ruleKey = RuleKey.of("squid", "org.sonar.api.batch.rule.CheckWithoutProperties");
builder.activate(ruleKey);
builder.create(ruleKey).activate();
CheckFactory checkFactory = new CheckFactory(builder.build());

Checks checks = checkFactory.create("squid").addAnnotatedChecks(CheckWithoutProperties.class);
@@ -60,7 +60,7 @@ public class CheckFactoryTest {
@Test
public void param_as_string_field() {
RuleKey ruleKey = RuleKey.of("squid", "org.sonar.api.batch.rule.CheckWithStringProperty");
builder.activate(ruleKey).setParam("pattern", "foo");
builder.create(ruleKey).setParam("pattern", "foo").activate();

CheckFactory checkFactory = new CheckFactory(builder.build());
Checks checks = checkFactory.create("squid").addAnnotatedChecks(CheckWithStringProperty.class);
@@ -77,7 +77,7 @@ public class CheckFactoryTest {
thrown.expectMessage("The field 'unknown' does not exist or is not annotated with @RuleProperty in the class org.sonar.api.batch.rule.CheckWithStringProperty");

RuleKey ruleKey = RuleKey.of("squid", "org.sonar.api.batch.rule.CheckWithStringProperty");
builder.activate(ruleKey).setParam("unknown", "foo");
builder.create(ruleKey).setParam("unknown", "foo").activate();

CheckFactory checkFactory = new CheckFactory(builder.build());
checkFactory.create("squid").addAnnotatedChecks(CheckWithStringProperty.class);
@@ -86,7 +86,7 @@ public class CheckFactoryTest {
@Test
public void param_as_primitive_fields() {
RuleKey ruleKey = RuleKey.of("squid", "org.sonar.api.batch.rule.CheckWithPrimitiveProperties");
builder.activate(ruleKey).setParam("max", "300").setParam("ignore", "true");
builder.create(ruleKey).setParam("max", "300").setParam("ignore", "true").activate();

CheckFactory checkFactory = new CheckFactory(builder.build());
Checks checks = checkFactory.create("squid").addAnnotatedChecks(CheckWithPrimitiveProperties.class);
@@ -103,7 +103,7 @@ public class CheckFactoryTest {
@Test
public void param_as_inherited_field() {
RuleKey ruleKey = RuleKey.of("squid", "org.sonar.api.batch.rule.CheckWithPrimitiveProperties");
builder.activate(ruleKey).setParam("max", "300");
builder.create(ruleKey).setParam("max", "300").activate();

CheckFactory checkFactory = new CheckFactory(builder.build());
Checks checks = checkFactory.create("squid").addAnnotatedChecks(CheckWithPrimitiveProperties.class);
@@ -116,7 +116,7 @@ public class CheckFactoryTest {
@Test
public void use_engine_key() {
RuleKey ruleKey = RuleKey.of("squid", "One");
builder.activate(ruleKey).setInternalKey("S0001");
builder.create(ruleKey).setInternalKey("S0001").activate();

CheckFactory checkFactory = new CheckFactory(builder.build());
Checks checks = checkFactory.create("squid").addAnnotatedChecks(CheckWithKey.class);
@@ -133,7 +133,7 @@ public class CheckFactoryTest {
thrown.expect(SonarException.class);

RuleKey ruleKey = RuleKey.of("squid", "org.sonar.api.batch.rule.CheckWithUnsupportedPropertyType");
builder.activate(ruleKey).setParam("max", "300");
builder.create(ruleKey).setParam("max", "300").activate();

CheckFactory checkFactory = new CheckFactory(builder.build());
checkFactory.create("squid").addAnnotatedChecks(CheckWithUnsupportedPropertyType.class);
@@ -142,7 +142,7 @@ public class CheckFactoryTest {
@Test
public void override_field_key() {
RuleKey ruleKey = RuleKey.of("squid", "org.sonar.api.batch.rule.CheckWithOverriddenPropertyKey");
builder.activate(ruleKey).setParam("maximum", "300");
builder.create(ruleKey).setParam("maximum", "300").activate();

CheckFactory checkFactory = new CheckFactory(builder.build());
Checks checks = checkFactory.create("squid").addAnnotatedChecks(CheckWithOverriddenPropertyKey.class);
@@ -158,7 +158,7 @@ public class CheckFactoryTest {
@Test
public void checks_as_objects() {
RuleKey ruleKey = RuleKey.of("squid", "org.sonar.api.batch.rule.CheckWithStringProperty");
builder.activate(ruleKey).setParam("pattern", "foo");
builder.create(ruleKey).setParam("pattern", "foo").activate();
CheckFactory checkFactory = new CheckFactory(builder.build());

CheckWithStringProperty check = new CheckWithStringProperty();

+ 6
- 6
sonar-plugin-api/src/test/java/org/sonar/api/batch/rule/internal/ActiveRulesBuilderTest.java View File

@@ -39,14 +39,14 @@ public class ActiveRulesBuilderTest {
@Test
public void build_rules() throws Exception {
ActiveRules activeRules = new ActiveRulesBuilder()
.activate(RuleKey.of("squid", "S0001"))
.create(RuleKey.of("squid", "S0001"))
.setSeverity(Severity.CRITICAL)
.setInternalKey("__S0001__")
.setParam("min", "20")
.end()
.activate()
// most simple rule
.activate(RuleKey.of("squid", "S0002")).end()
.activate(RuleKey.of("findbugs", "NPE")).setInternalKey(null).setSeverity(null).setParam("foo", null).end()
.create(RuleKey.of("squid", "S0002")).activate()
.create(RuleKey.of("findbugs", "NPE")).setInternalKey(null).setSeverity(null).setParam("foo", null).activate()
.build();

assertThat(activeRules.findAll()).hasSize(3);
@@ -77,9 +77,9 @@ public class ActiveRulesBuilderTest {
@Test
public void fail_to_add_twice_the_same_rule() throws Exception {
ActiveRulesBuilder builder = new ActiveRulesBuilder();
builder.activate(RuleKey.of("squid", "S0001"));
builder.create(RuleKey.of("squid", "S0001")).activate();
try {
builder.activate(RuleKey.of("squid", "S0001"));
builder.create(RuleKey.of("squid", "S0001")).activate();
fail();
} catch (IllegalStateException e) {
assertThat(e).hasMessage("Rule 'squid:S0001' is already activated");

Loading…
Cancel
Save