| //////////////////////////////////////////////////////////////////////////////// |
| // checkstyle: Checks Java source code for adherence to a set of rules. |
| // Copyright (C) 2001-2017 the original author or authors. |
| // |
| // This library is free software; you can redistribute it and/or |
| // modify it under the terms of the GNU Lesser General Public |
| // License as published by the Free Software Foundation; either |
| // version 2.1 of the License, or (at your option) any later version. |
| // |
| // This library is distributed in the hope that it will be useful, |
| // but WITHOUT ANY WARRANTY; without even the implied warranty of |
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| // Lesser General Public License for more details. |
| // |
| // You should have received a copy of the GNU Lesser General Public |
| // License along with this library; if not, write to the Free Software |
| // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| //////////////////////////////////////////////////////////////////////////////// |
| |
| package com.puppycrawl.tools.checkstyle; |
| |
| import static com.puppycrawl.tools.checkstyle.Checker.EXCEPTION_MSG; |
| import static com.puppycrawl.tools.checkstyle.DefaultLogger.AUDIT_FINISHED_MESSAGE; |
| import static com.puppycrawl.tools.checkstyle.DefaultLogger.AUDIT_STARTED_MESSAGE; |
| import static com.puppycrawl.tools.checkstyle.checks.NewlineAtEndOfFileCheck.MSG_KEY_NO_NEWLINE_EOF; |
| import static org.hamcrest.CoreMatchers.instanceOf; |
| import static org.junit.Assert.assertArrayEquals; |
| import static org.junit.Assert.assertEquals; |
| import static org.junit.Assert.assertFalse; |
| import static org.junit.Assert.assertNotNull; |
| import static org.junit.Assert.assertNull; |
| import static org.junit.Assert.assertThat; |
| import static org.junit.Assert.assertTrue; |
| import static org.junit.Assert.fail; |
| import static org.mockito.Mockito.when; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOError; |
| import java.io.IOException; |
| import java.io.InputStreamReader; |
| import java.io.LineNumberReader; |
| import java.io.UnsupportedEncodingException; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Method; |
| import java.nio.charset.StandardCharsets; |
| import java.nio.file.Files; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.List; |
| import java.util.Locale; |
| import java.util.Properties; |
| import java.util.Set; |
| import java.util.SortedSet; |
| import java.util.TreeSet; |
| import java.util.stream.Collectors; |
| |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.rules.TemporaryFolder; |
| import org.mockito.internal.util.reflection.Whitebox; |
| import org.powermock.api.mockito.PowerMockito; |
| |
| import com.puppycrawl.tools.checkstyle.api.AbstractCheck; |
| import com.puppycrawl.tools.checkstyle.api.AbstractFileSetCheck; |
| import com.puppycrawl.tools.checkstyle.api.AuditEvent; |
| import com.puppycrawl.tools.checkstyle.api.AuditListener; |
| import com.puppycrawl.tools.checkstyle.api.CheckstyleException; |
| import com.puppycrawl.tools.checkstyle.api.Configuration; |
| import com.puppycrawl.tools.checkstyle.api.Context; |
| import com.puppycrawl.tools.checkstyle.api.DetailAST; |
| import com.puppycrawl.tools.checkstyle.api.ExternalResourceHolder; |
| import com.puppycrawl.tools.checkstyle.api.FileText; |
| import com.puppycrawl.tools.checkstyle.api.Filter; |
| import com.puppycrawl.tools.checkstyle.api.FilterSet; |
| import com.puppycrawl.tools.checkstyle.api.LocalizedMessage; |
| import com.puppycrawl.tools.checkstyle.api.MessageDispatcher; |
| import com.puppycrawl.tools.checkstyle.api.TokenTypes; |
| import com.puppycrawl.tools.checkstyle.checks.NewlineAtEndOfFileCheck; |
| import com.puppycrawl.tools.checkstyle.checks.TranslationCheck; |
| import com.puppycrawl.tools.checkstyle.checks.coding.HiddenFieldCheck; |
| import com.puppycrawl.tools.checkstyle.filters.SuppressionFilter; |
| import com.puppycrawl.tools.checkstyle.internal.testmodules.DebugAuditAdapter; |
| import com.puppycrawl.tools.checkstyle.internal.testmodules.DebugFilter; |
| import com.puppycrawl.tools.checkstyle.internal.testmodules.TestBeforeExecutionFileFilter; |
| import com.puppycrawl.tools.checkstyle.internal.testmodules.TestFileSetCheck; |
| import com.puppycrawl.tools.checkstyle.internal.utils.CloseAndFlushTestByteArrayOutputStream; |
| import com.puppycrawl.tools.checkstyle.utils.CommonUtils; |
| |
| public class CheckerTest extends AbstractModuleTestSupport { |
| |
| @Rule |
| public final TemporaryFolder temporaryFolder = new TemporaryFolder(); |
| |
| private static Method getFireAuditFinished() throws NoSuchMethodException { |
| final Class<Checker> checkerClass = Checker.class; |
| final Method fireAuditFinished = checkerClass.getDeclaredMethod("fireAuditFinished"); |
| fireAuditFinished.setAccessible(true); |
| return fireAuditFinished; |
| } |
| |
| private static Method getFireAuditStartedMethod() throws NoSuchMethodException { |
| final Class<Checker> checkerClass = Checker.class; |
| final Method fireAuditStarted = checkerClass.getDeclaredMethod("fireAuditStarted"); |
| fireAuditStarted.setAccessible(true); |
| return fireAuditStarted; |
| } |
| |
| @Override |
| protected String getPackageLocation() { |
| return "com/puppycrawl/tools/checkstyle/checker"; |
| } |
| |
| @Test |
| public void testDestroy() throws Exception { |
| final Checker checker = new Checker(); |
| final DebugAuditAdapter auditAdapter = new DebugAuditAdapter(); |
| checker.addListener(auditAdapter); |
| final TestFileSetCheck fileSet = new TestFileSetCheck(); |
| checker.addFileSetCheck(fileSet); |
| final DebugFilter filter = new DebugFilter(); |
| checker.addFilter(filter); |
| final TestBeforeExecutionFileFilter fileFilter = new TestBeforeExecutionFileFilter(); |
| checker.addBeforeExecutionFileFilter(fileFilter); |
| |
| // should remove all listeners, file sets, and filters |
| checker.destroy(); |
| |
| checker.process(Collections.singletonList(temporaryFolder.newFile())); |
| final SortedSet<LocalizedMessage> messages = new TreeSet<>(); |
| messages.add(new LocalizedMessage(0, 0, "a Bundle", "message.key", |
| new Object[] {"arg"}, null, getClass(), null)); |
| checker.fireErrors("Some File Name", messages); |
| |
| assertFalse("Checker.destroy() doesn't remove listeners.", auditAdapter.wasCalled()); |
| assertFalse("Checker.destroy() doesn't remove file sets.", fileSet.wasCalled()); |
| assertFalse("Checker.destroy() doesn't remove filters.", filter.wasCalled()); |
| assertFalse("Checker.destroy() doesn't remove file filters.", fileFilter.wasCalled()); |
| } |
| |
| @Test |
| public void testAddListener() throws Exception { |
| final Checker checker = new Checker(); |
| final DebugAuditAdapter auditAdapter = new DebugAuditAdapter(); |
| checker.addListener(auditAdapter); |
| |
| // Let's try fire some events |
| getFireAuditStartedMethod().invoke(checker); |
| assertTrue("Checker.fireAuditStarted() doesn't call listener", auditAdapter.wasCalled()); |
| |
| auditAdapter.resetListener(); |
| getFireAuditFinished().invoke(checker); |
| assertTrue("Checker.fireAuditFinished() doesn't call listener", auditAdapter.wasCalled()); |
| |
| auditAdapter.resetListener(); |
| checker.fireFileStarted("Some File Name"); |
| assertTrue("Checker.fireFileStarted() doesn't call listener", auditAdapter.wasCalled()); |
| |
| auditAdapter.resetListener(); |
| checker.fireFileFinished("Some File Name"); |
| assertTrue("Checker.fireFileFinished() doesn't call listener", auditAdapter.wasCalled()); |
| |
| auditAdapter.resetListener(); |
| final SortedSet<LocalizedMessage> messages = new TreeSet<>(); |
| messages.add(new LocalizedMessage(0, 0, "a Bundle", "message.key", |
| new Object[] {"arg"}, null, getClass(), null)); |
| checker.fireErrors("Some File Name", messages); |
| assertTrue("Checker.fireErrors() doesn't call listener", auditAdapter.wasCalled()); |
| } |
| |
| @Test |
| public void testRemoveListener() throws Exception { |
| final Checker checker = new Checker(); |
| final DebugAuditAdapter auditAdapter = new DebugAuditAdapter(); |
| final DebugAuditAdapter aa2 = new DebugAuditAdapter(); |
| checker.addListener(auditAdapter); |
| checker.addListener(aa2); |
| checker.removeListener(auditAdapter); |
| |
| // Let's try fire some events |
| getFireAuditStartedMethod().invoke(checker); |
| assertTrue("Checker.fireAuditStarted() doesn't call listener", aa2.wasCalled()); |
| assertFalse("Checker.fireAuditStarted() does call removed listener", |
| auditAdapter.wasCalled()); |
| |
| aa2.resetListener(); |
| getFireAuditFinished().invoke(checker); |
| assertTrue("Checker.fireAuditFinished() doesn't call listener", aa2.wasCalled()); |
| assertFalse("Checker.fireAuditFinished() does call removed listener", |
| auditAdapter.wasCalled()); |
| |
| aa2.resetListener(); |
| checker.fireFileStarted("Some File Name"); |
| assertTrue("Checker.fireFileStarted() doesn't call listener", aa2.wasCalled()); |
| assertFalse("Checker.fireFileStarted() does call removed listener", |
| auditAdapter.wasCalled()); |
| |
| aa2.resetListener(); |
| checker.fireFileFinished("Some File Name"); |
| assertTrue("Checker.fireFileFinished() doesn't call listener", aa2.wasCalled()); |
| assertFalse("Checker.fireFileFinished() does call removed listener", |
| auditAdapter.wasCalled()); |
| |
| aa2.resetListener(); |
| final SortedSet<LocalizedMessage> messages = new TreeSet<>(); |
| messages.add(new LocalizedMessage(0, 0, "a Bundle", "message.key", |
| new Object[] {"arg"}, null, getClass(), null)); |
| checker.fireErrors("Some File Name", messages); |
| assertTrue("Checker.fireErrors() doesn't call listener", aa2.wasCalled()); |
| assertFalse("Checker.fireErrors() does call removed listener", auditAdapter.wasCalled()); |
| |
| } |
| |
| @Test |
| public void testAddBeforeExecutionFileFilter() throws Exception { |
| final Checker checker = new Checker(); |
| final TestBeforeExecutionFileFilter filter = new TestBeforeExecutionFileFilter(); |
| |
| checker.addBeforeExecutionFileFilter(filter); |
| |
| filter.resetFilter(); |
| checker.process(Collections.singletonList(new File("dummy.java"))); |
| assertTrue("Checker.acceptFileStarted() doesn't call filter", filter.wasCalled()); |
| } |
| |
| @Test |
| public void testRemoveBeforeExecutionFileFilter() throws Exception { |
| final Checker checker = new Checker(); |
| final TestBeforeExecutionFileFilter filter = new TestBeforeExecutionFileFilter(); |
| final TestBeforeExecutionFileFilter f2 = new TestBeforeExecutionFileFilter(); |
| checker.addBeforeExecutionFileFilter(filter); |
| checker.addBeforeExecutionFileFilter(f2); |
| checker.removeBeforeExecutionFileFilter(filter); |
| |
| f2.resetFilter(); |
| checker.process(Collections.singletonList(new File("dummy.java"))); |
| assertTrue("Checker.acceptFileStarted() doesn't call filter", f2.wasCalled()); |
| assertFalse("Checker.acceptFileStarted() does call removed filter", filter.wasCalled()); |
| } |
| |
| @Test |
| public void testAddFilter() { |
| final Checker checker = new Checker(); |
| final DebugFilter filter = new DebugFilter(); |
| |
| checker.addFilter(filter); |
| |
| filter.resetFilter(); |
| final SortedSet<LocalizedMessage> messages = new TreeSet<>(); |
| messages.add(new LocalizedMessage(0, 0, "a Bundle", "message.key", |
| new Object[] {"arg"}, null, getClass(), null)); |
| checker.fireErrors("Some File Name", messages); |
| assertTrue("Checker.fireErrors() doesn't call filter", filter.wasCalled()); |
| } |
| |
| @Test |
| public void testRemoveFilter() { |
| final Checker checker = new Checker(); |
| final DebugFilter filter = new DebugFilter(); |
| final DebugFilter f2 = new DebugFilter(); |
| checker.addFilter(filter); |
| checker.addFilter(f2); |
| checker.removeFilter(filter); |
| |
| f2.resetFilter(); |
| final SortedSet<LocalizedMessage> messages = new TreeSet<>(); |
| messages.add(new LocalizedMessage(0, 0, "a Bundle", "message.key", |
| new Object[] {"arg"}, null, getClass(), null)); |
| checker.fireErrors("Some File Name", messages); |
| assertTrue("Checker.fireErrors() doesn't call filter", f2.wasCalled()); |
| assertFalse("Checker.fireErrors() does call removed filter", filter.wasCalled()); |
| |
| } |
| |
| @Test |
| public void testFileExtensions() throws Exception { |
| final DefaultConfiguration checkerConfig = new DefaultConfiguration("configuration"); |
| checkerConfig.addAttribute("charset", StandardCharsets.UTF_8.name()); |
| checkerConfig.addAttribute("cacheFile", temporaryFolder.newFile().getPath()); |
| |
| final Checker checker = new Checker(); |
| checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader()); |
| checker.configure(checkerConfig); |
| |
| final DebugAuditAdapter auditAdapter = new DebugAuditAdapter(); |
| checker.addListener(auditAdapter); |
| |
| final List<File> files = new ArrayList<>(); |
| final File file = new File("file.pdf"); |
| files.add(file); |
| final File otherFile = new File("file.java"); |
| files.add(otherFile); |
| final String[] fileExtensions = {"java", "xml", "properties"}; |
| checker.setFileExtensions(fileExtensions); |
| checker.setCacheFile(temporaryFolder.newFile().getPath()); |
| final int counter = checker.process(files); |
| |
| // comparing to 1 as there is only one legal file in input |
| final int numLegalFiles = 1; |
| final PropertyCacheFile cache = |
| (PropertyCacheFile) Whitebox.getInternalState(checker, "cache"); |
| assertEquals("There were more legal files than expected", |
| numLegalFiles, counter); |
| assertEquals("Audit was started on larger amount of files than expected", |
| numLegalFiles, auditAdapter.getNumFilesStarted()); |
| assertEquals("Audit was finished on larger amount of files than expected", |
| numLegalFiles, auditAdapter.getNumFilesFinished()); |
| assertNull("Cache shout not contain any file", |
| cache.get(new File("file.java").getCanonicalPath())); |
| } |
| |
| @Test |
| public void testIgnoredFileExtensions() throws Exception { |
| final DefaultConfiguration checkerConfig = new DefaultConfiguration("configuration"); |
| checkerConfig.addAttribute("charset", StandardCharsets.UTF_8.name()); |
| checkerConfig.addAttribute("cacheFile", temporaryFolder.newFile().getPath()); |
| |
| final Checker checker = new Checker(); |
| checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader()); |
| checker.configure(checkerConfig); |
| |
| final DebugAuditAdapter auditAdapter = new DebugAuditAdapter(); |
| checker.addListener(auditAdapter); |
| |
| final List<File> allIgnoredFiles = new ArrayList<>(); |
| final File ignoredFile = new File("file.pdf"); |
| allIgnoredFiles.add(ignoredFile); |
| final String[] fileExtensions = {"java", "xml", "properties"}; |
| checker.setFileExtensions(fileExtensions); |
| checker.setCacheFile(temporaryFolder.newFile().getPath()); |
| final int counter = checker.process(allIgnoredFiles); |
| |
| // comparing to 0 as there is no legal file in input |
| final int numLegalFiles = 0; |
| assertEquals("There were more legal files than expected", |
| numLegalFiles, counter); |
| assertEquals("Audit was started on larger amount of files than expected", |
| numLegalFiles, auditAdapter.getNumFilesStarted()); |
| assertEquals("Audit was finished on larger amount of files than expected", |
| numLegalFiles, auditAdapter.getNumFilesFinished()); |
| } |
| |
| @Test |
| public void testSetters() { |
| // all that is set by reflection, so just make code coverage be happy |
| final Checker checker = new Checker(); |
| checker.setClassLoader(getClass().getClassLoader()); |
| checker.setBasedir("some"); |
| checker.setSeverity("ignore"); |
| |
| final PackageObjectFactory factory = new PackageObjectFactory( |
| new HashSet<>(), Thread.currentThread().getContextClassLoader()); |
| checker.setModuleFactory(factory); |
| |
| checker.setFileExtensions((String[]) null); |
| checker.setFileExtensions(".java", "xml"); |
| |
| try { |
| checker.setCharset("UNKNOWN-CHARSET"); |
| fail("Exception is expected"); |
| } |
| catch (UnsupportedEncodingException ex) { |
| assertEquals("Error message is not expected", |
| "unsupported charset: 'UNKNOWN-CHARSET'", ex.getMessage()); |
| } |
| } |
| |
| @Test |
| public void testNoClassLoaderNoModuleFactory() { |
| final Checker checker = new Checker(); |
| |
| try { |
| checker.finishLocalSetup(); |
| fail("Exception is expected"); |
| } |
| catch (CheckstyleException ex) { |
| assertEquals("Error message is not expected", |
| "if no custom moduleFactory is set, moduleClassLoader must be specified", |
| ex.getMessage()); |
| } |
| } |
| |
| @Test |
| public void testNoModuleFactory() throws Exception { |
| final Checker checker = new Checker(); |
| final ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); |
| |
| checker.setModuleClassLoader(classLoader); |
| checker.finishLocalSetup(); |
| final Context actualCtx = (Context) Whitebox.getInternalState(checker, "childContext"); |
| |
| assertNotNull("Default module factory should be created when it is not specified", |
| actualCtx.get("moduleFactory")); |
| assertEquals("Invalid classLoader", classLoader, actualCtx.get("classLoader")); |
| } |
| |
| @Test |
| public void testFinishLocalSetupFullyInitialized() throws Exception { |
| final Checker checker = new Checker(); |
| final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader(); |
| checker.setModuleClassLoader(contextClassLoader); |
| final PackageObjectFactory factory = new PackageObjectFactory( |
| new HashSet<>(), contextClassLoader); |
| checker.setModuleFactory(factory); |
| checker.setBasedir("testBaseDir"); |
| checker.setLocaleLanguage("it"); |
| checker.setLocaleCountry("IT"); |
| checker.finishLocalSetup(); |
| |
| final Context context = (Context) Whitebox.getInternalState(checker, "childContext"); |
| assertEquals("Charset was different than expected", |
| System.getProperty("file.encoding", StandardCharsets.UTF_8.name()), |
| context.get("charset")); |
| assertEquals("Was used unsufficient classloader", |
| contextClassLoader, context.get("classLoader")); |
| assertEquals("Severity is set to unexpected value", |
| "error", context.get("severity")); |
| assertEquals("Basedir is set to unexpected value", |
| "testBaseDir", context.get("basedir")); |
| |
| final Field sLocale = LocalizedMessage.class.getDeclaredField("sLocale"); |
| sLocale.setAccessible(true); |
| final Locale locale = (Locale) sLocale.get(null); |
| assertEquals("Locale is set to unexpected value", Locale.ITALY, locale); |
| } |
| |
| @Test |
| public void testSetupChildExceptions() { |
| final Checker checker = new Checker(); |
| final PackageObjectFactory factory = new PackageObjectFactory( |
| new HashSet<>(), Thread.currentThread().getContextClassLoader()); |
| checker.setModuleFactory(factory); |
| |
| final Configuration config = new DefaultConfiguration("java.lang.String"); |
| try { |
| checker.setupChild(config); |
| fail("Exception is expected"); |
| } |
| catch (CheckstyleException ex) { |
| assertEquals("Error message is not expected", |
| "java.lang.String is not allowed as a child in Checker", ex.getMessage()); |
| } |
| } |
| |
| @Test |
| @SuppressWarnings("unchecked") |
| public void testSetupChildListener() throws Exception { |
| final Checker checker = new Checker(); |
| final PackageObjectFactory factory = new PackageObjectFactory( |
| new HashSet<>(), Thread.currentThread().getContextClassLoader()); |
| checker.setModuleFactory(factory); |
| |
| final Configuration config = new DefaultConfiguration( |
| DebugAuditAdapter.class.getCanonicalName()); |
| checker.setupChild(config); |
| |
| final List<AuditListener> listeners = |
| (List<AuditListener>) Whitebox.getInternalState(checker, "listeners"); |
| assertTrue("Invalid child listener class", |
| listeners.get(listeners.size() - 1) instanceof DebugAuditAdapter); |
| |
| } |
| |
| @Test |
| public void testDestroyCheckerWithWrongCacheFileNameLength() throws Exception { |
| final Checker checker = new Checker(); |
| final PackageObjectFactory factory = new PackageObjectFactory( |
| new HashSet<>(), Thread.currentThread().getContextClassLoader()); |
| checker.setModuleFactory(factory); |
| checker.configure(new DefaultConfiguration("default config")); |
| // We set wrong file name length in order to reproduce IOException on OS Linux, OS Windows. |
| // The maximum file name length which is allowed in most UNIX, Windows file systems is 255. |
| // See https://en.wikipedia.org/wiki/Filename; |
| checker.setCacheFile(String.format(Locale.ENGLISH, "%0300d", 0)); |
| try { |
| checker.destroy(); |
| fail("Exception did not happen"); |
| } |
| catch (IllegalStateException ex) { |
| assertTrue("Cause of exception differs from IOException", |
| ex.getCause() instanceof IOException); |
| } |
| } |
| |
| /** |
| * It is OK to have long test method name here as it describes the test purpose. |
| * @noinspection InstanceMethodNamingConvention |
| */ |
| @Test |
| public void testCacheAndCheckWhichDoesNotImplementExternalResourceHolderInterface() |
| throws Exception { |
| assertFalse("ExternalResourceHolder has changed his parent", |
| ExternalResourceHolder.class.isAssignableFrom(HiddenFieldCheck.class)); |
| final DefaultConfiguration checkConfig = createModuleConfig(HiddenFieldCheck.class); |
| |
| final DefaultConfiguration treeWalkerConfig = createModuleConfig(TreeWalker.class); |
| treeWalkerConfig.addChild(checkConfig); |
| |
| final DefaultConfiguration checkerConfig = createRootConfig(treeWalkerConfig); |
| checkerConfig.addAttribute("charset", StandardCharsets.UTF_8.name()); |
| |
| final File cacheFile = temporaryFolder.newFile(); |
| checkerConfig.addAttribute("cacheFile", cacheFile.getPath()); |
| |
| final File tmpFile = temporaryFolder.newFile("file.java"); |
| final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; |
| |
| verify(checkerConfig, tmpFile.getPath(), expected); |
| final Properties cacheAfterFirstRun = new Properties(); |
| cacheAfterFirstRun.load(Files.newBufferedReader(cacheFile.toPath())); |
| |
| // one more time to reuse cache |
| verify(checkerConfig, tmpFile.getPath(), expected); |
| final Properties cacheAfterSecondRun = new Properties(); |
| cacheAfterSecondRun.load(Files.newBufferedReader(cacheFile.toPath())); |
| |
| assertEquals("Cache from first run differs from second run cache", |
| cacheAfterFirstRun, cacheAfterSecondRun); |
| } |
| |
| @Test |
| public void testWithCacheWithNoViolation() throws Exception { |
| final Checker checker = new Checker(); |
| final PackageObjectFactory factory = new PackageObjectFactory( |
| new HashSet<>(), Thread.currentThread().getContextClassLoader()); |
| checker.setModuleFactory(factory); |
| checker.configure(createModuleConfig(TranslationCheck.class)); |
| |
| final File cacheFile = temporaryFolder.newFile(); |
| checker.setCacheFile(cacheFile.getPath()); |
| |
| checker.setupChild(createModuleConfig(TranslationCheck.class)); |
| final File tmpFile = temporaryFolder.newFile("file.java"); |
| final List<File> files = new ArrayList<>(1); |
| files.add(tmpFile); |
| checker.process(files); |
| |
| // invoke destroy to persist cache |
| checker.destroy(); |
| |
| final Properties cache = new Properties(); |
| cache.load(Files.newBufferedReader(cacheFile.toPath())); |
| |
| // There should 2 objects in cache: processed file (file.java) and checker configuration. |
| final int expectedNumberOfObjectsInCache = 2; |
| assertEquals("Cache has unexpected size", |
| expectedNumberOfObjectsInCache, cache.size()); |
| |
| final String expectedConfigHash = "B8535A811CA90BE8B7A14D40BCA62B4FC2447B46"; |
| assertEquals("Cache has unexpected hash", |
| expectedConfigHash, cache.getProperty(PropertyCacheFile.CONFIG_HASH_KEY)); |
| |
| assertNotNull("Cache file has null path", |
| cache.getProperty(tmpFile.getPath())); |
| } |
| |
| @Test |
| public void testClearExistingCache() throws Exception { |
| final DefaultConfiguration checkerConfig = createRootConfig(null); |
| checkerConfig.addAttribute("charset", StandardCharsets.UTF_8.name()); |
| final File cacheFile = temporaryFolder.newFile(); |
| checkerConfig.addAttribute("cacheFile", cacheFile.getPath()); |
| |
| final Checker checker = new Checker(); |
| checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader()); |
| checker.configure(checkerConfig); |
| checker.addListener(getBriefUtLogger()); |
| |
| checker.clearCache(); |
| // invoke destroy to persist cache |
| checker.destroy(); |
| |
| final Properties cacheAfterClear = new Properties(); |
| cacheAfterClear.load(Files.newBufferedReader(cacheFile.toPath())); |
| |
| assertEquals("Cache has unexpected size", |
| 1, cacheAfterClear.size()); |
| assertNotNull("Cache has null hash", |
| cacheAfterClear.getProperty(PropertyCacheFile.CONFIG_HASH_KEY)); |
| |
| final String pathToEmptyFile = temporaryFolder.newFile("file.java").getPath(); |
| final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; |
| |
| // file that should be audited is not in cache |
| verify(checker, pathToEmptyFile, pathToEmptyFile, expected); |
| final Properties cacheAfterSecondRun = new Properties(); |
| cacheAfterSecondRun.load(Files.newBufferedReader(cacheFile.toPath())); |
| |
| assertNotNull("Cache has null path", |
| cacheAfterSecondRun.getProperty(pathToEmptyFile)); |
| assertEquals("Cash have changed it hash", |
| cacheAfterClear.getProperty(PropertyCacheFile.CONFIG_HASH_KEY), |
| cacheAfterSecondRun.getProperty(PropertyCacheFile.CONFIG_HASH_KEY) |
| ); |
| final int expectedNumberOfObjectsInCacheAfterSecondRun = 2; |
| assertEquals("Cache has changed number of items", |
| expectedNumberOfObjectsInCacheAfterSecondRun, cacheAfterSecondRun.size()); |
| } |
| |
| @Test |
| public void testClearCache() throws Exception { |
| final DefaultConfiguration violationCheck = |
| createModuleConfig(DummyFileSetViolationCheck.class); |
| final DefaultConfiguration checkerConfig = new DefaultConfiguration("myConfig"); |
| checkerConfig.addAttribute("charset", "UTF-8"); |
| final File cacheFile = temporaryFolder.newFile(); |
| checkerConfig.addAttribute("cacheFile", cacheFile.getPath()); |
| checkerConfig.addChild(violationCheck); |
| final Checker checker = new Checker(); |
| checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader()); |
| checker.configure(checkerConfig); |
| checker.addListener(getBriefUtLogger()); |
| |
| checker.process(Collections.singletonList(new File("dummy.java"))); |
| checker.clearCache(); |
| // invoke destroy to persist cache |
| final PropertyCacheFile cache = |
| (PropertyCacheFile) Whitebox.getInternalState(checker, "cache"); |
| cache.persist(); |
| |
| final Properties cacheAfterClear = new Properties(); |
| cacheAfterClear.load(Files.newBufferedReader(cacheFile.toPath())); |
| |
| assertEquals("Cache has unexpected size", |
| 1, cacheAfterClear.size()); |
| } |
| |
| @Test |
| public void setFileExtension() { |
| final Checker checker = new Checker(); |
| checker.setFileExtensions(".test1", "test2"); |
| final String[] actual = |
| (String[]) Whitebox.getInternalState(checker, "fileExtensions"); |
| assertArrayEquals("Extensions are not expected", |
| new String[] {".test1", ".test2"}, actual); |
| } |
| |
| @Test |
| public void testClearCacheWhenCacheFileIsNotSet() { |
| // The idea of the test is to check that when cache file is not set, |
| // the invocation of clearCache method does not throw an exception. |
| final Checker checker = new Checker(); |
| checker.clearCache(); |
| assertNull("If cache file is not set the cache should default to null", |
| Whitebox.getInternalState(checker, "cache")); |
| } |
| |
| @Test |
| public void testCatchErrorInProcessFilesMethod() throws Exception { |
| // The idea of the test is to satisfy coverage rate. |
| // An Error indicates serious problems that a reasonable application should not try to |
| // catch, but due to issue https://github.com/checkstyle/checkstyle/issues/2285 |
| // we catch errors in 'processFiles' method. Most such errors are abnormal conditions, |
| // that is why we use PowerMockito to reproduce them. |
| final File mock = PowerMockito.mock(File.class); |
| // Assume that I/O error is happened when we try to invoke 'lastModified()' method. |
| final String errorMessage = "Java Virtual Machine is broken" |
| + " or has run out of resources necessary for it to continue operating."; |
| final Error expectedError = new IOError(new InternalError(errorMessage)); |
| when(mock.lastModified()).thenThrow(expectedError); |
| final Checker checker = new Checker(); |
| final List<File> filesToProcess = new ArrayList<>(); |
| filesToProcess.add(mock); |
| try { |
| checker.process(filesToProcess); |
| fail("IOError is expected!"); |
| } |
| // -@cs[IllegalCatchExtended] Testing for catch Error is part of 100% coverage. |
| catch (Error error) { |
| assertThat("Error cause differs from IOError", |
| error.getCause(), instanceOf(IOError.class)); |
| assertThat("Error cause is not InternalError", |
| error.getCause().getCause(), instanceOf(InternalError.class)); |
| assertEquals("Error message is not expected", |
| errorMessage, error.getCause().getCause().getMessage()); |
| } |
| } |
| |
| /** |
| * It is OK to have long test method name here as it describes the test purpose. |
| * @noinspection InstanceMethodNamingConvention |
| */ |
| @Test |
| public void testCacheAndFilterWhichDoesNotImplementExternalResourceHolderInterface() |
| throws Exception { |
| assertFalse("ExternalResourceHolder has changed its parent", |
| ExternalResourceHolder.class.isAssignableFrom(DummyFilter.class)); |
| final DefaultConfiguration filterConfig = createModuleConfig(DummyFilter.class); |
| |
| final DefaultConfiguration checkerConfig = createRootConfig(filterConfig); |
| final File cacheFile = temporaryFolder.newFile(); |
| checkerConfig.addAttribute("cacheFile", cacheFile.getPath()); |
| |
| final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; |
| final String pathToEmptyFile = temporaryFolder.newFile("file.java").getPath(); |
| |
| verify(checkerConfig, pathToEmptyFile, expected); |
| final Properties cacheAfterFirstRun = new Properties(); |
| cacheAfterFirstRun.load(Files.newBufferedReader(cacheFile.toPath())); |
| |
| // One more time to use cache. |
| verify(checkerConfig, pathToEmptyFile, expected); |
| final Properties cacheAfterSecondRun = new Properties(); |
| cacheAfterSecondRun.load(Files.newBufferedReader(cacheFile.toPath())); |
| |
| assertEquals( |
| "Cache file has changed its path", |
| cacheAfterFirstRun.getProperty(pathToEmptyFile), |
| cacheAfterSecondRun.getProperty(pathToEmptyFile) |
| ); |
| assertEquals( |
| "Cache has changed its hash", |
| cacheAfterFirstRun.getProperty(PropertyCacheFile.CONFIG_HASH_KEY), |
| cacheAfterSecondRun.getProperty(PropertyCacheFile.CONFIG_HASH_KEY) |
| ); |
| final int expectedNumberOfObjectsInCache = 2; |
| assertEquals("Number of items in cache differs from expected", |
| expectedNumberOfObjectsInCache, cacheAfterFirstRun.size()); |
| assertEquals("Number of items in cache differs from expected", |
| expectedNumberOfObjectsInCache, cacheAfterSecondRun.size()); |
| } |
| |
| /** |
| * It is OK to have long test method name here as it describes the test purpose. |
| * @noinspection InstanceMethodNamingConvention |
| */ |
| // -@cs[ExecutableStatementCount] This test needs to verify many things. |
| @Test |
| public void testCacheAndCheckWhichAddsNewResourceLocationButKeepsSameCheckerInstance() |
| throws Exception { |
| |
| // Use case (https://github.com/checkstyle/checkstyle/pull/3092#issuecomment-218162436): |
| // Imagine that cache exists in a file. New version of Checkstyle appear. |
| // New release contains update to a some check to have additional external resource. |
| // User update his configuration and run validation as usually. |
| // Cache should not be reused. |
| |
| final DynamicalResourceHolderCheck check = new DynamicalResourceHolderCheck(); |
| final String firstExternalResourceLocation = getPath("InputCheckerImportControlOne.xml"); |
| final String firstExternalResourceKey = PropertyCacheFile.EXTERNAL_RESOURCE_KEY_PREFIX |
| + firstExternalResourceLocation; |
| check.setFirstExternalResourceLocation(firstExternalResourceLocation); |
| |
| final DefaultConfiguration checkerConfig = createRootConfig(null); |
| final File cacheFile = temporaryFolder.newFile(); |
| checkerConfig.addAttribute("cacheFile", cacheFile.getPath()); |
| |
| final Checker checker = new Checker(); |
| checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader()); |
| checker.addFileSetCheck(check); |
| checker.addFilter(new DummyFilterSet()); |
| checker.configure(checkerConfig); |
| checker.addListener(getBriefUtLogger()); |
| |
| final String pathToEmptyFile = temporaryFolder.newFile("file.java").getPath(); |
| final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; |
| |
| verify(checker, pathToEmptyFile, expected); |
| final Properties cacheAfterFirstRun = new Properties(); |
| cacheAfterFirstRun.load(Files.newBufferedReader(cacheFile.toPath())); |
| |
| final int expectedNumberOfObjectsInCacheAfterFirstRun = 4; |
| assertEquals("Number of items in cache differs from expected", |
| expectedNumberOfObjectsInCacheAfterFirstRun, cacheAfterFirstRun.size()); |
| |
| // Change a list of external resources which are used by the check |
| final String secondExternalResourceLocation = "InputCheckerImportControlTwo.xml"; |
| final String secondExternalResourceKey = PropertyCacheFile.EXTERNAL_RESOURCE_KEY_PREFIX |
| + secondExternalResourceLocation; |
| check.setSecondExternalResourceLocation(secondExternalResourceLocation); |
| |
| checker.addFileSetCheck(check); |
| checker.configure(checkerConfig); |
| |
| verify(checker, pathToEmptyFile, expected); |
| final Properties cacheAfterSecondRun = new Properties(); |
| cacheAfterSecondRun.load(Files.newBufferedReader(cacheFile.toPath())); |
| |
| assertEquals("Cache file has changed its path", |
| cacheAfterFirstRun.getProperty(pathToEmptyFile), |
| cacheAfterSecondRun.getProperty(pathToEmptyFile) |
| ); |
| assertEquals( |
| "Cache has changed its hash", |
| cacheAfterFirstRun.getProperty(PropertyCacheFile.CONFIG_HASH_KEY), |
| cacheAfterSecondRun.getProperty(PropertyCacheFile.CONFIG_HASH_KEY) |
| ); |
| assertEquals("Cache has changed its resource key", |
| cacheAfterFirstRun.getProperty(firstExternalResourceKey), |
| cacheAfterSecondRun.getProperty(firstExternalResourceKey) |
| ); |
| assertNotNull("Cache has null as a resource key", |
| cacheAfterFirstRun.getProperty(firstExternalResourceKey)); |
| final int expectedNumberOfObjectsInCacheAfterSecondRun = 4; |
| assertEquals("Number of items in cache differs from expected", |
| expectedNumberOfObjectsInCacheAfterSecondRun, cacheAfterSecondRun.size()); |
| assertNull("Cache has not null as a resource key", |
| cacheAfterFirstRun.getProperty(secondExternalResourceKey)); |
| assertNotNull("Cache has null as a resource key", |
| cacheAfterSecondRun.getProperty(secondExternalResourceKey)); |
| } |
| |
| @Test |
| public void testClearLazyLoadCacheInDetailAST() throws Exception { |
| final DefaultConfiguration checkConfig1 = |
| createModuleConfig(CheckWhichDoesNotRequireCommentNodes.class); |
| final DefaultConfiguration checkConfig2 = |
| createModuleConfig(CheckWhichRequiresCommentNodes.class); |
| |
| final DefaultConfiguration treeWalkerConfig = createModuleConfig(TreeWalker.class); |
| treeWalkerConfig.addChild(checkConfig1); |
| treeWalkerConfig.addChild(checkConfig2); |
| |
| final DefaultConfiguration checkerConfig = createRootConfig(treeWalkerConfig); |
| |
| final String filePath = getPath("InputCheckerClearDetailAstLazyLoadCache.java"); |
| final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; |
| |
| verify(checkerConfig, filePath, expected); |
| } |
| |
| @Test |
| public void testCacheOnViolationSuppression() throws Exception { |
| final File cacheFile = temporaryFolder.newFile(); |
| final DefaultConfiguration violationCheck = |
| createModuleConfig(DummyFileSetViolationCheck.class); |
| |
| final DefaultConfiguration filterConfig = createModuleConfig(SuppressionFilter.class); |
| filterConfig.addAttribute("file", getPath("InputCheckerSuppressAll.xml")); |
| |
| final DefaultConfiguration checkerConfig = createRootConfig(violationCheck); |
| checkerConfig.addAttribute("cacheFile", cacheFile.getPath()); |
| checkerConfig.addChild(filterConfig); |
| |
| final String fileViolationPath = temporaryFolder.newFile("ViolationFile.java").getPath(); |
| final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; |
| |
| verify(checkerConfig, fileViolationPath, expected); |
| |
| try (FileInputStream input = new FileInputStream(cacheFile)) { |
| final Properties details = new Properties(); |
| details.load(input); |
| |
| assertNotNull("suppressed violation file saved in cache", |
| details.getProperty(fileViolationPath)); |
| } |
| } |
| |
| @Test |
| public void testHaltOnExceptionOff() throws Exception { |
| final DefaultConfiguration checkConfig = |
| createModuleConfig(CheckWhichThrowsError.class); |
| |
| final DefaultConfiguration treeWalkerConfig = createModuleConfig(TreeWalker.class); |
| treeWalkerConfig.addChild(checkConfig); |
| |
| final DefaultConfiguration checkerConfig = createRootConfig(treeWalkerConfig); |
| checkerConfig.addChild(treeWalkerConfig); |
| |
| checkerConfig.addAttribute("haltOnException", "false"); |
| |
| final String filePath = getPath("InputChecker.java"); |
| final String[] expected = { |
| "0: " + getCheckMessage(EXCEPTION_MSG, "java.lang.IndexOutOfBoundsException: test"), |
| }; |
| |
| verify(checkerConfig, filePath, expected); |
| } |
| |
| @Test |
| public void testCheckerProcessCallAllNeededMethodsOfFileSets() throws Exception { |
| final DummyFileSet fileSet = new DummyFileSet(); |
| final Checker checker = new Checker(); |
| checker.addFileSetCheck(fileSet); |
| checker.process(Collections.singletonList(new File("dummy.java"))); |
| final List<String> expected = |
| Arrays.asList("beginProcessing", "finishProcessing", "destroy"); |
| assertArrayEquals("Method calls were not expected", |
| expected.toArray(), fileSet.getMethodCalls().toArray()); |
| } |
| |
| @Test |
| public void testSetFileSetCheckSetsMessageDispatcher() { |
| final DummyFileSet fileSet = new DummyFileSet(); |
| final Checker checker = new Checker(); |
| checker.addFileSetCheck(fileSet); |
| assertEquals("Message dispatcher was not expected", |
| checker, fileSet.getInternalMessageDispatcher()); |
| } |
| |
| @Test |
| public void testAddAuditListenerAsChild() throws Exception { |
| final Checker checker = new Checker(); |
| final DebugAuditAdapter auditAdapter = new DebugAuditAdapter(); |
| final PackageObjectFactory factory = new PackageObjectFactory( |
| new HashSet<>(), Thread.currentThread().getContextClassLoader()) { |
| @Override |
| public Object createModule(String name) throws CheckstyleException { |
| Object adapter = auditAdapter; |
| if (!name.equals(DebugAuditAdapter.class.getName())) { |
| adapter = super.createModule(name); |
| } |
| return adapter; |
| } |
| }; |
| checker.setModuleFactory(factory); |
| checker.setupChild(createModuleConfig(DebugAuditAdapter.class)); |
| // Let's try fire some events |
| checker.process(Collections.singletonList(new File("dummy.java"))); |
| assertTrue("Checker.fireAuditStarted() doesn't call listener", auditAdapter.wasCalled()); |
| } |
| |
| @Test |
| public void testAddBeforeExecutionFileFilterAsChild() throws Exception { |
| final Checker checker = new Checker(); |
| final TestBeforeExecutionFileFilter fileFilter = new TestBeforeExecutionFileFilter(); |
| final PackageObjectFactory factory = new PackageObjectFactory( |
| new HashSet<>(), Thread.currentThread().getContextClassLoader()) { |
| @Override |
| public Object createModule(String name) throws CheckstyleException { |
| Object filter = fileFilter; |
| if (!name.equals(TestBeforeExecutionFileFilter.class.getName())) { |
| filter = super.createModule(name); |
| } |
| return filter; |
| } |
| }; |
| checker.setModuleFactory(factory); |
| checker.setupChild(createModuleConfig(TestBeforeExecutionFileFilter.class)); |
| checker.process(Collections.singletonList(new File("dummy.java"))); |
| assertTrue("Checker.acceptFileStarted() doesn't call listener", fileFilter.wasCalled()); |
| } |
| |
| @Test |
| public void testFileSetCheckInitWhenAddedAsChild() throws Exception { |
| final Checker checker = new Checker(); |
| final DummyFileSet fileSet = new DummyFileSet(); |
| final PackageObjectFactory factory = new PackageObjectFactory( |
| new HashSet<>(), Thread.currentThread().getContextClassLoader()) { |
| @Override |
| public Object createModule(String name) throws CheckstyleException { |
| Object check = fileSet; |
| if (!name.equals(DummyFileSet.class.getName())) { |
| check = super.createModule(name); |
| } |
| return check; |
| } |
| }; |
| checker.setModuleFactory(factory); |
| checker.finishLocalSetup(); |
| checker.setupChild(createModuleConfig(DummyFileSet.class)); |
| assertTrue("FileSetCheck.init() wasn't called", fileSet.isInitCalled()); |
| } |
| |
| // -@cs[CheckstyleTestMakeup] must use raw class to directly initialize DefaultLogger |
| @Test |
| public void testDefaultLoggerClosesItStreams() throws Exception { |
| final Checker checker = new Checker(); |
| final CloseAndFlushTestByteArrayOutputStream testInfoOutputStream = |
| new CloseAndFlushTestByteArrayOutputStream(); |
| final CloseAndFlushTestByteArrayOutputStream testErrorOutputStream = |
| new CloseAndFlushTestByteArrayOutputStream(); |
| checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader()); |
| checker.addListener(new DefaultLogger(testInfoOutputStream, |
| true, testErrorOutputStream, true)); |
| |
| final File tmpFile = temporaryFolder.newFile("file.java"); |
| final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; |
| |
| verify(checker, tmpFile.getPath(), expected); |
| |
| assertEquals("Close count was not expected", |
| 1, testInfoOutputStream.getCloseCount()); |
| assertEquals("Flush count was not expected", |
| 3, testInfoOutputStream.getFlushCount()); |
| assertEquals("Close count was not expected", |
| 1, testErrorOutputStream.getCloseCount()); |
| assertEquals("Flush count was not expected", |
| 1, testErrorOutputStream.getFlushCount()); |
| } |
| |
| // -@cs[CheckstyleTestMakeup] must use raw class to directly initialize DefaultLogger |
| @Test |
| public void testXmlLoggerClosesItStreams() throws Exception { |
| final Checker checker = new Checker(); |
| final CloseAndFlushTestByteArrayOutputStream testInfoOutputStream = |
| new CloseAndFlushTestByteArrayOutputStream(); |
| checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader()); |
| checker.addListener(new XMLLogger(testInfoOutputStream, true)); |
| |
| final File tmpFile = temporaryFolder.newFile("file.java"); |
| final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; |
| |
| verify(checker, tmpFile.getPath(), tmpFile.getPath(), expected); |
| |
| assertEquals("Close count was not expected", |
| 1, testInfoOutputStream.getCloseCount()); |
| assertEquals("Flush count was not expected", |
| 0, testInfoOutputStream.getFlushCount()); |
| } |
| |
| @Test |
| public void testDuplicatedModule() throws Exception { |
| // we need to test a module with two instances, one with id and the other not |
| final DefaultConfiguration moduleConfig1 = |
| createModuleConfig(NewlineAtEndOfFileCheck.class); |
| final DefaultConfiguration moduleConfig2 = |
| createModuleConfig(NewlineAtEndOfFileCheck.class); |
| moduleConfig2.addAttribute("id", "ModuleId"); |
| final DefaultConfiguration root = new DefaultConfiguration("root"); |
| root.addChild(moduleConfig1); |
| root.addChild(moduleConfig2); |
| final Checker checker = new Checker(); |
| checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader()); |
| checker.configure(root); |
| // BriefUtLogger does not print the module name or id postfix, |
| // so we need to set logger manually |
| final ByteArrayOutputStream out = |
| (ByteArrayOutputStream) Whitebox.getInternalState(this, "stream"); |
| final DefaultLogger logger = |
| new DefaultLogger(out, true, out, false, new AuditEventDefaultFormatter()); |
| checker.addListener(logger); |
| |
| final String path = temporaryFolder.newFile("file.java").getPath(); |
| final String errorMessage = |
| getCheckMessage(NewlineAtEndOfFileCheck.class, MSG_KEY_NO_NEWLINE_EOF); |
| final String[] expected = { |
| "0: " + errorMessage + " [NewlineAtEndOfFile]", |
| "0: " + errorMessage + " [ModuleId]", |
| }; |
| |
| // super.verify does not work here, for we change the logger |
| out.flush(); |
| final int errs = checker.process(Collections.singletonList(new File(path))); |
| final ByteArrayInputStream inputStream = |
| new ByteArrayInputStream(out.toByteArray()); |
| try (LineNumberReader lnr = new LineNumberReader( |
| new InputStreamReader(inputStream, StandardCharsets.UTF_8))) { |
| // we need to ignore the unrelated lines |
| final List<String> actual = lnr.lines() |
| .filter(line -> !getCheckMessage(AUDIT_STARTED_MESSAGE).equals(line)) |
| .filter(line -> !getCheckMessage(AUDIT_FINISHED_MESSAGE).equals(line)) |
| .limit(expected.length) |
| .sorted() |
| .collect(Collectors.toList()); |
| Arrays.sort(expected); |
| |
| for (int i = 0; i < expected.length; i++) { |
| final String expectedResult = "[ERROR] " + path + ":" + expected[i]; |
| assertEquals("error message " + i, expectedResult, actual.get(i)); |
| } |
| |
| assertEquals("unexpected output: " + lnr.readLine(), expected.length, errs); |
| } |
| |
| checker.destroy(); |
| } |
| |
| private static class DummyFilter implements Filter { |
| |
| @Override |
| public boolean accept(AuditEvent event) { |
| return false; |
| } |
| } |
| |
| private static class DummyFileSetViolationCheck extends AbstractFileSetCheck |
| implements ExternalResourceHolder { |
| |
| @Override |
| protected void processFiltered(File file, FileText fileText) throws CheckstyleException { |
| log(0, "test"); |
| } |
| |
| @Override |
| public Set<String> getExternalResourceLocations() { |
| final Set<String> externalResourceLocation = new HashSet<>(1); |
| externalResourceLocation.add("non_existing_external_resource.xml"); |
| return externalResourceLocation; |
| } |
| } |
| |
| private static class DummyFilterSet extends FilterSet implements ExternalResourceHolder { |
| |
| @Override |
| public Set<String> getExternalResourceLocations() { |
| final Set<String> strings = new HashSet<>(); |
| strings.add("test"); |
| return strings; |
| } |
| } |
| |
| private static class DynamicalResourceHolderCheck extends AbstractFileSetCheck |
| implements ExternalResourceHolder { |
| |
| private String firstExternalResourceLocation; |
| private String secondExternalResourceLocation; |
| |
| public void setFirstExternalResourceLocation(String firstExternalResourceLocation) { |
| this.firstExternalResourceLocation = firstExternalResourceLocation; |
| } |
| |
| public void setSecondExternalResourceLocation(String secondExternalResourceLocation) { |
| this.secondExternalResourceLocation = secondExternalResourceLocation; |
| } |
| |
| @Override |
| protected void processFiltered(File file, FileText fileText) throws CheckstyleException { |
| // there is no need in implementation of the method |
| } |
| |
| @Override |
| public Set<String> getExternalResourceLocations() { |
| final Set<String> locations = new HashSet<>(); |
| locations.add(firstExternalResourceLocation); |
| // Attempt to change the behaviour of the check dynamically |
| if (secondExternalResourceLocation != null) { |
| locations.add(secondExternalResourceLocation); |
| } |
| return locations; |
| } |
| } |
| |
| private static class CheckWhichDoesNotRequireCommentNodes extends AbstractCheck { |
| |
| /** Number of children of method definition token. */ |
| private static final int METHOD_DEF_CHILD_COUNT = 7; |
| |
| @Override |
| public int[] getDefaultTokens() { |
| return new int[] {TokenTypes.METHOD_DEF}; |
| } |
| |
| @Override |
| public int[] getAcceptableTokens() { |
| return new int[] {TokenTypes.METHOD_DEF}; |
| } |
| |
| @Override |
| public int[] getRequiredTokens() { |
| return new int[] {TokenTypes.METHOD_DEF}; |
| } |
| |
| @Override |
| public void visitToken(DetailAST ast) { |
| if (ast.findFirstToken(TokenTypes.MODIFIERS).findFirstToken( |
| TokenTypes.BLOCK_COMMENT_BEGIN) != null) { |
| log(ast, "AST has incorrect structure structure." |
| + " The check does not require comment nodes but there were comment nodes" |
| + " in the AST."); |
| } |
| final int childCount = ast.getChildCount(); |
| if (childCount != METHOD_DEF_CHILD_COUNT) { |
| final String msg = String.format(Locale.getDefault(), |
| "AST node in no comment tree has wrong number of children. " |
| + "Expected is %d but was %d", |
| METHOD_DEF_CHILD_COUNT, childCount); |
| log(ast, msg); |
| } |
| // count children where comment lives |
| int actualChildCount = 0; |
| for (DetailAST child = ast.getFirstChild().getFirstChild(); child != null; child = |
| child.getNextSibling()) { |
| actualChildCount++; |
| } |
| final int cacheChildCount = ast.getFirstChild().getChildCount(); |
| if (cacheChildCount != actualChildCount) { |
| final String msg = String.format(Locale.getDefault(), |
| "AST node with no comment has wrong number of children. " |
| + "Expected is %d but was %d", |
| cacheChildCount, actualChildCount); |
| log(ast, msg); |
| } |
| } |
| } |
| |
| private static class CheckWhichRequiresCommentNodes extends AbstractCheck { |
| |
| /** Number of children of method definition token. */ |
| private static final int METHOD_DEF_CHILD_COUNT = 7; |
| |
| @Override |
| public boolean isCommentNodesRequired() { |
| return true; |
| } |
| |
| @Override |
| public int[] getDefaultTokens() { |
| return new int[] {TokenTypes.METHOD_DEF}; |
| } |
| |
| @Override |
| public int[] getAcceptableTokens() { |
| return new int[] {TokenTypes.METHOD_DEF}; |
| } |
| |
| @Override |
| public int[] getRequiredTokens() { |
| return new int[] {TokenTypes.METHOD_DEF}; |
| } |
| |
| @Override |
| public void visitToken(DetailAST ast) { |
| if (ast.findFirstToken(TokenTypes.MODIFIERS).findFirstToken( |
| TokenTypes.BLOCK_COMMENT_BEGIN) == null) { |
| log(ast, "Incorrect AST structure."); |
| } |
| final int childCount = ast.getChildCount(); |
| if (childCount != METHOD_DEF_CHILD_COUNT) { |
| final String msg = String.format(Locale.getDefault(), |
| "AST node in comment tree has wrong number of children. " |
| + "Expected is %d but was %d", |
| METHOD_DEF_CHILD_COUNT, childCount); |
| log(ast, msg); |
| } |
| // count children where comment lives |
| int actualChildCount = 0; |
| for (DetailAST child = ast.getFirstChild().getFirstChild(); child != null; child = |
| child.getNextSibling()) { |
| actualChildCount++; |
| } |
| final int cacheChildCount = ast.getFirstChild().getChildCount(); |
| if (cacheChildCount != actualChildCount) { |
| final String msg = String.format(Locale.getDefault(), |
| "AST node with comment has wrong number of children. " |
| + "Expected is %d but was %d", |
| cacheChildCount, actualChildCount); |
| log(ast, msg); |
| } |
| } |
| } |
| |
| private static class CheckWhichThrowsError extends AbstractCheck { |
| |
| @Override |
| public int[] getDefaultTokens() { |
| return new int[] {TokenTypes.CLASS_DEF}; |
| } |
| |
| @Override |
| public int[] getAcceptableTokens() { |
| return new int[] {TokenTypes.CLASS_DEF}; |
| } |
| |
| @Override |
| public int[] getRequiredTokens() { |
| return new int[] {TokenTypes.CLASS_DEF}; |
| } |
| |
| @Override |
| public void visitToken(DetailAST ast) { |
| throw new IndexOutOfBoundsException("test"); |
| } |
| } |
| |
| private static class DummyFileSet extends AbstractFileSetCheck { |
| |
| private final List<String> methodCalls = new ArrayList<>(); |
| |
| private boolean initCalled; |
| |
| @Override |
| public void init() { |
| super.init(); |
| initCalled = true; |
| } |
| |
| @Override |
| public void beginProcessing(String charset) { |
| methodCalls.add("beginProcessing"); |
| super.beginProcessing(charset); |
| } |
| |
| @Override |
| public void finishProcessing() { |
| methodCalls.add("finishProcessing"); |
| super.finishProcessing(); |
| } |
| |
| @Override |
| protected void processFiltered(File file, FileText fileText) throws CheckstyleException { |
| methodCalls.add("processFiltered"); |
| } |
| |
| @Override |
| public void destroy() { |
| methodCalls.add("destroy"); |
| super.destroy(); |
| } |
| |
| public List<String> getMethodCalls() { |
| return Collections.unmodifiableList(methodCalls); |
| } |
| |
| public boolean isInitCalled() { |
| return initCalled; |
| } |
| |
| public MessageDispatcher getInternalMessageDispatcher() { |
| return getMessageDispatcher(); |
| } |
| } |
| } |