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