View Javadoc
1   ///////////////////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code and other text files for adherence to a set of rules.
3   // Copyright (C) 2001-2025 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;
21  
22  import static com.google.common.truth.Truth.assertWithMessage;
23  import static com.puppycrawl.tools.checkstyle.Checker.EXCEPTION_MSG;
24  import static com.puppycrawl.tools.checkstyle.DefaultLogger.AUDIT_FINISHED_MESSAGE;
25  import static com.puppycrawl.tools.checkstyle.DefaultLogger.AUDIT_STARTED_MESSAGE;
26  import static com.puppycrawl.tools.checkstyle.checks.NewlineAtEndOfFileCheck.MSG_KEY_NO_NEWLINE_EOF;
27  import static com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck.MSG_KEY;
28  
29  import java.io.BufferedReader;
30  import java.io.ByteArrayInputStream;
31  import java.io.ByteArrayOutputStream;
32  import java.io.File;
33  import java.io.IOError;
34  import java.io.IOException;
35  import java.io.InputStream;
36  import java.io.InputStreamReader;
37  import java.io.LineNumberReader;
38  import java.io.OutputStream;
39  import java.io.UnsupportedEncodingException;
40  import java.lang.reflect.Field;
41  import java.lang.reflect.Method;
42  import java.nio.charset.StandardCharsets;
43  import java.nio.file.Files;
44  import java.util.ArrayList;
45  import java.util.Arrays;
46  import java.util.Collections;
47  import java.util.HashSet;
48  import java.util.List;
49  import java.util.Locale;
50  import java.util.Objects;
51  import java.util.Properties;
52  import java.util.Set;
53  import java.util.SortedSet;
54  import java.util.TreeSet;
55  import java.util.UUID;
56  import java.util.stream.Collectors;
57  
58  import org.junit.jupiter.api.Test;
59  import org.junit.jupiter.api.io.TempDir;
60  
61  import com.puppycrawl.tools.checkstyle.AbstractAutomaticBean.OutputStreamOptions;
62  import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
63  import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck;
64  import com.puppycrawl.tools.checkstyle.api.AuditEvent;
65  import com.puppycrawl.tools.checkstyle.api.AuditListener;
66  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
67  import com.puppycrawl.tools.checkstyle.api.Configuration;
68  import com.puppycrawl.tools.checkstyle.api.Context;
69  import com.puppycrawl.tools.checkstyle.api.DetailAST;
70  import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder;
71  import com.puppycrawl.tools.checkstyle.api.FileText;
72  import com.puppycrawl.tools.checkstyle.api.Filter;
73  import com.puppycrawl.tools.checkstyle.api.FilterSet;
74  import com.puppycrawl.tools.checkstyle.api.MessageDispatcher;
75  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
76  import com.puppycrawl.tools.checkstyle.api.Violation;
77  import com.puppycrawl.tools.checkstyle.checks.NewlineAtEndOfFileCheck;
78  import com.puppycrawl.tools.checkstyle.checks.TranslationCheck;
79  import com.puppycrawl.tools.checkstyle.checks.coding.HiddenFieldCheck;
80  import com.puppycrawl.tools.checkstyle.checks.sizes.LineLengthCheck;
81  import com.puppycrawl.tools.checkstyle.filefilters.BeforeExecutionExclusionFileFilter;
82  import com.puppycrawl.tools.checkstyle.filters.SuppressionFilter;
83  import com.puppycrawl.tools.checkstyle.internal.testmodules.CheckWhichThrowsError;
84  import com.puppycrawl.tools.checkstyle.internal.testmodules.DebugAuditAdapter;
85  import com.puppycrawl.tools.checkstyle.internal.testmodules.DebugFilter;
86  import com.puppycrawl.tools.checkstyle.internal.testmodules.TestBeforeExecutionFileFilter;
87  import com.puppycrawl.tools.checkstyle.internal.testmodules.TestFileSetCheck;
88  import com.puppycrawl.tools.checkstyle.internal.utils.CloseAndFlushTestByteArrayOutputStream;
89  import com.puppycrawl.tools.checkstyle.internal.utils.TestUtil;
90  import com.puppycrawl.tools.checkstyle.utils.CommonUtil;
91  import de.thetaphi.forbiddenapis.SuppressForbidden;
92  
93  /**
94   * CheckerTest.
95   *
96   * @noinspection ClassWithTooManyDependencies
97   * @noinspectionreason ClassWithTooManyDependencies - complex tests require a large number
98   *      of imports
99   */
100 public class CheckerTest extends AbstractModuleTestSupport {
101 
102     @TempDir
103     public File temporaryFolder;
104 
105     private File createTempFile(String prefix) throws IOException {
106         return createTempFile(prefix, ".tmp");
107     }
108 
109     private File createTempFile(String prefix, String suffix) throws IOException {
110         final String name = Objects.requireNonNull(prefix)
111                 + UUID.randomUUID()
112                 + Objects.requireNonNull(suffix);
113         return Files.createFile(temporaryFolder.toPath().resolve(name)).toFile();
114     }
115 
116     private static Method getFireAuditFinished() throws NoSuchMethodException {
117         final Class<Checker> checkerClass = Checker.class;
118         final Method fireAuditFinished = checkerClass.getDeclaredMethod("fireAuditFinished");
119         fireAuditFinished.setAccessible(true);
120         return fireAuditFinished;
121     }
122 
123     private static Method getFireAuditStartedMethod() throws NoSuchMethodException {
124         final Class<Checker> checkerClass = Checker.class;
125         final Method fireAuditStarted = checkerClass.getDeclaredMethod("fireAuditStarted");
126         fireAuditStarted.setAccessible(true);
127         return fireAuditStarted;
128     }
129 
130     @Override
131     protected String getPackageLocation() {
132         return "com/puppycrawl/tools/checkstyle/checker";
133     }
134 
135     @Test
136     public void testDestroy() throws Exception {
137         final Checker checker = new Checker();
138         final DebugAuditAdapter auditAdapter = new DebugAuditAdapter();
139         checker.addListener(auditAdapter);
140         final TestFileSetCheck fileSet = new TestFileSetCheck();
141         checker.addFileSetCheck(fileSet);
142         final DebugFilter filter = new DebugFilter();
143         checker.addFilter(filter);
144         final TestBeforeExecutionFileFilter fileFilter = new TestBeforeExecutionFileFilter();
145         checker.addBeforeExecutionFileFilter(fileFilter);
146 
147         // should remove all listeners, file sets, and filters
148         checker.destroy();
149 
150         final File tempFile = createTempFile("junit");
151         checker.process(Collections.singletonList(tempFile));
152         final SortedSet<Violation> violations = new TreeSet<>();
153         violations.add(new Violation(1, 0, "a Bundle", "message.key",
154                 new Object[] {"arg"}, null, getClass(), null));
155         checker.fireErrors("Some File Name", violations);
156 
157         assertWithMessage("Checker.destroy() doesn't remove listeners.")
158                 .that(auditAdapter.wasCalled())
159                 .isFalse();
160         assertWithMessage("Checker.destroy() doesn't remove file sets.")
161                 .that(fileSet.wasCalled())
162                 .isFalse();
163         assertWithMessage("Checker.destroy() doesn't remove filters.")
164                 .that(filter.wasCalled())
165                 .isFalse();
166         assertWithMessage("Checker.destroy() doesn't remove file filters.")
167                 .that(fileFilter.wasCalled())
168                 .isFalse();
169     }
170 
171     @Test
172     public void testAddListener() throws Exception {
173         final Checker checker = new Checker();
174         final DebugAuditAdapter auditAdapter = new DebugAuditAdapter();
175         checker.addListener(auditAdapter);
176 
177         // Let's try fire some events
178         getFireAuditStartedMethod().invoke(checker);
179         assertWithMessage("Checker.fireAuditStarted() doesn't call listener")
180                 .that(auditAdapter.wasCalled())
181                 .isTrue();
182         assertWithMessage("Checker.fireAuditStarted() doesn't pass event")
183                 .that(auditAdapter.wasEventPassed())
184                 .isTrue();
185 
186         auditAdapter.resetListener();
187         getFireAuditFinished().invoke(checker);
188         assertWithMessage("Checker.fireAuditFinished() doesn't call listener")
189                 .that(auditAdapter.wasCalled())
190                 .isTrue();
191         assertWithMessage("Checker.fireAuditFinished() doesn't pass event")
192                 .that(auditAdapter.wasEventPassed())
193                 .isTrue();
194 
195         auditAdapter.resetListener();
196         checker.fireFileStarted("Some File Name");
197         assertWithMessage("Checker.fireFileStarted() doesn't call listener")
198                 .that(auditAdapter.wasCalled())
199                 .isTrue();
200         assertWithMessage("Checker.fireFileStarted() doesn't pass event")
201                 .that(auditAdapter.wasEventPassed())
202                 .isTrue();
203 
204         auditAdapter.resetListener();
205         checker.fireFileFinished("Some File Name");
206         assertWithMessage("Checker.fireFileFinished() doesn't call listener")
207                 .that(auditAdapter.wasCalled())
208                 .isTrue();
209         assertWithMessage("Checker.fireFileFinished() doesn't pass event")
210                 .that(auditAdapter.wasEventPassed())
211                 .isTrue();
212 
213         auditAdapter.resetListener();
214         final SortedSet<Violation> violations = new TreeSet<>();
215         violations.add(new Violation(1, 0, "a Bundle", "message.key",
216                 new Object[] {"arg"}, null, getClass(), null));
217         checker.fireErrors("Some File Name", violations);
218         assertWithMessage("Checker.fireErrors() doesn't call listener")
219                 .that(auditAdapter.wasCalled())
220                 .isTrue();
221         assertWithMessage("Checker.fireErrors() doesn't pass event")
222                 .that(auditAdapter.wasEventPassed())
223                 .isTrue();
224     }
225 
226     @Test
227     public void testRemoveListener() throws Exception {
228         final Checker checker = new Checker();
229         final DebugAuditAdapter auditAdapter = new DebugAuditAdapter();
230         final DebugAuditAdapter aa2 = new DebugAuditAdapter();
231         checker.addListener(auditAdapter);
232         checker.addListener(aa2);
233         checker.removeListener(auditAdapter);
234 
235         // Let's try fire some events
236         getFireAuditStartedMethod().invoke(checker);
237         assertWithMessage("Checker.fireAuditStarted() doesn't call listener")
238                 .that(aa2.wasCalled())
239                 .isTrue();
240         assertWithMessage("Checker.fireAuditStarted() does call removed listener")
241                 .that(auditAdapter.wasCalled())
242                 .isFalse();
243 
244         aa2.resetListener();
245         getFireAuditFinished().invoke(checker);
246         assertWithMessage("Checker.fireAuditFinished() doesn't call listener")
247                 .that(aa2.wasCalled())
248                 .isTrue();
249         assertWithMessage("Checker.fireAuditFinished() does call removed listener")
250                 .that(auditAdapter.wasCalled())
251                 .isFalse();
252 
253         aa2.resetListener();
254         checker.fireFileStarted("Some File Name");
255         assertWithMessage("Checker.fireFileStarted() doesn't call listener")
256                 .that(aa2.wasCalled())
257                 .isTrue();
258         assertWithMessage("Checker.fireFileStarted() does call removed listener")
259                 .that(auditAdapter.wasCalled())
260                 .isFalse();
261 
262         aa2.resetListener();
263         checker.fireFileFinished("Some File Name");
264         assertWithMessage("Checker.fireFileFinished() doesn't call listener")
265                 .that(aa2.wasCalled())
266                 .isTrue();
267         assertWithMessage("Checker.fireFileFinished() does call removed listener")
268                 .that(auditAdapter.wasCalled())
269                 .isFalse();
270 
271         aa2.resetListener();
272         final SortedSet<Violation> violations = new TreeSet<>();
273         violations.add(new Violation(1, 0, "a Bundle", "message.key",
274                 new Object[] {"arg"}, null, getClass(), null));
275         checker.fireErrors("Some File Name", violations);
276         assertWithMessage("Checker.fireErrors() doesn't call listener")
277                 .that(aa2.wasCalled())
278                 .isTrue();
279         assertWithMessage("Checker.fireErrors() does call removed listener")
280                 .that(auditAdapter.wasCalled())
281                 .isFalse();
282     }
283 
284     @Test
285     public void testAddBeforeExecutionFileFilter() throws Exception {
286         final Checker checker = new Checker();
287         final TestBeforeExecutionFileFilter filter = new TestBeforeExecutionFileFilter();
288 
289         checker.addBeforeExecutionFileFilter(filter);
290 
291         filter.resetFilter();
292         checker.process(Collections.singletonList(new File("dummy.java")));
293         assertWithMessage("Checker.acceptFileStarted() doesn't call filter")
294                 .that(filter.wasCalled())
295                 .isTrue();
296     }
297 
298     @Test
299     public void testRemoveBeforeExecutionFileFilter() throws Exception {
300         final Checker checker = new Checker();
301         final TestBeforeExecutionFileFilter filter = new TestBeforeExecutionFileFilter();
302         final TestBeforeExecutionFileFilter f2 = new TestBeforeExecutionFileFilter();
303         checker.addBeforeExecutionFileFilter(filter);
304         checker.addBeforeExecutionFileFilter(f2);
305         checker.removeBeforeExecutionFileFilter(filter);
306 
307         f2.resetFilter();
308         checker.process(Collections.singletonList(new File("dummy.java")));
309         assertWithMessage("Checker.acceptFileStarted() doesn't call filter")
310                 .that(f2.wasCalled())
311                 .isTrue();
312         assertWithMessage("Checker.acceptFileStarted() does call removed filter")
313                 .that(filter.wasCalled())
314                 .isFalse();
315     }
316 
317     @Test
318     public void testAddFilter() {
319         final Checker checker = new Checker();
320         final DebugFilter filter = new DebugFilter();
321 
322         checker.addFilter(filter);
323 
324         filter.resetFilter();
325         final SortedSet<Violation> violations = new TreeSet<>();
326         violations.add(new Violation(1, 0, "a Bundle", "message.key",
327                 new Object[] {"arg"}, null, getClass(), null));
328         checker.fireErrors("Some File Name", violations);
329         assertWithMessage("Checker.fireErrors() doesn't call filter")
330                 .that(filter.wasCalled())
331                 .isTrue();
332     }
333 
334     @Test
335     public void testRemoveFilter() {
336         final Checker checker = new Checker();
337         final DebugFilter filter = new DebugFilter();
338         final DebugFilter f2 = new DebugFilter();
339         checker.addFilter(filter);
340         checker.addFilter(f2);
341         checker.removeFilter(filter);
342 
343         f2.resetFilter();
344         final SortedSet<Violation> violations = new TreeSet<>();
345         violations.add(new Violation(1, 0, "a Bundle", "message.key",
346                 new Object[] {"arg"}, null, getClass(), null));
347         checker.fireErrors("Some File Name", violations);
348         assertWithMessage("Checker.fireErrors() doesn't call filter")
349                 .that(f2.wasCalled())
350                 .isTrue();
351         assertWithMessage("Checker.fireErrors() does call removed filter")
352                 .that(filter.wasCalled())
353                 .isFalse();
354     }
355 
356     @Test
357     public void testFileExtensions() throws Exception {
358         final DefaultConfiguration checkerConfig = new DefaultConfiguration("configuration");
359         checkerConfig.addProperty("charset", StandardCharsets.UTF_8.name());
360         checkerConfig.addProperty("cacheFile", createTempFile("junit").getPath());
361 
362         final Checker checker = new Checker();
363         checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
364         checker.configure(checkerConfig);
365 
366         final DebugAuditAdapter auditAdapter = new DebugAuditAdapter();
367         checker.addListener(auditAdapter);
368 
369         final List<File> files = new ArrayList<>();
370         final File file = new File("file.pdf");
371         files.add(file);
372         final File otherFile = new File("file.java");
373         files.add(otherFile);
374         final String[] fileExtensions = {"java", "xml", "properties"};
375         checker.setFileExtensions(fileExtensions);
376         checker.setCacheFile(createTempFile("junit").getPath());
377         final int counter = checker.process(files);
378 
379         // comparing to 1 as there is only one legal file in input
380         final int numLegalFiles = 1;
381         final PropertyCacheFile cache = TestUtil.getInternalState(checker, "cacheFile");
382         assertWithMessage("There were more legal files than expected")
383             .that(counter)
384             .isEqualTo(numLegalFiles);
385         assertWithMessage("Audit was started on larger amount of files than expected")
386             .that(auditAdapter.getNumFilesStarted())
387             .isEqualTo(numLegalFiles);
388         assertWithMessage("Audit was finished on larger amount of files than expected")
389             .that(auditAdapter.getNumFilesFinished())
390             .isEqualTo(numLegalFiles);
391         assertWithMessage("Cache shout not contain any file")
392             .that(cache.get(new File("file.java").getCanonicalPath()))
393             .isNull();
394     }
395 
396     @Test
397     public void testIgnoredFileExtensions() throws Exception {
398         final DefaultConfiguration checkerConfig = new DefaultConfiguration("configuration");
399         checkerConfig.addProperty("charset", StandardCharsets.UTF_8.name());
400         final File tempFile = createTempFile("junit");
401         checkerConfig.addProperty("cacheFile", tempFile.getPath());
402 
403         final Checker checker = new Checker();
404         checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
405         checker.configure(checkerConfig);
406 
407         final DebugAuditAdapter auditAdapter = new DebugAuditAdapter();
408         checker.addListener(auditAdapter);
409 
410         final List<File> allIgnoredFiles = new ArrayList<>();
411         final File ignoredFile = new File("file.pdf");
412         allIgnoredFiles.add(ignoredFile);
413         final String[] fileExtensions = {"java", "xml", "properties"};
414         checker.setFileExtensions(fileExtensions);
415         checker.setCacheFile(createTempFile("junit").getPath());
416         final int counter = checker.process(allIgnoredFiles);
417 
418         // comparing to 0 as there is no legal file in input
419         final int numLegalFiles = 0;
420         assertWithMessage("There were more legal files than expected")
421             .that(counter)
422             .isEqualTo(numLegalFiles);
423         assertWithMessage("Audit was started on larger amount of files than expected")
424             .that(auditAdapter.getNumFilesStarted())
425             .isEqualTo(numLegalFiles);
426         assertWithMessage("Audit was finished on larger amount of files than expected")
427             .that(auditAdapter.getNumFilesFinished())
428             .isEqualTo(numLegalFiles);
429     }
430 
431     @Test
432     public void testSetters() {
433         // all  that is set by reflection, so just make code coverage be happy
434         final Checker checker = new Checker();
435         checker.setBasedir("some");
436         checker.setSeverity("ignore");
437 
438         final PackageObjectFactory factory = new PackageObjectFactory(
439             new HashSet<>(), Thread.currentThread().getContextClassLoader());
440         checker.setModuleFactory(factory);
441 
442         checker.setFileExtensions((String[]) null);
443         checker.setFileExtensions(".java", "xml");
444 
445         try {
446             checker.setCharset("UNKNOWN-CHARSET");
447             assertWithMessage("Exception is expected").fail();
448         }
449         catch (UnsupportedEncodingException ex) {
450             assertWithMessage("Error message is not expected")
451                 .that(ex.getMessage())
452                 .isEqualTo("unsupported charset: 'UNKNOWN-CHARSET'");
453         }
454     }
455 
456     @Test
457     public void testSetSeverity() throws Exception {
458         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
459 
460         verifyWithInlineXmlConfig(getPath("InputCheckerTestSeverity.java"), expected);
461     }
462 
463     @Test
464     public void testNoClassLoaderNoModuleFactory() {
465         final Checker checker = new Checker();
466 
467         try {
468             checker.finishLocalSetup();
469             assertWithMessage("Exception is expected").fail();
470         }
471         catch (CheckstyleException ex) {
472             assertWithMessage("Error message is not expected")
473                 .that(ex.getMessage())
474                 .isEqualTo("if no custom moduleFactory is set,"
475                     + " moduleClassLoader must be specified");
476         }
477     }
478 
479     @Test
480     public void testNoModuleFactory() throws Exception {
481         final Checker checker = new Checker();
482         final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
483 
484         checker.setModuleClassLoader(classLoader);
485         checker.finishLocalSetup();
486         final Context actualCtx = TestUtil.getInternalState(checker, "childContext");
487 
488         assertWithMessage("Default module factory should be created when it is not specified")
489             .that(actualCtx.get("moduleFactory"))
490             .isNotNull();
491     }
492 
493     @Test
494     public void testFinishLocalSetupFullyInitialized() throws Exception {
495         final Checker checker = new Checker();
496         final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
497         checker.setModuleClassLoader(contextClassLoader);
498         final PackageObjectFactory factory = new PackageObjectFactory(
499             new HashSet<>(), contextClassLoader);
500         checker.setModuleFactory(factory);
501         checker.setBasedir("testBaseDir");
502         checker.setLocaleLanguage("it");
503         checker.setLocaleCountry("IT");
504         checker.finishLocalSetup();
505 
506         final Context context = TestUtil.getInternalState(checker, "childContext");
507         final String encoding = StandardCharsets.UTF_8.name();
508         assertWithMessage("Charset was different than expected")
509             .that(context.get("charset"))
510             .isEqualTo(encoding);
511         assertWithMessage("Severity is set to unexpected value")
512             .that(context.get("severity"))
513             .isEqualTo("error");
514         assertWithMessage("Basedir is set to unexpected value")
515             .that(context.get("basedir"))
516             .isEqualTo("testBaseDir");
517 
518         final Field sLocale = LocalizedMessage.class.getDeclaredField("sLocale");
519         sLocale.setAccessible(true);
520         final Locale locale = (Locale) sLocale.get(null);
521         assertWithMessage("Locale is set to unexpected value")
522             .that(locale)
523             .isEqualTo(Locale.ITALY);
524     }
525 
526     @Test
527     public void testSetupChildExceptions() {
528         final Checker checker = new Checker();
529         final PackageObjectFactory factory = new PackageObjectFactory(
530             new HashSet<>(), Thread.currentThread().getContextClassLoader());
531         checker.setModuleFactory(factory);
532 
533         final Configuration config = new DefaultConfiguration("java.lang.String");
534         try {
535             checker.setupChild(config);
536             assertWithMessage("Exception is expected").fail();
537         }
538         catch (CheckstyleException ex) {
539             assertWithMessage("Error message is not expected")
540                 .that(ex.getMessage())
541                 .isEqualTo("java.lang.String is not allowed as a child in Checker");
542         }
543     }
544 
545     @Test
546     public void testSetupChildInvalidProperty() throws Exception {
547         final DefaultConfiguration checkConfig = createModuleConfig(HiddenFieldCheck.class);
548         checkConfig.addProperty("$$No such property", null);
549         try {
550             createChecker(checkConfig);
551             assertWithMessage("Exception is expected").fail();
552         }
553         catch (CheckstyleException ex) {
554             assertWithMessage("Error message is not expected")
555                 .that(ex.getMessage())
556                 .isEqualTo("cannot initialize module com.puppycrawl.tools.checkstyle.TreeWalker"
557                         + " - cannot initialize module " + checkConfig.getName()
558                         + " - Property '$$No such property'"
559                         + " does not exist, please check the documentation");
560         }
561     }
562 
563     @Test
564     public void testSetupChildListener() throws Exception {
565         final Checker checker = new Checker();
566         final PackageObjectFactory factory = new PackageObjectFactory(
567             new HashSet<>(), Thread.currentThread().getContextClassLoader());
568         checker.setModuleFactory(factory);
569 
570         final Configuration config = new DefaultConfiguration(
571             DebugAuditAdapter.class.getCanonicalName());
572         checker.setupChild(config);
573 
574         final List<AuditListener> listeners = TestUtil.getInternalState(checker, "listeners");
575         assertWithMessage("Invalid child listener class")
576                 .that(listeners.get(listeners.size() - 1) instanceof DebugAuditAdapter)
577                 .isTrue();
578     }
579 
580     @Test
581     public void testDestroyCheckerWithWrongCacheFileNameLength() throws Exception {
582         final Checker checker = new Checker();
583         final PackageObjectFactory factory = new PackageObjectFactory(
584             new HashSet<>(), Thread.currentThread().getContextClassLoader());
585         checker.setModuleFactory(factory);
586         checker.configure(new DefaultConfiguration("default config"));
587         // We set wrong file name length in order to reproduce IOException on OS Linux, OS Windows.
588         // The maximum file name length which is allowed in most UNIX, Windows file systems is 255.
589         // See https://en.wikipedia.org/wiki/Filename;
590         checker.setCacheFile(String.format(Locale.ENGLISH, "%0300d", 0));
591         try {
592             checker.destroy();
593             assertWithMessage("Exception did not happen").fail();
594         }
595         catch (IllegalStateException ex) {
596             assertWithMessage("Cause of exception differs from IOException")
597                     .that(ex.getCause())
598                     .isInstanceOf(IOException.class);
599         }
600     }
601 
602     /**
603      * It is OK to have long test method name here as it describes the test purpose.
604      */
605     @Test
606     public void testCacheAndCheckWhichDoesNotImplementExternalResourceHolderInterface()
607             throws Exception {
608         assertWithMessage("ExternalResourceHolder has changed his parent")
609                 .that(ExternalResourceHolder.class.isAssignableFrom(HiddenFieldCheck.class))
610                 .isFalse();
611         final DefaultConfiguration checkConfig = createModuleConfig(HiddenFieldCheck.class);
612 
613         final DefaultConfiguration treeWalkerConfig = createModuleConfig(TreeWalker.class);
614         treeWalkerConfig.addChild(checkConfig);
615 
616         final DefaultConfiguration checkerConfig = createRootConfig(treeWalkerConfig);
617         checkerConfig.addProperty("charset", StandardCharsets.UTF_8.name());
618 
619         final File cacheFile = createTempFile("junit");
620         checkerConfig.addProperty("cacheFile", cacheFile.getPath());
621 
622         final File tmpFile = createTempFile("file", ".java");
623 
624         execute(checkerConfig, tmpFile.getPath());
625         final Properties cacheAfterFirstRun = new Properties();
626         try (BufferedReader reader = Files.newBufferedReader(cacheFile.toPath())) {
627             cacheAfterFirstRun.load(reader);
628         }
629 
630         // one more time to reuse cache
631         execute(checkerConfig, tmpFile.getPath());
632         final Properties cacheAfterSecondRun = new Properties();
633         try (BufferedReader reader = Files.newBufferedReader(cacheFile.toPath())) {
634             cacheAfterSecondRun.load(reader);
635         }
636 
637         assertWithMessage("Cache from first run differs from second run cache")
638             .that(cacheAfterSecondRun)
639             .isEqualTo(cacheAfterFirstRun);
640     }
641 
642     @Test
643     public void testWithCacheWithNoViolation() throws Exception {
644         final Checker checker = new Checker();
645         final PackageObjectFactory factory = new PackageObjectFactory(
646             new HashSet<>(), Thread.currentThread().getContextClassLoader());
647         checker.setModuleFactory(factory);
648         checker.configure(createModuleConfig(TranslationCheck.class));
649 
650         final File cacheFile = createTempFile("junit");
651         checker.setCacheFile(cacheFile.getPath());
652 
653         checker.setupChild(createModuleConfig(TranslationCheck.class));
654         final File tmpFile = createTempFile("file", ".java");
655         final List<File> files = new ArrayList<>(1);
656         files.add(tmpFile);
657         checker.process(files);
658 
659         // invoke destroy to persist cache
660         checker.destroy();
661 
662         final Properties cache = new Properties();
663         try (BufferedReader reader = Files.newBufferedReader(cacheFile.toPath())) {
664             cache.load(reader);
665         }
666 
667         // There should 2 objects in cache: processed file (file.java) and checker configuration.
668         final int expectedNumberOfObjectsInCache = 2;
669         assertWithMessage("Cache has unexpected size")
670             .that(cache)
671             .hasSize(expectedNumberOfObjectsInCache);
672 
673         final String expectedConfigHash = "D581D4A2BD482D4E1EF1F82459356BA2D8A3B" + "FC3";
674         assertWithMessage("Cache has unexpected hash")
675             .that(cache.getProperty(PropertyCacheFile.CONFIG_HASH_KEY))
676             .isEqualTo(expectedConfigHash);
677 
678         assertWithMessage("Cache file has null path")
679             .that(cache.getProperty(tmpFile.getPath()))
680             .isNotNull();
681     }
682 
683     @Test
684     public void testClearExistingCache() throws Exception {
685         final DefaultConfiguration checkerConfig = createRootConfig(null);
686         checkerConfig.addProperty("charset", StandardCharsets.UTF_8.name());
687         final File cacheFile = createTempFile("junit");
688         checkerConfig.addProperty("cacheFile", cacheFile.getPath());
689 
690         final Checker checker = new Checker();
691         checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
692         checker.configure(checkerConfig);
693         checker.addListener(getBriefUtLogger());
694 
695         checker.clearCache();
696         // invoke destroy to persist cache
697         checker.destroy();
698 
699         final Properties cacheAfterClear = new Properties();
700         try (BufferedReader reader = Files.newBufferedReader(cacheFile.toPath())) {
701             cacheAfterClear.load(reader);
702         }
703 
704         assertWithMessage("Cache has unexpected size")
705             .that(cacheAfterClear)
706             .hasSize(1);
707         assertWithMessage("Cache has null hash")
708             .that(cacheAfterClear.getProperty(PropertyCacheFile.CONFIG_HASH_KEY))
709             .isNotNull();
710 
711         final String pathToEmptyFile = createTempFile("file", ".java").getPath();
712 
713         // file that should be audited is not in cache
714         execute(checkerConfig, pathToEmptyFile);
715         final Properties cacheAfterSecondRun = new Properties();
716         try (BufferedReader reader = Files.newBufferedReader(cacheFile.toPath())) {
717             cacheAfterSecondRun.load(reader);
718         }
719 
720         assertWithMessage("Cache has null path")
721             .that(cacheAfterSecondRun.getProperty(pathToEmptyFile))
722             .isNotNull();
723         final String cacheHash = cacheAfterSecondRun.getProperty(PropertyCacheFile.CONFIG_HASH_KEY);
724         assertWithMessage("Cash have changed it hash")
725             .that(cacheHash)
726             .isEqualTo(cacheAfterClear.getProperty(PropertyCacheFile.CONFIG_HASH_KEY));
727         final int expectedNumberOfObjectsInCacheAfterSecondRun = 2;
728         assertWithMessage("Cache has changed number of items")
729             .that(cacheAfterSecondRun)
730             .hasSize(expectedNumberOfObjectsInCacheAfterSecondRun);
731     }
732 
733     @Test
734     public void testClearCache() throws Exception {
735         final DefaultConfiguration violationCheck =
736                 createModuleConfig(DummyFileSetViolationCheck.class);
737         final DefaultConfiguration checkerConfig = new DefaultConfiguration("myConfig");
738         checkerConfig.addProperty("charset", "UTF-8");
739         final File cacheFile = createTempFile("junit");
740         checkerConfig.addProperty("cacheFile", cacheFile.getPath());
741         checkerConfig.addChild(violationCheck);
742         final Checker checker = new Checker();
743         checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
744         checker.configure(checkerConfig);
745         checker.addListener(getBriefUtLogger());
746 
747         checker.process(Collections.singletonList(new File("dummy.java")));
748         checker.clearCache();
749         // invoke destroy to persist cache
750         final PropertyCacheFile cache = TestUtil.getInternalState(checker, "cacheFile");
751         cache.persist();
752 
753         final Properties cacheAfterClear = new Properties();
754         try (BufferedReader reader = Files.newBufferedReader(cacheFile.toPath())) {
755             cacheAfterClear.load(reader);
756         }
757 
758         assertWithMessage("Cache has unexpected size")
759             .that(cacheAfterClear)
760             .hasSize(1);
761     }
762 
763     @Test
764     public void setFileExtension() {
765         final Checker checker = new Checker();
766         checker.setFileExtensions(".test1", "test2");
767         final String[] actual = TestUtil.getInternalState(checker, "fileExtensions");
768         assertWithMessage("Extensions are not expected")
769             .that(actual)
770             .isEqualTo(new String[] {".test1", ".test2"});
771     }
772 
773     @Test
774     public void testClearCacheWhenCacheFileIsNotSet() {
775         // The idea of the test is to check that when cache file is not set,
776         // the invocation of clearCache method does not throw an exception.
777         final Checker checker = new Checker();
778         checker.clearCache();
779         final PropertyCacheFile cache = TestUtil.getInternalState(checker, "cacheFile");
780         assertWithMessage("If cache file is not set the cache should default to null")
781             .that(cache)
782             .isNull();
783     }
784 
785     /**
786      * Test doesn't need to be serialized.
787      *
788      * @noinspection SerializableInnerClassWithNonSerializableOuterClass
789      * @noinspectionreason SerializableInnerClassWithNonSerializableOuterClass - mocked file
790      *      for test does not require serialization
791      */
792     @Test
793     public void testCatchErrorInProcessFilesMethod() throws Exception {
794         // Assume that I/O error is happened when we try to invoke 'lastModified()' method.
795         final String errorMessage = "Java Virtual Machine is broken"
796             + " or has run out of resources necessary for it to continue operating.";
797         final Error expectedError = new IOError(new InternalError(errorMessage));
798 
799         final File mock = new File("testFile") {
800             private static final long serialVersionUID = 1L;
801 
802             /**
803              * Test is checking catch clause when exception is thrown.
804              *
805              * @noinspection ProhibitedExceptionThrown
806              * @noinspectionreason ProhibitedExceptionThrown - we require mocked file to
807              *      throw exception as part of test
808              */
809             @Override
810             public long lastModified() {
811                 throw expectedError;
812             }
813         };
814 
815         final Checker checker = new Checker();
816         final List<File> filesToProcess = new ArrayList<>();
817         filesToProcess.add(mock);
818         try {
819             checker.process(filesToProcess);
820             assertWithMessage("IOError is expected!").fail();
821         }
822         // -@cs[IllegalCatchExtended] Testing for catch Error is part of 100% coverage.
823         catch (Error error) {
824             assertWithMessage("Error cause differs from IOError")
825                     .that(error.getCause())
826                     .isInstanceOf(IOError.class);
827             assertWithMessage("Error cause is not InternalError")
828                     .that(error.getCause().getCause())
829                     .isInstanceOf(InternalError.class);
830             assertWithMessage("Error message is not expected")
831                     .that(error)
832                     .hasCauseThat()
833                     .hasCauseThat()
834                     .hasMessageThat()
835                     .isEqualTo(errorMessage);
836         }
837     }
838 
839     /**
840      * Test doesn't need to be serialized.
841      *
842      * @noinspection SerializableInnerClassWithNonSerializableOuterClass
843      * @noinspectionreason SerializableInnerClassWithNonSerializableOuterClass - mocked file
844      *      for test does not require serialization
845      */
846     @Test
847     public void testCatchErrorWithNoFileName() throws Exception {
848         // Assume that I/O error is happened when we try to invoke 'lastModified()' method.
849         final String errorMessage = "Java Virtual Machine is broken"
850             + " or has run out of resources necessary for it to continue operating.";
851         final Error expectedError = new IOError(new InternalError(errorMessage));
852 
853         final File mock = new File("testFile") {
854             private static final long serialVersionUID = 1L;
855 
856             /**
857              * Test is checking catch clause when exception is thrown.
858              *
859              * @noinspection ProhibitedExceptionThrown
860              * @noinspectionreason ProhibitedExceptionThrown - we require mocked file to
861              *      throw exception as part of test
862              */
863             @Override
864             public long lastModified() {
865                 throw expectedError;
866             }
867 
868             @Override
869             public String getAbsolutePath() {
870                 return null;
871             }
872         };
873 
874         final Checker checker = new Checker();
875         final List<File> filesToProcess = new ArrayList<>();
876         filesToProcess.add(mock);
877         try {
878             checker.process(filesToProcess);
879             assertWithMessage("IOError is expected!").fail();
880         }
881         // -@cs[IllegalCatchExtended] Testing for catch Error is part of 100% coverage.
882         catch (Error error) {
883             assertWithMessage("Error cause differs from IOError")
884                     .that(error)
885                     .hasCauseThat()
886                     .isInstanceOf(IOError.class);
887             assertWithMessage("Error cause is not InternalError")
888                     .that(error)
889                     .hasCauseThat()
890                     .hasCauseThat()
891                     .isInstanceOf(InternalError.class);
892             assertWithMessage("Error message is not expected")
893                     .that(error)
894                     .hasCauseThat()
895                     .hasCauseThat()
896                     .hasMessageThat()
897                     .isEqualTo(errorMessage);
898         }
899     }
900 
901     /**
902      * It is OK to have long test method name here as it describes the test purpose.
903      */
904     @Test
905     public void testCacheAndFilterWhichDoesNotImplementExternalResourceHolderInterface()
906             throws Exception {
907         assertWithMessage("ExternalResourceHolder has changed its parent")
908                 .that(ExternalResourceHolder.class.isAssignableFrom(DummyFilter.class))
909                 .isFalse();
910         final DefaultConfiguration filterConfig = createModuleConfig(DummyFilter.class);
911 
912         final DefaultConfiguration checkerConfig = createRootConfig(filterConfig);
913         final File cacheFile = createTempFile("junit");
914         checkerConfig.addProperty("cacheFile", cacheFile.getPath());
915 
916         final String pathToEmptyFile = createTempFile("file", ".java").getPath();
917 
918         execute(checkerConfig, pathToEmptyFile);
919         final Properties cacheAfterFirstRun = new Properties();
920         try (BufferedReader reader = Files.newBufferedReader(cacheFile.toPath())) {
921             cacheAfterFirstRun.load(reader);
922         }
923 
924         // One more time to use cache.
925         execute(checkerConfig, pathToEmptyFile);
926         final Properties cacheAfterSecondRun = new Properties();
927         try (BufferedReader reader = Files.newBufferedReader(cacheFile.toPath())) {
928             cacheAfterSecondRun.load(reader);
929         }
930 
931         final String cacheFilePath = cacheAfterSecondRun.getProperty(pathToEmptyFile);
932         assertWithMessage("Cache file has changed its path")
933             .that(cacheFilePath)
934             .isEqualTo(cacheAfterFirstRun.getProperty(pathToEmptyFile));
935         final String cacheHash = cacheAfterSecondRun.getProperty(PropertyCacheFile.CONFIG_HASH_KEY);
936         assertWithMessage("Cache has changed its hash")
937             .that(cacheHash)
938             .isEqualTo(cacheAfterFirstRun.getProperty(PropertyCacheFile.CONFIG_HASH_KEY));
939         final int expectedNumberOfObjectsInCache = 2;
940         assertWithMessage("Number of items in cache differs from expected")
941             .that(cacheAfterFirstRun)
942             .hasSize(expectedNumberOfObjectsInCache);
943         assertWithMessage("Number of items in cache differs from expected")
944             .that(cacheAfterSecondRun)
945             .hasSize(expectedNumberOfObjectsInCache);
946     }
947 
948     /**
949      * It is OK to have long test method name here as it describes the test purpose.
950      */
951     // -@cs[ExecutableStatementCount] This test needs to verify many things.
952     @Test
953     public void testCacheAndCheckWhichAddsNewResourceLocationButKeepsSameCheckerInstance()
954             throws Exception {
955         // Use case (https://github.com/checkstyle/checkstyle/pull/3092#issuecomment-218162436):
956         // Imagine that cache exists in a file. New version of Checkstyle appear.
957         // New release contains update to a some check to have additional external resource.
958         // User update his configuration and run validation as usually.
959         // Cache should not be reused.
960 
961         final DynamicalResourceHolderCheck check = new DynamicalResourceHolderCheck();
962         final String firstExternalResourceLocation = getPath("InputCheckerImportControlOne.xml");
963         final String firstExternalResourceKey = PropertyCacheFile.EXTERNAL_RESOURCE_KEY_PREFIX
964                 + firstExternalResourceLocation;
965         check.setFirstExternalResourceLocation(firstExternalResourceLocation);
966 
967         final DefaultConfiguration checkerConfig = createRootConfig(null);
968         final File cacheFile = createTempFile("junit");
969         checkerConfig.addProperty("cacheFile", cacheFile.getPath());
970 
971         final Checker checker = new Checker();
972         checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
973         checker.addFileSetCheck(check);
974         checker.addFilter(new DummyFilterSet());
975         checker.configure(checkerConfig);
976         checker.addListener(getBriefUtLogger());
977 
978         final String pathToEmptyFile = createTempFile("file", ".java").getPath();
979 
980         execute(checker, pathToEmptyFile);
981         final Properties cacheAfterFirstRun = new Properties();
982         try (BufferedReader reader = Files.newBufferedReader(cacheFile.toPath())) {
983             cacheAfterFirstRun.load(reader);
984         }
985 
986         final int expectedNumberOfObjectsInCacheAfterFirstRun = 4;
987         assertWithMessage("Number of items in cache differs from expected")
988             .that(cacheAfterFirstRun)
989             .hasSize(expectedNumberOfObjectsInCacheAfterFirstRun);
990 
991         // Change a list of external resources which are used by the check
992         final String secondExternalResourceLocation = "InputCheckerImportControlTwo.xml";
993         final String secondExternalResourceKey = PropertyCacheFile.EXTERNAL_RESOURCE_KEY_PREFIX
994                 + secondExternalResourceLocation;
995         check.setSecondExternalResourceLocation(secondExternalResourceLocation);
996 
997         checker.addFileSetCheck(check);
998         checker.configure(checkerConfig);
999 
1000         execute(checker, pathToEmptyFile);
1001         final Properties cacheAfterSecondRun = new Properties();
1002         try (BufferedReader reader = Files.newBufferedReader(cacheFile.toPath())) {
1003             cacheAfterSecondRun.load(reader);
1004         }
1005 
1006         final String cacheFilePath = cacheAfterSecondRun.getProperty(pathToEmptyFile);
1007         assertWithMessage("Cache file has changed its path")
1008             .that(cacheFilePath)
1009             .isEqualTo(cacheAfterFirstRun.getProperty(pathToEmptyFile));
1010         final String cacheHash = cacheAfterSecondRun.getProperty(PropertyCacheFile.CONFIG_HASH_KEY);
1011         assertWithMessage("Cache has changed its hash")
1012             .that(cacheHash)
1013             .isEqualTo(cacheAfterFirstRun.getProperty(PropertyCacheFile.CONFIG_HASH_KEY));
1014         final String resourceKey = cacheAfterSecondRun.getProperty(firstExternalResourceKey);
1015         assertWithMessage("Cache has changed its resource key")
1016             .that(resourceKey)
1017             .isEqualTo(cacheAfterFirstRun.getProperty(firstExternalResourceKey));
1018         assertWithMessage("Cache has null as a resource key")
1019             .that(cacheAfterFirstRun.getProperty(firstExternalResourceKey))
1020             .isNotNull();
1021         final int expectedNumberOfObjectsInCacheAfterSecondRun = 4;
1022         assertWithMessage("Number of items in cache differs from expected")
1023             .that(cacheAfterSecondRun)
1024             .hasSize(expectedNumberOfObjectsInCacheAfterSecondRun);
1025         assertWithMessage("Cache has not null as a resource key")
1026             .that(cacheAfterFirstRun.getProperty(secondExternalResourceKey))
1027             .isNull();
1028         assertWithMessage("Cache has null as a resource key")
1029             .that(cacheAfterSecondRun.getProperty(secondExternalResourceKey))
1030             .isNotNull();
1031     }
1032 
1033     @Test
1034     public void testClearLazyLoadCacheInDetailAST() throws Exception {
1035 
1036         final String filePath = getPath("InputCheckerClearDetailAstLazyLoadCache.java");
1037 
1038         final String[] expected = CommonUtil.EMPTY_STRING_ARRAY;
1039         verifyWithInlineConfigParser(filePath, expected);
1040     }
1041 
1042     @Test
1043     public void testCacheOnViolationSuppression() throws Exception {
1044         final File cacheFile = createTempFile("junit");
1045         final DefaultConfiguration violationCheck =
1046                 createModuleConfig(DummyFileSetViolationCheck.class);
1047 
1048         final DefaultConfiguration filterConfig = createModuleConfig(SuppressionFilter.class);
1049         filterConfig.addProperty("file", getPath("InputCheckerSuppressAll.xml"));
1050 
1051         final DefaultConfiguration checkerConfig = createRootConfig(violationCheck);
1052         checkerConfig.addProperty("cacheFile", cacheFile.getPath());
1053         checkerConfig.addChild(filterConfig);
1054 
1055         final String fileViolationPath = createTempFile("ViolationFile", ".java").getPath();
1056 
1057         execute(checkerConfig, fileViolationPath);
1058 
1059         try (InputStream input = Files.newInputStream(cacheFile.toPath())) {
1060             final Properties details = new Properties();
1061             details.load(input);
1062 
1063             assertWithMessage("suppressed violation file saved in cache")
1064                 .that(details.getProperty(fileViolationPath))
1065                 .isNotNull();
1066         }
1067     }
1068 
1069     @Test
1070     public void testHaltOnException() throws Exception {
1071         final DefaultConfiguration checkConfig =
1072             createModuleConfig(CheckWhichThrowsError.class);
1073         final String filePath = getPath("InputChecker.java");
1074         try {
1075             execute(checkConfig, filePath);
1076             assertWithMessage("Exception is expected").fail();
1077         }
1078         catch (CheckstyleException ex) {
1079             assertWithMessage("Error message is not expected")
1080                 .that(ex.getMessage())
1081                 .isEqualTo("Exception was thrown while processing " + filePath);
1082         }
1083     }
1084 
1085     @Test
1086     public void testExceptionWithCache() throws Exception {
1087         final File cacheFile = createTempFile("junit");
1088 
1089         final DefaultConfiguration checkConfig =
1090                 createModuleConfig(CheckWhichThrowsError.class);
1091 
1092         final DefaultConfiguration treewalkerConfig =
1093                 createModuleConfig(TreeWalker.class);
1094         treewalkerConfig.addChild(checkConfig);
1095 
1096         final DefaultConfiguration checkerConfig = createRootConfig(treewalkerConfig);
1097         checkerConfig.addProperty("charset", StandardCharsets.UTF_8.name());
1098         checkerConfig.addProperty("cacheFile", cacheFile.getPath());
1099         checkerConfig.addChild(treewalkerConfig);
1100 
1101         final Checker checker = createChecker(checkerConfig);
1102 
1103         final String filePath = getPath("InputChecker.java");
1104         try {
1105             checker.process(Collections.singletonList(new File(filePath)));
1106             assertWithMessage("Exception is expected").fail();
1107         }
1108         catch (CheckstyleException ex) {
1109             assertWithMessage("Error message is not expected")
1110                 .that(ex.getMessage())
1111                 .isEqualTo("Exception was thrown while processing " + filePath);
1112 
1113             // destroy is called by Main
1114             checker.destroy();
1115 
1116             final Properties cache = new Properties();
1117             try (BufferedReader reader = Files.newBufferedReader(cacheFile.toPath())) {
1118                 cache.load(reader);
1119             }
1120 
1121             assertWithMessage("Cache has unexpected size")
1122                 .that(cache)
1123                 .hasSize(1);
1124             assertWithMessage("testFile is not in cache")
1125                 .that(cache.getProperty(filePath))
1126                 .isNull();
1127         }
1128     }
1129 
1130     /**
1131      * Test doesn't need to be serialized.
1132      *
1133      * @noinspection SerializableInnerClassWithNonSerializableOuterClass
1134      * @noinspectionreason SerializableInnerClassWithNonSerializableOuterClass - mocked file
1135      *      for test does not require serialization
1136      */
1137     @Test
1138     public void testCatchErrorWithCache() throws Exception {
1139         final File cacheFile = createTempFile("junit");
1140 
1141         final DefaultConfiguration checkerConfig = new DefaultConfiguration("configuration");
1142         checkerConfig.addProperty("charset", StandardCharsets.UTF_8.name());
1143         checkerConfig.addProperty("cacheFile", cacheFile.getPath());
1144 
1145         final String errorMessage = "Java Virtual Machine is broken"
1146             + " or has run out of resources necessary for it to continue operating.";
1147         final Error expectedError = new IOError(new InternalError(errorMessage));
1148 
1149         final File mock = new File("testFile") {
1150             private static final long serialVersionUID = 1L;
1151 
1152             @Override
1153             public String getAbsolutePath() {
1154                 return "testFile";
1155             }
1156 
1157             /**
1158              * Test is checking catch clause when exception is thrown.
1159              *
1160              * @noinspection ProhibitedExceptionThrown
1161              * @noinspectionreason ProhibitedExceptionThrown - we require mocked file to
1162              *      throw exception as part of test
1163              */
1164             @Override
1165             public File getAbsoluteFile() {
1166                 throw expectedError;
1167             }
1168         };
1169 
1170         final Checker checker = new Checker();
1171         checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
1172         checker.configure(checkerConfig);
1173         final List<File> filesToProcess = new ArrayList<>();
1174         filesToProcess.add(mock);
1175         try {
1176             checker.process(filesToProcess);
1177             assertWithMessage("IOError is expected!").fail();
1178         }
1179         // -@cs[IllegalCatchExtended] Testing for catch Error is part of 100% coverage.
1180         catch (Error error) {
1181             assertWithMessage("Error cause differs from IOError")
1182                     .that(error.getCause())
1183                     .isInstanceOf(IOError.class);
1184             assertWithMessage("Error message is not expected")
1185                     .that(error)
1186                     .hasCauseThat()
1187                     .hasCauseThat()
1188                     .hasMessageThat()
1189                     .isEqualTo(errorMessage);
1190 
1191             // destroy is called by Main
1192             checker.destroy();
1193 
1194             final Properties cache = new Properties();
1195             try (BufferedReader reader = Files.newBufferedReader(cacheFile.toPath())) {
1196                 cache.load(reader);
1197             }
1198 
1199             assertWithMessage("Cache has unexpected size")
1200                     .that(cache)
1201                     .hasSize(1);
1202             assertWithMessage("testFile is not in cache")
1203                 .that(cache.getProperty("testFile"))
1204                 .isNull();
1205         }
1206     }
1207 
1208     /**
1209      * Test doesn't need to be serialized.
1210      *
1211      * @noinspection SerializableInnerClassWithNonSerializableOuterClass
1212      * @noinspectionreason SerializableInnerClassWithNonSerializableOuterClass - mocked file
1213      *      for test does not require serialization
1214      */
1215     @Test
1216     public void testCatchErrorWithCacheWithNoFileName() throws Exception {
1217         final File cacheFile = createTempFile("junit");
1218 
1219         final DefaultConfiguration checkerConfig = new DefaultConfiguration("configuration");
1220         checkerConfig.addProperty("charset", StandardCharsets.UTF_8.name());
1221         checkerConfig.addProperty("cacheFile", cacheFile.getPath());
1222 
1223         final String errorMessage = "Java Virtual Machine is broken"
1224             + " or has run out of resources necessary for it to continue operating.";
1225         final Error expectedError = new IOError(new InternalError(errorMessage));
1226 
1227         final File mock = new File("testFile") {
1228             private static final long serialVersionUID = 1L;
1229 
1230             /**
1231              * Test is checking catch clause when exception is thrown.
1232              *
1233              * @noinspection ProhibitedExceptionThrown
1234              * @noinspectionreason ProhibitedExceptionThrown - we require mocked file to
1235              *      throw exception as part of test
1236              */
1237             @Override
1238             public String getAbsolutePath() {
1239                 throw expectedError;
1240             }
1241         };
1242 
1243         final Checker checker = new Checker();
1244         checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
1245         checker.configure(checkerConfig);
1246         final List<File> filesToProcess = new ArrayList<>();
1247         filesToProcess.add(mock);
1248         try {
1249             checker.process(filesToProcess);
1250             assertWithMessage("IOError is expected!").fail();
1251         }
1252         // -@cs[IllegalCatchExtended] Testing for catch Error is part of 100% coverage.
1253         catch (Error error) {
1254             assertWithMessage("Error cause differs from IOError")
1255                     .that(error)
1256                     .hasCauseThat()
1257                     .isInstanceOf(IOError.class);
1258             assertWithMessage("Error message is not expected")
1259                     .that(error)
1260                     .hasCauseThat()
1261                     .hasCauseThat()
1262                     .hasMessageThat()
1263                     .isEqualTo(errorMessage);
1264 
1265             // destroy is called by Main
1266             checker.destroy();
1267 
1268             final Properties cache = new Properties();
1269             try (BufferedReader reader = Files.newBufferedReader(cacheFile.toPath())) {
1270                 cache.load(reader);
1271             }
1272 
1273             assertWithMessage("Cache has unexpected size")
1274                     .that(cache)
1275                     .hasSize(1);
1276         }
1277     }
1278 
1279     /**
1280      * Test doesn't need to be serialized.
1281      *
1282      * @noinspection SerializableInnerClassWithNonSerializableOuterClass
1283      * @noinspectionreason SerializableInnerClassWithNonSerializableOuterClass - mocked file
1284      *      for test does not require serialization
1285      */
1286     @Test
1287     public void testExceptionWithNoFileName() {
1288         final String errorMessage = "Security Exception";
1289         final RuntimeException expectedError = new SecurityException(errorMessage);
1290 
1291         final File mock = new File("testFile") {
1292             private static final long serialVersionUID = 1L;
1293 
1294             /**
1295              * Test is checking catch clause when exception is thrown.
1296              *
1297              * @noinspection ProhibitedExceptionThrown
1298              * @noinspectionreason ProhibitedExceptionThrown - we require mocked file to
1299              *      throw exception as part of test
1300              */
1301             @Override
1302             public String getAbsolutePath() {
1303                 throw expectedError;
1304             }
1305         };
1306 
1307         final Checker checker = new Checker();
1308         final List<File> filesToProcess = new ArrayList<>();
1309         filesToProcess.add(mock);
1310         try {
1311             checker.process(filesToProcess);
1312             assertWithMessage("SecurityException is expected!").fail();
1313         }
1314         catch (CheckstyleException ex) {
1315             assertWithMessage("Error cause differs from SecurityException")
1316                     .that(ex)
1317                     .hasCauseThat()
1318                     .isInstanceOf(SecurityException.class);
1319             assertWithMessage("Error message is not expected")
1320                     .that(ex)
1321                     .hasCauseThat()
1322                     .hasMessageThat()
1323                     .isEqualTo(errorMessage);
1324         }
1325     }
1326 
1327     /**
1328      * Test doesn't need to be serialized.
1329      *
1330      * @noinspection SerializableInnerClassWithNonSerializableOuterClass
1331      * @noinspectionreason SerializableInnerClassWithNonSerializableOuterClass - mocked file
1332      *      for test does not require serialization
1333      */
1334     @Test
1335     public void testExceptionWithCacheAndNoFileName() throws Exception {
1336         final File cacheFile = createTempFile("junit");
1337 
1338         final DefaultConfiguration checkerConfig = new DefaultConfiguration("configuration");
1339         checkerConfig.addProperty("charset", StandardCharsets.UTF_8.name());
1340         checkerConfig.addProperty("cacheFile", cacheFile.getPath());
1341 
1342         final String errorMessage = "Security Exception";
1343         final RuntimeException expectedError = new SecurityException(errorMessage);
1344 
1345         final File mock = new File("testFile") {
1346             private static final long serialVersionUID = 1L;
1347 
1348             /**
1349              * Test is checking catch clause when exception is thrown.
1350              *
1351              * @noinspection ProhibitedExceptionThrown
1352              * @noinspectionreason ProhibitedExceptionThrown - we require mocked file to
1353              *      throw exception as part of test
1354              */
1355             @Override
1356             public String getAbsolutePath() {
1357                 throw expectedError;
1358             }
1359         };
1360 
1361         final Checker checker = new Checker();
1362         checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
1363         checker.configure(checkerConfig);
1364         final List<File> filesToProcess = new ArrayList<>();
1365         filesToProcess.add(mock);
1366         try {
1367             checker.process(filesToProcess);
1368             assertWithMessage("SecurityException is expected!").fail();
1369         }
1370         catch (CheckstyleException ex) {
1371             assertWithMessage("Error cause differs from SecurityException")
1372                     .that(ex)
1373                     .hasCauseThat()
1374                     .isInstanceOf(SecurityException.class);
1375             assertWithMessage("Error message is not expected")
1376                     .that(ex)
1377                     .hasCauseThat()
1378                     .hasMessageThat()
1379                     .isEqualTo(errorMessage);
1380 
1381             // destroy is called by Main
1382             checker.destroy();
1383 
1384             final Properties cache = new Properties();
1385             try (BufferedReader reader = Files.newBufferedReader(cacheFile.toPath())) {
1386                 cache.load(reader);
1387             }
1388 
1389             assertWithMessage("Cache has unexpected size")
1390                     .that(cache)
1391                     .hasSize(1);
1392         }
1393     }
1394 
1395     @Test
1396     public void testHaltOnExceptionOff() throws Exception {
1397         final String filePath = getPath("InputChecker.java");
1398         final String[] expected = {
1399             "1: " + getCheckMessage(EXCEPTION_MSG, "java.lang.IndexOutOfBoundsException: test"),
1400         };
1401 
1402         verifyWithInlineXmlConfig(filePath, expected);
1403     }
1404 
1405     @Test
1406     public void testTabViolationDefault() throws Exception {
1407         final String[] expected = {
1408             "17:17: violation",
1409             "21:49: violation",
1410         };
1411         verifyWithInlineConfigParser(getPath("InputCheckerTabCharacter.java"),
1412             expected);
1413     }
1414 
1415     @Test
1416     public void testTabViolationCustomWidth() throws Exception {
1417         final String[] expected = {
1418             "18:17: violation",
1419             "22:37: violation",
1420         };
1421 
1422         verifyWithInlineXmlConfig(getPath("InputCheckerTabCharacterCustomWidth.java"), expected);
1423     }
1424 
1425     @Test
1426     public void testCheckerProcessCallAllNeededMethodsOfFileSets() throws Exception {
1427         final DummyFileSet fileSet = new DummyFileSet();
1428         final Checker checker = new Checker();
1429         checker.addFileSetCheck(fileSet);
1430         checker.process(Collections.singletonList(new File("dummy.java")));
1431         final List<String> expected =
1432             Arrays.asList("beginProcessing", "finishProcessing", "destroy");
1433         assertWithMessage("Method calls were not expected")
1434             .that(fileSet.getMethodCalls())
1435             .isEqualTo(expected);
1436     }
1437 
1438     @Test
1439     public void testSetFileSetCheckSetsMessageDispatcher() {
1440         final DummyFileSet fileSet = new DummyFileSet();
1441         final Checker checker = new Checker();
1442         checker.addFileSetCheck(fileSet);
1443         assertWithMessage("Message dispatcher was not expected")
1444             .that(fileSet.getInternalMessageDispatcher())
1445             .isEqualTo(checker);
1446     }
1447 
1448     @Test
1449     public void testAddAuditListenerAsChild() throws Exception {
1450         final Checker checker = new Checker();
1451         final DebugAuditAdapter auditAdapter = new DebugAuditAdapter();
1452         final PackageObjectFactory factory = new PackageObjectFactory(
1453                 new HashSet<>(), Thread.currentThread().getContextClassLoader()) {
1454             @Override
1455             public Object createModule(String name) throws CheckstyleException {
1456                 Object adapter = auditAdapter;
1457                 if (!name.equals(DebugAuditAdapter.class.getName())) {
1458                     adapter = super.createModule(name);
1459                 }
1460                 return adapter;
1461             }
1462         };
1463         checker.setModuleFactory(factory);
1464         checker.setupChild(createModuleConfig(DebugAuditAdapter.class));
1465         // Let's try fire some events
1466         checker.process(Collections.singletonList(new File("dummy.java")));
1467         assertWithMessage("Checker.fireAuditStarted() doesn't call listener")
1468                 .that(auditAdapter.wasCalled())
1469                 .isTrue();
1470     }
1471 
1472     @Test
1473     public void testAddBeforeExecutionFileFilterAsChild() throws Exception {
1474         final Checker checker = new Checker();
1475         final TestBeforeExecutionFileFilter fileFilter = new TestBeforeExecutionFileFilter();
1476         final PackageObjectFactory factory = new PackageObjectFactory(
1477                 new HashSet<>(), Thread.currentThread().getContextClassLoader()) {
1478             @Override
1479             public Object createModule(String name) throws CheckstyleException {
1480                 Object filter = fileFilter;
1481                 if (!name.equals(TestBeforeExecutionFileFilter.class.getName())) {
1482                     filter = super.createModule(name);
1483                 }
1484                 return filter;
1485             }
1486         };
1487         checker.setModuleFactory(factory);
1488         checker.setupChild(createModuleConfig(TestBeforeExecutionFileFilter.class));
1489         checker.process(Collections.singletonList(new File("dummy.java")));
1490         assertWithMessage("Checker.acceptFileStarted() doesn't call listener")
1491                 .that(fileFilter.wasCalled())
1492                 .isTrue();
1493     }
1494 
1495     @Test
1496     public void testFileSetCheckInitWhenAddedAsChild() throws Exception {
1497         final Checker checker = new Checker();
1498         final DummyFileSet fileSet = new DummyFileSet();
1499         final PackageObjectFactory factory = new PackageObjectFactory(
1500                 new HashSet<>(), Thread.currentThread().getContextClassLoader()) {
1501             @Override
1502             public Object createModule(String name) throws CheckstyleException {
1503                 Object check = fileSet;
1504                 if (!name.equals(DummyFileSet.class.getName())) {
1505                     check = super.createModule(name);
1506                 }
1507                 return check;
1508             }
1509         };
1510         checker.setModuleFactory(factory);
1511         checker.finishLocalSetup();
1512         checker.setupChild(createModuleConfig(DummyFileSet.class));
1513         assertWithMessage("FileSetCheck.init() wasn't called")
1514                 .that(fileSet.isInitCalled())
1515                 .isTrue();
1516     }
1517 
1518     // -@cs[CheckstyleTestMakeup] must use raw class to directly initialize DefaultLogger
1519     @Test
1520     public void testDefaultLoggerClosesItStreams() throws Exception {
1521         final Checker checker = new Checker();
1522         try (CloseAndFlushTestByteArrayOutputStream testInfoOutputStream =
1523                 new CloseAndFlushTestByteArrayOutputStream();
1524             CloseAndFlushTestByteArrayOutputStream testErrorOutputStream =
1525                 new CloseAndFlushTestByteArrayOutputStream()) {
1526             checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
1527             checker.addListener(new DefaultLogger(testInfoOutputStream,
1528                 OutputStreamOptions.CLOSE, testErrorOutputStream, OutputStreamOptions.CLOSE));
1529 
1530             final File tmpFile = createTempFile("file", ".java");
1531 
1532             execute(checker, tmpFile.getPath());
1533 
1534             assertWithMessage("Output stream close count")
1535                     .that(testInfoOutputStream.getCloseCount())
1536                     .isEqualTo(1);
1537             assertWithMessage("Output stream flush count")
1538                     .that(testInfoOutputStream.getFlushCount())
1539                     .isEqualTo(TestUtil.adjustFlushCountForOutputStreamClose(3));
1540             assertWithMessage("Error stream close count")
1541                     .that(testErrorOutputStream.getCloseCount())
1542                     .isEqualTo(1);
1543             assertWithMessage("Error stream flush count")
1544                     .that(testErrorOutputStream.getFlushCount())
1545                     .isEqualTo(TestUtil.adjustFlushCountForOutputStreamClose(1));
1546         }
1547     }
1548 
1549     // -@cs[CheckstyleTestMakeup] must use raw class to directly initialize DefaultLogger
1550     @Test
1551     public void testXmlLoggerClosesItStreams() throws Exception {
1552         final Checker checker = new Checker();
1553         try (CloseAndFlushTestByteArrayOutputStream testInfoOutputStream =
1554                 new CloseAndFlushTestByteArrayOutputStream()) {
1555             checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
1556             checker.addListener(new XMLLogger(testInfoOutputStream, OutputStreamOptions.CLOSE));
1557 
1558             final File tmpFile = createTempFile("file", ".java");
1559 
1560             execute(checker, tmpFile.getPath(), tmpFile.getPath());
1561 
1562             assertWithMessage("Output stream close count")
1563                     .that(testInfoOutputStream.getCloseCount())
1564                     .isEqualTo(1);
1565             assertWithMessage("Output stream flush count")
1566                     .that(testInfoOutputStream.getFlushCount())
1567                     .isEqualTo(TestUtil.adjustFlushCountForOutputStreamClose(0));
1568         }
1569     }
1570 
1571     @Test
1572     public void testDuplicatedModule() throws Exception {
1573         // we need to test a module with two instances, one with id and the other not
1574         final DefaultConfiguration moduleConfig1 =
1575                 createModuleConfig(NewlineAtEndOfFileCheck.class);
1576         final DefaultConfiguration moduleConfig2 =
1577                 createModuleConfig(NewlineAtEndOfFileCheck.class);
1578         moduleConfig2.addProperty("id", "ModuleId");
1579         final DefaultConfiguration root = new DefaultConfiguration("root");
1580         root.addChild(moduleConfig1);
1581         root.addChild(moduleConfig2);
1582         final Checker checker = new Checker();
1583         checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
1584         checker.configure(root);
1585         // BriefUtLogger does not print the module name or id postfix,
1586         // so we need to set logger manually
1587         final ByteArrayOutputStream out = TestUtil.getInternalState(this, "stream");
1588         final DefaultLogger logger = new DefaultLogger(out, OutputStreamOptions.CLOSE, out,
1589                 OutputStreamOptions.NONE, new AuditEventDefaultFormatter());
1590         checker.addListener(logger);
1591 
1592         final String path = createTempFile("file", ".java").getPath();
1593         final String violationMessage =
1594                 getCheckMessage(NewlineAtEndOfFileCheck.class, MSG_KEY_NO_NEWLINE_EOF);
1595         final String[] expected = {
1596             "1: " + violationMessage + " [NewlineAtEndOfFile]",
1597             "1: " + violationMessage + " [ModuleId]",
1598         };
1599 
1600         // super.verify does not work here, for we change the logger
1601         out.flush();
1602         final int errs = checker.process(Collections.singletonList(new File(path)));
1603         try (ByteArrayInputStream inputStream =
1604                 new ByteArrayInputStream(out.toByteArray());
1605             LineNumberReader lnr = new LineNumberReader(
1606                 new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
1607             // we need to ignore the unrelated lines
1608             final List<String> actual = lnr.lines()
1609                     .filter(line -> !getCheckMessage(AUDIT_STARTED_MESSAGE).equals(line))
1610                     .filter(line -> !getCheckMessage(AUDIT_FINISHED_MESSAGE).equals(line))
1611                     .limit(expected.length)
1612                     .sorted()
1613                     .collect(Collectors.toUnmodifiableList());
1614             Arrays.sort(expected);
1615 
1616             for (int i = 0; i < expected.length; i++) {
1617                 final String expectedResult = "[ERROR] " + path + ":" + expected[i];
1618                 assertWithMessage("error message " + i)
1619                         .that(actual.get(i))
1620                         .isEqualTo(expectedResult);
1621             }
1622 
1623             assertWithMessage("unexpected output: " + lnr.readLine())
1624                     .that(errs)
1625                     .isEqualTo(expected.length);
1626         }
1627 
1628         checker.destroy();
1629     }
1630 
1631     @Test
1632     public void testCachedFile() throws Exception {
1633         final Checker checker = createChecker(createModuleConfig(TranslationCheck.class));
1634         final OutputStream infoStream = new ByteArrayOutputStream();
1635         final OutputStream errorStream = new ByteArrayOutputStream();
1636         final DefaultLoggerWithCounter loggerWithCounter =
1637             new DefaultLoggerWithCounter(infoStream, OutputStreamOptions.CLOSE,
1638                                          errorStream, OutputStreamOptions.CLOSE);
1639         checker.addListener(loggerWithCounter);
1640         final File cacheFile = createTempFile("cacheFile", ".txt");
1641         checker.setCacheFile(cacheFile.getAbsolutePath());
1642 
1643         final File testFile = createTempFile("testFile", ".java");
1644         final List<File> files = List.of(testFile, testFile);
1645         checker.process(files);
1646 
1647         assertWithMessage("Cached file should not be processed twice")
1648             .that(loggerWithCounter.fileStartedCount)
1649             .isEqualTo(1);
1650 
1651         checker.destroy();
1652     }
1653 
1654     @Test
1655     public void testUnmappableCharacters() throws Exception {
1656         final String[] expected = {
1657             "14: " + getCheckMessage(LineLengthCheck.class, MSG_KEY, 80, 225),
1658         };
1659 
1660         verifyWithInlineXmlConfig(getPath("InputCheckerTestCharset.java"),
1661                 expected);
1662     }
1663 
1664     /**
1665      * This tests uses 'verify' method, because it needs some config
1666      * to be executed on non-existing Input file,
1667      * but BDD style methods need config in existing file.
1668      *
1669      * @throws Exception exception
1670      */
1671     @SuppressForbidden
1672     @Test
1673     public void testViolationMessageOnIoException() throws Exception {
1674         final DefaultConfiguration checkConfig =
1675                 createModuleConfig(CheckWhichThrowsError.class);
1676 
1677         final DefaultConfiguration treeWalkerConfig = createModuleConfig(TreeWalker.class);
1678         treeWalkerConfig.addChild(checkConfig);
1679 
1680         final DefaultConfiguration checkerConfig = createRootConfig(treeWalkerConfig);
1681         checkerConfig.addChild(treeWalkerConfig);
1682 
1683         checkerConfig.addProperty("haltOnException", "false");
1684         final File file = new File("InputNonChecker.java");
1685         final String filePath = file.getAbsolutePath();
1686         final String[] expected = {
1687             "1: " + getCheckMessage(EXCEPTION_MSG, filePath
1688                         + " (No such file or directory)"),
1689         };
1690 
1691         verify(checkerConfig, filePath, expected);
1692     }
1693 
1694     /**
1695      * Reason of non-Input based testing:
1696      * There are bunch of asserts that expects full path to file,
1697      * usage of "basedir" make it stripped and we need put everywhere code like
1698      * <pre>CommonUtil.relativizePath(checker.getConfiguration().getProperty("basedir"), file)</pre>
1699      * but Checker object is not always available in code.
1700      * Propagating it in all code methods will complicate code.
1701      */
1702     @Test
1703     public void testRelativizedFileExclusion() throws Exception {
1704         final DefaultConfiguration newLineAtEndOfFileConfig =
1705                 createModuleConfig(NewlineAtEndOfFileCheck.class);
1706 
1707         final DefaultConfiguration beforeExecutionExclusionFileFilterConfig =
1708                 createModuleConfig(BeforeExecutionExclusionFileFilter.class);
1709 
1710         beforeExecutionExclusionFileFilterConfig.addProperty("fileNamePattern",
1711                         "^(?!InputCheckerTestExcludeRelativizedFile.*\\.java).*");
1712 
1713         final DefaultConfiguration checkerConfig = createRootConfig(null);
1714         checkerConfig.addChild(newLineAtEndOfFileConfig);
1715         checkerConfig.addChild(beforeExecutionExclusionFileFilterConfig);
1716 
1717         // -@cs[CheckstyleTestMakeup] Needs to be fixed.
1718         checkerConfig.addProperty("basedir",
1719                 temporaryFolder.getPath());
1720 
1721         final String violationMessage =
1722                 getCheckMessage(NewlineAtEndOfFileCheck.class, MSG_KEY_NO_NEWLINE_EOF);
1723 
1724         final String[] expected = {
1725             "1: " + violationMessage,
1726         };
1727 
1728         final File tempFile = createTempFile("InputCheckerTestExcludeRelativizedFile", ".java");
1729 
1730         final File[] processedFiles = {tempFile};
1731 
1732         verify(createChecker(checkerConfig), processedFiles,
1733                 tempFile.getName(), expected);
1734     }
1735 
1736     public static class DefaultLoggerWithCounter extends DefaultLogger {
1737 
1738         private int fileStartedCount;
1739 
1740         public DefaultLoggerWithCounter(OutputStream infoStream,
1741                                         OutputStreamOptions infoStreamOptions,
1742                                         OutputStream errorStream,
1743                                         OutputStreamOptions errorStreamOptions) {
1744             super(infoStream, infoStreamOptions, errorStream, errorStreamOptions);
1745         }
1746 
1747         @Override
1748         public void fileStarted(AuditEvent event) {
1749             fileStartedCount++;
1750         }
1751     }
1752 
1753     public static class DummyFilter implements Filter {
1754 
1755         @Override
1756         public boolean accept(AuditEvent event) {
1757             return false;
1758         }
1759 
1760     }
1761 
1762     public static class DummyFileSetViolationCheck extends AbstractFileSetCheck
1763         implements ExternalResourceHolder {
1764 
1765         @Override
1766         protected void processFiltered(File file, FileText fileText) {
1767             log(1, "test");
1768         }
1769 
1770         @Override
1771         public Set<String> getExternalResourceLocations() {
1772             final Set<String> externalResourceLocation = new HashSet<>(1);
1773             externalResourceLocation.add("non_existent_external_resource.xml");
1774             return externalResourceLocation;
1775         }
1776 
1777     }
1778 
1779     public static class DummyFilterSet extends FilterSet implements ExternalResourceHolder {
1780 
1781         @Override
1782         public Set<String> getExternalResourceLocations() {
1783             final Set<String> strings = new HashSet<>();
1784             strings.add("test");
1785             return strings;
1786         }
1787 
1788     }
1789 
1790     public static final class DynamicalResourceHolderCheck extends AbstractFileSetCheck
1791         implements ExternalResourceHolder {
1792 
1793         private String firstExternalResourceLocation;
1794         private String secondExternalResourceLocation;
1795 
1796         public void setFirstExternalResourceLocation(String firstExternalResourceLocation) {
1797             this.firstExternalResourceLocation = firstExternalResourceLocation;
1798         }
1799 
1800         public void setSecondExternalResourceLocation(String secondExternalResourceLocation) {
1801             this.secondExternalResourceLocation = secondExternalResourceLocation;
1802         }
1803 
1804         @Override
1805         protected void processFiltered(File file, FileText fileText) {
1806             // there is no need in implementation of the method
1807         }
1808 
1809         @Override
1810         public Set<String> getExternalResourceLocations() {
1811             final Set<String> locations = new HashSet<>();
1812             locations.add(firstExternalResourceLocation);
1813             // Attempt to change the behaviour of the check dynamically
1814             if (secondExternalResourceLocation != null) {
1815                 locations.add(secondExternalResourceLocation);
1816             }
1817             return locations;
1818         }
1819 
1820     }
1821 
1822     public static class CheckWhichDoesNotRequireCommentNodes extends AbstractCheck {
1823 
1824         /** Number of children of method definition token. */
1825         private static final int METHOD_DEF_CHILD_COUNT = 7;
1826 
1827         @Override
1828         public int[] getDefaultTokens() {
1829             return new int[] {TokenTypes.METHOD_DEF};
1830         }
1831 
1832         @Override
1833         public int[] getAcceptableTokens() {
1834             return new int[] {TokenTypes.METHOD_DEF};
1835         }
1836 
1837         @Override
1838         public int[] getRequiredTokens() {
1839             return new int[] {TokenTypes.METHOD_DEF};
1840         }
1841 
1842         @Override
1843         public void visitToken(DetailAST ast) {
1844             if (ast.findFirstToken(TokenTypes.MODIFIERS).findFirstToken(
1845                     TokenTypes.BLOCK_COMMENT_BEGIN) != null) {
1846                 log(ast, "AST has incorrect structure structure."
1847                     + " The check does not require comment nodes but there were comment nodes"
1848                     + " in the AST.");
1849             }
1850             final int childCount = ast.getChildCount();
1851             if (childCount != METHOD_DEF_CHILD_COUNT) {
1852                 final String msg = String.format(Locale.ENGLISH,
1853                     "AST node in no comment tree has wrong number of children. "
1854                             + "Expected is %d but was %d",
1855                     METHOD_DEF_CHILD_COUNT, childCount);
1856                 log(ast, msg);
1857             }
1858             // count children where comment lives
1859             int actualChildCount = 0;
1860             for (DetailAST child = ast.getFirstChild().getFirstChild(); child != null; child =
1861                     child.getNextSibling()) {
1862                 actualChildCount++;
1863             }
1864             final int cacheChildCount = ast.getFirstChild().getChildCount();
1865             if (cacheChildCount != actualChildCount) {
1866                 final String msg = String.format(Locale.ENGLISH,
1867                         "AST node with no comment has wrong number of children. "
1868                                 + "Expected is %d but was %d",
1869                         cacheChildCount, actualChildCount);
1870                 log(ast, msg);
1871             }
1872         }
1873 
1874     }
1875 
1876     public static class CheckWhichRequiresCommentNodes extends AbstractCheck {
1877 
1878         /** Number of children of method definition token. */
1879         private static final int METHOD_DEF_CHILD_COUNT = 7;
1880 
1881         @Override
1882         public boolean isCommentNodesRequired() {
1883             return true;
1884         }
1885 
1886         @Override
1887         public int[] getDefaultTokens() {
1888             return new int[] {TokenTypes.METHOD_DEF};
1889         }
1890 
1891         @Override
1892         public int[] getAcceptableTokens() {
1893             return new int[] {TokenTypes.METHOD_DEF};
1894         }
1895 
1896         @Override
1897         public int[] getRequiredTokens() {
1898             return new int[] {TokenTypes.METHOD_DEF};
1899         }
1900 
1901         // Locale.ENGLISH until #12104
1902         @Override
1903         public void visitToken(DetailAST ast) {
1904             if (ast.findFirstToken(TokenTypes.MODIFIERS).findFirstToken(
1905                     TokenTypes.BLOCK_COMMENT_BEGIN) == null) {
1906                 log(ast, "Incorrect AST structure.");
1907             }
1908             final int childCount = ast.getChildCount();
1909             if (childCount != METHOD_DEF_CHILD_COUNT) {
1910                 final String msg = String.format(Locale.ENGLISH,
1911                     "AST node in comment tree has wrong number of children. "
1912                             + "Expected is %d but was %d",
1913                     METHOD_DEF_CHILD_COUNT, childCount);
1914                 log(ast, msg);
1915             }
1916             // count children where comment lives
1917             int actualChildCount = 0;
1918             for (DetailAST child = ast.getFirstChild().getFirstChild(); child != null; child =
1919                     child.getNextSibling()) {
1920                 actualChildCount++;
1921             }
1922             final int cacheChildCount = ast.getFirstChild().getChildCount();
1923             if (cacheChildCount != actualChildCount) {
1924                 final String msg = String.format(Locale.ENGLISH,
1925                         "AST node with comment has wrong number of children. "
1926                                 + "Expected is %d but was %d",
1927                         cacheChildCount, actualChildCount);
1928                 log(ast, msg);
1929             }
1930         }
1931 
1932     }
1933 
1934     public static final class DummyFileSet extends AbstractFileSetCheck {
1935 
1936         private final List<String> methodCalls = new ArrayList<>();
1937 
1938         private boolean initCalled;
1939 
1940         @Override
1941         public void init() {
1942             super.init();
1943             initCalled = true;
1944         }
1945 
1946         @Override
1947         public void beginProcessing(String charset) {
1948             methodCalls.add("beginProcessing");
1949             super.beginProcessing(charset);
1950         }
1951 
1952         @Override
1953         public void finishProcessing() {
1954             methodCalls.add("finishProcessing");
1955             super.finishProcessing();
1956         }
1957 
1958         @Override
1959         protected void processFiltered(File file, FileText fileText) {
1960             methodCalls.add("processFiltered");
1961         }
1962 
1963         @Override
1964         public void destroy() {
1965             methodCalls.add("destroy");
1966             super.destroy();
1967         }
1968 
1969         public List<String> getMethodCalls() {
1970             return Collections.unmodifiableList(methodCalls);
1971         }
1972 
1973         public boolean isInitCalled() {
1974             return initCalled;
1975         }
1976 
1977         public MessageDispatcher getInternalMessageDispatcher() {
1978             return getMessageDispatcher();
1979         }
1980 
1981     }
1982 
1983 }