1 /**
2 * BSD-style license; for more info see http://pmd.sourceforge.net/license.html
3 */
4 package test.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.assertNull;
10 import static org.junit.Assert.assertTrue;
11 import static org.junit.Assert.fail;
12
13 import java.io.BufferedReader;
14 import java.io.ByteArrayInputStream;
15 import java.io.ByteArrayOutputStream;
16 import java.io.IOException;
17 import java.io.InputStream;
18 import java.io.InputStreamReader;
19 import java.util.ArrayList;
20 import java.util.HashSet;
21 import java.util.Iterator;
22 import java.util.List;
23 import java.util.Properties;
24 import java.util.Set;
25 import java.util.StringTokenizer;
26
27 import javax.xml.parsers.ParserConfigurationException;
28 import javax.xml.parsers.SAXParser;
29 import javax.xml.parsers.SAXParserFactory;
30
31 import junit.framework.JUnit4TestAdapter;
32 import net.sourceforge.pmd.PMD;
33 import net.sourceforge.pmd.Rule;
34 import net.sourceforge.pmd.RuleReference;
35 import net.sourceforge.pmd.RuleSet;
36 import net.sourceforge.pmd.RuleSetFactory;
37 import net.sourceforge.pmd.RuleSetNotFoundException;
38 import net.sourceforge.pmd.RuleSetWriter;
39 import net.sourceforge.pmd.rules.UnusedLocalVariableRule;
40 import net.sourceforge.pmd.util.ResourceLoader;
41
42 import org.junit.Before;
43 import org.junit.Test;
44 import org.xml.sax.InputSource;
45 import org.xml.sax.SAXException;
46 import org.xml.sax.SAXParseException;
47 import org.xml.sax.helpers.DefaultHandler;
48
49 import test.net.sourceforge.pmd.testframework.TestDescriptor;
50
51 public class RuleSetFactoryTest {
52
53 private boolean isJdk14;
54
55 @Before
56 public void setUp() {
57 try {
58 Class.forName("java.lang.Appendable");
59 } catch (Throwable t) {
60 isJdk14 = true;
61 }
62 }
63
64 @Test
65 public void testRuleSetFileName() throws RuleSetNotFoundException {
66 RuleSet rs = loadRuleSet(EMPTY_RULESET);
67 assertNull("RuleSet file name not expected", rs.getFileName());
68
69 RuleSetFactory rsf = new RuleSetFactory();
70 rs = rsf.createSingleRuleSet("rulesets/basic.xml");
71 assertEquals("wrong RuleSet file name", rs.getFileName(), "rulesets/basic.xml");
72 }
73
74 @Test
75 public void testNoRuleSetFileName() {
76 RuleSet rs = loadRuleSet(EMPTY_RULESET);
77 assertNull("RuleSet file name not expected", rs.getFileName());
78 }
79
80 @Test
81 public void testRefs() throws Throwable {
82 InputStream in = ResourceLoader.loadResourceAsStream("rulesets/favorites.xml", this.getClass().getClassLoader());
83 if (in == null) {
84 throw new RuleSetNotFoundException(
85 "Can't find resource Make sure the resource is a valid file or URL or is on the CLASSPATH. Here's the current classpath: "
86 + System.getProperty("java.class.path"));
87 }
88 RuleSetFactory rsf = new RuleSetFactory();
89 RuleSet rs = rsf.createSingleRuleSet("rulesets/favorites.xml");
90 assertNotNull(rs.getRuleByName("WhileLoopsMustUseBraces"));
91 }
92
93 @Test(expected = RuleSetNotFoundException.class)
94 public void testRuleSetNotFound() throws RuleSetNotFoundException {
95 RuleSetFactory rsf = new RuleSetFactory();
96 rsf.createSingleRuleSet("fooooo");
97 }
98
99 @Test
100 public void testCreateEmptyRuleSet() {
101 RuleSet rs = loadRuleSet(EMPTY_RULESET);
102 assertEquals("test", rs.getName());
103 assertEquals(0, rs.size());
104 }
105
106 @Test
107 public void testSingleRule() {
108 RuleSet rs = loadRuleSet(SINGLE_RULE);
109 assertEquals(1, rs.size());
110 Rule r = rs.getRules().iterator().next();
111 assertEquals("MockRuleName", r.getName());
112 assertEquals("net.sourceforge.pmd.MockRule", r.getRuleClass());
113 assertEquals("avoid the mock rule", r.getMessage());
114 }
115
116 @Test
117 public void testMultipleRules() {
118 RuleSet rs = loadRuleSet(MULTIPLE_RULES);
119 assertEquals(2, rs.size());
120 Set<String> expected = new HashSet<String>();
121 expected.add("MockRuleName1");
122 expected.add("MockRuleName2");
123 for (Iterator<Rule> i = rs.getRules().iterator(); i.hasNext();) {
124 assertTrue(expected.contains(i.next().getName()));
125 }
126 }
127
128 @Test
129 public void testSingleRuleWithPriority() {
130 assertEquals(3, loadFirstRule(PRIORITY).getPriority());
131 }
132
133 @Test
134 public void testProps() {
135 Rule r = loadFirstRule(PROPERTIES);
136 assertTrue(r.hasProperty("foo"));
137 assertEquals("bar", r.getStringProperty("foo"));
138 assertEquals(2, r.getIntProperty("fooint"));
139 assertTrue(r.hasProperty("fooBoolean"));
140 assertTrue(r.getBooleanProperty("fooBoolean"));
141 assertTrue(r.hasProperty("fooDouble"));
142 assertEquals(1.0, r.getDoubleProperty("fooDouble"), 0.05);
143 assertTrue(!r.hasProperty("BuggleFish"));
144 assertTrue(r.getDescription().indexOf("testdesc2") != -1);
145 }
146
147 @Test
148 public void testXPathPluginnameProperty() {
149 Rule r = loadFirstRule(XPATH_PLUGINNAME);
150 assertTrue(r.hasProperty("pluginname"));
151 }
152
153 @Test
154 public void testXPath() {
155 Rule r = loadFirstRule(XPATH);
156 assertTrue(r.hasProperty("xpath"));
157 assertTrue(r.getStringProperty("xpath").indexOf(" //Block ") != -1);
158 }
159
160 @Test
161 public void testFacadesOffByDefault() {
162 Rule r = loadFirstRule(XPATH);
163 assertFalse(r.usesDFA());
164 }
165
166 @Test
167 public void testDFAFlag() {
168 assertTrue(loadFirstRule(DFA).usesDFA());
169 }
170
171 @Test
172 public void testExternalReferenceOverride() {
173 Rule r = loadFirstRule(REF_OVERRIDE);
174 assertEquals("TestNameOverride", r.getName());
175 assertEquals("Test message override", r.getMessage());
176 assertEquals("Test description override", r.getDescription());
177 assertEquals("Test example override", r.getExample());
178 assertEquals("Test that both example are stored", 2, r.getExamples().size());
179 assertEquals(3, r.getPriority());
180 assertTrue(r.hasProperty("test2"));
181 assertEquals("override2", r.getStringProperty("test2"));
182 assertTrue(r.hasProperty("test3"));
183 assertEquals("override3", r.getStringProperty("test3"));
184 assertTrue(r.hasProperty("test4"));
185 assertEquals("new property", r.getStringProperty("test4"));
186 }
187
188 @Test
189 public void testOverrideMessage() {
190 Rule r = loadFirstRule(REF_OVERRIDE_ORIGINAL_NAME);
191 assertEquals("TestMessageOverride", r.getMessage());
192 }
193
194 @Test
195 public void testOverrideMessageOneElem() {
196 Rule r = loadFirstRule(REF_OVERRIDE_ORIGINAL_NAME_ONE_ELEM);
197 assertEquals("TestMessageOverride", r.getMessage());
198 }
199
200 @Test(expected = IllegalArgumentException.class)
201 public void testExternalRef() throws IllegalArgumentException {
202 loadFirstRule(REF_MISPELLED_XREF);
203 }
204
205 @Test
206 public void testSetPriority() {
207 RuleSetFactory rsf = new RuleSetFactory();
208 rsf.setMinimumPriority(2);
209 assertEquals(0, rsf.createRuleSet(new ByteArrayInputStream(SINGLE_RULE.getBytes())).size());
210 rsf.setMinimumPriority(4);
211 assertEquals(1, rsf.createRuleSet(new ByteArrayInputStream(SINGLE_RULE.getBytes())).size());
212 }
213
214 @Test
215 public void testIncludeExcludePatterns() {
216 RuleSet ruleSet = loadRuleSet(INCLUDE_EXCLUDE_RULESET);
217
218 assertNotNull("Include patterns", ruleSet.getIncludePatterns());
219 assertEquals("Include patterns size", 2, ruleSet.getIncludePatterns().size());
220 assertEquals("Include pattern #1", "include1", ruleSet.getIncludePatterns().get(0));
221 assertEquals("Include pattern #2", "include2", ruleSet.getIncludePatterns().get(1));
222
223 assertNotNull("Exclude patterns", ruleSet.getExcludePatterns());
224 assertEquals("Exclude patterns size", 3, ruleSet.getExcludePatterns().size());
225 assertEquals("Exclude pattern #1", "exclude1", ruleSet.getExcludePatterns().get(0));
226 assertEquals("Exclude pattern #2", "exclude2", ruleSet.getExcludePatterns().get(1));
227 assertEquals("Exclude pattern #3", "exclude3", ruleSet.getExcludePatterns().get(2));
228 }
229
230 @Test
231 public void testAllPMDBuiltInRulesNeedSinceAndCheckURL() throws IOException, RuleSetNotFoundException,
232 ParserConfigurationException, SAXException {
233 int invalidExternalInfoURL = 0;
234 int invalidSinceAttributes = 0;
235 String messages = "";
236 List<String> ruleSetFileNames = getRuleSetFileNames();
237 for (String fileName : ruleSetFileNames) {
238 RuleSet ruleSet = loadRuleSetByFileName(fileName);
239 for (Rule rule : ruleSet.getRules()) {
240
241 if (rule.getSince() == null) {
242 invalidSinceAttributes++;
243 messages += "Rule " + fileName + "/" + rule.getName() + " is missing 'since' attribute\n";
244 }
245
246 if (rule.getExternalInfoUrl() == null || "".equalsIgnoreCase(rule.getExternalInfoUrl())) {
247 messages += "Rule " + fileName + "/" + rule.getName() + " is missing 'externalInfoURL' attribute\n";
248 }
249 else {
250 String expectedExternalInfoURL = "http://pmd.sourceforge.net/rules/" + fileName.replaceAll("rulesets/","").replaceAll(".xml","") + ".html#" + rule.getName();
251 if ( ! expectedExternalInfoURL.equals(rule.getExternalInfoUrl())) {
252 messages += "Rule " + fileName + "/" + rule.getName() + " seems to have an invalid 'externalInfoURL' value (" + rule.getExternalInfoUrl() + "), it should be:" + expectedExternalInfoURL + "\n";
253 invalidExternalInfoURL++;
254 }
255 }
256 }
257 }
258
259 if ( invalidExternalInfoURL > 0 || invalidSinceAttributes > 0 ) {
260 fail("All built-in PMD rules need 'since' attribute ("+ invalidSinceAttributes + " are missing) and a proper ExternalURLInfo (" + invalidExternalInfoURL + " are invalid)" + "\n" + messages);
261 }
262 }
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286 @Test
287 public void testXmlSchema() throws IOException, RuleSetNotFoundException, ParserConfigurationException,
288 SAXException {
289 if (isJdk14) {
290
291 return;
292 }
293
294 boolean allValid = true;
295 List<String> ruleSetFileNames = getRuleSetFileNames();
296 for (String fileName : ruleSetFileNames) {
297 boolean valid = validateAgainstSchema(fileName);
298 allValid = allValid && valid;
299 }
300 assertTrue("All XML must parse without producing validation messages.", allValid);
301 }
302
303 @Test
304 public void testDtd() throws IOException, RuleSetNotFoundException, ParserConfigurationException, SAXException {
305 boolean allValid = true;
306 List<String> ruleSetFileNames = getRuleSetFileNames();
307 for (String fileName : ruleSetFileNames) {
308 boolean valid = validateAgainstDtd(fileName);
309 allValid = allValid && valid;
310 }
311 assertTrue("All XML must parse without producing validation messages.", allValid);
312 }
313
314 @Test
315 public void testReadWriteRoundTrip() throws IOException, RuleSetNotFoundException, ParserConfigurationException,
316 SAXException {
317
318 List<String> ruleSetFileNames = getRuleSetFileNames();
319 for (String fileName : ruleSetFileNames) {
320 testRuleSet(fileName);
321 }
322 }
323
324 @Test
325 public void testWindowsJdk14Bug() throws IOException, RuleSetNotFoundException, ParserConfigurationException,
326 SAXException {
327
328 if (TestDescriptor.inRegressionTestMode()) {
329
330 return;
331 }
332
333 testRuleSet("regress/test/net/sourceforge/pmd/xml/j2ee.xml");
334 }
335
336 public void testRuleSet(String fileName) throws IOException, RuleSetNotFoundException, ParserConfigurationException,
337 SAXException {
338
339
340 String xml1 = readFullyToString(ResourceLoader.loadResourceAsStream(fileName));
341
342
343 RuleSet ruleSet1 = loadRuleSetByFileName(fileName);
344
345
346 ByteArrayOutputStream outputStream1 = new ByteArrayOutputStream();
347 RuleSetWriter writer1 = new RuleSetWriter(outputStream1);
348 writer1.write(ruleSet1);
349 writer1.close();
350 String xml2 = new String(outputStream1.toByteArray());
351
352
353 RuleSetFactory ruleSetFactory = new RuleSetFactory();
354 RuleSet ruleSet2 = ruleSetFactory.createRuleSet(new ByteArrayInputStream(outputStream1.toByteArray()));
355
356
357
358
359 ByteArrayOutputStream outputStream2 = new ByteArrayOutputStream();
360 RuleSetWriter writer2 = new RuleSetWriter(outputStream2);
361 writer2.write(ruleSet2);
362 writer2.close();
363 String xml3 = new String(outputStream2.toByteArray());
364
365
366
367
368
369
370 RuleSet ruleSet3 = ruleSetFactory.createRuleSet(new ByteArrayInputStream(outputStream2.toByteArray()));
371
372
373 if (!isJdk14) {
374 assertTrue("1st roundtrip RuleSet XML is not valid against Schema",
375 validateAgainstSchema(new ByteArrayInputStream(xml2.getBytes())));
376 assertTrue("2nd roundtrip RuleSet XML is not valid against Schema",
377 validateAgainstSchema(new ByteArrayInputStream(xml3.getBytes())));
378 }
379 assertTrue("1st roundtrip RuleSet XML is not valid against DTD",
380 validateAgainstDtd(new ByteArrayInputStream(xml2.getBytes())));
381 assertTrue("2nd roundtrip RuleSet XML is not valid against DTD",
382 validateAgainstDtd(new ByteArrayInputStream(xml3.getBytes())));
383
384
385 assertEqualsRuleSet("Original RuleSet and 1st roundtrip Ruleset not the same", ruleSet1, ruleSet2);
386 assertEqualsRuleSet("1st roundtrip Ruleset and 2nd roundtrip RuleSet not the same", ruleSet2, ruleSet3);
387
388
389 assertEquals("1st roundtrip RuleSet XML and 2nd roundtrip RuleSet XML", xml2, xml3);
390 }
391
392 private void assertEqualsRuleSet(String message, RuleSet ruleSet1, RuleSet ruleSet2) {
393 assertEquals(message + ", RuleSet name", ruleSet1.getName(), ruleSet2.getName());
394 assertEquals(message + ", RuleSet description", ruleSet1.getDescription(), ruleSet2.getDescription());
395 assertEquals(message + ", RuleSet language", ruleSet1.getLanguage(), ruleSet2.getLanguage());
396 assertEquals(message + ", RuleSet exclude patterns", ruleSet1.getExcludePatterns(), ruleSet2.getExcludePatterns());
397 assertEquals(message + ", RuleSet include patterns", ruleSet1.getIncludePatterns(), ruleSet2.getIncludePatterns());
398 assertEquals(message + ", RuleSet rule count", ruleSet1.getRules().size(), ruleSet2.getRules().size());
399
400 for (int i = 0; i < ruleSet1.getRules().size(); i++) {
401 Rule rule1 = ((List<Rule>)ruleSet1.getRules()).get(i);
402 Rule rule2 = ((List<Rule>)ruleSet2.getRules()).get(i);
403
404 assertFalse(message + ", Different RuleReference",
405 ((rule1 instanceof RuleReference) && !(rule2 instanceof RuleReference))
406 || (!(rule1 instanceof RuleReference) && (rule2 instanceof RuleReference)));
407
408 if (rule1 instanceof RuleReference) {
409 RuleReference ruleReference1 = (RuleReference)rule1;
410 RuleReference ruleReference2 = (RuleReference)rule2;
411 assertEquals(message + ", RuleReference overridden name", ruleReference1.getOverriddenName(),
412 ruleReference2.getOverriddenName());
413 assertEquals(message + ", RuleReference overridden description", ruleReference1.getOverriddenDescription(),
414 ruleReference2.getOverriddenDescription());
415 assertEquals(message + ", RuleReference overridden message", ruleReference1.getOverriddenMessage(),
416 ruleReference2.getOverriddenMessage());
417 assertEquals(message + ", RuleReference overridden external info url",
418 ruleReference1.getOverriddenExternalInfoUrl(), ruleReference2.getOverriddenExternalInfoUrl());
419 assertEquals(message + ", RuleReference overridden priority", ruleReference1.getOverriddenPriority(),
420 ruleReference2.getOverriddenPriority());
421 assertEquals(message + ", RuleReference overridden examples", ruleReference1.getOverriddenExamples(),
422 ruleReference2.getOverriddenExamples());
423 assertEquals(message + ", RuleReference overridden properties", ruleReference1.getOverriddenProperties(),
424 ruleReference2.getOverriddenProperties());
425 }
426
427 assertEquals(message + ", Rule name", rule1.getName(), rule2.getName());
428 assertEquals(message + ", Rule class", rule1.getRuleClass(), rule2.getRuleClass());
429 assertEquals(message + ", Rule description", rule1.getDescription(), rule2.getDescription());
430 assertEquals(message + ", Rule message", rule1.getMessage(), rule2.getMessage());
431 assertEquals(message + ", Rule external info url", rule1.getExternalInfoUrl(), rule2.getExternalInfoUrl());
432 assertEquals(message + ", Rule priority", rule1.getPriority(), rule2.getPriority());
433 assertEquals(message + ", Rule examples", rule1.getExamples(), rule2.getExamples());
434 assertEquals(message + ", Rule properties", rule1.getProperties(), rule2.getProperties());
435 }
436 }
437
438 private boolean validateAgainstSchema(String fileName) throws IOException, RuleSetNotFoundException,
439 ParserConfigurationException, SAXException {
440 InputStream inputStream = loadResourceAsStream(fileName);
441 boolean valid = validateAgainstSchema(inputStream);
442 if (!valid) {
443 System.err.println("Validation against XML Schema failed for: " + fileName);
444 }
445 return valid;
446 }
447
448 private boolean validateAgainstSchema(InputStream inputStream) throws IOException, RuleSetNotFoundException,
449 ParserConfigurationException, SAXException {
450 SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
451 saxParserFactory.setValidating(true);
452 saxParserFactory.setNamespaceAware(true);
453
454
455
456 saxParserFactory.setFeature("http://xml.org/sax/features/validation", true);
457 saxParserFactory.setFeature("http://apache.org/xml/features/validation/schema", true);
458 saxParserFactory.setFeature("http://apache.org/xml/features/validation/schema-full-checking", true);
459
460 SAXParser saxParser = saxParserFactory.newSAXParser();
461 ValidateDefaultHandler validateDefaultHandler = new ValidateDefaultHandler("etc/ruleset_xml_schema.xsd");
462 saxParser.parse(inputStream, validateDefaultHandler);
463 inputStream.close();
464 return validateDefaultHandler.isValid();
465 }
466
467 private boolean validateAgainstDtd(String fileName) throws IOException, RuleSetNotFoundException,
468 ParserConfigurationException, SAXException {
469 InputStream inputStream = loadResourceAsStream(fileName);
470 boolean valid = validateAgainstDtd(inputStream);
471 if (!valid) {
472 System.err.println("Validation against DTD failed for: " + fileName);
473 }
474 return valid;
475 }
476
477 private boolean validateAgainstDtd(InputStream inputStream) throws IOException, RuleSetNotFoundException,
478 ParserConfigurationException, SAXException {
479 SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
480 saxParserFactory.setValidating(true);
481 saxParserFactory.setNamespaceAware(true);
482
483
484 String file = readFullyToString(inputStream);
485
486
487 file = file.replaceAll("<\\?xml [ a-zA-Z0-9=\".-]*\\?>", "");
488 file = file.replaceAll("xmlns=\"http://pmd.sf.net/ruleset/1.0.0\"", "");
489 file = file.replaceAll("xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"", "");
490 file = file.replaceAll(
491 "xsi:schemaLocation=\"http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd\"", "");
492 file = file.replaceAll("xsi:noNamespaceSchemaLocation=\"http://pmd.sf.net/ruleset_xml_schema.xsd\"", "");
493
494 file = "<?xml version=\"1.0\"?>" + PMD.EOL + "<!DOCTYPE ruleset SYSTEM \"file://"
495 + System.getProperty("user.dir") + "/etc/ruleset.dtd\">" + PMD.EOL + file;
496
497 inputStream = new ByteArrayInputStream(file.getBytes());
498
499 SAXParser saxParser = saxParserFactory.newSAXParser();
500 ValidateDefaultHandler validateDefaultHandler = new ValidateDefaultHandler("etc/ruleset.dtd");
501 saxParser.parse(inputStream, validateDefaultHandler);
502 inputStream.close();
503 return validateDefaultHandler.isValid();
504 }
505
506 private String readFullyToString(InputStream inputStream) throws IOException {
507 StringBuffer buf = new StringBuffer(64 * 1024);
508 BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
509 String line;
510 while ((line = reader.readLine()) != null) {
511 buf.append(line);
512 buf.append(PMD.EOL);
513 }
514 reader.close();
515 return buf.toString();
516 }
517
518
519 private List<String> getRuleSetFileNames() throws IOException, RuleSetNotFoundException {
520 Properties properties = new Properties();
521 properties.load(ResourceLoader.loadResourceAsStream("rulesets/rulesets.properties"));
522 String fileNames = properties.getProperty("rulesets.testnames");
523 StringTokenizer st = new StringTokenizer(fileNames, ",");
524 List<String> ruleSetFileNames = new ArrayList<String>();
525 while (st.hasMoreTokens()) {
526 ruleSetFileNames.add(st.nextToken());
527 }
528 return ruleSetFileNames;
529 }
530
531 private class ValidateDefaultHandler extends DefaultHandler {
532 private final String validateDocument;
533 private boolean valid = true;
534
535 public ValidateDefaultHandler(String validateDocument) {
536 this.validateDocument = validateDocument;
537 }
538
539 public boolean isValid() {
540 return valid;
541 }
542
543 public void error(SAXParseException e) throws SAXException {
544 log("Error", e);
545 }
546
547 public void fatalError(SAXParseException e) throws SAXException {
548 log("FatalError", e);
549 }
550
551 public void warning(SAXParseException e) throws SAXException {
552 log("Warning", e);
553 }
554
555 private void log(String prefix, SAXParseException e) {
556 String message = prefix + " at (" + e.getLineNumber() + ", " + e.getColumnNumber() + "): " + e.getMessage();
557 System.err.println(message);
558 valid = false;
559 }
560
561 public InputSource resolveEntity(String publicId, String systemId) throws IOException, SAXException {
562 if ("http://pmd.sf.net/ruleset_xml_schema.xsd".equals(systemId) || systemId.endsWith("ruleset.dtd")) {
563 try {
564 InputStream inputStream = loadResourceAsStream(validateDocument);
565 return new InputSource(inputStream);
566 } catch (RuleSetNotFoundException e) {
567 System.err.println(e.getMessage());
568 throw new IOException(e.getMessage());
569 }
570 } else {
571 throw new IllegalArgumentException("No clue how to handle: publicId=" + publicId + ", systemId="
572 + systemId);
573 }
574 }
575 }
576
577 private InputStream loadResourceAsStream(String resource) throws RuleSetNotFoundException {
578 InputStream inputStream = ResourceLoader.loadResourceAsStream(resource, this.getClass().getClassLoader());
579 if (inputStream == null) {
580 throw new RuleSetNotFoundException(
581 "Can't find resource "
582 + resource
583 + " Make sure the resource is a valid file or URL or is on the CLASSPATH. Here's the current classpath: "
584 + System.getProperty("java.class.path"));
585 }
586 return inputStream;
587 }
588
589 private static final String REF_OVERRIDE_ORIGINAL_NAME = "<?xml version=\"1.0\"?>" + PMD.EOL
590 + "<ruleset name=\"test\">" + PMD.EOL + " <description>testdesc</description>" + PMD.EOL + " <rule "
591 + PMD.EOL + " ref=\"rulesets/unusedcode.xml/UnusedLocalVariable\" message=\"TestMessageOverride\"> "
592 + PMD.EOL + " </rule>" + PMD.EOL + "</ruleset>";
593
594 private static final String REF_MISPELLED_XREF = "<?xml version=\"1.0\"?>" + PMD.EOL + "<ruleset name=\"test\">"
595 + PMD.EOL + " <description>testdesc</description>" + PMD.EOL + " <rule " + PMD.EOL
596 + " ref=\"rulesets/unusedcode.xml/FooUnusedLocalVariable\"> " + PMD.EOL + " </rule>" + PMD.EOL
597 + "</ruleset>";
598
599 private static final String REF_OVERRIDE_ORIGINAL_NAME_ONE_ELEM = "<?xml version=\"1.0\"?>" + PMD.EOL
600 + "<ruleset name=\"test\">" + PMD.EOL + " <description>testdesc</description>" + PMD.EOL
601 + " <rule ref=\"rulesets/unusedcode.xml/UnusedLocalVariable\" message=\"TestMessageOverride\"/> " + PMD.EOL
602 + "</ruleset>";
603
604 private static final String REF_OVERRIDE = "<?xml version=\"1.0\"?>" + PMD.EOL + "<ruleset name=\"test\">"
605 + PMD.EOL + " <description>testdesc</description>" + PMD.EOL + " <rule " + PMD.EOL
606 + " ref=\"rulesets/unusedcode.xml/UnusedLocalVariable\" " + PMD.EOL + " name=\"TestNameOverride\" "
607 + PMD.EOL + " message=\"Test message override\"> " + PMD.EOL
608 + " <description>Test description override</description>" + PMD.EOL
609 + " <example>Test example override</example>" + PMD.EOL + " <priority>3</priority>" + PMD.EOL
610 + " <properties>" + PMD.EOL + " <property name=\"test2\" value=\"override2\"/>" + PMD.EOL
611 + " <property name=\"test3\"><value>override3</value></property>" + PMD.EOL
612 + " <property name=\"test4\" value=\"new property\"/>" + PMD.EOL + " </properties>" + PMD.EOL
613 + " </rule>" + PMD.EOL + "</ruleset>";
614
615 private static final String EMPTY_RULESET = "<?xml version=\"1.0\"?>" + PMD.EOL + "<ruleset name=\"test\">"
616 + PMD.EOL + "<description>testdesc</description>" + PMD.EOL + "</ruleset>";
617
618 private static final String SINGLE_RULE = "<?xml version=\"1.0\"?>" + PMD.EOL + "<ruleset name=\"test\">" + PMD.EOL
619 + "<description>testdesc</description>" + PMD.EOL + "<rule " + PMD.EOL + "name=\"MockRuleName\" " + PMD.EOL
620 + "message=\"avoid the mock rule\" " + PMD.EOL + "class=\"net.sourceforge.pmd.MockRule\">"
621 + "<priority>3</priority>" + PMD.EOL + "</rule></ruleset>";
622
623 private static final String MULTIPLE_RULES = "<?xml version=\"1.0\"?>" + PMD.EOL + "<ruleset name=\"test\">"
624 + PMD.EOL + "<description>testdesc</description>" + PMD.EOL + "<rule name=\"MockRuleName1\" " + PMD.EOL
625 + "message=\"avoid the mock rule\" " + PMD.EOL + "class=\"net.sourceforge.pmd.MockRule\">" + PMD.EOL
626 + "</rule>" + PMD.EOL + "<rule name=\"MockRuleName2\" " + PMD.EOL + "message=\"avoid the mock rule\" "
627 + PMD.EOL + "class=\"net.sourceforge.pmd.MockRule\">" + PMD.EOL + "</rule></ruleset>";
628
629 private static final String PROPERTIES = "<?xml version=\"1.0\"?>" + PMD.EOL + "<ruleset name=\"test\">" + PMD.EOL
630 + "<description>testdesc</description>" + PMD.EOL + "<rule name=\"MockRuleName\" " + PMD.EOL
631 + "message=\"avoid the mock rule\" " + PMD.EOL + "class=\"net.sourceforge.pmd.MockRule\">" + PMD.EOL
632 + "<description>testdesc2</description>" + PMD.EOL + "<properties>" + PMD.EOL
633 + "<property name=\"fooBoolean\" value=\"true\"/>" + PMD.EOL
634 + "<property name=\"fooDouble\" value=\"1.0\" />" + PMD.EOL + "<property name=\"foo\" value=\"bar\"/>"
635 + PMD.EOL + "<property name=\"fooint\" value=\"2\"/>" + PMD.EOL + "</properties>" + PMD.EOL
636 + "</rule></ruleset>";
637
638 private static final String XPATH = "<?xml version=\"1.0\"?>" + PMD.EOL + "<ruleset name=\"test\">" + PMD.EOL
639 + "<description>testdesc</description>" + PMD.EOL + "<priority>3</priority>" + PMD.EOL
640 + "<rule name=\"MockRuleName\" " + PMD.EOL + "message=\"avoid the mock rule\" " + PMD.EOL
641 + "class=\"net.sourceforge.pmd.MockRule\">" + PMD.EOL + "<description>testdesc2</description>" + PMD.EOL
642 + "<properties>" + PMD.EOL + "<property name=\"xpath\">" + PMD.EOL + "<value>" + PMD.EOL
643 + "<![CDATA[ //Block ]]>" + PMD.EOL + "</value>" + PMD.EOL + "</property>" + PMD.EOL + "</properties>"
644 + PMD.EOL + "</rule></ruleset>";
645
646 private static final String XPATH_PLUGINNAME = "<?xml version=\"1.0\"?>" + PMD.EOL + "<ruleset name=\"test\">"
647 + PMD.EOL + "<description>testdesc</description>" + PMD.EOL + "<priority>3</priority>" + PMD.EOL
648 + "<rule name=\"MockRuleName\" " + PMD.EOL + "message=\"avoid the mock rule\" " + PMD.EOL
649 + "class=\"net.sourceforge.pmd.MockRule\">" + PMD.EOL + "<description>testdesc2</description>" + PMD.EOL
650 + "<properties>" + PMD.EOL + "<property name=\"xpath\" pluginname=\"true\">" + PMD.EOL + "<value>"
651 + PMD.EOL + "<![CDATA[ //Block ]]>" + PMD.EOL + "</value>" + PMD.EOL + "</property>" + PMD.EOL
652 + "</properties>" + PMD.EOL + "</rule></ruleset>";
653
654 private static final String PRIORITY = "<?xml version=\"1.0\"?>" + PMD.EOL + "<ruleset name=\"test\">" + PMD.EOL
655 + "<description>testdesc</description>" + PMD.EOL + "<rule " + PMD.EOL + "name=\"MockRuleName\" " + PMD.EOL
656 + "message=\"avoid the mock rule\" " + PMD.EOL + "class=\"net.sourceforge.pmd.MockRule\">"
657 + "<priority>3</priority>" + PMD.EOL + "</rule></ruleset>";
658
659 private static final String DFA = "<?xml version=\"1.0\"?>" + PMD.EOL + "<ruleset name=\"test\">" + PMD.EOL
660 + "<description>testdesc</description>" + PMD.EOL + "<rule " + PMD.EOL + "name=\"MockRuleName\" " + PMD.EOL
661 + "message=\"avoid the mock rule\" " + PMD.EOL + "dfa=\"true\" " + PMD.EOL
662 + "class=\"net.sourceforge.pmd.MockRule\">" + "<priority>3</priority>" + PMD.EOL + "</rule></ruleset>";
663
664 private static final String INCLUDE_EXCLUDE_RULESET = "<?xml version=\"1.0\"?>" + PMD.EOL
665 + "<ruleset name=\"test\">" + PMD.EOL + "<description>testdesc</description>" + PMD.EOL
666 + "<include-pattern>include1</include-pattern>" + PMD.EOL + "<include-pattern>include2</include-pattern>"
667 + PMD.EOL + "<exclude-pattern>exclude1</exclude-pattern>" + PMD.EOL
668 + "<exclude-pattern>exclude2</exclude-pattern>" + PMD.EOL + "<exclude-pattern>exclude3</exclude-pattern>"
669 + PMD.EOL + "</ruleset>";
670
671 private Rule loadFirstRule(String ruleSetXml) {
672 RuleSet rs = loadRuleSet(ruleSetXml);
673 return rs.getRules().iterator().next();
674 }
675
676 private RuleSet loadRuleSetByFileName(String ruleSetFileName) throws RuleSetNotFoundException {
677 RuleSetFactory rsf = new RuleSetFactory();
678 return rsf.createSingleRuleSet(ruleSetFileName);
679 }
680
681 private RuleSet loadRuleSet(String ruleSetXml) {
682 RuleSetFactory rsf = new RuleSetFactory();
683 return rsf.createRuleSet(new ByteArrayInputStream(ruleSetXml.getBytes()));
684 }
685
686 @Test
687 public void testExternalReferences() {
688 RuleSet rs = loadRuleSet(EXTERNAL_REFERENCE_RULE_SET);
689 assertEquals(1, rs.size());
690 assertEquals(UnusedLocalVariableRule.class.getName(), rs.getRuleByName("UnusedLocalVariable").getRuleClass());
691 }
692
693 private static final String EXTERNAL_REFERENCE_RULE_SET = "<?xml version=\"1.0\"?>" + PMD.EOL
694 + "<ruleset name=\"test\">" + PMD.EOL + "<description>testdesc</description>" + PMD.EOL
695 + "<rule ref=\"rulesets/unusedcode.xml/UnusedLocalVariable\"/>" + PMD.EOL + "</ruleset>";
696
697 public static junit.framework.Test suite() {
698 return new JUnit4TestAdapter(RuleSetFactoryTest.class);
699 }
700 }