View Javadoc

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