diff options
author | simonbrandhof <simon.brandhof@gmail.com> | 2010-09-13 17:49:40 +0000 |
---|---|---|
committer | simonbrandhof <simon.brandhof@gmail.com> | 2010-09-13 17:49:40 +0000 |
commit | cdd05f32ec75a1594f8f86e1fdb0bd4101598654 (patch) | |
tree | 54391e2d3ead800eb44b40feaa7d7068c80ddc02 | |
parent | ed770f36d376af5ef614f793865eb76713b4ff93 (diff) | |
download | sonarqube-cdd05f32ec75a1594f8f86e1fdb0bd4101598654.tar.gz sonarqube-cdd05f32ec75a1594f8f86e1fdb0bd4101598654.zip |
SONAR-1229 simplify the profiles API
30 files changed, 404 insertions, 415 deletions
diff --git a/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstyleProfileExporter.java b/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstyleProfileExporter.java index d5ea971a55e..b18a198b40a 100644 --- a/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstyleProfileExporter.java +++ b/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstyleProfileExporter.java @@ -146,14 +146,8 @@ public class CheckstyleProfileExporter extends ProfileExporter { private void appendRuleParameters(Writer writer, ActiveRule activeRule) throws IOException { for (RuleParam ruleParam : activeRule.getRule().getParams()) { - ActiveRuleParam activeParam = activeRule.getParameter(ruleParam.getKey()); - String value; - if (activeParam == null) { - value = ruleParam.getDefaultValue(); - } else { - value = activeParam.getValue(true); - } - if (value != null) { + String value = activeRule.getParameter(ruleParam.getKey(), true); + if (StringUtils.isNotBlank(value)) { appendModuleProperty(writer, ruleParam.getKey(), value); } } diff --git a/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstyleProfileImporter.java b/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstyleProfileImporter.java index 34c9ebf9301..891f6c7d91d 100644 --- a/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstyleProfileImporter.java +++ b/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/CheckstyleProfileImporter.java @@ -25,8 +25,12 @@ import org.codehaus.staxmate.SMInputFactory; import org.codehaus.staxmate.in.SMHierarchicCursor; import org.codehaus.staxmate.in.SMInputCursor; import org.sonar.api.profiles.ProfileImporter; -import org.sonar.api.profiles.ProfilePrototype; +import org.sonar.api.profiles.RulesProfile; import org.sonar.api.resources.Java; +import org.sonar.api.rules.ActiveRule; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RuleFinder; +import org.sonar.api.rules.RuleQuery; import org.sonar.api.utils.ValidationMessages; import javax.xml.stream.XMLInputFactory; @@ -38,16 +42,18 @@ public class CheckstyleProfileImporter extends ProfileImporter { private static final String CHECKER_MODULE = "Checker"; private static final String TREEWALKER_MODULE = "TreeWalker"; private static final String MODULE_NODE = "module"; + private final RuleFinder ruleFinder; - public CheckstyleProfileImporter() { + public CheckstyleProfileImporter(RuleFinder ruleFinder) { super(CheckstyleConstants.REPOSITORY_KEY, CheckstyleConstants.PLUGIN_NAME); setSupportedLanguages(Java.KEY); + this.ruleFinder = ruleFinder; } @Override - public ProfilePrototype importProfile(Reader reader, ValidationMessages messages) { + public RulesProfile importProfile(Reader reader, ValidationMessages messages) { SMInputFactory inputFactory = initStax(); - ProfilePrototype profile = ProfilePrototype.create(); + RulesProfile profile = RulesProfile.create(); try { SMHierarchicCursor rootC = inputFactory.rootElementCursor(reader); rootC.advance(); // <module name="Checker"> @@ -79,17 +85,23 @@ public class CheckstyleProfileImporter extends ProfileImporter { return inputFactory; } - private void processModule(ProfilePrototype profile, String path, SMInputCursor moduleCursor, ValidationMessages messages) throws XMLStreamException { + private void processModule(RulesProfile profile, String path, SMInputCursor moduleCursor, ValidationMessages messages) throws XMLStreamException { String configKey = moduleCursor.getAttrValue("name"); if (isFilter(configKey)) { messages.addWarningText("Checkstyle filters are not imported: " + configKey); } else if (isIgnored(configKey)) { + // ignore ! } else { - ProfilePrototype.RulePrototype rule = ProfilePrototype.RulePrototype.createByConfigKey(CheckstyleConstants.REPOSITORY_KEY, path + configKey); - processProperties(moduleCursor, messages, rule); - profile.activateRule(rule); + Rule rule = ruleFinder.find(RuleQuery.create().withRepositoryKey(CheckstyleConstants.REPOSITORY_KEY).withConfigKey(path + configKey)); + if (rule == null) { + messages.addWarningText("Checkstyle rule not found: " + path + configKey); + + } else { + ActiveRule activeRule = profile.activateRule(rule, null); + processProperties(moduleCursor, messages, activeRule); + } } } @@ -104,24 +116,24 @@ public class CheckstyleProfileImporter extends ProfileImporter { StringUtils.equals(configKey, "SuppressWithNearbyCommentFilter"); } - private void processProperties(SMInputCursor moduleCursor, ValidationMessages messages, ProfilePrototype.RulePrototype rule) throws XMLStreamException { + private void processProperties(SMInputCursor moduleCursor, ValidationMessages messages, ActiveRule activeRule) throws XMLStreamException { SMInputCursor propertyCursor = moduleCursor.childElementCursor("property"); while (propertyCursor.getNext() != null) { - processProperty(rule, propertyCursor, messages); + processProperty(activeRule, propertyCursor, messages); } } - private void processProperty(ProfilePrototype.RulePrototype rule, SMInputCursor propertyCursor, ValidationMessages messages) throws XMLStreamException { + private void processProperty(ActiveRule activeRule, SMInputCursor propertyCursor, ValidationMessages messages) throws XMLStreamException { String key = propertyCursor.getAttrValue("name"); String value = propertyCursor.getAttrValue("value"); if (StringUtils.equals("id", key)) { - messages.addWarningText("The checkstyle property 'id' is not supported in the rule: " + rule.getConfigKey()); + messages.addWarningText("The property 'id' is not supported in the Checkstyle rule: " + activeRule.getConfigKey()); } else if (StringUtils.equals("severity", key)) { - rule.setPriority(CheckstyleSeverityUtils.fromSeverity(value)); + activeRule.setPriority(CheckstyleSeverityUtils.fromSeverity(value)); } else { - rule.setParameter(key, value); + activeRule.setParameter(key, value); } } } diff --git a/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/SonarWayProfile.java b/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/SonarWayProfile.java index 476ed1d7bd9..a189560a695 100644 --- a/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/SonarWayProfile.java +++ b/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/SonarWayProfile.java @@ -22,10 +22,11 @@ package org.sonar.plugins.checkstyle; import org.sonar.api.profiles.RulesProfile; import org.sonar.api.profiles.XMLProfileDefinition; import org.sonar.api.resources.Java; +import org.sonar.api.rules.RuleFinder; public final class SonarWayProfile extends XMLProfileDefinition { - public SonarWayProfile() { - super(RulesProfile.SONAR_WAY_NAME, Java.KEY, SunConventionsProfile.class.getClassLoader(), "org/sonar/plugins/checkstyle/profile-sonar-way.xml"); + public SonarWayProfile(RuleFinder ruleFinder) { + super(SunConventionsProfile.class.getClassLoader(), "org/sonar/plugins/checkstyle/profile-sonar-way.xml", ruleFinder); } } diff --git a/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/SonarWayWithFindbugsProfile.java b/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/SonarWayWithFindbugsProfile.java index bfa5b2a2213..398f137c451 100644 --- a/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/SonarWayWithFindbugsProfile.java +++ b/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/SonarWayWithFindbugsProfile.java @@ -19,14 +19,27 @@ */ package org.sonar.plugins.checkstyle; +import org.sonar.api.profiles.ProfileDefinition; import org.sonar.api.profiles.RulesProfile; import org.sonar.api.profiles.XMLProfileDefinition; import org.sonar.api.resources.Java; +import org.sonar.api.rules.RuleFinder; +import org.sonar.api.utils.ValidationMessages; -public class SonarWayWithFindbugsProfile extends XMLProfileDefinition { +public class SonarWayWithFindbugsProfile extends ProfileDefinition { - public SonarWayWithFindbugsProfile() { - super(RulesProfile.SONAR_WAY_FINDBUGS_NAME, Java.KEY, SonarWayWithFindbugsProfile.class.getClassLoader(), "org/sonar/plugins/checkstyle/profile-sonar-way.xml"); + private SonarWayProfile sonarWay; + + public SonarWayWithFindbugsProfile(SonarWayProfile sonarWay) { + this.sonarWay = sonarWay; + } + + + @Override + public RulesProfile createProfile(ValidationMessages validationMessages) { + RulesProfile profile = sonarWay.createProfile(validationMessages); + profile.setName(RulesProfile.SONAR_WAY_FINDBUGS_NAME); + return profile; } } diff --git a/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/SunConventionsProfile.java b/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/SunConventionsProfile.java index fce303d924d..6351afed31c 100644 --- a/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/SunConventionsProfile.java +++ b/plugins/sonar-checkstyle-plugin/src/main/java/org/sonar/plugins/checkstyle/SunConventionsProfile.java @@ -22,10 +22,11 @@ package org.sonar.plugins.checkstyle; import org.sonar.api.profiles.RulesProfile; import org.sonar.api.profiles.XMLProfileDefinition; import org.sonar.api.resources.Java; +import org.sonar.api.rules.RuleFinder; public final class SunConventionsProfile extends XMLProfileDefinition { - public SunConventionsProfile() { - super(RulesProfile.SUN_CONVENTIONS_NAME, Java.KEY, SunConventionsProfile.class.getClassLoader(), "org/sonar/plugins/checkstyle/profile-sun-conventions.xml"); + public SunConventionsProfile(RuleFinder ruleFinder) { + super(SunConventionsProfile.class.getClassLoader(), "org/sonar/plugins/checkstyle/profile-sun-conventions.xml", ruleFinder); } } diff --git a/plugins/sonar-checkstyle-plugin/src/main/resources/org/sonar/plugins/checkstyle/profile-sonar-way.xml b/plugins/sonar-checkstyle-plugin/src/main/resources/org/sonar/plugins/checkstyle/profile-sonar-way.xml index 429d236fcde..0f7bc465582 100644 --- a/plugins/sonar-checkstyle-plugin/src/main/resources/org/sonar/plugins/checkstyle/profile-sonar-way.xml +++ b/plugins/sonar-checkstyle-plugin/src/main/resources/org/sonar/plugins/checkstyle/profile-sonar-way.xml @@ -1,4 +1,6 @@ <profile>
+ <name>Sonar way</name>
+ <language>java</language>
<rules>
<rule>
<repositoryKey>checkstyle</repositoryKey>
diff --git a/plugins/sonar-checkstyle-plugin/src/main/resources/org/sonar/plugins/checkstyle/profile-sun-conventions.xml b/plugins/sonar-checkstyle-plugin/src/main/resources/org/sonar/plugins/checkstyle/profile-sun-conventions.xml index d6fe70f3ff5..9ec3209ab48 100644 --- a/plugins/sonar-checkstyle-plugin/src/main/resources/org/sonar/plugins/checkstyle/profile-sun-conventions.xml +++ b/plugins/sonar-checkstyle-plugin/src/main/resources/org/sonar/plugins/checkstyle/profile-sun-conventions.xml @@ -1,4 +1,6 @@ <profile>
+ <name>Sun checks</name>
+ <language>java</language>
<rules>
<rule>
<repositoryKey>checkstyle</repositoryKey>
diff --git a/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/CheckstyleProfileImporterTest.java b/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/CheckstyleProfileImporterTest.java index 1e53bba97ab..8ad1a8c6b54 100644 --- a/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/CheckstyleProfileImporterTest.java +++ b/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/CheckstyleProfileImporterTest.java @@ -21,8 +21,10 @@ package org.sonar.plugins.checkstyle; import org.junit.Before; import org.junit.Test; -import org.sonar.api.profiles.ProfilePrototype; -import org.sonar.api.rules.RulePriority; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.sonar.api.profiles.RulesProfile; +import org.sonar.api.rules.*; import org.sonar.api.utils.ValidationMessages; import org.sonar.test.TestUtils; @@ -34,6 +36,10 @@ import static org.hamcrest.core.IsNull.nullValue; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.anyObject; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class CheckstyleProfileImporterTest { @@ -43,27 +49,36 @@ public class CheckstyleProfileImporterTest { @Before public void before() { messages = ValidationMessages.create(); - importer = new CheckstyleProfileImporter(); + + /* + + The mocked rule finder defines 2 rules : + + - JavadocCheck with 2 paramters format and ignore, default priority is MAJOR + - EqualsHashCodeCheck without parameters, default priority is BLOCKER + + */ + importer = new CheckstyleProfileImporter(newRuleFinder()); } @Test public void importSimpleProfile() { Reader reader = new StringReader(TestUtils.getResourceContent("/org/sonar/plugins/checkstyle/CheckstyleProfileImporterTest/simple.xml")); - ProfilePrototype profile = importer.importProfile(reader, messages); + RulesProfile profile = importer.importProfile(reader, messages); - assertThat(profile.getRules().size(), is(2)); - assertNotNull(profile.getRuleByConfigKey("checkstyle", "Checker/TreeWalker/EqualsHashCode")); - assertNotNull(profile.getRuleByConfigKey("checkstyle", "Checker/JavadocPackage")); + assertThat(profile.getActiveRules().size(), is(2)); + assertNotNull(profile.getActiveRuleByConfigKey("checkstyle", "Checker/TreeWalker/EqualsHashCode")); + assertNotNull(profile.getActiveRuleByConfigKey("checkstyle", "Checker/JavadocPackage")); assertThat(messages.hasErrors(), is(false)); } @Test public void importParameters() { Reader reader = new StringReader(TestUtils.getResourceContent("/org/sonar/plugins/checkstyle/CheckstyleProfileImporterTest/simple.xml")); - ProfilePrototype profile = importer.importProfile(reader, messages); + RulesProfile profile = importer.importProfile(reader, messages); - ProfilePrototype.RulePrototype javadocCheck = profile.getRuleByConfigKey("checkstyle", "Checker/JavadocPackage"); - assertThat(javadocCheck.getParameters().size(), is(2)); + ActiveRule javadocCheck = profile.getActiveRuleByConfigKey("checkstyle", "Checker/JavadocPackage"); + assertThat(javadocCheck.getActiveRuleParams().size(), is(2)); assertThat(javadocCheck.getParameter("format"), is("abcde")); assertThat(javadocCheck.getParameter("ignore"), is("true")); assertThat(javadocCheck.getParameter("severity"), nullValue()); // checkstyle internal parameter @@ -72,27 +87,27 @@ public class CheckstyleProfileImporterTest { @Test public void importPriorities() { Reader reader = new StringReader(TestUtils.getResourceContent("/org/sonar/plugins/checkstyle/CheckstyleProfileImporterTest/simple.xml")); - ProfilePrototype profile = importer.importProfile(reader, messages); + RulesProfile profile = importer.importProfile(reader, messages); - ProfilePrototype.RulePrototype javadocCheck = profile.getRuleByConfigKey("checkstyle", "Checker/JavadocPackage"); + ActiveRule javadocCheck = profile.getActiveRuleByConfigKey("checkstyle", "Checker/JavadocPackage"); assertThat(javadocCheck.getPriority(), is(RulePriority.BLOCKER)); } @Test public void priorityIsOptional() { Reader reader = new StringReader(TestUtils.getResourceContent("/org/sonar/plugins/checkstyle/CheckstyleProfileImporterTest/simple.xml")); - ProfilePrototype profile = importer.importProfile(reader, messages); + RulesProfile profile = importer.importProfile(reader, messages); - ProfilePrototype.RulePrototype check = profile.getRuleByConfigKey("checkstyle", "Checker/TreeWalker/EqualsHashCode"); - assertThat(check.getPriority(), nullValue()); + ActiveRule activeRule= profile.getActiveRuleByConfigKey("checkstyle", "Checker/TreeWalker/EqualsHashCode"); + assertThat(activeRule.getPriority(), is(RulePriority.BLOCKER)); // reuse the rule default priority } @Test public void idPropertyIsNotSupported() { Reader reader = new StringReader(TestUtils.getResourceContent("/org/sonar/plugins/checkstyle/CheckstyleProfileImporterTest/idProperty.xml")); - ProfilePrototype profile = importer.importProfile(reader, messages); + RulesProfile profile = importer.importProfile(reader, messages); - ProfilePrototype.RulePrototype check = profile.getRuleByConfigKey("checkstyle", "Checker/JavadocPackage"); + ActiveRule check = profile.getActiveRuleByConfigKey("checkstyle", "Checker/JavadocPackage"); assertThat(check.getParameter("id"), nullValue()); assertThat(messages.getWarnings().size(), is(1)); } @@ -107,12 +122,36 @@ public class CheckstyleProfileImporterTest { @Test public void importingFiltersIsNotSupported() { Reader reader = new StringReader(TestUtils.getResourceContent("/org/sonar/plugins/checkstyle/CheckstyleProfileImporterTest/importingFiltersIsNotSupported.xml")); - ProfilePrototype profile = importer.importProfile(reader, messages); + RulesProfile profile = importer.importProfile(reader, messages); - assertNull(profile.getRuleByConfigKey("checkstyle", "Checker/SuppressionCommentFilter")); - assertNull(profile.getRuleByConfigKey("checkstyle", "Checker/TreeWalker/FileContentsHolder")); - assertThat(profile.getRules().size(), is(2)); + assertNull(profile.getActiveRuleByConfigKey("checkstyle", "Checker/SuppressionCommentFilter")); + assertNull(profile.getActiveRuleByConfigKey("checkstyle", "Checker/TreeWalker/FileContentsHolder")); + assertThat(profile.getActiveRules().size(), is(2)); assertThat(messages.getWarnings().size(), is(1)); // no warning for FileContentsHolder } + private RuleFinder newRuleFinder() { + RuleFinder ruleFinder = mock(RuleFinder.class); + when(ruleFinder.find((RuleQuery)anyObject())).thenAnswer(new Answer<Rule>() { + public Rule answer(InvocationOnMock iom) throws Throwable { + RuleQuery query = (RuleQuery)iom.getArguments()[0]; + Rule rule = null; + if (query.getConfigKey().equals("Checker/JavadocPackage")) { + rule = Rule.create(query.getRepositoryKey(), "com.puppycrawl.tools.checkstyle.checks.javadoc.JavadocPackageCheck", "Javadoc Package") + .setConfigKey("Checker/JavadocPackage") + .setPriority(RulePriority.MAJOR); + rule.createParameter("format"); + rule.createParameter("ignore"); + + } else if (query.getConfigKey().equals("Checker/TreeWalker/EqualsHashCode")) { + rule = Rule.create(query.getRepositoryKey(), "com.puppycrawl.tools.checkstyle.checks.coding.EqualsHashCodeCheck", "Equals HashCode") + .setConfigKey("Checker/TreeWalker/EqualsHashCode") + .setPriority(RulePriority.BLOCKER); + } + return rule; + } + }); + return ruleFinder; + } + } diff --git a/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayProfileTest.java b/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayProfileTest.java index 697a9c6685c..268f94fe15b 100644 --- a/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayProfileTest.java +++ b/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayProfileTest.java @@ -20,23 +20,39 @@ package org.sonar.plugins.checkstyle; import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import org.sonar.api.profiles.ProfileDefinition; -import org.sonar.api.profiles.ProfilePrototype; +import org.sonar.api.profiles.RulesProfile; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RuleFinder; import org.sonar.api.utils.ValidationMessages; import static org.hamcrest.core.Is.is; import static org.hamcrest.number.OrderingComparisons.greaterThan; import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class SonarWayProfileTest { @Test public void create() { - ProfileDefinition sonarWay = new SonarWayProfile(); + ProfileDefinition sonarWay = new SonarWayProfile(newRuleFinder()); ValidationMessages validation = ValidationMessages.create(); - ProfilePrototype prototype = sonarWay.createPrototype(validation); - assertThat(prototype.getRulesByRepositoryKey(CheckstyleConstants.REPOSITORY_KEY).size(), greaterThan(1)); + RulesProfile profile = sonarWay.createProfile(validation); + assertThat(profile.getActiveRulesByRepository(CheckstyleConstants.REPOSITORY_KEY).size(), greaterThan(1)); assertThat(validation.hasErrors(), is(false)); } + private RuleFinder newRuleFinder() { + RuleFinder ruleFinder = mock(RuleFinder.class); + when(ruleFinder.findByKey(anyString(), anyString())).thenAnswer(new Answer<Rule>(){ + public Rule answer(InvocationOnMock iom) throws Throwable { + return Rule.create((String) iom.getArguments()[0], (String) iom.getArguments()[1], (String) iom.getArguments()[1]); + } + }); + return ruleFinder; + } } diff --git a/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayWithFindbugsProfileTest.java b/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayWithFindbugsProfileTest.java index ae6513bbfa2..6ed6bbca83c 100644 --- a/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayWithFindbugsProfileTest.java +++ b/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SonarWayWithFindbugsProfileTest.java @@ -19,20 +19,40 @@ */ package org.sonar.plugins.checkstyle; -import org.hamcrest.core.Is; import org.junit.Test; -import org.sonar.api.profiles.ProfilePrototype; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.sonar.api.profiles.RulesProfile; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RuleFinder; import org.sonar.api.utils.ValidationMessages; +import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; -import static org.hamcrest.CoreMatchers.is; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class SonarWayWithFindbugsProfileTest { @Test public void sameAsSonarWay() { - ProfilePrototype withFindbugs = new SonarWayWithFindbugsProfile().createPrototype(ValidationMessages.create()); - ProfilePrototype withoutFindbugs = new SonarWayProfile().createPrototype(ValidationMessages.create()); - assertThat(withFindbugs.getRules().size(), is(withoutFindbugs.getRules().size())); + RuleFinder ruleFinder = newRuleFinder(); + SonarWayProfile sonarWay = new SonarWayProfile(ruleFinder); + RulesProfile withoutFindbugs = sonarWay.createProfile(ValidationMessages.create()); + RulesProfile withFindbugs = new SonarWayWithFindbugsProfile(sonarWay).createProfile(ValidationMessages.create()); + assertThat(withFindbugs.getActiveRules().size(), is(withoutFindbugs.getActiveRules().size())); + assertThat(withFindbugs.getName(), is(RulesProfile.SONAR_WAY_FINDBUGS_NAME)); } + + private RuleFinder newRuleFinder() { + RuleFinder ruleFinder = mock(RuleFinder.class); + when(ruleFinder.findByKey(anyString(), anyString())).thenAnswer(new Answer<Rule>() { + public Rule answer(InvocationOnMock iom) throws Throwable { + return Rule.create((String) iom.getArguments()[0], (String) iom.getArguments()[1], (String) iom.getArguments()[1]); + } + }); + return ruleFinder; + } + } diff --git a/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SunConventionsProfileTest.java b/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SunConventionsProfileTest.java index 73eaa38e8e8..ff80d97a02e 100644 --- a/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SunConventionsProfileTest.java +++ b/plugins/sonar-checkstyle-plugin/src/test/java/org/sonar/plugins/checkstyle/SunConventionsProfileTest.java @@ -21,24 +21,38 @@ package org.sonar.plugins.checkstyle; import org.hamcrest.core.Is; import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; import org.sonar.api.profiles.ProfileDefinition; -import org.sonar.api.profiles.ProfilePrototype; +import org.sonar.api.profiles.RulesProfile; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RuleFinder; import org.sonar.api.utils.ValidationMessages; -import static org.hamcrest.Matchers.is; import static org.hamcrest.number.OrderingComparisons.greaterThan; import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class SunConventionsProfileTest { @Test public void create() { - ProfileDefinition sunConventionsProfile = new SunConventionsProfile(); + ProfileDefinition definition = new SunConventionsProfile(newRuleFinder()); ValidationMessages validation = ValidationMessages.create(); - ProfilePrototype prototype = sunConventionsProfile.createPrototype(validation); - assertThat(prototype.getRulesByRepositoryKey(CheckstyleConstants.REPOSITORY_KEY).size(), greaterThan(1)); - assertThat( - prototype.getRule(CheckstyleConstants.REPOSITORY_KEY, "com.puppycrawl.tools.checkstyle.checks.NewlineAtEndOfFileCheck").getParameter("lineSeparator"), - is("system")); + RulesProfile sunProfile = definition.createProfile(validation); + assertThat(sunProfile.getActiveRulesByRepository(CheckstyleConstants.REPOSITORY_KEY).size(), greaterThan(1)); assertThat(validation.hasErrors(), Is.is(false)); } + + private RuleFinder newRuleFinder() { + RuleFinder ruleFinder = mock(RuleFinder.class); + when(ruleFinder.findByKey(anyString(), anyString())).thenAnswer(new Answer<Rule>() { + public Rule answer(InvocationOnMock iom) throws Throwable { + return Rule.create((String) iom.getArguments()[0], (String) iom.getArguments()[1], (String) iom.getArguments()[1]); + } + }); + return ruleFinder; + } + } diff --git a/plugins/sonar-checkstyle-plugin/src/test/resources/org/sonar/plugins/checkstyle/CheckstyleProfileImporterTest/importingFiltersIsNotSupported.xml b/plugins/sonar-checkstyle-plugin/src/test/resources/org/sonar/plugins/checkstyle/CheckstyleProfileImporterTest/importingFiltersIsNotSupported.xml index 806ec61fae0..55a7faa374e 100644 --- a/plugins/sonar-checkstyle-plugin/src/test/resources/org/sonar/plugins/checkstyle/CheckstyleProfileImporterTest/importingFiltersIsNotSupported.xml +++ b/plugins/sonar-checkstyle-plugin/src/test/resources/org/sonar/plugins/checkstyle/CheckstyleProfileImporterTest/importingFiltersIsNotSupported.xml @@ -1,9 +1,9 @@ <?xml version="1.0" encoding="UTF-8"?> <module name="Checker"> <module name="SuppressionCommentFilter"/> - <module name="NewlineAtEndOfFile"/> + <module name="JavadocPackage"/> <module name="TreeWalker"> <module name="FileContentsHolder"/> - <module name="InterfaceIsType"/> + <module name="EqualsHashCode"/> </module> </module>
\ No newline at end of file diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/profiles/AnnotationProfileDefinition.java b/sonar-plugin-api/src/main/java/org/sonar/api/profiles/AnnotationProfileDefinition.java index e18e8e490ba..e55cf7e1246 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/profiles/AnnotationProfileDefinition.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/profiles/AnnotationProfileDefinition.java @@ -19,6 +19,8 @@ */ package org.sonar.api.profiles; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RuleFinder; import org.sonar.api.rules.RulePriority; import org.sonar.api.utils.ValidationMessages; import org.sonar.check.AnnotationIntrospector; @@ -35,34 +37,42 @@ public abstract class AnnotationProfileDefinition extends ProfileDefinition { private String language; private String repositoryKey; private Collection<Class> annotatedClasses; + private RuleFinder ruleFinder; - protected AnnotationProfileDefinition(String repositoryKey, String profileName, String language, Collection<Class> annotatedClasses) { + protected AnnotationProfileDefinition(String repositoryKey, String profileName, String language, Collection<Class> annotatedClasses, RuleFinder ruleFinder) { this.name = profileName; this.language = language; this.repositoryKey = repositoryKey; this.annotatedClasses = annotatedClasses; + this.ruleFinder = ruleFinder; } @Override - public ProfilePrototype createPrototype(ValidationMessages validation) { - ProfilePrototype profile = ProfilePrototype.create(name, language); + public RulesProfile createProfile(ValidationMessages validation) { + RulesProfile profile = RulesProfile.create(name, language); if (annotatedClasses != null) { for (Class aClass : annotatedClasses) { BelongsToProfile belongsToProfile = (BelongsToProfile) aClass.getAnnotation(BelongsToProfile.class); - registerRule(aClass, belongsToProfile, profile); + registerRule(aClass, belongsToProfile, profile, validation); } } - return profile; } - private void registerRule(Class aClass, BelongsToProfile belongsToProfile, ProfilePrototype profile) { + private void registerRule(Class aClass, BelongsToProfile belongsToProfile, RulesProfile profile, ValidationMessages validation) { if (belongsToProfile != null) { - RulePriority priority = null; - if (belongsToProfile.priority() != null) { - priority = RulePriority.fromCheckPriority(belongsToProfile.priority()); + String ruleKey = AnnotationIntrospector.getCheckKey(aClass); + Rule rule = ruleFinder.findByKey(repositoryKey, ruleKey); + if (rule == null) { + validation.addErrorText("Rule not found: [repository=" + repositoryKey + ", key=" + ruleKey + "]"); + + } else { + RulePriority priority = null; + if (belongsToProfile.priority() != null) { + priority = RulePriority.fromCheckPriority(belongsToProfile.priority()); + } + profile.activateRule(rule, priority); } - profile.activateRule(repositoryKey, AnnotationIntrospector.getCheckKey(aClass), priority); } } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/profiles/ProfileDefinition.java b/sonar-plugin-api/src/main/java/org/sonar/api/profiles/ProfileDefinition.java index 4f14c50da4a..e37343a9abf 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/profiles/ProfileDefinition.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/profiles/ProfileDefinition.java @@ -27,6 +27,6 @@ import org.sonar.api.utils.ValidationMessages; */ public abstract class ProfileDefinition implements ServerExtension { - public abstract ProfilePrototype createPrototype(ValidationMessages validation); + public abstract RulesProfile createProfile(ValidationMessages validation); }
\ No newline at end of file diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/profiles/ProfileImporter.java b/sonar-plugin-api/src/main/java/org/sonar/api/profiles/ProfileImporter.java index 8cceb8be6ed..8bf0cc62e66 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/profiles/ProfileImporter.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/profiles/ProfileImporter.java @@ -19,6 +19,8 @@ */ package org.sonar.api.profiles; +import org.apache.commons.lang.builder.ToStringBuilder; +import org.apache.commons.lang.builder.ToStringStyle; import org.sonar.api.ServerExtension; import org.sonar.api.utils.ValidationMessages; @@ -30,31 +32,31 @@ import java.io.Reader; public abstract class ProfileImporter implements ServerExtension { private String[] supportedLanguages = new String[0]; - private String key; - private String name; + private String importerKey; + private String importerName; protected ProfileImporter(String key, String name) { - this.key = key; - this.name = name; + this.importerKey = key; + this.importerName = name; } - public abstract ProfilePrototype importProfile(Reader reader, ValidationMessages messages); + public abstract RulesProfile importProfile(Reader reader, ValidationMessages messages); public final String getKey() { - return key; + return importerKey; } public final ProfileImporter setKey(String s) { - this.key = s; + this.importerKey = s; return this; } public final String getName() { - return name; + return importerName; } public final ProfileImporter setName(String s) { - this.name = s; + this.importerName = s; return this; } @@ -79,7 +81,7 @@ public abstract class ProfileImporter implements ServerExtension { return false; } ProfileImporter that = (ProfileImporter) o; - if (key != null ? !key.equals(that.key) : that.key != null) { + if (importerKey != null ? !importerKey.equals(that.importerKey) : that.importerKey != null) { return false; } return true; @@ -87,6 +89,15 @@ public abstract class ProfileImporter implements ServerExtension { @Override public final int hashCode() { - return key != null ? key.hashCode() : 0; + return importerKey != null ? importerKey.hashCode() : 0; + } + + @Override + public String toString() { + return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) + .append("key", importerKey) + .append("name", importerName) + .append("languages", supportedLanguages) + .toString(); } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/profiles/ProfilePrototype.java b/sonar-plugin-api/src/main/java/org/sonar/api/profiles/ProfilePrototype.java deleted file mode 100644 index cab5516bebe..00000000000 --- a/sonar-plugin-api/src/main/java/org/sonar/api/profiles/ProfilePrototype.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2009 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.api.profiles; - -import org.apache.commons.lang.StringUtils; -import org.apache.commons.lang.builder.ToStringBuilder; -import org.apache.commons.lang.builder.ToStringStyle; -import org.sonar.api.BatchComponent; -import org.sonar.api.rules.RulePriority; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -/** - * @since 2.3 - */ -public final class ProfilePrototype implements BatchComponent { - - private String name; - private String language; - private List<RulePrototype> rules = new ArrayList<RulePrototype>(); - - private ProfilePrototype() { - } - - public static ProfilePrototype create() { - return new ProfilePrototype(); - } - - public static ProfilePrototype create(String name, String language) { - return new ProfilePrototype().setName(name).setLanguage(language); - } - - public final String getName() { - return name; - } - - public final ProfilePrototype setName(String s) { - this.name = s; - return this; - } - - public final String getLanguage() { - return language; - } - - public final ProfilePrototype setLanguage(String s) { - this.language = s; - return this; - } - - public List<RulePrototype> getRules() { - return rules; - } - - public List<RulePrototype> getRulesByRepositoryKey(String repositoryKey) { - List<RulePrototype> result = new ArrayList<RulePrototype>(); - for (RulePrototype rule : rules) { - if (StringUtils.equals(repositoryKey, rule.getRepositoryKey())) { - result.add(rule); - } - } - return result; - } - - public RulePrototype getRule(String repositoryKey, String key) { - for (RulePrototype rule : rules) { - if (StringUtils.equals(repositoryKey, rule.getRepositoryKey()) && - StringUtils.equals(key, rule.getKey())) { - return rule; - } - } - return null; - } - - public RulePrototype getRuleByConfigKey(String repositoryKey, String configKey) { - for (RulePrototype rule : rules) { - if (StringUtils.equals(repositoryKey, rule.getRepositoryKey()) && - StringUtils.equals(configKey, rule.getConfigKey())) { - return rule; - } - } - return null; - } - - /** - * @param repositoryKey - * @param key - * @param nullablePriority if null, then the default rule priority is used. - * @return the created rule - */ - public RulePrototype activateRule(String repositoryKey, String key, RulePriority nullablePriority) { - RulePrototype rule = RulePrototype.create(repositoryKey, key); - rule.setPriority(nullablePriority); - rules.add(rule); - return rule; - } - - public RulePrototype activateRule(RulePrototype rule) { - rules.add(rule); - return rule; - } - - @Override - public String toString() { - return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE) - .append("name", name) - .append("language", language) - .toString(); - } - - public static final class RulePrototype { - private String repositoryKey; - - private String key; - - private String configKey; - - private RulePriority priority = null; - - private Map<String, String> parameters = new HashMap<String, String>(); - - private RulePrototype() { - } - - public static RulePrototype create() { - return new RulePrototype(); - } - - public static RulePrototype create(String repositoryKey, String key) { - return new RulePrototype().setRepositoryKey(repositoryKey).setKey(key); - } - - public static RulePrototype createByConfigKey(String repositoryKey, String configKey) { - return new RulePrototype().setRepositoryKey(repositoryKey).setConfigKey(configKey); - } - - public String getRepositoryKey() { - return repositoryKey; - } - - public RulePrototype setRepositoryKey(String s) { - this.repositoryKey = s; - return this; - } - - public String getKey() { - return key; - } - - public RulePrototype setKey(String s) { - this.key = s; - return this; - } - - public String getConfigKey() { - return configKey; - } - - public RulePrototype setConfigKey(String s) { - this.configKey = s; - return this; - } - - public RulePriority getPriority() { - return priority; - } - - public RulePrototype setPriority(RulePriority p) { - this.priority = p; - return this; - } - - public RulePrototype setParameter(String key, String value) { - parameters.put(key, value); - return this; - } - - public Map<String, String> getParameters() { - return parameters; - } - - public String getParameter(String key) { - return parameters.get(key); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder().append("[repository=").append(repositoryKey); - if (StringUtils.isNotBlank(key)) { - sb.append(",key=").append(key); - } - if (StringUtils.isNotBlank(configKey)) { - sb.append(",configKey=").append(configKey); - } - return sb.append("]").toString(); - } - } -} diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileDefinition.java b/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileDefinition.java index 759cbd7574c..9cbbe4eaa1b 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileDefinition.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileDefinition.java @@ -21,6 +21,7 @@ package org.sonar.api.profiles; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.CharEncoding; +import org.sonar.api.rules.RuleFinder; import org.sonar.api.utils.SonarException; import org.sonar.api.utils.ValidationMessages; @@ -34,26 +35,21 @@ import java.util.List; */ public abstract class XMLProfileDefinition extends ProfileDefinition { - private String name; - private String language; + private RuleFinder ruleFinder; private ClassLoader classloader; private String xmlClassPath; - protected XMLProfileDefinition(String name, String language, ClassLoader classloader, String xmlClassPath) { - this.name = name; - this.language = language; + protected XMLProfileDefinition(ClassLoader classloader, String xmlClassPath, RuleFinder ruleFinder) { + this.ruleFinder = ruleFinder; this.classloader = classloader; this.xmlClassPath = xmlClassPath; } @Override - public final ProfilePrototype createPrototype(ValidationMessages validation) { + public final RulesProfile createProfile(ValidationMessages validation) { Reader reader = new InputStreamReader(classloader.getResourceAsStream(xmlClassPath), Charset.forName(CharEncoding.UTF_8)); try { - ProfilePrototype profile = XMLProfileImporter.create().importProfile(reader, validation); - profile.setName(name); - profile.setLanguage(language); - return profile; + return XMLProfileImporter.create(ruleFinder).importProfile(reader, validation); } finally { IOUtils.closeQuietly(reader); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileExporter.java b/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileExporter.java index a045499060c..ee78f365cbe 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileExporter.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileExporter.java @@ -39,7 +39,7 @@ public final class XMLProfileExporter { public void exportProfile(RulesProfile profile, Writer writer) { try { - appendHeader(writer); + appendHeader(profile, writer); appendRules(profile, writer); appendFooter(writer); @@ -48,6 +48,16 @@ public final class XMLProfileExporter { } } + private void appendHeader(RulesProfile profile, Writer writer) throws IOException { + writer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + + "<!-- Generated by Sonar -->" + + "<profile><name>"); + StringEscapeUtils.escapeXml(writer, profile.getName()); + writer.append("</name><language>"); + StringEscapeUtils.escapeXml(writer, profile.getLanguage()); + writer.append("</language>"); + } + private void appendRules(RulesProfile profile, Writer writer) throws IOException { if (!profile.getActiveRules().isEmpty()) { writer.append("<rules>"); @@ -58,12 +68,6 @@ public final class XMLProfileExporter { } } - private void appendHeader(Writer writer) throws IOException { - writer.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>" - + "<!-- Generated by Sonar -->" - + "<profile>"); - } - private void appendRule(ActiveRule activeRule, Writer writer) throws IOException { writer.append("<rule><repositoryKey>"); writer.append(activeRule.getRepositoryKey()); diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileImporter.java b/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileImporter.java index b6aaf58050f..a15be26864c 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileImporter.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/profiles/XMLProfileImporter.java @@ -24,28 +24,35 @@ import org.codehaus.stax2.XMLInputFactory2; import org.codehaus.staxmate.SMInputFactory; import org.codehaus.staxmate.in.SMHierarchicCursor; import org.codehaus.staxmate.in.SMInputCursor; +import org.sonar.api.rules.ActiveRule; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RuleFinder; import org.sonar.api.rules.RulePriority; import org.sonar.api.utils.ValidationMessages; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import java.io.Reader; +import java.util.HashMap; +import java.util.Map; /** * @since 2.3 */ public final class XMLProfileImporter { - private XMLProfileImporter() { - // support all repositories + private RuleFinder ruleFinder; + + private XMLProfileImporter(RuleFinder ruleFinder) { + this.ruleFinder = ruleFinder; } - public static XMLProfileImporter create() { - return new XMLProfileImporter(); + public static XMLProfileImporter create(RuleFinder ruleFinder) { + return new XMLProfileImporter(ruleFinder); } - public ProfilePrototype importProfile(Reader reader, ValidationMessages messages) { - ProfilePrototype profile = ProfilePrototype.create(); + public RulesProfile importProfile(Reader reader, ValidationMessages messages) { + RulesProfile profile = RulesProfile.create(); SMInputFactory inputFactory = initStax(); try { SMHierarchicCursor rootC = inputFactory.rootElementCursor(reader); @@ -55,7 +62,13 @@ public final class XMLProfileImporter { String nodeName = cursor.getLocalName(); if (StringUtils.equals("rules", nodeName)) { SMInputCursor rulesCursor = cursor.childElementCursor("rule"); - processRules(rulesCursor, profile); + processRules(rulesCursor, profile, messages); + + } else if (StringUtils.equals("name", nodeName)) { + profile.setName(StringUtils.trim(cursor.collectDescendantText(false))); + + } else if (StringUtils.equals("language", nodeName)) { + profile.setLanguage(StringUtils.trim(cursor.collectDescendantText(false))); } } } catch (XMLStreamException e) { @@ -75,33 +88,51 @@ public final class XMLProfileImporter { return inputFactory; } - private void processRules(SMInputCursor rulesCursor, ProfilePrototype profile) throws XMLStreamException { + private void processRules(SMInputCursor rulesCursor, RulesProfile profile, ValidationMessages messages) throws XMLStreamException { + Map<String, String> parameters = new HashMap<String, String>(); while (rulesCursor.getNext() != null) { SMInputCursor ruleCursor = rulesCursor.childElementCursor(); - ProfilePrototype.RulePrototype rule = ProfilePrototype.RulePrototype.create(); - profile.activateRule(rule); + + String repositoryKey = null, key = null; + RulePriority priority = null; + parameters.clear(); while (ruleCursor.getNext() != null) { String nodeName = ruleCursor.getLocalName(); if (StringUtils.equals("repositoryKey", nodeName)) { - rule.setRepositoryKey(StringUtils.trim(ruleCursor.collectDescendantText(false))); + repositoryKey = StringUtils.trim(ruleCursor.collectDescendantText(false)); } else if (StringUtils.equals("key", nodeName)) { - rule.setKey(StringUtils.trim(ruleCursor.collectDescendantText(false))); + key = StringUtils.trim(ruleCursor.collectDescendantText(false)); } else if (StringUtils.equals("priority", nodeName)) { - rule.setPriority(RulePriority.valueOf(StringUtils.trim(ruleCursor.collectDescendantText(false)))); + priority = RulePriority.valueOf(StringUtils.trim(ruleCursor.collectDescendantText(false))); } else if (StringUtils.equals("parameters", nodeName)) { SMInputCursor propsCursor = ruleCursor.childElementCursor("parameter"); - processParameters(propsCursor, rule); + processParameters(propsCursor, parameters); + } + } + + Rule rule = ruleFinder.findByKey(repositoryKey, key); + if (rule == null) { + messages.addWarningText("Rule not found: [repository=" + repositoryKey + ", key=" + key + "]"); + + } else { + ActiveRule activeRule = profile.activateRule(rule, priority); + for (Map.Entry<String, String> entry : parameters.entrySet()) { + if (rule.getParam(entry.getKey()) == null) { + messages.addWarningText("The parameter '" + entry.getKey() + "' does not exist in the rule: [repository=" + repositoryKey + ", key=" + key + "]"); + } else { + activeRule.setParameter(entry.getKey(), entry.getValue()); + } } } } } - private void processParameters(SMInputCursor propsCursor, ProfilePrototype.RulePrototype rule) throws XMLStreamException { + private void processParameters(SMInputCursor propsCursor, Map<String, String> parameters) throws XMLStreamException { while (propsCursor.getNext() != null) { SMInputCursor propCursor = propsCursor.childElementCursor(); String key = null; @@ -116,7 +147,7 @@ public final class XMLProfileImporter { } } if (key != null) { - rule.setParameter(key, value); + parameters.put(key, value); } } } diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/rules/ActiveRule.java b/sonar-plugin-api/src/main/java/org/sonar/api/rules/ActiveRule.java index b76cd5e4220..8a44db85690 100644 --- a/sonar-plugin-api/src/main/java/org/sonar/api/rules/ActiveRule.java +++ b/sonar-plugin-api/src/main/java/org/sonar/api/rules/ActiveRule.java @@ -142,14 +142,24 @@ public class ActiveRule implements Cloneable { return this; } - public ActiveRuleParam getParameter(String key) { + public String getParameter(String key) { + return getParameter(key, false); + } + + public String getParameter(String key, boolean useDefaultValueIfNeeded) { if (activeRuleParams != null) { for (ActiveRuleParam param : activeRuleParams) { if (StringUtils.equals(key, param.getKey())) { - return param; + return param.getValue(useDefaultValueIfNeeded); } } } + if (useDefaultValueIfNeeded && rule.getParams()!=null) { + RuleParam param = rule.getParam(key); + if (param != null) { + return param.getDefaultValue(); + } + } return null; } diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/profiles/AnnotationProfileDefinitionTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/profiles/AnnotationProfileDefinitionTest.java index 98442f40957..45e6bee0be0 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/profiles/AnnotationProfileDefinitionTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/profiles/AnnotationProfileDefinitionTest.java @@ -20,6 +20,10 @@ package org.sonar.api.profiles; import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RuleFinder; import org.sonar.api.rules.RulePriority; import org.sonar.api.utils.ValidationMessages; import org.sonar.check.BelongsToProfile; @@ -32,15 +36,25 @@ import java.util.Collection; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class AnnotationProfileDefinitionTest { @Test public void importProfile() { - ProfileDefinition definition = new FakeDefinition(); + RuleFinder ruleFinder = mock(RuleFinder.class); + when(ruleFinder.findByKey(anyString(), anyString())).thenAnswer(new Answer<Rule>(){ + public Rule answer(InvocationOnMock iom) throws Throwable { + return Rule.create((String)iom.getArguments()[0], (String)iom.getArguments()[1], (String)iom.getArguments()[1]); + } + }); + + ProfileDefinition definition = new FakeDefinition(ruleFinder); ValidationMessages validation = ValidationMessages.create(); - ProfilePrototype profile = definition.createPrototype(validation); - assertThat(profile.getRule("squid", "fake").getPriority(), is(RulePriority.BLOCKER)); + RulesProfile profile = definition.createProfile(validation); + assertThat(profile.getActiveRule("squid", "fake").getPriority(), is(RulePriority.BLOCKER)); assertThat(validation.hasErrors(), is(false)); } } @@ -54,7 +68,7 @@ class FakeRule { class FakeDefinition extends AnnotationProfileDefinition { - public FakeDefinition() { - super("squid", "sonar way", "java", Arrays.<Class>asList(FakeRule.class)); + public FakeDefinition(RuleFinder ruleFinder) { + super("squid", "sonar way", "java", Arrays.<Class>asList(FakeRule.class), ruleFinder); } }
\ No newline at end of file diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/profiles/ProfileImporterTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/profiles/ProfileImporterTest.java index 13e5eb7ea5c..f13af1eaae2 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/profiles/ProfileImporterTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/profiles/ProfileImporterTest.java @@ -30,10 +30,10 @@ import static org.junit.Assert.assertThat; public class ProfileImporterTest { @Test - public void testSupportedRepositories() { + public void testSupportedLanguages() { ProfileImporter inmporter = new ProfileImporter("all", "All") { @Override - public ProfilePrototype importProfile(Reader reader, ValidationMessages messages) { + public RulesProfile importProfile(Reader reader, ValidationMessages messages) { return null; } }; @@ -45,10 +45,10 @@ public class ProfileImporterTest { } @Test - public void supportAllRepositories() { + public void supportAllLanguages() { ProfileImporter importer = new ProfileImporter("all", "All") { @Override - public ProfilePrototype importProfile(Reader reader, ValidationMessages messages) { + public RulesProfile importProfile(Reader reader, ValidationMessages messages) { return null; } }; diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/profiles/ProfilePrototypeTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/profiles/ProfilePrototypeTest.java deleted file mode 100644 index b8f87759d7c..00000000000 --- a/sonar-plugin-api/src/test/java/org/sonar/api/profiles/ProfilePrototypeTest.java +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Sonar, open source software quality management tool. - * Copyright (C) 2009 SonarSource SA - * mailto:contact AT sonarsource DOT com - * - * Sonar 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. - * - * Sonar 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 Sonar; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02 - */ -package org.sonar.api.profiles; - -import org.junit.Test; -import org.sonar.api.rules.RulePriority; - -import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.core.Is.is; -import static org.hamcrest.core.IsNull.nullValue; -import static org.junit.Assert.assertThat; - -public class ProfilePrototypeTest { - - @Test - public void addRuleByKey() { - ProfilePrototype profile = ProfilePrototype.create(); - profile.activateRule("checkstyle", "JavadocCheck", RulePriority.MINOR); - profile.activateRule("checkstyle", "EqualsHashCodeCheck", RulePriority.BLOCKER); - profile.activateRule("findbugs", "DetectNullPointer", RulePriority.BLOCKER); - - assertThat(profile.getRules().size(), is(3)); - assertThat(profile.getRulesByRepositoryKey("checkstyle").size(), is(2)); - assertThat(profile.getRulesByRepositoryKey("pmd").size(), is(0)); - assertThat(profile.getRule("findbugs", "DetectNullPointer"), not(nullValue())); - assertThat(profile.getRule("findbugs", "DetectNullPointer").getPriority(), is(RulePriority.BLOCKER)); - } - - @Test - public void addRuleByConfigKey() { - ProfilePrototype profile = ProfilePrototype.create(); - profile.activateRule(ProfilePrototype.RulePrototype.createByConfigKey("checkstyle", "Checker/TreeWalker/EqualsHashCode")); - - assertThat(profile.getRules().size(), is(1)); - assertThat(profile.getRule("checkstyle", "Checker/TreeWalker/EqualsHashCode"), nullValue()); - assertThat(profile.getRuleByConfigKey("checkstyle", "Checker/TreeWalker/EqualsHashCode"), not(nullValue())); - } -} diff --git a/sonar-plugin-api/src/test/java/org/sonar/api/profiles/XMLProfileImporterTest.java b/sonar-plugin-api/src/test/java/org/sonar/api/profiles/XMLProfileImporterTest.java index 50b9919fef9..3fe4ef39902 100644 --- a/sonar-plugin-api/src/test/java/org/sonar/api/profiles/XMLProfileImporterTest.java +++ b/sonar-plugin-api/src/test/java/org/sonar/api/profiles/XMLProfileImporterTest.java @@ -22,6 +22,11 @@ package org.sonar.api.profiles; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.CharEncoding; import org.junit.Test; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; +import org.sonar.api.rules.ActiveRule; +import org.sonar.api.rules.Rule; +import org.sonar.api.rules.RuleFinder; import org.sonar.api.rules.RulePriority; import org.sonar.api.utils.ValidationMessages; @@ -29,9 +34,13 @@ import java.io.InputStreamReader; import java.io.Reader; import java.io.UnsupportedEncodingException; +import static org.hamcrest.CoreMatchers.nullValue; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class XMLProfileImporterTest { @@ -40,11 +49,14 @@ public class XMLProfileImporterTest { Reader reader = new InputStreamReader(getClass().getResourceAsStream("/org/sonar/api/profiles/XMLProfileImporterTest/importProfile.xml"), CharEncoding.UTF_8); try { ValidationMessages validation = ValidationMessages.create(); - ProfilePrototype profile = XMLProfileImporter.create().importProfile(reader, validation); + RuleFinder ruleFinder = newRuleFinder(); + RulesProfile profile = XMLProfileImporter.create(ruleFinder).importProfile(reader, validation); + assertThat(profile.getLanguage(), is("java")); + assertThat(profile.getName(), is("sonar way")); assertThat(validation.hasErrors(), is(false)); assertNotNull(profile); - assertThat(profile.getRule("checkstyle", "IllegalRegexp").getPriority(), is(RulePriority.CRITICAL)); + assertThat(profile.getActiveRule("checkstyle", "IllegalRegexp").getPriority(), is(RulePriority.CRITICAL)); } finally { IOUtils.closeQuietly(reader); @@ -56,10 +68,12 @@ public class XMLProfileImporterTest { Reader reader = new InputStreamReader(getClass().getResourceAsStream("/org/sonar/api/profiles/XMLProfileImporterTest/importProfileWithRuleParameters.xml"), CharEncoding.UTF_8); try { ValidationMessages validation = ValidationMessages.create(); - ProfilePrototype profile = XMLProfileImporter.create().importProfile(reader, validation); + RuleFinder ruleFinder = newRuleFinder(); + RulesProfile profile = XMLProfileImporter.create(ruleFinder).importProfile(reader, validation); assertThat(validation.hasErrors(), is(false)); - ProfilePrototype.RulePrototype rule = profile.getRule("checkstyle", "IllegalRegexp"); + assertThat(validation.hasWarnings(), is(false)); + ActiveRule rule = profile.getActiveRule("checkstyle", "IllegalRegexp"); assertThat(rule.getParameter("format"), is("foo")); assertThat(rule.getParameter("message"), is("with special characters < > &")); @@ -67,4 +81,34 @@ public class XMLProfileImporterTest { IOUtils.closeQuietly(reader); } } -} + + @Test + public void importProfileWithUnknownRuleParameter() throws UnsupportedEncodingException { + Reader reader = new InputStreamReader(getClass().getResourceAsStream("/org/sonar/api/profiles/XMLProfileImporterTest/importProfileWithUnknownRuleParameter.xml"), CharEncoding.UTF_8); + try { + ValidationMessages validation = ValidationMessages.create(); + RuleFinder ruleFinder = newRuleFinder(); + RulesProfile profile = XMLProfileImporter.create(ruleFinder).importProfile(reader, validation); + + assertThat(validation.getWarnings().size(), is(1)); + ActiveRule rule = profile.getActiveRule("checkstyle", "IllegalRegexp"); + assertThat(rule.getParameter("unknown"), nullValue()); + + } finally { + IOUtils.closeQuietly(reader); + } + } + + private RuleFinder newRuleFinder() { + RuleFinder ruleFinder = mock(RuleFinder.class); + when(ruleFinder.findByKey(anyString(), anyString())).thenAnswer(new Answer<Rule>(){ + public Rule answer(InvocationOnMock iom) throws Throwable { + Rule rule = Rule.create((String) iom.getArguments()[0], (String) iom.getArguments()[1], (String) iom.getArguments()[1]); + rule.createParameter("format"); + rule.createParameter("message"); + return rule; + } + }); + return ruleFinder; + } +}
\ No newline at end of file diff --git a/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileExporterTest/exportEmptyProfile.xml b/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileExporterTest/exportEmptyProfile.xml index 7edbf410ba2..3bdb8fc1c76 100644 --- a/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileExporterTest/exportEmptyProfile.xml +++ b/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileExporterTest/exportEmptyProfile.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- Generated by Sonar --> <profile> - + <name>sonar way</name> + <language>java</language> </profile>
\ No newline at end of file diff --git a/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileExporterTest/exportProfile.xml b/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileExporterTest/exportProfile.xml index 7bf8cc8017d..76779cd4f33 100644 --- a/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileExporterTest/exportProfile.xml +++ b/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileExporterTest/exportProfile.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- Generated by Sonar --> <profile> + <name>sonar way</name> + <language>java</language> <rules> <rule> <repositoryKey>checkstyle</repositoryKey> diff --git a/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileExporterTest/exportRuleParameters.xml b/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileExporterTest/exportRuleParameters.xml index f635edff295..f3e2758b931 100644 --- a/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileExporterTest/exportRuleParameters.xml +++ b/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileExporterTest/exportRuleParameters.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- Generated by Sonar --> <profile> + <name>sonar way</name> + <language>java</language> <rules> <rule> <repositoryKey>checkstyle</repositoryKey> diff --git a/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileImporterTest/importProfile.xml b/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileImporterTest/importProfile.xml index 303494eb8bb..047c4c7a844 100644 --- a/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileImporterTest/importProfile.xml +++ b/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileImporterTest/importProfile.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- Generated by Sonar --> <profile> + <name>sonar way</name> + <language>java</language> <rules> <rule> <repositoryKey>checkstyle</repositoryKey> diff --git a/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileImporterTest/importProfileWithRuleParameters.xml b/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileImporterTest/importProfileWithRuleParameters.xml index f635edff295..f3e2758b931 100644 --- a/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileImporterTest/importProfileWithRuleParameters.xml +++ b/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileImporterTest/importProfileWithRuleParameters.xml @@ -1,6 +1,8 @@ <?xml version="1.0" encoding="UTF-8"?> <!-- Generated by Sonar --> <profile> + <name>sonar way</name> + <language>java</language> <rules> <rule> <repositoryKey>checkstyle</repositoryKey> diff --git a/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileImporterTest/importProfileWithUnknownRuleParameter.xml b/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileImporterTest/importProfileWithUnknownRuleParameter.xml new file mode 100644 index 00000000000..eb4a460fcf1 --- /dev/null +++ b/sonar-plugin-api/src/test/resources/org/sonar/api/profiles/XMLProfileImporterTest/importProfileWithUnknownRuleParameter.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Generated by Sonar --> +<profile> + <name>sonar way</name> + <language>java</language> + <rules> + <rule> + <repositoryKey>checkstyle</repositoryKey> + <key>IllegalRegexp</key> + <priority>BLOCKER</priority> + <parameters> + <parameter> + <key>unknown</key> + <value>foo</value> + </parameter> + </parameters> + </rule> + </rules> +</profile>
\ No newline at end of file |