View Javadoc
1   ////////////////////////////////////////////////////////////////////////////////
2   // checkstyle: Checks Java source code for adherence to a set of rules.
3   // Copyright (C) 2001-2017 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.puppycrawl.tools.checkstyle.Checker.EXCEPTION_MSG;
23  import static com.puppycrawl.tools.checkstyle.DefaultLogger.AUDIT_FINISHED_MESSAGE;
24  import static com.puppycrawl.tools.checkstyle.DefaultLogger.AUDIT_STARTED_MESSAGE;
25  import static com.puppycrawl.tools.checkstyle.checks.NewlineAtEndOfFileCheck.MSG_KEY_NO_NEWLINE_EOF;
26  import static org.hamcrest.CoreMatchers.instanceOf;
27  import static org.junit.Assert.assertArrayEquals;
28  import static org.junit.Assert.assertEquals;
29  import static org.junit.Assert.assertFalse;
30  import static org.junit.Assert.assertNotNull;
31  import static org.junit.Assert.assertNull;
32  import static org.junit.Assert.assertThat;
33  import static org.junit.Assert.assertTrue;
34  import static org.junit.Assert.fail;
35  import static org.mockito.Mockito.when;
36  
37  import java.io.ByteArrayInputStream;
38  import java.io.ByteArrayOutputStream;
39  import java.io.File;
40  import java.io.FileInputStream;
41  import java.io.IOError;
42  import java.io.IOException;
43  import java.io.InputStreamReader;
44  import java.io.LineNumberReader;
45  import java.io.UnsupportedEncodingException;
46  import java.lang.reflect.Field;
47  import java.lang.reflect.Method;
48  import java.nio.charset.StandardCharsets;
49  import java.nio.file.Files;
50  import java.util.ArrayList;
51  import java.util.Arrays;
52  import java.util.Collections;
53  import java.util.HashSet;
54  import java.util.List;
55  import java.util.Locale;
56  import java.util.Properties;
57  import java.util.Set;
58  import java.util.SortedSet;
59  import java.util.TreeSet;
60  import java.util.stream.Collectors;
61  
62  import org.junit.Rule;
63  import org.junit.Test;
64  import org.junit.rules.TemporaryFolder;
65  import org.mockito.internal.util.reflection.Whitebox;
66  import org.powermock.api.mockito.PowerMockito;
67  
68  import com.puppycrawl.tools.checkstyle.api.AbstractCheck;
69  import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck;
70  import com.puppycrawl.tools.checkstyle.api.AuditEvent;
71  import com.puppycrawl.tools.checkstyle.api.AuditListener;
72  import com.puppycrawl.tools.checkstyle.api.CheckstyleException;
73  import com.puppycrawl.tools.checkstyle.api.Configuration;
74  import com.puppycrawl.tools.checkstyle.api.Context;
75  import com.puppycrawl.tools.checkstyle.api.DetailAST;
76  import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder;
77  import com.puppycrawl.tools.checkstyle.api.FileText;
78  import com.puppycrawl.tools.checkstyle.api.Filter;
79  import com.puppycrawl.tools.checkstyle.api.FilterSet;
80  import com.puppycrawl.tools.checkstyle.api.LocalizedMessage;
81  import com.puppycrawl.tools.checkstyle.api.MessageDispatcher;
82  import com.puppycrawl.tools.checkstyle.api.TokenTypes;
83  import com.puppycrawl.tools.checkstyle.checks.NewlineAtEndOfFileCheck;
84  import com.puppycrawl.tools.checkstyle.checks.TranslationCheck;
85  import com.puppycrawl.tools.checkstyle.checks.coding.HiddenFieldCheck;
86  import com.puppycrawl.tools.checkstyle.filters.SuppressionFilter;
87  import com.puppycrawl.tools.checkstyle.internal.testmodules.DebugAuditAdapter;
88  import com.puppycrawl.tools.checkstyle.internal.testmodules.DebugFilter;
89  import com.puppycrawl.tools.checkstyle.internal.testmodules.TestBeforeExecutionFileFilter;
90  import com.puppycrawl.tools.checkstyle.internal.testmodules.TestFileSetCheck;
91  import com.puppycrawl.tools.checkstyle.internal.utils.CloseAndFlushTestByteArrayOutputStream;
92  import com.puppycrawl.tools.checkstyle.utils.CommonUtils;
93  
94  public class CheckerTest extends AbstractModuleTestSupport {
95  
96      @Rule
97      public final TemporaryFolder temporaryFolder = new TemporaryFolder();
98  
99      private static Method getFireAuditFinished() throws NoSuchMethodException {
100         final Class<Checker> checkerClass = Checker.class;
101         final Method fireAuditFinished = checkerClass.getDeclaredMethod("fireAuditFinished");
102         fireAuditFinished.setAccessible(true);
103         return fireAuditFinished;
104     }
105 
106     private static Method getFireAuditStartedMethod() throws NoSuchMethodException {
107         final Class<Checker> checkerClass = Checker.class;
108         final Method fireAuditStarted = checkerClass.getDeclaredMethod("fireAuditStarted");
109         fireAuditStarted.setAccessible(true);
110         return fireAuditStarted;
111     }
112 
113     @Override
114     protected String getPackageLocation() {
115         return "com/puppycrawl/tools/checkstyle/checker";
116     }
117 
118     @Test
119     public void testDestroy() throws Exception {
120         final Checker checker = new Checker();
121         final DebugAuditAdapter auditAdapter = new DebugAuditAdapter();
122         checker.addListener(auditAdapter);
123         final TestFileSetCheck fileSet = new TestFileSetCheck();
124         checker.addFileSetCheck(fileSet);
125         final DebugFilter filter = new DebugFilter();
126         checker.addFilter(filter);
127         final TestBeforeExecutionFileFilter fileFilter = new TestBeforeExecutionFileFilter();
128         checker.addBeforeExecutionFileFilter(fileFilter);
129 
130         // should remove all listeners, file sets, and filters
131         checker.destroy();
132 
133         checker.process(Collections.singletonList(temporaryFolder.newFile()));
134         final SortedSet<LocalizedMessage> messages = new TreeSet<>();
135         messages.add(new LocalizedMessage(0, 0, "a Bundle", "message.key",
136                 new Object[] {"arg"}, null, getClass(), null));
137         checker.fireErrors("Some File Name", messages);
138 
139         assertFalse("Checker.destroy() doesn't remove listeners.", auditAdapter.wasCalled());
140         assertFalse("Checker.destroy() doesn't remove file sets.", fileSet.wasCalled());
141         assertFalse("Checker.destroy() doesn't remove filters.", filter.wasCalled());
142         assertFalse("Checker.destroy() doesn't remove file filters.", fileFilter.wasCalled());
143     }
144 
145     @Test
146     public void testAddListener() throws Exception {
147         final Checker checker = new Checker();
148         final DebugAuditAdapter auditAdapter = new DebugAuditAdapter();
149         checker.addListener(auditAdapter);
150 
151         // Let's try fire some events
152         getFireAuditStartedMethod().invoke(checker);
153         assertTrue("Checker.fireAuditStarted() doesn't call listener", auditAdapter.wasCalled());
154 
155         auditAdapter.resetListener();
156         getFireAuditFinished().invoke(checker);
157         assertTrue("Checker.fireAuditFinished() doesn't call listener", auditAdapter.wasCalled());
158 
159         auditAdapter.resetListener();
160         checker.fireFileStarted("Some File Name");
161         assertTrue("Checker.fireFileStarted() doesn't call listener", auditAdapter.wasCalled());
162 
163         auditAdapter.resetListener();
164         checker.fireFileFinished("Some File Name");
165         assertTrue("Checker.fireFileFinished() doesn't call listener", auditAdapter.wasCalled());
166 
167         auditAdapter.resetListener();
168         final SortedSet<LocalizedMessage> messages = new TreeSet<>();
169         messages.add(new LocalizedMessage(0, 0, "a Bundle", "message.key",
170                 new Object[] {"arg"}, null, getClass(), null));
171         checker.fireErrors("Some File Name", messages);
172         assertTrue("Checker.fireErrors() doesn't call listener", auditAdapter.wasCalled());
173     }
174 
175     @Test
176     public void testRemoveListener() throws Exception {
177         final Checker checker = new Checker();
178         final DebugAuditAdapter auditAdapter = new DebugAuditAdapter();
179         final DebugAuditAdapter aa2 = new DebugAuditAdapter();
180         checker.addListener(auditAdapter);
181         checker.addListener(aa2);
182         checker.removeListener(auditAdapter);
183 
184         // Let's try fire some events
185         getFireAuditStartedMethod().invoke(checker);
186         assertTrue("Checker.fireAuditStarted() doesn't call listener", aa2.wasCalled());
187         assertFalse("Checker.fireAuditStarted() does call removed listener",
188                 auditAdapter.wasCalled());
189 
190         aa2.resetListener();
191         getFireAuditFinished().invoke(checker);
192         assertTrue("Checker.fireAuditFinished() doesn't call listener", aa2.wasCalled());
193         assertFalse("Checker.fireAuditFinished() does call removed listener",
194                 auditAdapter.wasCalled());
195 
196         aa2.resetListener();
197         checker.fireFileStarted("Some File Name");
198         assertTrue("Checker.fireFileStarted() doesn't call listener", aa2.wasCalled());
199         assertFalse("Checker.fireFileStarted() does call removed listener",
200                 auditAdapter.wasCalled());
201 
202         aa2.resetListener();
203         checker.fireFileFinished("Some File Name");
204         assertTrue("Checker.fireFileFinished() doesn't call listener", aa2.wasCalled());
205         assertFalse("Checker.fireFileFinished() does call removed listener",
206                 auditAdapter.wasCalled());
207 
208         aa2.resetListener();
209         final SortedSet<LocalizedMessage> messages = new TreeSet<>();
210         messages.add(new LocalizedMessage(0, 0, "a Bundle", "message.key",
211                 new Object[] {"arg"}, null, getClass(), null));
212         checker.fireErrors("Some File Name", messages);
213         assertTrue("Checker.fireErrors() doesn't call listener", aa2.wasCalled());
214         assertFalse("Checker.fireErrors() does call removed listener", auditAdapter.wasCalled());
215 
216     }
217 
218     @Test
219     public void testAddBeforeExecutionFileFilter() throws Exception {
220         final Checker checker = new Checker();
221         final TestBeforeExecutionFileFilter filter = new TestBeforeExecutionFileFilter();
222 
223         checker.addBeforeExecutionFileFilter(filter);
224 
225         filter.resetFilter();
226         checker.process(Collections.singletonList(new File("dummy.java")));
227         assertTrue("Checker.acceptFileStarted() doesn't call filter", filter.wasCalled());
228     }
229 
230     @Test
231     public void testRemoveBeforeExecutionFileFilter() throws Exception {
232         final Checker checker = new Checker();
233         final TestBeforeExecutionFileFilter filter = new TestBeforeExecutionFileFilter();
234         final TestBeforeExecutionFileFilter f2 = new TestBeforeExecutionFileFilter();
235         checker.addBeforeExecutionFileFilter(filter);
236         checker.addBeforeExecutionFileFilter(f2);
237         checker.removeBeforeExecutionFileFilter(filter);
238 
239         f2.resetFilter();
240         checker.process(Collections.singletonList(new File("dummy.java")));
241         assertTrue("Checker.acceptFileStarted() doesn't call filter", f2.wasCalled());
242         assertFalse("Checker.acceptFileStarted() does call removed filter", filter.wasCalled());
243     }
244 
245     @Test
246     public void testAddFilter() {
247         final Checker checker = new Checker();
248         final DebugFilter filter = new DebugFilter();
249 
250         checker.addFilter(filter);
251 
252         filter.resetFilter();
253         final SortedSet<LocalizedMessage> messages = new TreeSet<>();
254         messages.add(new LocalizedMessage(0, 0, "a Bundle", "message.key",
255                 new Object[] {"arg"}, null, getClass(), null));
256         checker.fireErrors("Some File Name", messages);
257         assertTrue("Checker.fireErrors() doesn't call filter", filter.wasCalled());
258     }
259 
260     @Test
261     public void testRemoveFilter() {
262         final Checker checker = new Checker();
263         final DebugFilter filter = new DebugFilter();
264         final DebugFilter f2 = new DebugFilter();
265         checker.addFilter(filter);
266         checker.addFilter(f2);
267         checker.removeFilter(filter);
268 
269         f2.resetFilter();
270         final SortedSet<LocalizedMessage> messages = new TreeSet<>();
271         messages.add(new LocalizedMessage(0, 0, "a Bundle", "message.key",
272                 new Object[] {"arg"}, null, getClass(), null));
273         checker.fireErrors("Some File Name", messages);
274         assertTrue("Checker.fireErrors() doesn't call filter", f2.wasCalled());
275         assertFalse("Checker.fireErrors() does call removed filter", filter.wasCalled());
276 
277     }
278 
279     @Test
280     public void testFileExtensions() throws Exception {
281         final DefaultConfiguration checkerConfig = new DefaultConfiguration("configuration");
282         checkerConfig.addAttribute("charset", StandardCharsets.UTF_8.name());
283         checkerConfig.addAttribute("cacheFile", temporaryFolder.newFile().getPath());
284 
285         final Checker checker = new Checker();
286         checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
287         checker.configure(checkerConfig);
288 
289         final DebugAuditAdapter auditAdapter = new DebugAuditAdapter();
290         checker.addListener(auditAdapter);
291 
292         final List<File> files = new ArrayList<>();
293         final File file = new File("file.pdf");
294         files.add(file);
295         final File otherFile = new File("file.java");
296         files.add(otherFile);
297         final String[] fileExtensions = {"java", "xml", "properties"};
298         checker.setFileExtensions(fileExtensions);
299         checker.setCacheFile(temporaryFolder.newFile().getPath());
300         final int counter = checker.process(files);
301 
302         // comparing to 1 as there is only one legal file in input
303         final int numLegalFiles = 1;
304         final PropertyCacheFile cache =
305                 (PropertyCacheFile) Whitebox.getInternalState(checker, "cache");
306         assertEquals("There were more legal files than expected",
307                 numLegalFiles, counter);
308         assertEquals("Audit was started on larger amount of files than expected",
309                 numLegalFiles, auditAdapter.getNumFilesStarted());
310         assertEquals("Audit was finished on larger amount of files than expected",
311                 numLegalFiles, auditAdapter.getNumFilesFinished());
312         assertNull("Cache shout not contain any file",
313                 cache.get(new File("file.java").getCanonicalPath()));
314     }
315 
316     @Test
317     public void testIgnoredFileExtensions() throws Exception {
318         final DefaultConfiguration checkerConfig = new DefaultConfiguration("configuration");
319         checkerConfig.addAttribute("charset", StandardCharsets.UTF_8.name());
320         checkerConfig.addAttribute("cacheFile", temporaryFolder.newFile().getPath());
321 
322         final Checker checker = new Checker();
323         checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
324         checker.configure(checkerConfig);
325 
326         final DebugAuditAdapter auditAdapter = new DebugAuditAdapter();
327         checker.addListener(auditAdapter);
328 
329         final List<File> allIgnoredFiles = new ArrayList<>();
330         final File ignoredFile = new File("file.pdf");
331         allIgnoredFiles.add(ignoredFile);
332         final String[] fileExtensions = {"java", "xml", "properties"};
333         checker.setFileExtensions(fileExtensions);
334         checker.setCacheFile(temporaryFolder.newFile().getPath());
335         final int counter = checker.process(allIgnoredFiles);
336 
337         // comparing to 0 as there is no legal file in input
338         final int numLegalFiles = 0;
339         assertEquals("There were more legal files than expected",
340                 numLegalFiles, counter);
341         assertEquals("Audit was started on larger amount of files than expected",
342                 numLegalFiles, auditAdapter.getNumFilesStarted());
343         assertEquals("Audit was finished on larger amount of files than expected",
344                 numLegalFiles, auditAdapter.getNumFilesFinished());
345     }
346 
347     @Test
348     public void testSetters() {
349         // all  that is set by reflection, so just make code coverage be happy
350         final Checker checker = new Checker();
351         checker.setClassLoader(getClass().getClassLoader());
352         checker.setBasedir("some");
353         checker.setSeverity("ignore");
354 
355         final PackageObjectFactory factory = new PackageObjectFactory(
356             new HashSet<>(), Thread.currentThread().getContextClassLoader());
357         checker.setModuleFactory(factory);
358 
359         checker.setFileExtensions((String[]) null);
360         checker.setFileExtensions(".java", "xml");
361 
362         try {
363             checker.setCharset("UNKNOWN-CHARSET");
364             fail("Exception is expected");
365         }
366         catch (UnsupportedEncodingException ex) {
367             assertEquals("Error message is not expected",
368                     "unsupported charset: 'UNKNOWN-CHARSET'", ex.getMessage());
369         }
370     }
371 
372     @Test
373     public void testNoClassLoaderNoModuleFactory() {
374         final Checker checker = new Checker();
375 
376         try {
377             checker.finishLocalSetup();
378             fail("Exception is expected");
379         }
380         catch (CheckstyleException ex) {
381             assertEquals("Error message is not expected",
382                     "if no custom moduleFactory is set, moduleClassLoader must be specified",
383                     ex.getMessage());
384         }
385     }
386 
387     @Test
388     public void testNoModuleFactory() throws Exception {
389         final Checker checker = new Checker();
390         final ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
391 
392         checker.setModuleClassLoader(classLoader);
393         checker.finishLocalSetup();
394         final Context actualCtx = (Context) Whitebox.getInternalState(checker, "childContext");
395 
396         assertNotNull("Default module factory should be created when it is not specified",
397             actualCtx.get("moduleFactory"));
398         assertEquals("Invalid classLoader", classLoader, actualCtx.get("classLoader"));
399     }
400 
401     @Test
402     public void testFinishLocalSetupFullyInitialized() throws Exception {
403         final Checker checker = new Checker();
404         final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
405         checker.setModuleClassLoader(contextClassLoader);
406         final PackageObjectFactory factory = new PackageObjectFactory(
407             new HashSet<>(), contextClassLoader);
408         checker.setModuleFactory(factory);
409         checker.setBasedir("testBaseDir");
410         checker.setLocaleLanguage("it");
411         checker.setLocaleCountry("IT");
412         checker.finishLocalSetup();
413 
414         final Context context = (Context) Whitebox.getInternalState(checker, "childContext");
415         assertEquals("Charset was different than expected",
416                 System.getProperty("file.encoding", StandardCharsets.UTF_8.name()),
417                 context.get("charset"));
418         assertEquals("Was used insufficient classloader",
419                 contextClassLoader, context.get("classLoader"));
420         assertEquals("Severity is set to unexpected value",
421                 "error", context.get("severity"));
422         assertEquals("Basedir is set to unexpected value",
423                 "testBaseDir", context.get("basedir"));
424 
425         final Field sLocale = LocalizedMessage.class.getDeclaredField("sLocale");
426         sLocale.setAccessible(true);
427         final Locale locale = (Locale) sLocale.get(null);
428         assertEquals("Locale is set to unexpected value", Locale.ITALY, locale);
429     }
430 
431     @Test
432     public void testSetupChildExceptions() {
433         final Checker checker = new Checker();
434         final PackageObjectFactory factory = new PackageObjectFactory(
435             new HashSet<>(), Thread.currentThread().getContextClassLoader());
436         checker.setModuleFactory(factory);
437 
438         final Configuration config = new DefaultConfiguration("java.lang.String");
439         try {
440             checker.setupChild(config);
441             fail("Exception is expected");
442         }
443         catch (CheckstyleException ex) {
444             assertEquals("Error message is not expected",
445                     "java.lang.String is not allowed as a child in Checker", ex.getMessage());
446         }
447     }
448 
449     @Test
450     @SuppressWarnings("unchecked")
451     public void testSetupChildListener() throws Exception {
452         final Checker checker = new Checker();
453         final PackageObjectFactory factory = new PackageObjectFactory(
454             new HashSet<>(), Thread.currentThread().getContextClassLoader());
455         checker.setModuleFactory(factory);
456 
457         final Configuration config = new DefaultConfiguration(
458             DebugAuditAdapter.class.getCanonicalName());
459         checker.setupChild(config);
460 
461         final List<AuditListener> listeners =
462             (List<AuditListener>) Whitebox.getInternalState(checker, "listeners");
463         assertTrue("Invalid child listener class",
464             listeners.get(listeners.size() - 1) instanceof DebugAuditAdapter);
465 
466     }
467 
468     @Test
469     public void testDestroyCheckerWithWrongCacheFileNameLength() throws Exception {
470         final Checker checker = new Checker();
471         final PackageObjectFactory factory = new PackageObjectFactory(
472             new HashSet<>(), Thread.currentThread().getContextClassLoader());
473         checker.setModuleFactory(factory);
474         checker.configure(new DefaultConfiguration("default config"));
475         // We set wrong file name length in order to reproduce IOException on OS Linux, OS Windows.
476         // The maximum file name length which is allowed in most UNIX, Windows file systems is 255.
477         // See https://en.wikipedia.org/wiki/Filename;
478         checker.setCacheFile(String.format(Locale.ENGLISH, "%0300d", 0));
479         try {
480             checker.destroy();
481             fail("Exception did not happen");
482         }
483         catch (IllegalStateException ex) {
484             assertTrue("Cause of exception differs from IOException",
485                     ex.getCause() instanceof IOException);
486         }
487     }
488 
489     /**
490      * It is OK to have long test method name here as it describes the test purpose.
491      * @noinspection InstanceMethodNamingConvention
492      */
493     @Test
494     public void testCacheAndCheckWhichDoesNotImplementExternalResourceHolderInterface()
495             throws Exception {
496         assertFalse("ExternalResourceHolder has changed his parent",
497                 ExternalResourceHolder.class.isAssignableFrom(HiddenFieldCheck.class));
498         final DefaultConfiguration checkConfig = createModuleConfig(HiddenFieldCheck.class);
499 
500         final DefaultConfiguration treeWalkerConfig = createModuleConfig(TreeWalker.class);
501         treeWalkerConfig.addChild(checkConfig);
502 
503         final DefaultConfiguration checkerConfig = createRootConfig(treeWalkerConfig);
504         checkerConfig.addAttribute("charset", StandardCharsets.UTF_8.name());
505 
506         final File cacheFile = temporaryFolder.newFile();
507         checkerConfig.addAttribute("cacheFile", cacheFile.getPath());
508 
509         final File tmpFile = temporaryFolder.newFile("file.java");
510         final String[] expected = CommonUtils.EMPTY_STRING_ARRAY;
511 
512         verify(checkerConfig, tmpFile.getPath(), expected);
513         final Properties cacheAfterFirstRun = new Properties();
514         cacheAfterFirstRun.load(Files.newBufferedReader(cacheFile.toPath()));
515 
516         // one more time to reuse cache
517         verify(checkerConfig, tmpFile.getPath(), expected);
518         final Properties cacheAfterSecondRun = new Properties();
519         cacheAfterSecondRun.load(Files.newBufferedReader(cacheFile.toPath()));
520 
521         assertEquals("Cache from first run differs from second run cache",
522                 cacheAfterFirstRun, cacheAfterSecondRun);
523     }
524 
525     @Test
526     public void testWithCacheWithNoViolation() throws Exception {
527         final Checker checker = new Checker();
528         final PackageObjectFactory factory = new PackageObjectFactory(
529             new HashSet<>(), Thread.currentThread().getContextClassLoader());
530         checker.setModuleFactory(factory);
531         checker.configure(createModuleConfig(TranslationCheck.class));
532 
533         final File cacheFile = temporaryFolder.newFile();
534         checker.setCacheFile(cacheFile.getPath());
535 
536         checker.setupChild(createModuleConfig(TranslationCheck.class));
537         final File tmpFile = temporaryFolder.newFile("file.java");
538         final List<File> files = new ArrayList<>(1);
539         files.add(tmpFile);
540         checker.process(files);
541 
542         // invoke destroy to persist cache
543         checker.destroy();
544 
545         final Properties cache = new Properties();
546         cache.load(Files.newBufferedReader(cacheFile.toPath()));
547 
548         // There should 2 objects in cache: processed file (file.java) and checker configuration.
549         final int expectedNumberOfObjectsInCache = 2;
550         assertEquals("Cache has unexpected size",
551                 expectedNumberOfObjectsInCache, cache.size());
552 
553         final String expectedConfigHash = "B8535A811CA90BE8B7A14D40BCA62B4FC2447B46";
554         assertEquals("Cache has unexpected hash",
555                 expectedConfigHash, cache.getProperty(PropertyCacheFile.CONFIG_HASH_KEY));
556 
557         assertNotNull("Cache file has null path",
558                 cache.getProperty(tmpFile.getPath()));
559     }
560 
561     @Test
562     public void testClearExistingCache() throws Exception {
563         final DefaultConfiguration checkerConfig = createRootConfig(null);
564         checkerConfig.addAttribute("charset", StandardCharsets.UTF_8.name());
565         final File cacheFile = temporaryFolder.newFile();
566         checkerConfig.addAttribute("cacheFile", cacheFile.getPath());
567 
568         final Checker checker = new Checker();
569         checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
570         checker.configure(checkerConfig);
571         checker.addListener(getBriefUtLogger());
572 
573         checker.clearCache();
574         // invoke destroy to persist cache
575         checker.destroy();
576 
577         final Properties cacheAfterClear = new Properties();
578         cacheAfterClear.load(Files.newBufferedReader(cacheFile.toPath()));
579 
580         assertEquals("Cache has unexpected size",
581                 1, cacheAfterClear.size());
582         assertNotNull("Cache has null hash",
583                 cacheAfterClear.getProperty(PropertyCacheFile.CONFIG_HASH_KEY));
584 
585         final String pathToEmptyFile = temporaryFolder.newFile("file.java").getPath();
586         final String[] expected = CommonUtils.EMPTY_STRING_ARRAY;
587 
588         // file that should be audited is not in cache
589         verify(checker, pathToEmptyFile, pathToEmptyFile, expected);
590         final Properties cacheAfterSecondRun = new Properties();
591         cacheAfterSecondRun.load(Files.newBufferedReader(cacheFile.toPath()));
592 
593         assertNotNull("Cache has null path",
594                 cacheAfterSecondRun.getProperty(pathToEmptyFile));
595         assertEquals("Cash have changed it hash",
596             cacheAfterClear.getProperty(PropertyCacheFile.CONFIG_HASH_KEY),
597             cacheAfterSecondRun.getProperty(PropertyCacheFile.CONFIG_HASH_KEY)
598         );
599         final int expectedNumberOfObjectsInCacheAfterSecondRun = 2;
600         assertEquals("Cache has changed number of items",
601                 expectedNumberOfObjectsInCacheAfterSecondRun, cacheAfterSecondRun.size());
602     }
603 
604     @Test
605     public void testClearCache() throws Exception {
606         final DefaultConfiguration violationCheck =
607                 createModuleConfig(DummyFileSetViolationCheck.class);
608         final DefaultConfiguration checkerConfig = new DefaultConfiguration("myConfig");
609         checkerConfig.addAttribute("charset", "UTF-8");
610         final File cacheFile = temporaryFolder.newFile();
611         checkerConfig.addAttribute("cacheFile", cacheFile.getPath());
612         checkerConfig.addChild(violationCheck);
613         final Checker checker = new Checker();
614         checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
615         checker.configure(checkerConfig);
616         checker.addListener(getBriefUtLogger());
617 
618         checker.process(Collections.singletonList(new File("dummy.java")));
619         checker.clearCache();
620         // invoke destroy to persist cache
621         final PropertyCacheFile cache =
622                 (PropertyCacheFile) Whitebox.getInternalState(checker, "cache");
623         cache.persist();
624 
625         final Properties cacheAfterClear = new Properties();
626         cacheAfterClear.load(Files.newBufferedReader(cacheFile.toPath()));
627 
628         assertEquals("Cache has unexpected size",
629                 1, cacheAfterClear.size());
630     }
631 
632     @Test
633     public void setFileExtension() {
634         final Checker checker = new Checker();
635         checker.setFileExtensions(".test1", "test2");
636         final String[] actual =
637                 (String[]) Whitebox.getInternalState(checker, "fileExtensions");
638         assertArrayEquals("Extensions are not expected",
639                 new String[] {".test1", ".test2"}, actual);
640     }
641 
642     @Test
643     public void testClearCacheWhenCacheFileIsNotSet() {
644         // The idea of the test is to check that when cache file is not set,
645         // the invocation of clearCache method does not throw an exception.
646         final Checker checker = new Checker();
647         checker.clearCache();
648         assertNull("If cache file is not set the cache should default to null",
649             Whitebox.getInternalState(checker, "cache"));
650     }
651 
652     @Test
653     public void testCatchErrorInProcessFilesMethod() throws Exception {
654         // The idea of the test is to satisfy coverage rate.
655         // An Error indicates serious problems that a reasonable application should not try to
656         // catch, but due to issue https://github.com/checkstyle/checkstyle/issues/2285
657         // we catch errors in 'processFiles' method. Most such errors are abnormal conditions,
658         // that is why we use PowerMockito to reproduce them.
659         final File mock = PowerMockito.mock(File.class);
660         // Assume that I/O error is happened when we try to invoke 'lastModified()' method.
661         final String errorMessage = "Java Virtual Machine is broken"
662             + " or has run out of resources necessary for it to continue operating.";
663         final Error expectedError = new IOError(new InternalError(errorMessage));
664         when(mock.lastModified()).thenThrow(expectedError);
665         final Checker checker = new Checker();
666         final List<File> filesToProcess = new ArrayList<>();
667         filesToProcess.add(mock);
668         try {
669             checker.process(filesToProcess);
670             fail("IOError is expected!");
671         }
672         // -@cs[IllegalCatchExtended] Testing for catch Error is part of 100% coverage.
673         catch (Error error) {
674             assertThat("Error cause differs from IOError",
675                     error.getCause(), instanceOf(IOError.class));
676             assertThat("Error cause is not InternalError",
677                     error.getCause().getCause(), instanceOf(InternalError.class));
678             assertEquals("Error message is not expected",
679                     errorMessage, error.getCause().getCause().getMessage());
680         }
681     }
682 
683     /**
684      * It is OK to have long test method name here as it describes the test purpose.
685      * @noinspection InstanceMethodNamingConvention
686      */
687     @Test
688     public void testCacheAndFilterWhichDoesNotImplementExternalResourceHolderInterface()
689             throws Exception {
690         assertFalse("ExternalResourceHolder has changed its parent",
691                 ExternalResourceHolder.class.isAssignableFrom(DummyFilter.class));
692         final DefaultConfiguration filterConfig = createModuleConfig(DummyFilter.class);
693 
694         final DefaultConfiguration checkerConfig = createRootConfig(filterConfig);
695         final File cacheFile = temporaryFolder.newFile();
696         checkerConfig.addAttribute("cacheFile", cacheFile.getPath());
697 
698         final String[] expected = CommonUtils.EMPTY_STRING_ARRAY;
699         final String pathToEmptyFile = temporaryFolder.newFile("file.java").getPath();
700 
701         verify(checkerConfig, pathToEmptyFile, expected);
702         final Properties cacheAfterFirstRun = new Properties();
703         cacheAfterFirstRun.load(Files.newBufferedReader(cacheFile.toPath()));
704 
705         // One more time to use cache.
706         verify(checkerConfig, pathToEmptyFile, expected);
707         final Properties cacheAfterSecondRun = new Properties();
708         cacheAfterSecondRun.load(Files.newBufferedReader(cacheFile.toPath()));
709 
710         assertEquals(
711                 "Cache file has changed its path",
712             cacheAfterFirstRun.getProperty(pathToEmptyFile),
713             cacheAfterSecondRun.getProperty(pathToEmptyFile)
714         );
715         assertEquals(
716                 "Cache has changed its hash",
717             cacheAfterFirstRun.getProperty(PropertyCacheFile.CONFIG_HASH_KEY),
718             cacheAfterSecondRun.getProperty(PropertyCacheFile.CONFIG_HASH_KEY)
719         );
720         final int expectedNumberOfObjectsInCache = 2;
721         assertEquals("Number of items in cache differs from expected",
722                 expectedNumberOfObjectsInCache, cacheAfterFirstRun.size());
723         assertEquals("Number of items in cache differs from expected",
724                 expectedNumberOfObjectsInCache, cacheAfterSecondRun.size());
725     }
726 
727     /**
728      * It is OK to have long test method name here as it describes the test purpose.
729      * @noinspection InstanceMethodNamingConvention
730      */
731     // -@cs[ExecutableStatementCount] This test needs to verify many things.
732     @Test
733     public void testCacheAndCheckWhichAddsNewResourceLocationButKeepsSameCheckerInstance()
734             throws Exception {
735 
736         // Use case (https://github.com/checkstyle/checkstyle/pull/3092#issuecomment-218162436):
737         // Imagine that cache exists in a file. New version of Checkstyle appear.
738         // New release contains update to a some check to have additional external resource.
739         // User update his configuration and run validation as usually.
740         // Cache should not be reused.
741 
742         final DynamicalResourceHolderCheck check = new DynamicalResourceHolderCheck();
743         final String firstExternalResourceLocation = getPath("InputCheckerImportControlOne.xml");
744         final String firstExternalResourceKey = PropertyCacheFile.EXTERNAL_RESOURCE_KEY_PREFIX
745                 + firstExternalResourceLocation;
746         check.setFirstExternalResourceLocation(firstExternalResourceLocation);
747 
748         final DefaultConfiguration checkerConfig = createRootConfig(null);
749         final File cacheFile = temporaryFolder.newFile();
750         checkerConfig.addAttribute("cacheFile", cacheFile.getPath());
751 
752         final Checker checker = new Checker();
753         checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
754         checker.addFileSetCheck(check);
755         checker.addFilter(new DummyFilterSet());
756         checker.configure(checkerConfig);
757         checker.addListener(getBriefUtLogger());
758 
759         final String pathToEmptyFile = temporaryFolder.newFile("file.java").getPath();
760         final String[] expected = CommonUtils.EMPTY_STRING_ARRAY;
761 
762         verify(checker, pathToEmptyFile, expected);
763         final Properties cacheAfterFirstRun = new Properties();
764         cacheAfterFirstRun.load(Files.newBufferedReader(cacheFile.toPath()));
765 
766         final int expectedNumberOfObjectsInCacheAfterFirstRun = 4;
767         assertEquals("Number of items in cache differs from expected",
768                 expectedNumberOfObjectsInCacheAfterFirstRun, cacheAfterFirstRun.size());
769 
770         // Change a list of external resources which are used by the check
771         final String secondExternalResourceLocation = "InputCheckerImportControlTwo.xml";
772         final String secondExternalResourceKey = PropertyCacheFile.EXTERNAL_RESOURCE_KEY_PREFIX
773                 + secondExternalResourceLocation;
774         check.setSecondExternalResourceLocation(secondExternalResourceLocation);
775 
776         checker.addFileSetCheck(check);
777         checker.configure(checkerConfig);
778 
779         verify(checker, pathToEmptyFile, expected);
780         final Properties cacheAfterSecondRun = new Properties();
781         cacheAfterSecondRun.load(Files.newBufferedReader(cacheFile.toPath()));
782 
783         assertEquals("Cache file has changed its path",
784             cacheAfterFirstRun.getProperty(pathToEmptyFile),
785             cacheAfterSecondRun.getProperty(pathToEmptyFile)
786         );
787         assertEquals(
788                 "Cache has changed its hash",
789             cacheAfterFirstRun.getProperty(PropertyCacheFile.CONFIG_HASH_KEY),
790             cacheAfterSecondRun.getProperty(PropertyCacheFile.CONFIG_HASH_KEY)
791         );
792         assertEquals("Cache has changed its resource key",
793             cacheAfterFirstRun.getProperty(firstExternalResourceKey),
794             cacheAfterSecondRun.getProperty(firstExternalResourceKey)
795         );
796         assertNotNull("Cache has null as a resource key",
797                 cacheAfterFirstRun.getProperty(firstExternalResourceKey));
798         final int expectedNumberOfObjectsInCacheAfterSecondRun = 4;
799         assertEquals("Number of items in cache differs from expected",
800                 expectedNumberOfObjectsInCacheAfterSecondRun, cacheAfterSecondRun.size());
801         assertNull("Cache has not null as a resource key",
802                 cacheAfterFirstRun.getProperty(secondExternalResourceKey));
803         assertNotNull("Cache has null as a resource key",
804                 cacheAfterSecondRun.getProperty(secondExternalResourceKey));
805     }
806 
807     @Test
808     public void testClearLazyLoadCacheInDetailAST() throws Exception {
809         final DefaultConfiguration checkConfig1 =
810             createModuleConfig(CheckWhichDoesNotRequireCommentNodes.class);
811         final DefaultConfiguration checkConfig2 =
812             createModuleConfig(CheckWhichRequiresCommentNodes.class);
813 
814         final DefaultConfiguration treeWalkerConfig = createModuleConfig(TreeWalker.class);
815         treeWalkerConfig.addChild(checkConfig1);
816         treeWalkerConfig.addChild(checkConfig2);
817 
818         final DefaultConfiguration checkerConfig = createRootConfig(treeWalkerConfig);
819 
820         final String filePath = getPath("InputCheckerClearDetailAstLazyLoadCache.java");
821         final String[] expected = CommonUtils.EMPTY_STRING_ARRAY;
822 
823         verify(checkerConfig, filePath, expected);
824     }
825 
826     @Test
827     public void testCacheOnViolationSuppression() throws Exception {
828         final File cacheFile = temporaryFolder.newFile();
829         final DefaultConfiguration violationCheck =
830                 createModuleConfig(DummyFileSetViolationCheck.class);
831 
832         final DefaultConfiguration filterConfig = createModuleConfig(SuppressionFilter.class);
833         filterConfig.addAttribute("file", getPath("InputCheckerSuppressAll.xml"));
834 
835         final DefaultConfiguration checkerConfig = createRootConfig(violationCheck);
836         checkerConfig.addAttribute("cacheFile", cacheFile.getPath());
837         checkerConfig.addChild(filterConfig);
838 
839         final String fileViolationPath = temporaryFolder.newFile("ViolationFile.java").getPath();
840         final String[] expected = CommonUtils.EMPTY_STRING_ARRAY;
841 
842         verify(checkerConfig, fileViolationPath, expected);
843 
844         try (FileInputStream input = new FileInputStream(cacheFile)) {
845             final Properties details = new Properties();
846             details.load(input);
847 
848             assertNotNull("suppressed violation file saved in cache",
849                     details.getProperty(fileViolationPath));
850         }
851     }
852 
853     @Test
854     public void testHaltOnExceptionOff() throws Exception {
855         final DefaultConfiguration checkConfig =
856             createModuleConfig(CheckWhichThrowsError.class);
857 
858         final DefaultConfiguration treeWalkerConfig = createModuleConfig(TreeWalker.class);
859         treeWalkerConfig.addChild(checkConfig);
860 
861         final DefaultConfiguration checkerConfig = createRootConfig(treeWalkerConfig);
862         checkerConfig.addChild(treeWalkerConfig);
863 
864         checkerConfig.addAttribute("haltOnException", "false");
865 
866         final String filePath = getPath("InputChecker.java");
867         final String[] expected = {
868             "0: " + getCheckMessage(EXCEPTION_MSG, "java.lang.IndexOutOfBoundsException: test"),
869         };
870 
871         verify(checkerConfig, filePath, expected);
872     }
873 
874     @Test
875     public void testCheckerProcessCallAllNeededMethodsOfFileSets() throws Exception {
876         final DummyFileSet fileSet = new DummyFileSet();
877         final Checker checker = new Checker();
878         checker.addFileSetCheck(fileSet);
879         checker.process(Collections.singletonList(new File("dummy.java")));
880         final List<String> expected =
881             Arrays.asList("beginProcessing", "finishProcessing", "destroy");
882         assertArrayEquals("Method calls were not expected",
883                 expected.toArray(), fileSet.getMethodCalls().toArray());
884     }
885 
886     @Test
887     public void testSetFileSetCheckSetsMessageDispatcher() {
888         final DummyFileSet fileSet = new DummyFileSet();
889         final Checker checker = new Checker();
890         checker.addFileSetCheck(fileSet);
891         assertEquals("Message dispatcher was not expected",
892                 checker, fileSet.getInternalMessageDispatcher());
893     }
894 
895     @Test
896     public void testAddAuditListenerAsChild() throws Exception {
897         final Checker checker = new Checker();
898         final DebugAuditAdapter auditAdapter = new DebugAuditAdapter();
899         final PackageObjectFactory factory = new PackageObjectFactory(
900                 new HashSet<>(), Thread.currentThread().getContextClassLoader()) {
901             @Override
902             public Object createModule(String name) throws CheckstyleException {
903                 Object adapter = auditAdapter;
904                 if (!name.equals(DebugAuditAdapter.class.getName())) {
905                     adapter = super.createModule(name);
906                 }
907                 return adapter;
908             }
909         };
910         checker.setModuleFactory(factory);
911         checker.setupChild(createModuleConfig(DebugAuditAdapter.class));
912         // Let's try fire some events
913         checker.process(Collections.singletonList(new File("dummy.java")));
914         assertTrue("Checker.fireAuditStarted() doesn't call listener", auditAdapter.wasCalled());
915     }
916 
917     @Test
918     public void testAddBeforeExecutionFileFilterAsChild() throws Exception {
919         final Checker checker = new Checker();
920         final TestBeforeExecutionFileFilter fileFilter = new TestBeforeExecutionFileFilter();
921         final PackageObjectFactory factory = new PackageObjectFactory(
922                 new HashSet<>(), Thread.currentThread().getContextClassLoader()) {
923             @Override
924             public Object createModule(String name) throws CheckstyleException {
925                 Object filter = fileFilter;
926                 if (!name.equals(TestBeforeExecutionFileFilter.class.getName())) {
927                     filter = super.createModule(name);
928                 }
929                 return filter;
930             }
931         };
932         checker.setModuleFactory(factory);
933         checker.setupChild(createModuleConfig(TestBeforeExecutionFileFilter.class));
934         checker.process(Collections.singletonList(new File("dummy.java")));
935         assertTrue("Checker.acceptFileStarted() doesn't call listener", fileFilter.wasCalled());
936     }
937 
938     @Test
939     public void testFileSetCheckInitWhenAddedAsChild() throws Exception {
940         final Checker checker = new Checker();
941         final DummyFileSet fileSet = new DummyFileSet();
942         final PackageObjectFactory factory = new PackageObjectFactory(
943                 new HashSet<>(), Thread.currentThread().getContextClassLoader()) {
944             @Override
945             public Object createModule(String name) throws CheckstyleException {
946                 Object check = fileSet;
947                 if (!name.equals(DummyFileSet.class.getName())) {
948                     check = super.createModule(name);
949                 }
950                 return check;
951             }
952         };
953         checker.setModuleFactory(factory);
954         checker.finishLocalSetup();
955         checker.setupChild(createModuleConfig(DummyFileSet.class));
956         assertTrue("FileSetCheck.init() wasn't called", fileSet.isInitCalled());
957     }
958 
959     // -@cs[CheckstyleTestMakeup] must use raw class to directly initialize DefaultLogger
960     @Test
961     public void testDefaultLoggerClosesItStreams() throws Exception {
962         final Checker checker = new Checker();
963         final CloseAndFlushTestByteArrayOutputStream testInfoOutputStream =
964             new CloseAndFlushTestByteArrayOutputStream();
965         final CloseAndFlushTestByteArrayOutputStream testErrorOutputStream =
966             new CloseAndFlushTestByteArrayOutputStream();
967         checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
968         checker.addListener(new DefaultLogger(testInfoOutputStream,
969             true, testErrorOutputStream, true));
970 
971         final File tmpFile = temporaryFolder.newFile("file.java");
972         final String[] expected = CommonUtils.EMPTY_STRING_ARRAY;
973 
974         verify(checker, tmpFile.getPath(), expected);
975 
976         assertEquals("Close count was not expected",
977                 1, testInfoOutputStream.getCloseCount());
978         assertEquals("Flush count was not expected",
979                 3, testInfoOutputStream.getFlushCount());
980         assertEquals("Close count was not expected",
981                 1, testErrorOutputStream.getCloseCount());
982         assertEquals("Flush count was not expected",
983                 1, testErrorOutputStream.getFlushCount());
984     }
985 
986     // -@cs[CheckstyleTestMakeup] must use raw class to directly initialize DefaultLogger
987     @Test
988     public void testXmlLoggerClosesItStreams() throws Exception {
989         final Checker checker = new Checker();
990         final CloseAndFlushTestByteArrayOutputStream testInfoOutputStream =
991             new CloseAndFlushTestByteArrayOutputStream();
992         checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
993         checker.addListener(new XMLLogger(testInfoOutputStream, true));
994 
995         final File tmpFile = temporaryFolder.newFile("file.java");
996         final String[] expected = CommonUtils.EMPTY_STRING_ARRAY;
997 
998         verify(checker, tmpFile.getPath(), tmpFile.getPath(), expected);
999 
1000         assertEquals("Close count was not expected",
1001                 1, testInfoOutputStream.getCloseCount());
1002         assertEquals("Flush count was not expected",
1003                 0, testInfoOutputStream.getFlushCount());
1004     }
1005 
1006     @Test
1007     public void testDuplicatedModule() throws Exception {
1008         // we need to test a module with two instances, one with id and the other not
1009         final DefaultConfiguration moduleConfig1 =
1010                 createModuleConfig(NewlineAtEndOfFileCheck.class);
1011         final DefaultConfiguration moduleConfig2 =
1012                 createModuleConfig(NewlineAtEndOfFileCheck.class);
1013         moduleConfig2.addAttribute("id", "ModuleId");
1014         final DefaultConfiguration root = new DefaultConfiguration("root");
1015         root.addChild(moduleConfig1);
1016         root.addChild(moduleConfig2);
1017         final Checker checker = new Checker();
1018         checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader());
1019         checker.configure(root);
1020         // BriefUtLogger does not print the module name or id postfix,
1021         // so we need to set logger manually
1022         final ByteArrayOutputStream out =
1023                 (ByteArrayOutputStream) Whitebox.getInternalState(this, "stream");
1024         final DefaultLogger logger =
1025                 new DefaultLogger(out, true, out, false, new AuditEventDefaultFormatter());
1026         checker.addListener(logger);
1027 
1028         final String path = temporaryFolder.newFile("file.java").getPath();
1029         final String errorMessage =
1030                 getCheckMessage(NewlineAtEndOfFileCheck.class, MSG_KEY_NO_NEWLINE_EOF);
1031         final String[] expected = {
1032             "0: " + errorMessage + " [NewlineAtEndOfFile]",
1033             "0: " + errorMessage + " [ModuleId]",
1034         };
1035 
1036         // super.verify does not work here, for we change the logger
1037         out.flush();
1038         final int errs = checker.process(Collections.singletonList(new File(path)));
1039         final ByteArrayInputStream inputStream =
1040                 new ByteArrayInputStream(out.toByteArray());
1041         try (LineNumberReader lnr = new LineNumberReader(
1042                 new InputStreamReader(inputStream, StandardCharsets.UTF_8))) {
1043             // we need to ignore the unrelated lines
1044             final List<String> actual = lnr.lines()
1045                     .filter(line -> !getCheckMessage(AUDIT_STARTED_MESSAGE).equals(line))
1046                     .filter(line -> !getCheckMessage(AUDIT_FINISHED_MESSAGE).equals(line))
1047                     .limit(expected.length)
1048                     .sorted()
1049                     .collect(Collectors.toList());
1050             Arrays.sort(expected);
1051 
1052             for (int i = 0; i < expected.length; i++) {
1053                 final String expectedResult = "[ERROR] " + path + ":" + expected[i];
1054                 assertEquals("error message " + i, expectedResult, actual.get(i));
1055             }
1056 
1057             assertEquals("unexpected output: " + lnr.readLine(), expected.length, errs);
1058         }
1059 
1060         checker.destroy();
1061     }
1062 
1063     private static class DummyFilter implements Filter {
1064 
1065         @Override
1066         public boolean accept(AuditEvent event) {
1067             return false;
1068         }
1069     }
1070 
1071     private static class DummyFileSetViolationCheck extends AbstractFileSetCheck
1072         implements ExternalResourceHolder {
1073 
1074         @Override
1075         protected void processFiltered(File file, FileText fileText) throws CheckstyleException {
1076             log(0, "test");
1077         }
1078 
1079         @Override
1080         public Set<String> getExternalResourceLocations() {
1081             final Set<String> externalResourceLocation = new HashSet<>(1);
1082             externalResourceLocation.add("non_existent_external_resource.xml");
1083             return externalResourceLocation;
1084         }
1085     }
1086 
1087     private static class DummyFilterSet extends FilterSet implements ExternalResourceHolder {
1088 
1089         @Override
1090         public Set<String> getExternalResourceLocations() {
1091             final Set<String> strings = new HashSet<>();
1092             strings.add("test");
1093             return strings;
1094         }
1095     }
1096 
1097     private static class DynamicalResourceHolderCheck extends AbstractFileSetCheck
1098         implements ExternalResourceHolder {
1099 
1100         private String firstExternalResourceLocation;
1101         private String secondExternalResourceLocation;
1102 
1103         public void setFirstExternalResourceLocation(String firstExternalResourceLocation) {
1104             this.firstExternalResourceLocation = firstExternalResourceLocation;
1105         }
1106 
1107         public void setSecondExternalResourceLocation(String secondExternalResourceLocation) {
1108             this.secondExternalResourceLocation = secondExternalResourceLocation;
1109         }
1110 
1111         @Override
1112         protected void processFiltered(File file, FileText fileText) throws CheckstyleException {
1113             // there is no need in implementation of the method
1114         }
1115 
1116         @Override
1117         public Set<String> getExternalResourceLocations() {
1118             final Set<String> locations = new HashSet<>();
1119             locations.add(firstExternalResourceLocation);
1120             // Attempt to change the behaviour of the check dynamically
1121             if (secondExternalResourceLocation != null) {
1122                 locations.add(secondExternalResourceLocation);
1123             }
1124             return locations;
1125         }
1126     }
1127 
1128     private static class CheckWhichDoesNotRequireCommentNodes extends AbstractCheck {
1129 
1130         /** Number of children of method definition token. */
1131         private static final int METHOD_DEF_CHILD_COUNT = 7;
1132 
1133         @Override
1134         public int[] getDefaultTokens() {
1135             return new int[] {TokenTypes.METHOD_DEF};
1136         }
1137 
1138         @Override
1139         public int[] getAcceptableTokens() {
1140             return new int[] {TokenTypes.METHOD_DEF};
1141         }
1142 
1143         @Override
1144         public int[] getRequiredTokens() {
1145             return new int[] {TokenTypes.METHOD_DEF};
1146         }
1147 
1148         @Override
1149         public void visitToken(DetailAST ast) {
1150             if (ast.findFirstToken(TokenTypes.MODIFIERS).findFirstToken(
1151                     TokenTypes.BLOCK_COMMENT_BEGIN) != null) {
1152                 log(ast, "AST has incorrect structure structure."
1153                     + " The check does not require comment nodes but there were comment nodes"
1154                     + " in the AST.");
1155             }
1156             final int childCount = ast.getChildCount();
1157             if (childCount != METHOD_DEF_CHILD_COUNT) {
1158                 final String msg = String.format(Locale.getDefault(),
1159                     "AST node in no comment tree has wrong number of children. "
1160                             + "Expected is %d but was %d",
1161                     METHOD_DEF_CHILD_COUNT, childCount);
1162                 log(ast, msg);
1163             }
1164             // count children where comment lives
1165             int actualChildCount = 0;
1166             for (DetailAST child = ast.getFirstChild().getFirstChild(); child != null; child =
1167                     child.getNextSibling()) {
1168                 actualChildCount++;
1169             }
1170             final int cacheChildCount = ast.getFirstChild().getChildCount();
1171             if (cacheChildCount != actualChildCount) {
1172                 final String msg = String.format(Locale.getDefault(),
1173                         "AST node with no comment has wrong number of children. "
1174                                 + "Expected is %d but was %d",
1175                         cacheChildCount, actualChildCount);
1176                 log(ast, msg);
1177             }
1178         }
1179     }
1180 
1181     private static class CheckWhichRequiresCommentNodes extends AbstractCheck {
1182 
1183         /** Number of children of method definition token. */
1184         private static final int METHOD_DEF_CHILD_COUNT = 7;
1185 
1186         @Override
1187         public boolean isCommentNodesRequired() {
1188             return true;
1189         }
1190 
1191         @Override
1192         public int[] getDefaultTokens() {
1193             return new int[] {TokenTypes.METHOD_DEF};
1194         }
1195 
1196         @Override
1197         public int[] getAcceptableTokens() {
1198             return new int[] {TokenTypes.METHOD_DEF};
1199         }
1200 
1201         @Override
1202         public int[] getRequiredTokens() {
1203             return new int[] {TokenTypes.METHOD_DEF};
1204         }
1205 
1206         @Override
1207         public void visitToken(DetailAST ast) {
1208             if (ast.findFirstToken(TokenTypes.MODIFIERS).findFirstToken(
1209                     TokenTypes.BLOCK_COMMENT_BEGIN) == null) {
1210                 log(ast, "Incorrect AST structure.");
1211             }
1212             final int childCount = ast.getChildCount();
1213             if (childCount != METHOD_DEF_CHILD_COUNT) {
1214                 final String msg = String.format(Locale.getDefault(),
1215                     "AST node in comment tree has wrong number of children. "
1216                             + "Expected is %d but was %d",
1217                     METHOD_DEF_CHILD_COUNT, childCount);
1218                 log(ast, msg);
1219             }
1220             // count children where comment lives
1221             int actualChildCount = 0;
1222             for (DetailAST child = ast.getFirstChild().getFirstChild(); child != null; child =
1223                     child.getNextSibling()) {
1224                 actualChildCount++;
1225             }
1226             final int cacheChildCount = ast.getFirstChild().getChildCount();
1227             if (cacheChildCount != actualChildCount) {
1228                 final String msg = String.format(Locale.getDefault(),
1229                         "AST node with comment has wrong number of children. "
1230                                 + "Expected is %d but was %d",
1231                         cacheChildCount, actualChildCount);
1232                 log(ast, msg);
1233             }
1234         }
1235     }
1236 
1237     private static class CheckWhichThrowsError extends AbstractCheck {
1238 
1239         @Override
1240         public int[] getDefaultTokens() {
1241             return new int[] {TokenTypes.CLASS_DEF};
1242         }
1243 
1244         @Override
1245         public int[] getAcceptableTokens() {
1246             return new int[] {TokenTypes.CLASS_DEF};
1247         }
1248 
1249         @Override
1250         public int[] getRequiredTokens() {
1251             return new int[] {TokenTypes.CLASS_DEF};
1252         }
1253 
1254         @Override
1255         public void visitToken(DetailAST ast) {
1256             throw new IndexOutOfBoundsException("test");
1257         }
1258     }
1259 
1260     private static class DummyFileSet extends AbstractFileSetCheck {
1261 
1262         private final List<String> methodCalls = new ArrayList<>();
1263 
1264         private boolean initCalled;
1265 
1266         @Override
1267         public void init() {
1268             super.init();
1269             initCalled = true;
1270         }
1271 
1272         @Override
1273         public void beginProcessing(String charset) {
1274             methodCalls.add("beginProcessing");
1275             super.beginProcessing(charset);
1276         }
1277 
1278         @Override
1279         public void finishProcessing() {
1280             methodCalls.add("finishProcessing");
1281             super.finishProcessing();
1282         }
1283 
1284         @Override
1285         protected void processFiltered(File file, FileText fileText) throws CheckstyleException {
1286             methodCalls.add("processFiltered");
1287         }
1288 
1289         @Override
1290         public void destroy() {
1291             methodCalls.add("destroy");
1292             super.destroy();
1293         }
1294 
1295         public List<String> getMethodCalls() {
1296             return Collections.unmodifiableList(methodCalls);
1297         }
1298 
1299         public boolean isInitCalled() {
1300             return initCalled;
1301         }
1302 
1303         public MessageDispatcher getInternalMessageDispatcher() {
1304             return getMessageDispatcher();
1305         }
1306     }
1307 }