diff --git a/pom.xml b/pom.xml index ae26f0a83..a3ecd0f39 100644 --- a/pom.xml +++ b/pom.xml @@ -271,7 +271,7 @@ nl.jqno.equalsverifier equalsverifier - 1.7.6 + 1.7.7 test diff --git a/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionFilter.java b/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionFilter.java index 39465ab5b..9069f7ac9 100644 --- a/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionFilter.java +++ b/src/main/java/com/puppycrawl/tools/checkstyle/filters/SuppressionFilter.java @@ -19,6 +19,10 @@ package com.puppycrawl.tools.checkstyle.filters; +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URL; import java.util.Objects; import com.puppycrawl.tools.checkstyle.api.AuditEvent; @@ -26,6 +30,7 @@ import com.puppycrawl.tools.checkstyle.api.AutomaticBean; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; import com.puppycrawl.tools.checkstyle.api.Filter; import com.puppycrawl.tools.checkstyle.api.FilterSet; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; /** *

@@ -33,21 +38,32 @@ import com.puppycrawl.tools.checkstyle.api.FilterSet; * column, as specified in a suppression file. *

* @author Rick Giles + * @author liscju */ public class SuppressionFilter extends AutomaticBean implements Filter { + /** Filename of supression file. */ + private String file; + /** Tells whether config file existence is optional. */ + private boolean optional; /** Set of individual suppresses. */ private FilterSet filters = new FilterSet(); /** - * Loads the suppressions for a file. + * Sets name of the supression file. * @param fileName name of the suppressions file. - * @throws CheckstyleException if there is an error. */ - public void setFile(String fileName) - throws CheckstyleException { - filters = SuppressionsLoader.loadSuppressions(fileName); + public void setFile(String fileName) { + file = fileName; + } + + /** + * Sets whether config file existence is optional. + * @param optional tells if config file existence is optional. + */ + public void setOptional(boolean optional) { + this.optional = optional; } @Override @@ -71,4 +87,50 @@ public class SuppressionFilter public int hashCode() { return Objects.hash(filters); } + + @Override + protected void finishLocalSetup() throws CheckstyleException { + if (file != null) { + if (optional) { + if (suppressionSourceExists(file)) { + filters = SuppressionsLoader.loadSuppressions(file); + } + else { + filters = new FilterSet(); + } + } + else { + filters = SuppressionsLoader.loadSuppressions(file); + } + } + } + + /** + * Checks if suppression source with given fileName exists. + * @param fileName name of the suppressions file. + * @return true if suppression file exists, otherwise false + */ + private static boolean suppressionSourceExists(String fileName) { + boolean suppressionSourceExists = true; + InputStream sourceInput = null; + try { + final URI uriByFilename = CommonUtils.getUriByFilename(fileName); + final URL url = uriByFilename.toURL(); + sourceInput = url.openStream(); + } + catch (CheckstyleException | IOException ignored) { + suppressionSourceExists = false; + } + finally { + if (sourceInput != null) { + try { + sourceInput.close(); + } + catch (IOException ignored) { + suppressionSourceExists = false; + } + } + } + return suppressionSourceExists; + } } diff --git a/src/test/java/com/puppycrawl/tools/checkstyle/filters/SuppressionFilterTest.java b/src/test/java/com/puppycrawl/tools/checkstyle/filters/SuppressionFilterTest.java index d065f4dc2..0fd06b8c4 100644 --- a/src/test/java/com/puppycrawl/tools/checkstyle/filters/SuppressionFilterTest.java +++ b/src/test/java/com/puppycrawl/tools/checkstyle/filters/SuppressionFilterTest.java @@ -19,14 +19,34 @@ package com.puppycrawl.tools.checkstyle.filters; -import org.junit.Assert; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URI; +import java.net.URL; + import org.junit.Test; +import org.junit.runner.RunWith; + +import org.mockito.BDDMockito; +import org.mockito.Mockito; + +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; import com.puppycrawl.tools.checkstyle.api.AuditEvent; import com.puppycrawl.tools.checkstyle.api.CheckstyleException; +import com.puppycrawl.tools.checkstyle.utils.CommonUtils; + import nl.jqno.equalsverifier.EqualsVerifier; import nl.jqno.equalsverifier.Warning; +@RunWith(PowerMockRunner.class) +@PrepareForTest({SuppressionFilter.class, CommonUtils.class}) public class SuppressionFilterTest { @Test public void testEqualsAndHashCode() { @@ -39,13 +59,122 @@ public class SuppressionFilterTest { @Test public void testAccept() throws CheckstyleException { - final SuppressionFilter filter = new SuppressionFilter(); - filter.setFile("src/test/resources/com/puppycrawl/tools/checkstyle/filters/" - + "suppressions_none.xml"); + final String fileName = "src/test/resources/com/puppycrawl/tools/checkstyle/filters/" + + "suppressions_none.xml"; + final boolean optional = false; + final SuppressionFilter filter = createSupressionFilter(fileName, optional); final AuditEvent ev = new AuditEvent(this, "ATest.java", null); - Assert.assertTrue(filter.accept(ev)); + assertTrue(filter.accept(ev)); } + @Test + public void testAcceptOnNullFile() throws CheckstyleException { + final String fileName = null; + final boolean optional = false; + final SuppressionFilter filter = createSupressionFilter(fileName, optional); + + final AuditEvent ev = new AuditEvent(this, "AnyJava.java", null); + + assertTrue(filter.accept(ev)); + } + + @Test + public void testNonExistanceSuppressionFileWithFalseOptional() throws Exception { + final String fileName = "src/test/resources/com/puppycrawl/tools/checkstyle/filters/" + + "non_existance_suppresion_file.xml"; + try { + final boolean optional = false; + createSupressionFilter(fileName, optional); + fail("Exception is expected"); + } + catch (CheckstyleException ex) { + assertEquals("Unable to find: " + fileName, ex.getMessage()); + } + } + + @Test + public void testExistanceInvalidSuppressionFileWithTrueOptional() throws Exception { + final String fileName = "src/test/resources/com/puppycrawl/tools/checkstyle/filters/" + + "suppressions_invalid_file.xml"; + try { + final boolean optional = true; + createSupressionFilter(fileName, optional); + fail("Exception is expected"); + } + catch (CheckstyleException ex) { + assertEquals("Unable to parse " + fileName + " - invalid files or checks format", + ex.getMessage()); + } + } + + @Test + public void testExistingSuppressionFileWithTrueOptional() throws Exception { + final String fileName = "src/test/resources/com/puppycrawl/tools/checkstyle/filters/" + + "suppressions_none.xml"; + final boolean optional = true; + final SuppressionFilter filter = createSupressionFilter(fileName, optional); + + final AuditEvent ev = new AuditEvent(this, "AnyFile.java", null); + + assertTrue(filter.accept(ev)); + } + + @Test + public void testExistingConfigWithTrueOptionalThrowsIoErrorWhileClosing() + throws Exception { + final InputStream inputStream = PowerMockito.mock(InputStream.class); + Mockito.doThrow(IOException.class).when(inputStream).close(); + + final URL url = PowerMockito.mock(URL.class); + BDDMockito.given(url.openStream()).willReturn(inputStream); + + final URI uri = PowerMockito.mock(URI.class); + BDDMockito.given(uri.toURL()).willReturn(url); + + PowerMockito.mockStatic(CommonUtils.class); + + final String fileName = "src/test/resources/com/puppycrawl/tools/checkstyle/filters/" + + "suppressions_none.xml"; + BDDMockito.given(CommonUtils.getUriByFilename(fileName)).willReturn(uri); + + final boolean optional = true; + final SuppressionFilter filter = createSupressionFilter(fileName, optional); + final AuditEvent ev = new AuditEvent(this, "AnyFile.java", null); + assertTrue(filter.accept(ev)); + } + + @Test + public void testNonExistanceSuppressionFileWithTrueOptional() throws Exception { + final String fileName = "src/test/resources/com/puppycrawl/tools/checkstyle/filters/" + + "non_existance_suppresion_file.xml"; + final boolean optional = true; + final SuppressionFilter filter = createSupressionFilter(fileName, optional); + + final AuditEvent ev = new AuditEvent(this, "AnyFile.java", null); + + assertTrue(filter.accept(ev)); + } + + @Test + public void testNonExistanceSuppressionUrlWithTrueOptional() throws Exception { + final String fileName = + "http://checkstyle.sourceforge.net/non_existing_suppression.xml"; + final boolean optional = true; + final SuppressionFilter filter = createSupressionFilter(fileName, optional); + + final AuditEvent ev = new AuditEvent(this, "AnyFile.java", null); + + assertTrue(filter.accept(ev)); + } + + private static SuppressionFilter createSupressionFilter(String fileName, boolean optional) + throws CheckstyleException { + final SuppressionFilter suppressionFilter = new SuppressionFilter(); + suppressionFilter.setFile(fileName); + suppressionFilter.setOptional(optional); + suppressionFilter.finishLocalSetup(); + return suppressionFilter; + } } diff --git a/src/xdocs/config_filters.xml b/src/xdocs/config_filters.xml index 18563a246..aa8172203 100644 --- a/src/xdocs/config_filters.xml +++ b/src/xdocs/config_filters.xml @@ -389,7 +389,8 @@ public static void foo() { audit events for Check errors according to a suppressions XML document in a file. If there is no configured - suppressions file, the Filter accepts all audit events. + suppressions file or the optional is set to true and + suppressions file was not found the Filter accepts all audit events.

@@ -421,6 +422,18 @@ public static void foo() { string none + + optional + + Tells what to do when the file is not existing. If + optional is set to false the file must exist, or else + it ends with error. On the other hand if optional is + true and file is not found, the filter accept all + audit events. + + boolean + false + @@ -433,6 +446,7 @@ public static void foo() { <module name="SuppressionFilter"> <property name="file" value="config/suppressions.xml"/> + <property name="optional" value="false"/> </module>