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