//////////////////////////////////////////////////////////////////////////////// // 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.checks.imports; import static com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheck.MSG_DISALLOWED; import static com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheck.MSG_MISSING_FILE; import static com.puppycrawl.tools.checkstyle.checks.imports.ImportControlCheck.MSG_UNKNOWN_PKG; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; import java.io.IOException; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import com.puppycrawl.tools.checkstyle.BaseCheckTestSupport; import com.puppycrawl.tools.checkstyle.BriefUtLogger; import com.puppycrawl.tools.checkstyle.Checker; import com.puppycrawl.tools.checkstyle.DefaultConfiguration; import com.puppycrawl.tools.checkstyle.TreeWalker; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.TokenTypes; import com.puppycrawl.tools.checkstyle.utils.CommonUtils; public class ImportControlCheckTest extends BaseCheckTestSupport { @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder(); @Override protected String getPath(String filename) throws IOException { return super.getPath("checks" + File.separator + "imports" + File.separator + filename); } @Override protected String getUriString(String filename) { return super.getUriString("checks" + File.separator + "imports" + File.separator + filename); } private static String getResourcePath(String filename) { return "/com/puppycrawl/tools/checkstyle/checks/imports/" + filename; } @Test public void testGetRequiredTokens() { final ImportControlCheck checkObj = new ImportControlCheck(); final int[] expected = { TokenTypes.PACKAGE_DEF, TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT, }; assertArrayEquals(expected, checkObj.getRequiredTokens()); } @Test public void testOne() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", getPath("import-control_one.xml")); final String[] expected = {"5:1: " + getCheckMessage(MSG_DISALLOWED, "java.io.File")}; verify(checkConfig, getPath("InputImportControl.java"), expected); } @Test public void testTwo() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", getPath("import-control_two.xml")); final String[] expected = { "3:1: " + getCheckMessage(MSG_DISALLOWED, "java.awt.Image"), "4:1: " + getCheckMessage(MSG_DISALLOWED, "javax.swing.border.*"), "6:1: " + getCheckMessage(MSG_DISALLOWED, "java.awt.Button.ABORT"), }; verify(checkConfig, getPath("InputImportControl.java"), expected); } @Test public void testWrong() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", getPath("import-control_wrong.xml")); final String[] expected = {"1:1: " + getCheckMessage(MSG_UNKNOWN_PKG)}; verify(checkConfig, getPath("InputImportControl.java"), expected); } @Test public void testMissing() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); final String[] expected = {"1:1: " + getCheckMessage(MSG_MISSING_FILE)}; verify(checkConfig, getPath("InputImportControl.java"), expected); } @Test public void testEmpty() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", " "); final String[] expected = {"1:1: " + getCheckMessage(MSG_MISSING_FILE)}; verify(checkConfig, getPath("InputImportControl.java"), expected); } @Test public void testNull() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", null); final String[] expected = {"1:1: " + getCheckMessage(MSG_MISSING_FILE)}; verify(checkConfig, getPath("InputImportControl.java"), expected); } @Test public void testUnknown() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", "unknown-file"); try { final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; verify(checkConfig, getPath("InputImportControl.java"), expected); fail("Test should fail if exception was not thrown"); } catch (CheckstyleException ex) { final String message = getCheckstyleExceptionMessage(ex); assertTrue(message.startsWith("Unable to find: ")); } } @Test public void testBroken() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", getPath("import-control_broken.xml")); try { final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; verify(checkConfig, getPath("InputImportControl.java"), expected); fail("Test should fail if exception was not thrown"); } catch (CheckstyleException ex) { final String message = getCheckstyleExceptionMessage(ex); assertTrue(message.startsWith("Unable to load ")); } } @Test public void testOneRegExp() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", getPath("import-control_one-re.xml")); final String[] expected = {"5:1: " + getCheckMessage(MSG_DISALLOWED, "java.io.File")}; verify(checkConfig, getPath("InputImportControl.java"), expected); } @Test public void testTwoRegExp() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", getPath("import-control_two-re.xml")); final String[] expected = { "3:1: " + getCheckMessage(MSG_DISALLOWED, "java.awt.Image"), "4:1: " + getCheckMessage(MSG_DISALLOWED, "javax.swing.border.*"), "6:1: " + getCheckMessage(MSG_DISALLOWED, "java.awt.Button.ABORT"), }; verify(checkConfig, getPath("InputImportControl.java"), expected); } @Test public void testBlacklist() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", getPath("import-control_blacklist.xml")); final String[] expected = { "3:1: " + getCheckMessage(MSG_DISALLOWED, "java.util.stream.Stream"), "4:1: " + getCheckMessage(MSG_DISALLOWED, "java.util.Date"), "6:1: " + getCheckMessage(MSG_DISALLOWED, "java.util.stream.Collectors"), "7:1: " + getCheckMessage(MSG_DISALLOWED, "java.util.stream.IntStream"), }; verify(checkConfig, getPath("InputImportControl_Blacklist.java"), expected); } @Test public void testPkgRegExpInParent() throws Exception { testRegExpInPackage("import-control_pkg-re-in-parent.xml"); } @Test public void testPkgRegExpInChild() throws Exception { testRegExpInPackage("import-control_pkg-re-in-child.xml"); } @Test public void testPkgRegExpInBoth() throws Exception { testRegExpInPackage("import-control_pkg-re-in-both.xml"); } // all import-control_pkg-re* files should be equivalent so use one test for all private void testRegExpInPackage(String file) throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", getPath(file)); final String[] expected = {"5:1: " + getCheckMessage(MSG_DISALLOWED, "java.io.File")}; verify(checkConfig, getPath("InputImportControl.java"), expected); } @Test public void testGetAcceptableTokens() { final ImportControlCheck testCheckObject = new ImportControlCheck(); final int[] actual = testCheckObject.getAcceptableTokens(); final int[] expected = { TokenTypes.PACKAGE_DEF, TokenTypes.IMPORT, TokenTypes.STATIC_IMPORT, }; assertArrayEquals(expected, actual); } @Test public void testUrl() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("url", getUriString("import-control_one.xml")); final String[] expected = {"5:1: " + getCheckMessage(MSG_DISALLOWED, "java.io.File")}; verify(checkConfig, getPath("InputImportControl.java"), expected); } @Test public void testUrlBlank() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("url", ""); final String[] expected = {"1:1: " + getCheckMessage(MSG_MISSING_FILE)}; verify(checkConfig, getPath("InputImportControl.java"), expected); } @Test public void testUrlNull() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("url", null); final String[] expected = {"1:1: " + getCheckMessage(MSG_MISSING_FILE)}; verify(checkConfig, getPath("InputImportControl.java"), expected); } @Test public void testUrlUnableToLoad() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("url", "https://UnableToLoadThisURL"); try { final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; verify(checkConfig, getPath("InputImportControl.java"), expected); fail("Test should fail if exception was not thrown"); } catch (final CheckstyleException ex) { final String message = getCheckstyleExceptionMessage(ex); assertTrue(message.startsWith("Unable to load ")); } } @Test public void testUrlIncorrectUrl() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("url", "https://{WrongCharsInURL}"); try { final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; verify(checkConfig, getPath("InputImportControl.java"), expected); fail("Test should fail if exception was not thrown"); } catch (final CheckstyleException ex) { final String message = getCheckstyleExceptionMessage(ex); assertTrue(message.startsWith("Unable to find: ")); } } @Test public void testResource() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", getResourcePath("import-control_one.xml")); final String[] expected = {"5:1: " + getCheckMessage(MSG_DISALLOWED, "java.io.File")}; verify(checkConfig, getPath("InputImportControl.java"), expected); } @Test public void testResourceUnableToLoad() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", getResourcePath("import-control_unknown.xml")); try { final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; verify(checkConfig, getPath("InputImportControl.java"), expected); fail("Test should fail if exception was not thrown"); } catch (final CheckstyleException ex) { final String message = getCheckstyleExceptionMessage(ex); assertTrue(message.startsWith("Unable to find: ")); } } @Test public void testUrlInFileProperty() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", getUriString("import-control_one.xml")); final String[] expected = {"5:1: " + getCheckMessage(MSG_DISALLOWED, "java.io.File")}; verify(checkConfig, getPath("InputImportControl.java"), expected); } @Test public void testUrlInFilePropertyUnableToLoad() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", "https://UnableToLoadThisURL"); try { final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; verify(checkConfig, getPath("InputImportControl.java"), expected); fail("Test should fail if exception was not thrown"); } catch (final CheckstyleException ex) { final String message = getCheckstyleExceptionMessage(ex); assertTrue(message.startsWith("Unable to load ")); } } @Test public void testCacheWhenFileExternalResourceContentDoesNotChange() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", getPath("import-control_one-re.xml")); final Checker checker = createMockCheckerWithCache(checkConfig); final String filePath = temporaryFolder.newFile("EmptyFile.java").getPath(); final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; verify(checker, filePath, filePath, expected); // One more time to use cache. verify(checker, filePath, filePath, expected); } @Test public void testCacheWhenUrlExternalResourceContentDoesNotChange() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("url", getUriString("import-control_one.xml")); final Checker checker = createMockCheckerWithCache(checkConfig); final String pathToEmptyFile = temporaryFolder.newFile("TestFile.java").getPath(); final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; verify(checker, pathToEmptyFile, pathToEmptyFile, expected); // One more time to use cache. verify(checker, pathToEmptyFile, pathToEmptyFile, expected); } @Test public void testPathRegexMatches() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", getResourcePath("import-control_one.xml")); checkConfig.addAttribute("path", "^.*[\\\\/]src[\\\\/]test[\\\\/].*$"); final String[] expected = {"5:1: " + getCheckMessage(MSG_DISALLOWED, "java.io.File")}; verify(checkConfig, getPath("InputImportControl.java"), expected); } @Test public void testPathRegexMatchesPartially() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", getResourcePath("import-control_one.xml")); checkConfig.addAttribute("path", "[\\\\/]InputImportControl\\.java"); final String[] expected = {"5:1: " + getCheckMessage(MSG_DISALLOWED, "java.io.File")}; verify(checkConfig, getPath("InputImportControl.java"), expected); } @Test public void testPathRegexDoesntMatch() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", getResourcePath("import-control_one.xml")); checkConfig.addAttribute("path", "^.*[\\\\/]src[\\\\/]main[\\\\/].*$"); final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; verify(checkConfig, getPath("InputImportControl.java"), expected); } @Test public void testPathRegexDoesntMatchPartially() throws Exception { final DefaultConfiguration checkConfig = createCheckConfig(ImportControlCheck.class); checkConfig.addAttribute("file", getResourcePath("import-control_one.xml")); checkConfig.addAttribute("path", "[\\\\/]NoMatch\\.java"); final String[] expected = CommonUtils.EMPTY_STRING_ARRAY; verify(checkConfig, getPath("InputImportControl.java"), expected); } private Checker createMockCheckerWithCache(DefaultConfiguration checkConfig) throws IOException, CheckstyleException { final DefaultConfiguration treeWalkerConfig = createCheckConfig(TreeWalker.class); treeWalkerConfig.addChild(checkConfig); final DefaultConfiguration checkerConfig = new DefaultConfiguration("checkstyle_checks"); checkerConfig.addChild(treeWalkerConfig); checkerConfig.addAttribute("cacheFile", temporaryFolder.newFile().getPath()); final Checker checker = new Checker(); checker.setModuleClassLoader(Thread.currentThread().getContextClassLoader()); checker.configure(checkerConfig); checker.addListener(new BriefUtLogger(stream)); return checker; } /** * Returns String message of original exception that was thrown in * ImportControlCheck.setUrl or ImportControlCheck.setFile * and caught in test (it was caught and re-thrown twice after that) * Note: this is helper method with hard-coded structure of exception causes. It works * fine for methods mentioned, you may need to adjust it if you try to use it for other needs * @param exception Exception * @return String message of original exception */ private static String getCheckstyleExceptionMessage(CheckstyleException exception) { return exception.getCause().getCause().getCause().getMessage(); } }