From 4da773b7fcf775b7ce9d22ba40d781eb897eccb6 Mon Sep 17 00:00:00 2001 From: Andreas Dangel Date: Sun, 9 Nov 2014 11:20:54 +0100 Subject: [PATCH] Add ruleset factory tests for all languages --- .../sourceforge/pmd/RuleSetFactoryTest.java | 549 ----------------- .../sourceforge/pmd/RuleSetFactoryTest.java | 35 ++ .../sourceforge/pmd/RuleSetFactoryTest.java | 12 + .../sourceforge/pmd/RuleSetFactoryTest.java | 12 + .../sourceforge/pmd/RuleSetFactoryTest.java | 12 + .../pmd/AbstractRuleSetFactoryTest.java | 556 ++++++++++++++++++ .../sourceforge/pmd/RuleSetFactoryTest.java | 12 + .../sourceforge/pmd/RuleSetFactoryTest.java | 12 + 8 files changed, 651 insertions(+), 549 deletions(-) create mode 100644 pmd-java/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java create mode 100644 pmd-javascript/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java create mode 100644 pmd-jsp/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java create mode 100644 pmd-plsql/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java create mode 100644 pmd-test/src/main/java/net/sourceforge/pmd/AbstractRuleSetFactoryTest.java create mode 100644 pmd-vm/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java create mode 100644 pmd-xml/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java diff --git a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java index fc33151da6..691badb6d1 100644 --- a/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java +++ b/pmd-core/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java @@ -9,72 +9,23 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; -import java.io.BufferedReader; import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; import java.io.InputStream; -import java.io.InputStreamReader; import java.io.UnsupportedEncodingException; -import java.util.ArrayList; import java.util.HashSet; -import java.util.List; -import java.util.Properties; import java.util.Set; -import java.util.StringTokenizer; - -import javax.xml.parsers.ParserConfigurationException; -import javax.xml.parsers.SAXParser; -import javax.xml.parsers.SAXParserFactory; import net.sourceforge.pmd.lang.DummyLanguageModule; -import net.sourceforge.pmd.lang.Language; import net.sourceforge.pmd.lang.LanguageRegistry; import net.sourceforge.pmd.lang.rule.MockRule; import net.sourceforge.pmd.lang.rule.RuleReference; -import net.sourceforge.pmd.lang.rule.XPathRule; import net.sourceforge.pmd.util.ResourceLoader; import org.junit.Assert; -import org.junit.BeforeClass; import org.junit.Test; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.SAXParseException; -import org.xml.sax.helpers.DefaultHandler; public class RuleSetFactoryTest { - private static SAXParserFactory saxParserFactory; - private static ValidateDefaultHandler validateDefaultHandlerXsd; - private static ValidateDefaultHandler validateDefaultHandlerDtd; - private static SAXParser saxParser; - - @BeforeClass - public static void init() throws Exception { - saxParserFactory = SAXParserFactory.newInstance(); - saxParserFactory.setValidating(true); - saxParserFactory.setNamespaceAware(true); - - // Hope we're using Xerces, or this may not work! - // Note: Features are listed here - // http://xerces.apache.org/xerces2-j/features.html - saxParserFactory.setFeature("http://xml.org/sax/features/validation", - true); - saxParserFactory.setFeature( - "http://apache.org/xml/features/validation/schema", true); - saxParserFactory - .setFeature( - "http://apache.org/xml/features/validation/schema-full-checking", - true); - - validateDefaultHandlerXsd = new ValidateDefaultHandler("src/main/resources/ruleset_2_0_0.xsd"); - validateDefaultHandlerDtd = new ValidateDefaultHandler("src/main/resources/ruleset_2_0_0.dtd"); - - saxParser = saxParserFactory.newSAXParser(); - } - @Test public void testRuleSetFileName() throws RuleSetNotFoundException { RuleSet rs = loadRuleSet(EMPTY_RULESET); @@ -566,500 +517,6 @@ public class RuleSetFactoryTest { ruleSetFactory.createRuleSet(ref); } - @Test - public void testAllPMDBuiltInRulesMeetConventions() throws IOException, - RuleSetNotFoundException, ParserConfigurationException, - SAXException { - int invalidSinceAttributes = 0; - int invalidExternalInfoURL = 0; - int invalidClassName = 0; - int invalidRegexSuppress = 0; - int invalidXPathSuppress = 0; - String messages = ""; - List ruleSetFileNames = getRuleSetFileNames(); - for (String fileName : ruleSetFileNames) { - RuleSet ruleSet = loadRuleSetByFileName(fileName); - for (Rule rule : ruleSet.getRules()) { - - // Skip references - if (rule instanceof RuleReference) { - continue; - } - - Language language = rule.getLanguage(); - String group = fileName - .substring(fileName.lastIndexOf('/') + 1); - group = group.substring(0, group.indexOf(".xml")); - if (group.indexOf('-') >= 0) { - group = group.substring(0, group.indexOf('-')); - } - - // Is since missing ? - if (rule.getSince() == null) { - invalidSinceAttributes++; - messages += "Rule " + fileName + "/" + rule.getName() - + " is missing 'since' attribute" + PMD.EOL; - } - // Is URL valid ? - if (rule.getExternalInfoUrl() == null - || "".equalsIgnoreCase(rule.getExternalInfoUrl())) { - invalidExternalInfoURL++; - messages += "Rule " + fileName + "/" + rule.getName() - + " is missing 'externalInfoURL' attribute" - + PMD.EOL; - } else { - String expectedExternalInfoURL = "http://pmd.sourceforge.net/.+/rules/" - + fileName.replaceAll("rulesets/", "").replaceAll( - ".xml", "") + ".html#" + rule.getName(); - if (rule.getExternalInfoUrl() == null - || !rule.getExternalInfoUrl().matches(expectedExternalInfoURL)) { - invalidExternalInfoURL++; - messages += "Rule " - + fileName - + "/" - + rule.getName() - + " seems to have an invalid 'externalInfoURL' value (" - + rule.getExternalInfoUrl() - + "), it should be:" + expectedExternalInfoURL - + PMD.EOL; - } - } - // Proper class name/packaging? - String expectedClassName = "net.sourceforge.pmd.lang." - + language.getTerseName() + ".rule." + group + "." - + rule.getName() + "Rule"; - if (!rule.getRuleClass().equals(expectedClassName) - && !rule.getRuleClass().equals( - XPathRule.class.getName())) { - invalidClassName++; - messages += "Rule " + fileName + "/" + rule.getName() - + " seems to have an invalid 'class' value (" - + rule.getRuleClass() + "), it should be:" - + expectedClassName + PMD.EOL; - } - // Should not have violation suppress regex property - if (rule.getProperty(Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR) != null) { - invalidRegexSuppress++; - messages += "Rule " - + fileName - + "/" - + rule.getName() - + " should not have '" - + Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR.name() - + "', this is intended for end user customization only." - + PMD.EOL; - } - // Should not have violation suppress xpath property - if (rule.getProperty(Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR) != null) { - invalidXPathSuppress++; - messages += "Rule " - + fileName - + "/" - + rule.getName() - + " should not have '" - + Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR.name() - + "', this is intended for end user customization only." - + PMD.EOL; - } - } - } - // We do this at the end to ensure we test ALL the rules before failing - // the test - if (invalidSinceAttributes > 0 || invalidExternalInfoURL > 0 - || invalidClassName > 0 || invalidRegexSuppress > 0 - || invalidXPathSuppress > 0) { - fail("All built-in PMD rules need 'since' attribute (" - + invalidSinceAttributes - + " are missing), a proper ExternalURLInfo (" - + invalidExternalInfoURL - + " are invalid), a class name meeting conventions (" - + invalidClassName + " are invalid), no '" - + Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR.name() - + "' property (" + invalidRegexSuppress - + " are invalid), and no '" - + Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR.name() - + "' property (" + invalidXPathSuppress + " are invalid)" - + PMD.EOL + messages); - } - } - - @Test - public void testXmlSchema() throws IOException, RuleSetNotFoundException, - ParserConfigurationException, SAXException { - boolean allValid = true; - List ruleSetFileNames = getRuleSetFileNames(); - for (String fileName : ruleSetFileNames) { - boolean valid = validateAgainstSchema(fileName); - allValid = allValid && valid; - } - assertTrue("All XML must parse without producing validation messages.", - allValid); - } - - @Test - public void testDtd() throws IOException, RuleSetNotFoundException, - ParserConfigurationException, SAXException { - boolean allValid = true; - List ruleSetFileNames = getRuleSetFileNames(); - for (String fileName : ruleSetFileNames) { - boolean valid = validateAgainstDtd(fileName); - allValid = allValid && valid; - } - assertTrue("All XML must parse without producing validation messages.", - allValid); - } - - @Test - public void testReadWriteRoundTrip() throws IOException, - RuleSetNotFoundException, ParserConfigurationException, - SAXException { - - List ruleSetFileNames = getRuleSetFileNames(); - for (String fileName : ruleSetFileNames) { - testRuleSet(fileName); - } - } - - private void testRuleSet(String fileName) throws IOException, - RuleSetNotFoundException, ParserConfigurationException, - SAXException { - - // Load original XML -// String xml1 = readFullyToString(ResourceLoader.loadResourceAsStream(fileName)); -// System.out.println("xml1: " + xml1); - - // Load the original RuleSet - RuleSet ruleSet1 = loadRuleSetByFileName(fileName); - - // Write to XML, first time - ByteArrayOutputStream outputStream1 = new ByteArrayOutputStream(); - RuleSetWriter writer1 = new RuleSetWriter(outputStream1); - writer1.write(ruleSet1); - writer1.close(); - String xml2 = new String(outputStream1.toByteArray()); - // System.out.println("xml2: " + xml2); - - // Read RuleSet from XML, first time - RuleSetFactory ruleSetFactory = new RuleSetFactory(); - RuleSet ruleSet2 = ruleSetFactory - .createRuleSet(createRuleSetReferenceId(xml2)); - - // Do write/read a 2nd time, just to be sure - - // Write to XML, second time - ByteArrayOutputStream outputStream2 = new ByteArrayOutputStream(); - RuleSetWriter writer2 = new RuleSetWriter(outputStream2); - writer2.write(ruleSet2); - writer2.close(); - String xml3 = new String(outputStream2.toByteArray()); - // System.out.println("xml3: " + xml3); - - // Read RuleSet from XML, second time - RuleSet ruleSet3 = ruleSetFactory - .createRuleSet(createRuleSetReferenceId(xml3)); - - // The 2 written XMLs should all be valid w.r.t Schema/DTD - assertTrue( - "1st roundtrip RuleSet XML is not valid against Schema (filename: " + fileName + ")", - validateAgainstSchema(new ByteArrayInputStream(xml2.getBytes()))); - assertTrue( - "2nd roundtrip RuleSet XML is not valid against Schema (filename: " + fileName + ")", - validateAgainstSchema(new ByteArrayInputStream(xml3.getBytes()))); - assertTrue("1st roundtrip RuleSet XML is not valid against DTD (filename: " + fileName + ")", - validateAgainstDtd(new ByteArrayInputStream(xml2.getBytes()))); - assertTrue("2nd roundtrip RuleSet XML is not valid against DTD (filename: " + fileName + ")", - validateAgainstDtd(new ByteArrayInputStream(xml3.getBytes()))); - - // All 3 versions of the RuleSet should be the same - assertEqualsRuleSet( - "Original RuleSet and 1st roundtrip Ruleset not the same (filename: " + fileName + ")", - ruleSet1, ruleSet2); - assertEqualsRuleSet( - "1st roundtrip Ruleset and 2nd roundtrip RuleSet not the same (filename: " + fileName + ")", - ruleSet2, ruleSet3); - - // It's hard to compare the XML DOMs. At least the roundtrip ones should - // textually be the same. - assertEquals("1st roundtrip RuleSet XML and 2nd roundtrip RuleSet XML (filename: " + fileName + ")", - xml2, xml3); - } - - private void assertEqualsRuleSet(String message, RuleSet ruleSet1, - RuleSet ruleSet2) { - assertEquals(message + ", RuleSet name", ruleSet1.getName(), ruleSet2 - .getName()); - assertEquals(message + ", RuleSet description", ruleSet1 - .getDescription(), ruleSet2.getDescription()); - assertEquals(message + ", RuleSet exclude patterns", ruleSet1 - .getExcludePatterns(), ruleSet2.getExcludePatterns()); - assertEquals(message + ", RuleSet include patterns", ruleSet1 - .getIncludePatterns(), ruleSet2.getIncludePatterns()); - assertEquals(message + ", RuleSet rule count", ruleSet1.getRules() - .size(), ruleSet2.getRules().size()); - - for (int i = 0; i < ruleSet1.getRules().size(); i++) { - Rule rule1 = ((List) ruleSet1.getRules()).get(i); - Rule rule2 = ((List) ruleSet2.getRules()).get(i); - - assertFalse(message + ", Different RuleReference", - rule1 instanceof RuleReference - && !(rule2 instanceof RuleReference) - || !(rule1 instanceof RuleReference) - && rule2 instanceof RuleReference); - - if (rule1 instanceof RuleReference) { - RuleReference ruleReference1 = (RuleReference) rule1; - RuleReference ruleReference2 = (RuleReference) rule2; - assertEquals(message + ", RuleReference overridden language", - ruleReference1.getOverriddenLanguage(), ruleReference2 - .getOverriddenLanguage()); - assertEquals( - message - + ", RuleReference overridden minimum language version", - ruleReference1.getOverriddenMinimumLanguageVersion(), - ruleReference2.getOverriddenMinimumLanguageVersion()); - assertEquals( - message - + ", RuleReference overridden maximum language version", - ruleReference1.getOverriddenMaximumLanguageVersion(), - ruleReference2.getOverriddenMaximumLanguageVersion()); - assertEquals(message + ", RuleReference overridden deprecated", - ruleReference1.isOverriddenDeprecated(), ruleReference2 - .isOverriddenDeprecated()); - assertEquals(message + ", RuleReference overridden name", - ruleReference1.getOverriddenName(), ruleReference2 - .getOverriddenName()); - assertEquals( - message + ", RuleReference overridden description", - ruleReference1.getOverriddenDescription(), - ruleReference2.getOverriddenDescription()); - assertEquals(message + ", RuleReference overridden message", - ruleReference1.getOverriddenMessage(), ruleReference2 - .getOverriddenMessage()); - assertEquals(message - + ", RuleReference overridden external info url", - ruleReference1.getOverriddenExternalInfoUrl(), - ruleReference2.getOverriddenExternalInfoUrl()); - assertEquals(message + ", RuleReference overridden priority", - ruleReference1.getOverriddenPriority(), ruleReference2 - .getOverriddenPriority()); - assertEquals(message + ", RuleReference overridden examples", - ruleReference1.getOverriddenExamples(), ruleReference2 - .getOverriddenExamples()); - } - - assertEquals(message + ", Rule name", rule1.getName(), rule2 - .getName()); - assertEquals(message + ", Rule class", rule1.getRuleClass(), rule2 - .getRuleClass()); - assertEquals(message + ", Rule description " + rule1.getName(), - rule1.getDescription(), rule2.getDescription()); - assertEquals(message + ", Rule message", rule1.getMessage(), rule2 - .getMessage()); - assertEquals(message + ", Rule external info url", rule1 - .getExternalInfoUrl(), rule2.getExternalInfoUrl()); - assertEquals(message + ", Rule priority", rule1.getPriority(), - rule2.getPriority()); - assertEquals(message + ", Rule examples", rule1.getExamples(), - rule2.getExamples()); - - List> propertyDescriptors1 = rule1 - .getPropertyDescriptors(); - List> propertyDescriptors2 = rule2 - .getPropertyDescriptors(); - try { - assertEquals(message + ", Rule property descriptor ", - propertyDescriptors1, propertyDescriptors2); - } catch (Error e) { - throw e; - } - for (int j = 0; j < propertyDescriptors1.size(); j++) { - assertEquals(message + ", Rule property value " + j, rule1 - .getProperty(propertyDescriptors1.get(j)), rule2 - .getProperty(propertyDescriptors2.get(j))); - } - assertEquals(message + ", Rule property descriptor count", - propertyDescriptors1.size(), propertyDescriptors2.size()); - } - } - - private boolean validateAgainstSchema(String fileName) throws IOException, - RuleSetNotFoundException, ParserConfigurationException, - SAXException { - InputStream inputStream = loadResourceAsStream(fileName); - boolean valid = validateAgainstSchema(inputStream); - if (!valid) { - System.err.println("Validation against XML Schema failed for: " - + fileName); - } - return valid; - } - - private boolean validateAgainstSchema(InputStream inputStream) - throws IOException, RuleSetNotFoundException, - ParserConfigurationException, SAXException { - - saxParser.parse(inputStream, validateDefaultHandlerXsd.resetValid()); - inputStream.close(); - return validateDefaultHandlerXsd.isValid(); - } - - private boolean validateAgainstDtd(String fileName) throws IOException, - RuleSetNotFoundException, ParserConfigurationException, - SAXException { - InputStream inputStream = loadResourceAsStream(fileName); - boolean valid = validateAgainstDtd(inputStream); - if (!valid) { - System.err - .println("Validation against DTD failed for: " + fileName); - } - return valid; - } - - private boolean validateAgainstDtd(InputStream inputStream) - throws IOException, RuleSetNotFoundException, - ParserConfigurationException, SAXException { - - // Read file into memory - String file = readFullyToString(inputStream); - - // Remove XML Schema stuff, replace with DTD - file = file.replaceAll("<\\?xml [ a-zA-Z0-9=\".-]*\\?>", ""); - file = file.replaceAll( - "xmlns=\"" + RuleSetWriter.RULESET_NS_URI + "\"", ""); - file = file.replaceAll( - "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", ""); - file = file - .replaceAll( - "xsi:schemaLocation=\"" + RuleSetWriter.RULESET_NS_URI + " http://pmd.sourceforge.net/ruleset_2_0_0.xsd\"", - ""); - - file = "" + PMD.EOL - + "" - + PMD.EOL + file; - - inputStream = new ByteArrayInputStream(file.getBytes()); - - saxParser.parse(inputStream, validateDefaultHandlerDtd.resetValid()); - inputStream.close(); - return validateDefaultHandlerDtd.isValid(); - } - - private String readFullyToString(InputStream inputStream) - throws IOException { - StringBuilder buf = new StringBuilder(64 * 1024); - BufferedReader reader = new BufferedReader(new InputStreamReader( - inputStream)); - String line; - while ((line = reader.readLine()) != null) { - buf.append(line); - buf.append(PMD.EOL); - } - reader.close(); - return buf.toString(); - } - - // Gets all test PMD Ruleset XML files - private List getRuleSetFileNames() throws IOException, - RuleSetNotFoundException { - List result = new ArrayList(); - - for (Language language : LanguageRegistry.getLanguages()) { - result.addAll(getRuleSetFileNames(language.getTerseName())); - } - - return result; - } - - private List getRuleSetFileNames(String language) throws IOException, RuleSetNotFoundException { - List ruleSetFileNames = new ArrayList(); - try { - Properties properties = new Properties(); - properties.load(ResourceLoader.loadResourceAsStream("rulesets/" + language + "/rulesets.properties")); - String fileNames = properties.getProperty("rulesets.filenames"); - StringTokenizer st = new StringTokenizer(fileNames, ","); - while (st.hasMoreTokens()) { - ruleSetFileNames.add(st.nextToken()); - } - } catch (RuleSetNotFoundException e) { - // this might happen if a language is only support by CPD, but not by PMD - System.err.println("No ruleset found for language " + language); - } - return ruleSetFileNames; - } - - private static class ValidateDefaultHandler extends DefaultHandler { - private final String validateDocument; - private boolean valid = true; - - public ValidateDefaultHandler(String validateDocument) { - this.validateDocument = validateDocument; - } - - public ValidateDefaultHandler resetValid() { - valid = true; - return this; - } - - public boolean isValid() { - return valid; - } - - @Override - public void error(SAXParseException e) throws SAXException { - log("Error", e); - } - - @Override - public void fatalError(SAXParseException e) throws SAXException { - log("FatalError", e); - } - - @Override - public void warning(SAXParseException e) throws SAXException { - log("Warning", e); - } - - private void log(String prefix, SAXParseException e) { - String message = prefix + " at (" + e.getLineNumber() + ", " + e.getColumnNumber() + "): " + e.getMessage(); - System.err.println(message); - valid = false; - } - - @Override - public InputSource resolveEntity(String publicId, String systemId) - throws IOException, SAXException { - if ("http://pmd.sourceforge.net/ruleset_2_0_0.xsd".equals(systemId) - || systemId.endsWith("ruleset_2_0_0.dtd")) { - try { - InputStream inputStream = loadResourceAsStream(validateDocument); - return new InputSource(inputStream); - } catch (RuleSetNotFoundException e) { - System.err.println(e.getMessage()); - throw new IOException(e.getMessage()); - } - } - throw new IllegalArgumentException( - "No clue how to handle: publicId=" + publicId - + ", systemId=" + systemId); - } - } - - private static InputStream loadResourceAsStream(String resource) - throws RuleSetNotFoundException { - InputStream inputStream = ResourceLoader.loadResourceAsStream(resource, - RuleSetFactoryTest.class.getClassLoader()); - if (inputStream == null) { - throw new RuleSetNotFoundException( - "Can't find resource " - + resource - + " Make sure the resource is a valid file or URL or is on the CLASSPATH. Here's the current classpath: " - + System.getProperty("java.class.path")); - } - return inputStream; - } - private static final String REF_OVERRIDE_ORIGINAL_NAME = "" + PMD.EOL + "" @@ -1476,12 +933,6 @@ public class RuleSetFactoryTest { return rs.getRules().iterator().next(); } - private RuleSet loadRuleSetByFileName(String ruleSetFileName) - throws RuleSetNotFoundException { - RuleSetFactory rsf = new RuleSetFactory(); - return rsf.createRuleSet(ruleSetFileName); - } - private RuleSet loadRuleSet(String ruleSetXml) throws RuleSetNotFoundException { RuleSetFactory rsf = new RuleSetFactory(); diff --git a/pmd-java/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java b/pmd-java/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java new file mode 100644 index 0000000000..3edeba0208 --- /dev/null +++ b/pmd-java/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java @@ -0,0 +1,35 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package net.sourceforge.pmd; + +import static org.junit.Assert.assertNull; + +import org.junit.Test; + +/** + * Test java's rulesets + */ +public class RuleSetFactoryTest extends AbstractRuleSetFactoryTest { + + @Test + public void testExclusionOfUselessParantheses() throws RuleSetNotFoundException { + RuleSetReferenceId ref = createRuleSetReferenceId("\n" + + "\n" + + " Custom ruleset for tests\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "\n"); + RuleSetFactory ruleSetFactory = new RuleSetFactory(); + RuleSet ruleset = ruleSetFactory.createRuleSet(ref); + Rule rule = ruleset.getRuleByName("UselessParentheses"); + assertNull(rule); + } +} diff --git a/pmd-javascript/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java b/pmd-javascript/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java new file mode 100644 index 0000000000..0fae78b02d --- /dev/null +++ b/pmd-javascript/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java @@ -0,0 +1,12 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package net.sourceforge.pmd; + + +/** + * Test javascript's rulesets + */ +public class RuleSetFactoryTest extends AbstractRuleSetFactoryTest { + // no additional tests yet +} diff --git a/pmd-jsp/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java b/pmd-jsp/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java new file mode 100644 index 0000000000..c1b168ab16 --- /dev/null +++ b/pmd-jsp/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java @@ -0,0 +1,12 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package net.sourceforge.pmd; + + +/** + * Test jsp's rulesets + */ +public class RuleSetFactoryTest extends AbstractRuleSetFactoryTest { + // no additional tests yet +} diff --git a/pmd-plsql/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java b/pmd-plsql/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java new file mode 100644 index 0000000000..7aa82a2e39 --- /dev/null +++ b/pmd-plsql/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java @@ -0,0 +1,12 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package net.sourceforge.pmd; + + +/** + * Test plsql's rulesets + */ +public class RuleSetFactoryTest extends AbstractRuleSetFactoryTest { + // no additional tests yet +} diff --git a/pmd-test/src/main/java/net/sourceforge/pmd/AbstractRuleSetFactoryTest.java b/pmd-test/src/main/java/net/sourceforge/pmd/AbstractRuleSetFactoryTest.java new file mode 100644 index 0000000000..8abbbea5a2 --- /dev/null +++ b/pmd-test/src/main/java/net/sourceforge/pmd/AbstractRuleSetFactoryTest.java @@ -0,0 +1,556 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package net.sourceforge.pmd; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.BufferedReader; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.UnsupportedEncodingException; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; +import java.util.StringTokenizer; + +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; + +import net.sourceforge.pmd.lang.Language; +import net.sourceforge.pmd.lang.LanguageRegistry; +import net.sourceforge.pmd.lang.rule.RuleReference; +import net.sourceforge.pmd.lang.rule.XPathRule; +import net.sourceforge.pmd.util.ResourceLoader; + +import org.junit.BeforeClass; +import org.junit.Test; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +import org.xml.sax.helpers.DefaultHandler; + +/** + * Base test class to verify the language's rulesets. + * This class should be subclassed for each language. + */ +public abstract class AbstractRuleSetFactoryTest { + private static SAXParserFactory saxParserFactory; + private static ValidateDefaultHandler validateDefaultHandlerXsd; + private static ValidateDefaultHandler validateDefaultHandlerDtd; + private static SAXParser saxParser; + + /** + * Setups the XML parser with validation. + * @throws Exception any error + */ + @BeforeClass + public static void init() throws Exception { + saxParserFactory = SAXParserFactory.newInstance(); + saxParserFactory.setValidating(true); + saxParserFactory.setNamespaceAware(true); + + // Hope we're using Xerces, or this may not work! + // Note: Features are listed here + // http://xerces.apache.org/xerces2-j/features.html + saxParserFactory.setFeature("http://xml.org/sax/features/validation", + true); + saxParserFactory.setFeature( + "http://apache.org/xml/features/validation/schema", true); + saxParserFactory + .setFeature( + "http://apache.org/xml/features/validation/schema-full-checking", + true); + + validateDefaultHandlerXsd = new ValidateDefaultHandler("ruleset_2_0_0.xsd"); + validateDefaultHandlerDtd = new ValidateDefaultHandler("ruleset_2_0_0.dtd"); + + saxParser = saxParserFactory.newSAXParser(); + } + + /** + * Checks all rulesets of all languages on the classpath and verifies that all required attributes + * for all rules are specified. + * @throws Exception any error + */ + @Test + public void testAllPMDBuiltInRulesMeetConventions() throws Exception { + int invalidSinceAttributes = 0; + int invalidExternalInfoURL = 0; + int invalidClassName = 0; + int invalidRegexSuppress = 0; + int invalidXPathSuppress = 0; + String messages = ""; + List ruleSetFileNames = getRuleSetFileNames(); + for (String fileName : ruleSetFileNames) { + RuleSet ruleSet = loadRuleSetByFileName(fileName); + for (Rule rule : ruleSet.getRules()) { + + // Skip references + if (rule instanceof RuleReference) { + continue; + } + + Language language = rule.getLanguage(); + String group = fileName.substring(fileName.lastIndexOf('/') + 1); + group = group.substring(0, group.indexOf(".xml")); + if (group.indexOf('-') >= 0) { + group = group.substring(0, group.indexOf('-')); + } + + // Is since missing ? + if (rule.getSince() == null) { + invalidSinceAttributes++; + messages += "Rule " + fileName + "/" + rule.getName() + " is missing 'since' attribute" + PMD.EOL; + } + // Is URL valid ? + if (rule.getExternalInfoUrl() == null || "".equalsIgnoreCase(rule.getExternalInfoUrl())) { + invalidExternalInfoURL++; + messages += "Rule " + fileName + "/" + rule.getName() + " is missing 'externalInfoURL' attribute" + + PMD.EOL; + } else { + String expectedExternalInfoURL = "http://pmd.sourceforge.net/.+/rules/" + + fileName.replaceAll("rulesets/", "").replaceAll(".xml", "") + ".html#" + rule.getName(); + if (rule.getExternalInfoUrl() == null + || !rule.getExternalInfoUrl().matches(expectedExternalInfoURL)) { + invalidExternalInfoURL++; + messages += "Rule " + fileName + "/" + rule.getName() + + " seems to have an invalid 'externalInfoURL' value (" + rule.getExternalInfoUrl() + + "), it should be:" + expectedExternalInfoURL + PMD.EOL; + } + } + // Proper class name/packaging? + String expectedClassName = "net.sourceforge.pmd.lang." + language.getTerseName() + ".rule." + group + + "." + rule.getName() + "Rule"; + if (!rule.getRuleClass().equals(expectedClassName) + && !rule.getRuleClass().equals(XPathRule.class.getName())) { + invalidClassName++; + messages += "Rule " + fileName + "/" + rule.getName() + " seems to have an invalid 'class' value (" + + rule.getRuleClass() + "), it should be:" + expectedClassName + PMD.EOL; + } + // Should not have violation suppress regex property + if (rule.getProperty(Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR) != null) { + invalidRegexSuppress++; + messages += "Rule " + fileName + "/" + rule.getName() + " should not have '" + + Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR.name() + + "', this is intended for end user customization only." + PMD.EOL; + } + // Should not have violation suppress xpath property + if (rule.getProperty(Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR) != null) { + invalidXPathSuppress++; + messages += "Rule " + fileName + "/" + rule.getName() + " should not have '" + + Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR.name() + + "', this is intended for end user customization only." + PMD.EOL; + } + } + } + // We do this at the end to ensure we test ALL the rules before failing + // the test + if (invalidSinceAttributes > 0 || invalidExternalInfoURL > 0 || invalidClassName > 0 + || invalidRegexSuppress > 0 || invalidXPathSuppress > 0) { + fail("All built-in PMD rules need 'since' attribute (" + invalidSinceAttributes + + " are missing), a proper ExternalURLInfo (" + invalidExternalInfoURL + + " are invalid), a class name meeting conventions (" + invalidClassName + " are invalid), no '" + + Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR.name() + "' property (" + invalidRegexSuppress + + " are invalid), and no '" + Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR.name() + "' property (" + + invalidXPathSuppress + " are invalid)" + PMD.EOL + messages); + } + } + + /** + * Verifies that all rulesets are valid XML according to the xsd schema. + * @throws Exception any error + */ + @Test + public void testXmlSchema() throws Exception { + boolean allValid = true; + List ruleSetFileNames = getRuleSetFileNames(); + for (String fileName : ruleSetFileNames) { + boolean valid = validateAgainstSchema(fileName); + allValid = allValid && valid; + } + assertTrue("All XML must parse without producing validation messages.", allValid); + } + + /** + * Verifies that all rulesets are valid XML according to the DTD. + * @throws Exception any error + */ + @Test + public void testDtd() throws Exception { + boolean allValid = true; + List ruleSetFileNames = getRuleSetFileNames(); + for (String fileName : ruleSetFileNames) { + boolean valid = validateAgainstDtd(fileName); + allValid = allValid && valid; + } + assertTrue("All XML must parse without producing validation messages.", allValid); + } + + /** + * Reads and writes the rulesets to make sure, that no data is lost if the rulests are + * processed. + * @throws Exception any error + */ + @Test + public void testReadWriteRoundTrip() throws Exception { + + List ruleSetFileNames = getRuleSetFileNames(); + for (String fileName : ruleSetFileNames) { + testRuleSet(fileName); + } + } + + // Gets all test PMD Ruleset XML files + private List getRuleSetFileNames() throws IOException, RuleSetNotFoundException { + List result = new ArrayList(); + + for (Language language : LanguageRegistry.getLanguages()) { + result.addAll(getRuleSetFileNames(language.getTerseName())); + } + + return result; + } + + private List getRuleSetFileNames(String language) throws IOException, RuleSetNotFoundException { + List ruleSetFileNames = new ArrayList(); + try { + Properties properties = new Properties(); + properties.load(ResourceLoader.loadResourceAsStream("rulesets/" + language + "/rulesets.properties")); + String fileNames = properties.getProperty("rulesets.filenames"); + StringTokenizer st = new StringTokenizer(fileNames, ","); + while (st.hasMoreTokens()) { + ruleSetFileNames.add(st.nextToken()); + } + } catch (RuleSetNotFoundException e) { + // this might happen if a language is only support by CPD, but not + // by PMD + System.err.println("No ruleset found for language " + language); + } + return ruleSetFileNames; + } + + private RuleSet loadRuleSetByFileName(String ruleSetFileName) throws RuleSetNotFoundException { + RuleSetFactory rsf = new RuleSetFactory(); + return rsf.createRuleSet(ruleSetFileName); + } + + private boolean validateAgainstSchema(String fileName) throws IOException, RuleSetNotFoundException, + ParserConfigurationException, SAXException { + InputStream inputStream = loadResourceAsStream(fileName); + boolean valid = validateAgainstSchema(inputStream); + if (!valid) { + System.err.println("Validation against XML Schema failed for: " + fileName); + } + return valid; + } + + private boolean validateAgainstSchema(InputStream inputStream) throws IOException, RuleSetNotFoundException, + ParserConfigurationException, SAXException { + + saxParser.parse(inputStream, validateDefaultHandlerXsd.resetValid()); + inputStream.close(); + return validateDefaultHandlerXsd.isValid(); + } + + private boolean validateAgainstDtd(String fileName) throws IOException, RuleSetNotFoundException, + ParserConfigurationException, SAXException { + InputStream inputStream = loadResourceAsStream(fileName); + boolean valid = validateAgainstDtd(inputStream); + if (!valid) { + System.err.println("Validation against DTD failed for: " + fileName); + } + return valid; + } + + private boolean validateAgainstDtd(InputStream inputStream) throws IOException, RuleSetNotFoundException, + ParserConfigurationException, SAXException { + + // Read file into memory + String file = readFullyToString(inputStream); + inputStream.close(); + + // Remove XML Schema stuff, replace with DTD + file = file.replaceAll("<\\?xml [ a-zA-Z0-9=\".-]*\\?>", ""); + file = file.replaceAll("xmlns=\"" + RuleSetWriter.RULESET_NS_URI + "\"", ""); + file = file.replaceAll("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", ""); + file = file.replaceAll("xsi:schemaLocation=\"" + RuleSetWriter.RULESET_NS_URI + + " http://pmd.sourceforge.net/ruleset_2_0_0.xsd\"", ""); + + file = "" + PMD.EOL + "" + PMD.EOL + file; + + InputStream modifiedStream = new ByteArrayInputStream(file.getBytes()); + + saxParser.parse(modifiedStream, validateDefaultHandlerDtd.resetValid()); + modifiedStream.close(); + return validateDefaultHandlerDtd.isValid(); + } + + private String readFullyToString(InputStream inputStream) throws IOException { + StringBuilder buf = new StringBuilder(64 * 1024); + BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream)); + String line; + while ((line = reader.readLine()) != null) { + buf.append(line); + buf.append(PMD.EOL); + } + reader.close(); + return buf.toString(); + } + + private static InputStream loadResourceAsStream(String resource) throws RuleSetNotFoundException { + InputStream inputStream = ResourceLoader.loadResourceAsStream(resource, + AbstractRuleSetFactoryTest.class.getClassLoader()); + if (inputStream == null) { + throw new RuleSetNotFoundException( + "Can't find resource " + + resource + + " Make sure the resource is a valid file or URL or is on the CLASSPATH. Here's the current classpath: " + + System.getProperty("java.class.path")); + } + return inputStream; + } + + private void testRuleSet(String fileName) throws IOException, RuleSetNotFoundException, + ParserConfigurationException, SAXException { + + // Load original XML + // String xml1 = + // readFullyToString(ResourceLoader.loadResourceAsStream(fileName)); + // System.out.println("xml1: " + xml1); + + // Load the original RuleSet + RuleSet ruleSet1 = loadRuleSetByFileName(fileName); + + // Write to XML, first time + ByteArrayOutputStream outputStream1 = new ByteArrayOutputStream(); + RuleSetWriter writer1 = new RuleSetWriter(outputStream1); + writer1.write(ruleSet1); + writer1.close(); + String xml2 = new String(outputStream1.toByteArray()); + // System.out.println("xml2: " + xml2); + + // Read RuleSet from XML, first time + RuleSetFactory ruleSetFactory = new RuleSetFactory(); + RuleSet ruleSet2 = ruleSetFactory.createRuleSet(createRuleSetReferenceId(xml2)); + + // Do write/read a 2nd time, just to be sure + + // Write to XML, second time + ByteArrayOutputStream outputStream2 = new ByteArrayOutputStream(); + RuleSetWriter writer2 = new RuleSetWriter(outputStream2); + writer2.write(ruleSet2); + writer2.close(); + String xml3 = new String(outputStream2.toByteArray()); + // System.out.println("xml3: " + xml3); + + // Read RuleSet from XML, second time + RuleSet ruleSet3 = ruleSetFactory.createRuleSet(createRuleSetReferenceId(xml3)); + + // The 2 written XMLs should all be valid w.r.t Schema/DTD + assertTrue("1st roundtrip RuleSet XML is not valid against Schema (filename: " + fileName + ")", + validateAgainstSchema(new ByteArrayInputStream(xml2.getBytes()))); + assertTrue("2nd roundtrip RuleSet XML is not valid against Schema (filename: " + fileName + ")", + validateAgainstSchema(new ByteArrayInputStream(xml3.getBytes()))); + assertTrue("1st roundtrip RuleSet XML is not valid against DTD (filename: " + fileName + ")", + validateAgainstDtd(new ByteArrayInputStream(xml2.getBytes()))); + assertTrue("2nd roundtrip RuleSet XML is not valid against DTD (filename: " + fileName + ")", + validateAgainstDtd(new ByteArrayInputStream(xml3.getBytes()))); + + // All 3 versions of the RuleSet should be the same + assertEqualsRuleSet("Original RuleSet and 1st roundtrip Ruleset not the same (filename: " + fileName + ")", + ruleSet1, ruleSet2); + assertEqualsRuleSet( + "1st roundtrip Ruleset and 2nd roundtrip RuleSet not the same (filename: " + fileName + ")", ruleSet2, + ruleSet3); + + // It's hard to compare the XML DOMs. At least the roundtrip ones should + // textually be the same. + assertEquals("1st roundtrip RuleSet XML and 2nd roundtrip RuleSet XML (filename: " + fileName + ")", xml2, xml3); + } + + private void assertEqualsRuleSet(String message, RuleSet ruleSet1, + RuleSet ruleSet2) { + assertEquals(message + ", RuleSet name", ruleSet1.getName(), ruleSet2 + .getName()); + assertEquals(message + ", RuleSet description", ruleSet1 + .getDescription(), ruleSet2.getDescription()); + assertEquals(message + ", RuleSet exclude patterns", ruleSet1 + .getExcludePatterns(), ruleSet2.getExcludePatterns()); + assertEquals(message + ", RuleSet include patterns", ruleSet1 + .getIncludePatterns(), ruleSet2.getIncludePatterns()); + assertEquals(message + ", RuleSet rule count", ruleSet1.getRules() + .size(), ruleSet2.getRules().size()); + + for (int i = 0; i < ruleSet1.getRules().size(); i++) { + Rule rule1 = ((List) ruleSet1.getRules()).get(i); + Rule rule2 = ((List) ruleSet2.getRules()).get(i); + + assertFalse(message + ", Different RuleReference", + rule1 instanceof RuleReference + && !(rule2 instanceof RuleReference) + || !(rule1 instanceof RuleReference) + && rule2 instanceof RuleReference); + + if (rule1 instanceof RuleReference) { + RuleReference ruleReference1 = (RuleReference) rule1; + RuleReference ruleReference2 = (RuleReference) rule2; + assertEquals(message + ", RuleReference overridden language", + ruleReference1.getOverriddenLanguage(), ruleReference2 + .getOverriddenLanguage()); + assertEquals( + message + + ", RuleReference overridden minimum language version", + ruleReference1.getOverriddenMinimumLanguageVersion(), + ruleReference2.getOverriddenMinimumLanguageVersion()); + assertEquals( + message + + ", RuleReference overridden maximum language version", + ruleReference1.getOverriddenMaximumLanguageVersion(), + ruleReference2.getOverriddenMaximumLanguageVersion()); + assertEquals(message + ", RuleReference overridden deprecated", + ruleReference1.isOverriddenDeprecated(), ruleReference2 + .isOverriddenDeprecated()); + assertEquals(message + ", RuleReference overridden name", + ruleReference1.getOverriddenName(), ruleReference2 + .getOverriddenName()); + assertEquals( + message + ", RuleReference overridden description", + ruleReference1.getOverriddenDescription(), + ruleReference2.getOverriddenDescription()); + assertEquals(message + ", RuleReference overridden message", + ruleReference1.getOverriddenMessage(), ruleReference2 + .getOverriddenMessage()); + assertEquals(message + + ", RuleReference overridden external info url", + ruleReference1.getOverriddenExternalInfoUrl(), + ruleReference2.getOverriddenExternalInfoUrl()); + assertEquals(message + ", RuleReference overridden priority", + ruleReference1.getOverriddenPriority(), ruleReference2 + .getOverriddenPriority()); + assertEquals(message + ", RuleReference overridden examples", + ruleReference1.getOverriddenExamples(), ruleReference2 + .getOverriddenExamples()); + } + + assertEquals(message + ", Rule name", rule1.getName(), rule2 + .getName()); + assertEquals(message + ", Rule class", rule1.getRuleClass(), rule2 + .getRuleClass()); + assertEquals(message + ", Rule description " + rule1.getName(), + rule1.getDescription(), rule2.getDescription()); + assertEquals(message + ", Rule message", rule1.getMessage(), rule2 + .getMessage()); + assertEquals(message + ", Rule external info url", rule1 + .getExternalInfoUrl(), rule2.getExternalInfoUrl()); + assertEquals(message + ", Rule priority", rule1.getPriority(), + rule2.getPriority()); + assertEquals(message + ", Rule examples", rule1.getExamples(), + rule2.getExamples()); + + List> propertyDescriptors1 = rule1 + .getPropertyDescriptors(); + List> propertyDescriptors2 = rule2 + .getPropertyDescriptors(); + try { + assertEquals(message + ", Rule property descriptor ", + propertyDescriptors1, propertyDescriptors2); + } catch (Error e) { + throw e; + } + for (int j = 0; j < propertyDescriptors1.size(); j++) { + assertEquals(message + ", Rule property value " + j, rule1 + .getProperty(propertyDescriptors1.get(j)), rule2 + .getProperty(propertyDescriptors2.get(j))); + } + assertEquals(message + ", Rule property descriptor count", + propertyDescriptors1.size(), propertyDescriptors2.size()); + } + } + + /** + * Create a {@link RuleSetReferenceId} by the given XML string. + * @param ruleSetXml the ruleset file content as string + * @return the {@link RuleSetReferenceId} + */ + protected static RuleSetReferenceId createRuleSetReferenceId(final String ruleSetXml) { + return new RuleSetReferenceId(null) { + @Override + public InputStream getInputStream(ClassLoader classLoader) throws RuleSetNotFoundException { + try { + return new ByteArrayInputStream(ruleSetXml.getBytes("UTF-8")); + } catch (UnsupportedEncodingException e) { + return null; + } + } + }; + } + + /** + * Validator for the SAX parser + */ + private static class ValidateDefaultHandler extends DefaultHandler { + private final String validateDocument; + private boolean valid = true; + + public ValidateDefaultHandler(String validateDocument) { + this.validateDocument = validateDocument; + } + + public ValidateDefaultHandler resetValid() { + valid = true; + return this; + } + + public boolean isValid() { + return valid; + } + + @Override + public void error(SAXParseException e) throws SAXException { + log("Error", e); + } + + @Override + public void fatalError(SAXParseException e) throws SAXException { + log("FatalError", e); + } + + @Override + public void warning(SAXParseException e) throws SAXException { + log("Warning", e); + } + + private void log(String prefix, SAXParseException e) { + String message = prefix + " at (" + e.getLineNumber() + ", " + e.getColumnNumber() + "): " + e.getMessage(); + System.err.println(message); + valid = false; + } + + @Override + public InputSource resolveEntity(String publicId, String systemId) + throws IOException, SAXException { + if ("http://pmd.sourceforge.net/ruleset_2_0_0.xsd".equals(systemId) + || systemId.endsWith("ruleset_2_0_0.dtd")) { + try { + InputStream inputStream = loadResourceAsStream(validateDocument); + return new InputSource(inputStream); + } catch (RuleSetNotFoundException e) { + System.err.println(e.getMessage()); + throw new IOException(e.getMessage()); + } + } + throw new IllegalArgumentException( + "No clue how to handle: publicId=" + publicId + + ", systemId=" + systemId); + } + } + +} diff --git a/pmd-vm/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java b/pmd-vm/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java new file mode 100644 index 0000000000..9b720022f6 --- /dev/null +++ b/pmd-vm/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java @@ -0,0 +1,12 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package net.sourceforge.pmd; + + +/** + * Test velocity's rulesets + */ +public class RuleSetFactoryTest extends AbstractRuleSetFactoryTest { + // no additional tests yet +} diff --git a/pmd-xml/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java b/pmd-xml/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java new file mode 100644 index 0000000000..3035e532be --- /dev/null +++ b/pmd-xml/src/test/java/net/sourceforge/pmd/RuleSetFactoryTest.java @@ -0,0 +1,12 @@ +/** + * BSD-style license; for more info see http://pmd.sourceforge.net/license.html + */ +package net.sourceforge.pmd; + + +/** + * Test xml's and xslt's rulesets + */ +public class RuleSetFactoryTest extends AbstractRuleSetFactoryTest { + // no additional tests yet +}