1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package com.puppycrawl.tools.checkstyle.ant;
21
22 import static com.google.common.truth.Truth.assertWithMessage;
23 import static com.puppycrawl.tools.checkstyle.internal.utils.TestUtil.getExpectedThrowable;
24 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
25
26 import java.io.File;
27 import java.io.IOException;
28 import java.net.URL;
29 import java.nio.charset.StandardCharsets;
30 import java.nio.file.Files;
31 import java.util.Arrays;
32 import java.util.List;
33 import java.util.Locale;
34 import java.util.Map;
35 import java.util.Optional;
36 import java.util.ResourceBundle;
37 import java.util.regex.Matcher;
38 import java.util.regex.Pattern;
39
40 import org.apache.tools.ant.BuildException;
41 import org.apache.tools.ant.Location;
42 import org.apache.tools.ant.Project;
43 import org.apache.tools.ant.types.FileSet;
44 import org.apache.tools.ant.types.Path;
45 import org.apache.tools.ant.types.resources.FileResource;
46 import org.junit.jupiter.api.Test;
47 import org.junit.jupiter.api.io.TempDir;
48
49 import com.google.common.base.Splitter;
50 import com.google.common.collect.Iterables;
51 import com.google.common.truth.StandardSubjectBuilder;
52 import com.puppycrawl.tools.checkstyle.AbstractPathTestSupport;
53 import com.puppycrawl.tools.checkstyle.DefaultLogger;
54 import com.puppycrawl.tools.checkstyle.Definitions;
55 import com.puppycrawl.tools.checkstyle.SarifLogger;
56 import com.puppycrawl.tools.checkstyle.XMLLogger;
57 import com.puppycrawl.tools.checkstyle.internal.testmodules.CheckstyleAntTaskLogStub;
58 import com.puppycrawl.tools.checkstyle.internal.testmodules.CheckstyleAntTaskStub;
59 import com.puppycrawl.tools.checkstyle.internal.testmodules.MessageLevelPair;
60 import com.puppycrawl.tools.checkstyle.internal.testmodules.TestRootModuleChecker;
61
62 public class CheckstyleAntTaskTest extends AbstractPathTestSupport {
63
64 private static final String FLAWLESS_INPUT =
65 "InputCheckstyleAntTaskFlawless.java";
66 private static final String VIOLATED_INPUT =
67 "InputCheckstyleAntTaskError.java";
68 private static final String WARNING_INPUT =
69 "InputCheckstyleAntTaskWarning.java";
70 private static final String CONFIG_FILE =
71 "InputCheckstyleAntTaskTestChecks.xml";
72 private static final String CUSTOM_ROOT_CONFIG_FILE =
73 "InputCheckstyleAntTaskConfigCustomRootModule.xml";
74 private static final String NOT_EXISTING_FILE = "target/not_existing.xml";
75 private static final String FAILURE_PROPERTY_VALUE = "myValue";
76
77 @TempDir
78 public File temporaryFolder;
79
80 @Override
81 public String getPackageLocation() {
82 return "com/puppycrawl/tools/checkstyle/ant/checkstyleanttask/";
83 }
84
85 private CheckstyleAntTask getCheckstyleAntTask() throws IOException {
86 return getCheckstyleAntTask(CONFIG_FILE);
87 }
88
89 private CheckstyleAntTask getCheckstyleAntTask(String configFile) throws IOException {
90 final CheckstyleAntTask antTask = new CheckstyleAntTask();
91 antTask.setConfig(getPath(configFile));
92 antTask.setProject(new Project());
93 return antTask;
94 }
95
96 @Test
97 public final void testDefaultFlawless() throws IOException {
98 TestRootModuleChecker.reset();
99 final CheckstyleAntTask antTask = getCheckstyleAntTask(CUSTOM_ROOT_CONFIG_FILE);
100 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
101 antTask.execute();
102
103 assertWithMessage("Checker is not processed")
104 .that(TestRootModuleChecker.isProcessed())
105 .isTrue();
106 }
107
108 @Test
109 public final void testPathsOneFile() throws IOException {
110
111 TestRootModuleChecker.reset();
112
113 final CheckstyleAntTask antTask = getCheckstyleAntTask(CUSTOM_ROOT_CONFIG_FILE);
114 final FileSet examinationFileSet = new FileSet();
115 examinationFileSet.setFile(new File(getPath(FLAWLESS_INPUT)));
116 final Path sourcePath = new Path(antTask.getProject());
117 sourcePath.addFileset(examinationFileSet);
118 antTask.addPath(sourcePath);
119
120
121 antTask.execute();
122
123
124 assertWithMessage("Checker is not processed")
125 .that(TestRootModuleChecker.isProcessed())
126 .isTrue();
127 final List<File> filesToCheck = TestRootModuleChecker.getFilesToCheck();
128 assertWithMessage("There are more files to check than expected")
129 .that(filesToCheck)
130 .hasSize(1);
131 assertWithMessage("The path of file differs from expected")
132 .that(filesToCheck.getFirst().getAbsolutePath())
133 .isEqualTo(getPath(FLAWLESS_INPUT));
134 }
135
136 @Test
137 public final void testPathsFileWithLogVerification() throws IOException {
138
139 TestRootModuleChecker.reset();
140 final CheckstyleAntTaskLogStub antTask = new CheckstyleAntTaskLogStub();
141 antTask.setConfig(getPath(CUSTOM_ROOT_CONFIG_FILE));
142 antTask.setProject(new Project());
143 final FileSet examinationFileSet = new FileSet();
144 examinationFileSet.setFile(new File(getPath(FLAWLESS_INPUT)));
145 final Path sourcePath = new Path(antTask.getProject());
146 sourcePath.addFileset(examinationFileSet);
147 antTask.addPath(sourcePath);
148 antTask.addPath(new Path(new Project()));
149
150
151 antTask.execute();
152
153
154 final List<MessageLevelPair> loggedMessages = antTask.getLoggedMessages();
155
156 assertWithMessage("Scanning path was not logged")
157 .that(loggedMessages.stream().filter(
158 msg -> msg.getMsg().startsWith("1) Scanning path")).count())
159 .isEqualTo(1);
160
161 assertWithMessage("Scanning path was not logged")
162 .that(loggedMessages.stream().filter(
163 msg -> msg.getMsg().startsWith("1) Adding 1 files from path")).count())
164 .isEqualTo(1);
165
166 assertWithMessage("Scanning empty was logged")
167 .that(loggedMessages.stream().filter(
168 msg -> msg.getMsg().startsWith("2) Adding 0 files from path ")).count())
169 .isEqualTo(0);
170
171 assertWithMessage("Checker is not processed")
172 .that(TestRootModuleChecker.isProcessed())
173 .isTrue();
174 final List<File> filesToCheck = TestRootModuleChecker.getFilesToCheck();
175 assertWithMessage("There are more files to check than expected")
176 .that(filesToCheck)
177 .hasSize(1);
178 assertWithMessage("The path of file differs from expected")
179 .that(filesToCheck.getFirst().getAbsolutePath())
180 .isEqualTo(getPath(FLAWLESS_INPUT));
181 }
182
183 @Test
184 public final void testBaseDirPresence() throws IOException {
185 TestRootModuleChecker.reset();
186
187 final CheckstyleAntTaskLogStub antTask = new CheckstyleAntTaskLogStub();
188 antTask.setConfig(getPath(CUSTOM_ROOT_CONFIG_FILE));
189
190 final Project project = new Project();
191 project.setBaseDir(new File("."));
192 antTask.setProject(new Project());
193
194 final FileSet fileSet = new FileSet();
195 fileSet.setFile(new File(getPath(FLAWLESS_INPUT)));
196 antTask.addFileset(fileSet);
197
198 antTask.scanFileSets();
199
200 final List<MessageLevelPair> loggedMessages = antTask.getLoggedMessages();
201
202 final String expectedPath = new File(getPath(".")).getAbsolutePath();
203 final boolean containsBaseDir = loggedMessages.stream()
204 .anyMatch(msg -> msg.getMsg().contains(expectedPath));
205
206 assertWithMessage("Base directory should be present in logs.")
207 .that(containsBaseDir)
208 .isTrue();
209 }
210
211 @Test
212 public final void testPathsDirectoryWithNestedFile() throws IOException {
213
214 TestRootModuleChecker.reset();
215
216 final CheckstyleAntTaskLogStub antTask = new CheckstyleAntTaskLogStub();
217 antTask.setConfig(getPath(CUSTOM_ROOT_CONFIG_FILE));
218 antTask.setProject(new Project());
219
220 final FileResource fileResource = new FileResource(
221 antTask.getProject(), getPath(""));
222 final Path sourcePath = new Path(antTask.getProject());
223 sourcePath.add(fileResource);
224 antTask.addPath(sourcePath);
225
226
227 antTask.execute();
228
229
230 assertWithMessage("Checker is not processed")
231 .that(TestRootModuleChecker.isProcessed())
232 .isTrue();
233 final List<File> filesToCheck = TestRootModuleChecker.getFilesToCheck();
234 assertWithMessage("There are more files to check than expected")
235 .that(filesToCheck)
236 .hasSize(10);
237 assertWithMessage("The path of file differs from expected")
238 .that(filesToCheck.get(6).getAbsolutePath())
239 .isEqualTo(getPath(FLAWLESS_INPUT));
240 assertWithMessage("Amount of logged messages in unexpected")
241 .that(antTask.getLoggedMessages())
242 .hasSize(8);
243 }
244
245 @Test
246 public final void testCustomRootModule() throws IOException {
247 TestRootModuleChecker.reset();
248
249 final CheckstyleAntTask antTask = getCheckstyleAntTask(CUSTOM_ROOT_CONFIG_FILE);
250 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
251 antTask.execute();
252
253 assertWithMessage("Checker is not processed")
254 .that(TestRootModuleChecker.isProcessed())
255 .isTrue();
256 }
257
258 @Test
259 public final void testFileSet() throws IOException {
260 TestRootModuleChecker.reset();
261 final CheckstyleAntTask antTask = getCheckstyleAntTask(CUSTOM_ROOT_CONFIG_FILE);
262 final FileSet examinationFileSet = new FileSet();
263 examinationFileSet.setFile(new File(getPath(FLAWLESS_INPUT)));
264 antTask.addFileset(examinationFileSet);
265 antTask.execute();
266
267 assertWithMessage("Checker is not processed")
268 .that(TestRootModuleChecker.isProcessed())
269 .isTrue();
270 final List<File> filesToCheck = TestRootModuleChecker.getFilesToCheck();
271 assertWithMessage("There are more files to check than expected")
272 .that(filesToCheck)
273 .hasSize(1);
274 assertWithMessage("The path of file differs from expected")
275 .that(filesToCheck.getFirst().getAbsolutePath())
276 .isEqualTo(getPath(FLAWLESS_INPUT));
277 }
278
279 @Test
280 public final void testNoConfigFile() throws IOException {
281 final CheckstyleAntTask antTask = new CheckstyleAntTask();
282 antTask.setProject(new Project());
283 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
284 final Location fileLocation = new Location("build.xml", 42, 10);
285 antTask.setLocation(fileLocation);
286
287 final BuildException ex = getExpectedThrowable(BuildException.class,
288 antTask::execute,
289 "BuildException is expected");
290 assertWithMessage("Error message is unexpected")
291 .that(ex.getMessage())
292 .isEqualTo("Must specify 'config'.");
293 assertWithMessage("Location is missing in exception")
294 .that(ex.getLocation())
295 .isEqualTo(fileLocation);
296 }
297
298 @Test
299 public void testNoFileOrPathSpecified() {
300 final CheckstyleAntTask antTask = new CheckstyleAntTask();
301 antTask.setProject(new Project());
302
303 final Location fileLocation = new Location("build.xml", 42, 10);
304 antTask.setLocation(fileLocation);
305
306 final BuildException ex = getExpectedThrowable(BuildException.class,
307 antTask::execute,
308 "BuildException is expected");
309
310 assertWithMessage("Error message is unexpected")
311 .that(ex.getMessage())
312 .isEqualTo("Must specify at least one of 'file' or nested 'fileset' or 'path'.");
313 assertWithMessage("Location is missing in the exception")
314 .that(ex.getLocation())
315 .isEqualTo(fileLocation);
316 }
317
318 @Test
319 public final void testNonExistentConfig() throws IOException {
320 final CheckstyleAntTask antTask = new CheckstyleAntTask();
321 antTask.setConfig(getPath(NOT_EXISTING_FILE));
322 antTask.setProject(new Project());
323 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
324 final BuildException ex = getExpectedThrowable(BuildException.class,
325 antTask::execute,
326 "BuildException is expected");
327
328 final String expectedExceptionFormat = String.format(Locale.ROOT,
329 "Unable to create Root Module: config {%s}.", getPath(NOT_EXISTING_FILE));
330 assertWithMessage("Error message is unexpected")
331 .that(ex.getMessage())
332 .isEqualTo(expectedExceptionFormat);
333 }
334
335 @Test
336 public final void testEmptyConfigFile() throws IOException {
337 final CheckstyleAntTask antTask = new CheckstyleAntTask();
338 antTask.setConfig(getPath("InputCheckstyleAntTaskEmptyConfig.xml"));
339 antTask.setProject(new Project());
340 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
341 final BuildException ex = getExpectedThrowable(BuildException.class,
342 antTask::execute,
343 "BuildException is expected");
344 final String expectedMessage = String.format(Locale.ROOT,
345 "Unable to create Root Module: config {%s}.",
346 getPath("InputCheckstyleAntTaskEmptyConfig.xml"));
347 assertWithMessage("Error message is unexpected")
348 .that(ex.getMessage())
349 .isEqualTo(expectedMessage);
350 }
351
352 @Test
353 public final void testNoFile() throws IOException {
354 final CheckstyleAntTask antTask = getCheckstyleAntTask();
355 final BuildException ex = getExpectedThrowable(BuildException.class,
356 antTask::execute,
357 "BuildException is expected");
358 assertWithMessage("Error message is unexpected")
359 .that(ex.getMessage())
360 .isEqualTo("Must specify at least one of 'file' or nested 'fileset' or 'path'.");
361 }
362
363 @Test
364 public void testPackagePrefixResolution() throws IOException {
365 final CheckstyleAntTask antTask = new CheckstyleAntTask();
366 antTask.setProject(new Project());
367 antTask.setConfig(getPath("InputCheckstyleAntTaskPackagePrefix.xml"));
368 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
369
370 try {
371 antTask.execute();
372 assertWithMessage("Should throw BuildException for non-existent module.")
373 .fail();
374 }
375 catch (final BuildException exception) {
376 final Throwable cause = exception.getCause();
377
378 assertWithMessage("BuildException should have a cause")
379 .that(cause)
380 .isNotNull();
381 assertWithMessage("Error message should contain the correct package prefix")
382 .that(cause.getMessage())
383 .contains("com.puppycrawl.tools.checkstyle");
384 }
385 }
386
387 @Test
388 public final void testMaxWarningExceeded() throws IOException {
389 final CheckstyleAntTask antTask = getCheckstyleAntTask();
390 antTask.setFile(new File(getPath(WARNING_INPUT)));
391 antTask.setMaxWarnings(0);
392 final Location fileLocation = new Location("build.xml", 42, 10);
393 antTask.setLocation(fileLocation);
394
395 final BuildException ex = getExpectedThrowable(BuildException.class,
396 antTask::execute,
397 "BuildException is expected");
398 assertWithMessage("Error message is unexpected")
399 .that(ex.getMessage())
400 .isEqualTo("Got 0 errors (max allowed: 0) and 1 warnings.");
401 assertWithMessage("Location is missing in exception")
402 .that(ex.getLocation())
403 .isEqualTo(fileLocation);
404 }
405
406 @Test
407 public final void testMaxErrorsExceeded() throws IOException {
408 final CheckstyleAntTask antTask = getCheckstyleAntTask();
409 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
410 antTask.setMaxErrors(1);
411
412 final BuildException ex = getExpectedThrowable(BuildException.class,
413 antTask::execute,
414 "BuildException is expected");
415 assertWithMessage("Failure message should include maxErrors value")
416 .that(ex.getMessage())
417 .contains("max allowed: 1");
418 }
419
420 @Test
421 public final void testMaxErrors() throws IOException {
422 TestRootModuleChecker.reset();
423
424 final CheckstyleAntTask antTask = getCheckstyleAntTask(CUSTOM_ROOT_CONFIG_FILE);
425 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
426 antTask.setMaxErrors(2);
427 antTask.execute();
428
429 assertWithMessage("Checker is not processed")
430 .that(TestRootModuleChecker.isProcessed())
431 .isTrue();
432 }
433
434 @Test
435 public final void testFailureProperty() throws IOException {
436 final CheckstyleAntTask antTask = new CheckstyleAntTask();
437 antTask.setConfig(getPath(CONFIG_FILE));
438 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
439
440 final Project project = new Project();
441 final String failurePropertyName = "myProperty";
442 project.setProperty(failurePropertyName, FAILURE_PROPERTY_VALUE);
443
444 antTask.setProject(project);
445 antTask.setFailureProperty(failurePropertyName);
446 final BuildException ex = getExpectedThrowable(BuildException.class,
447 antTask::execute,
448 "BuildException is expected");
449 assertWithMessage("Error message is unexpected")
450 .that(ex.getMessage())
451 .isEqualTo("Got 2 errors (max allowed: 0) and 0 warnings.");
452 final Map<String, Object> hashtable = project.getProperties();
453 final Object propertyValue = hashtable.get(failurePropertyName);
454 assertWithMessage("Number of errors is unexpected")
455 .that(propertyValue)
456 .isEqualTo("Got 2 errors (max allowed: 0) and 0 warnings.");
457 }
458
459 @Test
460 public final void testOverrideProperty() throws IOException {
461 TestRootModuleChecker.reset();
462
463 final CheckstyleAntTask antTask = getCheckstyleAntTask(CUSTOM_ROOT_CONFIG_FILE);
464 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
465 final CheckstyleAntTask.Property property = new CheckstyleAntTask.Property();
466 property.setKey("lineLength.severity");
467 property.setValue("ignore");
468 antTask.addProperty(property);
469 antTask.execute();
470
471 assertWithMessage("Property key should not be empty")
472 .that(property.getKey())
473 .isNotEmpty();
474 assertWithMessage("Checker is not processed")
475 .that(TestRootModuleChecker.isProcessed())
476 .isTrue();
477 assertWithMessage("Property should be passed to checker with correct value")
478 .that(TestRootModuleChecker.getProperty())
479 .isEqualTo("ignore");
480
481 }
482
483 @Test
484 public final void testExecuteIgnoredModules() throws IOException {
485 final CheckstyleAntTask antTask = getCheckstyleAntTask();
486 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
487 antTask.setFailOnViolation(false);
488 antTask.setExecuteIgnoredModules(true);
489
490 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
491 final File outputFile = new File("target/ant_task_plain_output.txt");
492 formatter.setTofile(outputFile);
493 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
494 formatterType.setValue("plain");
495 formatter.setType(formatterType);
496 formatter.createListener(null);
497
498 antTask.addFormatter(formatter);
499 antTask.execute();
500
501 final ResourceBundle bundle = ResourceBundle.getBundle(
502 Definitions.CHECKSTYLE_BUNDLE, Locale.ROOT);
503 final String auditStartedMessage = bundle.getString(DefaultLogger.AUDIT_STARTED_MESSAGE);
504 final String auditFinishedMessage = bundle.getString(DefaultLogger.AUDIT_FINISHED_MESSAGE);
505 final List<String> output = readWholeFile(outputFile);
506 final String errorMessage = "Content of file with violations differs from expected";
507 assertWithMessage(errorMessage)
508 .that(output.getFirst())
509 .isEqualTo(auditStartedMessage);
510 assertWithMessage(errorMessage)
511 .that(output.get(1))
512 .matches("^\\[WARN].*InputCheckstyleAntTaskError.java:4: .*"
513 + "@incomplete=Some javadoc \\[WriteTag]");
514 assertWithMessage(errorMessage)
515 .that(output.get(2))
516 .matches("^\\[ERROR].*InputCheckstyleAntTaskError.java:7: "
517 + "Line is longer than 70 characters \\(found 80\\). \\[LineLength]");
518 assertWithMessage(errorMessage)
519 .that(output.get(3))
520 .matches("^\\[ERROR].*InputCheckstyleAntTaskError.java:9: "
521 + "Line is longer than 70 characters \\(found 81\\). \\[LineLength]");
522 assertWithMessage(errorMessage)
523 .that(output.get(4))
524 .isEqualTo(auditFinishedMessage);
525 }
526
527 @Test
528 public void testScanPathLogsVerboseMessage() throws IOException {
529 final CheckstyleAntTaskLogStub antTask = new CheckstyleAntTaskLogStub();
530 antTask.setConfig(getPath(CUSTOM_ROOT_CONFIG_FILE));
531 antTask.setProject(new Project());
532
533 final Path path = new Path(antTask.getProject());
534 path.setPath(getPath(FLAWLESS_INPUT));
535 antTask.addPath(path);
536
537 antTask.execute();
538
539 final String expectedLogFragment = ") Scanning path " + path;
540
541 final boolean logFound = antTask.getLoggedMessages().stream()
542 .anyMatch(pair -> {
543 return pair.getMsg().contains(expectedLogFragment)
544 && pair.getLevel() == Project.MSG_VERBOSE;
545 });
546
547 assertWithMessage("Verbose log should contain the scanning path")
548 .that(logFound)
549 .isTrue();
550 }
551
552 @Test
553 public final void testConfigurationByUrl() throws IOException {
554 final CheckstyleAntTask antTask = new CheckstyleAntTask();
555 antTask.setProject(new Project());
556 final URL url = new File(getPath(CONFIG_FILE)).toURI().toURL();
557 antTask.setConfig(url.toString());
558 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
559
560 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
561 final File outputFile = new File("target/ant_task_config_by_url.txt");
562 formatter.setTofile(outputFile);
563 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
564 formatterType.setValue("plain");
565 formatter.setType(formatterType);
566 formatter.createListener(null);
567 antTask.addFormatter(formatter);
568
569 antTask.execute();
570
571 final List<String> output = readWholeFile(outputFile);
572 final int sizeOfOutputWithNoViolations = 2;
573 assertWithMessage("No violations expected")
574 .that(output)
575 .hasSize(sizeOfOutputWithNoViolations);
576 }
577
578 @Test
579 public final void testConfigurationByResource() throws IOException {
580 final CheckstyleAntTask antTask = new CheckstyleAntTask();
581 antTask.setProject(new Project());
582 antTask.setConfig(getPath(CONFIG_FILE));
583 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
584
585 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
586 final File outputFile = new File("target/ant_task_config_by_url.txt");
587 formatter.setTofile(outputFile);
588 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
589 formatterType.setValue("plain");
590 formatter.setType(formatterType);
591 formatter.createListener(null);
592 antTask.addFormatter(formatter);
593
594 antTask.execute();
595
596 final List<String> output = readWholeFile(outputFile);
597 final int sizeOfOutputWithNoViolations = 2;
598 assertWithMessage("No violations expected")
599 .that(output)
600 .hasSize(sizeOfOutputWithNoViolations);
601 }
602
603 @Test
604 public final void testSimultaneousConfiguration() throws IOException {
605 final File file = new File(getPath(CONFIG_FILE));
606 final URL url = file.toURI().toURL();
607
608 final CheckstyleAntTask antTask = new CheckstyleAntTask();
609 antTask.setConfig(url.toString());
610 final BuildException ex = getExpectedThrowable(BuildException.class,
611 () -> antTask.setConfig("Any string value"),
612 "BuildException is expected");
613 final String expected = "Attribute 'config' has already been set";
614 assertWithMessage("Error message is unexpected")
615 .that(ex.getMessage())
616 .isEqualTo(expected);
617 }
618
619 @Test
620 public final void testSetPropertiesFile() throws IOException {
621 TestRootModuleChecker.reset();
622
623 final CheckstyleAntTask antTask = getCheckstyleAntTask(CUSTOM_ROOT_CONFIG_FILE);
624 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
625 antTask.setProperties(new File(getPath(
626 "InputCheckstyleAntTaskCheckstyleAntTest.properties")));
627 antTask.execute();
628
629 assertWithMessage("Property is not set")
630 .that(TestRootModuleChecker.getProperty())
631 .isEqualTo("ignore");
632 }
633
634 @Test
635 public final void testSetPropertiesNonExistentFile() throws IOException {
636 final CheckstyleAntTask antTask = getCheckstyleAntTask();
637 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
638 final File propertiesFile = new File(getPath(NOT_EXISTING_FILE));
639 antTask.setProperties(propertiesFile);
640 final BuildException ex = getExpectedThrowable(BuildException.class,
641 antTask::execute,
642 "BuildException is expected");
643 assertWithMessage("Error message is unexpected")
644 .that(ex.getMessage())
645 .startsWith("Error loading Properties file");
646 assertWithMessage("Error message should contain file path")
647 .that(ex.getMessage())
648 .contains(propertiesFile.toPath().toString());
649 assertWithMessage("Exception should have a location")
650 .that(ex.getLocation())
651 .isNotNull();
652 }
653
654 @Test
655 public final void testXmlOutput() throws IOException {
656 final CheckstyleAntTask antTask = getCheckstyleAntTask();
657 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
658 antTask.setFailOnViolation(false);
659 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
660 final File outputFile = new File("target/log.xml");
661 formatter.setTofile(outputFile);
662 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
663 formatterType.setValue("xml");
664 formatter.setType(formatterType);
665 antTask.addFormatter(formatter);
666 antTask.execute();
667
668 final List<String> expected = readWholeFile(
669 new File(getPath("ExpectedCheckstyleAntTaskXmlOutput.xml")));
670 final List<String> actual = readWholeFile(outputFile);
671 for (int i = 0; i < expected.size(); i++) {
672 final String line = expected.get(i);
673 if (!line.startsWith("<checkstyle version") && !line.startsWith("<file")) {
674 assertWithMessage("Content of file with violations differs from expected")
675 .that(actual.get(i))
676 .isEqualTo(line);
677 }
678 }
679 }
680
681 @Test
682 public final void testSarifOutput() throws IOException {
683 final CheckstyleAntTask antTask = getCheckstyleAntTask();
684 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
685 antTask.setFailOnViolation(false);
686 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
687 final File outputFile = new File("target/log.sarif");
688 formatter.setTofile(outputFile);
689 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
690 formatterType.setValue("sarif");
691 formatter.setType(formatterType);
692 antTask.addFormatter(formatter);
693 antTask.execute();
694
695 final List<String> expected = readWholeFile(
696 new File(getPath("ExpectedCheckstyleAntTaskSarifOutput.sarif")));
697 final List<String> actual = readWholeFile(outputFile);
698 for (int lineNumber = 0; lineNumber < expected.size(); lineNumber++) {
699 final String line = expected.get(lineNumber);
700 final StandardSubjectBuilder assertWithMessage =
701 assertWithMessage("Content of file with violations differs from expected");
702 if (line.trim().startsWith("\"uri\"")) {
703 final String expectedPathEnd = Iterables.get(
704 Splitter.on("**").split(line), 1);
705
706 final String actualLine = actual.get(lineNumber).replaceAll("\\\\", "/");
707 assertWithMessage
708 .that(actualLine)
709 .endsWith(expectedPathEnd);
710 }
711 else {
712 assertWithMessage
713 .that(actual.get(lineNumber))
714 .isEqualTo(line);
715 }
716 }
717 }
718
719 @Test
720 public final void testCreateListenerException() throws IOException {
721 final CheckstyleAntTask antTask = getCheckstyleAntTask();
722 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
723 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
724 final File outputFile = new File("target/");
725 formatter.setTofile(outputFile);
726 antTask.addFormatter(formatter);
727 final BuildException ex = getExpectedThrowable(BuildException.class,
728 antTask::execute,
729 "BuildException is expected");
730 assertWithMessage("Error message is unexpected")
731 .that(ex.getMessage())
732 .isEqualTo("Unable to create listeners: formatters "
733 + "{" + List.of(formatter) + "}.");
734 }
735
736 @Test
737 public final void testCreateListenerExceptionWithXmlLogger() throws IOException {
738 final CheckstyleAntTask antTask = getCheckstyleAntTask();
739 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
740 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
741 final File outputFile = new File("target/");
742 formatter.setTofile(outputFile);
743 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
744 formatterType.setValue("xml");
745 formatter.setType(formatterType);
746 antTask.addFormatter(formatter);
747 final BuildException ex = getExpectedThrowable(BuildException.class,
748 antTask::execute,
749 "BuildException is expected");
750 assertWithMessage("Error message is unexpected")
751 .that(ex.getMessage())
752 .startsWith("Unable to create listeners: formatters");
753 }
754
755 @Test
756 public final void testCreateListenerExceptionWithSarifLogger() throws IOException {
757 final CheckstyleAntTask antTask = getCheckstyleAntTask();
758 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
759 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
760 final File outputFile = new File("target/");
761 formatter.setTofile(outputFile);
762 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
763 formatterType.setValue("sarif");
764 formatter.setType(formatterType);
765 antTask.addFormatter(formatter);
766 final BuildException ex = getExpectedThrowable(BuildException.class,
767 antTask::execute,
768 "BuildException is expected");
769 assertWithMessage("Error message is unexpected")
770 .that(ex.getMessage())
771 .startsWith("Unable to create listeners: formatters");
772 }
773
774 @Test
775 public void testSetInvalidType() {
776 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
777 final BuildException ex = getExpectedThrowable(BuildException.class,
778 () -> formatterType.setValue("foo"),
779 "BuildException is expected");
780 assertWithMessage("Error message is unexpected")
781 .that(ex.getMessage())
782 .isEqualTo("foo is not a legal value for this attribute");
783 }
784
785 @Test
786 public void testSetFileValueByFile() throws IOException {
787 final String filename = getPath("InputCheckstyleAntTaskCheckstyleAntTest.properties");
788 final CheckstyleAntTask.Property property = new CheckstyleAntTask.Property();
789 property.setFile(new File(filename));
790 assertWithMessage("File path is unexpected")
791 .that(new File(filename).getAbsolutePath())
792 .isEqualTo(property.getValue());
793 }
794
795 @Test
796 public void testDefaultLoggerListener() throws IOException {
797 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
798 formatter.setUseFile(false);
799 assertWithMessage("Listener instance has unexpected type")
800 .that(formatter.createListener(null))
801 .isInstanceOf(DefaultLogger.class);
802 }
803
804 @Test
805 public void testDefaultLoggerListenerWithToFile() throws IOException {
806 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
807 formatter.setUseFile(false);
808 formatter.setTofile(new File("target/"));
809 assertWithMessage("Listener instance has unexpected type")
810 .that(formatter.createListener(null))
811 .isInstanceOf(DefaultLogger.class);
812 }
813
814 @Test
815 public void testXmlLoggerListener() throws IOException {
816 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
817 formatterType.setValue("xml");
818 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
819 formatter.setType(formatterType);
820 formatter.setUseFile(false);
821 assertWithMessage("Listener instance has unexpected type")
822 .that(formatter.createListener(null))
823 .isInstanceOf(XMLLogger.class);
824 }
825
826 @Test
827 public void testXmlLoggerListenerWithToFile() throws IOException {
828 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
829 formatterType.setValue("xml");
830 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
831 formatter.setType(formatterType);
832 formatter.setUseFile(false);
833 formatter.setTofile(new File("target/"));
834 assertWithMessage("Listener instance has unexpected type")
835 .that(formatter.createListener(null))
836 .isInstanceOf(XMLLogger.class);
837 }
838
839 @Test
840 public void testDefaultLoggerWithNullToFile() throws IOException {
841 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
842 formatter.setTofile(null);
843 assertWithMessage("Listener instance has unexpected type")
844 .that(formatter.createListener(null))
845 .isInstanceOf(DefaultLogger.class);
846 }
847
848 @Test
849 public void testXmlLoggerWithNullToFile() throws IOException {
850 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
851 formatterType.setValue("xml");
852 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
853 formatter.setType(formatterType);
854 formatter.setTofile(null);
855 assertWithMessage("Listener instance has unexpected type")
856 .that(formatter.createListener(null))
857 .isInstanceOf(XMLLogger.class);
858 }
859
860 @Test
861 public void testSarifLoggerListener() throws IOException {
862 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
863 formatterType.setValue("sarif");
864 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
865 formatter.setType(formatterType);
866 formatter.setUseFile(false);
867 assertWithMessage("Listener instance has unexpected type")
868 .that(formatter.createListener(null))
869 .isInstanceOf(SarifLogger.class);
870 }
871
872 @Test
873 public void testSarifLoggerListenerWithToFile() throws IOException {
874 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
875 formatterType.setValue("sarif");
876 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
877 formatter.setType(formatterType);
878 formatter.setUseFile(false);
879 formatter.setTofile(new File("target/"));
880 assertWithMessage("Listener instance has unexpected type")
881 .that(formatter.createListener(null))
882 .isInstanceOf(SarifLogger.class);
883 }
884
885 @Test
886 public void testSarifLoggerWithNullToFile() throws IOException {
887 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
888 formatterType.setValue("sarif");
889 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
890 formatter.setType(formatterType);
891 formatter.setTofile(null);
892 assertWithMessage("Listener instance has unexpected type")
893 .that(formatter.createListener(null))
894 .isInstanceOf(SarifLogger.class);
895 }
896
897 @Test
898 public void testDestroyed() throws IOException {
899 TestRootModuleChecker.reset();
900
901 final CheckstyleAntTask antTask = getCheckstyleAntTask(CUSTOM_ROOT_CONFIG_FILE);
902 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
903 antTask.setMaxWarnings(0);
904 antTask.execute();
905
906 assertWithMessage("Checker is not destroyed")
907 .that(TestRootModuleChecker.isDestroyed())
908 .isTrue();
909 }
910
911 @Test
912 public void testMaxWarnings() throws IOException {
913 TestRootModuleChecker.reset();
914
915 final CheckstyleAntTask antTask = getCheckstyleAntTask(CUSTOM_ROOT_CONFIG_FILE);
916 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
917 antTask.setMaxWarnings(0);
918 antTask.execute();
919
920 assertWithMessage("Checker is not processed")
921 .that(TestRootModuleChecker.isProcessed())
922 .isTrue();
923 }
924
925 @Test
926 public final void testExecuteLogOutput() throws Exception {
927 final URL url = new File(getPath(CONFIG_FILE)).toURI().toURL();
928 final ResourceBundle bundle = ResourceBundle.getBundle(
929 Definitions.CHECKSTYLE_BUNDLE, Locale.ROOT);
930 final String auditStartedMessage = bundle.getString(DefaultLogger.AUDIT_STARTED_MESSAGE);
931 final String auditFinishedMessage = bundle.getString(DefaultLogger.AUDIT_FINISHED_MESSAGE);
932
933 final List<MessageLevelPair> expectedList = Arrays.asList(
934 new MessageLevelPair("checkstyle version .*", Project.MSG_VERBOSE),
935 new MessageLevelPair("Adding standalone file for audit", Project.MSG_VERBOSE),
936 new MessageLevelPair("To locate the files took \\d+ ms.", Project.MSG_VERBOSE),
937 new MessageLevelPair("Running Checkstyle on 1 files", Project.MSG_INFO),
938 new MessageLevelPair("Using configuration file:.*", Project.MSG_VERBOSE),
939 new MessageLevelPair(auditStartedMessage, Project.MSG_DEBUG),
940 new MessageLevelPair(auditFinishedMessage, Project.MSG_DEBUG),
941 new MessageLevelPair("To process the files took \\d+ ms.", Project.MSG_VERBOSE),
942 new MessageLevelPair("Total execution took \\d+ ms.", Project.MSG_VERBOSE)
943 );
944
945 final CheckstyleAntTaskLogStub antTask = new CheckstyleAntTaskLogStub();
946 antTask.setProject(new Project());
947 antTask.setConfig(url.toString());
948 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
949
950 antTask.execute();
951
952 final List<MessageLevelPair> loggedMessages = antTask.getLoggedMessages();
953
954 assertWithMessage("Amount of log messages is unexpected")
955 .that(loggedMessages)
956 .hasSize(expectedList.size());
957
958 for (int i = 0; i < expectedList.size(); i++) {
959 final MessageLevelPair expected = expectedList.get(i);
960 final MessageLevelPair actual = loggedMessages.get(i);
961 assertWithMessage("Log messages should match")
962 .that(actual.getMsg())
963 .matches(expected.getMsg());
964 assertWithMessage("Log levels should be equal")
965 .that(actual.getLevel())
966 .isEqualTo(expected.getLevel());
967 }
968 }
969
970 @Test
971 public void testCheckerException() throws IOException {
972 final CheckstyleAntTask antTask = new CheckstyleAntTaskStub();
973 antTask.setConfig(getPath(CONFIG_FILE));
974 antTask.setProject(new Project());
975 antTask.setFile(new File(""));
976 final BuildException ex = getExpectedThrowable(BuildException.class,
977 antTask::execute,
978 "BuildException is expected");
979 assertWithMessage("Error message is unexpected")
980 .that(ex)
981 .hasMessageThat()
982 .startsWith("Unable to process files:");
983 }
984
985 @Test
986 public void testLoggedTime() throws IOException {
987 final CheckstyleAntTaskLogStub antTask = new CheckstyleAntTaskLogStub();
988 antTask.setConfig(getPath(CONFIG_FILE));
989 antTask.setProject(new Project());
990 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
991 final long startTime = System.currentTimeMillis();
992 antTask.execute();
993 final long endTime = System.currentTimeMillis();
994 final long testingTime = endTime - startTime;
995 final List<MessageLevelPair> loggedMessages = antTask.getLoggedMessages();
996
997 assertLoggedTime(loggedMessages, testingTime, "Total execution");
998 assertLoggedTime(loggedMessages, testingTime, "To locate the files");
999 assertLoggedTime(loggedMessages, testingTime, "To process the files");
1000 }
1001
1002 private static void assertLoggedTime(List<MessageLevelPair> loggedMessages,
1003 long testingTime, String expectedMsg) {
1004
1005 final Optional<MessageLevelPair> optionalMessageLevelPair = loggedMessages.stream()
1006 .filter(msg -> msg.getMsg().startsWith(expectedMsg))
1007 .findFirst();
1008
1009 assertWithMessage("Message should be present.")
1010 .that(optionalMessageLevelPair.isPresent())
1011 .isTrue();
1012
1013 final long actualTime = getNumberFromLine(optionalMessageLevelPair.orElseThrow().getMsg());
1014
1015 assertWithMessage("Logged time in '%s' must be less than the testing time", expectedMsg)
1016 .that(actualTime)
1017 .isAtMost(testingTime);
1018 }
1019
1020 private static List<String> readWholeFile(File outputFile) throws IOException {
1021 return Files.readAllLines(outputFile.toPath(), StandardCharsets.UTF_8);
1022 }
1023
1024 private static long getNumberFromLine(String line) {
1025 final Matcher matcher = Pattern.compile("(\\d+)").matcher(line);
1026 matcher.find();
1027 return Long.parseLong(matcher.group(1));
1028 }
1029
1030 @Test
1031 public void testMaxWarningDefault() throws IOException {
1032 final CheckstyleAntTask antTask = getCheckstyleAntTask();
1033 final File inputFile = new File(getPath(WARNING_INPUT));
1034 final Location fileLocation = new Location("build.xml", 42, 10);
1035
1036 antTask.setFile(inputFile);
1037 antTask.setLocation(fileLocation);
1038 assertDoesNotThrow(antTask::execute, "BuildException is not expected");
1039 }
1040
1041 @Test
1042 public void testMultipleFormattersProduceOutputs() throws IOException {
1043 final CheckstyleAntTask antTask = getCheckstyleAntTask();
1044 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
1045 antTask.setFailOnViolation(false);
1046
1047 final File firstOutput = new File(temporaryFolder, "ant_task_multi_formatter_1.txt");
1048 final File secondOutput = new File(temporaryFolder, "ant_task_multi_formatter_2.txt");
1049
1050 antTask.addFormatter(createPlainFormatter(firstOutput));
1051 antTask.addFormatter(createPlainFormatter(secondOutput));
1052
1053 antTask.execute();
1054
1055 assertWithMessage("First formatter output was not created")
1056 .that(firstOutput.exists())
1057 .isTrue();
1058 assertWithMessage("First formatter output is empty")
1059 .that(firstOutput.length())
1060 .isGreaterThan(0L);
1061 assertWithMessage("Second formatter output was not created")
1062 .that(secondOutput.exists())
1063 .isTrue();
1064 assertWithMessage("Second formatter output is empty")
1065 .that(secondOutput.length())
1066 .isGreaterThan(0L);
1067 }
1068
1069 @Test
1070 public void testExceptionMessageContainsFileList() throws Exception {
1071 final CheckstyleAntTask antTask = new CheckstyleAntTaskStub();
1072 antTask.setConfig(getPath(CONFIG_FILE));
1073 antTask.setProject(new Project());
1074
1075 final File file = new File(getPath(FLAWLESS_INPUT));
1076 antTask.setFile(file);
1077
1078 final BuildException ex = getExpectedThrowable(
1079 BuildException.class, antTask::execute, "BuildException is expected");
1080
1081 assertWithMessage("Exception message must contain the file name")
1082 .that(ex.getMessage())
1083 .contains(file.getName());
1084 }
1085
1086 @Test
1087 public void testAntProjectPropertyValueIsCopiedCorrectly() throws IOException {
1088 TestRootModuleChecker.reset();
1089
1090 final CheckstyleAntTask antTask = getCheckstyleAntTask(CUSTOM_ROOT_CONFIG_FILE);
1091
1092 final Project project = new Project();
1093 project.setProperty("lineLength.severity", "ignore");
1094 antTask.setProject(project);
1095
1096 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
1097
1098 antTask.execute();
1099
1100 assertWithMessage("Failed to propagate Ant project property value correctly")
1101 .that(TestRootModuleChecker.getProperty())
1102 .isEqualTo("ignore");
1103 }
1104
1105 @Test
1106 public final void testFileSetWithLogIndexVerification() throws IOException {
1107
1108 TestRootModuleChecker.reset();
1109
1110 final CheckstyleAntTaskLogStub antTask = new CheckstyleAntTaskLogStub();
1111 antTask.setConfig(getPath(CUSTOM_ROOT_CONFIG_FILE));
1112 antTask.setProject(new Project());
1113
1114 final FileSet fileSet = new FileSet();
1115 fileSet.setFile(new File(getPath(FLAWLESS_INPUT)));
1116 antTask.addFileset(fileSet);
1117
1118
1119 antTask.scanFileSets();
1120
1121
1122 final List<MessageLevelPair> loggedMessages = antTask.getLoggedMessages();
1123
1124 assertWithMessage("Log message with correct index was not found")
1125 .that(loggedMessages.stream().filter(
1126 msg -> msg.getMsg().startsWith("0) Adding 1 files from directory")).count())
1127 .isEqualTo(1);
1128 }
1129
1130 private static CheckstyleAntTask.Formatter createPlainFormatter(File outputFile) {
1131 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
1132 formatter.setTofile(outputFile);
1133 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
1134 formatterType.setValue("plain");
1135 formatter.setType(formatterType);
1136 return formatter;
1137 }
1138
1139 }