You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@commons.apache.org by gg...@apache.org on 2023/06/30 04:02:29 UTC

[commons-io] branch master updated: Add PathMatcherFileFilter to adapt java.nio.file.PathMatcher

This is an automated email from the ASF dual-hosted git repository.

ggregory pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/commons-io.git


The following commit(s) were added to refs/heads/master by this push:
     new 4d1ded4b Add PathMatcherFileFilter to adapt java.nio.file.PathMatcher
     new c3471687 Merge branch 'master' of https://gitbox.apache.org/repos/asf/commons-io.git
4d1ded4b is described below

commit 4d1ded4b111e25ffea2fbe3c02b4c705cd06d2d0
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Fri Jun 30 00:02:07 2023 -0400

    Add PathMatcherFileFilter to adapt java.nio.file.PathMatcher
    
    - MagicNumberFileFilter.accept(Path, BasicFileAttributes) doesn't its
    byteOffset before reading.
    - Move fixes into first changes section
---
 src/changes/changes.xml                            | 24 +++++++----
 .../io/filefilter/MagicNumberFileFilter.java       |  1 +
 .../io/filefilter/PathMatcherFileFilter.java       | 50 ++++++++++++++++++++++
 .../commons/io/filefilter/AbstractFilterTest.java  | 22 +++++++---
 .../commons/io/filefilter/FileFilterTest.java      | 45 ++++++++++---------
 .../io/filefilter/PathMatcherFileFilterTest.java   | 50 ++++++++++++++++++++++
 .../io/filefilter/WildcardFileFilterTest.java      |  3 +-
 7 files changed, 155 insertions(+), 40 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 1ce68660..81a4f784 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -48,6 +48,19 @@ The <action> type attribute can be add,update,fix,remove.
 
   <body>
     <release version="2.14.0" date="2023-MM-DD" description="Java 8 required.">
+      <!-- FIX -->
+      <action dev="ggregory" type="fix" issue="IO-799" due-to="Jeroen van der Vegt, Gary Gregory">
+        ReaderInputStream.read() throws an exception instead of returning -1 when called again after returning -1.
+      </action>
+      <action dev="ggregory" type="fix" issue="IO-804" due-to="Elliotte Rusty Harold, Gary Gregory">
+        FileUtils.forceMkdirParent() Javadoc is likely incorrect.
+      </action>
+      <action dev="ggregory" type="fix" due-to="step-security-bot, Gary Gregory">
+        [StepSecurity] ci: Harden GitHub Actions #461.
+      </action>
+      <action dev="ggregory" type="fix" due-to="Gary Gregory">
+        MagicNumberFileFilter.accept(Path, BasicFileAttributes) doesn't its byteOffset before reading.
+      </action>
       <!-- ADD -->
       <action dev="ggregory" type="add" due-to="Gary Gregory">
         Add DeferredFileOutputStream.getPath().
@@ -82,15 +95,8 @@ The <action> type attribute can be add,update,fix,remove.
       <action dev="ggregory" type="add" due-to="Gary Gregory">
         IOFileFilter now also extends java.nio.file.PathMatcher.
       </action>
-      <!-- FIX -->
-      <action dev="ggregory" type="fix" issue="IO-799" due-to="Jeroen van der Vegt, Gary Gregory">
-        ReaderInputStream.read() throws an exception instead of returning -1 when called again after returning -1.
-      </action>
-      <action dev="ggregory" type="fix" issue="IO-804" due-to="Elliotte Rusty Harold, Gary Gregory">
-        FileUtils.forceMkdirParent() Javadoc is likely incorrect.
-      </action>
-      <action dev="ggregory" type="fix" due-to="step-security-bot, Gary Gregory">
-        [StepSecurity] ci: Harden GitHub Actions #461.
+      <action dev="ggregory" type="add" due-to="Gary Gregory">
+        Add PathMatcherFileFilter to adapt java.nio.file.PathMatcher.
       </action>
       <!-- UPDATE -->
     </release>    
