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