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