diff --git a/src/main/java/org/apache/commons/io/filefilter/MagicNumberFileFilter.java b/src/main/java/org/apache/commons/io/filefilter/MagicNumberFileFilter.java
index e7743408..1793ef2a 100644
--- a/src/main/java/org/apache/commons/io/filefilter/MagicNumberFileFilter.java
+++ b/src/main/java/org/apache/commons/io/filefilter/MagicNumberFileFilter.java
@@ -293,6 +293,7 @@ public class MagicNumberFileFilter extends AbstractFileFilter implements Seriali
             try {
                 try (FileChannel fileChannel = FileChannel.open(file)) {
                     final ByteBuffer byteBuffer = ByteBuffer.allocate(this.magicNumbers.length);
+                    fileChannel.position(byteOffset);
                     final int read = fileChannel.read(byteBuffer);
                     if (read != magicNumbers.length) {
                         return FileVisitResult.TERMINATE;
diff --git a/src/main/java/org/apache/commons/io/filefilter/PathMatcherFileFilter.java b/src/main/java/org/apache/commons/io/filefilter/PathMatcherFileFilter.java
new file mode 100644
index 00000000..a36c6879
--- /dev/null
+++ b/src/main/java/org/apache/commons/io/filefilter/PathMatcherFileFilter.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.io.filefilter;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.PathMatcher;
+
+/**
+ * Delegates matching to a {@link PathMatcher}.
+ *
+ * @since 2.14.0
+ */
+public class PathMatcherFileFilter extends AbstractFileFilter {
+
+    private final PathMatcher pathMatcher;
+
+    /**
+     * Constructs a new instance to perform matching with a PathMatcher.
+     *
+     * @param pathMatcher The PathMatcher delegate.
+     */
+    public PathMatcherFileFilter(final PathMatcher pathMatcher) {
+        this.pathMatcher = pathMatcher;
+    }
+
+    @Override
+    public boolean accept(File file) {
+        return file != null && matches(file.toPath());
+    }
+    @Override
+    public boolean matches(final Path path) {
+        return pathMatcher.matches(path);
+    }
+}
diff --git a/src/test/java/org/apache/commons/io/filefilter/AbstractFilterTest.java b/src/test/java/org/apache/commons/io/filefilter/AbstractFilterTest.java
index 3014b315..ca6f8874 100644
--- a/src/test/java/org/apache/commons/io/filefilter/AbstractFilterTest.java
+++ b/src/test/java/org/apache/commons/io/filefilter/AbstractFilterTest.java
@@ -24,6 +24,7 @@ import java.io.IOException;
 import java.nio.file.FileVisitResult;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.attribute.BasicFileAttributes;
 
 import org.apache.commons.io.IOCase;
 import org.junit.jupiter.api.io.TempDir;
@@ -43,7 +44,7 @@ public class AbstractFilterTest {
     @TempDir
     public File temporaryFolder;
 
-    void assertFiltering(final IOFileFilter filter, final File file, final boolean expected) {
+    void assertFiltering(final IOFileFilter filter, final File file, final boolean expected) throws IOException {
         // Note. This only tests the (File, String) version if the parent of
         // the File passed in is not null
         assertEquals(expected, filter.accept(file), "Filter(File) " + filter.getClass().getName() + " not " + expected + " for " + file);
@@ -51,6 +52,13 @@ public class AbstractFilterTest {
         if (file != null && file.getParentFile() != null) {
             assertEquals(expected, filter.accept(file.getParentFile(), file.getName()),
                     "Filter(File, String) " + filter.getClass().getName() + " not " + expected + " for " + file);
+            final Path path = file.toPath();
+            assertEquals(expected, filter.accept(path, null) != FileVisitResult.TERMINATE, filter::toString);
+            if (Files.isRegularFile(path)) {
+                assertEquals(expected, filter.accept(path, Files.readAttributes(path, BasicFileAttributes.class)) != FileVisitResult.TERMINATE,
+                        filter::toString);
+            }
+            assertEquals(expected, filter.matches(path), filter::toString);
         } else if (file == null) {
             assertEquals(expected, filter.accept(null), "Filter(File, String) " + filter.getClass().getName() + " not " + expected + " for null");
             assertEquals(expected, filter.matches(null), "Filter(File, String) " + filter.getClass().getName() + " not " + expected + " for null");
@@ -63,7 +71,7 @@ public class AbstractFilterTest {
         // the File passed in is not null
         final FileVisitResult expectedFileVisitResult = AbstractFileFilter.toDefaultFileVisitResult(expected);
         assertEquals(expectedFileVisitResult, filter.accept(path, null),
-            "Filter(Path) " + filter.getClass().getName() + " not " + expectedFileVisitResult + " for " + path);
+                "Filter(Path) " + filter.getClass().getName() + " not " + expectedFileVisitResult + " for " + path);
 
         if (path != null && path.getParent() != null) {
             assertEquals(expectedFileVisitResult, filter.accept(path, null),
@@ -79,7 +87,7 @@ public class AbstractFilterTest {
         assertNotNull(filter.toString());
     }
 
-    void assertFooBarFileFiltering(IOFileFilter filter) {
+    void assertFooBarFileFiltering(IOFileFilter filter) throws IOException {
         assertFiltering(filter, new File("foo"), true);
         assertFiltering(filter, new File("foo"), true);
         assertFiltering(filter, new File("bar"), true);
@@ -89,7 +97,7 @@ public class AbstractFilterTest {
         assertFiltering(filter, new File("bar").toPath(), true);
         assertFiltering(filter, new File("fred").toPath(), false);
 
-        filter = new NameFileFilter(new String[] {"foo", "bar"}, IOCase.SENSITIVE);
+        filter = new NameFileFilter(new String[] { "foo", "bar" }, IOCase.SENSITIVE);
         assertFiltering(filter, new File("foo"), true);
         assertFiltering(filter, new File("bar"), true);
         assertFiltering(filter, new File("FOO"), false);
@@ -99,7 +107,7 @@ public class AbstractFilterTest {
         assertFiltering(filter, new File("FOO").toPath(), false);
         assertFiltering(filter, new File("BAR").toPath(), false);
 
-        filter = new NameFileFilter(new String[] {"foo", "bar"}, IOCase.INSENSITIVE);
+        filter = new NameFileFilter(new String[] { "foo", "bar" }, IOCase.INSENSITIVE);
         assertFiltering(filter, new File("foo"), true);
         assertFiltering(filter, new File("bar"), true);
         assertFiltering(filter, new File("FOO"), true);
@@ -109,7 +117,7 @@ public class AbstractFilterTest {
         assertFiltering(filter, new File("FOO").toPath(), true);
         assertFiltering(filter, new File("BAR").toPath(), true);
 
-        filter = new NameFileFilter(new String[] {"foo", "bar"}, IOCase.SYSTEM);
+        filter = new NameFileFilter(new String[] { "foo", "bar" }, IOCase.SYSTEM);
         assertFiltering(filter, new File("foo"), true);
         assertFiltering(filter, new File("bar"), true);
         assertFiltering(filter, new File("FOO"), WINDOWS);
@@ -119,7 +127,7 @@ public class AbstractFilterTest {
         assertFiltering(filter, new File("FOO").toPath(), WINDOWS);
         assertFiltering(filter, new File("BAR").toPath(), WINDOWS);
 
-        filter = new NameFileFilter(new String[] {"foo", "bar"}, null);
+        filter = new NameFileFilter(new String[] { "foo", "bar" }, null);
         assertFiltering(filter, new File("foo"), true);
         assertFiltering(filter, new File("bar"), true);
         assertFiltering(filter, new File("FOO"), false);
diff --git a/src/test/java/org/apache/commons/io/filefilter/FileFilterTest.java b/src/test/java/org/apache/commons/io/filefilter/FileFilterTest.java
index 9aa39b72..858c4a19 100644
--- a/src/test/java/org/apache/commons/io/filefilter/FileFilterTest.java
+++ b/src/test/java/org/apache/commons/io/filefilter/FileFilterTest.java
@@ -29,6 +29,7 @@ import java.io.BufferedOutputStream;
 import java.io.File;
 import java.io.FileFilter;
 import java.io.FilenameFilter;
+import java.io.IOException;
 import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.FileVisitResult;
@@ -153,7 +154,7 @@ public class FileFilterTest extends AbstractFilterTest {
     }
 
     @Test
-    public void testAnd() {
+    public void testAnd() throws IOException {
         final IOFileFilter trueFilter = TrueFileFilter.INSTANCE;
         final IOFileFilter falseFilter = FalseFileFilter.INSTANCE;
         assertFiltering(trueFilter.and(trueFilter), new File("foo.test"), true);
@@ -163,7 +164,7 @@ public class FileFilterTest extends AbstractFilterTest {
     }
 
     @Test
-    public void testAnd2() {
+    public void testAnd2() throws IOException {
         final IOFileFilter trueFilter = TrueFileFilter.INSTANCE;
         final IOFileFilter falseFilter = FalseFileFilter.INSTANCE;
         assertFiltering(new AndFileFilter(trueFilter, trueFilter), new File("foo.test"), true);
@@ -181,7 +182,7 @@ public class FileFilterTest extends AbstractFilterTest {
     }
 
     @Test
-    public void testAndArray() {
+    public void testAndArray() throws IOException {
         final IOFileFilter trueFilter = TrueFileFilter.INSTANCE;
         final IOFileFilter falseFilter = FalseFileFilter.INSTANCE;
         assertFiltering(new AndFileFilter(trueFilter, trueFilter, trueFilter), new File("foo.test"), true);
@@ -252,7 +253,7 @@ public class FileFilterTest extends AbstractFilterTest {
     }
 
     @Test
-    public void testDelegateFileFilter() {
+    public void testDelegateFileFilter() throws IOException {
         final OrFileFilter orFilter = new OrFileFilter();
         final File testFile = new File("test.txt");
 
@@ -276,7 +277,7 @@ public class FileFilterTest extends AbstractFilterTest {
 
     @SuppressWarnings("deprecation")
     @Test
-    public void testDeprecatedWildcard() {
+    public void testDeprecatedWildcard() throws IOException {
         IOFileFilter filter = new WildcardFilter("*.txt");
         final List<String> patternList = Arrays.asList("*.txt", "*.xml", "*.gif");
         final IOFileFilter listFilter = new WildcardFilter(patternList);
@@ -355,7 +356,7 @@ public class FileFilterTest extends AbstractFilterTest {
     }
 
     @Test
-    public void testDirectory() {
+    public void testDirectory() throws IOException {
         // XXX: This test presumes the current working dir is the base dir of the source checkout.
         final IOFileFilter filter = new DirectoryFileFilter();
 
@@ -432,7 +433,7 @@ public class FileFilterTest extends AbstractFilterTest {
     }
 
     @Test
-    public void testFalse() {
+    public void testFalse() throws IOException {
         final IOFileFilter filter = FileFilterUtils.falseFileFilter();
         assertFiltering(filter, new File("foo.test"), false);
         assertFiltering(filter, new File("foo.test").toPath(), false);
@@ -447,13 +448,13 @@ public class FileFilterTest extends AbstractFilterTest {
     }
 
     @Test
-    public void testFileEqualsFilter() {
+    public void testFileEqualsFilter() throws IOException {
         assertFooBarFileFiltering(
             new FileEqualsFileFilter(new File("foo")).or(new FileEqualsFileFilter(new File("bar"))));
     }
 
     @Test
-    public void testFileFilterUtils_and() {
+    public void testFileFilterUtils_and() throws IOException {
         final IOFileFilter trueFilter = TrueFileFilter.INSTANCE;
         final IOFileFilter falseFilter = FalseFileFilter.INSTANCE;
         assertFiltering(FileFilterUtils.and(trueFilter, trueFilter, trueFilter), new File("foo.test"), true);
@@ -463,7 +464,7 @@ public class FileFilterTest extends AbstractFilterTest {
     }
 
     @Test
-    public void testFileFilterUtils_or() {
+    public void testFileFilterUtils_or() throws IOException {
         final IOFileFilter trueFilter = TrueFileFilter.INSTANCE;
         final IOFileFilter falseFilter = FalseFileFilter.INSTANCE;
         final File testFile = new File("foo.test");
@@ -474,7 +475,7 @@ public class FileFilterTest extends AbstractFilterTest {
     }
 
     @Test
-    public void testFiles() {
+    public void testFiles() throws IOException {
         // XXX: This test presumes the current working dir is the base dir of the source checkout.
         final IOFileFilter filter = FileFileFilter.INSTANCE;
 
@@ -700,7 +701,7 @@ public class FileFilterTest extends AbstractFilterTest {
     }
 
     @Test
-    public void testHidden() {
+    public void testHidden() throws IOException {
         final File hiddenDirFile = new File(SVN_DIR_NAME);
         final Path hiddenDirPath = hiddenDirFile.toPath();
         if (hiddenDirFile.exists()) {
@@ -797,8 +798,6 @@ public class FileFilterTest extends AbstractFilterTest {
         assertFiltering(filter, dir, false);
     }
 
-    // -----------------------------------------------------------------------
-
     @Test
     public void testMagicNumberFileFilterString() throws Exception {
         final byte[] classFileMagicNumber = {(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE};
@@ -1037,7 +1036,7 @@ public class FileFilterTest extends AbstractFilterTest {
     }
 
     @Test
-    public void testNameFilter() {
+    public void testNameFilter() throws IOException {
         assertFooBarFileFiltering(new NameFileFilter("foo", "bar"));
     }
 
@@ -1061,7 +1060,7 @@ public class FileFilterTest extends AbstractFilterTest {
     }
 
     @Test
-    public void testNegate() {
+    public void testNegate() throws IOException {
         final IOFileFilter filter = FileFilterUtils.notFileFilter(FileFilterUtils.trueFileFilter());
         assertFiltering(filter, new File("foo.test"), false);
         assertFiltering(filter, new File("foo"), false);
@@ -1077,7 +1076,7 @@ public class FileFilterTest extends AbstractFilterTest {
     }
 
     @Test
-    public void testOr() {
+    public void testOr() throws IOException {
         final IOFileFilter trueFilter = TrueFileFilter.INSTANCE;
         final IOFileFilter falseFilter = FalseFileFilter.INSTANCE;
         final File testFile = new File("foo.test");
@@ -1124,13 +1123,13 @@ public class FileFilterTest extends AbstractFilterTest {
     }
 
     @Test
-    public void testPathEqualsFilter() {
+    public void testPathEqualsFilter() throws IOException {
         assertFooBarFileFiltering(
             new PathEqualsFileFilter(Paths.get("foo")).or(new PathEqualsFileFilter(Paths.get("bar"))));
     }
 
     @Test
-    public void testPrefix() {
+    public void testPrefix() throws IOException {
         IOFileFilter filter = new PrefixFileFilter("foo", "bar");
         final File testFile = new File("test");
         final Path testPath = testFile.toPath();
@@ -1194,7 +1193,7 @@ public class FileFilterTest extends AbstractFilterTest {
     }
 
     @Test
-    public void testPrefixCaseInsensitive() {
+    public void testPrefixCaseInsensitive() throws IOException {
 
         IOFileFilter filter = new PrefixFileFilter(new String[] {"foo", "bar"}, IOCase.INSENSITIVE);
         assertFiltering(filter, new File("foo.test1"), true);
@@ -1323,7 +1322,7 @@ public class FileFilterTest extends AbstractFilterTest {
     }
 
     @Test
-    public void testSuffix() {
+    public void testSuffix() throws IOException {
         IOFileFilter filter = new SuffixFileFilter("tes", "est");
         final File testFile = new File("test");
         final Path testPath = testFile.toPath();
@@ -1380,7 +1379,7 @@ public class FileFilterTest extends AbstractFilterTest {
     }
 
     @Test
-    public void testSuffixCaseInsensitive() {
+    public void testSuffixCaseInsensitive() throws IOException {
 
         IOFileFilter filter = new SuffixFileFilter(new String[] {"tes", "est"}, IOCase.INSENSITIVE);
         assertFiltering(filter, new File("foo.tes"), true);
@@ -1414,7 +1413,7 @@ public class FileFilterTest extends AbstractFilterTest {
     }
 
     @Test
-    public void testTrue() {
+    public void testTrue() throws IOException {
         final IOFileFilter filter = FileFilterUtils.trueFileFilter();
         assertFiltering(filter, new File("foo.test"), true);
         assertFiltering(filter, new File("foo"), true);
diff --git a/src/test/java/org/apache/commons/io/filefilter/PathMatcherFileFilterTest.java b/src/test/java/org/apache/commons/io/filefilter/PathMatcherFileFilterTest.java
new file mode 100644
index 00000000..ce794115
--- /dev/null
+++ b/src/test/java/org/apache/commons/io/filefilter/PathMatcherFileFilterTest.java
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.io.filefilter;
+
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.FileSystems;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Tests {@link PathMatcherFileFilter}.
+ */
+public class PathMatcherFileFilterTest extends AbstractFilterTest {
+
+    @Test
+    public void testGlob() throws IOException {
+        @SuppressWarnings("resource")
+        final IOFileFilter filter = new PathMatcherFileFilter(FileSystems.getDefault().getPathMatcher("glob:*.txt"));
+        final File file1 = new File("log.txt");
+        final File file2 = new File("log.TXT");
+        //
+        assertTrue(filter.accept(file1));
+        assertTrue(filter.accept(file2));
+        assertTrue(filter.accept(file1.getParentFile(), file1.getName()));
+        assertTrue(filter.accept(file2.getParentFile(), file2.getName()));
+        assertFiltering(filter, file1, true);
+        assertFiltering(filter, file2, true);
+        assertFiltering(filter, file1.toPath(), true);
+        assertFiltering(filter, file2.toPath(), true);
+    }
+
+}
diff --git a/src/test/java/org/apache/commons/io/filefilter/WildcardFileFilterTest.java b/src/test/java/org/apache/commons/io/filefilter/WildcardFileFilterTest.java
index af3755ae..44ee1fa9 100644
--- a/src/test/java/org/apache/commons/io/filefilter/WildcardFileFilterTest.java
+++ b/src/test/java/org/apache/commons/io/filefilter/WildcardFileFilterTest.java
@@ -23,6 +23,7 @@ import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.io.File;
+import java.io.IOException;
 import java.nio.file.FileVisitResult;
 import java.nio.file.Path;
 import java.util.Arrays;
@@ -34,7 +35,7 @@ import org.junit.jupiter.api.Test;
 public class WildcardFileFilterTest extends AbstractFilterTest {
 
     @Test
-    public void testWildcard() {
+    public void testWildcard() throws IOException {
         IOFileFilter filter = new WildcardFileFilter("*.txt");
         assertFiltering(filter, new File("log.txt"), true);
         assertFiltering(filter, new File("log.TXT"), false);