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 assertWithMessage("Property should be passed to checker with correct value")
450 .that(TestRootModuleChecker.getProperty())
451 .isEqualTo("ignore");
452
453 }
454
455 @Test
456 public final void testExecuteIgnoredModules() throws IOException {
457 final CheckstyleAntTask antTask = getCheckstyleAntTask();
458 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
459 antTask.setFailOnViolation(false);
460 antTask.setExecuteIgnoredModules(true);
461
462 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
463 final File outputFile = new File("target/ant_task_plain_output.txt");
464 formatter.setTofile(outputFile);
465 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
466 formatterType.setValue("plain");
467 formatter.setType(formatterType);
468 formatter.createListener(null);
469
470 antTask.addFormatter(formatter);
471 antTask.execute();
472
473 final ResourceBundle bundle = ResourceBundle.getBundle(
474 Definitions.CHECKSTYLE_BUNDLE, Locale.ROOT);
475 final String auditStartedMessage = bundle.getString(DefaultLogger.AUDIT_STARTED_MESSAGE);
476 final String auditFinishedMessage = bundle.getString(DefaultLogger.AUDIT_FINISHED_MESSAGE);
477 final List<String> output = readWholeFile(outputFile);
478 final String errorMessage = "Content of file with violations differs from expected";
479 assertWithMessage(errorMessage)
480 .that(output.get(0))
481 .isEqualTo(auditStartedMessage);
482 assertWithMessage(errorMessage)
483 .that(output.get(1))
484 .matches("^\\[WARN].*InputCheckstyleAntTaskError.java:4: .*"
485 + "@incomplete=Some javadoc \\[WriteTag]");
486 assertWithMessage(errorMessage)
487 .that(output.get(2))
488 .matches("^\\[ERROR].*InputCheckstyleAntTaskError.java:7: "
489 + "Line is longer than 70 characters \\(found 80\\). \\[LineLength]");
490 assertWithMessage(errorMessage)
491 .that(output.get(3))
492 .matches("^\\[ERROR].*InputCheckstyleAntTaskError.java:9: "
493 + "Line is longer than 70 characters \\(found 81\\). \\[LineLength]");
494 assertWithMessage(errorMessage)
495 .that(output.get(4))
496 .isEqualTo(auditFinishedMessage);
497 }
498
499 @Test
500 public final void testConfigurationByUrl() throws IOException {
501 final CheckstyleAntTask antTask = new CheckstyleAntTask();
502 antTask.setProject(new Project());
503 final URL url = new File(getPath(CONFIG_FILE)).toURI().toURL();
504 antTask.setConfig(url.toString());
505 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
506
507 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
508 final File outputFile = new File("target/ant_task_config_by_url.txt");
509 formatter.setTofile(outputFile);
510 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
511 formatterType.setValue("plain");
512 formatter.setType(formatterType);
513 formatter.createListener(null);
514 antTask.addFormatter(formatter);
515
516 antTask.execute();
517
518 final List<String> output = readWholeFile(outputFile);
519 final int sizeOfOutputWithNoViolations = 2;
520 assertWithMessage("No violations expected")
521 .that(output)
522 .hasSize(sizeOfOutputWithNoViolations);
523 }
524
525 @Test
526 public final void testConfigurationByResource() throws IOException {
527 final CheckstyleAntTask antTask = new CheckstyleAntTask();
528 antTask.setProject(new Project());
529 antTask.setConfig(getPath(CONFIG_FILE));
530 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
531
532 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
533 final File outputFile = new File("target/ant_task_config_by_url.txt");
534 formatter.setTofile(outputFile);
535 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
536 formatterType.setValue("plain");
537 formatter.setType(formatterType);
538 formatter.createListener(null);
539 antTask.addFormatter(formatter);
540
541 antTask.execute();
542
543 final List<String> output = readWholeFile(outputFile);
544 final int sizeOfOutputWithNoViolations = 2;
545 assertWithMessage("No violations expected")
546 .that(output)
547 .hasSize(sizeOfOutputWithNoViolations);
548 }
549
550 @Test
551 public final void testSimultaneousConfiguration() throws IOException {
552 final File file = new File(getPath(CONFIG_FILE));
553 final URL url = file.toURI().toURL();
554
555 final CheckstyleAntTask antTask = new CheckstyleAntTask();
556 antTask.setConfig(url.toString());
557 final BuildException ex = getExpectedThrowable(BuildException.class,
558 () -> antTask.setConfig("Any string value"),
559 "BuildException is expected");
560 final String expected = "Attribute 'config' has already been set";
561 assertWithMessage("Error message is unexpected")
562 .that(ex.getMessage())
563 .isEqualTo(expected);
564 }
565
566 @Test
567 public final void testSetPropertiesFile() throws IOException {
568 TestRootModuleChecker.reset();
569
570 final CheckstyleAntTask antTask = getCheckstyleAntTask(CUSTOM_ROOT_CONFIG_FILE);
571 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
572 antTask.setProperties(new File(getPath(
573 "InputCheckstyleAntTaskCheckstyleAntTest.properties")));
574 antTask.execute();
575
576 assertWithMessage("Property is not set")
577 .that(TestRootModuleChecker.getProperty())
578 .isEqualTo("ignore");
579 }
580
581 @Test
582 public final void testSetPropertiesNonExistentFile() throws IOException {
583 final CheckstyleAntTask antTask = getCheckstyleAntTask();
584 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
585 antTask.setProperties(new File(getPath(NOT_EXISTING_FILE)));
586 final BuildException ex = getExpectedThrowable(BuildException.class,
587 antTask::execute,
588 "BuildException is expected");
589 assertWithMessage("Error message is unexpected")
590 .that(ex.getMessage())
591 .startsWith("Error loading Properties file");
592 }
593
594 @Test
595 public final void testXmlOutput() throws IOException {
596 final CheckstyleAntTask antTask = getCheckstyleAntTask();
597 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
598 antTask.setFailOnViolation(false);
599 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
600 final File outputFile = new File("target/log.xml");
601 formatter.setTofile(outputFile);
602 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
603 formatterType.setValue("xml");
604 formatter.setType(formatterType);
605 antTask.addFormatter(formatter);
606 antTask.execute();
607
608 final List<String> expected = readWholeFile(
609 new File(getPath("ExpectedCheckstyleAntTaskXmlOutput.xml")));
610 final List<String> actual = readWholeFile(outputFile);
611 for (int i = 0; i < expected.size(); i++) {
612 final String line = expected.get(i);
613 if (!line.startsWith("<checkstyle version") && !line.startsWith("<file")) {
614 assertWithMessage("Content of file with violations differs from expected")
615 .that(actual.get(i))
616 .isEqualTo(line);
617 }
618 }
619 }
620
621 @Test
622 public final void testSarifOutput() throws IOException {
623 final CheckstyleAntTask antTask = getCheckstyleAntTask();
624 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
625 antTask.setFailOnViolation(false);
626 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
627 final File outputFile = new File("target/log.sarif");
628 formatter.setTofile(outputFile);
629 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
630 formatterType.setValue("sarif");
631 formatter.setType(formatterType);
632 antTask.addFormatter(formatter);
633 antTask.execute();
634
635 final List<String> expected = readWholeFile(
636 new File(getPath("ExpectedCheckstyleAntTaskSarifOutput.sarif")));
637 final List<String> actual = readWholeFile(outputFile);
638 for (int lineNumber = 0; lineNumber < expected.size(); lineNumber++) {
639 final String line = expected.get(lineNumber);
640 final StandardSubjectBuilder assertWithMessage =
641 assertWithMessage("Content of file with violations differs from expected");
642 if (line.trim().startsWith("\"uri\"")) {
643 final String expectedPathEnd = Iterables.get(
644 Splitter.on("**").split(line), 1);
645
646 final String actualLine = actual.get(lineNumber).replaceAll("\\\\", "/");
647 assertWithMessage
648 .that(actualLine)
649 .endsWith(expectedPathEnd);
650 }
651 else {
652 assertWithMessage
653 .that(actual.get(lineNumber))
654 .isEqualTo(line);
655 }
656 }
657 }
658
659 @Test
660 public final void testCreateListenerException() throws IOException {
661 final CheckstyleAntTask antTask = getCheckstyleAntTask();
662 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
663 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
664 final File outputFile = new File("target/");
665 formatter.setTofile(outputFile);
666 antTask.addFormatter(formatter);
667 final BuildException ex = getExpectedThrowable(BuildException.class,
668 antTask::execute,
669 "BuildException is expected");
670 assertWithMessage("Error message is unexpected")
671 .that(ex.getMessage())
672 .isEqualTo("Unable to create listeners: formatters "
673 + "{" + List.of(formatter) + "}.");
674 }
675
676 @Test
677 public final void testCreateListenerExceptionWithXmlLogger() throws IOException {
678 final CheckstyleAntTask antTask = getCheckstyleAntTask();
679 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
680 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
681 final File outputFile = new File("target/");
682 formatter.setTofile(outputFile);
683 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
684 formatterType.setValue("xml");
685 formatter.setType(formatterType);
686 antTask.addFormatter(formatter);
687 final BuildException ex = getExpectedThrowable(BuildException.class,
688 antTask::execute,
689 "BuildException is expected");
690 assertWithMessage("Error message is unexpected")
691 .that(ex.getMessage())
692 .startsWith("Unable to create listeners: formatters");
693 }
694
695 @Test
696 public final void testCreateListenerExceptionWithSarifLogger() throws IOException {
697 final CheckstyleAntTask antTask = getCheckstyleAntTask();
698 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
699 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
700 final File outputFile = new File("target/");
701 formatter.setTofile(outputFile);
702 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
703 formatterType.setValue("sarif");
704 formatter.setType(formatterType);
705 antTask.addFormatter(formatter);
706 final BuildException ex = getExpectedThrowable(BuildException.class,
707 antTask::execute,
708 "BuildException is expected");
709 assertWithMessage("Error message is unexpected")
710 .that(ex.getMessage())
711 .startsWith("Unable to create listeners: formatters");
712 }
713
714 @Test
715 public void testSetInvalidType() {
716 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
717 final BuildException ex = getExpectedThrowable(BuildException.class,
718 () -> formatterType.setValue("foo"),
719 "BuildException is expected");
720 assertWithMessage("Error message is unexpected")
721 .that(ex.getMessage())
722 .isEqualTo("foo is not a legal value for this attribute");
723 }
724
725 @Test
726 public void testSetFileValueByFile() throws IOException {
727 final String filename = getPath("InputCheckstyleAntTaskCheckstyleAntTest.properties");
728 final CheckstyleAntTask.Property property = new CheckstyleAntTask.Property();
729 property.setFile(new File(filename));
730 assertWithMessage("File path is unexpected")
731 .that(new File(filename).getAbsolutePath())
732 .isEqualTo(property.getValue());
733 }
734
735 @Test
736 public void testDefaultLoggerListener() throws IOException {
737 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
738 formatter.setUseFile(false);
739 assertWithMessage("Listener instance has unexpected type")
740 .that(formatter.createListener(null))
741 .isInstanceOf(DefaultLogger.class);
742 }
743
744 @Test
745 public void testDefaultLoggerListenerWithToFile() throws IOException {
746 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
747 formatter.setUseFile(false);
748 formatter.setTofile(new File("target/"));
749 assertWithMessage("Listener instance has unexpected type")
750 .that(formatter.createListener(null))
751 .isInstanceOf(DefaultLogger.class);
752 }
753
754 @Test
755 public void testXmlLoggerListener() throws IOException {
756 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
757 formatterType.setValue("xml");
758 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
759 formatter.setType(formatterType);
760 formatter.setUseFile(false);
761 assertWithMessage("Listener instance has unexpected type")
762 .that(formatter.createListener(null))
763 .isInstanceOf(XMLLogger.class);
764 }
765
766 @Test
767 public void testXmlLoggerListenerWithToFile() throws IOException {
768 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
769 formatterType.setValue("xml");
770 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
771 formatter.setType(formatterType);
772 formatter.setUseFile(false);
773 formatter.setTofile(new File("target/"));
774 assertWithMessage("Listener instance has unexpected type")
775 .that(formatter.createListener(null))
776 .isInstanceOf(XMLLogger.class);
777 }
778
779 @Test
780 public void testDefaultLoggerWithNullToFile() throws IOException {
781 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
782 formatter.setTofile(null);
783 assertWithMessage("Listener instance has unexpected type")
784 .that(formatter.createListener(null))
785 .isInstanceOf(DefaultLogger.class);
786 }
787
788 @Test
789 public void testXmlLoggerWithNullToFile() throws IOException {
790 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
791 formatterType.setValue("xml");
792 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
793 formatter.setType(formatterType);
794 formatter.setTofile(null);
795 assertWithMessage("Listener instance has unexpected type")
796 .that(formatter.createListener(null))
797 .isInstanceOf(XMLLogger.class);
798 }
799
800 @Test
801 public void testSarifLoggerListener() throws IOException {
802 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
803 formatterType.setValue("sarif");
804 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
805 formatter.setType(formatterType);
806 formatter.setUseFile(false);
807 assertWithMessage("Listener instance has unexpected type")
808 .that(formatter.createListener(null))
809 .isInstanceOf(SarifLogger.class);
810 }
811
812 @Test
813 public void testSarifLoggerListenerWithToFile() throws IOException {
814 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
815 formatterType.setValue("sarif");
816 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
817 formatter.setType(formatterType);
818 formatter.setUseFile(false);
819 formatter.setTofile(new File("target/"));
820 assertWithMessage("Listener instance has unexpected type")
821 .that(formatter.createListener(null))
822 .isInstanceOf(SarifLogger.class);
823 }
824
825 @Test
826 public void testSarifLoggerWithNullToFile() throws IOException {
827 final CheckstyleAntTask.FormatterType formatterType = new CheckstyleAntTask.FormatterType();
828 formatterType.setValue("sarif");
829 final CheckstyleAntTask.Formatter formatter = new CheckstyleAntTask.Formatter();
830 formatter.setType(formatterType);
831 formatter.setTofile(null);
832 assertWithMessage("Listener instance has unexpected type")
833 .that(formatter.createListener(null))
834 .isInstanceOf(SarifLogger.class);
835 }
836
837
838
839
840 @Test
841 public void testCreateClasspath() {
842 final CheckstyleAntTask antTask = new CheckstyleAntTask();
843 final Project mockProject = new Project();
844 antTask.setProject(mockProject);
845
846 assertWithMessage("Classpath should belong to the expected project")
847 .that(antTask.createClasspath().getProject())
848 .isEqualTo(mockProject);
849
850 assertWithMessage("Invalid classpath")
851 .that(antTask.createClasspath().toString())
852 .isEmpty();
853 }
854
855 @Test
856 public void testDestroyed() throws IOException {
857 TestRootModuleChecker.reset();
858
859 final CheckstyleAntTask antTask = getCheckstyleAntTask(CUSTOM_ROOT_CONFIG_FILE);
860 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
861 antTask.setMaxWarnings(0);
862 antTask.execute();
863
864 assertWithMessage("Checker is not destroyed")
865 .that(TestRootModuleChecker.isDestroyed())
866 .isTrue();
867 }
868
869 @Test
870 public void testMaxWarnings() throws IOException {
871 TestRootModuleChecker.reset();
872
873 final CheckstyleAntTask antTask = getCheckstyleAntTask(CUSTOM_ROOT_CONFIG_FILE);
874 antTask.setFile(new File(getPath(VIOLATED_INPUT)));
875 antTask.setMaxWarnings(0);
876 antTask.execute();
877
878 assertWithMessage("Checker is not processed")
879 .that(TestRootModuleChecker.isProcessed())
880 .isTrue();
881 }
882
883 @Test
884 public final void testExecuteLogOutput() throws Exception {
885 final URL url = new File(getPath(CONFIG_FILE)).toURI().toURL();
886 final ResourceBundle bundle = ResourceBundle.getBundle(
887 Definitions.CHECKSTYLE_BUNDLE, Locale.ROOT);
888 final String auditStartedMessage = bundle.getString(DefaultLogger.AUDIT_STARTED_MESSAGE);
889 final String auditFinishedMessage = bundle.getString(DefaultLogger.AUDIT_FINISHED_MESSAGE);
890
891 final List<MessageLevelPair> expectedList = Arrays.asList(
892 new MessageLevelPair("checkstyle version .*", Project.MSG_VERBOSE),
893 new MessageLevelPair("Adding standalone file for audit", Project.MSG_VERBOSE),
894 new MessageLevelPair("To locate the files took \\d+ ms.", Project.MSG_VERBOSE),
895 new MessageLevelPair("Running Checkstyle on 1 files", Project.MSG_INFO),
896 new MessageLevelPair("Using configuration file:.*", Project.MSG_VERBOSE),
897 new MessageLevelPair(auditStartedMessage, Project.MSG_DEBUG),
898 new MessageLevelPair(auditFinishedMessage, Project.MSG_DEBUG),
899 new MessageLevelPair("To process the files took \\d+ ms.", Project.MSG_VERBOSE),
900 new MessageLevelPair("Total execution took \\d+ ms.", Project.MSG_VERBOSE)
901 );
902
903 final CheckstyleAntTaskLogStub antTask = new CheckstyleAntTaskLogStub();
904 antTask.setProject(new Project());
905 antTask.setConfig(url.toString());
906 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
907
908 antTask.execute();
909
910 final List<MessageLevelPair> loggedMessages = antTask.getLoggedMessages();
911
912 assertWithMessage("Amount of log messages is unexpected")
913 .that(loggedMessages)
914 .hasSize(expectedList.size());
915
916 for (int i = 0; i < expectedList.size(); i++) {
917 final MessageLevelPair expected = expectedList.get(i);
918 final MessageLevelPair actual = loggedMessages.get(i);
919 assertWithMessage("Log messages should match")
920 .that(actual.getMsg())
921 .matches(expected.getMsg());
922 assertWithMessage("Log levels should be equal")
923 .that(actual.getLevel())
924 .isEqualTo(expected.getLevel());
925 }
926 }
927
928 @Test
929 public void testCheckerException() throws IOException {
930 final CheckstyleAntTask antTask = new CheckstyleAntTaskStub();
931 antTask.setConfig(getPath(CONFIG_FILE));
932 antTask.setProject(new Project());
933 antTask.setFile(new File(""));
934 final BuildException ex = getExpectedThrowable(BuildException.class,
935 antTask::execute,
936 "BuildException is expected");
937 assertWithMessage("Error message is unexpected")
938 .that(ex)
939 .hasMessageThat()
940 .startsWith("Unable to process files:");
941 }
942
943 @Test
944 public void testLoggedTime() throws IOException {
945 final CheckstyleAntTaskLogStub antTask = new CheckstyleAntTaskLogStub();
946 antTask.setConfig(getPath(CONFIG_FILE));
947 antTask.setProject(new Project());
948 antTask.setFile(new File(getPath(FLAWLESS_INPUT)));
949 final long startTime = System.currentTimeMillis();
950 antTask.execute();
951 final long endTime = System.currentTimeMillis();
952 final long testingTime = endTime - startTime;
953 final List<MessageLevelPair> loggedMessages = antTask.getLoggedMessages();
954
955 assertLoggedTime(loggedMessages, testingTime, "Total execution");
956 assertLoggedTime(loggedMessages, testingTime, "To locate the files");
957 assertLoggedTime(loggedMessages, testingTime, "To process the files");
958 }
959
960 private static void assertLoggedTime(List<MessageLevelPair> loggedMessages,
961 long testingTime, String expectedMsg) {
962
963 final Optional<MessageLevelPair> optionalMessageLevelPair = loggedMessages.stream()
964 .filter(msg -> msg.getMsg().startsWith(expectedMsg))
965 .findFirst();
966
967 assertWithMessage("Message should be present.")
968 .that(optionalMessageLevelPair.isPresent())
969 .isTrue();
970
971 final long actualTime = getNumberFromLine(optionalMessageLevelPair.orElseThrow().getMsg());
972
973 assertWithMessage("Logged time in '" + expectedMsg + "' "
974 + "must be less than the testing time")
975 .that(actualTime)
976 .isAtMost(testingTime);
977 }
978
979 private static List<String> readWholeFile(File outputFile) throws IOException {
980 return Files.readAllLines(outputFile.toPath(), StandardCharsets.UTF_8);
981 }
982
983 private static long getNumberFromLine(String line) {
984 final Matcher matcher = Pattern.compile("(\\d+)").matcher(line);
985 matcher.find();
986 return Long.parseLong(matcher.group(1));
987 }
988
989 @Test
990 public void testMaxWarningDefault() throws IOException {
991 final CheckstyleAntTask antTask = getCheckstyleAntTask();
992 final File inputFile = new File(getPath(WARNING_INPUT));
993 final Location fileLocation = new Location("build.xml", 42, 10);
994
995 antTask.setFile(inputFile);
996 antTask.setLocation(fileLocation);
997 assertDoesNotThrow(antTask::execute, "BuildException is not expected");
998 }
999
1000 }