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