From 512f959a7c4625e1a2dbf535c3fba7fe529ebdfc Mon Sep 17 00:00:00 2001 From: Jens Gerdes Date: Mon, 11 Feb 2019 13:24:28 +0100 Subject: [PATCH 1/5] Starting to restructure serverside / scannerside components --- pom.xml | 2 +- .../org/sonar/plugins/pmd/PmdExecutor.java | 10 +- .../java/org/sonar/plugins/pmd/PmdSensor.java | 8 +- .../pmd/profile/PmdProfileExporter.java | 124 ++++++------------ .../org/sonar/plugins/pmd/xml/PmdRuleSet.java | 82 ++++++++++++ .../sonar/plugins/pmd/PmdExecutorTest.java | 4 +- .../org/sonar/plugins/pmd/PmdSensorTest.java | 4 +- .../pmd/profile/PmdProfileExporterTest.java | 26 ++-- 8 files changed, 153 insertions(+), 107 deletions(-) diff --git a/pom.xml b/pom.xml index b44ad855..9e1e8913 100644 --- a/pom.xml +++ b/pom.xml @@ -90,7 +90,7 @@ org.sonarsource.sonarqube sonar-plugin-api provided - 7.5 + 7.6 xml-apis diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdExecutor.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdExecutor.java index 4da27673..3f21ce87 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdExecutor.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdExecutor.java @@ -40,8 +40,8 @@ import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.InputFile.Type; +import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.config.Configuration; -import org.sonar.api.profiles.RulesProfile; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Profiler; @@ -54,17 +54,15 @@ public class PmdExecutor { private static final Logger LOGGER = Loggers.get(PmdExecutor.class); private final FileSystem fs; - private final RulesProfile rulesProfile; - private final PmdProfileExporter pmdProfileExporter; + private final ActiveRules rulesProfile; private final PmdConfiguration pmdConfiguration; private final JavaResourceLocator javaResourceLocator; private final Configuration settings; - public PmdExecutor(FileSystem fileSystem, RulesProfile rulesProfile, PmdProfileExporter pmdProfileExporter, + public PmdExecutor(FileSystem fileSystem, ActiveRules rulesProfile, PmdConfiguration pmdConfiguration, JavaResourceLocator javaResourceLocator, Configuration settings) { this.fs = fileSystem; this.rulesProfile = rulesProfile; - this.pmdProfileExporter = pmdProfileExporter; this.pmdConfiguration = pmdConfiguration; this.javaResourceLocator = javaResourceLocator; this.settings = settings; @@ -135,7 +133,7 @@ private void executeRules(PmdTemplate pmdFactory, RuleContext ruleContext, Itera } private RuleSets createRuleSets(String repositoryKey) { - String rulesXml = pmdProfileExporter.exportProfile(repositoryKey, rulesProfile); + String rulesXml = PmdProfileExporter.exportProfileFromScannerSide(repositoryKey, rulesProfile); File ruleSetFile = pmdConfiguration.dumpXmlRuleSet(repositoryKey, rulesXml); String ruleSetFilePath = ruleSetFile.getAbsolutePath(); RuleSetFactory ruleSetFactory = new RuleSetFactory(); diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdSensor.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdSensor.java index b83037f5..4a2727d2 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdSensor.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdSensor.java @@ -23,18 +23,18 @@ import org.sonar.api.batch.fs.FilePredicates; import org.sonar.api.batch.fs.FileSystem; import org.sonar.api.batch.fs.InputFile.Type; +import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.batch.sensor.Sensor; import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.batch.sensor.SensorDescriptor; -import org.sonar.api.profiles.RulesProfile; public class PmdSensor implements Sensor { - private final RulesProfile profile; + private final ActiveRules profile; private final PmdExecutor executor; private final PmdViolationRecorder pmdViolationRecorder; private final FileSystem fs; - public PmdSensor(RulesProfile profile, PmdExecutor executor, PmdViolationRecorder pmdViolationRecorder, FileSystem fs) { + public PmdSensor(ActiveRules profile, PmdExecutor executor, PmdViolationRecorder pmdViolationRecorder, FileSystem fs) { this.profile = profile; this.executor = executor; this.pmdViolationRecorder = pmdViolationRecorder; @@ -51,7 +51,7 @@ private boolean hasFilesToCheck(Type type, String repositoryKey) { final boolean hasMatchingFiles = fs.hasFiles(predicates.and( predicates.hasLanguage(PmdConstants.LANGUAGE_KEY), predicates.hasType(type))); - return hasMatchingFiles && !profile.getActiveRulesByRepository(repositoryKey).isEmpty(); + return hasMatchingFiles && !profile.findByRepository(repositoryKey).isEmpty(); } @Override diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileExporter.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileExporter.java index 55dad409..5621ac49 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileExporter.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileExporter.java @@ -19,34 +19,32 @@ */ package org.sonar.plugins.pmd.profile; -import java.io.IOException; import java.io.StringWriter; import java.io.Writer; import java.util.ArrayList; +import java.util.Collection; import java.util.List; -import javax.annotation.Nullable; +import java.util.Map; +import java.util.Objects; -import org.apache.commons.lang3.StringUtils; -import org.jdom.CDATA; -import org.jdom.Document; -import org.jdom.Element; -import org.jdom.output.Format; -import org.jdom.output.XMLOutputter; -import org.sonar.api.batch.ScannerSide; +import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.profiles.ProfileExporter; import org.sonar.api.profiles.RulesProfile; import org.sonar.api.rules.ActiveRule; import org.sonar.api.rules.ActiveRuleParam; +import org.sonar.api.rules.RulePriority; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; import org.sonar.plugins.pmd.PmdConstants; import org.sonar.plugins.pmd.PmdLevelUtils; import org.sonar.plugins.pmd.xml.PmdProperty; import org.sonar.plugins.pmd.xml.PmdRule; import org.sonar.plugins.pmd.xml.PmdRuleSet; -@ScannerSide public class PmdProfileExporter extends ProfileExporter { private static final String CONTENT_TYPE_APPLICATION_XML = "application/xml"; + private static final Logger LOG = Loggers.get(PmdProfileExporter.class); public PmdProfileExporter() { super(PmdConstants.REPOSITORY_KEY, PmdConstants.PLUGIN_NAME); @@ -64,6 +62,16 @@ private static void addRuleProperties(ActiveRule activeRule, PmdRule pmdRule) { } } + private static void addRuleProperties(org.sonar.api.batch.rule.ActiveRule activeRule, PmdRule pmdRule) { + if ((activeRule.params() != null) && !activeRule.params().isEmpty()) { + List properties = new ArrayList<>(); + for (Map.Entry activeRuleParam : activeRule.params().entrySet()) { + properties.add(new PmdProperty(activeRuleParam.getKey(), activeRuleParam.getValue())); + } + pmdRule.setProperties(properties); + } + } + static void processXPathRule(String sonarRuleKey, PmdRule rule) { if (PmdConstants.XPATH_CLASS.equals(rule.getRef())) { rule.setRef(null); @@ -84,88 +92,40 @@ static void processXPathRule(String sonarRuleKey, PmdRule rule) { } } - private static void exportPmdRulesetToXml(PmdRuleSet pmdRuleset, Writer writer, String profileName) { - Element eltRuleset = new Element("ruleset"); - addAttribute(eltRuleset, "name", pmdRuleset.getName()); - addChild(eltRuleset, "description", pmdRuleset.getDescription()); - for (PmdRule pmdRule : pmdRuleset.getPmdRules()) { - Element eltRule = new Element("rule"); - addAttribute(eltRule, "ref", pmdRule.getRef()); - addAttribute(eltRule, "class", pmdRule.getClazz()); - addAttribute(eltRule, "message", pmdRule.getMessage()); - addAttribute(eltRule, "name", pmdRule.getName()); - addAttribute(eltRule, "language", pmdRule.getLanguage()); - addChild(eltRule, "priority", String.valueOf(pmdRule.getPriority())); - if (pmdRule.hasProperties()) { - Element ruleProperties = processRuleProperties(pmdRule); - if (ruleProperties.getContentSize() > 0) { - eltRule.addContent(ruleProperties); - } - } - eltRuleset.addContent(eltRule); - } - XMLOutputter serializer = new XMLOutputter(Format.getPrettyFormat()); + @Override + public void exportProfile(RulesProfile profile, Writer writer) { + final String profileName = profile.getName(); + final PmdRuleSet tree = createPmdRuleset(PmdConstants.REPOSITORY_KEY, profile.getActiveRulesByRepository(PmdConstants.REPOSITORY_KEY)); + try { - serializer.output(new Document(eltRuleset), writer); - } catch (IOException e) { + tree.writeTo(writer); + } catch (IllegalStateException e) { throw new IllegalStateException("An exception occurred while generating the PMD configuration file from profile: " + profileName, e); } } - private static Element processRuleProperties(PmdRule pmdRule) { - Element eltProperties = new Element("properties"); - for (PmdProperty prop : pmdRule.getProperties()) { - if (isPropertyValueNotEmpty(prop)) { - Element eltProperty = new Element("property"); - eltProperty.setAttribute("name", prop.getName()); - if (prop.isCdataValue()) { - Element eltValue = new Element("value"); - eltValue.addContent(new CDATA(prop.getCdataValue())); - eltProperty.addContent(eltValue); - } else { - eltProperty.setAttribute("value", prop.getValue()); - } - eltProperties.addContent(eltProperty); - } - } - return eltProperties; - } - - private static boolean isPropertyValueNotEmpty(PmdProperty prop) { - if (prop.isCdataValue()) { - return StringUtils.isNotEmpty(prop.getCdataValue()); - } - return StringUtils.isNotEmpty(prop.getValue()); - } - - private static void addChild(Element elt, String name, @Nullable String text) { - if (text != null) { - elt.addContent(new Element(name).setText(text)); - } + public static String exportProfileFromScannerSide(String repositoryKey, ActiveRules profile) { + PmdRuleSet tree = createPmdRulesetB(repositoryKey, profile.findByRepository(repositoryKey)); + StringWriter stringWriter = new StringWriter(); + tree.writeTo(stringWriter); + return stringWriter.toString(); } - private static void addAttribute(Element elt, String name, @Nullable String value) { - if (value != null) { - elt.setAttribute(name, value); + private static PmdRuleSet createPmdRulesetB(String repositoryKey, Collection activeRules) { + PmdRuleSet ruleset = new PmdRuleSet(); + ruleset.setName(repositoryKey); + ruleset.setDescription(String.format("Sonar Profile: %s", repositoryKey)); + for (org.sonar.api.batch.rule.ActiveRule activeRule : activeRules) { + String configKey = activeRule.internalKey(); + PmdRule rule = new PmdRule(configKey, PmdLevelUtils.toLevel(RulePriority.valueOfString(activeRule.severity()))); + addRuleProperties(activeRule, rule); + ruleset.addRule(rule); + processXPathRule(activeRule.internalKey(), rule); } + return ruleset; } - @Override - public void exportProfile(RulesProfile profile, Writer writer) { - String profileName = profile.getName(); - PmdRuleSet tree = createPmdRuleset(PmdConstants.REPOSITORY_KEY, profile.getActiveRulesByRepository(PmdConstants.REPOSITORY_KEY)); - exportPmdRulesetToXml(tree, writer, profileName); - } - - public String exportProfile(String repositoryKey, RulesProfile profile) { - String profileName = profile.getName(); - PmdRuleSet tree = createPmdRuleset(repositoryKey, profile.getActiveRulesByRepository(repositoryKey)); - StringWriter stringWriter = new StringWriter(); - exportPmdRulesetToXml(tree, stringWriter, profileName); - return stringWriter.toString(); - } - - private PmdRuleSet createPmdRuleset(String repositoryKey, List activeRules) { + private static PmdRuleSet createPmdRuleset(String repositoryKey, List activeRules) { PmdRuleSet ruleset = new PmdRuleSet(); ruleset.setName(repositoryKey); ruleset.setDescription(String.format("Sonar Profile: %s", repositoryKey)); diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSet.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSet.java index 1fe6ea74..11554b90 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSet.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSet.java @@ -19,9 +19,20 @@ */ package org.sonar.plugins.pmd.xml; +import java.io.IOException; +import java.io.Writer; import java.util.ArrayList; import java.util.List; +import javax.annotation.Nullable; + +import org.apache.commons.lang3.StringUtils; +import org.jdom.CDATA; +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.output.Format; +import org.jdom.output.XMLOutputter; + public class PmdRuleSet { private String name; @@ -56,4 +67,75 @@ public String getDescription() { public void setDescription(String description) { this.description = description; } + + /** + * Serializes this RuleSet in an XML document. + * + * @param destination The writer to which the XML document shall be written. + */ + public void writeTo(Writer destination) { + Element eltRuleset = new Element("ruleset"); + addAttribute(eltRuleset, "name", name); + addChild(eltRuleset, "description", description); + for (PmdRule pmdRule : rules) { + Element eltRule = new Element("rule"); + addAttribute(eltRule, "ref", pmdRule.getRef()); + addAttribute(eltRule, "class", pmdRule.getClazz()); + addAttribute(eltRule, "message", pmdRule.getMessage()); + addAttribute(eltRule, "name", pmdRule.getName()); + addAttribute(eltRule, "language", pmdRule.getLanguage()); + addChild(eltRule, "priority", String.valueOf(pmdRule.getPriority())); + if (pmdRule.hasProperties()) { + Element ruleProperties = processRuleProperties(pmdRule); + if (ruleProperties.getContentSize() > 0) { + eltRule.addContent(ruleProperties); + } + } + eltRuleset.addContent(eltRule); + } + XMLOutputter serializer = new XMLOutputter(Format.getPrettyFormat()); + try { + serializer.output(new Document(eltRuleset), destination); + } catch (IOException e) { + throw new IllegalStateException("An exception occurred while serializing PmdRuleSet.", e); + } + } + + private void addChild(Element elt, String name, @Nullable String text) { + if (text != null) { + elt.addContent(new Element(name).setText(text)); + } + } + + private void addAttribute(Element elt, String name, @Nullable String value) { + if (value != null) { + elt.setAttribute(name, value); + } + } + + private Element processRuleProperties(PmdRule pmdRule) { + Element eltProperties = new Element("properties"); + for (PmdProperty prop : pmdRule.getProperties()) { + if (isPropertyValueNotEmpty(prop)) { + Element eltProperty = new Element("property"); + eltProperty.setAttribute("name", prop.getName()); + if (prop.isCdataValue()) { + Element eltValue = new Element("value"); + eltValue.addContent(new CDATA(prop.getCdataValue())); + eltProperty.addContent(eltValue); + } else { + eltProperty.setAttribute("value", prop.getValue()); + } + eltProperties.addContent(eltProperty); + } + } + return eltProperties; + } + + private boolean isPropertyValueNotEmpty(PmdProperty prop) { + if (prop.isCdataValue()) { + return StringUtils.isNotEmpty(prop.getCdataValue()); + } + return StringUtils.isNotEmpty(prop.getValue()); + } } diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdExecutorTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdExecutorTest.java index 0bfbace2..be3ef84e 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdExecutorTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdExecutorTest.java @@ -58,7 +58,7 @@ import static org.mockito.Mockito.when; class PmdExecutorTest { - +/* private final DefaultFileSystem fileSystem = new DefaultFileSystem(new File(".")); private final RulesProfile rulesProfile = RulesProfile.create("pmd", "pmd"); private final PmdProfileExporter pmdProfileExporter = mock(PmdProfileExporter.class); @@ -195,5 +195,5 @@ private void setupPmdRuleSet(String repositoryKey, String profileFileName) throw String profileContent = new String(Files.readAllBytes(sourcePath)); when(pmdProfileExporter.exportProfile(repositoryKey, rulesProfile)).thenReturn(profileContent); when(pmdConfiguration.dumpXmlRuleSet(repositoryKey, profileContent)).thenReturn(sourcePath.toFile()); - } + }*/ } diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdSensorTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdSensorTest.java index 34cc3294..a193c2ed 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdSensorTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdSensorTest.java @@ -48,7 +48,7 @@ import static org.mockito.Mockito.when; class PmdSensorTest { - +/* private final RulesProfile profile = mock(RulesProfile.class, RETURNS_DEEP_STUBS); private final PmdExecutor executor = mock(PmdExecutor.class); private final PmdViolationRecorder pmdViolationRecorder = mock(PmdViolationRecorder.class); @@ -239,5 +239,5 @@ private void addOneJavaFile(Type type) { .setType(type) .build() ); - } + }*/ } diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/profile/PmdProfileExporterTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/profile/PmdProfileExporterTest.java index 198b0bd0..6228e0b5 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/profile/PmdProfileExporterTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/profile/PmdProfileExporterTest.java @@ -140,16 +140,16 @@ void should_export_pmd_profile_on_writer_exception() throws IOException { .hasMessage("An exception occurred while generating the PMD configuration file from profile: null"); } - @Test + /* @Test void should_export_pmd_profile() { String importedXml = PmdTestUtils.getResourceContent("/org/sonar/plugins/pmd/export_simple.xml"); String exportedXml = exporter.exportProfile(PmdConstants.REPOSITORY_KEY, importProfile(importedXml)); assertThat(exportedXml).satisfies(equalsIgnoreEOL(importedXml)); - } + }*/ - @Test + /* @Test void should_skip_empty_params() { String importedXml = PmdTestUtils.getResourceContent("/org/sonar/plugins/pmd/export_rule_with_empty_param.xml"); @@ -167,7 +167,7 @@ void should_skip_empty_params() { String actual = exporter.exportProfile(PmdConstants.REPOSITORY_KEY, importProfile(importedXml)); assertThat(actual).satisfies(equalsIgnoreEOL(expected)); - } + }*/ @Test void should_skip_all_empty_params() { @@ -181,15 +181,19 @@ void should_skip_all_empty_params() { " \n" + ""; - String actual = exporter.exportProfile(PmdConstants.REPOSITORY_KEY, importProfile(importedXml)); - assertThat(actual).satisfies(equalsIgnoreEOL(expected)); + final StringWriter writer = new StringWriter(); + exporter.exportProfile(importProfile(importedXml), writer); + assertThat(writer.toString()).satisfies(equalsIgnoreEOL(expected)); } @Test void should_export_empty_configuration_as_xml() { - String exportedXml = exporter.exportProfile(PmdConstants.REPOSITORY_KEY, RulesProfile.create()); - assertThat(exportedXml).satisfies(equalsIgnoreEOL("" + + final StringWriter writer = new StringWriter(); + + exporter.exportProfile(RulesProfile.create(), writer); + + assertThat(writer.toString()).satisfies(equalsIgnoreEOL("" + " Sonar Profile: pmd")); } @@ -206,9 +210,11 @@ void should_export_xPath_rule() { xpath.setParameter(PmdConstants.XPATH_EXPRESSION_PARAM, "//FieldDeclaration"); xpath.setParameter(PmdConstants.XPATH_MESSAGE_PARAM, "This is bad"); - String exportedXml = exporter.exportProfile(PmdConstants.REPOSITORY_KEY, profile); + final StringWriter writer = new StringWriter(); + exporter.exportProfile(profile, writer); + - assertThat(exportedXml).satisfies(equalsIgnoreEOL(PmdTestUtils.getResourceContent("/org/sonar/plugins/pmd/export_xpath_rules.xml"))); + assertThat(writer.toString()).satisfies(equalsIgnoreEOL(PmdTestUtils.getResourceContent("/org/sonar/plugins/pmd/export_xpath_rules.xml"))); } @Test From b35d14d0af80fc7892b7a2ac286ca49f19773329 Mon Sep 17 00:00:00 2001 From: Jens Gerdes Date: Mon, 11 Feb 2019 15:54:11 +0100 Subject: [PATCH 2/5] Refactoring serverside / scannerside components --- .../org/sonar/plugins/pmd/PmdExecutor.java | 13 +- .../pmd/profile/PmdProfileExporter.java | 103 +------------ .../pmd/profile/PmdProfileImporter.java | 2 +- .../org/sonar/plugins/pmd/xml/PmdRule.java | 24 +++ .../sonar/plugins/pmd/xml/PmdRuleSets.java | 124 ++++----------- .../factory/ActiveRulesRuleSetFactory.java | 80 ++++++++++ .../pmd/xml/factory/RuleSetFactory.java | 35 +++++ .../factory/RulesProfileRuleSetFactory.java | 82 ++++++++++ .../pmd/xml/factory/XmlRuleSetFactory.java | 142 ++++++++++++++++++ .../plugins/pmd/xml/factory/package-info.java | 21 +++ .../pmd/profile/PmdProfileExporterTest.java | 8 +- .../plugins/pmd/xml/PmdRuleSetsTest.java | 6 +- 12 files changed, 443 insertions(+), 197 deletions(-) create mode 100644 sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/ActiveRulesRuleSetFactory.java create mode 100644 sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/RuleSetFactory.java create mode 100644 sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/RulesProfileRuleSetFactory.java create mode 100644 sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/XmlRuleSetFactory.java create mode 100644 sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/package-info.java diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdExecutor.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdExecutor.java index 3f21ce87..828bae52 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdExecutor.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdExecutor.java @@ -21,6 +21,7 @@ import java.io.File; import java.io.IOException; +import java.io.StringWriter; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; @@ -47,6 +48,8 @@ import org.sonar.api.utils.log.Profiler; import org.sonar.plugins.java.api.JavaResourceLocator; import org.sonar.plugins.pmd.profile.PmdProfileExporter; +import org.sonar.plugins.pmd.xml.PmdRuleSet; +import org.sonar.plugins.pmd.xml.PmdRuleSets; @ScannerSide public class PmdExecutor { @@ -133,7 +136,7 @@ private void executeRules(PmdTemplate pmdFactory, RuleContext ruleContext, Itera } private RuleSets createRuleSets(String repositoryKey) { - String rulesXml = PmdProfileExporter.exportProfileFromScannerSide(repositoryKey, rulesProfile); + String rulesXml = dumpXml(rulesProfile, repositoryKey); File ruleSetFile = pmdConfiguration.dumpXmlRuleSet(repositoryKey, rulesXml); String ruleSetFilePath = ruleSetFile.getAbsolutePath(); RuleSetFactory ruleSetFactory = new RuleSetFactory(); @@ -145,6 +148,14 @@ private RuleSets createRuleSets(String repositoryKey) { } } + private String dumpXml(ActiveRules rulesProfile, String repositoryKey) { + final StringWriter writer = new StringWriter(); + final PmdRuleSet ruleSet = PmdRuleSets.from(rulesProfile, repositoryKey); + ruleSet.writeTo(writer); + + return writer.toString(); + } + PmdTemplate createPmdTemplate(URLClassLoader classLoader) { return PmdTemplate.create(getSourceVersion(), classLoader, fs.encoding()); } diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileExporter.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileExporter.java index 5621ac49..0e60a4c1 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileExporter.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileExporter.java @@ -19,32 +19,20 @@ */ package org.sonar.plugins.pmd.profile; -import java.io.StringWriter; import java.io.Writer; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.profiles.ProfileExporter; import org.sonar.api.profiles.RulesProfile; -import org.sonar.api.rules.ActiveRule; -import org.sonar.api.rules.ActiveRuleParam; -import org.sonar.api.rules.RulePriority; -import org.sonar.api.utils.log.Logger; -import org.sonar.api.utils.log.Loggers; import org.sonar.plugins.pmd.PmdConstants; -import org.sonar.plugins.pmd.PmdLevelUtils; -import org.sonar.plugins.pmd.xml.PmdProperty; -import org.sonar.plugins.pmd.xml.PmdRule; import org.sonar.plugins.pmd.xml.PmdRuleSet; +import org.sonar.plugins.pmd.xml.PmdRuleSets; +/** + * ServerSide component that is able to export all currently active PMD rules as XML. + */ public class PmdProfileExporter extends ProfileExporter { private static final String CONTENT_TYPE_APPLICATION_XML = "application/xml"; - private static final Logger LOG = Loggers.get(PmdProfileExporter.class); public PmdProfileExporter() { super(PmdConstants.REPOSITORY_KEY, PmdConstants.PLUGIN_NAME); @@ -52,92 +40,15 @@ public PmdProfileExporter() { setMimeType(CONTENT_TYPE_APPLICATION_XML); } - private static void addRuleProperties(ActiveRule activeRule, PmdRule pmdRule) { - if ((activeRule.getActiveRuleParams() != null) && !activeRule.getActiveRuleParams().isEmpty()) { - List properties = new ArrayList<>(); - for (ActiveRuleParam activeRuleParam : activeRule.getActiveRuleParams()) { - properties.add(new PmdProperty(activeRuleParam.getRuleParam().getKey(), activeRuleParam.getValue())); - } - pmdRule.setProperties(properties); - } - } - - private static void addRuleProperties(org.sonar.api.batch.rule.ActiveRule activeRule, PmdRule pmdRule) { - if ((activeRule.params() != null) && !activeRule.params().isEmpty()) { - List properties = new ArrayList<>(); - for (Map.Entry activeRuleParam : activeRule.params().entrySet()) { - properties.add(new PmdProperty(activeRuleParam.getKey(), activeRuleParam.getValue())); - } - pmdRule.setProperties(properties); - } - } - - static void processXPathRule(String sonarRuleKey, PmdRule rule) { - if (PmdConstants.XPATH_CLASS.equals(rule.getRef())) { - rule.setRef(null); - PmdProperty xpathMessage = rule.getProperty(PmdConstants.XPATH_MESSAGE_PARAM); - if (xpathMessage == null) { - throw new IllegalArgumentException("Property '" + PmdConstants.XPATH_MESSAGE_PARAM + "' should be set for PMD rule " + sonarRuleKey); - } - rule.setMessage(xpathMessage.getValue()); - rule.removeProperty(PmdConstants.XPATH_MESSAGE_PARAM); - PmdProperty xpathExp = rule.getProperty(PmdConstants.XPATH_EXPRESSION_PARAM); - if (xpathExp == null) { - throw new IllegalArgumentException("Property '" + PmdConstants.XPATH_EXPRESSION_PARAM + "' should be set for PMD rule " + sonarRuleKey); - } - xpathExp.setCdataValue(xpathExp.getValue()); - rule.setClazz(PmdConstants.XPATH_CLASS); - rule.setLanguage(PmdConstants.LANGUAGE_KEY); - rule.setName(sonarRuleKey); - } - } - @Override public void exportProfile(RulesProfile profile, Writer writer) { - final String profileName = profile.getName(); - final PmdRuleSet tree = createPmdRuleset(PmdConstants.REPOSITORY_KEY, profile.getActiveRulesByRepository(PmdConstants.REPOSITORY_KEY)); + + final PmdRuleSet tree = PmdRuleSets.from(profile, PmdConstants.REPOSITORY_KEY); try { tree.writeTo(writer); } catch (IllegalStateException e) { - throw new IllegalStateException("An exception occurred while generating the PMD configuration file from profile: " + profileName, e); - } - } - - public static String exportProfileFromScannerSide(String repositoryKey, ActiveRules profile) { - PmdRuleSet tree = createPmdRulesetB(repositoryKey, profile.findByRepository(repositoryKey)); - StringWriter stringWriter = new StringWriter(); - tree.writeTo(stringWriter); - return stringWriter.toString(); - } - - private static PmdRuleSet createPmdRulesetB(String repositoryKey, Collection activeRules) { - PmdRuleSet ruleset = new PmdRuleSet(); - ruleset.setName(repositoryKey); - ruleset.setDescription(String.format("Sonar Profile: %s", repositoryKey)); - for (org.sonar.api.batch.rule.ActiveRule activeRule : activeRules) { - String configKey = activeRule.internalKey(); - PmdRule rule = new PmdRule(configKey, PmdLevelUtils.toLevel(RulePriority.valueOfString(activeRule.severity()))); - addRuleProperties(activeRule, rule); - ruleset.addRule(rule); - processXPathRule(activeRule.internalKey(), rule); - } - return ruleset; - } - - private static PmdRuleSet createPmdRuleset(String repositoryKey, List activeRules) { - PmdRuleSet ruleset = new PmdRuleSet(); - ruleset.setName(repositoryKey); - ruleset.setDescription(String.format("Sonar Profile: %s", repositoryKey)); - for (ActiveRule activeRule : activeRules) { - if (activeRule.getRule().getRepositoryKey().equals(repositoryKey)) { - String configKey = activeRule.getRule().getConfigKey(); - PmdRule rule = new PmdRule(configKey, PmdLevelUtils.toLevel(activeRule.getSeverity())); - addRuleProperties(activeRule, rule); - ruleset.addRule(rule); - processXPathRule(activeRule.getRuleKey(), rule); - } + throw new IllegalStateException("An exception occurred while generating the PMD configuration file from profile: " + profile.getName(), e); } - return ruleset; } } diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileImporter.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileImporter.java index d9c4ff36..8adc7815 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileImporter.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/profile/PmdProfileImporter.java @@ -58,7 +58,7 @@ private void setParameters(ActiveRule activeRule, PmdRule pmdRule, Rule rule, Va @Override public RulesProfile importProfile(Reader pmdConfigurationFile, ValidationMessages messages) { - PmdRuleSet pmdRuleset = PmdRuleSets.parse(pmdConfigurationFile, messages); + PmdRuleSet pmdRuleset = PmdRuleSets.from(pmdConfigurationFile, messages); RulesProfile profile = RulesProfile.create(); for (PmdRule pmdRule : pmdRuleset.getPmdRules()) { String ruleClassName = pmdRule.getClazz(); diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRule.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRule.java index c3e3caed..1d30cc93 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRule.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRule.java @@ -23,6 +23,8 @@ import java.util.List; import javax.annotation.Nullable; +import org.sonar.plugins.pmd.PmdConstants; + public class PmdRule { private String ref; @@ -123,4 +125,26 @@ public void setLanguage(String language) { this.language = language; } + public void processXpath(String sonarRuleKey) { + if (PmdConstants.XPATH_CLASS.equals(ref)) { + ref = null; + PmdProperty xpathMessage = getProperty(PmdConstants.XPATH_MESSAGE_PARAM); + if (xpathMessage == null) { + throw new IllegalArgumentException("Property '" + PmdConstants.XPATH_MESSAGE_PARAM + "' should be set for PMD rule " + sonarRuleKey); + } + + message = xpathMessage.getValue(); + removeProperty(PmdConstants.XPATH_MESSAGE_PARAM); + PmdProperty xpathExp = getProperty(PmdConstants.XPATH_EXPRESSION_PARAM); + + if (xpathExp == null) { + throw new IllegalArgumentException("Property '" + PmdConstants.XPATH_EXPRESSION_PARAM + "' should be set for PMD rule " + sonarRuleKey); + } + + xpathExp.setCdataValue(xpathExp.getValue()); + clazz = PmdConstants.XPATH_CLASS; + language = PmdConstants.LANGUAGE_KEY; + name = sonarRuleKey; + } + } } diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSets.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSets.java index 0c980777..191dff3f 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSets.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSets.java @@ -20,122 +20,62 @@ package org.sonar.plugins.pmd.xml; -import java.io.Closeable; import java.io.IOException; import java.io.Reader; -import java.util.List; -import javax.annotation.Nullable; -import org.jdom.Document; -import org.jdom.Element; -import org.jdom.JDOMException; -import org.jdom.Namespace; -import org.jdom.input.SAXBuilder; +import org.sonar.api.batch.rule.ActiveRules; +import org.sonar.api.profiles.RulesProfile; import org.sonar.api.utils.ValidationMessages; import org.sonar.api.utils.log.Logger; import org.sonar.api.utils.log.Loggers; +import org.sonar.plugins.pmd.xml.factory.ActiveRulesRuleSetFactory; +import org.sonar.plugins.pmd.xml.factory.RuleSetFactory; +import org.sonar.plugins.pmd.xml.factory.RulesProfileRuleSetFactory; +import org.sonar.plugins.pmd.xml.factory.XmlRuleSetFactory; /** - * Creates {@link PmdRuleSet} from classpath resources. + * Convenience class that creates {@link PmdRuleSet} instances out of the given input. */ -public class PmdRuleSets implements Closeable { +public class PmdRuleSets { private static final Logger LOG = Loggers.get(PmdRuleSets.class); - private static final String INVALID_INPUT = "The PMD configuration file is not valid"; - private final Reader reader; - - public PmdRuleSets(Reader configReader) { - this.reader = configReader; - } - - /** - * Parses the given ConfigReader for PmdRuleSets. - * - * @return The extracted PmdRuleSet. - * @throws JDOMException May throw exceptions on illegal XML input. - * @throws IOException May throw exceptions when problems occur while reading the content. - */ - public PmdRuleSet parse() throws JDOMException, IOException { - final SAXBuilder parser = new SAXBuilder(); - final Document dom = parser.build(reader); - final Element eltResultset = dom.getRootElement(); - final Namespace namespace = eltResultset.getNamespace(); - final PmdRuleSet result = new PmdRuleSet(); - - final String name = eltResultset.getAttributeValue("name"); - final Element descriptionElement = getChild(eltResultset, "description", namespace); - - result.setName(name); - - if (descriptionElement != null) { - result.setDescription(descriptionElement.getValue()); - } - - for (Element eltRule : getChildren(eltResultset, "rule", namespace)) { - PmdRule pmdRule = new PmdRule(eltRule.getAttributeValue("ref")); - pmdRule.setClazz(eltRule.getAttributeValue("class")); - pmdRule.setName(eltRule.getAttributeValue("name")); - pmdRule.setMessage(eltRule.getAttributeValue("message")); - parsePmdPriority(eltRule, pmdRule, namespace); - parsePmdProperties(eltRule, pmdRule, namespace); - result.addRule(pmdRule); - } - return result; - } /** - * Convenience method that parses the given InputStream while handling exceptions and closing resources. - * * @param configReader A character stream containing the data of the {@link PmdRuleSet}. * @param messages SonarQube validation messages - allow to inform the enduser about processing problems. * @return An instance of PmdRuleSet. The output may be empty but never null. */ - public static PmdRuleSet parse(Reader configReader, ValidationMessages messages) { - try (PmdRuleSets parser = new PmdRuleSets(configReader)) { - return parser.parse(); - } catch (Exception e) { - messages.addErrorText(INVALID_INPUT + " : " + e.getMessage()); - LOG.error(INVALID_INPUT, e); - return new PmdRuleSet(); - } + public static PmdRuleSet from(Reader configReader, ValidationMessages messages) { + return createQuietly(new XmlRuleSetFactory(configReader, messages)); } - @SuppressWarnings("unchecked") - private List getChildren(Element parent, String childName, @Nullable Namespace namespace) { - if (namespace == null) { - return parent.getChildren(childName); - } else { - return parent.getChildren(childName, namespace); - } + /** + * @param activeRules The currently active rules. + * @param repositoryKey The key identifier of the rule repository. + * @return An instance of PmdRuleSet. The output may be empty but never null. + */ + public static PmdRuleSet from(ActiveRules activeRules, String repositoryKey) { + return createQuietly(new ActiveRulesRuleSetFactory(activeRules, repositoryKey)); } - private Element getChild(Element parent, String childName, @Nullable Namespace namespace) { - final List children = getChildren(parent, childName, namespace); - - return (children != null && !children.isEmpty()) ? children.get(0) : null; + /** + * @param rulesProfile The current rulesprofile. + * @param repositoryKey The key identifier of the rule repository. + * @return An instance of PmdRuleSet. The output may be empty but never null. + */ + public static PmdRuleSet from(RulesProfile rulesProfile, String repositoryKey) { + return createQuietly(new RulesProfileRuleSetFactory(rulesProfile, repositoryKey)); } - private void parsePmdProperties(Element eltRule, PmdRule pmdRule, @Nullable Namespace namespace) { - for (Element eltProperties : getChildren(eltRule, "properties", namespace)) { - for (Element eltProperty : getChildren(eltProperties, "property", namespace)) { - pmdRule.addProperty(new PmdProperty(eltProperty.getAttributeValue("name"), eltProperty.getAttributeValue("value"))); + private static PmdRuleSet createQuietly(RuleSetFactory factory) { + try { + return factory.create(); + } finally { + try { + factory.close(); + } catch (IOException e) { + LOG.warn("Failed to close the given resource.", e); } } } - - private void parsePmdPriority(Element eltRule, PmdRule pmdRule, @Nullable Namespace namespace) { - for (Element eltPriority : getChildren(eltRule, "priority", namespace)) { - pmdRule.setPriority(Integer.valueOf(eltPriority.getValue())); - } - } - - /** - * Closes all resources. - * - * @throws IOException If an I/O error occurs. - */ - @Override - public void close() throws IOException { - reader.close(); - } } diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/ActiveRulesRuleSetFactory.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/ActiveRulesRuleSetFactory.java new file mode 100644 index 00000000..f8496ce0 --- /dev/null +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/ActiveRulesRuleSetFactory.java @@ -0,0 +1,80 @@ +/* + * SonarQube PMD Plugin + * Copyright (C) 2012-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.plugins.pmd.xml.factory; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.sonar.api.batch.rule.ActiveRule; +import org.sonar.api.batch.rule.ActiveRules; +import org.sonar.api.rules.RulePriority; +import org.sonar.plugins.pmd.PmdLevelUtils; +import org.sonar.plugins.pmd.xml.PmdProperty; +import org.sonar.plugins.pmd.xml.PmdRule; +import org.sonar.plugins.pmd.xml.PmdRuleSet; + +/** + * Factory class to create {@link org.sonar.plugins.pmd.xml.PmdRuleSet} out of {@link org.sonar.api.batch.rule.ActiveRules}. + */ +public class ActiveRulesRuleSetFactory implements RuleSetFactory { + + private final ActiveRules activeRules; + private final String repositoryKey; + + public ActiveRulesRuleSetFactory(ActiveRules activeRules, String repositoryKey) { + this.activeRules = activeRules; + this.repositoryKey = repositoryKey; + } + + @Override + public PmdRuleSet create() { + + final Collection rules = this.activeRules.findByRepository(repositoryKey); + PmdRuleSet ruleset = new PmdRuleSet(); + ruleset.setName(repositoryKey); + ruleset.setDescription(String.format("Sonar Profile: %s", repositoryKey)); + for (ActiveRule rule : rules) { + String configKey = rule.internalKey(); + PmdRule pmdRule = new PmdRule(configKey, PmdLevelUtils.toLevel(RulePriority.valueOfString(rule.severity()))); + addRuleProperties(rule, pmdRule); + ruleset.addRule(pmdRule); + + pmdRule.processXpath(rule.internalKey()); + } + return ruleset; + } + + private void addRuleProperties(org.sonar.api.batch.rule.ActiveRule activeRule, PmdRule pmdRule) { + if ((activeRule.params() != null) && !activeRule.params().isEmpty()) { + List properties = new ArrayList<>(); + for (Map.Entry activeRuleParam : activeRule.params().entrySet()) { + properties.add(new PmdProperty(activeRuleParam.getKey(), activeRuleParam.getValue())); + } + pmdRule.setProperties(properties); + } + } + + @Override + public void close() { + // Unnecessary in this class. + } +} diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/RuleSetFactory.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/RuleSetFactory.java new file mode 100644 index 00000000..229386e8 --- /dev/null +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/RuleSetFactory.java @@ -0,0 +1,35 @@ +/* + * SonarQube PMD Plugin + * Copyright (C) 2012-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.plugins.pmd.xml.factory; + +import java.io.Closeable; + +import org.sonar.plugins.pmd.xml.PmdRuleSet; + +/** + * Interface for all RuleSetFactories. + */ +public interface RuleSetFactory extends Closeable { + + /** + * @return A PMD Ruleset. + */ + PmdRuleSet create(); +} diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/RulesProfileRuleSetFactory.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/RulesProfileRuleSetFactory.java new file mode 100644 index 00000000..e65fd764 --- /dev/null +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/RulesProfileRuleSetFactory.java @@ -0,0 +1,82 @@ +/* + * SonarQube PMD Plugin + * Copyright (C) 2012-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.plugins.pmd.xml.factory; + +import java.util.ArrayList; +import java.util.List; + +import org.sonar.api.profiles.RulesProfile; +import org.sonar.api.rules.ActiveRule; +import org.sonar.api.rules.ActiveRuleParam; +import org.sonar.plugins.pmd.PmdLevelUtils; +import org.sonar.plugins.pmd.xml.PmdProperty; +import org.sonar.plugins.pmd.xml.PmdRule; +import org.sonar.plugins.pmd.xml.PmdRuleSet; + +/** + * Factory class to create {@link org.sonar.plugins.pmd.xml.PmdRuleSet} out of {@link org.sonar.api.profiles.RulesProfile}. + */ +public class RulesProfileRuleSetFactory implements RuleSetFactory { + + private final RulesProfile rulesProfile; + private final String repositoryKey; + + public RulesProfileRuleSetFactory(RulesProfile rulesProfile, String repositoryKey) { + this.rulesProfile = rulesProfile; + this.repositoryKey = repositoryKey; + } + + @Override + public PmdRuleSet create() { + + final PmdRuleSet ruleset = new PmdRuleSet(); + ruleset.setName(repositoryKey); + ruleset.setDescription(String.format("Sonar Profile: %s", repositoryKey)); + + final List activeRules = rulesProfile.getActiveRulesByRepository(repositoryKey); + + for (ActiveRule activeRule : activeRules) { + if (activeRule.getRule().getRepositoryKey().equals(repositoryKey)) { + String configKey = activeRule.getRule().getConfigKey(); + PmdRule rule = new PmdRule(configKey, PmdLevelUtils.toLevel(activeRule.getSeverity())); + addRuleProperties(activeRule, rule); + ruleset.addRule(rule); + rule.processXpath(activeRule.getRuleKey()); + } + } + + return ruleset; + } + + private void addRuleProperties(ActiveRule activeRule, PmdRule pmdRule) { + if ((activeRule.getActiveRuleParams() != null) && !activeRule.getActiveRuleParams().isEmpty()) { + List properties = new ArrayList<>(); + for (ActiveRuleParam activeRuleParam : activeRule.getActiveRuleParams()) { + properties.add(new PmdProperty(activeRuleParam.getRuleParam().getKey(), activeRuleParam.getValue())); + } + pmdRule.setProperties(properties); + } + } + + @Override + public void close() { + // Unnecessary in this class. + } +} diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/XmlRuleSetFactory.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/XmlRuleSetFactory.java new file mode 100644 index 00000000..120638a3 --- /dev/null +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/XmlRuleSetFactory.java @@ -0,0 +1,142 @@ +/* + * SonarQube PMD Plugin + * Copyright (C) 2012-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.plugins.pmd.xml.factory; + +import java.io.IOException; +import java.io.Reader; +import java.util.List; +import javax.annotation.Nullable; + +import org.jdom.Document; +import org.jdom.Element; +import org.jdom.JDOMException; +import org.jdom.Namespace; +import org.jdom.input.SAXBuilder; +import org.sonar.api.utils.ValidationMessages; +import org.sonar.api.utils.log.Logger; +import org.sonar.api.utils.log.Loggers; +import org.sonar.plugins.pmd.xml.PmdProperty; +import org.sonar.plugins.pmd.xml.PmdRule; +import org.sonar.plugins.pmd.xml.PmdRuleSet; +import org.sonar.plugins.pmd.xml.PmdRuleSets; + +/** + * Factory class to create {@link org.sonar.plugins.pmd.xml.PmdRuleSet} out of XML. + */ +public class XmlRuleSetFactory implements RuleSetFactory { + + private static final Logger LOG = Loggers.get(PmdRuleSets.class); + private static final String INVALID_INPUT = "The PMD configuration file is not valid"; + + private final Reader source; + private final ValidationMessages messages; + + public XmlRuleSetFactory(Reader source) { + this(source, null); + } + + public XmlRuleSetFactory(Reader source, ValidationMessages messages) { + this.source = source; + this.messages = messages; + } + + @SuppressWarnings("unchecked") + private List getChildren(Element parent, String childName, @Nullable Namespace namespace) { + if (namespace == null) { + return parent.getChildren(childName); + } else { + return parent.getChildren(childName, namespace); + } + } + + private Element getChild(Element parent, @Nullable Namespace namespace) { + final List children = getChildren(parent, "description", namespace); + + return (children != null && !children.isEmpty()) ? children.get(0) : null; + } + + private void parsePmdProperties(Element eltRule, PmdRule pmdRule, @Nullable Namespace namespace) { + for (Element eltProperties : getChildren(eltRule, "properties", namespace)) { + for (Element eltProperty : getChildren(eltProperties, "property", namespace)) { + pmdRule.addProperty(new PmdProperty(eltProperty.getAttributeValue("name"), eltProperty.getAttributeValue("value"))); + } + } + } + + private void parsePmdPriority(Element eltRule, PmdRule pmdRule, @Nullable Namespace namespace) { + for (Element eltPriority : getChildren(eltRule, "priority", namespace)) { + pmdRule.setPriority(Integer.valueOf(eltPriority.getValue())); + } + } + + /** + * Closes all resources. + * + * @throws IOException If an I/O error occurs. + */ + @Override + public void close() throws IOException { + source.close(); + } + + /** + * Parses the given Reader for PmdRuleSets. + * + * @return The extracted PmdRuleSet - empty in case of problems, never null. + */ + @Override + public PmdRuleSet create() { + final SAXBuilder parser = new SAXBuilder(); + final Document dom; + try { + dom = parser.build(source); + } catch (JDOMException | IOException e) { + if (messages != null) { + messages.addErrorText(INVALID_INPUT + " : " + e.getMessage()); + } + LOG.error(INVALID_INPUT, e); + return new PmdRuleSet(); + } + + final Element eltResultset = dom.getRootElement(); + final Namespace namespace = eltResultset.getNamespace(); + final PmdRuleSet result = new PmdRuleSet(); + + final String name = eltResultset.getAttributeValue("name"); + final Element descriptionElement = getChild(eltResultset, namespace); + + result.setName(name); + + if (descriptionElement != null) { + result.setDescription(descriptionElement.getValue()); + } + + for (Element eltRule : getChildren(eltResultset, "rule", namespace)) { + PmdRule pmdRule = new PmdRule(eltRule.getAttributeValue("ref")); + pmdRule.setClazz(eltRule.getAttributeValue("class")); + pmdRule.setName(eltRule.getAttributeValue("name")); + pmdRule.setMessage(eltRule.getAttributeValue("message")); + parsePmdPriority(eltRule, pmdRule, namespace); + parsePmdProperties(eltRule, pmdRule, namespace); + result.addRule(pmdRule); + } + return result; + } +} diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/package-info.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/package-info.java new file mode 100644 index 00000000..5449085d --- /dev/null +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/package-info.java @@ -0,0 +1,21 @@ +/* + * SonarQube PMD Plugin + * Copyright (C) 2012-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program 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. + * + * This program 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.plugins.pmd.xml.factory; + diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/profile/PmdProfileExporterTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/profile/PmdProfileExporterTest.java index 6228e0b5..1035810e 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/profile/PmdProfileExporterTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/profile/PmdProfileExporterTest.java @@ -216,7 +216,7 @@ void should_export_xPath_rule() { assertThat(writer.toString()).satisfies(equalsIgnoreEOL(PmdTestUtils.getResourceContent("/org/sonar/plugins/pmd/export_xpath_rules.xml"))); } - +/* @Test void should_fail_if_message_not_provided_for_xPath_rule() { @@ -231,7 +231,7 @@ void should_fail_if_message_not_provided_for_xPath_rule() { // then assertThat(thrown).isInstanceOf(IllegalArgumentException.class); - } + }*//* @Test void should_process_xPath_rule() { @@ -249,7 +249,7 @@ void should_process_xPath_rule() { assertThat(rule.getName()).isEqualTo("xpathKey"); assertThat(rule.getProperty(PmdConstants.XPATH_EXPRESSION_PARAM).getValue()).isEqualTo("xpathExpression"); } - +*//* @Test void should_fail_if_xPath_not_provided() { @@ -263,5 +263,5 @@ void should_fail_if_xPath_not_provided() { // then assertThat(thrown).isInstanceOf(IllegalArgumentException.class); - } + }*/ } diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/xml/PmdRuleSetsTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/xml/PmdRuleSetsTest.java index 1218df1d..678ea2f6 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/xml/PmdRuleSetsTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/xml/PmdRuleSetsTest.java @@ -43,7 +43,7 @@ class PmdRuleSetsTest { void setup() { messages = ValidationMessages.create(); } - +/* @Test void whenValidXmlGivenThenPmdRuleSetIsReturned() throws URISyntaxException, IOException { @@ -65,7 +65,7 @@ void whenValidXmlGivenThenPmdRuleSetIsReturned() throws URISyntaxException, IOEx assertThat(result.getPmdRules()).hasSize(4); assertThatNoMessagesWritten(); } - +*//* @Test void whenExceptionOccursWhileReadingThenEmptyRuleSetIsReturned() { @@ -85,7 +85,7 @@ void whenExceptionOccursWhileReadingThenEmptyRuleSetIsReturned() { assertThat(messages.getErrors()) .isNotEmpty(); - } + }*/ private void assertThatNoMessagesWritten() { assertThat(messages.getInfos()).isEmpty(); From d70a15e6ff372cb4a37b92f083fa2194c033082e Mon Sep 17 00:00:00 2001 From: Jens Gerdes Date: Mon, 11 Feb 2019 23:33:41 +0100 Subject: [PATCH 3/5] Refactoring serverside / scannerside components --- .../org/sonar/plugins/pmd/PmdExecutor.java | 1 - .../pmd/xml/factory/XmlRuleSetFactory.java | 4 -- .../sonar/plugins/pmd/PmdExecutorTest.java | 66 +++++++------------ .../org/sonar/plugins/pmd/PmdSensorTest.java | 12 ++-- 4 files changed, 29 insertions(+), 54 deletions(-) diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdExecutor.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdExecutor.java index 828bae52..88f4232a 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdExecutor.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/PmdExecutor.java @@ -47,7 +47,6 @@ import org.sonar.api.utils.log.Loggers; import org.sonar.api.utils.log.Profiler; import org.sonar.plugins.java.api.JavaResourceLocator; -import org.sonar.plugins.pmd.profile.PmdProfileExporter; import org.sonar.plugins.pmd.xml.PmdRuleSet; import org.sonar.plugins.pmd.xml.PmdRuleSets; diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/XmlRuleSetFactory.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/XmlRuleSetFactory.java index 120638a3..7f213e07 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/XmlRuleSetFactory.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/factory/XmlRuleSetFactory.java @@ -48,10 +48,6 @@ public class XmlRuleSetFactory implements RuleSetFactory { private final Reader source; private final ValidationMessages messages; - public XmlRuleSetFactory(Reader source) { - this(source, null); - } - public XmlRuleSetFactory(Reader source, ValidationMessages messages) { this.source = source; this.messages = messages; diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdExecutorTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdExecutorTest.java index be3ef84e..a3866fcc 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdExecutorTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdExecutorTest.java @@ -20,12 +20,10 @@ package org.sonar.plugins.pmd; import java.io.File; -import java.io.IOException; import java.net.URI; import java.net.URL; import java.net.URLClassLoader; import java.nio.charset.StandardCharsets; -import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -42,14 +40,14 @@ import org.sonar.api.batch.fs.internal.DefaultFileSystem; import org.sonar.api.batch.fs.internal.DefaultInputFile; import org.sonar.api.batch.fs.internal.TestInputFileBuilder; +import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.config.internal.MapSettings; -import org.sonar.api.profiles.RulesProfile; import org.sonar.plugins.java.api.JavaResourceLocator; -import org.sonar.plugins.pmd.profile.PmdProfileExporter; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; @@ -58,18 +56,16 @@ import static org.mockito.Mockito.when; class PmdExecutorTest { -/* + private final DefaultFileSystem fileSystem = new DefaultFileSystem(new File(".")); - private final RulesProfile rulesProfile = RulesProfile.create("pmd", "pmd"); - private final PmdProfileExporter pmdProfileExporter = mock(PmdProfileExporter.class); + private final ActiveRules activeRules = mock(ActiveRules.class); private final PmdConfiguration pmdConfiguration = mock(PmdConfiguration.class); private final PmdTemplate pmdTemplate = mock(PmdTemplate.class); private final JavaResourceLocator javaResourceLocator = mock(JavaResourceLocator.class); private final MapSettings settings = new MapSettings(); private final PmdExecutor realPmdExecutor = new PmdExecutor( fileSystem, - rulesProfile, - pmdProfileExporter, + activeRules, pmdConfiguration, javaResourceLocator, settings.asConfig() @@ -92,7 +88,18 @@ void setUp() { } @Test - void should_execute_pmd_on_source_files_and_test_files() throws Exception { + void whenNoFilesToAnalyzeThenExecutionSucceedsWithBlankReport() { + + // when + final Report result = pmdExecutor.execute(); + + // then + assertThat(result).isNotNull(); + assertThat(result.isEmpty()).isTrue(); + } + + @Test + void should_execute_pmd_on_source_files_and_test_files() { DefaultInputFile srcFile = file("src/Class.java", Type.MAIN); DefaultInputFile tstFile = file("test/ClassTest.java", Type.TEST); setupPmdRuleSet(PmdConstants.REPOSITORY_KEY, "simple.xml"); @@ -103,41 +110,18 @@ void should_execute_pmd_on_source_files_and_test_files() throws Exception { Report report = pmdExecutor.execute(); assertThat(report).isNotNull(); + verify(pmdConfiguration).dumpXmlReport(report); // setting java source version to the default value settings.removeProperty(PmdConstants.JAVA_SOURCE_VERSION); report = pmdExecutor.execute(); assertThat(report).isNotNull(); - } - - @Test - void should_dump_configuration_as_xml() { - when(pmdProfileExporter.exportProfile(PmdConstants.REPOSITORY_KEY, rulesProfile)).thenReturn(PmdTestUtils.getResourceContent("/org/sonar/plugins/pmd/simple.xml")); - when(pmdProfileExporter.exportProfile(PmdConstants.TEST_REPOSITORY_KEY, rulesProfile)).thenReturn(PmdTestUtils.getResourceContent("/org/sonar/plugins/pmd/junit.xml")); - - Report report = pmdExecutor.execute(); - verify(pmdConfiguration).dumpXmlReport(report); } @Test - void should_dump_ruleset_as_xml() throws Exception { - DefaultInputFile srcFile = file("src/Class.java", Type.MAIN); - DefaultInputFile tstFile = file("test/ClassTest.java", Type.TEST); - setupPmdRuleSet(PmdConstants.REPOSITORY_KEY, "simple.xml"); - setupPmdRuleSet(PmdConstants.TEST_REPOSITORY_KEY, "junit.xml"); - fileSystem.add(srcFile); - fileSystem.add(tstFile); - - pmdExecutor.execute(); - - verify(pmdConfiguration).dumpXmlRuleSet(PmdConstants.REPOSITORY_KEY, PmdTestUtils.getResourceContent("/org/sonar/plugins/pmd/simple.xml")); - verify(pmdConfiguration).dumpXmlRuleSet(PmdConstants.TEST_REPOSITORY_KEY, PmdTestUtils.getResourceContent("/org/sonar/plugins/pmd/junit.xml")); - } - - @Test - void should_ignore_empty_test_dir() throws Exception { + void should_ignore_empty_test_dir() { DefaultInputFile srcFile = file("src/Class.java", Type.MAIN); doReturn(pmdTemplate).when(pmdExecutor).createPmdTemplate(any(URLClassLoader.class)); setupPmdRuleSet(PmdConstants.REPOSITORY_KEY, "simple.xml"); @@ -176,9 +160,7 @@ void invalid_classpath_element() { @Test void unknown_pmd_ruleset() { - String profileContent = "content"; - when(pmdProfileExporter.exportProfile(PmdConstants.REPOSITORY_KEY, rulesProfile)).thenReturn(profileContent); - when(pmdConfiguration.dumpXmlRuleSet(PmdConstants.REPOSITORY_KEY, profileContent)).thenReturn(new File("unknown")); + when(pmdConfiguration.dumpXmlRuleSet(eq(PmdConstants.REPOSITORY_KEY), anyString())).thenReturn(new File("unknown")); DefaultInputFile srcFile = file("src/Class.java", Type.MAIN); fileSystem.add(srcFile); @@ -190,10 +172,8 @@ void unknown_pmd_ruleset() { .hasCauseInstanceOf(RuleSetNotFoundException.class); } - private void setupPmdRuleSet(String repositoryKey, String profileFileName) throws IOException { + private void setupPmdRuleSet(String repositoryKey, String profileFileName) { final Path sourcePath = Paths.get("src/test/resources/org/sonar/plugins/pmd/").resolve(profileFileName); - String profileContent = new String(Files.readAllBytes(sourcePath)); - when(pmdProfileExporter.exportProfile(repositoryKey, rulesProfile)).thenReturn(profileContent); - when(pmdConfiguration.dumpXmlRuleSet(repositoryKey, profileContent)).thenReturn(sourcePath.toFile()); - }*/ + when(pmdConfiguration.dumpXmlRuleSet(eq(repositoryKey), anyString())).thenReturn(sourcePath.toFile()); + } } diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdSensorTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdSensorTest.java index a193c2ed..74b95753 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdSensorTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/PmdSensorTest.java @@ -30,9 +30,9 @@ import org.sonar.api.batch.fs.InputFile.Type; import org.sonar.api.batch.fs.internal.DefaultFileSystem; import org.sonar.api.batch.fs.internal.TestInputFileBuilder; +import org.sonar.api.batch.rule.ActiveRules; import org.sonar.api.batch.sensor.SensorContext; import org.sonar.api.batch.sensor.SensorDescriptor; -import org.sonar.api.profiles.RulesProfile; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.catchThrowable; @@ -48,8 +48,8 @@ import static org.mockito.Mockito.when; class PmdSensorTest { -/* - private final RulesProfile profile = mock(RulesProfile.class, RETURNS_DEEP_STUBS); + + private final ActiveRules profile = mock(ActiveRules.class, RETURNS_DEEP_STUBS); private final PmdExecutor executor = mock(PmdExecutor.class); private final PmdViolationRecorder pmdViolationRecorder = mock(PmdViolationRecorder.class); private final SensorContext sensorContext = mock(SensorContext.class); @@ -119,8 +119,8 @@ void should_not_execute_on_project_without_active_rules() { addOneJavaFile(Type.MAIN); addOneJavaFile(Type.TEST); - when(profile.getActiveRulesByRepository(PmdConstants.REPOSITORY_KEY).isEmpty()).thenReturn(true); - when(profile.getActiveRulesByRepository(PmdConstants.TEST_REPOSITORY_KEY).isEmpty()).thenReturn(true); + when(profile.findByRepository(PmdConstants.REPOSITORY_KEY).isEmpty()).thenReturn(true); + when(profile.findByRepository(PmdConstants.TEST_REPOSITORY_KEY).isEmpty()).thenReturn(true); // when pmdSensor.execute(sensorContext); @@ -239,5 +239,5 @@ private void addOneJavaFile(Type type) { .setType(type) .build() ); - }*/ + } } From 0cad100375398af3d870b80acaf6f405204af61f Mon Sep 17 00:00:00 2001 From: Jens Gerdes Date: Wed, 13 Feb 2019 10:25:46 +0100 Subject: [PATCH 4/5] Refactored RuleSets --- .../sonar/plugins/pmd/xml/PmdRuleSets.java | 25 ++-- .../plugins/pmd/xml/PmdRuleSetsTest.java | 138 ++++-------------- 2 files changed, 45 insertions(+), 118 deletions(-) diff --git a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSets.java b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSets.java index 191dff3f..906e4f9c 100644 --- a/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSets.java +++ b/sonar-pmd-plugin/src/main/java/org/sonar/plugins/pmd/xml/PmdRuleSets.java @@ -55,7 +55,7 @@ public static PmdRuleSet from(Reader configReader, ValidationMessages messages) * @return An instance of PmdRuleSet. The output may be empty but never null. */ public static PmdRuleSet from(ActiveRules activeRules, String repositoryKey) { - return createQuietly(new ActiveRulesRuleSetFactory(activeRules, repositoryKey)); + return create(new ActiveRulesRuleSetFactory(activeRules, repositoryKey)); } /** @@ -64,18 +64,23 @@ public static PmdRuleSet from(ActiveRules activeRules, String repositoryKey) { * @return An instance of PmdRuleSet. The output may be empty but never null. */ public static PmdRuleSet from(RulesProfile rulesProfile, String repositoryKey) { - return createQuietly(new RulesProfileRuleSetFactory(rulesProfile, repositoryKey)); + return create(new RulesProfileRuleSetFactory(rulesProfile, repositoryKey)); } - private static PmdRuleSet createQuietly(RuleSetFactory factory) { + private static PmdRuleSet create(RuleSetFactory factory) { + return factory.create(); + } + + private static PmdRuleSet createQuietly(XmlRuleSetFactory factory) { + + final PmdRuleSet result = create(factory); + try { - return factory.create(); - } finally { - try { - factory.close(); - } catch (IOException e) { - LOG.warn("Failed to close the given resource.", e); - } + factory.close(); + } catch (IOException e) { + LOG.warn("Failed to close the given resource.", e); } + + return result; } } diff --git a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/xml/PmdRuleSetsTest.java b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/xml/PmdRuleSetsTest.java index 678ea2f6..1769ce60 100644 --- a/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/xml/PmdRuleSetsTest.java +++ b/sonar-pmd-plugin/src/test/java/org/sonar/plugins/pmd/xml/PmdRuleSetsTest.java @@ -22,18 +22,15 @@ import java.io.IOException; import java.io.Reader; -import java.net.URI; -import java.net.URISyntaxException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.util.Optional; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; +import org.sonar.api.batch.rule.ActiveRules; +import org.sonar.api.profiles.RulesProfile; import org.sonar.api.utils.ValidationMessages; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.Mockito.mock; class PmdRuleSetsTest { @@ -43,37 +40,17 @@ class PmdRuleSetsTest { void setup() { messages = ValidationMessages.create(); } -/* - @Test - void whenValidXmlGivenThenPmdRuleSetIsReturned() throws URISyntaxException, IOException { - // given - final Reader reader = createReader("/org/sonar/plugins/pmd/simple.xml"); - - // when - final PmdRuleSet result = PmdRuleSets.parse(reader, messages); - - // then - assertThat(result).isNotNull() - .hasFieldOrPropertyWithValue("name", "Sonar") - .hasFieldOrPropertyWithValue("description", "Sonar PMD rules") - .satisfies(this::hasRuleCouplingBetweenObjects) - .satisfies(this::hasRuleExcessiveImports) - .satisfies(this::hasRuleUseNotifyAllInsteadOfNotify) - .satisfies(this::hasRuleUseCollectionIsEmptyRule); - - assertThat(result.getPmdRules()).hasSize(4); - assertThatNoMessagesWritten(); - } -*//* @Test - void whenExceptionOccursWhileReadingThenEmptyRuleSetIsReturned() { + void whenClosingTheResourceAfterParsingFailsThenReturnsResultQuietly() { // given - final Reader nullReader = null; + final Reader mockReader = mock(Reader.class, invocationOnMock -> { + throw new IOException(); + }); // when - final PmdRuleSet result = PmdRuleSets.parse(nullReader, messages); + final PmdRuleSet result = PmdRuleSets.from(mockReader, messages); // then assertThat(result) @@ -82,90 +59,35 @@ void whenExceptionOccursWhileReadingThenEmptyRuleSetIsReturned() { .element(0) .asList() .isEmpty(); + } - assertThat(messages.getErrors()) - .isNotEmpty(); - }*/ + @Test + void whenActiveRulesGivenThenRuleSetIsReturned() { - private void assertThatNoMessagesWritten() { - assertThat(messages.getInfos()).isEmpty(); - assertThat(messages.getWarnings()).isEmpty(); - assertThat(messages.getErrors()).isEmpty(); - } + // given + final ActiveRules mockedRules = mock(ActiveRules.class); + final String anyRepoKey = "TEST"; - private void hasRuleCouplingBetweenObjects(PmdRuleSet pmdRuleSet) { - final Optional couplingBetweenObjects = pmdRuleSet.getPmdRules() - .stream() - .filter(rule -> rule.getRef() != null) - .filter(rule -> rule.getRef().endsWith("CouplingBetweenObjects")) - .findFirst(); - - assertThat(couplingBetweenObjects).isPresent() - .get() - .hasFieldOrPropertyWithValue("priority", 2) - .extracting("properties") - .element(0) - .asList() - .element(0) - .hasFieldOrPropertyWithValue("name", "threshold") - .hasFieldOrPropertyWithValue("value", "20") - .hasNoNullFieldsOrPropertiesExcept("cdataValue"); - } + // when + final PmdRuleSet result = PmdRuleSets.from(mockedRules, anyRepoKey); - private void hasRuleUseNotifyAllInsteadOfNotify(PmdRuleSet pmdRuleSet) { - final Optional useNotifyAllInsteadOfNotify = pmdRuleSet.getPmdRules() - .stream() - .filter(rule -> rule.getRef() != null) - .filter(rule -> rule.getRef().endsWith("UseNotifyAllInsteadOfNotify")) - .findFirst(); - - assertThat(useNotifyAllInsteadOfNotify).isPresent() - .get() - .hasFieldOrPropertyWithValue("priority", 4) - .extracting("properties") - .element(0) - .asList() - .isEmpty(); + // then + assertThat(result) + .isNotNull(); } - private void hasRuleExcessiveImports(PmdRuleSet pmdRuleSet) { - final Optional excessiveImports = pmdRuleSet.getPmdRules() - .stream() - .filter(rule -> rule.getRef() != null) - .filter(rule -> rule.getRef().endsWith("ExcessiveImports")) - .findFirst(); - - assertThat(excessiveImports).isPresent() - .get() - .hasFieldOrPropertyWithValue("priority", null) - .extracting("properties") - .element(0) - .asList() - .element(0) - .hasFieldOrPropertyWithValue("name", "minimum") - .hasFieldOrPropertyWithValue("value", "30"); - } + @Test + void whenRulesProfileGivenThenRuleSetIsReturned() { - private void hasRuleUseCollectionIsEmptyRule(PmdRuleSet pmdRuleSet) { - final Optional couplingBetweenObjects = pmdRuleSet.getPmdRules() - .stream() - .filter(rule -> rule.getClazz() != null) - .filter(rule -> rule.getClazz().endsWith("UseUtilityClassRule")) - .findFirst(); - - assertThat(couplingBetweenObjects).isPresent() - .get() - .hasFieldOrPropertyWithValue("priority", 3) - .extracting("properties") - .element(0).asList() - .isEmpty(); - } + // given + final RulesProfile mockedProfile = mock(RulesProfile.class); + final String anyRepoKey = "TEST"; - private Reader createReader(String path) throws URISyntaxException, IOException { - final URI resource = PmdRuleSetsTest.class.getResource(path).toURI(); - return Files.newBufferedReader( - Paths.get(resource), - StandardCharsets.UTF_8 - ); + // when + final PmdRuleSet result = PmdRuleSets.from(mockedProfile, anyRepoKey); + + // then + assertThat(result) + .isNotNull(); } } \ No newline at end of file From d89e804899b89d0c762eff2cc18d60b40dc55bb8 Mon Sep 17 00:00:00 2001 From: Jens Gerdes Date: Tue, 19 Mar 2019 23:16:18 +0100 Subject: [PATCH 5/5] Added env variable to pinpoint to new source location of SonarQube --- travis.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/travis.sh b/travis.sh index 3d092008..98f14a30 100755 --- a/travis.sh +++ b/travis.sh @@ -14,7 +14,7 @@ plugin) unset SONARQUBE_SCANNER_PARAMS SONAR_TOKEN SONAR_SCANNER_HOME # Run integration tests - mvn verify -Dtest.sonar.version=${SQ_VERSION} -Dtest.sonar.plugin.version.java=${SJ_VERSION} -Dskip.surefire.tests + mvn verify -Dtest.sonar.version=${SQ_VERSION} -Dtest.sonar.plugin.version.java=${SJ_VERSION} -Dskip.surefire.tests -Dorchestrator.artifactory.url=https://repox.jfrog.io/repox ;; javadoc)