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 net.sourceforge.pmd.lang.Language;
33  import net.sourceforge.pmd.lang.LanguageVersion;
34  import net.sourceforge.pmd.lang.java.rule.unusedcode.UnusedLocalVariableRule;
35  import net.sourceforge.pmd.lang.rule.RuleReference;
36  import net.sourceforge.pmd.lang.rule.XPathRule;
37  import net.sourceforge.pmd.util.ResourceLoader;
38  
39  import org.junit.Assert;
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     /**
500      * Rule reference can't be resolved - ref is used instead of class and the class is old (pmd 4.3 and not pmd 5).
501      * @throws Exception any error
502      */
503     @Test(expected = RuntimeException.class)
504     public void testBug1202() throws Exception {
505         RuleSetReferenceId ref = createRuleSetReferenceId("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + 
506                 "<ruleset>\n" +
507                 "  <rule ref=\"net.sourceforge.pmd.rules.XPathRule\">\n" + 
508                 "    <priority>1</priority>\n" + 
509                 "    <properties>\n" + 
510                 "      <property name=\"xpath\" value=\"//TypeDeclaration\" />\n" + 
511                 "      <property name=\"message\" value=\"Foo\" />\n" + 
512                 "    </properties>\n" + 
513                 "  </rule>\n" + 
514                 "</ruleset>\n");
515         RuleSetFactory ruleSetFactory = new RuleSetFactory();
516         ruleSetFactory.createRuleSet(ref);
517     }
518 
519     /**
520      * See https://sourceforge.net/p/pmd/bugs/1225/
521      * @throws Exception any error
522      */
523     @Test
524     public void testEmptyRuleSetFile() throws Exception {
525         RuleSetReferenceId ref = createRuleSetReferenceId("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + 
526                 "\n" + 
527                 "<ruleset name=\"Custom ruleset\" xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n" + 
528                 "    xmlns:xsi=\"http:www.w3.org/2001/XMLSchema-instance\"\n" + 
529                 "    xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd\">\n" + 
530                 "    <description>PMD Ruleset.</description>\n" + 
531                 "\n" + 
532                 "    <exclude-pattern>.*Test.*</exclude-pattern>\n" + 
533                 "\n" + 
534                 "</ruleset>\n");
535         RuleSetFactory ruleSetFactory = new RuleSetFactory();
536         RuleSet ruleset = ruleSetFactory.createRuleSet(ref);
537         assertEquals(0, ruleset.getRules().size());
538     }
539 
540     /**
541      * See https://sourceforge.net/p/pmd/bugs/1231/
542      * @throws Exception any error
543      */
544     @Test(expected = IllegalArgumentException.class)
545     public void testWrongRuleNameReferenced() throws Exception {
546         RuleSetReferenceId ref = createRuleSetReferenceId("<?xml version=\"1.0\"?>\n" + 
547                 "<ruleset name=\"Custom ruleset for tests\"\n" + 
548                 "    xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n" + 
549                 "    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" + 
550                 "    xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd\">\n" + 
551                 "  <description>Custom ruleset for tests</description>\n" + 
552                 "  <rule ref=\"rulesets/java/basic.xml/ThisRuleDoesNotExist\"/>\n" + 
553                 "</ruleset>\n");
554         RuleSetFactory ruleSetFactory = new RuleSetFactory();
555         ruleSetFactory.createRuleSet(ref);
556     }
557 
558     /**
559      * See https://sourceforge.net/p/pmd/bugs/1231/
560      * @throws Exception any error
561      */
562     @Test(expected = IllegalArgumentException.class)
563     public void testWrongRuleNameExcluded() throws Exception {
564         RuleSetReferenceId ref = createRuleSetReferenceId("<?xml version=\"1.0\"?>\n" + 
565                 "<ruleset name=\"Custom ruleset for tests\"\n" + 
566                 "    xmlns=\"http://pmd.sourceforge.net/ruleset/2.0.0\"\n" + 
567                 "    xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" + 
568                 "    xsi:schemaLocation=\"http://pmd.sourceforge.net/ruleset/2.0.0 http://pmd.sourceforge.net/ruleset_2_0_0.xsd\">\n" + 
569                 "  <description>Custom ruleset for tests</description>\n" + 
570                 "  <rule ref=\"rulesets/java/basic.xml\">\n" + 
571                 "    <exclude name=\"ThisRuleDoesNotExist\"/>\n" + 
572                 "  </rule>\n" + 
573                 "</ruleset>\n");
574         RuleSetFactory ruleSetFactory = new RuleSetFactory();
575         ruleSetFactory.createRuleSet(ref);
576     }
577 
578 	@Test
579 	public void testAllPMDBuiltInRulesMeetConventions() throws IOException,
580 			RuleSetNotFoundException, ParserConfigurationException,
581 			SAXException {
582 		int invalidSinceAttributes = 0;
583 		int invalidExternalInfoURL = 0;
584 		int invalidClassName = 0;
585 		int invalidRegexSuppress = 0;
586 		int invalidXPathSuppress = 0;
587 		String messages = "";
588 		List<String> ruleSetFileNames = getRuleSetFileNames();
589 		for (String fileName : ruleSetFileNames) {
590 			RuleSet ruleSet = loadRuleSetByFileName(fileName);
591 			for (Rule rule : ruleSet.getRules()) {
592 
593 				// Skip references
594 				if (rule instanceof RuleReference) {
595 					continue;
596 				}
597 
598 				Language language = rule.getLanguage();
599 				String group = fileName
600 						.substring(fileName.lastIndexOf('/') + 1);
601 				group = group.substring(0, group.indexOf(".xml"));
602 				if (group.indexOf('-') >= 0) {
603 					group = group.substring(0, group.indexOf('-'));
604 				}
605 
606 				// Is since missing ?
607 				if (rule.getSince() == null) {
608 					invalidSinceAttributes++;
609 					messages += "Rule " + fileName + "/" + rule.getName()
610 							+ " is missing 'since' attribute" + PMD.EOL;
611 				}
612 				// Is URL valid ?
613 				if (rule.getExternalInfoUrl() == null
614 						|| "".equalsIgnoreCase(rule.getExternalInfoUrl())) {
615 					invalidExternalInfoURL++;
616 					messages += "Rule " + fileName + "/" + rule.getName()
617 							+ " is missing 'externalInfoURL' attribute"
618 							+ PMD.EOL;
619 				} else {
620 					String expectedExternalInfoURL = "http://pmd.sourceforge.net/.+/rules/"
621 							+ fileName.replaceAll("rulesets/", "").replaceAll(
622 									".xml", "") + ".html#" + rule.getName();
623 					if (rule.getExternalInfoUrl() == null
624 						|| !rule.getExternalInfoUrl().matches(expectedExternalInfoURL)) {
625 						invalidExternalInfoURL++;
626 						messages += "Rule "
627 								+ fileName
628 								+ "/"
629 								+ rule.getName()
630 								+ " seems to have an invalid 'externalInfoURL' value ("
631 								+ rule.getExternalInfoUrl()
632 								+ "), it should be:" + expectedExternalInfoURL
633 								+ PMD.EOL;
634 					}
635 				}
636 				// Proper class name/packaging?
637 				String expectedClassName = "net.sourceforge.pmd.lang."
638 						+ language.getTerseName() + ".rule." + group + "."
639 						+ rule.getName() + "Rule";
640 				if (!rule.getRuleClass().equals(expectedClassName)
641 						&& !rule.getRuleClass().equals(
642 								XPathRule.class.getName())) {
643 					invalidClassName++;
644 					messages += "Rule " + fileName + "/" + rule.getName()
645 							+ " seems to have an invalid 'class' value ("
646 							+ rule.getRuleClass() + "), it should be:"
647 							+ expectedClassName + PMD.EOL;
648 				}
649 				// Should not have violation suppress regex property
650 				if (rule.getProperty(Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR) != null) {
651 					invalidRegexSuppress++;
652 					messages += "Rule "
653 							+ fileName
654 							+ "/"
655 							+ rule.getName()
656 							+ " should not have '"
657 							+ Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR.name()
658 							+ "', this is intended for end user customization only."
659 							+ PMD.EOL;
660 				}
661 				// Should not have violation suppress xpath property
662 				if (rule.getProperty(Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR) != null) {
663 					invalidXPathSuppress++;
664 					messages += "Rule "
665 							+ fileName
666 							+ "/"
667 							+ rule.getName()
668 							+ " should not have '"
669 							+ Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR.name()
670 							+ "', this is intended for end user customization only."
671 							+ PMD.EOL;
672 				}
673 			}
674 		}
675 		// We do this at the end to ensure we test ALL the rules before failing
676 		// the test
677 		if (invalidSinceAttributes > 0 || invalidExternalInfoURL > 0
678 				|| invalidClassName > 0 || invalidRegexSuppress > 0
679 				|| invalidXPathSuppress > 0) {
680 			fail("All built-in PMD rules need 'since' attribute ("
681 					+ invalidSinceAttributes
682 					+ " are missing), a proper ExternalURLInfo ("
683 					+ invalidExternalInfoURL
684 					+ " are invalid), a class name meeting conventions ("
685 					+ invalidClassName + " are invalid), no '"
686 					+ Rule.VIOLATION_SUPPRESS_REGEX_DESCRIPTOR.name()
687 					+ "' property (" + invalidRegexSuppress
688 					+ " are invalid), and no '"
689 					+ Rule.VIOLATION_SUPPRESS_XPATH_DESCRIPTOR.name()
690 					+ "' property (" + invalidXPathSuppress + " are invalid)"
691 					+ PMD.EOL + messages);
692 		}
693 	}
694 
695 	@Test
696 	public void testXmlSchema() throws IOException, RuleSetNotFoundException,
697 			ParserConfigurationException, SAXException {
698 		boolean allValid = true;
699 		List<String> ruleSetFileNames = getRuleSetFileNames();
700 		for (String fileName : ruleSetFileNames) {
701 			boolean valid = validateAgainstSchema(fileName);
702 			allValid = allValid && valid;
703 		}
704 		assertTrue("All XML must parse without producing validation messages.",
705 				allValid);
706 	}
707 
708 	@Test
709 	public void testDtd() throws IOException, RuleSetNotFoundException,
710 			ParserConfigurationException, SAXException {
711 		boolean allValid = true;
712 		List<String> ruleSetFileNames = getRuleSetFileNames();
713 		for (String fileName : ruleSetFileNames) {
714 			boolean valid = validateAgainstDtd(fileName);
715 			allValid = allValid && valid;
716 		}
717 		assertTrue("All XML must parse without producing validation messages.",
718 				allValid);
719 	}
720 
721 	@Test
722 	public void testReadWriteRoundTrip() throws IOException,
723 			RuleSetNotFoundException, ParserConfigurationException,
724 			SAXException {
725 
726 		List<String> ruleSetFileNames = getRuleSetFileNames();
727 		for (String fileName : ruleSetFileNames) {
728 			testRuleSet(fileName);
729 		}
730 	}
731 
732 	private void testRuleSet(String fileName) throws IOException,
733 			RuleSetNotFoundException, ParserConfigurationException,
734 			SAXException {
735 
736 		// Load original XML
737 //		String xml1 = readFullyToString(ResourceLoader.loadResourceAsStream(fileName));
738 //		System.out.println("xml1: " + xml1);
739 
740 		// Load the original RuleSet
741 		RuleSet ruleSet1 = loadRuleSetByFileName(fileName);
742 
743 		// Write to XML, first time
744 		ByteArrayOutputStream outputStream1 = new ByteArrayOutputStream();
745 		RuleSetWriter writer1 = new RuleSetWriter(outputStream1);
746 		writer1.write(ruleSet1);
747 		writer1.close();
748 		String xml2 = new String(outputStream1.toByteArray());
749 		// System.out.println("xml2: " + xml2);
750 
751 		// Read RuleSet from XML, first time
752 		RuleSetFactory ruleSetFactory = new RuleSetFactory();
753 		RuleSet ruleSet2 = ruleSetFactory
754 				.createRuleSet(createRuleSetReferenceId(xml2));
755 
756 		// Do write/read a 2nd time, just to be sure
757 
758 		// Write to XML, second time
759 		ByteArrayOutputStream outputStream2 = new ByteArrayOutputStream();
760 		RuleSetWriter writer2 = new RuleSetWriter(outputStream2);
761 		writer2.write(ruleSet2);
762 		writer2.close();
763 		String xml3 = new String(outputStream2.toByteArray());
764 		// System.out.println("xml3: " + xml3);
765 
766 		// Read RuleSet from XML, second time
767 		RuleSet ruleSet3 = ruleSetFactory
768 				.createRuleSet(createRuleSetReferenceId(xml3));
769 
770 		// The 2 written XMLs should all be valid w.r.t Schema/DTD
771 		assertTrue(
772 				"1st roundtrip RuleSet XML is not valid against Schema (filename: " + fileName + ")",
773 				validateAgainstSchema(new ByteArrayInputStream(xml2.getBytes())));
774 		assertTrue(
775 				"2nd roundtrip RuleSet XML is not valid against Schema (filename: " + fileName + ")",
776 				validateAgainstSchema(new ByteArrayInputStream(xml3.getBytes())));
777 		assertTrue("1st roundtrip RuleSet XML is not valid against DTD (filename: " + fileName + ")",
778 				validateAgainstDtd(new ByteArrayInputStream(xml2.getBytes())));
779 		assertTrue("2nd roundtrip RuleSet XML is not valid against DTD (filename: " + fileName + ")",
780 				validateAgainstDtd(new ByteArrayInputStream(xml3.getBytes())));
781 
782 		// All 3 versions of the RuleSet should be the same
783 		assertEqualsRuleSet(
784 				"Original RuleSet and 1st roundtrip Ruleset not the same (filename: " + fileName + ")",
785 				ruleSet1, ruleSet2);
786 		assertEqualsRuleSet(
787 				"1st roundtrip Ruleset and 2nd roundtrip RuleSet not the same (filename: " + fileName + ")",
788 				ruleSet2, ruleSet3);
789 
790 		// It's hard to compare the XML DOMs. At least the roundtrip ones should
791 		// textually be the same.
792 		assertEquals("1st roundtrip RuleSet XML and 2nd roundtrip RuleSet XML (filename: " + fileName + ")",
793 				xml2, xml3);
794 	}
795 
796 	private void assertEqualsRuleSet(String message, RuleSet ruleSet1,
797 			RuleSet ruleSet2) {
798 		assertEquals(message + ", RuleSet name", ruleSet1.getName(), ruleSet2
799 				.getName());
800 		assertEquals(message + ", RuleSet description", ruleSet1
801 				.getDescription(), ruleSet2.getDescription());
802 		assertEquals(message + ", RuleSet exclude patterns", ruleSet1
803 				.getExcludePatterns(), ruleSet2.getExcludePatterns());
804 		assertEquals(message + ", RuleSet include patterns", ruleSet1
805 				.getIncludePatterns(), ruleSet2.getIncludePatterns());
806 		assertEquals(message + ", RuleSet rule count", ruleSet1.getRules()
807 				.size(), ruleSet2.getRules().size());
808 
809 		for (int i = 0; i < ruleSet1.getRules().size(); i++) {
810 			Rule rule1 = ((List<Rule>) ruleSet1.getRules()).get(i);
811 			Rule rule2 = ((List<Rule>) ruleSet2.getRules()).get(i);
812 
813 			assertFalse(message + ", Different RuleReference",
814 					rule1 instanceof RuleReference
815 							&& !(rule2 instanceof RuleReference)
816 							|| !(rule1 instanceof RuleReference)
817 							&& rule2 instanceof RuleReference);
818 
819 			if (rule1 instanceof RuleReference) {
820 				RuleReference ruleReference1 = (RuleReference) rule1;
821 				RuleReference ruleReference2 = (RuleReference) rule2;
822 				assertEquals(message + ", RuleReference overridden language",
823 						ruleReference1.getOverriddenLanguage(), ruleReference2
824 								.getOverriddenLanguage());
825 				assertEquals(
826 						message
827 								+ ", RuleReference overridden minimum language version",
828 						ruleReference1.getOverriddenMinimumLanguageVersion(),
829 						ruleReference2.getOverriddenMinimumLanguageVersion());
830 				assertEquals(
831 						message
832 								+ ", RuleReference overridden maximum language version",
833 						ruleReference1.getOverriddenMaximumLanguageVersion(),
834 						ruleReference2.getOverriddenMaximumLanguageVersion());
835 				assertEquals(message + ", RuleReference overridden deprecated",
836 						ruleReference1.isOverriddenDeprecated(), ruleReference2
837 								.isOverriddenDeprecated());
838 				assertEquals(message + ", RuleReference overridden name",
839 						ruleReference1.getOverriddenName(), ruleReference2
840 								.getOverriddenName());
841 				assertEquals(
842 						message + ", RuleReference overridden description",
843 						ruleReference1.getOverriddenDescription(),
844 						ruleReference2.getOverriddenDescription());
845 				assertEquals(message + ", RuleReference overridden message",
846 						ruleReference1.getOverriddenMessage(), ruleReference2
847 								.getOverriddenMessage());
848 				assertEquals(message
849 						+ ", RuleReference overridden external info url",
850 						ruleReference1.getOverriddenExternalInfoUrl(),
851 						ruleReference2.getOverriddenExternalInfoUrl());
852 				assertEquals(message + ", RuleReference overridden priority",
853 						ruleReference1.getOverriddenPriority(), ruleReference2
854 								.getOverriddenPriority());
855 				assertEquals(message + ", RuleReference overridden examples",
856 						ruleReference1.getOverriddenExamples(), ruleReference2
857 								.getOverriddenExamples());
858 			}
859 
860 			assertEquals(message + ", Rule name", rule1.getName(), rule2
861 					.getName());
862 			assertEquals(message + ", Rule class", rule1.getRuleClass(), rule2
863 					.getRuleClass());
864 			assertEquals(message + ", Rule description " + rule1.getName(),
865 					rule1.getDescription(), rule2.getDescription());
866 			assertEquals(message + ", Rule message", rule1.getMessage(), rule2
867 					.getMessage());
868 			assertEquals(message + ", Rule external info url", rule1
869 					.getExternalInfoUrl(), rule2.getExternalInfoUrl());
870 			assertEquals(message + ", Rule priority", rule1.getPriority(),
871 					rule2.getPriority());
872 			assertEquals(message + ", Rule examples", rule1.getExamples(),
873 					rule2.getExamples());
874 
875 			List<PropertyDescriptor<?>> propertyDescriptors1 = rule1
876 					.getPropertyDescriptors();
877 			List<PropertyDescriptor<?>> propertyDescriptors2 = rule2
878 					.getPropertyDescriptors();
879 			try {
880 				assertEquals(message + ", Rule property descriptor ",
881 						propertyDescriptors1, propertyDescriptors2);
882 			} catch (Error e) {
883 				throw e;
884 			}
885 			for (int j = 0; j < propertyDescriptors1.size(); j++) {
886 				assertEquals(message + ", Rule property value " + j, rule1
887 						.getProperty(propertyDescriptors1.get(j)), rule2
888 						.getProperty(propertyDescriptors2.get(j)));
889 			}
890 			assertEquals(message + ", Rule property descriptor count",
891 					propertyDescriptors1.size(), propertyDescriptors2.size());
892 		}
893 	}
894 
895 	private boolean validateAgainstSchema(String fileName) throws IOException,
896 			RuleSetNotFoundException, ParserConfigurationException,
897 			SAXException {
898 		InputStream inputStream = loadResourceAsStream(fileName);
899 		boolean valid = validateAgainstSchema(inputStream);
900 		if (!valid) {
901 			System.err.println("Validation against XML Schema failed for: "
902 					+ fileName);
903 		}
904 		return valid;
905 	}
906 
907 	private boolean validateAgainstSchema(InputStream inputStream)
908 			throws IOException, RuleSetNotFoundException,
909 			ParserConfigurationException, SAXException {
910 		
911 		saxParser.parse(inputStream, validateDefaultHandlerXsd.resetValid());
912 		inputStream.close();
913 		return validateDefaultHandlerXsd.isValid();
914 	}
915 
916 	private boolean validateAgainstDtd(String fileName) throws IOException,
917 			RuleSetNotFoundException, ParserConfigurationException,
918 			SAXException {
919 		InputStream inputStream = loadResourceAsStream(fileName);
920 		boolean valid = validateAgainstDtd(inputStream);
921 		if (!valid) {
922 			System.err
923 					.println("Validation against DTD failed for: " + fileName);
924 		}
925 		return valid;
926 	}
927 
928 	private boolean validateAgainstDtd(InputStream inputStream)
929 			throws IOException, RuleSetNotFoundException,
930 			ParserConfigurationException, SAXException {
931 		
932 		// Read file into memory
933 		String file = readFullyToString(inputStream);
934 
935 		// Remove XML Schema stuff, replace with DTD
936 		file = file.replaceAll("<\\?xml [ a-zA-Z0-9=\".-]*\\?>", "");
937 		file = file.replaceAll(
938 				"xmlns=\"" + RuleSetWriter.RULESET_NS_URI + "\"", "");
939 		file = file.replaceAll(
940 				"xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", "");
941 		file = file
942 				.replaceAll(
943 						"xsi:schemaLocation=\"" + RuleSetWriter.RULESET_NS_URI + " http://pmd.sourceforge.net/ruleset_2_0_0.xsd\"",
944 						"");
945 
946 		file = "<?xml version=\"1.0\"?>" + PMD.EOL
947 				+ "<!DOCTYPE ruleset SYSTEM \"file://"
948 				+ System.getProperty("user.dir") + "/src/main/resources/ruleset_2_0_0.dtd\">"
949 				+ PMD.EOL + file;
950 
951 		inputStream = new ByteArrayInputStream(file.getBytes());
952 
953 		saxParser.parse(inputStream, validateDefaultHandlerDtd.resetValid());
954 		inputStream.close();
955 		return validateDefaultHandlerDtd.isValid();
956 	}
957 
958 	private String readFullyToString(InputStream inputStream)
959 			throws IOException {
960 		StringBuilder buf = new StringBuilder(64 * 1024);
961 		BufferedReader reader = new BufferedReader(new InputStreamReader(
962 				inputStream));
963 		String line;
964 		while ((line = reader.readLine()) != null) {
965 			buf.append(line);
966 			buf.append(PMD.EOL);
967 		}
968 		reader.close();
969 		return buf.toString();
970 	}
971 
972 	// Gets all test PMD Ruleset XML files
973     private List<String> getRuleSetFileNames() throws IOException,
974     RuleSetNotFoundException {
975         List<String> result = new ArrayList<String>();
976 
977         for (Language language : Language.values()) {
978             result.addAll(getRuleSetFileNames(language.getTerseName()));
979         }
980 
981         return result;
982     }
983 
984     private List<String> getRuleSetFileNames(String language) throws IOException, RuleSetNotFoundException {
985         List<String> ruleSetFileNames = new ArrayList<String>();
986         try {
987             Properties properties = new Properties();
988             properties.load(ResourceLoader.loadResourceAsStream("rulesets/" + language + "/rulesets.properties"));
989             String fileNames = properties.getProperty("rulesets.filenames");
990             StringTokenizer st = new StringTokenizer(fileNames, ",");
991             while (st.hasMoreTokens()) {
992                 ruleSetFileNames.add(st.nextToken());
993             }
994         } catch (RuleSetNotFoundException e) {
995             // this might happen if a language is only support by CPD, but not by PMD
996             System.err.println("No ruleset found for language " + language);
997         }
998         return ruleSetFileNames;
999     }
1000 
1001 	private static class ValidateDefaultHandler extends DefaultHandler {
1002 		private final String validateDocument;
1003 		private boolean valid = true;
1004 
1005 		public ValidateDefaultHandler(String validateDocument) {
1006 			this.validateDocument = validateDocument;
1007 		}
1008 		
1009 		public ValidateDefaultHandler resetValid() {
1010 			valid = true;
1011 			return this;
1012 		}
1013 
1014 		public boolean isValid() {
1015 			return valid;
1016 		}
1017 
1018 		@Override
1019 		public void error(SAXParseException e) throws SAXException {
1020 			log("Error", e);
1021 		}
1022 
1023 		@Override
1024 		public void fatalError(SAXParseException e) throws SAXException {
1025 			log("FatalError", e);
1026 		}
1027 
1028 		@Override
1029 		public void warning(SAXParseException e) throws SAXException {
1030 			log("Warning", e);
1031 		}
1032 
1033 		private void log(String prefix, SAXParseException e) {
1034 			String message = prefix + " at (" + e.getLineNumber() + ", " + e.getColumnNumber() + "): " + e.getMessage();
1035 			System.err.println(message);
1036 			valid = false;
1037 		}
1038 
1039 		@Override
1040 		public InputSource resolveEntity(String publicId, String systemId)
1041 				throws IOException, SAXException {
1042 			if ("http://pmd.sourceforge.net/ruleset_2_0_0.xsd".equals(systemId)
1043 					|| systemId.endsWith("ruleset_2_0_0.dtd")) {
1044 				try {
1045 					InputStream inputStream = loadResourceAsStream(validateDocument);
1046 					return new InputSource(inputStream);
1047 				} catch (RuleSetNotFoundException e) {
1048 					System.err.println(e.getMessage());
1049 					throw new IOException(e.getMessage());
1050 				}
1051 			}
1052 			throw new IllegalArgumentException(
1053 					"No clue how to handle: publicId=" + publicId
1054 							+ ", systemId=" + systemId);
1055 		}
1056 	}
1057 
1058 	private static InputStream loadResourceAsStream(String resource)
1059 			throws RuleSetNotFoundException {
1060 		InputStream inputStream = ResourceLoader.loadResourceAsStream(resource,
1061 				RuleSetFactoryTest.class.getClassLoader());
1062 		if (inputStream == null) {
1063 			throw new RuleSetNotFoundException(
1064 					"Can't find resource "
1065 							+ resource
1066 							+ "  Make sure the resource is a valid file or URL or is on the CLASSPATH.  Here's the current classpath: "
1067 							+ System.getProperty("java.class.path"));
1068 		}
1069 		return inputStream;
1070 	}
1071 
1072 	private static final String REF_OVERRIDE_ORIGINAL_NAME = "<?xml version=\"1.0\"?>"
1073 			+ PMD.EOL
1074 			+ "<ruleset name=\"test\">"
1075 			+ PMD.EOL
1076 			+ " <description>testdesc</description>"
1077 			+ PMD.EOL
1078 			+ " <rule "
1079 			+ PMD.EOL
1080 			+ "  ref=\"rulesets/java/unusedcode.xml/UnusedLocalVariable\" message=\"TestMessageOverride\"> "
1081 			+ PMD.EOL + " </rule>" + PMD.EOL + "</ruleset>";
1082 
1083 	private static final String REF_MISPELLED_XREF = "<?xml version=\"1.0\"?>"
1084 			+ PMD.EOL + "<ruleset name=\"test\">" + PMD.EOL
1085 			+ " <description>testdesc</description>" + PMD.EOL + " <rule "
1086 			+ PMD.EOL
1087 			+ "  ref=\"rulesets/java/unusedcode.xml/FooUnusedLocalVariable\"> "
1088 			+ PMD.EOL + " </rule>" + PMD.EOL + "</ruleset>";
1089 
1090 	private static final String REF_OVERRIDE_ORIGINAL_NAME_ONE_ELEM = "<?xml version=\"1.0\"?>"
1091 			+ PMD.EOL
1092 			+ "<ruleset name=\"test\">"
1093 			+ PMD.EOL
1094 			+ " <description>testdesc</description>"
1095 			+ PMD.EOL
1096 			+ " <rule ref=\"rulesets/java/unusedcode.xml/UnusedLocalVariable\" message=\"TestMessageOverride\"/> "
1097 			+ PMD.EOL + "</ruleset>";
1098 
1099 	private static final String REF_OVERRIDE = "<?xml version=\"1.0\"?>"
1100 			+ PMD.EOL
1101 			+ "<ruleset name=\"test\">"
1102 			+ PMD.EOL
1103 			+ " <description>testdesc</description>"
1104 			+ PMD.EOL
1105 			+ " <rule "
1106 			+ PMD.EOL
1107 			+ "  ref=\"rulesets/java/unusedcode.xml/UnusedLocalVariable\" "
1108 			+ PMD.EOL
1109 			+ "  name=\"TestNameOverride\" "
1110 			+ PMD.EOL
1111 			+ "  message=\"Test message override\"> "
1112 			+ PMD.EOL
1113 			+ "  <description>Test description override</description>"
1114 			+ PMD.EOL
1115 			+ "  <example>Test example override</example>"
1116 			+ PMD.EOL
1117 			+ "  <priority>3</priority>"
1118 			+ PMD.EOL
1119 			+ "  <properties>"
1120 			+ PMD.EOL
1121 			+ "   <property name=\"test2\" description=\"test2\" type=\"String\" value=\"override2\"/>"
1122 			+ PMD.EOL
1123 			+ "   <property name=\"test3\" description=\"test3\" type=\"String\"><value>override3</value></property>"
1124 			+ PMD.EOL
1125 			+ "   <property name=\"test4\" description=\"test4\" type=\"String\" value=\"new property\"/>"
1126 			+ PMD.EOL + "  </properties>" + PMD.EOL + " </rule>" + PMD.EOL
1127 			+ "</ruleset>";
1128 
1129 	private static final String REF_INTERNAL_TO_INTERNAL = "<?xml version=\"1.0\"?>"
1130 			+ PMD.EOL
1131 			+ "<ruleset name=\"test\">"
1132 			+ PMD.EOL
1133 			+ " <description>testdesc</description>"
1134 			+ PMD.EOL
1135 			+ "<rule "
1136 			+ PMD.EOL
1137 			+ "name=\"MockRuleName\" "
1138 			+ PMD.EOL
1139 			+ "message=\"avoid the mock rule\" "
1140 			+ PMD.EOL
1141 			+ "class=\"net.sourceforge.pmd.lang.rule.MockRule\">"
1142 			+ PMD.EOL
1143 			+ "</rule>"
1144 			+ " <rule ref=\"MockRuleName\" name=\"MockRuleNameRef\"/> "
1145 			+ PMD.EOL + "</ruleset>";
1146 
1147 	private static final String REF_INTERNAL_TO_INTERNAL_CHAIN = "<?xml version=\"1.0\"?>"
1148 			+ PMD.EOL
1149 			+ "<ruleset name=\"test\">"
1150 			+ PMD.EOL
1151 			+ " <description>testdesc</description>"
1152 			+ PMD.EOL
1153 			+ "<rule "
1154 			+ PMD.EOL
1155 			+ "name=\"MockRuleName\" "
1156 			+ PMD.EOL
1157 			+ "message=\"avoid the mock rule\" "
1158 			+ PMD.EOL
1159 			+ "class=\"net.sourceforge.pmd.lang.rule.MockRule\">"
1160 			+ PMD.EOL
1161 			+ "</rule>"
1162 			+ " <rule ref=\"MockRuleName\" name=\"MockRuleNameRef\"><priority>2</priority></rule> "
1163 			+ PMD.EOL
1164 			+ " <rule ref=\"MockRuleNameRef\" name=\"MockRuleNameRefRef\"><priority>1</priority></rule> "
1165 			+ PMD.EOL + "</ruleset>";
1166 
1167 	private static final String REF_INTERNAL_TO_EXTERNAL = "<?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\"/> "
1180 			+ PMD.EOL + "</ruleset>";
1181 
1182 	private static final String REF_INTERNAL_TO_EXTERNAL_CHAIN = "<?xml version=\"1.0\"?>"
1183 			+ PMD.EOL
1184 			+ "<ruleset name=\"test\">"
1185 			+ PMD.EOL
1186 			+ " <description>testdesc</description>"
1187 			+ PMD.EOL
1188 			+ "<rule "
1189 			+ PMD.EOL
1190 			+ "name=\"ExternalRefRuleName\" "
1191 			+ PMD.EOL
1192 			+ "ref=\"rulesets/java/unusedcode.xml/UnusedLocalVariable\"/>"
1193 			+ PMD.EOL
1194 			+ " <rule ref=\"ExternalRefRuleName\" name=\"ExternalRefRuleNameRef\"><priority>2</priority></rule> "
1195 			+ PMD.EOL
1196 			+ " <rule ref=\"ExternalRefRuleNameRef\" name=\"ExternalRefRuleNameRefRef\"><priority>1</priority></rule> "
1197 			+ PMD.EOL + "</ruleset>";
1198 
1199 	private static final String EMPTY_RULESET = "<?xml version=\"1.0\"?>"
1200 			+ PMD.EOL + "<ruleset name=\"test\">" + PMD.EOL
1201 			+ "<description>testdesc</description>" + PMD.EOL + "</ruleset>";
1202 
1203 	private static final String SINGLE_RULE = "<?xml version=\"1.0\"?>"
1204 			+ PMD.EOL + "<ruleset name=\"test\">" + PMD.EOL
1205 			+ "<description>testdesc</description>" + PMD.EOL + "<rule "
1206 			+ PMD.EOL + "name=\"MockRuleName\" " + PMD.EOL
1207 			+ "message=\"avoid the mock rule\" " + PMD.EOL
1208 			+ "class=\"net.sourceforge.pmd.lang.rule.MockRule\">"
1209 			+ "<priority>3</priority>" + PMD.EOL + "</rule></ruleset>";
1210 
1211 	private static final String MULTIPLE_RULES = "<?xml version=\"1.0\"?>"
1212 			+ PMD.EOL + "<ruleset name=\"test\">" + PMD.EOL
1213 			+ "<description>testdesc</description>" + PMD.EOL
1214 			+ "<rule name=\"MockRuleName1\" " + PMD.EOL
1215 			+ "message=\"avoid the mock rule\" " + PMD.EOL
1216 			+ "class=\"net.sourceforge.pmd.lang.rule.MockRule\">" + PMD.EOL
1217 			+ "</rule>" + PMD.EOL + "<rule name=\"MockRuleName2\" " + PMD.EOL
1218 			+ "message=\"avoid the mock rule\" " + PMD.EOL
1219 			+ "class=\"net.sourceforge.pmd.lang.rule.MockRule\">" + PMD.EOL
1220 			+ "</rule></ruleset>";
1221 
1222 	private static final String PROPERTIES = "<?xml version=\"1.0\"?>"
1223 			+ PMD.EOL
1224 			+ "<ruleset name=\"test\">"
1225 			+ PMD.EOL
1226 			+ "<description>testdesc</description>"
1227 			+ PMD.EOL
1228 			+ "<rule name=\"MockRuleName\" "
1229 			+ PMD.EOL
1230 			+ "message=\"avoid the mock rule\" "
1231 			+ PMD.EOL
1232 			+ "class=\"net.sourceforge.pmd.lang.rule.MockRule\">"
1233 			+ PMD.EOL
1234 			+ "<description>testdesc2</description>"
1235 			+ PMD.EOL
1236 			+ "<properties>"
1237 			+ PMD.EOL
1238 			+ "<property name=\"fooBoolean\" description=\"test\" type=\"Boolean\" value=\"true\" />"
1239 			+ PMD.EOL
1240 			+ "<property name=\"fooChar\" description=\"test\" type=\"Character\" value=\"B\" />"
1241 			+ PMD.EOL
1242 			+ "<property name=\"fooInt\" description=\"test\" type=\"Integer\" min=\"1\" max=\"10\" value=\"3\" />"
1243 			+ PMD.EOL
1244 			+ "<property name=\"fooFloat\" description=\"test\" type=\"Float\" min=\"1.0\" max=\"1.0\" value=\"1.0\"  />"
1245 			+ PMD.EOL
1246 			+ "<property name=\"fooDouble\" description=\"test\" type=\"Double\" min=\"1.0\" max=\"9.0\" value=\"3.0\"  />"
1247 			+ PMD.EOL
1248 			+ "<property name=\"fooString\" description=\"test\" type=\"String\" value=\"bar\" />"
1249 			+ PMD.EOL + "</properties>" + PMD.EOL + "</rule></ruleset>";
1250 
1251 	private static final String XPATH = "<?xml version=\"1.0\"?>" + PMD.EOL
1252 			+ "<ruleset name=\"test\">" + PMD.EOL
1253 			+ "<description>testdesc</description>" + PMD.EOL
1254 			+ "<rule name=\"MockRuleName\" " + PMD.EOL
1255 			+ "message=\"avoid the mock rule\" " + PMD.EOL
1256 			+ "class=\"net.sourceforge.pmd.lang.rule.MockRule\">"
1257 			+ "<priority>3</priority>" + PMD.EOL + PMD.EOL
1258 			+ "<description>testdesc2</description>" + PMD.EOL + "<properties>"
1259 			+ PMD.EOL
1260 			+ "<property name=\"xpath\" description=\"test\" type=\"String\">"
1261 			+ PMD.EOL + "<value>" + PMD.EOL + "<![CDATA[ //Block ]]>" + PMD.EOL
1262 			+ "</value>" + PMD.EOL + "</property>" + PMD.EOL + "</properties>"
1263 			+ PMD.EOL + "</rule></ruleset>";
1264 
1265 	private static final String PRIORITY = "<?xml version=\"1.0\"?>" + PMD.EOL
1266 			+ "<ruleset name=\"test\">" + PMD.EOL
1267 			+ "<description>testdesc</description>" + PMD.EOL + "<rule "
1268 			+ PMD.EOL + "name=\"MockRuleName\" " + PMD.EOL
1269 			+ "message=\"avoid the mock rule\" " + PMD.EOL
1270 			+ "class=\"net.sourceforge.pmd.lang.rule.MockRule\">"
1271 			+ "<priority>3</priority>" + PMD.EOL + "</rule></ruleset>";
1272 
1273 	private static final String LANGUAGE = "<?xml version=\"1.0\"?>"
1274 			+ PMD.EOL
1275 			+ "<ruleset name=\"test\">"
1276 			+ PMD.EOL
1277 			+ "<description>testdesc</description>"
1278 			+ PMD.EOL
1279 			+ "<rule "
1280 			+ PMD.EOL
1281 			+ "name=\"MockRuleName\" "
1282 			+ PMD.EOL
1283 			+ "message=\"avoid the mock rule\" "
1284 			+ PMD.EOL
1285 			+ "class=\"net.sourceforge.pmd.lang.rule.MockRule\" language=\"java\">"
1286 			+ PMD.EOL + "</rule></ruleset>";
1287 
1288 	private static final String INCORRECT_LANGUAGE = "<?xml version=\"1.0\"?>"
1289 			+ PMD.EOL + "<ruleset name=\"test\">" + PMD.EOL
1290 			+ "<description>testdesc</description>" + PMD.EOL + "<rule "
1291 			+ PMD.EOL + "name=\"MockRuleName\" " + PMD.EOL
1292 			+ "message=\"avoid the mock rule\" " + PMD.EOL
1293 			+ "class=\"net.sourceforge.pmd.lang.rule.MockRule\"" + PMD.EOL
1294 			+ " language=\"bogus\">" + PMD.EOL + "</rule></ruleset>";
1295 
1296 	private static final String MINIMUM_LANGUAGE_VERSION = "<?xml version=\"1.0\"?>"
1297 			+ PMD.EOL
1298 			+ "<ruleset name=\"test\">"
1299 			+ PMD.EOL
1300 			+ "<description>testdesc</description>"
1301 			+ PMD.EOL
1302 			+ "<rule "
1303 			+ PMD.EOL
1304 			+ "name=\"MockRuleName\" "
1305 			+ PMD.EOL
1306 			+ "message=\"avoid the mock rule\" "
1307 			+ PMD.EOL
1308 			+ "class=\"net.sourceforge.pmd.lang.rule.MockRule\""
1309 			+ PMD.EOL
1310 			+ " language=\"java\""
1311 			+ PMD.EOL
1312 			+ " minimumLanguageVersion=\"1.4\">"
1313 			+ PMD.EOL
1314 			+ "</rule></ruleset>";
1315 
1316 	private static final String INCORRECT_MINIMUM_LANGUAGE_VERSION = "<?xml version=\"1.0\"?>"
1317 			+ PMD.EOL
1318 			+ "<ruleset name=\"test\">"
1319 			+ PMD.EOL
1320 			+ "<description>testdesc</description>"
1321 			+ PMD.EOL
1322 			+ "<rule "
1323 			+ PMD.EOL
1324 			+ "name=\"MockRuleName\" "
1325 			+ PMD.EOL
1326 			+ "message=\"avoid the mock rule\" "
1327 			+ PMD.EOL
1328 			+ "class=\"net.sourceforge.pmd.lang.rule.MockRule\""
1329 			+ PMD.EOL
1330 			+ " language=\"java\""
1331 			+ PMD.EOL
1332 			+ " minimumLanguageVersion=\"bogus\">"
1333 			+ PMD.EOL
1334 			+ "</rule></ruleset>";
1335 
1336 	private static final String MAXIMUM_LANGUAGE_VERSION = "<?xml version=\"1.0\"?>"
1337 			+ PMD.EOL
1338 			+ "<ruleset name=\"test\">"
1339 			+ PMD.EOL
1340 			+ "<description>testdesc</description>"
1341 			+ PMD.EOL
1342 			+ "<rule "
1343 			+ PMD.EOL
1344 			+ "name=\"MockRuleName\" "
1345 			+ PMD.EOL
1346 			+ "message=\"avoid the mock rule\" "
1347 			+ PMD.EOL
1348 			+ "class=\"net.sourceforge.pmd.lang.rule.MockRule\""
1349 			+ PMD.EOL
1350 			+ " language=\"java\""
1351 			+ PMD.EOL
1352 			+ " maximumLanguageVersion=\"1.7\">"
1353 			+ PMD.EOL
1354 			+ "</rule></ruleset>";
1355 
1356 	private static final String INCORRECT_MAXIMUM_LANGUAGE_VERSION = "<?xml version=\"1.0\"?>"
1357 			+ PMD.EOL
1358 			+ "<ruleset name=\"test\">"
1359 			+ PMD.EOL
1360 			+ "<description>testdesc</description>"
1361 			+ PMD.EOL
1362 			+ "<rule "
1363 			+ PMD.EOL
1364 			+ "name=\"MockRuleName\" "
1365 			+ PMD.EOL
1366 			+ "message=\"avoid the mock rule\" "
1367 			+ PMD.EOL
1368 			+ "class=\"net.sourceforge.pmd.lang.rule.MockRule\""
1369 			+ PMD.EOL
1370 			+ " language=\"java\""
1371 			+ PMD.EOL
1372 			+ " maximumLanguageVersion=\"bogus\">"
1373 			+ PMD.EOL
1374 			+ "</rule></ruleset>";
1375 
1376 	private static final String INVERTED_MINIMUM_MAXIMUM_LANGUAGE_VERSIONS = "<?xml version=\"1.0\"?>"
1377 			+ PMD.EOL
1378 			+ "<ruleset name=\"test\">"
1379 			+ PMD.EOL
1380 			+ "<description>testdesc</description>"
1381 			+ PMD.EOL
1382 			+ "<rule "
1383 			+ PMD.EOL
1384 			+ "name=\"MockRuleName\" "
1385 			+ PMD.EOL
1386 			+ "message=\"avoid the mock rule\" "
1387 			+ PMD.EOL
1388 			+ "class=\"net.sourceforge.pmd.lang.rule.MockRule\" "
1389 			+ PMD.EOL
1390 			+ "language=\"java\""
1391 			+ PMD.EOL
1392 			+ " minimumLanguageVersion=\"1.7\""
1393 			+ PMD.EOL
1394 			+ "maximumLanguageVersion=\"1.4\">"
1395 			+ PMD.EOL
1396 			+ "</rule></ruleset>";
1397 
1398 	private static final String DIRECT_DEPRECATED_RULE = "<?xml version=\"1.0\"?>"
1399 			+ PMD.EOL
1400 			+ "<ruleset name=\"test\">"
1401 			+ PMD.EOL
1402 			+ "<description>testdesc</description>"
1403 			+ PMD.EOL
1404 			+ "<rule "
1405 			+ PMD.EOL
1406 			+ "name=\"MockRuleName\" "
1407 			+ PMD.EOL
1408 			+ "message=\"avoid the mock rule\" "
1409 			+ PMD.EOL
1410 			+ "class=\"net.sourceforge.pmd.lang.rule.MockRule\" deprecated=\"true\">"
1411 			+ PMD.EOL + "</rule></ruleset>";
1412 
1413 	// Note: Update this RuleSet name to a different RuleSet with deprecated
1414 	// Rules when the Rules are finally removed.
1415 	private static final String DEPRECATED_RULE_RULESET_NAME = "rulesets/java/basic.xml";
1416 
1417 	// Note: Update this Rule name to a different deprecated Rule when the one
1418 	// listed here is finally removed.
1419 	private static final String DEPRECATED_RULE_NAME = "EmptyCatchBlock";
1420 
1421 	private static final String REFERENCE_TO_DEPRECATED_RULE = "<?xml version=\"1.0\"?>"
1422 			+ PMD.EOL
1423 			+ "<ruleset name=\"test\">"
1424 			+ PMD.EOL
1425 			+ "<description>testdesc</description>"
1426 			+ PMD.EOL
1427 			+ "<rule "
1428 			+ PMD.EOL
1429 			+ "ref=\""
1430 			+ DEPRECATED_RULE_RULESET_NAME
1431 			+ "/"
1432 			+ DEPRECATED_RULE_NAME + "\">" + PMD.EOL + "</rule></ruleset>";
1433 
1434 	private static final String REFERENCE_TO_RULESET_WITH_DEPRECATED_RULE = "<?xml version=\"1.0\"?>"
1435 			+ PMD.EOL
1436 			+ "<ruleset name=\"test\">"
1437 			+ PMD.EOL
1438 			+ "<description>testdesc</description>"
1439 			+ PMD.EOL
1440 			+ "<rule "
1441 			+ PMD.EOL
1442 			+ "ref=\""
1443 			+ DEPRECATED_RULE_RULESET_NAME
1444 			+ "\">"
1445 			+ PMD.EOL + "</rule></ruleset>";
1446 
1447 	private static final String DFA = "<?xml version=\"1.0\"?>" + PMD.EOL
1448 			+ "<ruleset name=\"test\">" + PMD.EOL
1449 			+ "<description>testdesc</description>" + PMD.EOL + "<rule "
1450 			+ PMD.EOL + "name=\"MockRuleName\" " + PMD.EOL
1451 			+ "message=\"avoid the mock rule\" " + PMD.EOL + "dfa=\"true\" "
1452 			+ PMD.EOL + "class=\"net.sourceforge.pmd.lang.rule.MockRule\">"
1453 			+ "<priority>3</priority>" + PMD.EOL + "</rule></ruleset>";
1454 
1455 	private static final String INCLUDE_EXCLUDE_RULESET = "<?xml version=\"1.0\"?>"
1456 			+ PMD.EOL
1457 			+ "<ruleset name=\"test\">"
1458 			+ PMD.EOL
1459 			+ "<description>testdesc</description>"
1460 			+ PMD.EOL
1461 			+ "<include-pattern>include1</include-pattern>"
1462 			+ PMD.EOL
1463 			+ "<include-pattern>include2</include-pattern>"
1464 			+ PMD.EOL
1465 			+ "<exclude-pattern>exclude1</exclude-pattern>"
1466 			+ PMD.EOL
1467 			+ "<exclude-pattern>exclude2</exclude-pattern>"
1468 			+ PMD.EOL
1469 			+ "<exclude-pattern>exclude3</exclude-pattern>"
1470 			+ PMD.EOL
1471 			+ "</ruleset>";
1472 
1473 	private static final String EXTERNAL_REFERENCE_RULE_SET = "<?xml version=\"1.0\"?>"
1474 			+ PMD.EOL
1475 			+ "<ruleset name=\"test\">"
1476 			+ PMD.EOL
1477 			+ "<description>testdesc</description>"
1478 			+ PMD.EOL
1479 			+ "<rule ref=\"rulesets/java/unusedcode.xml/UnusedLocalVariable\"/>"
1480 			+ PMD.EOL + "</ruleset>";
1481 
1482 	private Rule loadFirstRule(String ruleSetXml)
1483 			throws RuleSetNotFoundException {
1484 		RuleSet rs = loadRuleSet(ruleSetXml);
1485 		return rs.getRules().iterator().next();
1486 	}
1487 
1488 	private RuleSet loadRuleSetByFileName(String ruleSetFileName)
1489 			throws RuleSetNotFoundException {
1490 		RuleSetFactory rsf = new RuleSetFactory();
1491 		return rsf.createRuleSet(ruleSetFileName);
1492 	}
1493 
1494 	private RuleSet loadRuleSet(String ruleSetXml)
1495 			throws RuleSetNotFoundException {
1496 		RuleSetFactory rsf = new RuleSetFactory();
1497 		return rsf.createRuleSet(createRuleSetReferenceId(ruleSetXml));
1498 	}
1499 
1500     private static RuleSetReferenceId createRuleSetReferenceId(final String ruleSetXml) {
1501         return new RuleSetReferenceId(null) {
1502             @Override
1503             public InputStream getInputStream(ClassLoader classLoader) throws RuleSetNotFoundException {
1504                 try {
1505                     return new ByteArrayInputStream(ruleSetXml.getBytes("UTF-8"));
1506                 } catch (UnsupportedEncodingException e) {
1507                     return null;
1508                 }
1509             }
1510         };
1511     }
1512 }