View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.plugins.pmd;
20  
21  import java.io.BufferedReader;
22  import java.io.File;
23  import java.io.FileReader;
24  import java.io.IOException;
25  import java.net.ServerSocket;
26  import java.net.URL;
27  import java.nio.charset.StandardCharsets;
28  import java.util.Locale;
29  
30  import com.github.tomakehurst.wiremock.WireMockServer;
31  import com.github.tomakehurst.wiremock.client.WireMock;
32  import net.sourceforge.pmd.renderers.Renderer;
33  import org.apache.commons.io.IOUtils;
34  import org.apache.commons.lang3.StringUtils;
35  import org.apache.maven.plugins.pmd.exec.PmdExecutor;
36  import org.apache.maven.reporting.MavenReportException;
37  import org.codehaus.plexus.util.FileUtils;
38  
39  /**
40   * @author <a href="mailto:oching@apache.org">Maria Odea Ching</a>
41   * @version $Id$
42   */
43  public class PmdReportTest extends AbstractPmdReportTestCase {
44  
45      /**
46       * {@inheritDoc}
47       */
48      @Override
49      protected void setUp() throws Exception {
50          super.setUp();
51          Locale.setDefault(Locale.ENGLISH);
52          FileUtils.deleteDirectory(new File(getBasedir(), "target/test/unit"));
53      }
54  
55      public void testDefaultConfiguration() throws Exception {
56          FileUtils.copyDirectoryStructure(
57                  new File(getBasedir(), "src/test/resources/unit/default-configuration/jxr-files"),
58                  new File(getBasedir(), "target/test/unit/default-configuration/target/site"));
59  
60          File generatedReport = generateReport("pmd", "default-configuration/default-configuration-plugin-config.xml");
61          assertTrue(FileUtils.fileExists(generatedReport.getAbsolutePath()));
62  
63          // check if the PMD files were generated
64          File generatedFile = new File(getBasedir(), "target/test/unit/default-configuration/target/pmd.xml");
65          assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
66  
67          // check if the rulesets, that have been applied, have been copied
68          generatedFile = new File(
69                  getBasedir(),
70                  "target/test/unit/default-configuration/target/pmd/rulesets/maven-pmd-plugin-default.xml");
71          assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
72  
73          // check if there's a link to the JXR files
74          String str = readFile(generatedReport);
75  
76          assertTrue(str.contains("/xref/def/configuration/App.html#L31"));
77  
78          assertTrue(str.contains("/xref/def/configuration/AppSample.html#L45"));
79  
80          // check if there's a priority column
81          assertTrue(str.contains("<th>Priority</th>"));
82  
83          // there should be a rule column
84          assertTrue(str.contains("<th>Rule</th>"));
85          // along with a link to the rule
86          assertTrue(str.contains("pmd_rules_java_bestpractices.html#unusedprivatefield\">UnusedPrivateField</a>"));
87  
88          // there should be the section Violations By Priority
89          assertTrue(str.contains("Violations By Priority</h3>"));
90          assertTrue(str.contains("Priority 3</h4>"));
91          assertTrue(str.contains("Priority 4</h4>"));
92          // the file App.java is mentioned 3 times: in prio 3, in prio 4 and in the files section
93          assertEquals(3, StringUtils.countMatches(str, "def/configuration/App.java"));
94  
95          // there must be no warnings (like deprecated rules) in the log output
96          String output = CapturingPrintStream.getOutput();
97          assertFalse(output.contains("deprecated Rule name"));
98          assertFalse(output.contains("Discontinue using Rule name"));
99          assertFalse(output.contains("is referenced multiple times"));
100 
101         // the version should be logged
102         assertTrue(output.contains("PMD version: " + AbstractPmdReport.getPmdVersion()));
103     }
104 
105     public void testDefaultConfigurationNotRenderRuleViolationPriority() throws Exception {
106         FileUtils.copyDirectoryStructure(
107                 new File(getBasedir(), "src/test/resources/unit/default-configuration/jxr-files"),
108                 new File(getBasedir(), "target/test/unit/default-configuration/target/site"));
109 
110         File generatedReport =
111                 generateReport("pmd", "default-configuration/pmd-report-not-render-rule-priority-plugin-config.xml");
112         assertTrue(FileUtils.fileExists(generatedReport.getAbsolutePath()));
113 
114         String str = readFile(generatedReport);
115 
116         // check that there's no priority column
117         assertFalse(str.contains("<th>Priority</th>"));
118     }
119 
120     public void testDefaultConfigurationNoRenderViolationsByPriority() throws Exception {
121         FileUtils.copyDirectoryStructure(
122                 new File(getBasedir(), "src/test/resources/unit/default-configuration/jxr-files"),
123                 new File(getBasedir(), "target/test/unit/default-configuration/target/site"));
124 
125         File generatedReport =
126                 generateReport("pmd", "default-configuration/pmd-report-no-render-violations-by-priority.xml");
127         assertTrue(FileUtils.fileExists(generatedReport.getAbsolutePath()));
128 
129         String str = readFile(generatedReport);
130 
131         // there should be no section Violations By Priority
132         assertFalse(str.contains("Violations By Priority</h2>"));
133         assertFalse(str.contains("Priority 3</h3>"));
134         assertFalse(str.contains("Priority 4</h3>"));
135         // the file App.java is mentioned once: in the files section
136         assertEquals(1, StringUtils.countMatches(str, "def/configuration/App.java"));
137     }
138 
139     public void testDefaultConfigurationWithAnalysisCache() throws Exception {
140         FileUtils.copyDirectoryStructure(
141                 new File(getBasedir(), "src/test/resources/unit/default-configuration/jxr-files"),
142                 new File(getBasedir(), "target/test/unit/pmd-with-analysis-cache-plugin-config/target/site"));
143 
144         generateReport("pmd", "default-configuration/pmd-with-analysis-cache-plugin-config.xml");
145 
146         // check if the PMD analysis cache file has been generated
147         File cacheFile =
148                 new File(getBasedir(), "target/test/unit/pmd-with-analysis-cache-plugin-config/target/pmd/pmd.cache");
149         assertTrue(FileUtils.fileExists(cacheFile.getAbsolutePath()));
150     }
151 
152     public void testJavascriptConfiguration() throws Exception {
153         File generatedReport =
154                 generateReport("pmd", "default-configuration/javascript-configuration-plugin-config.xml");
155         assertTrue(FileUtils.fileExists(generatedReport.getAbsolutePath()));
156 
157         // check if the PMD files were generated
158         File generatedFile = new File(getBasedir(), "target/test/unit/default-configuration/target/pmd.xml");
159         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
160 
161         // these are the rulesets, that have been applied...
162         generatedFile =
163                 new File(getBasedir(), "target/test/unit/default-configuration/target/pmd/rulesets/bestpractices.xml");
164         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
165 
166         generatedFile =
167                 new File(getBasedir(), "target/test/unit/default-configuration/target/pmd/rulesets/codestyle.xml");
168         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
169 
170         generatedFile =
171                 new File(getBasedir(), "target/test/unit/default-configuration/target/pmd/rulesets/errorprone.xml");
172         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
173 
174         String str = readFile(generatedReport);
175         assertTrue(str.contains("Avoid using global variables"));
176     }
177 
178     public void testFileURL() throws Exception {
179         FileUtils.copyDirectoryStructure(
180                 new File(getBasedir(), "src/test/resources/unit/default-configuration/jxr-files"),
181                 new File(getBasedir(), "target/test/unit/default-configuration/target/site"));
182 
183         File testPom = new File(
184                 getBasedir(), "src/test/resources/unit/default-configuration/default-configuration-plugin-config.xml");
185         PmdReport mojo = (PmdReport) createReportMojo("pmd", testPom);
186 
187         // Additional test case for MPMD-174 (https://issues.apache.org/jira/browse/MPMD-174).
188         int port = determineFreePort();
189         WireMockServer mockServer = new WireMockServer(port);
190         mockServer.start();
191 
192         String sonarRuleset = IOUtils.toString(
193                 getClass()
194                         .getClassLoader()
195                         .getResourceAsStream("unit/default-configuration/rulesets/sonar-way-ruleset.xml"),
196                 StandardCharsets.UTF_8);
197 
198         String sonarMainPageHtml = IOUtils.toString(
199                 getClass()
200                         .getClassLoader()
201                         .getResourceAsStream("unit/default-configuration/rulesets/sonar-main-page.html"),
202                 StandardCharsets.UTF_8);
203 
204         final String sonarBaseUrl = "/profiles";
205         final String sonarProfileUrl = sonarBaseUrl + "/export?format=pmd&language=java&name=Sonar%2520way";
206         final String sonarExportRulesetUrl = "http://localhost:" + mockServer.port() + sonarProfileUrl;
207 
208         WireMock.configureFor("localhost", port);
209         WireMock.stubFor(WireMock.get(WireMock.urlEqualTo(sonarBaseUrl))
210                 .willReturn(WireMock.aResponse()
211                         .withStatus(200)
212                         .withHeader("Content-Type", "text/html")
213                         .withBody(sonarMainPageHtml)));
214 
215         WireMock.stubFor(WireMock.get(WireMock.urlEqualTo(sonarProfileUrl))
216                 .willReturn(WireMock.aResponse()
217                         .withStatus(200)
218                         .withHeader("Content-Type", "text/xml")
219                         .withBody(sonarRuleset)));
220 
221         URL url = getClass().getClassLoader().getResource("rulesets/java/basic.xml");
222         URL url2 = getClass().getClassLoader().getResource("rulesets/java/unusedcode.xml");
223         URL url3 = getClass().getClassLoader().getResource("rulesets/java/imports.xml");
224         mojo.setRulesets(new String[] {url.toString(), url2.toString(), url3.toString(), sonarExportRulesetUrl});
225 
226         File generatedReport = generateReport(mojo, testPom);
227         assertTrue(FileUtils.fileExists(generatedReport.getAbsolutePath()));
228 
229         // check if the PMD files were generated
230         File generatedFile = new File(getBasedir(), "target/test/unit/default-configuration/target/pmd.xml");
231         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
232 
233         // the resolved and extracted rulesets
234         generatedFile = new File(getBasedir(), "target/test/unit/default-configuration/target/pmd/rulesets/basic.xml");
235         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
236 
237         generatedFile =
238                 new File(getBasedir(), "target/test/unit/default-configuration/target/pmd/rulesets/imports.xml");
239         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
240 
241         generatedFile =
242                 new File(getBasedir(), "target/test/unit/default-configuration/target/pmd/rulesets/unusedcode.xml");
243         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
244 
245         generatedFile = new File(
246                 getBasedir(),
247                 "target/test/unit/default-configuration/target/pmd/rulesets/export_format_pmd_language_java_name_Sonar_2520way.xml");
248         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
249 
250         // check if there's a link to the JXR files
251         String str = readFile(generatedReport);
252 
253         assertTrue(str.contains("/xref/def/configuration/App.html#L31"));
254 
255         assertTrue(str.contains("/xref/def/configuration/AppSample.html#L45"));
256 
257         mockServer.stop();
258     }
259 
260     private int determineFreePort() {
261         try (ServerSocket socket = new ServerSocket(0)) {
262             return socket.getLocalPort();
263         } catch (IOException e) {
264             throw new RuntimeException("Couldn't find a free port.", e);
265         }
266     }
267 
268     /**
269      * With custom rulesets
270      *
271      * @throws Exception
272      */
273     public void testCustomConfiguration() throws Exception {
274         File generatedReport = generateReport("pmd", "custom-configuration/custom-configuration-plugin-config.xml");
275         assertTrue(FileUtils.fileExists(generatedReport.getAbsolutePath()));
276 
277         // check the generated files
278         File generatedFile = new File(getBasedir(), "target/test/unit/custom-configuration/target/pmd.csv");
279         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
280 
281         generatedFile = new File(getBasedir(), "target/test/unit/custom-configuration/target/pmd/rulesets/custom.xml");
282         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
283 
284         // check if custom ruleset was applied
285         String str = readFile(generatedReport);
286 
287         // codestyle.xml/ControlStatementBraces:
288         assertTrue(lowerCaseContains(str, "This statement should have braces"));
289 
290         // Must be false as codestyle.xml/ControlStatementBraces with checkIfElseStmt=false is used
291         assertFalse(lowerCaseContains(str, "Avoid using if...else statements without curly braces"));
292 
293         assertFalse(
294                 "unnecessary constructor should not be triggered because of low priority",
295                 lowerCaseContains(str, "Avoid unnecessary constructors - the compiler will generate these for you"));
296 
297         // veryLongVariableNameWithViolation is really too long
298         assertTrue(lowerCaseContains(str, "veryLongVariableNameWithViolation"));
299         // notSoLongVariableName should not be reported
300         assertFalse(lowerCaseContains(str, "notSoLongVariableName"));
301     }
302 
303     /**
304      * Verify skip parameter
305      *
306      * @throws Exception
307      */
308     public void testSkipConfiguration() throws Exception {
309         File generatedReport = generateReport("pmd", "custom-configuration/skip-plugin-config.xml");
310         assertFalse(FileUtils.fileExists(generatedReport.getAbsolutePath()));
311 
312         // verify the generated files do not exist because PMD was skipped
313         File generatedFile = new File(getBasedir(), "target/test/unit/skip-configuration/target/pmd.csv");
314         assertFalse(FileUtils.fileExists(generatedFile.getAbsolutePath()));
315 
316         generatedFile = new File(getBasedir(), "target/test/unit/custom-configuration/target/custom.xml");
317         assertFalse(FileUtils.fileExists(generatedFile.getAbsolutePath()));
318 
319         // the fact, the PMD execution has been skipped, should be logged
320         String output = CapturingPrintStream.getOutput();
321         assertTrue(output.contains("Skipping PMD execution"));
322     }
323 
324     public void testSkipEmptyReportConfiguration() throws Exception {
325         // verify the generated files do not exist because PMD was skipped
326         File generatedReport = generateReport("pmd", "empty-report/skip-empty-report-plugin-config.xml");
327         assertFalse(FileUtils.fileExists(generatedReport.getAbsolutePath()));
328     }
329 
330     public void testEmptyReportConfiguration() throws Exception {
331         File generatedReport = generateReport("pmd", "empty-report/empty-report-plugin-config.xml");
332         assertTrue(FileUtils.fileExists(generatedReport.getAbsolutePath()));
333 
334         // verify the generated files do exist, even if there are no violations
335         String str = readFile(generatedReport);
336         assertFalse(lowerCaseContains(str, "Hello.java"));
337         assertEquals(1, StringUtils.countMatches(str, "PMD found no problems in your source code."));
338         // no sections files or violations by priority
339         assertFalse(str.contains("Files</h2>"));
340         assertFalse(str.contains("Violations By Priority</h2>"));
341     }
342 
343     public void testInvalidFormat() throws Exception {
344         try {
345             File testPom =
346                     new File(getBasedir(), "src/test/resources/unit/invalid-format/invalid-format-plugin-config.xml");
347             AbstractPmdReport mojo = createReportMojo("pmd", testPom);
348             setVariableValueToObject(
349                     mojo, "compileSourceRoots", mojo.getProject().getCompileSourceRoots());
350             generateReport(mojo, testPom);
351 
352             fail("Must throw MavenReportException.");
353         } catch (Exception e) {
354             assertTrue(true);
355         }
356     }
357 
358     public void testInvalidTargetJdk() throws Exception {
359         try {
360             generateReport("pmd", "empty-report/invalid-format/invalid-target-jdk-plugin-config.xml");
361 
362             fail("Must throw MavenReportException.");
363         } catch (Exception e) {
364             assertTrue(true);
365         }
366     }
367 
368     /**
369      * verify the pmd.xml file is included in the site when requested.
370      * @throws Exception
371      */
372     public void testIncludeXmlInSite() throws Exception {
373         File generatedReport =
374                 generateReport("pmd", "default-configuration/pmd-report-include-xml-in-site-plugin-config.xml");
375         assertTrue(FileUtils.fileExists(generatedReport.getAbsolutePath()));
376 
377         // verify the pmd file is included in site
378         File generatedXmlFile = new File(getBasedir(), "target/test/unit/default-configuration/target/site/pmd.xml");
379         assertTrue(FileUtils.fileExists(generatedXmlFile.getAbsolutePath()));
380 
381         String pmdXmlTarget = readFile(new File(getBasedir(), "target/test/unit/default-configuration/target/pmd.xml"));
382         assertTrue(pmdXmlTarget.contains("</pmd>"));
383 
384         // check that pmd.xml file has the closing element
385         String pmdXml = readFile(generatedXmlFile);
386         assertTrue(pmdXml.contains("</pmd>"));
387     }
388 
389     /**
390      * Read the contents of the specified file object into a string
391      *
392      * @param file the file to be read
393      * @return a String object that contains the contents of the file
394      * @throws java.io.IOException
395      */
396     private String readFile(File file) throws IOException {
397         try (BufferedReader reader = new BufferedReader(new FileReader(file))) {
398             final StringBuilder str = new StringBuilder((int) file.length());
399 
400             for (String line = reader.readLine(); line != null; line = reader.readLine()) {
401                 str.append(' ');
402                 str.append(line);
403                 str.append('\n');
404             }
405             return str.toString();
406         }
407     }
408 
409     /**
410      * Verify the correct working of the locationTemp method
411      *
412      * @throws Exception
413      */
414     public void testLocationTemp() throws Exception {
415 
416         File testPom = new File(
417                 getBasedir(), "src/test/resources/unit/default-configuration/default-configuration-plugin-config.xml");
418         PmdReport mojo = (PmdReport) lookupMojo("pmd", testPom);
419 
420         assertEquals(
421                 "locationTemp is not correctly encoding filename",
422                 "export_format_pmd_language_java_name_some_2520name.xml",
423                 mojo.getLocationTemp(
424                         "http://nemo.sonarsource.org/sonar/profiles/export?format=pmd&language=java&name=some%2520name"));
425     }
426 
427     /**
428      * Verify that suppressMarker works
429      *
430      * @throws Exception
431      */
432     public void testSuppressMarkerConfiguration() throws Exception {
433         File generatedReport = generateReport("pmd", "default-configuration/pmd-with-suppressMarker-plugin-config.xml");
434         assertTrue(FileUtils.fileExists(generatedReport.getAbsolutePath()));
435 
436         // check if the PMD files were generated
437         File generatedFile = new File(getBasedir(), "target/test/unit/default-configuration/target/pmd.xml");
438         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
439 
440         String str = readFile(generatedFile);
441 
442         // check that there is no violation reported for "unusedVar2" - as it is suppressed
443         assertFalse(str.contains("Avoid unused private fields such as 'unusedVar2'.\n </violation>"));
444         // but it appears as suppressed
445         assertTrue(str.contains("suppressiontype=\"nopmd\" msg=\"Avoid unused private fields such as 'unusedVar2'.\""));
446 
447         // check if there's a link to the JXR files
448         str = readFile(generatedReport);
449 
450         assertTrue(str.contains("/xref/def/configuration/AppSample.html#L27"));
451         // suppressed violation
452         assertTrue(str.contains("Avoid unused private fields such as 'unusedVar2'."));
453     }
454 
455     public void testSuppressMarkerConfigurationWithoutRendering() throws Exception {
456         File generatedReport =
457                 generateReport("pmd", "default-configuration/pmd-with-suppressMarker-no-render-plugin-config.xml");
458         assertTrue(FileUtils.fileExists(generatedReport.getAbsolutePath()));
459 
460         // check if the PMD files were generated
461         File generatedFile = new File(getBasedir(), "target/test/unit/default-configuration/target/pmd.xml");
462         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
463 
464         String str = readFile(generatedFile);
465 
466         // check that there is no violation reported for "unusedVar2" - as it is suppressed
467         assertFalse(str.contains("Avoid unused private fields such as 'unusedVar2'.\n </violation>"));
468         // but it appears as suppressed
469         assertTrue(str.contains("suppressiontype=\"nopmd\" msg=\"Avoid unused private fields such as 'unusedVar2'.\""));
470 
471         // check if there's a link to the JXR files
472         str = readFile(generatedReport);
473 
474         assertTrue(str.contains("/xref/def/configuration/AppSample.html#L27"));
475         // suppressed violations are not rendered
476         assertFalse(str.contains("Avoid unused private fields such as 'unusedVar2'."));
477     }
478 
479     public void testJspConfiguration() throws Exception {
480         File generatedReport = generateReport("pmd", "default-configuration/jsp-configuration-plugin-config.xml");
481         assertTrue(FileUtils.fileExists(generatedReport.getAbsolutePath()));
482 
483         // check if the PMD files were generated
484         File generatedFile = new File(getBasedir(), "target/test/unit/default-configuration/target/pmd.xml");
485         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
486 
487         // these are the rulesets, that have been applied...
488         generatedFile =
489                 new File(getBasedir(), "target/test/unit/default-configuration/target/pmd/rulesets/bestpractices.xml");
490         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
491 
492         generatedFile =
493                 new File(getBasedir(), "target/test/unit/default-configuration/target/pmd/rulesets/codestyle.xml");
494         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
495 
496         generatedFile = new File(getBasedir(), "target/test/unit/default-configuration/target/pmd/rulesets/design.xml");
497         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
498 
499         generatedFile =
500                 new File(getBasedir(), "target/test/unit/default-configuration/target/pmd/rulesets/errorprone.xml");
501         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
502 
503         generatedFile =
504                 new File(getBasedir(), "target/test/unit/default-configuration/target/pmd/rulesets/security.xml");
505         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
506 
507         String str = readFile(generatedReport);
508         assertTrue(str.contains("JSP file should use UTF-8 encoding"));
509         assertTrue(str.contains("Using unsanitized JSP expression can lead to Cross Site Scripting (XSS) attacks"));
510         assertTrue(str.contains("Avoid having style information in JSP files."));
511     }
512 
513     public void testPMDProcessingError() throws Exception {
514         try {
515             generateReport("pmd", "processing-error/pmd-processing-error-plugin-config.xml");
516             fail("Expected exception");
517         } catch (RuntimeException e) {
518             assertTrue(e.getMessage().endsWith("Found 1 PMD processing errors"));
519         }
520     }
521 
522     public void testPMDProcessingErrorWithDetailsSkipped() throws Exception {
523         File generatedReport = generateReport("pmd", "processing-error/pmd-processing-error-skip-plugin-config.xml");
524         assertTrue(FileUtils.fileExists(generatedReport.getAbsolutePath()));
525 
526         String output = CapturingPrintStream.getOutput();
527         assertTrue(output.contains("There are 1 PMD processing errors:"));
528 
529         File generatedFile = new File(getBasedir(), "target/test/unit/parse-error/target/pmd.xml");
530         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
531         String str = readFile(generatedFile);
532         assertTrue(str.contains("Error while parsing"));
533         // The parse exception must be in the XML report
534         assertTrue(str.contains("ParseException: Encountered \"\" at line 23, column 5."));
535 
536         str = readFile(generatedReport);
537         // The parse exception must also be in the HTML report
538         assertTrue(str.contains("ParseException: Encountered \"\" at line 23, column 5."));
539     }
540 
541     public void testPMDProcessingErrorWithDetailsNoReport() throws Exception {
542         File generatedReport =
543                 generateReport("pmd", "processing-error/pmd-processing-error-no-report-plugin-config.xml");
544         assertTrue(FileUtils.fileExists(generatedReport.getAbsolutePath()));
545 
546         String output = CapturingPrintStream.getOutput();
547         assertTrue(output.contains("There are 1 PMD processing errors:"));
548 
549         File generatedFile = new File(getBasedir(), "target/test/unit/parse-error/target/pmd.xml");
550         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
551         String str = readFile(generatedFile);
552         assertTrue(str.contains("Error while parsing"));
553         // The parse exception must be in the XML report
554         assertTrue(str.contains("ParseException: Encountered \"\" at line 23, column 5."));
555 
556         str = readFile(generatedReport);
557         // The parse exception must NOT be in the HTML report, since reportProcessingErrors is false
558         assertFalse(str.contains("ParseException: Encountered \"\" at line 23, column 5."));
559     }
560 
561     public void testPMDExcludeRootsShouldExcludeSubdirectories() throws Exception {
562         generateReport("pmd", "exclude-roots/pmd-exclude-roots-plugin-config.xml");
563 
564         File generatedFile = new File(getBasedir(), "target/test/unit/exclude-roots/target/pmd.xml");
565         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
566         String str = readFile(generatedFile);
567 
568         assertTrue("Seems like all directories are excluded now", str.contains("ForLoopShouldBeWhileLoop"));
569         assertFalse(
570                 "Exclusion of an exact source directory not working", str.contains("OverrideBothEqualsAndHashcode"));
571         assertFalse(
572                 "Exclusion of basedirectory with subdirectories not working (MPMD-178)",
573                 str.contains("JumbledIncrementer"));
574     }
575 
576     public void testViolationExclusion() throws Exception {
577         generateReport("pmd", "default-configuration/pmd-report-pmd-exclusions-configuration-plugin-config.xml");
578 
579         File generatedFile = new File(getBasedir(), "target/test/unit/default-configuration/target/pmd.xml");
580         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
581         String str = readFile(generatedFile);
582 
583         assertEquals(0, StringUtils.countMatches(str, "<violation"));
584     }
585 
586     public void testCustomRenderer() throws MavenReportException {
587         final Renderer renderer = PmdExecutor.createRenderer("net.sourceforge.pmd.renderers.TextRenderer", "UTF-8");
588         assertNotNull(renderer);
589     }
590 
591     public void testCodeClimateRenderer() throws MavenReportException {
592         final Renderer renderer =
593                 PmdExecutor.createRenderer("net.sourceforge.pmd.renderers.CodeClimateRenderer", "UTF-8");
594         assertNotNull(renderer);
595     }
596 
597     public void testPmdReportCustomRulesNoExternalInfoUrl() throws Exception {
598         FileUtils.copyDirectoryStructure(
599                 new File(getBasedir(), "src/test/resources/unit/default-configuration/jxr-files"),
600                 new File(getBasedir(), "target/test/unit/default-configuration/target/site"));
601 
602         File generatedReport = generateReport("pmd", "default-configuration/pmd-report-custom-rules.xml");
603         assertTrue(FileUtils.fileExists(generatedReport.getAbsolutePath()));
604 
605         String str = readFile(generatedReport);
606 
607         // custom rule without link
608         assertEquals(2, StringUtils.countMatches(str, "<td align=\"left\">CustomRule</td>"));
609         // standard rule with link
610         assertEquals(4, StringUtils.countMatches(str, "\">UnusedPrivateField</a></td>"));
611     }
612 
613     public void testPmdReportResolveRulesets() throws Exception {
614         int port = determineFreePort();
615         WireMockServer mockServer = new WireMockServer(port);
616         mockServer.start();
617 
618         String sonarRuleset = IOUtils.toString(
619                 getClass()
620                         .getClassLoader()
621                         .getResourceAsStream("unit/default-configuration/rulesets/sonar-way-ruleset.xml"),
622                 StandardCharsets.UTF_8);
623 
624         final String sonarProfileUrl = "/profiles/export?format=pmd&language=java&name=Sonar%2520way";
625         final String sonarExportRulesetUrl = "http://localhost:" + mockServer.port() + sonarProfileUrl;
626         final String myRulesetBaseUrl = "/config/my-ruleset.xml";
627         final String myRulesetUrl = "http://localhost:" + mockServer.port() + myRulesetBaseUrl;
628         final String notAInternalRulesetBaseUrl =
629                 "/projects/OURPROJECT/repos/ourproject-pmd/raw/InProgressRuleset.xml?at=refs%2Fheads%2Fmaster";
630         final String notAInternalRulesetUrl = "http://localhost:" + mockServer.port() + notAInternalRulesetBaseUrl;
631 
632         WireMock.configureFor("localhost", port);
633         WireMock.stubFor(WireMock.get(WireMock.urlEqualTo(sonarProfileUrl))
634                 .willReturn(WireMock.aResponse()
635                         .withStatus(200)
636                         .withHeader("Content-Type", "text/xml")
637                         .withBody(sonarRuleset)));
638         WireMock.stubFor(WireMock.get(WireMock.urlEqualTo(myRulesetBaseUrl))
639                 .willReturn(WireMock.aResponse()
640                         .withStatus(200)
641                         .withHeader("Content-Type", "text/xml")
642                         .withBody(sonarRuleset)));
643         WireMock.stubFor(WireMock.get(WireMock.urlEqualTo(notAInternalRulesetBaseUrl))
644                 .willReturn(WireMock.aResponse()
645                         .withStatus(200)
646                         .withHeader("Content-Type", "text/xml")
647                         .withBody(sonarRuleset)));
648 
649         FileUtils.copyDirectoryStructure(
650                 new File(getBasedir(), "src/test/resources/unit/default-configuration/jxr-files"),
651                 new File(getBasedir(), "target/test/unit/default-configuration/target/site"));
652 
653         File testPom =
654                 new File(getBasedir(), "src/test/resources/unit/default-configuration/pmd-report-resolve-rulesets.xml");
655         PmdReport mojo = (PmdReport) createReportMojo("pmd", testPom);
656         mojo.rulesets[3] = sonarExportRulesetUrl;
657         mojo.rulesets[4] = myRulesetUrl;
658         mojo.rulesets[5] = notAInternalRulesetUrl;
659         generateReport(mojo, testPom);
660 
661         // these are the rulesets, that have been copied to target/pmd/rulesets
662         File generatedFile =
663                 new File(getBasedir(), "target/test/unit/default-configuration/target/pmd/rulesets/custom-rules.xml");
664         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
665 
666         generatedFile =
667                 new File(getBasedir(), "target/test/unit/default-configuration/target/pmd/rulesets/bestpractices.xml");
668         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
669 
670         generatedFile =
671                 new File(getBasedir(), "target/test/unit/default-configuration/target/pmd/rulesets/java-design.xml");
672         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
673 
674         generatedFile = new File(
675                 getBasedir(),
676                 "target/test/unit/default-configuration/target/pmd/rulesets/export_format_pmd_language_java_name_Sonar_2520way.xml");
677         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
678 
679         generatedFile =
680                 new File(getBasedir(), "target/test/unit/default-configuration/target/pmd/rulesets/my-ruleset.xml");
681         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
682 
683         generatedFile = new File(
684                 getBasedir(),
685                 "target/test/unit/default-configuration/target/pmd/rulesets/InProgressRuleset.xml_at_refs_2Fheads_2Fmaster.xml");
686         assertTrue(FileUtils.fileExists(generatedFile.getAbsolutePath()));
687 
688         mockServer.stop();
689     }
690 }