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 final BuildException exception = getExpectedThrowable(BuildException.class,
371 antTask::execute,
372 "Should throw BuildException for non-existent module.");
373 final Throwable cause = exception.getCause();
374
375 assertWithMessage("BuildException should have a cause")
376 .that(cause)
377 .isNotNull();
378 assertWithMessage("Error message should contain the correct package prefix")
379 .that(cause.getMessage())
380 .contains("com.puppycrawl.tools.checkstyle");
381 }
382
383 @Test
384 public final void testMaxWarningExceeded() throws IOException {
385 final CheckstyleAntTask antTask = getCheckstyleAntTask();
386 antTask.setFile(new File(getPath(WARNING_INPUT)));
387 antTask.setMaxWarnings(0);
388 final Location fileLocation = new Location("build.xml", 42, 10);
389 antTask.setLocation(fileLocation);
390
391 final BuildException ex = getExpectedThrowable(BuildException.class,
392 antTask::execute,
393 "BuildException is expected");
394 assertWithMessage("Error message is unexpected")
395 .that(ex.getMessage())
396 .isEqualTo("Got 0 errors (max allowed: 0) and 1 warnings.");
397 assertWithMessage("Location is missing in exception")
398 .that(ex.getLocation())
399 .isEqualTo(fileLocation);
400 }
401
402 @Test
403 public final void testMaxErrorsExceeded() throws IOException {
404 final CheckstyleAntTask antTask = getCheckstyleAntTask();
405 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
406 antTask.setMaxErrors(1);
407
408 final BuildException ex = getExpectedThrowable(BuildException.class,
409 antTask::execute,
410 "BuildException is expected");
411 assertWithMessage("Failure message should include maxErrors value")
412 .that(ex.getMessage())
413 .contains("max allowed: 1");
414 }
415
416 @Test
417 public final void testMaxErrors() throws IOException {
418 TestRootModuleChecker.reset();
419
420 final CheckstyleAntTask antTask = getCheckstyleAntTask(CUSTOM_ROOT_CONFIG_FILE);
421 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
422 antTask.setMaxErrors(2);
423 antTask.execute();
424
425 assertWithMessage("Checker is not processed")
426 .that(TestRootModuleChecker.isProcessed())
427 .isTrue();
428 }
429
430 @Test
431 public final void testFailureProperty() throws IOException {
432 final CheckstyleAntTask antTask = new CheckstyleAntTask();
433 antTask.setConfig(getPath(CONFIG_FILE));
434 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
435
436 final Project project = new Project();
437 final String failurePropertyName = "myProperty";
438 project.setProperty(failurePropertyName, FAILURE_PROPERTY_VALUE);
439
440 antTask.setProject(project);
441 antTask.setFailureProperty(failurePropertyName);
442 final BuildException ex = getExpectedThrowable(BuildException.class,
443 antTask::execute,
444 "BuildException is expected");
445 assertWithMessage("Error message is unexpected")
446 .that(ex.getMessage())
447 .isEqualTo("Got 2 errors (max allowed: 0) and 0 warnings.");
448 final Map<String, Object> hashtable = project.getProperties();
449 final Object propertyValue = hashtable.get(failurePropertyName);
450 assertWithMessage("Number of errors is unexpected")
451 .that(propertyValue)
452 .isEqualTo("Got 2 errors (max allowed: 0) and 0 warnings.");
453 }
454
455 @Test
456 public final void testOverrideProperty() throws IOException {
457 TestRootModuleChecker.reset();
458
459 final CheckstyleAntTask antTask = getCheckstyleAntTask(CUSTOM_ROOT_CONFIG_FILE);
460 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
461 final CheckstyleAntTask.Property property = new CheckstyleAntTask.Property();
462 property.setKey("lineLength.severity");
463 property.setValue("ignore");
464 antTask.addProperty(property);
465 antTask.execute();
466
467 assertWithMessage("Property key should not be empty")
468 .that(property.getKey())
469 .isNotEmpty();
470 assertWithMessage("Checker is not processed")
471 .that(TestRootModuleChecker.isProcessed())
472 .isTrue();
473 assertWithMessage("Property should be passed to checker with correct value")
474 .that(TestRootModuleChecker.getProperty())
475 .isEqualTo("ignore");
476
477 }
478
479 @Test
480 public final void testExecuteIgnoredModules() throws IOException {
481 final CheckstyleAntTask antTask = getCheckstyleAntTask();
482 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
483 antTask.setFailOnViolation(false);
484 antTask.setExecuteIgnoredModules(true);
485
486 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
487 final File outputFile = new File("target/ant_task_plain_output.txt");
488 formatter.setTofile(outputFile);
489 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
490 formatterType.setValue("plain");
491 formatter.setType(formatterType);
492 formatter.createListener(null);
493
494 antTask.addFormatter(formatter);
495 antTask.execute();
496
497 final ResourceBundle bundle = ResourceBundle.getBundle(
498 Definitions.CHECKSTYLE_BUNDLE, Locale.ROOT);
499 final String auditStartedMessage = bundle.getString(DefaultLogger.AUDIT_STARTED_MESSAGE);
500 final String auditFinishedMessage = bundle.getString(DefaultLogger.AUDIT_FINISHED_MESSAGE);
501 final List<String> output = readWholeFile(outputFile);
502 final String errorMessage = "Content of file with violations differs from expected";
503 assertWithMessage(errorMessage)
504 .that(output.getFirst())
505 .isEqualTo(auditStartedMessage);
506 assertWithMessage(errorMessage)
507 .that(output.get(1))
508 .matches("^\\[WARN].*InputCheckstyleAntTaskError.java:4: .*"
509 + "@incomplete=Some javadoc \\[WriteTag]");
510 assertWithMessage(errorMessage)
511 .that(output.get(2))
512 .matches("^\\[ERROR].*InputCheckstyleAntTaskError.java:7: "
513 + "Line is longer than 70 characters \\(found 80\\). \\[LineLength]");
514 assertWithMessage(errorMessage)
515 .that(output.get(3))
516 .matches("^\\[ERROR].*InputCheckstyleAntTaskError.java:9: "
517 + "Line is longer than 70 characters \\(found 81\\). \\[LineLength]");
518 assertWithMessage(errorMessage)
519 .that(output.get(4))
520 .isEqualTo(auditFinishedMessage);
521 }
522
523 @Test
524 public void testScanPathLogsVerboseMessage() throws IOException {
525 final CheckstyleAntTaskLogStub antTask = new CheckstyleAntTaskLogStub();
526 antTask.setConfig(getPath(CUSTOM_ROOT_CONFIG_FILE));
527 antTask.setProject(new Project());
528
529 final Path path = new Path(antTask.getProject());
530 path.setPath(getPath(FLAWLESS_INPUT));
531 antTask.addPath(path);
532
533 antTask.execute();
534
535 final String expectedLogFragment = ") Scanning path " + path;
536
537 final boolean logFound = antTask.getLoggedMessages().stream()
538 .anyMatch(pair -> {
539 return pair.getMsg().contains(expectedLogFragment)
540 && pair.getLevel() == Project.MSG_VERBOSE;
541 });
542
543 assertWithMessage("Verbose log should contain the scanning path")
544 .that(logFound)
545 .isTrue();
546 }
547
548 @Test
549 public final void testConfigurationByUrl() throws IOException {
550 final CheckstyleAntTask antTask = new CheckstyleAntTask();
551 antTask.setProject(new Project());
552 final URL url = new File(getPath(CONFIG_FILE)).toURI().toURL();
553 antTask.setConfig(url.toString());
554 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
555
556 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
557 final File outputFile = new File("target/ant_task_config_by_url.txt");
558 formatter.setTofile(outputFile);
559 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
560 formatterType.setValue("plain");
561 formatter.setType(formatterType);
562 formatter.createListener(null);
563 antTask.addFormatter(formatter);
564
565 antTask.execute();
566
567 final List<String> output = readWholeFile(outputFile);
568 final int sizeOfOutputWithNoViolations = 2;
569 assertWithMessage("No violations expected")
570 .that(output)
571 .hasSize(sizeOfOutputWithNoViolations);
572 }
573
574 @Test
575 public final void testConfigurationByResource() throws IOException {
576 final CheckstyleAntTask antTask = new CheckstyleAntTask();
577 antTask.setProject(new Project());
578 antTask.setConfig(getPath(CONFIG_FILE));
579 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
580
581 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
582 final File outputFile = new File("target/ant_task_config_by_url.txt");
583 formatter.setTofile(outputFile);
584 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
585 formatterType.setValue("plain");
586 formatter.setType(formatterType);
587 formatter.createListener(null);
588 antTask.addFormatter(formatter);
589
590 antTask.execute();
591
592 final List<String> output = readWholeFile(outputFile);
593 final int sizeOfOutputWithNoViolations = 2;
594 assertWithMessage("No violations expected")
595 .that(output)
596 .hasSize(sizeOfOutputWithNoViolations);
597 }
598
599 @Test
600 public final void testSimultaneousConfiguration() throws IOException {
601 final File file = new File(getPath(CONFIG_FILE));
602 final URL url = file.toURI().toURL();
603
604 final CheckstyleAntTask antTask = new CheckstyleAntTask();
605 antTask.setConfig(url.toString());
606 final BuildException ex = getExpectedThrowable(BuildException.class,
607 () -> antTask.setConfig("Any string value"),
608 "BuildException is expected");
609 final String expected = "Attribute 'config' has already been set";
610 assertWithMessage("Error message is unexpected")
611 .that(ex.getMessage())
612 .isEqualTo(expected);
613 }
614
615 @Test
616 public final void testSetPropertiesFile() throws IOException {
617 TestRootModuleChecker.reset();
618
619 final CheckstyleAntTask antTask = getCheckstyleAntTask(CUSTOM_ROOT_CONFIG_FILE);
620 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
621 antTask.setProperties(new File(getPath(
622 "InputCheckstyleAntTaskCheckstyleAntTest.properties")));
623 antTask.execute();
624
625 assertWithMessage("Property is not set")
626 .that(TestRootModuleChecker.getProperty())
627 .isEqualTo("ignore");
628 }
629
630 @Test
631 public final void testSetPropertiesNonExistentFile() throws IOException {
632 final CheckstyleAntTask antTask = getCheckstyleAntTask();
633 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
634 final File propertiesFile = new File(getPath(NOT_EXISTING_FILE));
635 antTask.setProperties(propertiesFile);
636 final BuildException ex = getExpectedThrowable(BuildException.class,
637 antTask::execute,
638 "BuildException is expected");
639 assertWithMessage("Error message is unexpected")
640 .that(ex.getMessage())
641 .startsWith("Error loading Properties file");
642 assertWithMessage("Error message should contain file path")
643 .that(ex.getMessage())
644 .contains(propertiesFile.toPath().toString());
645 assertWithMessage("Exception should have a location")
646 .that(ex.getLocation())
647 .isNotNull();
648 }
649
650 @Test
651 public final void testXmlOutput() throws IOException {
652 final CheckstyleAntTask antTask = getCheckstyleAntTask();
653 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
654 antTask.setFailOnViolation(false);
655 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
656 final File outputFile = new File("target/log.xml");
657 formatter.setTofile(outputFile);
658 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
659 formatterType.setValue("xml");
660 formatter.setType(formatterType);
661 antTask.addFormatter(formatter);
662 antTask.execute();
663
664 final List<String> expected = readWholeFile(
665 new File(getPath("ExpectedCheckstyleAntTaskXmlOutput.xml")));
666 final List<String> actual = readWholeFile(outputFile);
667 for (int i = 0; i < expected.size(); i++) {
668 final String line = expected.get(i);
669 if (!line.startsWith("<checkstyle version") && !line.startsWith("<file")) {
670 assertWithMessage("Content of file with violations differs from expected")
671 .that(actual.get(i))
672 .isEqualTo(line);
673 }
674 }
675 }
676
677 @Test
678 public final void testSarifOutput() throws IOException {
679 final CheckstyleAntTask antTask = getCheckstyleAntTask();
680 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
681 antTask.setFailOnViolation(false);
682 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
683 final File outputFile = new File("target/log.sarif");
684 formatter.setTofile(outputFile);
685 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
686 formatterType.setValue("sarif");
687 formatter.setType(formatterType);
688 antTask.addFormatter(formatter);
689 antTask.execute();
690
691 final List<String> expected = readWholeFile(
692 new File(getPath("ExpectedCheckstyleAntTaskSarifOutput.sarif")));
693 final List<String> actual = readWholeFile(outputFile);
694 for (int lineNumber = 0; lineNumber < expected.size(); lineNumber++) {
695 final String line = expected.get(lineNumber);
696 final StandardSubjectBuilder assertWithMessage =
697 assertWithMessage("Content of file with violations differs from expected");
698 if (line.trim().startsWith("\"uri\"")) {
699 final String expectedPathEnd = Iterables.get(
700 Splitter.on("**").split(line), 1);
701
702 final String actualLine = actual.get(lineNumber).replaceAll("\\\\", "/");
703 assertWithMessage
704 .that(actualLine)
705 .endsWith(expectedPathEnd);
706 }
707 else {
708 assertWithMessage
709 .that(actual.get(lineNumber))
710 .isEqualTo(line);
711 }
712 }
713 }
714
715 @Test
716 public final void testCreateListenerException() throws IOException {
717 final CheckstyleAntTask antTask = getCheckstyleAntTask();
718 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
719 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
720 final File outputFile = new File("target/");
721 formatter.setTofile(outputFile);
722 antTask.addFormatter(formatter);
723 final BuildException ex = getExpectedThrowable(BuildException.class,
724 antTask::execute,
725 "BuildException is expected");
726 assertWithMessage("Error message is unexpected")
727 .that(ex.getMessage())
728 .isEqualTo("Unable to create listeners: formatters "
729 + "{" + List.of(formatter) + "}.");
730 }
731
732 @Test
733 public final void testCreateListenerExceptionWithXmlLogger() throws IOException {
734 final CheckstyleAntTask antTask = getCheckstyleAntTask();
735 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
736 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
737 final File outputFile = new File("target/");
738 formatter.setTofile(outputFile);
739 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
740 formatterType.setValue("xml");
741 formatter.setType(formatterType);
742 antTask.addFormatter(formatter);
743 final BuildException ex = getExpectedThrowable(BuildException.class,
744 antTask::execute,
745 "BuildException is expected");
746 assertWithMessage("Error message is unexpected")
747 .that(ex.getMessage())
748 .startsWith("Unable to create listeners: formatters");
749 }
750
751 @Test
752 public final void testCreateListenerExceptionWithSarifLogger() throws IOException {
753 final CheckstyleAntTask antTask = getCheckstyleAntTask();
754 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
755 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
756 final File outputFile = new File("target/");
757 formatter.setTofile(outputFile);
758 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
759 formatterType.setValue("sarif");
760 formatter.setType(formatterType);
761 antTask.addFormatter(formatter);
762 final BuildException ex = getExpectedThrowable(BuildException.class,
763 antTask::execute,
764 "BuildException is expected");
765 assertWithMessage("Error message is unexpected")
766 .that(ex.getMessage())
767 .startsWith("Unable to create listeners: formatters");
768 }
769
770 @Test
771 public void testSetInvalidType() {
772 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
773 final BuildException ex = getExpectedThrowable(BuildException.class,
774 () -> formatterType.setValue("foo"),
775 "BuildException is expected");
776 assertWithMessage("Error message is unexpected")
777 .that(ex.getMessage())
778 .isEqualTo("foo is not a legal value for this attribute");
779 }
780
781 @Test
782 public void testSetFileValueByFile() throws IOException {
783 final String filename = getPath("InputCheckstyleAntTaskCheckstyleAntTest.properties");
784 final CheckstyleAntTask.Property property = new CheckstyleAntTask.Property();
785 property.setFile(new File(filename));
786 assertWithMessage("File path is unexpected")
787 .that(new File(filename).getAbsolutePath())
788 .isEqualTo(property.getValue());
789 }
790
791 @Test
792 public void testDefaultLoggerListener() throws IOException {
793 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
794 formatter.setUseFile(false);
795 assertWithMessage("Listener instance has unexpected type")
796 .that(formatter.createListener(null))
797 .isInstanceOf(DefaultLogger.class);
798 }
799
800 @Test
801 public void testDefaultLoggerListenerWithToFile() throws IOException {
802 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
803 formatter.setUseFile(false);
804 formatter.setTofile(new File("target/"));
805 assertWithMessage("Listener instance has unexpected type")
806 .that(formatter.createListener(null))
807 .isInstanceOf(DefaultLogger.class);
808 }
809
810 @Test
811 public void testXmlLoggerListener() 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 assertWithMessage("Listener instance has unexpected type")
818 .that(formatter.createListener(null))
819 .isInstanceOf(XMLLogger.class);
820 }
821
822 @Test
823 public void testXmlLoggerListenerWithToFile() throws IOException {
824 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
825 formatterType.setValue("xml");
826 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
827 formatter.setType(formatterType);
828 formatter.setUseFile(false);
829 formatter.setTofile(new File("target/"));
830 assertWithMessage("Listener instance has unexpected type")
831 .that(formatter.createListener(null))
832 .isInstanceOf(XMLLogger.class);
833 }
834
835 @Test
836 public void testDefaultLoggerWithNullToFile() throws IOException {
837 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
838 formatter.setTofile(null);
839 assertWithMessage("Listener instance has unexpected type")
840 .that(formatter.createListener(null))
841 .isInstanceOf(DefaultLogger.class);
842 }
843
844 @Test
845 public void testXmlLoggerWithNullToFile() throws IOException {
846 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
847 formatterType.setValue("xml");
848 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
849 formatter.setType(formatterType);
850 formatter.setTofile(null);
851 assertWithMessage("Listener instance has unexpected type")
852 .that(formatter.createListener(null))
853 .isInstanceOf(XMLLogger.class);
854 }
855
856 @Test
857 public void testSarifLoggerListener() 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 assertWithMessage("Listener instance has unexpected type")
864 .that(formatter.createListener(null))
865 .isInstanceOf(SarifLogger.class);
866 }
867
868 @Test
869 public void testSarifLoggerListenerWithToFile() throws IOException {
870 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
871 formatterType.setValue("sarif");
872 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
873 formatter.setType(formatterType);
874 formatter.setUseFile(false);
875 formatter.setTofile(new File("target/"));
876 assertWithMessage("Listener instance has unexpected type")
877 .that(formatter.createListener(null))
878 .isInstanceOf(SarifLogger.class);
879 }
880
881 @Test
882 public void testSarifLoggerWithNullToFile() throws IOException {
883 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
884 formatterType.setValue("sarif");
885 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
886 formatter.setType(formatterType);
887 formatter.setTofile(null);
888 assertWithMessage("Listener instance has unexpected type")
889 .that(formatter.createListener(null))
890 .isInstanceOf(SarifLogger.class);
891 }
892
893 @Test
894 public void testDestroyed() throws IOException {
895 TestRootModuleChecker.reset();
896
897 final CheckstyleAntTask antTask = getCheckstyleAntTask(CUSTOM_ROOT_CONFIG_FILE);
898 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
899 antTask.setMaxWarnings(0);
900 antTask.execute();
901
902 assertWithMessage("Checker is not destroyed")
903 .that(TestRootModuleChecker.isDestroyed())
904 .isTrue();
905 }
906
907 @Test
908 public void testMaxWarnings() throws IOException {
909 TestRootModuleChecker.reset();
910
911 final CheckstyleAntTask antTask = getCheckstyleAntTask(CUSTOM_ROOT_CONFIG_FILE);
912 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
913 antTask.setMaxWarnings(0);
914 antTask.execute();
915
916 assertWithMessage("Checker is not processed")
917 .that(TestRootModuleChecker.isProcessed())
918 .isTrue();
919 }
920
921 @Test
922 public final void testExecuteLogOutput() throws Exception {
923 final URL url = new File(getPath(CONFIG_FILE)).toURI().toURL();
924 final ResourceBundle bundle = ResourceBundle.getBundle(
925 Definitions.CHECKSTYLE_BUNDLE, Locale.ROOT);
926 final String auditStartedMessage = bundle.getString(DefaultLogger.AUDIT_STARTED_MESSAGE);
927 final String auditFinishedMessage = bundle.getString(DefaultLogger.AUDIT_FINISHED_MESSAGE);
928
929 final List<MessageLevelPair> expectedList = Arrays.asList(
930 new MessageLevelPair("checkstyle version .*", Project.MSG_VERBOSE),
931 new MessageLevelPair("Adding standalone file for audit", Project.MSG_VERBOSE),
932 new MessageLevelPair("To locate the files took \\d+ ms.", Project.MSG_VERBOSE),
933 new MessageLevelPair("Running Checkstyle on 1 files", Project.MSG_INFO),
934 new MessageLevelPair("Using configuration file:.*", Project.MSG_VERBOSE),
935 new MessageLevelPair(auditStartedMessage, Project.MSG_DEBUG),
936 new MessageLevelPair(auditFinishedMessage, Project.MSG_DEBUG),
937 new MessageLevelPair("To process the files took \\d+ ms.", Project.MSG_VERBOSE),
938 new MessageLevelPair("Total execution took \\d+ ms.", Project.MSG_VERBOSE)
939 );
940
941 final CheckstyleAntTaskLogStub antTask = new CheckstyleAntTaskLogStub();
942 antTask.setProject(new Project());
943 antTask.setConfig(url.toString());
944 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
945
946 antTask.execute();
947
948 final List<MessageLevelPair> loggedMessages = antTask.getLoggedMessages();
949
950 assertWithMessage("Amount of log messages is unexpected")
951 .that(loggedMessages)
952 .hasSize(expectedList.size());
953
954 for (int i = 0; i < expectedList.size(); i++) {
955 final MessageLevelPair expected = expectedList.get(i);
956 final MessageLevelPair actual = loggedMessages.get(i);
957 assertWithMessage("Log messages should match")
958 .that(actual.getMsg())
959 .matches(expected.getMsg());
960 assertWithMessage("Log levels should be equal")
961 .that(actual.getLevel())
962 .isEqualTo(expected.getLevel());
963 }
964 }
965
966 @Test
967 public void testCheckerException() throws IOException {
968 final CheckstyleAntTask antTask = new CheckstyleAntTaskStub();
969 antTask.setConfig(getPath(CONFIG_FILE));
970 antTask.setProject(new Project());
971 antTask.setFile(new File(""));
972 final BuildException ex = getExpectedThrowable(BuildException.class,
973 antTask::execute,
974 "BuildException is expected");
975 assertWithMessage("Error message is unexpected")
976 .that(ex)
977 .hasMessageThat()
978 .startsWith("Unable to process files:");
979 }
980
981 @Test
982 public void testLoggedTime() throws IOException {
983 final CheckstyleAntTaskLogStub antTask = new CheckstyleAntTaskLogStub();
984 antTask.setConfig(getPath(CONFIG_FILE));
985 antTask.setProject(new Project());
986 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
987 final long startTime = System.currentTimeMillis();
988 antTask.execute();
989 final long endTime = System.currentTimeMillis();
990 final long testingTime = endTime - startTime;
991 final List<MessageLevelPair> loggedMessages = antTask.getLoggedMessages();
992
993 assertLoggedTime(loggedMessages, testingTime, "Total execution");
994 assertLoggedTime(loggedMessages, testingTime, "To locate the files");
995 assertLoggedTime(loggedMessages, testingTime, "To process the files");
996 }
997
998 private static void assertLoggedTime(List<MessageLevelPair> loggedMessages,
999 long testingTime, String expectedMsg) {
1000
1001 final Optional<MessageLevelPair> optionalMessageLevelPair = loggedMessages.stream()
1002 .filter(msg -> msg.getMsg().startsWith(expectedMsg))
1003 .findFirst();
1004
1005 assertWithMessage("Message should be present.")
1006 .that(optionalMessageLevelPair.isPresent())
1007 .isTrue();
1008
1009 final long actualTime = getNumberFromLine(optionalMessageLevelPair.orElseThrow().getMsg());
1010
1011 assertWithMessage("Logged time in '%s' must be less than the testing time", expectedMsg)
1012 .that(actualTime)
1013 .isAtMost(testingTime);
1014 }
1015
1016 private static List<String> readWholeFile(File outputFile) throws IOException {
1017 return Files.readAllLines(outputFile.toPath(), StandardCharsets.UTF_8);
1018 }
1019
1020 private static long getNumberFromLine(String line) {
1021 final Matcher matcher = Pattern.compile("(\\d+)").matcher(line);
1022 matcher.find();
1023 return Long.parseLong(matcher.group(1));
1024 }
1025
1026 @Test
1027 public void testMaxWarningDefault() throws IOException {
1028 final CheckstyleAntTask antTask = getCheckstyleAntTask();
1029 final File inputFile = new File(getPath(WARNING_INPUT));
1030 final Location fileLocation = new Location("build.xml", 42, 10);
1031
1032 antTask.setFile(inputFile);
1033 antTask.setLocation(fileLocation);
1034 assertDoesNotThrow(antTask::execute, "BuildException is not expected");
1035 }
1036
1037 @Test
1038 public void testMultipleFormattersProduceOutputs() throws IOException {
1039 final CheckstyleAntTask antTask = getCheckstyleAntTask();
1040 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
1041 antTask.setFailOnViolation(false);
1042
1043 final File firstOutput = new File(temporaryFolder, "ant_task_multi_formatter_1.txt");
1044 final File secondOutput = new File(temporaryFolder, "ant_task_multi_formatter_2.txt");
1045
1046 antTask.addFormatter(createPlainFormatter(firstOutput));
1047 antTask.addFormatter(createPlainFormatter(secondOutput));
1048
1049 antTask.execute();
1050
1051 assertWithMessage("First formatter output was not created")
1052 .that(firstOutput.exists())
1053 .isTrue();
1054 assertWithMessage("First formatter output is empty")
1055 .that(firstOutput.length())
1056 .isGreaterThan(0L);
1057 assertWithMessage("Second formatter output was not created")
1058 .that(secondOutput.exists())
1059 .isTrue();
1060 assertWithMessage("Second formatter output is empty")
1061 .that(secondOutput.length())
1062 .isGreaterThan(0L);
1063 }
1064
1065 @Test
1066 public void testExceptionMessageContainsFileList() throws Exception {
1067 final CheckstyleAntTask antTask = new CheckstyleAntTaskStub();
1068 antTask.setConfig(getPath(CONFIG_FILE));
1069 antTask.setProject(new Project());
1070
1071 final File file = new File(getPath(FLAWLESS_INPUT));
1072 antTask.setFile(file);
1073
1074 final BuildException ex = getExpectedThrowable(
1075 BuildException.class, antTask::execute, "BuildException is expected");
1076
1077 assertWithMessage("Exception message must contain the file name")
1078 .that(ex.getMessage())
1079 .contains(file.getName());
1080 }
1081
1082 @Test
1083 public void testAntProjectPropertyValueIsCopiedCorrectly() throws IOException {
1084 TestRootModuleChecker.reset();
1085
1086 final CheckstyleAntTask antTask = getCheckstyleAntTask(CUSTOM_ROOT_CONFIG_FILE);
1087
1088 final Project project = new Project();
1089 project.setProperty("lineLength.severity", "ignore");
1090 antTask.setProject(project);
1091
1092 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
1093
1094 antTask.execute();
1095
1096 assertWithMessage("Failed to propagate Ant project property value correctly")
1097 .that(TestRootModuleChecker.getProperty())
1098 .isEqualTo("ignore");
1099 }
1100
1101 @Test
1102 public final void testFileSetWithLogIndexVerification() throws IOException {
1103
1104 TestRootModuleChecker.reset();
1105
1106 final CheckstyleAntTaskLogStub antTask = new CheckstyleAntTaskLogStub();
1107 antTask.setConfig(getPath(CUSTOM_ROOT_CONFIG_FILE));
1108 antTask.setProject(new Project());
1109
1110 final FileSet fileSet = new FileSet();
1111 fileSet.setFile(new File(getPath(FLAWLESS_INPUT)));
1112 antTask.addFileset(fileSet);
1113
1114
1115 antTask.scanFileSets();
1116
1117
1118 final List<MessageLevelPair> loggedMessages = antTask.getLoggedMessages();
1119
1120 assertWithMessage("Log message with correct index was not found")
1121 .that(loggedMessages.stream().filter(
1122 msg -> msg.getMsg().startsWith("0) Adding 1 files from directory")).count())
1123 .isEqualTo(1);
1124 }
1125
1126 private static CheckstyleAntTask.Formatter createPlainFormatter(File outputFile) {
1127 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
1128 formatter.setTofile(outputFile);
1129 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
1130 formatterType.setValue("plain");
1131 formatter.setType(formatterType);
1132 return formatter;
1133 }
1134
1135 }