RuleSetFactoryTest xref
1 /**
2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 */
4 package net.sourceforge.pmd;
5
6 import static org.junit.Assert.assertEquals;
7 import static org.junit.Assert.assertFalse;
8 import static org.junit.Assert.assertNotNull;
9 import static org.junit.Assert.assertNotSame;
10 import static org.junit.Assert.assertNull;
11 import static org.junit.Assert.assertTrue;
12 import static org.junit.Assert.fail;
13
14 import java.io.BufferedReader;
15 import java.io.ByteArrayInputStream;
16 import java.io.ByteArrayOutputStream;
17 import java.io.IOException;
18 import java.io.InputStream;
19 import java.io.InputStreamReader;
20 import java.util.ArrayList;
21 import java.util.HashSet;
22 import java.util.List;
23 import java.util.Properties;
24 import java.util.Set;
25 import java.util.StringTokenizer;
26
27 import javax.xml.parsers.ParserConfigurationException;
28 import javax.xml.parsers.SAXParser;
29 import javax.xml.parsers.SAXParserFactory;
30
31 import junit.framework.Assert;
32 import junit.framework.JUnit4TestAdapter;
33 import net.sourceforge.pmd.lang.Language;
34 import net.sourceforge.pmd.lang.LanguageVersion;
35 import net.sourceforge.pmd.lang.java.rule.unusedcode.UnusedLocalVariableRule;
36 import net.sourceforge.pmd.lang.rule.RuleReference;
37 import net.sourceforge.pmd.lang.rule.XPathRule;
38 import net.sourceforge.pmd.util.ResourceLoader;
39
40 import org.junit.BeforeClass;
41 import org.junit.Test;
42 import org.xml.sax.InputSource;
43 import org.xml.sax.SAXException;
44 import org.xml.sax.SAXParseException;
45 import org.xml.sax.helpers.DefaultHandler;
46
47 public class RuleSetFactoryTest {
48 private static SAXParserFactory saxParserFactory;
49 private static ValidateDefaultHandler validateDefaultHandlerXsd;
50 private static ValidateDefaultHandler validateDefaultHandlerDtd;
51 private static SAXParser saxParser;
52
53 @BeforeClass
54 public static void init() throws Exception {
55 saxParserFactory = SAXParserFactory.newInstance();
56 saxParserFactory.setValidating(true);
57 saxParserFactory.setNamespaceAware(true);
58
59 // Hope we're using Xerces, or this may not work!
60 // Note: Features are listed here
61 // http://xerces.apache.org/xerces2-j/features.html
62 saxParserFactory.setFeature("http://xml.org/sax/features/validation",
63 true);
64 saxParserFactory.setFeature(
65 "http://apache.org/xml/features/validation/schema", true);
66 saxParserFactory
67 .setFeature(
68 "http://apache.org/xml/features/validation/schema-full-checking",
69 true);
70
71 validateDefaultHandlerXsd = new ValidateDefaultHandler("src/main/resources/ruleset_2_0_0.xsd");
72 validateDefaultHandlerDtd = new ValidateDefaultHandler("src/main/resources/ruleset_2_0_0.dtd");
73
74 saxParser = saxParserFactory.newSAXParser();
75 }
76
77 @Test
78 public void testRuleSetFileName() throws RuleSetNotFoundException {
79 RuleSet rs = loadRuleSet(EMPTY_RULESET);
80 assertNull("RuleSet file name not expected", rs.getFileName());
81
82 RuleSetFactory rsf = new RuleSetFactory();
83 rs = rsf.createRuleSet("rulesets/java/basic.xml");
84 assertEquals("wrong RuleSet file name", rs.getFileName(),
85 "rulesets/java/basic.xml");
86 }
87
88 @Test
89 public void testNoRuleSetFileName() throws RuleSetNotFoundException {
90 RuleSet rs = loadRuleSet(EMPTY_RULESET);
91 assertNull("RuleSet file name not expected", rs.getFileName());
92 }
93
94 @Test
95 public void testRefs() throws Throwable {
96 InputStream in = ResourceLoader.loadResourceAsStream(
97 "rulesets/java/migrating_to_15.xml", this.getClass()
98 .getClassLoader());
99 if (in == null) {
100 throw new RuleSetNotFoundException(
101 "Can't find resource Make sure the resource is a valid file or URL or is on the CLASSPATH. Here's the current classpath: "
102 + System.getProperty("java.class.path"));
103 }
104 RuleSetFactory rsf = new RuleSetFactory();
105 RuleSet rs = rsf.createRuleSet("rulesets/java/migrating_to_15.xml");
106 assertNotNull(rs.getRuleByName("AvoidEnumAsIdentifier"));
107 }
108
109 @Test
110 public void testExtendedReferences() throws Exception {
111 InputStream in = ResourceLoader.loadResourceAsStream("net/sourceforge/pmd/rulesets/reference-ruleset.xml",
112 this.getClass().getClassLoader());
113 Assert.assertNotNull("Test ruleset not found - can't continue with test!", in);
114
115 RuleSetFactory rsf = new RuleSetFactory();
116 RuleSets rs = rsf.createRuleSets("net/sourceforge/pmd/rulesets/reference-ruleset.xml");
117 // added by referencing a complete ruleset (java-basic)
118 assertNotNull(rs.getRuleByName("JumbledIncrementer"));
119 assertNotNull(rs.getRuleByName("ForLoopShouldBeWhileLoop"));
120 assertNotNull(rs.getRuleByName("OverrideBothEqualsAndHashcode"));
121
122 // added by specific reference
123 assertNotNull(rs.getRuleByName("UnusedLocalVariable"));
124 assertNotNull(rs.getRuleByName("DuplicateImports"));
125 // this is from java-unusedcode, but not referenced
126 assertNull(rs.getRuleByName("UnusedPrivateField"));
127
128 Rule emptyCatchBlock = rs.getRuleByName("EmptyCatchBlock");
129 assertNotNull(emptyCatchBlock);
130
131 Rule collapsibleIfStatements = rs.getRuleByName("CollapsibleIfStatements");
132 assertEquals("Just combine them!", collapsibleIfStatements.getMessage());
133 // assert that CollapsibleIfStatements is only once added to the ruleset, so that it really
134 // overwrites the configuration inherited from java/basic.xml
135 assertEquals(1, countRule(rs, "CollapsibleIfStatements"));
136
137 Rule cyclomaticComplexity = rs.getRuleByName("CyclomaticComplexity");
138 assertNotNull(cyclomaticComplexity);
139 PropertyDescriptor<?> prop = cyclomaticComplexity.getPropertyDescriptor("reportLevel");
140 Object property = cyclomaticComplexity.getProperty(prop);
141 assertEquals("5", String.valueOf(property));
142
143 // included from braces
144 assertNotNull(rs.getRuleByName("IfStmtsMustUseBraces"));
145 // excluded from braces
146 assertNull(rs.getRuleByName("WhileLoopsMustUseBraces"));
147
148 // overridden to 5
149 Rule simplifyBooleanExpressions = rs.getRuleByName("SimplifyBooleanExpressions");
150 assertNotNull(simplifyBooleanExpressions);
151 assertEquals(5, simplifyBooleanExpressions.getPriority().getPriority());
152 assertEquals(1, countRule(rs, "SimplifyBooleanExpressions"));
153 // priority overridden for whole design group
154 Rule useUtilityClass = rs.getRuleByName("UseUtilityClass");
155 assertNotNull(useUtilityClass);
156 assertEquals(2, useUtilityClass.getPriority().getPriority());
157 Rule simplifyBooleanReturns = rs.getRuleByName("SimplifyBooleanReturns");
158 assertNotNull(simplifyBooleanReturns);
159 assertEquals(2, simplifyBooleanReturns.getPriority().getPriority());
160 }
161
162 private int countRule(RuleSets rs, String ruleName) {
163 int count = 0;
164 for (Rule r : rs.getAllRules()) {
165 if (ruleName.equals(r.getName())) {
166 count++;
167 }
168 }
169 return count;
170 }
171
172 @Test(expected = RuleSetNotFoundException.class)
173 public void testRuleSetNotFound() throws RuleSetNotFoundException {
174 RuleSetFactory rsf = new RuleSetFactory();
175 rsf.createRuleSet("fooooo");
176 }
177
178 @Test
179 public void testCreateEmptyRuleSet() throws RuleSetNotFoundException {
180 RuleSet rs = loadRuleSet(EMPTY_RULESET);
181 assertEquals("test", rs.getName());
182 assertEquals(0, rs.size());
183 }
184
185 @Test
186 public void testSingleRule() throws RuleSetNotFoundException {
187 RuleSet rs = loadRuleSet(SINGLE_RULE);
188 assertEquals(1, rs.size());
189 Rule r = rs.getRules().iterator().next();
190 assertEquals("MockRuleName", r.getName());
191 assertEquals("net.sourceforge.pmd.lang.rule.MockRule", r.getRuleClass());
192 assertEquals("avoid the mock rule", r.getMessage());
193 }
194
195 @Test
196 public void testMultipleRules() throws RuleSetNotFoundException {
197 RuleSet rs = loadRuleSet(MULTIPLE_RULES);
198 assertEquals(2, rs.size());
199 Set<String> expected = new HashSet<String>();
200 expected.add("MockRuleName1");
201 expected.add("MockRuleName2");
202 for (Rule rule : rs.getRules()) {
203 assertTrue(expected.contains(rule.getName()));
204 }
205 }
206
207 @Test
208 public void testSingleRuleWithPriority() throws RuleSetNotFoundException {
209 assertEquals(RulePriority.MEDIUM, loadFirstRule(PRIORITY).getPriority());
210 }
211
212 @Test
213 @SuppressWarnings("unchecked")
214 public void testProps() throws RuleSetNotFoundException {
215 Rule r = loadFirstRule(PROPERTIES);
216 assertEquals("bar", r.getProperty((PropertyDescriptor<String>) r.getPropertyDescriptor("fooString")));
217 assertEquals(new Integer(3), r.getProperty((PropertyDescriptor<Integer>) r.getPropertyDescriptor("fooInt")));
218 assertTrue(r.getProperty((PropertyDescriptor<Boolean>) r.getPropertyDescriptor("fooBoolean")));
219 assertEquals(3.0d, r.getProperty((PropertyDescriptor<Double>) r.getPropertyDescriptor("fooDouble")), 0.05);
220 assertNull(r.getPropertyDescriptor("BuggleFish"));
221 assertNotSame(r.getDescription().indexOf("testdesc2"), -1);
222 }
223
224 @Test
225 @SuppressWarnings("unchecked")
226 public void testXPath() throws RuleSetNotFoundException {
227 Rule r = loadFirstRule(XPATH);
228 PropertyDescriptor<String> xpathProperty = (PropertyDescriptor<String>) r.getPropertyDescriptor("xpath");
229 assertNotNull("xpath property descriptor", xpathProperty);
230 assertNotSame(r.getProperty(xpathProperty).indexOf(" //Block "), -1);
231 }
232
233 @Test
234 public void testFacadesOffByDefault() throws RuleSetNotFoundException {
235 Rule r = loadFirstRule(XPATH);
236 assertFalse(r.usesDFA());
237 }
238
239 @Test
240 public void testDFAFlag() throws RuleSetNotFoundException {
241 assertTrue(loadFirstRule(DFA).usesDFA());
242 }
243
244 @Test
245 public void testExternalReferenceOverride() throws RuleSetNotFoundException {
246 Rule r = loadFirstRule(REF_OVERRIDE);
247 assertEquals("TestNameOverride", r.getName());
248 assertEquals("Test message override", r.getMessage());
249 assertEquals("Test description override", r.getDescription());
250 assertEquals("Test that both example are stored", 2, r.getExamples().size());
251 assertEquals("Test example override", r.getExamples().get(1));
252 assertEquals(RulePriority.MEDIUM, r.getPriority());
253 PropertyDescriptor<?> test2Descriptor = r.getPropertyDescriptor("test2");
254 assertNotNull("test2 descriptor", test2Descriptor);
255 assertEquals("override2", r.getProperty(test2Descriptor));
256 PropertyDescriptor<?> test3Descriptor = r.getPropertyDescriptor("test3");
257 assertNotNull("test3 descriptor", test3Descriptor);
258 assertEquals("override3", r.getProperty(test3Descriptor));
259 PropertyDescriptor<?> test4Descriptor = r.getPropertyDescriptor("test4");
260 assertNotNull("test3 descriptor", test4Descriptor);
261 assertEquals("new property", r.getProperty(test4Descriptor));
262 }
263
264 @Test
265 public void testReferenceInternalToInternal()
266 throws RuleSetNotFoundException {
267 RuleSet ruleSet = loadRuleSet(REF_INTERNAL_TO_INTERNAL);
268
269 Rule rule = ruleSet.getRuleByName("MockRuleName");
270 assertNotNull("Could not find Rule MockRuleName", rule);
271
272 Rule ruleRef = ruleSet.getRuleByName("MockRuleNameRef");
273 assertNotNull("Could not find Rule MockRuleNameRef", ruleRef);
274 }
275
276 @Test
277 public void testReferenceInternalToInternalChain()
278 throws RuleSetNotFoundException {
279 RuleSet ruleSet = loadRuleSet(REF_INTERNAL_TO_INTERNAL_CHAIN);
280
281 Rule rule = ruleSet.getRuleByName("MockRuleName");
282 assertNotNull("Could not find Rule MockRuleName", rule);
283
284 Rule ruleRef = ruleSet.getRuleByName("MockRuleNameRef");
285 assertNotNull("Could not find Rule MockRuleNameRef", ruleRef);
286
287 Rule ruleRefRef = ruleSet.getRuleByName("MockRuleNameRefRef");
288 assertNotNull("Could not find Rule MockRuleNameRefRef", ruleRefRef);
289 }
290
291 @Test
292 public void testReferenceInternalToExternal()
293 throws RuleSetNotFoundException {
294 RuleSet ruleSet = loadRuleSet(REF_INTERNAL_TO_EXTERNAL);
295
296 Rule rule = ruleSet.getRuleByName("ExternalRefRuleName");
297 assertNotNull("Could not find Rule ExternalRefRuleName", rule);
298
299 Rule ruleRef = ruleSet.getRuleByName("ExternalRefRuleNameRef");
300 assertNotNull("Could not find Rule ExternalRefRuleNameRef", ruleRef);
301 }
302
303 @Test
304 public void testReferenceInternalToExternalChain()
305 throws RuleSetNotFoundException {
306 RuleSet ruleSet = loadRuleSet(REF_INTERNAL_TO_EXTERNAL_CHAIN);
307
308 Rule rule = ruleSet.getRuleByName("ExternalRefRuleName");
309 assertNotNull("Could not find Rule ExternalRefRuleName", rule);
310
311 Rule ruleRef = ruleSet.getRuleByName("ExternalRefRuleNameRef");
312 assertNotNull("Could not find Rule ExternalRefRuleNameRef", ruleRef);
313
314 Rule ruleRefRef = ruleSet.getRuleByName("ExternalRefRuleNameRefRef");
315 assertNotNull("Could not find Rule ExternalRefRuleNameRefRef",
316 ruleRefRef);
317 }
318
319 @Test
320 public void testReferencePriority() throws RuleSetNotFoundException {
321 RuleSetFactory rsf = new RuleSetFactory();
322
323 rsf.setMinimumPriority(RulePriority.LOW);
324 RuleSet ruleSet = rsf
325 .createRuleSet(createRuleSetReferenceId(REF_INTERNAL_TO_INTERNAL_CHAIN));
326 assertEquals("Number of Rules", 3, ruleSet.getRules().size());
327 assertNotNull(ruleSet.getRuleByName("MockRuleName"));
328 assertNotNull(ruleSet.getRuleByName("MockRuleNameRef"));
329 assertNotNull(ruleSet.getRuleByName("MockRuleNameRefRef"));
330
331 rsf.setMinimumPriority(RulePriority.MEDIUM_HIGH);
332 ruleSet = rsf
333 .createRuleSet(createRuleSetReferenceId(REF_INTERNAL_TO_INTERNAL_CHAIN));
334 assertEquals("Number of Rules", 2, ruleSet.getRules().size());
335 assertNotNull(ruleSet.getRuleByName("MockRuleNameRef"));
336 assertNotNull(ruleSet.getRuleByName("MockRuleNameRefRef"));
337
338 rsf.setMinimumPriority(RulePriority.HIGH);
339 ruleSet = rsf
340 .createRuleSet(createRuleSetReferenceId(REF_INTERNAL_TO_INTERNAL_CHAIN));
341 assertEquals("Number of Rules", 1, ruleSet.getRules().size());
342 assertNotNull(ruleSet.getRuleByName("MockRuleNameRefRef"));
343
344 rsf.setMinimumPriority(RulePriority.LOW);
345 ruleSet = rsf
346 .createRuleSet(createRuleSetReferenceId(REF_INTERNAL_TO_EXTERNAL_CHAIN));
347 assertEquals("Number of Rules", 3, ruleSet.getRules().size());
348 assertNotNull(ruleSet.getRuleByName("ExternalRefRuleName"));
349 assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRef"));
350 assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRefRef"));
351
352 rsf.setMinimumPriority(RulePriority.MEDIUM_HIGH);
353 ruleSet = rsf
354 .createRuleSet(createRuleSetReferenceId(REF_INTERNAL_TO_EXTERNAL_CHAIN));
355 assertEquals("Number of Rules", 2, ruleSet.getRules().size());
356 assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRef"));
357 assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRefRef"));
358
359 rsf.setMinimumPriority(RulePriority.HIGH);
360 ruleSet = rsf
361 .createRuleSet(createRuleSetReferenceId(REF_INTERNAL_TO_EXTERNAL_CHAIN));
362 assertEquals("Number of Rules", 1, ruleSet.getRules().size());
363 assertNotNull(ruleSet.getRuleByName("ExternalRefRuleNameRefRef"));
364 }
365
366 @Test
367 public void testOverrideMessage() throws RuleSetNotFoundException {
368 Rule r = loadFirstRule(REF_OVERRIDE_ORIGINAL_NAME);
369 assertEquals("TestMessageOverride", r.getMessage());
370 }
371
372 @Test
373 public void testOverrideMessageOneElem() throws RuleSetNotFoundException {
374 Rule r = loadFirstRule(REF_OVERRIDE_ORIGINAL_NAME_ONE_ELEM);
375 assertEquals("TestMessageOverride", r.getMessage());
376 }
377
378 @Test(expected = IllegalArgumentException.class)
379 public void testIncorrectExternalRef() throws IllegalArgumentException,
380 RuleSetNotFoundException {
381 loadFirstRule(REF_MISPELLED_XREF);
382 }
383
384 @Test
385 public void testSetPriority() throws RuleSetNotFoundException {
386 RuleSetFactory rsf = new RuleSetFactory();
387 rsf.setMinimumPriority(RulePriority.MEDIUM_HIGH);
388 assertEquals(0, rsf
389 .createRuleSet(createRuleSetReferenceId(SINGLE_RULE)).size());
390 rsf.setMinimumPriority(RulePriority.MEDIUM_LOW);
391 assertEquals(1, rsf
392 .createRuleSet(createRuleSetReferenceId(SINGLE_RULE)).size());
393 }
394
395 @Test
396 public void testLanguage() throws RuleSetNotFoundException {
397 Rule r = loadFirstRule(LANGUAGE);
398 assertEquals(Language.JAVA, r.getLanguage());
399 }
400
401 @Test(expected = IllegalArgumentException.class)
402 public void testIncorrectLanguage() throws RuleSetNotFoundException {
403 loadFirstRule(INCORRECT_LANGUAGE);
404 }
405
406 @Test
407 public void testMinimumLanugageVersion() throws RuleSetNotFoundException {
408 Rule r = loadFirstRule(MINIMUM_LANGUAGE_VERSION);
409 assertEquals(LanguageVersion.JAVA_14, r.getMinimumLanguageVersion());
410 }
411
412 @Test(expected = IllegalArgumentException.class)
413 public void testIncorrectMinimumLanugageVersion()
414 throws RuleSetNotFoundException {
415 loadFirstRule(INCORRECT_MINIMUM_LANGUAGE_VERSION);
416 }
417
418 @Test
419 public void testMaximumLanugageVersion() throws RuleSetNotFoundException {
420 Rule r = loadFirstRule(MAXIMUM_LANGUAGE_VERSION);
421 assertEquals(LanguageVersion.JAVA_17, r.getMaximumLanguageVersion());
422 }
423
424 @Test(expected = IllegalArgumentException.class)
425 public void testIncorrectMaximumLanugageVersion()
426 throws RuleSetNotFoundException {
427 loadFirstRule(INCORRECT_MAXIMUM_LANGUAGE_VERSION);
428 }
429
430 @Test(expected = IllegalArgumentException.class)
431 public void testInvertedMinimumMaximumLanugageVersions()
432 throws RuleSetNotFoundException {
433 loadFirstRule(INVERTED_MINIMUM_MAXIMUM_LANGUAGE_VERSIONS);
434 }
435
436 @Test
437 public void testDirectDeprecatedRule() throws RuleSetNotFoundException {
438 Rule r = loadFirstRule(DIRECT_DEPRECATED_RULE);
439 assertNotNull("Direct Deprecated Rule", r);
440 }
441
442 @Test
443 public void testReferenceToDeprecatedRule() throws RuleSetNotFoundException {
444 Rule r = loadFirstRule(REFERENCE_TO_DEPRECATED_RULE);
445 assertNotNull("Reference to Deprecated Rule", r);
446 assertTrue("Rule Reference", r instanceof RuleReference);
447 assertFalse("Not deprecated", r.isDeprecated());
448 assertTrue("Original Rule Deprecated", ((RuleReference) r).getRule()
449 .isDeprecated());
450 assertEquals("Rule name", r.getName(), DEPRECATED_RULE_NAME);
451 }
452
453 @Test
454 public void testRuleSetReferenceWithDeprecatedRule()
455 throws RuleSetNotFoundException {
456 RuleSet ruleSet = loadRuleSet(REFERENCE_TO_RULESET_WITH_DEPRECATED_RULE);
457 assertNotNull("RuleSet", ruleSet);
458 assertFalse("RuleSet empty", ruleSet.getRules().isEmpty());
459 // No deprecated Rules should be loaded when loading an entire RuleSet
460 // by reference.
461 Rule r = ruleSet.getRuleByName(DEPRECATED_RULE_NAME);
462 assertNull("Deprecated Rule Reference", r);
463 for (Rule rule : ruleSet.getRules()) {
464 assertFalse("Rule not deprecated", rule.isDeprecated());
465 }
466 }
467
468 @Test
469 public void testExternalReferences() throws RuleSetNotFoundException {
470 RuleSet rs = loadRuleSet(EXTERNAL_REFERENCE_RULE_SET);
471 assertEquals(1, rs.size());
472 assertEquals(UnusedLocalVariableRule.class.getName(), rs.getRuleByName(
473 "UnusedLocalVariable").getRuleClass());
474 }
475
476 @Test
477 public void testIncludeExcludePatterns() throws RuleSetNotFoundException {
478 RuleSet ruleSet = loadRuleSet(INCLUDE_EXCLUDE_RULESET);
479
480 assertNotNull("Include patterns", ruleSet.getIncludePatterns());
481 assertEquals("Include patterns size", 2, ruleSet.getIncludePatterns()
482 .size());
483 assertEquals("Include pattern #1", "include1", ruleSet
484 .getIncludePatterns().get(0));
485 assertEquals("Include pattern #2", "include2", ruleSet
486 .getIncludePatterns().get(1));
487
488 assertNotNull("Exclude patterns", ruleSet.getExcludePatterns());
489 assertEquals("Exclude patterns size", 3, ruleSet.getExcludePatterns()
490 .size());
491 assertEquals("Exclude pattern #1", "exclude1", ruleSet
492 .getExcludePatterns().get(0));
493 assertEquals("Exclude pattern #2", "exclude2", ruleSet
494 .getExcludePatterns().get(1));
495 assertEquals("Exclude pattern #3", "exclude3", ruleSet
496 .getExcludePatterns().get(2));
497 }
498
499 @Test
500 public void testAllPMDBuiltInRulesMeetConventions() throws IOException,
501 RuleSetNotFoundException, ParserConfigurationException,
502 SAXException {
503 int invalidSinceAttributes = 0;
504 int invalidExternalInfoURL = 0;
505 int invalidClassName = 0;
506 int invalidRegexSuppress = 0;
507 int invalidXPathSuppress = 0;
508 String messages = "";
509 List<String> ruleSetFileNames = getRuleSetFileNames();
510 for (String fileName : ruleSetFileNames) {
511 RuleSet ruleSet = loadRuleSetByFileName(fileName);
512 for (Rule rule : ruleSet.getRules()) {
513
514 // Skip references
515 if (rule instanceof RuleReference) {
516 continue;
517 }
518
519 Language language = rule.getLanguage();
520 String group = fileName
521 .substring(fileName.lastIndexOf('/') + 1);
522 group = group.substring(0, group.indexOf(".xml"));
523 if (group.indexOf('-') >= 0) {
524 group = group.substring(0, group.indexOf('-'));
525 }
526
527 // Is since missing ?
528 if (rule.getSince() == null) {
529 invalidSinceAttributes++;
530 messages += "Rule " + fileName + "/" + rule.getName()
531 + " is missing 'since' attribute" + PMD.EOL;
532 }
533 // Is URL valid ?
534 if (rule.getExternalInfoUrl() == null
535 || "".equalsIgnoreCase(rule.getExternalInfoUrl())) {
536 invalidExternalInfoURL++;
537 messages += "Rule " + fileName + "/" + rule.getName()
538 + " is missing 'externalInfoURL' attribute"
539 + PMD.EOL;
540 } else {
541 String expectedExternalInfoURL = "http://pmd.sourceforge.net/.+/rules/"
542 + fileName.replaceAll("rulesets/", "").replaceAll(
543 ".xml", "") + ".html#" + rule.getName();
544 if (rule.getExternalInfoUrl() == null
545 || !rule.getExternalInfoUrl().matches(expectedExternalInfoURL)) {
546 invalidExternalInfoURL++;
547 messages += "Rule "
548 + fileName
549 + "/"
550 + rule.getName()
551 + " seems to have an invalid 'externalInfoURL' value ("
552 + rule.getExternalInfoUrl()
553 + "), it should be:" + expectedExternalInfoURL
554 + PMD.EOL;
555 }
556 }
557 // Proper class name/packaging?
558 String expectedClassName = "net.sourceforge.pmd.lang."
559 + language.getTerseName() + ".rule." + group + "."
560 + rule.getName() + "Rule";
561 if (!rule.getRuleClass().equals(expectedClassName)
562 && !rule.getRuleClass().equals(
563 XPathRule.class.getName())) {
564 invalidClassName++;
565 messages += "Rule " + fileName + "/" + rule.getName()
566 + " seems to have an invalid 'class' value ("
567 + rule.getRuleClass() + "), it should be:"
568 + expectedClassName + PMD.EOL;
569 }
570 // Should not have violation suppress regex property
571 if (rule.getProperty(Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR) != null) {
572 invalidRegexSuppress++;
573 messages += "Rule "
574 + fileName
575 + "/"
576 + rule.getName()
577 + " should not have '"
578 + Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR.name()
579 + "', this is intended for end user customization only."
580 + PMD.EOL;
581 }
582 // Should not have violation suppress xpath property
583 if (rule.getProperty(Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR) != null) {
584 invalidXPathSuppress++;
585 messages += "Rule "
586 + fileName
587 + "/"
588 + rule.getName()
589 + " should not have '"
590 + Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR.name()
591 + "', this is intended for end user customization only."
592 + PMD.EOL;
593 }
594 }
595 }
596 // We do this at the end to ensure we test ALL the rules before failing
597 // the test
598 if (invalidSinceAttributes > 0 || invalidExternalInfoURL > 0
599 || invalidClassName > 0 || invalidRegexSuppress > 0
600 || invalidXPathSuppress > 0) {
601 fail("All built-in PMD rules need 'since' attribute ("
602 + invalidSinceAttributes
603 + " are missing), a proper ExternalURLInfo ("
604 + invalidExternalInfoURL
605 + " are invalid), a class name meeting conventions ("
606 + invalidClassName + " are invalid), no '"
607 + Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR.name()
608 + "' property (" + invalidRegexSuppress
609 + " are invalid), and no '"
610 + Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR.name()
611 + "' property (" + invalidXPathSuppress + " are invalid)"
612 + PMD.EOL + messages);
613 }
614 }
615
616 @Test
617 public void testXmlSchema() throws IOException, RuleSetNotFoundException,
618 ParserConfigurationException, SAXException {
619 boolean allValid = true;
620 List<String> ruleSetFileNames = getRuleSetFileNames();
621 for (String fileName : ruleSetFileNames) {
622 boolean valid = validateAgainstSchema(fileName);
623 allValid = allValid && valid;
624 }
625 assertTrue("All XML must parse without producing validation messages.",
626 allValid);
627 }
628
629 @Test
630 public void testDtd() throws IOException, RuleSetNotFoundException,
631 ParserConfigurationException, SAXException {
632 boolean allValid = true;
633 List<String> ruleSetFileNames = getRuleSetFileNames();
634 for (String fileName : ruleSetFileNames) {
635 boolean valid = validateAgainstDtd(fileName);
636 allValid = allValid && valid;
637 }
638 assertTrue("All XML must parse without producing validation messages.",
639 allValid);
640 }
641
642 @Test
643 public void testReadWriteRoundTrip() throws IOException,
644 RuleSetNotFoundException, ParserConfigurationException,
645 SAXException {
646
647 List<String> ruleSetFileNames = getRuleSetFileNames();
648 for (String fileName : ruleSetFileNames) {
649 testRuleSet(fileName);
650 }
651 }
652
653 public void testRuleSet(String fileName) throws IOException,
654 RuleSetNotFoundException, ParserConfigurationException,
655 SAXException {
656
657 // Load original XML
658 // String xml1 = readFullyToString(ResourceLoader.loadResourceAsStream(fileName));
659 // System.out.println("xml1: " + xml1);
660
661 // Load the original RuleSet
662 RuleSet ruleSet1 = loadRuleSetByFileName(fileName);
663
664 // Write to XML, first time
665 ByteArrayOutputStream outputStream1 = new ByteArrayOutputStream();
666 RuleSetWriter writer1 = new RuleSetWriter(outputStream1);
667 writer1.write(ruleSet1);
668 writer1.close();
669 String xml2 = new String(outputStream1.toByteArray());
670 // System.out.println("xml2: " + xml2);
671
672 // Read RuleSet from XML, first time
673 RuleSetFactory ruleSetFactory = new RuleSetFactory();
674 RuleSet ruleSet2 = ruleSetFactory
675 .createRuleSet(createRuleSetReferenceId(xml2));
676
677 // Do write/read a 2nd time, just to be sure
678
679 // Write to XML, second time
680 ByteArrayOutputStream outputStream2 = new ByteArrayOutputStream();
681 RuleSetWriter writer2 = new RuleSetWriter(outputStream2);
682 writer2.write(ruleSet2);
683 writer2.close();
684 String xml3 = new String(outputStream2.toByteArray());
685 // System.out.println("xml3: " + xml3);
686
687 // Read RuleSet from XML, second time
688 RuleSet ruleSet3 = ruleSetFactory
689 .createRuleSet(createRuleSetReferenceId(xml3));
690
691 // The 2 written XMLs should all be valid w.r.t Schema/DTD
692 assertTrue(
693 "1st roundtrip RuleSet XML is not valid against Schema (filename: " + fileName + ")",
694 validateAgainstSchema(new ByteArrayInputStream(xml2.getBytes())));
695 assertTrue(
696 "2nd roundtrip RuleSet XML is not valid against Schema (filename: " + fileName + ")",
697 validateAgainstSchema(new ByteArrayInputStream(xml3.getBytes())));
698 assertTrue("1st roundtrip RuleSet XML is not valid against DTD (filename: " + fileName + ")",
699 validateAgainstDtd(new ByteArrayInputStream(xml2.getBytes())));
700 assertTrue("2nd roundtrip RuleSet XML is not valid against DTD (filename: " + fileName + ")",
701 validateAgainstDtd(new ByteArrayInputStream(xml3.getBytes())));
702
703 // All 3 versions of the RuleSet should be the same
704 assertEqualsRuleSet(
705 "Original RuleSet and 1st roundtrip Ruleset not the same (filename: " + fileName + ")",
706 ruleSet1, ruleSet2);
707 assertEqualsRuleSet(
708 "1st roundtrip Ruleset and 2nd roundtrip RuleSet not the same (filename: " + fileName + ")",
709 ruleSet2, ruleSet3);
710
711 // It's hard to compare the XML DOMs. At least the roundtrip ones should
712 // textually be the same.
713 assertEquals("1st roundtrip RuleSet XML and 2nd roundtrip RuleSet XML (filename: " + fileName + ")",
714 xml2, xml3);
715 }
716
717 private void assertEqualsRuleSet(String message, RuleSet ruleSet1,
718 RuleSet ruleSet2) {
719 assertEquals(message + ", RuleSet name", ruleSet1.getName(), ruleSet2
720 .getName());
721 assertEquals(message + ", RuleSet description", ruleSet1
722 .getDescription(), ruleSet2.getDescription());
723 assertEquals(message + ", RuleSet exclude patterns", ruleSet1
724 .getExcludePatterns(), ruleSet2.getExcludePatterns());
725 assertEquals(message + ", RuleSet include patterns", ruleSet1
726 .getIncludePatterns(), ruleSet2.getIncludePatterns());
727 assertEquals(message + ", RuleSet rule count", ruleSet1.getRules()
728 .size(), ruleSet2.getRules().size());
729
730 for (int i = 0; i < ruleSet1.getRules().size(); i++) {
731 Rule rule1 = ((List<Rule>) ruleSet1.getRules()).get(i);
732 Rule rule2 = ((List<Rule>) ruleSet2.getRules()).get(i);
733
734 assertFalse(message + ", Different RuleReference",
735 rule1 instanceof RuleReference
736 && !(rule2 instanceof RuleReference)
737 || !(rule1 instanceof RuleReference)
738 && rule2 instanceof RuleReference);
739
740 if (rule1 instanceof RuleReference) {
741 RuleReference ruleReference1 = (RuleReference) rule1;
742 RuleReference ruleReference2 = (RuleReference) rule2;
743 assertEquals(message + ", RuleReference overridden language",
744 ruleReference1.getOverriddenLanguage(), ruleReference2
745 .getOverriddenLanguage());
746 assertEquals(
747 message
748 + ", RuleReference overridden minimum language version",
749 ruleReference1.getOverriddenMinimumLanguageVersion(),
750 ruleReference2.getOverriddenMinimumLanguageVersion());
751 assertEquals(
752 message
753 + ", RuleReference overridden maximum language version",
754 ruleReference1.getOverriddenMaximumLanguageVersion(),
755 ruleReference2.getOverriddenMaximumLanguageVersion());
756 assertEquals(message + ", RuleReference overridden deprecated",
757 ruleReference1.isOverriddenDeprecated(), ruleReference2
758 .isOverriddenDeprecated());
759 assertEquals(message + ", RuleReference overridden name",
760 ruleReference1.getOverriddenName(), ruleReference2
761 .getOverriddenName());
762 assertEquals(
763 message + ", RuleReference overridden description",
764 ruleReference1.getOverriddenDescription(),
765 ruleReference2.getOverriddenDescription());
766 assertEquals(message + ", RuleReference overridden message",
767 ruleReference1.getOverriddenMessage(), ruleReference2
768 .getOverriddenMessage());
769 assertEquals(message
770 + ", RuleReference overridden external info url",
771 ruleReference1.getOverriddenExternalInfoUrl(),
772 ruleReference2.getOverriddenExternalInfoUrl());
773 assertEquals(message + ", RuleReference overridden priority",
774 ruleReference1.getOverriddenPriority(), ruleReference2
775 .getOverriddenPriority());
776 assertEquals(message + ", RuleReference overridden examples",
777 ruleReference1.getOverriddenExamples(), ruleReference2
778 .getOverriddenExamples());
779 }
780
781 assertEquals(message + ", Rule name", rule1.getName(), rule2
782 .getName());
783 assertEquals(message + ", Rule class", rule1.getRuleClass(), rule2
784 .getRuleClass());
785 assertEquals(message + ", Rule description " + rule1.getName(),
786 rule1.getDescription(), rule2.getDescription());
787 assertEquals(message + ", Rule message", rule1.getMessage(), rule2
788 .getMessage());
789 assertEquals(message + ", Rule external info url", rule1
790 .getExternalInfoUrl(), rule2.getExternalInfoUrl());
791 assertEquals(message + ", Rule priority", rule1.getPriority(),
792 rule2.getPriority());
793 assertEquals(message + ", Rule examples", rule1.getExamples(),
794 rule2.getExamples());
795
796 List<PropertyDescriptor<?>> propertyDescriptors1 = rule1
797 .getPropertyDescriptors();
798 List<PropertyDescriptor<?>> propertyDescriptors2 = rule2
799 .getPropertyDescriptors();
800 try {
801 assertEquals(message + ", Rule property descriptor ",
802 propertyDescriptors1, propertyDescriptors2);
803 } catch (Error e) {
804 throw e;
805 }
806 for (int j = 0; j < propertyDescriptors1.size(); j++) {
807 assertEquals(message + ", Rule property value " + j, rule1
808 .getProperty(propertyDescriptors1.get(j)), rule2
809 .getProperty(propertyDescriptors2.get(j)));
810 }
811 assertEquals(message + ", Rule property descriptor count",
812 propertyDescriptors1.size(), propertyDescriptors2.size());
813 }
814 }
815
816 private boolean validateAgainstSchema(String fileName) throws IOException,
817 RuleSetNotFoundException, ParserConfigurationException,
818 SAXException {
819 InputStream inputStream = loadResourceAsStream(fileName);
820 boolean valid = validateAgainstSchema(inputStream);
821 if (!valid) {
822 System.err.println("Validation against XML Schema failed for: "
823 + fileName);
824 }
825 return valid;
826 }
827
828 private boolean validateAgainstSchema(InputStream inputStream)
829 throws IOException, RuleSetNotFoundException,
830 ParserConfigurationException, SAXException {
831
832 saxParser.parse(inputStream, validateDefaultHandlerXsd.resetValid());
833 inputStream.close();
834 return validateDefaultHandlerXsd.isValid();
835 }
836
837 private boolean validateAgainstDtd(String fileName) throws IOException,
838 RuleSetNotFoundException, ParserConfigurationException,
839 SAXException {
840 InputStream inputStream = loadResourceAsStream(fileName);
841 boolean valid = validateAgainstDtd(inputStream);
842 if (!valid) {
843 System.err
844 .println("Validation against DTD failed for: " + fileName);
845 }
846 return valid;
847 }
848
849 private boolean validateAgainstDtd(InputStream inputStream)
850 throws IOException, RuleSetNotFoundException,
851 ParserConfigurationException, SAXException {
852
853 // Read file into memory
854 String file = readFullyToString(inputStream);
855
856 // Remove XML Schema stuff, replace with DTD
857 file = file.replaceAll("<\\?xml [ a-zA-Z0-9=\".-]*\\?>", "");
858 file = file.replaceAll(
859 "xmlns=\"" + RuleSetWriter.RULESET_NS_URI + "\"", "");
860 file = file.replaceAll(
861 "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", "");
862 file = file
863 .replaceAll(
864 "xsi:schemaLocation=\"" + RuleSetWriter.RULESET_NS_URI + " http://pmd.sourceforge.net/ruleset_2_0_0.xsd\"",
865 "");
866
867 file = "<?xml version=\"1.0\"?>" + PMD.EOL
868 + "<!DOCTYPE ruleset SYSTEM \"file://"
869 + System.getProperty("user.dir") + "/src/main/resources/ruleset_2_0_0.dtd\">"
870 + PMD.EOL + file;
871
872 inputStream = new ByteArrayInputStream(file.getBytes());
873
874 saxParser.parse(inputStream, validateDefaultHandlerDtd.resetValid());
875 inputStream.close();
876 return validateDefaultHandlerDtd.isValid();
877 }
878
879 private String readFullyToString(InputStream inputStream)
880 throws IOException {
881 StringBuilder buf = new StringBuilder(64 * 1024);
882 BufferedReader reader = new BufferedReader(new InputStreamReader(
883 inputStream));
884 String line;
885 while ((line = reader.readLine()) != null) {
886 buf.append(line);
887 buf.append(PMD.EOL);
888 }
889 reader.close();
890 return buf.toString();
891 }
892
893 // Gets all test PMD Ruleset XML files
894 private List<String> getRuleSetFileNames() throws IOException,
895 RuleSetNotFoundException {
896 List<String> result = new ArrayList<String>();
897
898 for (Language language : Language.values()) {
899 result.addAll(getRuleSetFileNames(language.getTerseName()));
900 }
901
902 return result;
903 }
904
905 private List<String> getRuleSetFileNames(String language) throws IOException, RuleSetNotFoundException {
906 List<String> ruleSetFileNames = new ArrayList<String>();
907 try {
908 Properties properties = new Properties();
909 properties.load(ResourceLoader.loadResourceAsStream("rulesets/" + language + "/rulesets.properties"));
910 String fileNames = properties.getProperty("rulesets.filenames");
911 StringTokenizer st = new StringTokenizer(fileNames, ",");
912 while (st.hasMoreTokens()) {
913 ruleSetFileNames.add(st.nextToken());
914 }
915 } catch (RuleSetNotFoundException e) {
916 // this might happen if a language is only support by CPD, but not by PMD
917 System.err.println("No ruleset found for language " + language);
918 }
919 return ruleSetFileNames;
920 }
921
922 private static class ValidateDefaultHandler extends DefaultHandler {
923 private final String validateDocument;
924 private boolean valid = true;
925
926 public ValidateDefaultHandler(String validateDocument) {
927 this.validateDocument = validateDocument;
928 }
929
930 public ValidateDefaultHandler resetValid() {
931 valid = true;
932 return this;
933 }
934
935 public boolean isValid() {
936 return valid;
937 }
938
939 @Override
940 public void error(SAXParseException e) throws SAXException {
941 log("Error", e);
942 }
943
944 @Override
945 public void fatalError(SAXParseException e) throws SAXException {
946 log("FatalError", e);
947 }
948
949 @Override
950 public void warning(SAXParseException e) throws SAXException {
951 log("Warning", e);
952 }
953
954 private void log(String prefix, SAXParseException e) {
955 String message = prefix + " at (" + e.getLineNumber() + ", " + e.getColumnNumber() + "): " + e.getMessage();
956 System.err.println(message);
957 valid = false;
958 }
959
960 @Override
961 public InputSource resolveEntity(String publicId, String systemId)
962 throws IOException, SAXException {
963 if ("http://pmd.sourceforge.net/ruleset_2_0_0.xsd".equals(systemId)
964 || systemId.endsWith("ruleset_2_0_0.dtd")) {
965 try {
966 InputStream inputStream = loadResourceAsStream(validateDocument);
967 return new InputSource(inputStream);
968 } catch (RuleSetNotFoundException e) {
969 System.err.println(e.getMessage());
970 throw new IOException(e.getMessage());
971 }
972 }
973 throw new IllegalArgumentException(
974 "No clue how to handle: publicId=" + publicId
975 + ", systemId=" + systemId);
976 }
977 }
978
979 private static InputStream loadResourceAsStream(String resource)
980 throws RuleSetNotFoundException {
981 InputStream inputStream = ResourceLoader.loadResourceAsStream(resource,
982 RuleSetFactoryTest.class.getClassLoader());
983 if (inputStream == null) {
984 throw new RuleSetNotFoundException(
985 "Can't find resource "
986 + resource
987 + " Make sure the resource is a valid file or URL or is on the CLASSPATH. Here's the current classpath: "
988 + System.getProperty("java.class.path"));
989 }
990 return inputStream;
991 }
992
993 private static final String REF_OVERRIDE_ORIGINAL_NAME = "<?xml version=\"1.0\"?>"
994 + PMD.EOL
995 + "<ruleset name=\"test\">"
996 + PMD.EOL
997 + " <description>testdesc</description>"
998 + PMD.EOL
999 + " <rule "
1000 + PMD.EOL
1001 + " ref=\"rulesets/java/unusedcode.xml/UnusedLocalVariable\" message=\"TestMessageOverride\"> "
1002 + PMD.EOL + " </rule>" + PMD.EOL + "</ruleset>";
1003
1004 private static final String REF_MISPELLED_XREF = "<?xml version=\"1.0\"?>"
1005 + PMD.EOL + "<ruleset name=\"test\">" + PMD.EOL
1006 + " <description>testdesc</description>" + PMD.EOL + " <rule "
1007 + PMD.EOL
1008 + " ref=\"rulesets/java/unusedcode.xml/FooUnusedLocalVariable\"> "
1009 + PMD.EOL + " </rule>" + PMD.EOL + "</ruleset>";
1010
1011 private static final String REF_OVERRIDE_ORIGINAL_NAME_ONE_ELEM = "<?xml version=\"1.0\"?>"
1012 + PMD.EOL
1013 + "<ruleset name=\"test\">"
1014 + PMD.EOL
1015 + " <description>testdesc</description>"
1016 + PMD.EOL
1017 + " <rule ref=\"rulesets/java/unusedcode.xml/UnusedLocalVariable\" message=\"TestMessageOverride\"/> "
1018 + PMD.EOL + "</ruleset>";
1019
1020 private static final String REF_OVERRIDE = "<?xml version=\"1.0\"?>"
1021 + PMD.EOL
1022 + "<ruleset name=\"test\">"
1023 + PMD.EOL
1024 + " <description>testdesc</description>"
1025 + PMD.EOL
1026 + " <rule "
1027 + PMD.EOL
1028 + " ref=\"rulesets/java/unusedcode.xml/UnusedLocalVariable\" "
1029 + PMD.EOL
1030 + " name=\"TestNameOverride\" "
1031 + PMD.EOL
1032 + " message=\"Test message override\"> "
1033 + PMD.EOL
1034 + " <description>Test description override</description>"
1035 + PMD.EOL
1036 + " <example>Test example override</example>"
1037 + PMD.EOL
1038 + " <priority>3</priority>"
1039 + PMD.EOL
1040 + " <properties>"
1041 + PMD.EOL
1042 + " <property name=\"test2\" description=\"test2\" type=\"String\" value=\"override2\"/>"
1043 + PMD.EOL
1044 + " <property name=\"test3\" description=\"test3\" type=\"String\"><value>override3</value></property>"
1045 + PMD.EOL
1046 + " <property name=\"test4\" description=\"test4\" type=\"String\" value=\"new property\"/>"
1047 + PMD.EOL + " </properties>" + PMD.EOL + " </rule>" + PMD.EOL
1048 + "</ruleset>";
1049
1050 private static final String REF_INTERNAL_TO_INTERNAL = "<?xml version=\"1.0\"?>"
1051 + PMD.EOL
1052 + "<ruleset name=\"test\">"
1053 + PMD.EOL
1054 + " <description>testdesc</description>"
1055 + PMD.EOL
1056 + "<rule "
1057 + PMD.EOL
1058 + "name=\"MockRuleName\" "
1059 + PMD.EOL
1060 + "message=\"avoid the mock rule\" "
1061 + PMD.EOL
1062 + "class=\"net.sourceforge.pmd.lang.rule.MockRule\">"
1063 + PMD.EOL
1064 + "</rule>"
1065 + " <rule ref=\"MockRuleName\" name=\"MockRuleNameRef\"/> "
1066 + PMD.EOL + "</ruleset>";
1067
1068 private static final String REF_INTERNAL_TO_INTERNAL_CHAIN = "<?xml version=\"1.0\"?>"
1069 + PMD.EOL
1070 + "<ruleset name=\"test\">"
1071 + PMD.EOL
1072 + " <description>testdesc</description>"
1073 + PMD.EOL
1074 + "<rule "
1075 + PMD.EOL
1076 + "name=\"MockRuleName\" "
1077 + PMD.EOL
1078 + "message=\"avoid the mock rule\" "
1079 + PMD.EOL
1080 + "class=\"net.sourceforge.pmd.lang.rule.MockRule\">"
1081 + PMD.EOL
1082 + "</rule>"
1083 + " <rule ref=\"MockRuleName\" name=\"MockRuleNameRef\"><priority>2</priority></rule> "
1084 + PMD.EOL
1085 + " <rule ref=\"MockRuleNameRef\" name=\"MockRuleNameRefRef\"><priority>1</priority></rule> "
1086 + PMD.EOL + "</ruleset>";
1087
1088 private static final String REF_INTERNAL_TO_EXTERNAL = "<?xml version=\"1.0\"?>"
1089 + PMD.EOL
1090 + "<ruleset name=\"test\">"
1091 + PMD.EOL
1092 + " <description>testdesc</description>"
1093 + PMD.EOL
1094 + "<rule "
1095 + PMD.EOL
1096 + "name=\"ExternalRefRuleName\" "
1097 + PMD.EOL
1098 + "ref=\"rulesets/java/unusedcode.xml/UnusedLocalVariable\"/>"
1099 + PMD.EOL
1100 + " <rule ref=\"ExternalRefRuleName\" name=\"ExternalRefRuleNameRef\"/> "
1101 + PMD.EOL + "</ruleset>";
1102
1103 private static final String REF_INTERNAL_TO_EXTERNAL_CHAIN = "<?xml version=\"1.0\"?>"
1104 + PMD.EOL
1105 + "<ruleset name=\"test\">"
1106 + PMD.EOL
1107 + " <description>testdesc</description>"
1108 + PMD.EOL
1109 + "<rule "
1110 + PMD.EOL
1111 + "name=\"ExternalRefRuleName\" "
1112 + PMD.EOL
1113 + "ref=\"rulesets/java/unusedcode.xml/UnusedLocalVariable\"/>"
1114 + PMD.EOL
1115 + " <rule ref=\"ExternalRefRuleName\" name=\"ExternalRefRuleNameRef\"><priority>2</priority></rule> "
1116 + PMD.EOL
1117 + " <rule ref=\"ExternalRefRuleNameRef\" name=\"ExternalRefRuleNameRefRef\"><priority>1</priority></rule> "
1118 + PMD.EOL + "</ruleset>";
1119
1120 private static final String EMPTY_RULESET = "<?xml version=\"1.0\"?>"
1121 + PMD.EOL + "<ruleset name=\"test\">" + PMD.EOL
1122 + "<description>testdesc</description>" + PMD.EOL + "</ruleset>";
1123
1124 private static final String SINGLE_RULE = "<?xml version=\"1.0\"?>"
1125 + PMD.EOL + "<ruleset name=\"test\">" + PMD.EOL
1126 + "<description>testdesc</description>" + PMD.EOL + "<rule "
1127 + PMD.EOL + "name=\"MockRuleName\" " + PMD.EOL
1128 + "message=\"avoid the mock rule\" " + PMD.EOL
1129 + "class=\"net.sourceforge.pmd.lang.rule.MockRule\">"
1130 + "<priority>3</priority>" + PMD.EOL + "</rule></ruleset>";
1131
1132 private static final String MULTIPLE_RULES = "<?xml version=\"1.0\"?>"
1133 + PMD.EOL + "<ruleset name=\"test\">" + PMD.EOL
1134 + "<description>testdesc</description>" + PMD.EOL
1135 + "<rule name=\"MockRuleName1\" " + PMD.EOL
1136 + "message=\"avoid the mock rule\" " + PMD.EOL
1137 + "class=\"net.sourceforge.pmd.lang.rule.MockRule\">" + PMD.EOL
1138 + "</rule>" + PMD.EOL + "<rule name=\"MockRuleName2\" " + PMD.EOL
1139 + "message=\"avoid the mock rule\" " + PMD.EOL
1140 + "class=\"net.sourceforge.pmd.lang.rule.MockRule\">" + PMD.EOL
1141 + "</rule></ruleset>";
1142
1143 private static final String PROPERTIES = "<?xml version=\"1.0\"?>"
1144 + PMD.EOL
1145 + "<ruleset name=\"test\">"
1146 + PMD.EOL
1147 + "<description>testdesc</description>"
1148 + PMD.EOL
1149 + "<rule name=\"MockRuleName\" "
1150 + PMD.EOL
1151 + "message=\"avoid the mock rule\" "
1152 + PMD.EOL
1153 + "class=\"net.sourceforge.pmd.lang.rule.MockRule\">"
1154 + PMD.EOL
1155 + "<description>testdesc2</description>"
1156 + PMD.EOL
1157 + "<properties>"
1158 + PMD.EOL
1159 + "<property name=\"fooBoolean\" description=\"test\" type=\"Boolean\" value=\"true\" />"
1160 + PMD.EOL
1161 + "<property name=\"fooChar\" description=\"test\" type=\"Character\" value=\"B\" />"
1162 + PMD.EOL
1163 + "<property name=\"fooInt\" description=\"test\" type=\"Integer\" min=\"1\" max=\"10\" value=\"3\" />"
1164 + PMD.EOL
1165 + "<property name=\"fooFloat\" description=\"test\" type=\"Float\" min=\"1.0\" max=\"1.0\" value=\"1.0\" />"
1166 + PMD.EOL
1167 + "<property name=\"fooDouble\" description=\"test\" type=\"Double\" min=\"1.0\" max=\"9.0\" value=\"3.0\" />"
1168 + PMD.EOL
1169 + "<property name=\"fooString\" description=\"test\" type=\"String\" value=\"bar\" />"
1170 + PMD.EOL + "</properties>" + PMD.EOL + "</rule></ruleset>";
1171
1172 private static final String XPATH = "<?xml version=\"1.0\"?>" + PMD.EOL
1173 + "<ruleset name=\"test\">" + PMD.EOL
1174 + "<description>testdesc</description>" + PMD.EOL
1175 + "<rule name=\"MockRuleName\" " + PMD.EOL
1176 + "message=\"avoid the mock rule\" " + PMD.EOL
1177 + "class=\"net.sourceforge.pmd.lang.rule.MockRule\">"
1178 + "<priority>3</priority>" + PMD.EOL + PMD.EOL
1179 + "<description>testdesc2</description>" + PMD.EOL + "<properties>"
1180 + PMD.EOL
1181 + "<property name=\"xpath\" description=\"test\" type=\"String\">"
1182 + PMD.EOL + "<value>" + PMD.EOL + "<![CDATA[ //Block ]]>" + PMD.EOL
1183 + "</value>" + PMD.EOL + "</property>" + PMD.EOL + "</properties>"
1184 + PMD.EOL + "</rule></ruleset>";
1185
1186 private static final String PRIORITY = "<?xml version=\"1.0\"?>" + PMD.EOL
1187 + "<ruleset name=\"test\">" + PMD.EOL
1188 + "<description>testdesc</description>" + PMD.EOL + "<rule "
1189 + PMD.EOL + "name=\"MockRuleName\" " + PMD.EOL
1190 + "message=\"avoid the mock rule\" " + PMD.EOL
1191 + "class=\"net.sourceforge.pmd.lang.rule.MockRule\">"
1192 + "<priority>3</priority>" + PMD.EOL + "</rule></ruleset>";
1193
1194 private static final String LANGUAGE = "<?xml version=\"1.0\"?>"
1195 + PMD.EOL
1196 + "<ruleset name=\"test\">"
1197 + PMD.EOL
1198 + "<description>testdesc</description>"
1199 + PMD.EOL
1200 + "<rule "
1201 + PMD.EOL
1202 + "name=\"MockRuleName\" "
1203 + PMD.EOL
1204 + "message=\"avoid the mock rule\" "
1205 + PMD.EOL
1206 + "class=\"net.sourceforge.pmd.lang.rule.MockRule\" language=\"java\">"
1207 + PMD.EOL + "</rule></ruleset>";
1208
1209 private static final String INCORRECT_LANGUAGE = "<?xml version=\"1.0\"?>"
1210 + PMD.EOL + "<ruleset name=\"test\">" + PMD.EOL
1211 + "<description>testdesc</description>" + PMD.EOL + "<rule "
1212 + PMD.EOL + "name=\"MockRuleName\" " + PMD.EOL
1213 + "message=\"avoid the mock rule\" " + PMD.EOL
1214 + "class=\"net.sourceforge.pmd.lang.rule.MockRule\"" + PMD.EOL
1215 + " language=\"bogus\">" + PMD.EOL + "</rule></ruleset>";
1216
1217 private static final String MINIMUM_LANGUAGE_VERSION = "<?xml version=\"1.0\"?>"
1218 + PMD.EOL
1219 + "<ruleset name=\"test\">"
1220 + PMD.EOL
1221 + "<description>testdesc</description>"
1222 + PMD.EOL
1223 + "<rule "
1224 + PMD.EOL
1225 + "name=\"MockRuleName\" "
1226 + PMD.EOL
1227 + "message=\"avoid the mock rule\" "
1228 + PMD.EOL
1229 + "class=\"net.sourceforge.pmd.lang.rule.MockRule\""
1230 + PMD.EOL
1231 + " language=\"java\""
1232 + PMD.EOL
1233 + " minimumLanguageVersion=\"1.4\">"
1234 + PMD.EOL
1235 + "</rule></ruleset>";
1236
1237 private static final String INCORRECT_MINIMUM_LANGUAGE_VERSION = "<?xml version=\"1.0\"?>"
1238 + PMD.EOL
1239 + "<ruleset name=\"test\">"
1240 + PMD.EOL
1241 + "<description>testdesc</description>"
1242 + PMD.EOL
1243 + "<rule "
1244 + PMD.EOL
1245 + "name=\"MockRuleName\" "
1246 + PMD.EOL
1247 + "message=\"avoid the mock rule\" "
1248 + PMD.EOL
1249 + "class=\"net.sourceforge.pmd.lang.rule.MockRule\""
1250 + PMD.EOL
1251 + " language=\"java\""
1252 + PMD.EOL
1253 + " minimumLanguageVersion=\"bogus\">"
1254 + PMD.EOL
1255 + "</rule></ruleset>";
1256
1257 private static final String MAXIMUM_LANGUAGE_VERSION = "<?xml version=\"1.0\"?>"
1258 + PMD.EOL
1259 + "<ruleset name=\"test\">"
1260 + PMD.EOL
1261 + "<description>testdesc</description>"
1262 + PMD.EOL
1263 + "<rule "
1264 + PMD.EOL
1265 + "name=\"MockRuleName\" "
1266 + PMD.EOL
1267 + "message=\"avoid the mock rule\" "
1268 + PMD.EOL
1269 + "class=\"net.sourceforge.pmd.lang.rule.MockRule\""
1270 + PMD.EOL
1271 + " language=\"java\""
1272 + PMD.EOL
1273 + " maximumLanguageVersion=\"1.7\">"
1274 + PMD.EOL
1275 + "</rule></ruleset>";
1276
1277 private static final String INCORRECT_MAXIMUM_LANGUAGE_VERSION = "<?xml version=\"1.0\"?>"
1278 + PMD.EOL
1279 + "<ruleset name=\"test\">"
1280 + PMD.EOL
1281 + "<description>testdesc</description>"
1282 + PMD.EOL
1283 + "<rule "
1284 + PMD.EOL
1285 + "name=\"MockRuleName\" "
1286 + PMD.EOL
1287 + "message=\"avoid the mock rule\" "
1288 + PMD.EOL
1289 + "class=\"net.sourceforge.pmd.lang.rule.MockRule\""
1290 + PMD.EOL
1291 + " language=\"java\""
1292 + PMD.EOL
1293 + " maximumLanguageVersion=\"bogus\">"
1294 + PMD.EOL
1295 + "</rule></ruleset>";
1296
1297 private static final String INVERTED_MINIMUM_MAXIMUM_LANGUAGE_VERSIONS = "<?xml version=\"1.0\"?>"
1298 + PMD.EOL
1299 + "<ruleset name=\"test\">"
1300 + PMD.EOL
1301 + "<description>testdesc</description>"
1302 + PMD.EOL
1303 + "<rule "
1304 + PMD.EOL
1305 + "name=\"MockRuleName\" "
1306 + PMD.EOL
1307 + "message=\"avoid the mock rule\" "
1308 + PMD.EOL
1309 + "class=\"net.sourceforge.pmd.lang.rule.MockRule\" "
1310 + PMD.EOL
1311 + "language=\"java\""
1312 + PMD.EOL
1313 + " minimumLanguageVersion=\"1.7\""
1314 + PMD.EOL
1315 + "maximumLanguageVersion=\"1.4\">"
1316 + PMD.EOL
1317 + "</rule></ruleset>";
1318
1319 private static final String DIRECT_DEPRECATED_RULE = "<?xml version=\"1.0\"?>"
1320 + PMD.EOL
1321 + "<ruleset name=\"test\">"
1322 + PMD.EOL
1323 + "<description>testdesc</description>"
1324 + PMD.EOL
1325 + "<rule "
1326 + PMD.EOL
1327 + "name=\"MockRuleName\" "
1328 + PMD.EOL
1329 + "message=\"avoid the mock rule\" "
1330 + PMD.EOL
1331 + "class=\"net.sourceforge.pmd.lang.rule.MockRule\" deprecated=\"true\">"
1332 + PMD.EOL + "</rule></ruleset>";
1333
1334 // Note: Update this RuleSet name to a different RuleSet with deprecated
1335 // Rules when the Rules are finally removed.
1336 private static final String DEPRECATED_RULE_RULESET_NAME = "rulesets/java/basic.xml";
1337
1338 // Note: Update this Rule name to a different deprecated Rule when the one
1339 // listed here is finally removed.
1340 private static final String DEPRECATED_RULE_NAME = "EmptyCatchBlock";
1341
1342 private static final String REFERENCE_TO_DEPRECATED_RULE = "<?xml version=\"1.0\"?>"
1343 + PMD.EOL
1344 + "<ruleset name=\"test\">"
1345 + PMD.EOL
1346 + "<description>testdesc</description>"
1347 + PMD.EOL
1348 + "<rule "
1349 + PMD.EOL
1350 + "ref=\""
1351 + DEPRECATED_RULE_RULESET_NAME
1352 + "/"
1353 + DEPRECATED_RULE_NAME + "\">" + PMD.EOL + "</rule></ruleset>";
1354
1355 private static final String REFERENCE_TO_RULESET_WITH_DEPRECATED_RULE = "<?xml version=\"1.0\"?>"
1356 + PMD.EOL
1357 + "<ruleset name=\"test\">"
1358 + PMD.EOL
1359 + "<description>testdesc</description>"
1360 + PMD.EOL
1361 + "<rule "
1362 + PMD.EOL
1363 + "ref=\""
1364 + DEPRECATED_RULE_RULESET_NAME
1365 + "\">"
1366 + PMD.EOL + "</rule></ruleset>";
1367
1368 private static final String DFA = "<?xml version=\"1.0\"?>" + PMD.EOL
1369 + "<ruleset name=\"test\">" + PMD.EOL
1370 + "<description>testdesc</description>" + PMD.EOL + "<rule "
1371 + PMD.EOL + "name=\"MockRuleName\" " + PMD.EOL
1372 + "message=\"avoid the mock rule\" " + PMD.EOL + "dfa=\"true\" "
1373 + PMD.EOL + "class=\"net.sourceforge.pmd.lang.rule.MockRule\">"
1374 + "<priority>3</priority>" + PMD.EOL + "</rule></ruleset>";
1375
1376 private static final String INCLUDE_EXCLUDE_RULESET = "<?xml version=\"1.0\"?>"
1377 + PMD.EOL
1378 + "<ruleset name=\"test\">"
1379 + PMD.EOL
1380 + "<description>testdesc</description>"
1381 + PMD.EOL
1382 + "<include-pattern>include1</include-pattern>"
1383 + PMD.EOL
1384 + "<include-pattern>include2</include-pattern>"
1385 + PMD.EOL
1386 + "<exclude-pattern>exclude1</exclude-pattern>"
1387 + PMD.EOL
1388 + "<exclude-pattern>exclude2</exclude-pattern>"
1389 + PMD.EOL
1390 + "<exclude-pattern>exclude3</exclude-pattern>"
1391 + PMD.EOL
1392 + "</ruleset>";
1393
1394 private static final String EXTERNAL_REFERENCE_RULE_SET = "<?xml version=\"1.0\"?>"
1395 + PMD.EOL
1396 + "<ruleset name=\"test\">"
1397 + PMD.EOL
1398 + "<description>testdesc</description>"
1399 + PMD.EOL
1400 + "<rule ref=\"rulesets/java/unusedcode.xml/UnusedLocalVariable\"/>"
1401 + PMD.EOL + "</ruleset>";
1402
1403 private Rule loadFirstRule(String ruleSetXml)
1404 throws RuleSetNotFoundException {
1405 RuleSet rs = loadRuleSet(ruleSetXml);
1406 return rs.getRules().iterator().next();
1407 }
1408
1409 private RuleSet loadRuleSetByFileName(String ruleSetFileName)
1410 throws RuleSetNotFoundException {
1411 RuleSetFactory rsf = new RuleSetFactory();
1412 return rsf.createRuleSet(ruleSetFileName);
1413 }
1414
1415 private RuleSet loadRuleSet(String ruleSetXml)
1416 throws RuleSetNotFoundException {
1417 RuleSetFactory rsf = new RuleSetFactory();
1418 return rsf.createRuleSet(createRuleSetReferenceId(ruleSetXml));
1419 }
1420
1421 private static RuleSetReferenceId createRuleSetReferenceId(
1422 final String ruleSetXml) {
1423 return new RuleSetReferenceId(null) {
1424 @Override
1425 public InputStream getInputStream(ClassLoader classLoader)
1426 throws RuleSetNotFoundException {
1427 return new ByteArrayInputStream(ruleSetXml.getBytes());
1428 }
1429 };
1430 }
1431
1432 public static junit.framework.Test suite() {
1433 return new JUnit4TestAdapter(RuleSetFactoryTest.class);
1434 }
1435
1436 }