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 2021/09/15 15:38:21 UTC

[commons-io] branch master updated (3cccfe6 -> 23c837f)

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

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


    from 3cccfe6  Nicer Javadoc.
     new d6d5d0b  Nicer Javadoc.
     new dcb09db  Add and use PathUtils.sizeOf(Path)
     new 17bb2a7  Sort test members.
     new 23c837f  Use assertThrows and don't catch and rethrow exceptions in tests.

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 src/changes/changes.xml                            |    6 +
 src/main/java/org/apache/commons/io/FileUtils.java |  112 +-
 .../commons/io/file/CountingPathVisitor.java       |    9 +-
 .../java/org/apache/commons/io/file/PathUtils.java |  119 +-
 .../apache/commons/io/ByteOrderMarkTestCase.java   |   62 +-
 .../org/apache/commons/io/CharsetsTestCase.java    |   10 +-
 .../java/org/apache/commons/io/CopyUtilsTest.java  |  108 +-
 .../java/org/apache/commons/io/DemuxTestCase.java  |  198 +--
 .../apache/commons/io/DirectoryWalkerTestCase.java |  630 +++----
 .../commons/io/DirectoryWalkerTestCaseJava4.java   |  606 +++----
 .../org/apache/commons/io/EndianUtilsTest.java     |  280 ++--
 .../commons/io/FileCleaningTrackerTestCase.java    |  184 +-
 .../commons/io/FileDeleteStrategyTestCase.java     |   72 +-
 .../apache/commons/io/FileSystemUtilsTestCase.java |  710 ++++----
 .../io/FileUtilsCleanDirectoryTestCase.java        |   82 +-
 .../commons/io/FileUtilsCleanSymlinksTestCase.java |  162 +-
 .../commons/io/FileUtilsCopyToFileTestCase.java    |   58 +-
 .../io/FileUtilsDirectoryContainsTestCase.java     |   48 +-
 .../commons/io/FileUtilsFileNewerTestCase.java     |   56 +-
 .../commons/io/FileUtilsListFilesTestCase.java     |   82 +-
 .../org/apache/commons/io/FileUtilsTestCase.java   |  313 +---
 .../commons/io/FileUtilsWaitForTestCase.java       |   10 +-
 .../apache/commons/io/FilenameUtilsTestCase.java   | 1750 ++++++++++----------
 .../commons/io/FilenameUtilsWildcardTestCase.java  |  254 +--
 .../java/org/apache/commons/io/HexDumpTest.java    |   20 +-
 .../java/org/apache/commons/io/IOCaseTestCase.java |  264 +--
 .../org/apache/commons/io/IOUtilsTestCase.java     |   16 +-
 .../apache/commons/io/IOUtilsWriteTestCase.java    |  390 ++---
 .../apache/commons/io/LineIteratorTestCase.java    |  348 ++--
 .../org/apache/commons/io/SelectorAdapter.java     |   22 +-
 .../java/org/apache/commons/io/TestResources.java  |    8 +-
 .../apache/commons/io/ThreadMonitorTestCase.java   |   30 +-
 .../io/comparator/ComparatorAbstractTestCase.java  |   16 +-
 .../io/comparator/CompositeFileComparatorTest.java |   74 +-
 .../io/comparator/SizeFileComparatorTest.java      |   16 +-
 .../io/file/CountersEqualsAndHashCodeTest.java     |   10 +-
 .../commons/io/file/CountingPathVisitorTest.java   |   10 +-
 .../io/file/PathUtilsContentEqualsTest.java        |  180 +-
 .../commons/io/file/PathUtilsCountingTest.java     |   10 +
 .../commons/io/file/PathUtilsDeleteFileTest.java   |   32 +-
 .../io/filefilter/AndFileFilterTestCase.java       |   36 +-
 .../ConditionalFileFilterAbstractTestCase.java     |   90 +-
 .../filefilter/IOFileFilterAbstractTestCase.java   |  132 +-
 .../io/filefilter/OrFileFilterTestCase.java        |    8 +-
 .../commons/io/input/BOMInputStreamTest.java       |   74 +-
 .../commons/io/input/BoundedInputStreamTest.java   |   58 +-
 .../apache/commons/io/input/BoundedReaderTest.java |  168 +-
 .../io/input/CharSequenceInputStreamTest.java      |  134 +-
 .../commons/io/input/CharSequenceReaderTest.java   |  176 +-
 .../io/input/ClassLoaderObjectInputStreamTest.java |  100 +-
 .../commons/io/input/CountingInputStreamTest.java  |  116 +-
 .../io/input/MarkShieldInputStreamTest.java        |   40 +-
 .../commons/io/input/NullInputStreamTest.java      |  182 +-
 .../apache/commons/io/input/NullReaderTest.java    |  176 +-
 .../commons/io/input/QueueInputStreamTest.java     |   60 +-
 .../io/input/RandomAccessFileInputStreamTest.java  |   60 +-
 .../commons/io/input/ReaderInputStreamTest.java    |  122 +-
 .../ReversedLinesFileReaderTestParamBlockSize.java |  210 +--
 .../input/ReversedLinesFileReaderTestSimple.java   |   12 +-
 .../commons/io/input/SequenceReaderTest.java       |   16 +-
 .../commons/io/input/TaggedInputStreamTest.java    |   50 +-
 .../apache/commons/io/input/TaggedReaderTest.java  |   48 +-
 .../org/apache/commons/io/input/TailerTest.java    |  430 ++---
 .../commons/io/input/TeeInputStreamTest.java       |  126 +-
 .../io/input/UnixLineEndingInputStreamTest.java    |   38 +-
 .../io/input/WindowsLineEndingInputStreamTest.java |   30 +-
 .../commons/io/input/XmlStreamReaderTest.java      |  556 +++----
 .../io/input/XmlStreamReaderUtilitiesTest.java     |  370 ++---
 .../buffer/CircularBufferInputStreamTest.java      |   46 +-
 .../io/input/compatibility/XmlStreamReader.java    |  778 ++++-----
 .../XmlStreamReaderUtilitiesCompatibilityTest.java |   18 +-
 .../io/monitor/AbstractMonitorTestCase.java        |   64 +-
 .../commons/io/monitor/CollectionFileListener.java |   56 +-
 .../io/monitor/FileAlterationMonitorTestCase.java  |  140 +-
 .../io/monitor/FileAlterationObserverTestCase.java |  154 +-
 .../io/output/AppendableOutputStreamTest.java      |   14 +-
 .../io/output/ByteArrayOutputStreamTestCase.java   |  316 ++--
 .../commons/io/output/ChunkedOutputStreamTest.java |   28 +-
 .../commons/io/output/ChunkedWriterTest.java       |   34 +-
 .../commons/io/output/ClosedOutputStreamTest.java  |   16 +-
 .../apache/commons/io/output/ClosedWriterTest.java |   16 +-
 .../io/output/CountingOutputStreamTest.java        |   12 +-
 .../commons/io/output/LockableFileWriterTest.java  |  114 +-
 .../apache/commons/io/output/ProxyWriterTest.java  |  198 +--
 .../commons/io/output/StringBuilderWriterTest.java |   46 +-
 .../commons/io/output/TaggedOutputStreamTest.java  |   36 +-
 .../apache/commons/io/output/TaggedWriterTest.java |   36 +-
 .../commons/io/output/TeeOutputStreamTest.java     |   26 +-
 .../commons/io/output/WriterOutputStreamTest.java  |  102 +-
 .../commons/io/output/XmlStreamWriterTest.java     |   88 +-
 .../serialization/AbstractCloseableListTest.java   |   22 +-
 .../io/serialization/MockSerializedClass.java      |   10 +-
 .../io/serialization/MoreComplexObjectTest.java    |   30 +-
 .../serialization/RegexpClassNameMatcherTest.java  |   24 +-
 .../ValidatingObjectInputStreamTest.java           |  170 +-
 .../io/test/ThrowOnFlushAndCloseOutputStream.java  |   18 +-
 .../dirs-a-file-size-1/file-size-1.bin             |    1 +
 .../dirs-a-file-size-1/file-size-2.bin             |    1 +
 .../dirs-b-file-size-1/file-size-1.bin             |    1 +
 .../dirs-b-file-size-1/file-size-2.bin             |    1 +
 100 files changed, 6734 insertions(+), 6867 deletions(-)
 create mode 100644 src/test/resources/org/apache/commons/io/dirs-2-file-size-4/dirs-a-file-size-1/file-size-1.bin
 create mode 100644 src/test/resources/org/apache/commons/io/dirs-2-file-size-4/dirs-a-file-size-1/file-size-2.bin
 create mode 100644 src/test/resources/org/apache/commons/io/dirs-2-file-size-4/dirs-b-file-size-1/file-size-1.bin
 create mode 100644 src/test/resources/org/apache/commons/io/dirs-2-file-size-4/dirs-b-file-size-1/file-size-2.bin

[commons-io] 01/04: Nicer Javadoc.

Posted by gg...@apache.org.
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

commit d6d5d0beeec5846e61728a950bf52c916ccad0a9
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Wed Sep 15 10:03:23 2021 -0400

    Nicer Javadoc.
---
 .../java/org/apache/commons/io/file/CountingPathVisitor.java     | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/src/main/java/org/apache/commons/io/file/CountingPathVisitor.java b/src/main/java/org/apache/commons/io/file/CountingPathVisitor.java
index f9ae727..0d96cde 100644
--- a/src/main/java/org/apache/commons/io/file/CountingPathVisitor.java
+++ b/src/main/java/org/apache/commons/io/file/CountingPathVisitor.java
@@ -18,6 +18,7 @@
 package org.apache.commons.io.file;
 
 import java.io.IOException;
+import java.math.BigInteger;
 import java.nio.file.FileVisitResult;
 import java.nio.file.Files;
 import java.nio.file.Path;
@@ -37,18 +38,18 @@ public class CountingPathVisitor extends SimplePathVisitor {
     static final String[] EMPTY_STRING_ARRAY = {};
 
     /**
-     * Creates a new instance configured with a BigInteger {@link PathCounters}.
+     * Creates a new instance configured with a {@link BigInteger} {@link PathCounters}.
      *
-     * @return a new instance configured with a BigInteger {@link PathCounters}.
+     * @return a new instance configured with a {@link BigInteger} {@link PathCounters}.
      */
     public static CountingPathVisitor withBigIntegerCounters() {
         return new CountingPathVisitor(Counters.bigIntegerPathCounters());
     }
 
     /**
-     * Creates a new instance configured with a long {@link PathCounters}.
+     * Creates a new instance configured with a {@code long} {@link PathCounters}.
      *
-     * @return a new instance configured with a long {@link PathCounters}.
+     * @return a new instance configured with a {@code long} {@link PathCounters}.
      */
     public static CountingPathVisitor withLongCounters() {
         return new CountingPathVisitor(Counters.longPathCounters());

[commons-io] 02/04: Add and use PathUtils.sizeOf(Path)

Posted by gg...@apache.org.
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

commit dcb09db922e1edbd6dc6cb1531b827451d58aa83
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Wed Sep 15 10:44:58 2021 -0400

    Add and use PathUtils.sizeOf(Path)
    
    - Add and use PathUtils.sizeOfAsBigInteger(Path)
    - Add and use PathUtils.sizeOfDirectory(Path)
    - Add and use PathUtils.sizeOfDirectoryAsBigInteger(Path)
    - Use assertThrows in tests.
---
 src/changes/changes.xml                            |   6 ++
 src/main/java/org/apache/commons/io/FileUtils.java | 112 ++++++-------------
 .../java/org/apache/commons/io/file/PathUtils.java | 119 +++++++++++++++++++--
 .../org/apache/commons/io/FileUtilsTestCase.java   |  33 ++++++
 .../apache/commons/io/LineIteratorTestCase.java    | 114 ++++----------------
 .../commons/io/file/PathUtilsCountingTest.java     |  10 ++
 .../dirs-a-file-size-1/file-size-1.bin             |   1 +
 .../dirs-a-file-size-1/file-size-2.bin             |   1 +
 .../dirs-b-file-size-1/file-size-1.bin             |   1 +
 .../dirs-b-file-size-1/file-size-2.bin             |   1 +
 10 files changed, 213 insertions(+), 185 deletions(-)

diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 4670cb0..1a6e543 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -190,6 +190,12 @@ The <action> type attribute can be add,update,fix,remove.
         Add and use PathUtils.isOlder(Path, long, LinkOption...)
         Add and use PathUtils.isOlder(Path, Path)
       </action>
+      <action dev="ggregory" type="add" due-to="Gary Gregory">
+        Add and use PathUtils.sizeOf(Path)
+        Add and use PathUtils.sizeOfAsBigInteger(Path)
+        Add and use PathUtils.sizeOfDirectory(Path)
+        Add and use PathUtils.sizeOfDirectoryAsBigInteger(Path)
+      </action>
       <!-- UPDATE -->
       <action dev="ggregory" type="add" due-to="Gary Gregory">
         Update FileEntry to use FileTime instead of long for file time stamps.
diff --git a/src/main/java/org/apache/commons/io/FileUtils.java b/src/main/java/org/apache/commons/io/FileUtils.java
index 8e1d016..9c0d3dd 100644
--- a/src/main/java/org/apache/commons/io/FileUtils.java
+++ b/src/main/java/org/apache/commons/io/FileUtils.java
@@ -2184,7 +2184,7 @@ public class FileUtils {
     public static LineIterator lineIterator(final File file, final String charsetName) throws IOException {
         InputStream inputStream = null;
         try {
-            inputStream = openInputStream(file);
+            inputStream = Files.newInputStream(file.toPath());
             return IOUtils.lineIterator(inputStream, charsetName);
         } catch (final IOException | RuntimeException ex) {
             IOUtils.closeQuietly(inputStream, ex::addSuppressed);
@@ -2644,7 +2644,7 @@ public class FileUtils {
      * @since 2.3
      */
     public static String readFileToString(final File file, final Charset charsetName) throws IOException {
-        try (InputStream inputStream = openInputStream(file)) {
+        try (InputStream inputStream = Files.newInputStream(file.toPath())) {
             return IOUtils.toString(inputStream, Charsets.toCharset(charsetName));
         }
     }
@@ -2699,9 +2699,7 @@ public class FileUtils {
      * @since 2.3
      */
     public static List<String> readLines(final File file, final Charset charset) throws IOException {
-        try (InputStream inputStream = openInputStream(file)) {
-            return IOUtils.readLines(inputStream, Charsets.toCharset(charset));
-        }
+        return Files.readAllLines(file.toPath(), charset);
     }
 
     /**
@@ -2960,27 +2958,18 @@ public class FileUtils {
      *
      * @throws NullPointerException     if the file is {@code null}.
      * @throws IllegalArgumentException if the file does not exist.
+     * @throws UncheckedIOException if an IO error occurs.
      *
      * @since 2.0
      */
     public static long sizeOf(final File file) {
         requireExists(file, "file");
-        return file.isDirectory() ? sizeOfDirectory0(file) : file.length();
-    }
-
-    /**
-     * Gets the size of a file.
-     *
-     * @param file the file to check.
-     * @return the size of the file.
-     * @throws NullPointerException if the file is {@code null}.
-     */
-    private static long sizeOf0(final File file) {
-        Objects.requireNonNull(file, "file");
-        if (file.isDirectory()) {
-            return sizeOfDirectory0(file);
+        try {
+            return PathUtils.sizeOf(file.toPath());
+        } catch (IOException e) {
+            // TODO Update method signature
+            throw new UncheckedIOException(e);
         }
-        return file.length(); // will be 0 if file does not exist
     }
 
     /**
@@ -2998,23 +2987,18 @@ public class FileUtils {
      *
      * @throws NullPointerException     if the file is {@code null}.
      * @throws IllegalArgumentException if the file does not exist.
+     * @throws UncheckedIOException if an IO error occurs.
      *
      * @since 2.4
      */
     public static BigInteger sizeOfAsBigInteger(final File file) {
         requireExists(file, "file");
-        return file.isDirectory() ? sizeOfDirectoryBig0(file) : BigInteger.valueOf(file.length());
-    }
-
-    /**
-     * Returns the size of a file or directory.
-     *
-     * @param file The file or directory.
-     * @return the size
-     */
-    private static BigInteger sizeOfBig0(final File file) {
-        Objects.requireNonNull(file, "fileOrDir");
-        return file.isDirectory() ? sizeOfDirectoryBig0(file) : BigInteger.valueOf(file.length());
+        try {
+            return PathUtils.sizeOfAsBigInteger(file.toPath());
+        } catch (IOException e) {
+            // TODO Update method signature
+            throw new UncheckedIOException(e);
+        }
     }
 
     /**
@@ -3029,36 +3013,16 @@ public class FileUtils {
      * @return size of directory in bytes, 0 if directory is security restricted, a negative number when the real total
      * is greater than {@link Long#MAX_VALUE}.
      * @throws NullPointerException if the directory is {@code null}.
+     * @throws UncheckedIOException if an IO error occurs.
      */
     public static long sizeOfDirectory(final File directory) {
-        return sizeOfDirectory0(requireDirectoryExists(directory, "directory"));
-    }
-
-    /**
-     * Gets the size of a directory.
-     *
-     * @param directory the directory to check
-     * @return the size
-     * @throws NullPointerException if the directory is {@code null}.
-     */
-    private static long sizeOfDirectory0(final File directory) {
-        Objects.requireNonNull(directory, "directory");
-        final File[] files = directory.listFiles();
-        if (files == null) {  // null if security restricted
-            return 0L;
-        }
-        long size = 0;
-
-        for (final File file : files) {
-            if (!isSymlink(file)) {
-                size += sizeOf0(file);
-                if (size < 0) {
-                    break;
-                }
-            }
+        requireDirectoryExists(directory, "directory");
+        try {
+            return PathUtils.sizeOfDirectory(directory.toPath());
+        } catch (IOException e) {
+            // TODO Update method signature
+            throw new UncheckedIOException(e);
         }
-
-        return size;
     }
 
     /**
@@ -3067,34 +3031,18 @@ public class FileUtils {
      * @param directory directory to inspect, must not be {@code null}.
      * @return size of directory in bytes, 0 if directory is security restricted.
      * @throws NullPointerException if the directory is {@code null}.
+     * @throws UncheckedIOException if an IO error occurs.
      * @since 2.4
      */
     public static BigInteger sizeOfDirectoryAsBigInteger(final File directory) {
-        return sizeOfDirectoryBig0(requireDirectoryExists(directory, "directory"));
-    }
-
-    /**
-     * Computes the size of a directory.
-     *
-     * @param directory The directory.
-     * @return the size.
-     */
-    private static BigInteger sizeOfDirectoryBig0(final File directory) {
-        Objects.requireNonNull(directory, "directory");
-        final File[] files = directory.listFiles();
-        if (files == null) {
-            // null if security restricted
-            return BigInteger.ZERO;
-        }
-        BigInteger size = BigInteger.ZERO;
-
-        for (final File file : files) {
-            if (!isSymlink(file)) {
-                size = size.add(sizeOfBig0(file));
-            }
+        requireDirectoryExists(directory, "directory");
+        try {
+            return PathUtils.sizeOfDirectoryAsBigInteger(directory.toPath());
+        } catch (IOException e) {
+            // TODO Update method signature
+            throw new UncheckedIOException(e);
         }
 
-        return size;
     }
 
     /**
diff --git a/src/main/java/org/apache/commons/io/file/PathUtils.java b/src/main/java/org/apache/commons/io/file/PathUtils.java
index b7e736c..1759d2d 100644
--- a/src/main/java/org/apache/commons/io/file/PathUtils.java
+++ b/src/main/java/org/apache/commons/io/file/PathUtils.java
@@ -22,6 +22,7 @@ import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.io.UncheckedIOException;
+import java.math.BigInteger;
 import java.net.URI;
 import java.net.URL;
 import java.nio.charset.Charset;
@@ -305,7 +306,18 @@ public final class PathUtils {
      * @throws IOException if an I/O error is thrown by a visitor method.
      */
     public static PathCounters countDirectory(final Path directory) throws IOException {
-        return visitFileTree(new CountingPathVisitor(Counters.longPathCounters()), directory).getPathCounters();
+        return visitFileTree(CountingPathVisitor.withLongCounters(), directory).getPathCounters();
+    }
+
+    /**
+     * Counts aspects of a directory including sub-directories.
+     *
+     * @param directory directory to delete.
+     * @return The visitor used to count the given directory.
+     * @throws IOException if an I/O error is thrown by a visitor method.
+     */
+    public static PathCounters countDirectoryAsBigInteger(final Path directory) throws IOException {
+        return visitFileTree(CountingPathVisitor.withBigIntegerCounters(), directory).getPathCounters();
     }
 
     /**
@@ -499,7 +511,7 @@ public final class PathUtils {
      * @param path1 The first directory.
      * @param path2 The second directory.
      * @return Whether the two directories contain the same files while considering file contents.
-     * @throws IOException if an I/O error is thrown by a visitor method
+     * @throws IOException if an I/O error is thrown by a visitor method.
      */
     public static boolean directoryAndFileContentEquals(final Path path1, final Path path2) throws IOException {
         return directoryAndFileContentEquals(path1, path2, EMPTY_LINK_OPTION_ARRAY, EMPTY_OPEN_OPTION_ARRAY, EMPTY_FILE_VISIT_OPTION_ARRAY);
@@ -515,7 +527,7 @@ public final class PathUtils {
      * @param openOptions options to open files.
      * @param fileVisitOption options to configure traversal.
      * @return Whether the two directories contain the same files while considering file contents.
-     * @throws IOException if an I/O error is thrown by a visitor method
+     * @throws IOException if an I/O error is thrown by a visitor method.
      */
     public static boolean directoryAndFileContentEquals(final Path path1, final Path path2, final LinkOption[] linkOptions, final OpenOption[] openOptions,
         final FileVisitOption[] fileVisitOption) throws IOException {
@@ -556,7 +568,7 @@ public final class PathUtils {
      * @param path1 The first directory.
      * @param path2 The second directory.
      * @return Whether the two directories contain the same files without considering file contents.
-     * @throws IOException if an I/O error is thrown by a visitor method
+     * @throws IOException if an I/O error is thrown by a visitor method.
      */
     public static boolean directoryContentEquals(final Path path1, final Path path2) throws IOException {
         return directoryContentEquals(path1, path2, Integer.MAX_VALUE, EMPTY_LINK_OPTION_ARRAY, EMPTY_FILE_VISIT_OPTION_ARRAY);
@@ -572,7 +584,7 @@ public final class PathUtils {
      * @param linkOptions options to follow links.
      * @param fileVisitOptions options to configure the traversal
      * @return Whether the two directories contain the same files without considering file contents.
-     * @throws IOException if an I/O error is thrown by a visitor method
+     * @throws IOException if an I/O error is thrown by a visitor method.
      */
     public static boolean directoryContentEquals(final Path path1, final Path path2, final int maxDepth, final LinkOption[] linkOptions,
         final FileVisitOption[] fileVisitOptions) throws IOException {
@@ -1123,6 +1135,94 @@ public final class PathUtils {
     }
 
     /**
+     * Returns the size of the specified file or directory. If the provided {@link File} is a regular file, then the file's
+     * length is returned. If the argument is a directory, then the size of the directory is calculated recursively. If a
+     * directory or subdirectory is security restricted, its size will not be included.
+     * <p>
+     * Note that overflow is not detected, and the return value may be negative if overflow occurs. See
+     * {@link #sizeOfAsBigInteger(Path)} for an alternative method that does not overflow.
+     * </p>
+     *
+     * @param path the regular file or directory to return the size of (must not be {@code null}).
+     * @return the length of the file, or recursive size of the directory, provided (in bytes).
+     * @throws NullPointerException if the file is {@code null}.
+     * @throws IllegalArgumentException if the file does not exist.
+     * @throws IOException if an I/O error occurs.
+     *
+     * @since 2.12.0
+     */
+    public static long sizeOf(final Path path) throws IOException {
+        requireExists(path, "path");
+        return Files.isDirectory(path) ? sizeOfDirectory(path) : Files.size(path);
+    }
+
+    /**
+     * Returns the size of the specified file or directory. If the provided {@link Path} is a regular file, then the file's
+     * length is returned. If the argument is a directory, then the size of the directory is calculated recursively. If a
+     * directory or subdirectory is security restricted, its size will not be included.
+     *
+     * @param path the regular file or directory to return the size of (must not be {@code null}).
+     * @return the length of the file, or recursive size of the directory, provided (in bytes).
+     * @throws NullPointerException if the file is {@code null}.
+     * @throws IllegalArgumentException if the file does not exist.
+     * @throws IOException if an I/O error occurs.
+     *
+     * @since 2.12.0
+     */
+    public static BigInteger sizeOfAsBigInteger(final Path path) throws IOException {
+        requireExists(path, "path");
+        return Files.isDirectory(path) ? sizeOfDirectoryAsBigInteger(path) : BigInteger.valueOf(Files.size(path));
+    }
+
+    /**
+     * Counts the size of a directory recursively (sum of the length of all files).
+     * <p>
+     * Note that overflow is not detected, and the return value may be negative if overflow occurs. See
+     * {@link #sizeOfDirectoryAsBigInteger(Path)} for an alternative method that does not overflow.
+     * </p>
+     *
+     * @param directory directory to inspect, must not be {@code null}.
+     * @return size of directory in bytes, 0 if directory is security restricted, a negative number when the real total is
+     *         greater than {@link Long#MAX_VALUE}.
+     * @throws NullPointerException if the directory is {@code null}.
+     * @throws IOException if an I/O error occurs.
+     * @since 2.12.0
+     */
+    public static long sizeOfDirectory(final Path directory) throws IOException {
+        return countDirectory(directory).getByteCounter().getLong();
+    }
+
+    /**
+     * Counts the size of a directory recursively (sum of the length of all files).
+     *
+     * @param directory directory to inspect, must not be {@code null}.
+     * @return size of directory in bytes, 0 if directory is security restricted.
+     * @throws NullPointerException if the directory is {@code null}.
+     * @throws IOException if an I/O error occurs.
+     * @since 2.12.0
+     */
+    public static BigInteger sizeOfDirectoryAsBigInteger(final Path directory) throws IOException {
+        return countDirectoryAsBigInteger(directory).getByteCounter().getBigInteger();
+    }
+
+    /**
+     * Requires that the given {@code File} exists and throws an {@link IllegalArgumentException} if it doesn't.
+     *
+     * @param file The {@code File} to check.
+     * @param fileParamName The parameter name to use in the exception message in case of {@code null} input.
+     * @return the given file.
+     * @throws NullPointerException if the given {@code File} is {@code null}.
+     * @throws IllegalArgumentException if the given {@code File} does not exist.
+     */
+    private static Path requireExists(final Path file, final String fileParamName) {
+        Objects.requireNonNull(file, fileParamName);
+        if (!Files.exists(file)) {
+            throw new IllegalArgumentException("File system element for parameter '" + fileParamName + "' does not exist: '" + file + "'");
+        }
+        return file;
+    }
+
+    /**
      * Converts an array of {@link FileVisitOption} to a {@link Set}.
      *
      * @param fileVisitOptions input array.
@@ -1142,9 +1242,10 @@ public final class PathUtils {
      * @param <T> See {@link Files#walkFileTree(Path,FileVisitor)}.
      * @return the given visitor.
      *
-     * @throws IOException if an I/O error is thrown by a visitor method
+     * @throws IOException if an I/O error is thrown by a visitor method.
      */
     public static <T extends FileVisitor<? super Path>> T visitFileTree(final T visitor, final Path directory) throws IOException {
+        requireExists(directory, "directory");
         Files.walkFileTree(directory, visitor);
         return visitor;
     }
@@ -1161,7 +1262,7 @@ public final class PathUtils {
      * @param <T> See {@link Files#walkFileTree(Path,Set,int,FileVisitor)}.
      * @return the given visitor.
      *
-     * @throws IOException if an I/O error is thrown by a visitor method
+     * @throws IOException if an I/O error is thrown by a visitor method.
      */
     public static <T extends FileVisitor<? super Path>> T visitFileTree(final T visitor, final Path start, final Set<FileVisitOption> options,
         final int maxDepth) throws IOException {
@@ -1180,7 +1281,7 @@ public final class PathUtils {
      * @param <T> See {@link Files#walkFileTree(Path,FileVisitor)}.
      * @return the given visitor.
      *
-     * @throws IOException if an I/O error is thrown by a visitor method
+     * @throws IOException if an I/O error is thrown by a visitor method.
      */
     public static <T extends FileVisitor<? super Path>> T visitFileTree(final T visitor, final String first, final String... more) throws IOException {
         return visitFileTree(visitor, Paths.get(first, more));
@@ -1196,7 +1297,7 @@ public final class PathUtils {
      * @param <T> See {@link Files#walkFileTree(Path,FileVisitor)}.
      * @return the given visitor.
      *
-     * @throws IOException if an I/O error is thrown by a visitor method
+     * @throws IOException if an I/O error is thrown by a visitor method.
      */
     public static <T extends FileVisitor<? super Path>> T visitFileTree(final T visitor, final URI uri) throws IOException {
         return visitFileTree(visitor, Paths.get(uri));
diff --git a/src/test/java/org/apache/commons/io/FileUtilsTestCase.java b/src/test/java/org/apache/commons/io/FileUtilsTestCase.java
index 4509ffc..8bf4b57 100644
--- a/src/test/java/org/apache/commons/io/FileUtilsTestCase.java
+++ b/src/test/java/org/apache/commons/io/FileUtilsTestCase.java
@@ -42,6 +42,7 @@ import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.nio.file.StandardCopyOption;
 import java.time.Instant;
 import java.time.LocalDate;
@@ -3227,4 +3228,36 @@ public class FileUtilsTestCase {
         assertEquals(expected, actual);
     }
 
+    /**
+     * Tests a directory with one file of size 0.
+     */
+    @Test
+    public void testCountFolders1FileSize0() throws IOException {
+        assertEquals(0, FileUtils.sizeOfDirectory(Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-0").toFile()));
+    }
+
+    /**
+     * Tests a directory with one file of size 1.
+     */
+    @Test
+    public void testCountFolders1FileSize1() throws IOException {
+        assertEquals(1, FileUtils.sizeOfDirectory(Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-1").toFile()));
+    }
+
+    /**
+     * Tests a directory with two subdirectories, each containing one file of size 1.
+     */
+    @Test
+    public void testCountFolders2FileSize2() throws IOException {
+        assertEquals(2, FileUtils.sizeOfDirectory(Paths.get("src/test/resources/org/apache/commons/io/dirs-2-file-size-2").toFile()));
+    }
+
+    /**
+     * Tests a directory with two subdirectories, each containing one file of size 1.
+     */
+    @Test
+    public void testCountFolders2FileSize4() throws IOException {
+        assertEquals(8, FileUtils.sizeOfDirectory(Paths.get("src/test/resources/org/apache/commons/io/dirs-2-file-size-4").toFile()));
+    }
+
 }
diff --git a/src/test/java/org/apache/commons/io/LineIteratorTestCase.java b/src/test/java/org/apache/commons/io/LineIteratorTestCase.java
index 4c5ec33..82831ca 100644
--- a/src/test/java/org/apache/commons/io/LineIteratorTestCase.java
+++ b/src/test/java/org/apache/commons/io/LineIteratorTestCase.java
@@ -31,6 +31,7 @@ import java.io.Reader;
 import java.io.StringReader;
 import java.nio.charset.UnsupportedCharsetException;
 import java.nio.file.Files;
+import java.nio.file.NoSuchFileException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.NoSuchElementException;
@@ -112,9 +113,8 @@ public class LineIteratorTestCase {
     @Test
     public void testConstructor() {
         assertThrows(IllegalArgumentException.class, () -> {
-            try (
-                LineIterator li = new LineIterator(null)
-            ) { }
+            try (LineIterator li = new LineIterator(null)) {
+            }
         });
     }
 
@@ -141,14 +141,7 @@ public class LineIteratorTestCase {
     @Test
     public void testMissingFile() throws Exception {
         final File testFile = new File(temporaryFolder, "dummy-missing-file.txt");
-
-        try (
-            LineIterator iterator = FileUtils.lineIterator(testFile, "UTF-8")
-        ){
-            fail("Expected FileNotFoundException");
-        } catch (final FileNotFoundException expected) {
-            // ignore, expected result
-        }
+        assertThrows(NoSuchFileException.class, () -> FileUtils.lineIterator(testFile, "UTF-8"));
     }
 
     @Test
@@ -158,9 +151,7 @@ public class LineIteratorTestCase {
         final File testFile = new File(temporaryFolder, "LineIterator-validEncoding.txt");
         createLinesFile(testFile, encoding, 3);
 
-        try (
-            final LineIterator iterator = FileUtils.lineIterator(testFile, encoding)
-        ){
+        try (final LineIterator iterator = FileUtils.lineIterator(testFile, encoding)) {
             int count = 0;
             while (iterator.hasNext()) {
                 assertNotNull(iterator.next());
@@ -177,13 +168,7 @@ public class LineIteratorTestCase {
         final File testFile = new File(temporaryFolder, "LineIterator-invalidEncoding.txt");
         createLinesFile(testFile, "UTF-8", 3);
 
-        try (
-            LineIterator iterator = FileUtils.lineIterator(testFile, encoding)
-        ) {
-            fail("Expected UnsupportedCharsetException");
-        } catch (final UnsupportedCharsetException expected) {
-            // ignore, expected result
-        }
+        assertThrows(UnsupportedCharsetException.class, () -> FileUtils.lineIterator(testFile, encoding));
     }
 
     @Test
@@ -224,9 +209,7 @@ public class LineIteratorTestCase {
         final File testFile = new File(temporaryFolder, "LineIterator-nextOnly.txt");
         final List<String> lines = createLinesFile(testFile, encoding, 3);
 
-        try (
-            final LineIterator iterator = FileUtils.lineIterator(testFile, encoding)
-        ){
+        try (final LineIterator iterator = FileUtils.lineIterator(testFile, encoding)) {
             for (int i = 0; i < lines.size(); i++) {
                 final String line = iterator.next();
                 assertEquals(lines.get(i), line, "next() line " + i);
@@ -243,9 +226,7 @@ public class LineIteratorTestCase {
                 throw new IOException("hasNext");
             }
         };
-        try (
-            LineIterator li = new LineIterator(reader)
-        ) {
+        try (LineIterator li = new LineIterator(reader)) {
             assertThrows(IllegalStateException.class, () -> {
                 li.hasNext();
             });
@@ -259,9 +240,7 @@ public class LineIteratorTestCase {
         final File testFile = new File(temporaryFolder, "LineIterator-closeEarly.txt");
         createLinesFile(testFile, encoding, 3);
 
-        try (
-            final LineIterator iterator = FileUtils.lineIterator(testFile, encoding)
-        ) {
+        try (final LineIterator iterator = FileUtils.lineIterator(testFile, encoding)) {
             // get
             assertNotNull("Line expected", iterator.next());
             assertTrue(iterator.hasNext(), "More expected");
@@ -269,33 +248,12 @@ public class LineIteratorTestCase {
             // close
             iterator.close();
             assertFalse(iterator.hasNext(), "No more expected");
-            try {
-                iterator.next();
-                fail();
-            } catch (final NoSuchElementException ex) {
-                // expected
-            }
-            try {
-                iterator.nextLine();
-                fail();
-            } catch (final NoSuchElementException ex) {
-                // expected
-            }
-
+            assertThrows(NoSuchElementException.class, iterator::next);
+            assertThrows(NoSuchElementException.class, iterator::nextLine);
             // try closing again
             iterator.close();
-            try {
-                iterator.next();
-                fail();
-            } catch (final NoSuchElementException ex) {
-                // expected
-            }
-            try {
-                iterator.nextLine();
-                fail();
-            } catch (final NoSuchElementException ex) {
-                // expected
-            }
+            assertThrows(NoSuchElementException.class, iterator::next);
+            assertThrows(NoSuchElementException.class, iterator::nextLine);
         }
     }
 
@@ -313,15 +271,8 @@ public class LineIteratorTestCase {
         final File testFile = new File(temporaryFolder, fileName);
         final List<String> lines = createLinesFile(testFile, encoding, lineCount);
 
-        try (
-            final LineIterator iterator = FileUtils.lineIterator(testFile, encoding)
-        ){
-            try {
-                iterator.remove();
-                fail("Remove is unsupported");
-            } catch (final UnsupportedOperationException ex) {
-                // expected
-            }
+        try (final LineIterator iterator = FileUtils.lineIterator(testFile, encoding)) {
+            assertThrows(UnsupportedOperationException.class, iterator::remove);
 
             int idx = 0;
             while (iterator.hasNext()) {
@@ -333,18 +284,8 @@ public class LineIteratorTestCase {
             assertEquals(idx, lines.size(), "Line Count doesn't match");
 
             // try calling next() after file processed
-            try {
-                iterator.next();
-                fail("Expected NoSuchElementException");
-            } catch (final NoSuchElementException expected) {
-                // ignore, expected result
-            }
-            try {
-                iterator.nextLine();
-                fail("Expected NoSuchElementException");
-            } catch (final NoSuchElementException expected) {
-                // ignore, expected result
-            }
+            assertThrows(NoSuchElementException.class, iterator::next);
+            assertThrows(NoSuchElementException.class, iterator::nextLine);
         }
     }
 
@@ -382,12 +323,7 @@ public class LineIteratorTestCase {
             }
         };
         try {
-            try {
-                iterator.remove();
-                fail("Remove is unsupported");
-            } catch (final UnsupportedOperationException ex) {
-                // expected
-            }
+            assertThrows(UnsupportedOperationException.class, iterator::remove);
 
             int idx = 0;
             int actualLines = 0;
@@ -406,18 +342,8 @@ public class LineIteratorTestCase {
             assertEquals(6, actualLines, "Line Count doesn't match");
 
             // try calling next() after file processed
-            try {
-                iterator.next();
-                fail("Expected NoSuchElementException");
-            } catch (final NoSuchElementException expected) {
-                // ignore, expected result
-            }
-            try {
-                iterator.nextLine();
-                fail("Expected NoSuchElementException");
-            } catch (final NoSuchElementException expected) {
-                // ignore, expected result
-            }
+            assertThrows(NoSuchElementException.class, iterator::next);
+            assertThrows(NoSuchElementException.class, iterator::nextLine);
         } finally {
             try {
                 IOUtils.close(iterator);
diff --git a/src/test/java/org/apache/commons/io/file/PathUtilsCountingTest.java b/src/test/java/org/apache/commons/io/file/PathUtilsCountingTest.java
index 74c7125..c0829c5 100644
--- a/src/test/java/org/apache/commons/io/file/PathUtilsCountingTest.java
+++ b/src/test/java/org/apache/commons/io/file/PathUtilsCountingTest.java
@@ -75,4 +75,14 @@ public class PathUtilsCountingTest {
                 .countDirectory(Paths.get("src/test/resources/org/apache/commons/io/dirs-2-file-size-2"));
         assertCounts(3, 2, 2, pathCounts);
     }
+
+    /**
+     * Tests a directory with two subdirectories, each containing one file of size 2.
+     */
+    @Test
+    public void testCountFolders2FileSize4() throws IOException {
+        final PathCounters pathCounts = PathUtils
+                .countDirectory(Paths.get("src/test/resources/org/apache/commons/io/dirs-2-file-size-4"));
+        assertCounts(3, 4, 8, pathCounts);
+    }
 }
diff --git a/src/test/resources/org/apache/commons/io/dirs-2-file-size-4/dirs-a-file-size-1/file-size-1.bin b/src/test/resources/org/apache/commons/io/dirs-2-file-size-4/dirs-a-file-size-1/file-size-1.bin
new file mode 100644
index 0000000..9ae9e86
--- /dev/null
+++ b/src/test/resources/org/apache/commons/io/dirs-2-file-size-4/dirs-a-file-size-1/file-size-1.bin
@@ -0,0 +1 @@
+ab
\ No newline at end of file
diff --git a/src/test/resources/org/apache/commons/io/dirs-2-file-size-4/dirs-a-file-size-1/file-size-2.bin b/src/test/resources/org/apache/commons/io/dirs-2-file-size-4/dirs-a-file-size-1/file-size-2.bin
new file mode 100644
index 0000000..eb49652
--- /dev/null
+++ b/src/test/resources/org/apache/commons/io/dirs-2-file-size-4/dirs-a-file-size-1/file-size-2.bin
@@ -0,0 +1 @@
+ac
\ No newline at end of file
diff --git a/src/test/resources/org/apache/commons/io/dirs-2-file-size-4/dirs-b-file-size-1/file-size-1.bin b/src/test/resources/org/apache/commons/io/dirs-2-file-size-4/dirs-b-file-size-1/file-size-1.bin
new file mode 100644
index 0000000..9ae9e86
--- /dev/null
+++ b/src/test/resources/org/apache/commons/io/dirs-2-file-size-4/dirs-b-file-size-1/file-size-1.bin
@@ -0,0 +1 @@
+ab
\ No newline at end of file
diff --git a/src/test/resources/org/apache/commons/io/dirs-2-file-size-4/dirs-b-file-size-1/file-size-2.bin b/src/test/resources/org/apache/commons/io/dirs-2-file-size-4/dirs-b-file-size-1/file-size-2.bin
new file mode 100644
index 0000000..eb49652
--- /dev/null
+++ b/src/test/resources/org/apache/commons/io/dirs-2-file-size-4/dirs-b-file-size-1/file-size-2.bin
@@ -0,0 +1 @@
+ac
\ No newline at end of file

[commons-io] 04/04: Use assertThrows and don't catch and rethrow exceptions in tests.

Posted by gg...@apache.org.
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

commit 23c837f830724a342bbbfa3ae9061ecf48cf4a3b
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Wed Sep 15 11:38:18 2021 -0400

    Use assertThrows and don't catch and rethrow exceptions in tests.
    
    Simplify some exception assertion.
---
 .../org/apache/commons/io/FileUtilsTestCase.java   | 268 ++++-----------------
 1 file changed, 53 insertions(+), 215 deletions(-)

diff --git a/src/test/java/org/apache/commons/io/FileUtilsTestCase.java b/src/test/java/org/apache/commons/io/FileUtilsTestCase.java
index 64704b3..092e204 100644
--- a/src/test/java/org/apache/commons/io/FileUtilsTestCase.java
+++ b/src/test/java/org/apache/commons/io/FileUtilsTestCase.java
@@ -552,12 +552,7 @@ public class FileUtilsTestCase {
 
     @Test
     public void testChecksumOnDirectory() throws Exception {
-        try {
-            FileUtils.checksum(new File("."), new CRC32());
-            fail();
-        } catch (final IllegalArgumentException ex) {
-            // expected
-        }
+        assertThrows(IllegalArgumentException.class, () -> FileUtils.checksum(new File("."), new CRC32()));
     }
 
     @Test
@@ -566,22 +561,12 @@ public class FileUtilsTestCase {
         final String text = "Imagination is more important than knowledge - Einstein";
         final File file = new File(temporaryFolder, "checksum-test.txt");
         FileUtils.writeStringToFile(file, text, "US-ASCII");
-        try {
-            FileUtils.checksum(file, null);
-            fail();
-        } catch (final NullPointerException ex) {
-            // expected
-        }
+        assertThrows(NullPointerException.class, () -> FileUtils.checksum(file, null));
     }
 
     @Test
     public void testChecksumOnNullFile() throws Exception {
-        try {
-            FileUtils.checksum(null, new CRC32());
-            fail();
-        } catch (final NullPointerException ex) {
-            // expected
-        }
+        assertThrows(NullPointerException.class, () -> FileUtils.checksum(null, new CRC32()));
     }
 
     // Compare sizes of a directory tree using long and BigInteger methods
@@ -1346,12 +1331,7 @@ public class FileUtilsTestCase {
 
     @Test
     public void testDeleteDirectoryWithNonDirectory() throws Exception {
-        try {
-            FileUtils.deleteDirectory(testFile1);
-            fail();
-        } catch (final IllegalArgumentException ex) {
-            // expected
-        }
+        assertThrows(IllegalArgumentException.class, () -> FileUtils.deleteDirectory(testFile1));
     }
 
     @Test
@@ -1402,23 +1382,14 @@ public class FileUtilsTestCase {
 
     @Test
     public void testDeleteQuietlyForNull() {
-        try {
-            FileUtils.deleteQuietly(null);
-        } catch (final Exception ex) {
-            fail(ex.getMessage());
-        }
+        FileUtils.deleteQuietly(null);
     }
 
     @Test
     public void testDeleteQuietlyNonExistent() {
         final File testFile = new File("testDeleteQuietlyNonExistent");
         assertFalse(testFile.exists());
-
-        try {
-            FileUtils.deleteQuietly(testFile);
-        } catch (final Exception ex) {
-            fail(ex.getMessage());
-        }
+        FileUtils.deleteQuietly(testFile);
     }
 
     /*
@@ -1473,11 +1444,8 @@ public class FileUtilsTestCase {
     public void testForceDeleteAFile3() throws Exception {
         final File destination = new File(temporaryFolder, "no_such_file");
         assertFalse(destination.exists(), "Check No Exist");
-        try {
-            FileUtils.forceDelete(destination);
-            fail("Should generate FileNotFoundException");
-        } catch (final FileNotFoundException ignored) {
-        }
+        assertThrows(FileNotFoundException.class, () -> FileUtils.forceDelete(destination));
+
     }
 
     @Test
@@ -1549,8 +1517,6 @@ public class FileUtilsTestCase {
         assertFalse(testFile.exists());
     }
 
-    // copyFileToDirectory
-
     @Test
     public void testGetFile() {
         final File expected_A = new File("src");
@@ -1559,12 +1525,8 @@ public class FileUtilsTestCase {
         assertEquals(expected_A, FileUtils.getFile("src"), "A");
         assertEquals(expected_B, FileUtils.getFile("src", "main"), "B");
         assertEquals(expected_C, FileUtils.getFile("src", "main", "java"), "C");
-        try {
-            FileUtils.getFile((String[]) null);
-            fail("Expected NullPointerException");
-        } catch (final NullPointerException e) {
-            // expected
-        }
+        assertThrows(NullPointerException.class, () -> FileUtils.getFile((String[]) null));
+
     }
 
     @Test
@@ -1576,22 +1538,10 @@ public class FileUtilsTestCase {
         assertEquals(expected_A, FileUtils.getFile(parent, "src"), "A");
         assertEquals(expected_B, FileUtils.getFile(parent, "src", "main"), "B");
         assertEquals(expected_C, FileUtils.getFile(parent, "src", "main", "java"), "C");
-        try {
-            FileUtils.getFile(parent, (String[]) null);
-            fail("Expected NullPointerException");
-        } catch (final NullPointerException e) {
-            // expected
-        }
-        try {
-            FileUtils.getFile((File) null, "src");
-            fail("Expected NullPointerException");
-        } catch (final NullPointerException e) {
-            // expected
-        }
+        assertThrows(NullPointerException.class, () -> FileUtils.getFile(parent, (String[]) null));
+        assertThrows(NullPointerException.class, () -> FileUtils.getFile((File) null, "src"));
     }
 
-    // forceDelete
-
     @Test
     public void testGetTempDirectory() {
         final File tempDirectory = new File(System.getProperty("java.io.tmpdir"));
@@ -1600,8 +1550,7 @@ public class FileUtilsTestCase {
 
     @Test
     public void testGetTempDirectoryPath() {
-        assertEquals(System.getProperty("java.io.tmpdir"),
-                FileUtils.getTempDirectoryPath());
+        assertEquals(System.getProperty("java.io.tmpdir"), FileUtils.getTempDirectoryPath());
     }
 
     @Test
@@ -1612,8 +1561,7 @@ public class FileUtilsTestCase {
 
     @Test
     public void testGetUserDirectoryPath() {
-        assertEquals(System.getProperty("user.home"),
-                FileUtils.getUserDirectoryPath());
+        assertEquals(System.getProperty("user.home"), FileUtils.getUserDirectoryPath());
     }
 
     // This test relies on FileUtils.copyFile using File.length to check the output size
@@ -1649,12 +1597,7 @@ public class FileUtilsTestCase {
         final File dest = new File(src, "dir2");
         assertTrue(dest.mkdirs());
         assertTrue(src.exists());
-        try {
-            FileUtils.moveDirectoryToDirectory(src, dest, false);
-            fail("expected IOException");
-        } catch (final IOException ioe) {
-            // expected
-        }
+        assertThrows(IOException.class, () -> FileUtils.moveDirectoryToDirectory(src, dest, false));
         assertTrue(src.exists());
     }
 
@@ -1777,13 +1720,7 @@ public class FileUtilsTestCase {
         assertFalse(FileUtils.isFileNewer(newFile, localDatePlusDay, localTime), "New File - Newer - LocalDate plus one day,ZoneId");
         assertFalse(FileUtils.isFileNewer(invalidFile, reference), "Invalid - Newer - File");
         final String invalidFileName = invalidFile.getName();
-        try {
-            FileUtils.isFileNewer(newFile, invalidFile);
-            fail("Should have cause IllegalArgumentException");
-        } catch (final IllegalArgumentException iae) {
-            final String message = iae.getMessage();
-            assertTrue(message.contains(invalidFileName), "Message should contain: " + invalidFileName + " but was: " + message);
-        }
+        assertThrows(IllegalArgumentException.class, () -> FileUtils.isFileNewer(newFile, invalidFile));
 
         // Test isFileOlder()
         assertTrue(FileUtils.isFileOlder(oldFile, reference), "Old File - Older - File");
@@ -1812,14 +1749,6 @@ public class FileUtilsTestCase {
 
         assertFalse(FileUtils.isFileOlder(invalidFile, reference), "Invalid - Older - File");
         assertThrows(IllegalArgumentException.class, () -> FileUtils.isFileOlder(newFile, invalidFile));
-        try {
-            FileUtils.isFileOlder(newFile, invalidFile);
-            fail("Should have cause IllegalArgumentException");
-        } catch (final IllegalArgumentException iae) {
-            final String message = iae.getMessage();
-            assertTrue(message.contains(invalidFileName), "Message should contain: " + invalidFileName + " but was: " + message);
-        }
-
 
         // ----- Test isFileNewer() exceptions -----
         // Null File
@@ -2103,19 +2032,13 @@ public class FileUtilsTestCase {
     public void testMoveDirectory_Errors() throws Exception {
         assertThrows(NullPointerException.class, () -> FileUtils.moveDirectory(null, new File("foo")));
         assertThrows(NullPointerException.class, () -> FileUtils.moveDirectory(new File("foo"), null));
-        try {
-            FileUtils.moveDirectory(new File("nonexistant"), new File("foo"));
-            fail("Expected FileNotFoundException for source");
-        } catch (final FileNotFoundException e) {
-            // expected
-        }
+        assertThrows(FileNotFoundException.class, () -> FileUtils.moveDirectory(new File("nonexistant"), new File("foo")));
+
         final File testFile = new File(temporaryFolder, "testMoveDirectoryFile");
         if (!testFile.getParentFile().exists()) {
-            throw new IOException("Cannot create file " + testFile
-                    + " as the parent directory does not exist");
+            throw new IOException("Cannot create file " + testFile + " as the parent directory does not exist");
         }
-        final OutputStream output =
-                new BufferedOutputStream(Files.newOutputStream(testFile.toPath()));
+        final OutputStream output = new BufferedOutputStream(Files.newOutputStream(testFile.toPath()));
         try {
             TestUtils.generateTestData(output, 0);
         } finally {
@@ -2126,12 +2049,9 @@ public class FileUtilsTestCase {
         final File testDestFile = new File(temporaryFolder, "testMoveDirectoryDest");
         testSrcFile.mkdir();
         testDestFile.mkdir();
-        try {
-            FileUtils.moveDirectory(testSrcFile, testDestFile);
-            fail("Expected FileExistsException when dest already exists");
-        } catch (final FileExistsException e) {
-            // expected
-        }
+        assertThrows(FileExistsException.class, () -> FileUtils.moveDirectory(testSrcFile, testDestFile),
+            "Expected FileExistsException when dest already exists");
+
     }
 
     @Test
@@ -2227,20 +2147,10 @@ public class FileUtilsTestCase {
         } finally {
             IOUtils.closeQuietly(output);
         }
-        try {
-            FileUtils.moveDirectoryToDirectory(testFile1, testFile2, true);
-            fail("Expected IOException when dest not a directory");
-        } catch (final IOException e) {
-            // expected
-        }
+        assertThrows(IOException.class, () -> FileUtils.moveDirectoryToDirectory(testFile1, testFile2, true));
 
         final File nonexistant = new File(temporaryFolder, "testMoveFileNonExistant");
-        try {
-            FileUtils.moveDirectoryToDirectory(testFile1, nonexistant, false);
-            fail("Expected IOException when dest does not exist and create=false");
-        } catch (final IOException e) {
-            // expected
-        }
+        assertThrows(IOException.class, () -> FileUtils.moveDirectoryToDirectory(testFile1, nonexistant, false));
     }
 
     @Test
@@ -2354,43 +2264,28 @@ public class FileUtilsTestCase {
     public void testMoveFile_Errors() throws Exception {
         assertThrows(NullPointerException.class, () -> FileUtils.moveFile(null, new File("foo")));
         assertThrows(NullPointerException.class, () -> FileUtils.moveFile(new File("foo"), null));
-        try {
-            FileUtils.moveFile(new File("nonexistant"), new File("foo"));
-            fail("Expected FileNotFoundException for source");
-        } catch (final FileNotFoundException e) {
-            // expected
-        }
+        assertThrows(FileNotFoundException.class, () -> FileUtils.moveFile(new File("nonexistant"), new File("foo")));
         assertThrows(IllegalArgumentException.class, () -> FileUtils.moveFile(temporaryFolder, new File("foo")));
         final File testSourceFile = new File(temporaryFolder, "testMoveFileSource");
         final File testDestFile = new File(temporaryFolder, "testMoveFileSource");
         if (!testSourceFile.getParentFile().exists()) {
-            throw new IOException("Cannot create file " + testSourceFile
-                    + " as the parent directory does not exist");
+            throw new IOException("Cannot create file " + testSourceFile + " as the parent directory does not exist");
         }
-        final BufferedOutputStream output1 =
-                new BufferedOutputStream(Files.newOutputStream(testSourceFile.toPath()));
+        final BufferedOutputStream output1 = new BufferedOutputStream(Files.newOutputStream(testSourceFile.toPath()));
         try {
             TestUtils.generateTestData(output1, 0);
         } finally {
             IOUtils.closeQuietly(output1);
         }
-        if (!testDestFile.getParentFile().exists()) {
-            throw new IOException("Cannot create file " + testDestFile
-                    + " as the parent directory does not exist");
-        }
-        final BufferedOutputStream output =
-                new BufferedOutputStream(Files.newOutputStream(testDestFile.toPath()));
+        assertTrue(testDestFile.getParentFile().exists(), () -> "Cannot create file " + testDestFile + " as the parent directory does not exist");
+        final BufferedOutputStream output = new BufferedOutputStream(Files.newOutputStream(testDestFile.toPath()));
         try {
             TestUtils.generateTestData(output, 0);
         } finally {
             IOUtils.closeQuietly(output);
         }
-        try {
-            FileUtils.moveFile(testSourceFile, testDestFile);
-            fail("Expected FileExistsException when dest already exists");
-        } catch (final FileExistsException e) {
-            // expected
-        }
+        assertThrows(FileExistsException.class, () -> FileUtils.moveFile(testSourceFile, testDestFile),
+            "Expected FileExistsException when dest already exists");
     }
 
     @Test
@@ -2445,12 +2340,7 @@ public class FileUtilsTestCase {
         assertThrows(IllegalArgumentException.class, () -> FileUtils.moveFileToDirectory(testFile1, testFile2, true));
 
         final File nonexistant = new File(temporaryFolder, "testMoveFileNonExistant");
-        try {
-            FileUtils.moveFileToDirectory(testFile1, nonexistant, false);
-            fail("Expected IOException when dest does not exist and create=false");
-        } catch (final IOException e) {
-            // expected
-        }
+        assertThrows(IOException.class, () -> FileUtils.moveFileToDirectory(testFile1, nonexistant, false));
     }
 
     @Test
@@ -2489,26 +2379,12 @@ public class FileUtilsTestCase {
 
     @Test
     public void testMoveToDirectory_Errors() throws Exception {
-        try {
-            FileUtils.moveDirectoryToDirectory(null, new File("foo"), true);
-            fail("Expected NullPointerException when source is null");
-        } catch (final NullPointerException e) {
-            // expected
-        }
-        try {
-            FileUtils.moveDirectoryToDirectory(new File("foo"), null, true);
-            fail("Expected NullPointerException when destination is null");
-        } catch (final NullPointerException e) {
-            // expected
-        }
+        assertThrows(NullPointerException.class, () -> FileUtils.moveDirectoryToDirectory(null, new File("foo"), true));
+        assertThrows(NullPointerException.class, () -> FileUtils.moveDirectoryToDirectory(new File("foo"), null, true));
         final File nonexistant = new File(temporaryFolder, "nonexistant");
         final File destDir = new File(temporaryFolder, "MoveToDirectoryDestDir");
-        try {
-            FileUtils.moveToDirectory(nonexistant, destDir, true);
-            fail("Expected IOException when source does not exist");
-        } catch (final IOException e) {
-            // expected
-        }
+        assertThrows(IOException.class, () -> FileUtils.moveToDirectory(nonexistant, destDir, true), "Expected IOException when source does not exist");
+
     }
 
     @Test
@@ -2571,18 +2447,10 @@ public class FileUtilsTestCase {
         final File file = new File(temporaryFolder, getName());
 
         // Null argument
-        try {
-            FileUtils.sizeOf(null);
-            fail("Exception expected.");
-        } catch (final NullPointerException ignore) {
-        }
+        assertThrows(NullPointerException.class, () -> FileUtils.sizeOf(null));
 
         // Non-existent file
-        try {
-            FileUtils.sizeOf(file);
-            fail("Exception expected.");
-        } catch (final IllegalArgumentException ignore) {
-        }
+        assertThrows(IllegalArgumentException.class, () -> FileUtils.sizeOf(file));
 
         // Creates file
         file.createNewFile();
@@ -2604,18 +2472,9 @@ public class FileUtilsTestCase {
         final File file = new File(temporaryFolder, getName());
 
         // Null argument
-        try {
-            FileUtils.sizeOfAsBigInteger(null);
-            fail("Exception expected.");
-        } catch (final NullPointerException ignore) {
-        }
-
+        assertThrows(NullPointerException.class, () -> FileUtils.sizeOfAsBigInteger(null));
         // Non-existent file
-        try {
-            FileUtils.sizeOfAsBigInteger(file);
-            fail("Exception expected.");
-        } catch (final IllegalArgumentException ignore) {
-        }
+        assertThrows(IllegalArgumentException.class, () -> FileUtils.sizeOfAsBigInteger(file));
 
         // Creates file
         file.createNewFile();
@@ -2638,22 +2497,16 @@ public class FileUtilsTestCase {
     public void testSizeOfDirectory() throws Exception {
         final File file = new File(temporaryFolder, getName());
 
+        // Null argument
+        assertThrows(NullPointerException.class, () -> FileUtils.sizeOfDirectory(null));
         // Non-existent file
-        try {
-            FileUtils.sizeOfDirectory(file);
-            fail("Exception expected.");
-        } catch (final IllegalArgumentException ignore) {
-        }
+        assertThrows(IllegalArgumentException.class, () -> FileUtils.sizeOfAsBigInteger(file));
 
         // Creates file
         file.createNewFile();
 
         // Existing file
-        try {
-            FileUtils.sizeOfDirectory(file);
-            fail("Exception expected.");
-        } catch (final IllegalArgumentException ignore) {
-        }
+        assertThrows(IllegalArgumentException.class, () -> FileUtils.sizeOfDirectory(file));
 
         // Existing directory
         file.delete();
@@ -2669,23 +2522,17 @@ public class FileUtilsTestCase {
     public void testSizeOfDirectoryAsBigInteger() throws Exception {
         final File file = new File(temporaryFolder, getName());
 
+        // Null argument
+        assertThrows(NullPointerException.class, () -> FileUtils.sizeOfDirectoryAsBigInteger(null));
         // Non-existent file
-        try {
-            FileUtils.sizeOfDirectoryAsBigInteger(file);
-            fail("Exception expected.");
-        } catch (final IllegalArgumentException ignore) {
-        }
+        assertThrows(IllegalArgumentException.class, () -> FileUtils.sizeOfDirectoryAsBigInteger(file));
 
         // Creates file
         file.createNewFile();
         file.deleteOnExit();
 
         // Existing file
-        try {
-            FileUtils.sizeOfDirectoryAsBigInteger(file);
-            fail("Exception expected.");
-        } catch (final IllegalArgumentException ignore) {
-        }
+        assertThrows(IllegalArgumentException.class, () -> FileUtils.sizeOfDirectoryAsBigInteger(file));
 
         // Existing directory
         file.delete();
@@ -2700,12 +2547,8 @@ public class FileUtilsTestCase {
         file.mkdir();
 
         final File nonEmptyFile = new File(file, "nonEmptyFile" + System.nanoTime());
-        if (!nonEmptyFile.getParentFile().exists()) {
-            throw new IOException("Cannot create file " + nonEmptyFile
-                    + " as the parent directory does not exist");
-        }
-        final OutputStream output =
-                new BufferedOutputStream(Files.newOutputStream(nonEmptyFile.toPath()));
+        assertTrue(nonEmptyFile.getParentFile().exists(), () -> "Cannot create file " + nonEmptyFile + " as the parent directory does not exist");
+        final OutputStream output = new BufferedOutputStream(Files.newOutputStream(nonEmptyFile.toPath()));
         try {
             TestUtils.generateTestData(output, TEST_DIRECTORY_SIZE_GT_ZERO_BI.longValue());
         } finally {
@@ -2713,8 +2556,7 @@ public class FileUtilsTestCase {
         }
         nonEmptyFile.deleteOnExit();
 
-        assertEquals(TEST_DIRECTORY_SIZE_GT_ZERO_BI, FileUtils.sizeOfDirectoryAsBigInteger(file),
-                "Unexpected directory size");
+        assertEquals(TEST_DIRECTORY_SIZE_GT_ZERO_BI, FileUtils.sizeOfDirectoryAsBigInteger(file), "Unexpected directory size");
 
         nonEmptyFile.delete();
         file.delete();
@@ -2803,11 +2645,7 @@ public class FileUtilsTestCase {
                 new URL("file", null, "file1.txt"),
                 new URL("http", "jakarta.apache.org", "file1.txt"),
         };
-        try {
-            FileUtils.toFiles(urls);
-            fail();
-        } catch (final IllegalArgumentException ignore) {
-        }
+        assertThrows(IllegalArgumentException.class, () -> FileUtils.toFiles(urls));
     }
 
     @Test

[commons-io] 03/04: Sort test members.

Posted by gg...@apache.org.
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

commit 17bb2a7b54d379082d2b2df290c4d1bedbd02220
Author: Gary Gregory <ga...@gmail.com>
AuthorDate: Wed Sep 15 10:45:10 2021 -0400

    Sort test members.
---
 .../apache/commons/io/ByteOrderMarkTestCase.java   |   62 +-
 .../org/apache/commons/io/CharsetsTestCase.java    |   10 +-
 .../java/org/apache/commons/io/CopyUtilsTest.java  |  108 +-
 .../java/org/apache/commons/io/DemuxTestCase.java  |  198 +--
 .../apache/commons/io/DirectoryWalkerTestCase.java |  630 +++----
 .../commons/io/DirectoryWalkerTestCaseJava4.java   |  606 +++----
 .../org/apache/commons/io/EndianUtilsTest.java     |  280 ++--
 .../commons/io/FileCleaningTrackerTestCase.java    |  184 +-
 .../commons/io/FileDeleteStrategyTestCase.java     |   72 +-
 .../apache/commons/io/FileSystemUtilsTestCase.java |  710 ++++----
 .../io/FileUtilsCleanDirectoryTestCase.java        |   82 +-
 .../commons/io/FileUtilsCleanSymlinksTestCase.java |  162 +-
 .../commons/io/FileUtilsCopyToFileTestCase.java    |   58 +-
 .../io/FileUtilsDirectoryContainsTestCase.java     |   48 +-
 .../commons/io/FileUtilsFileNewerTestCase.java     |   56 +-
 .../commons/io/FileUtilsListFilesTestCase.java     |   82 +-
 .../org/apache/commons/io/FileUtilsTestCase.java   |   84 +-
 .../commons/io/FileUtilsWaitForTestCase.java       |   10 +-
 .../apache/commons/io/FilenameUtilsTestCase.java   | 1750 ++++++++++----------
 .../commons/io/FilenameUtilsWildcardTestCase.java  |  254 +--
 .../java/org/apache/commons/io/HexDumpTest.java    |   20 +-
 .../java/org/apache/commons/io/IOCaseTestCase.java |  264 +--
 .../org/apache/commons/io/IOUtilsTestCase.java     |   16 +-
 .../apache/commons/io/IOUtilsWriteTestCase.java    |  390 ++---
 .../apache/commons/io/LineIteratorTestCase.java    |  264 +--
 .../org/apache/commons/io/SelectorAdapter.java     |   22 +-
 .../java/org/apache/commons/io/TestResources.java  |    8 +-
 .../apache/commons/io/ThreadMonitorTestCase.java   |   30 +-
 .../io/comparator/ComparatorAbstractTestCase.java  |   16 +-
 .../io/comparator/CompositeFileComparatorTest.java |   74 +-
 .../io/comparator/SizeFileComparatorTest.java      |   16 +-
 .../io/file/CountersEqualsAndHashCodeTest.java     |   10 +-
 .../commons/io/file/CountingPathVisitorTest.java   |   10 +-
 .../io/file/PathUtilsContentEqualsTest.java        |  180 +-
 .../commons/io/file/PathUtilsDeleteFileTest.java   |   32 +-
 .../io/filefilter/AndFileFilterTestCase.java       |   36 +-
 .../ConditionalFileFilterAbstractTestCase.java     |   90 +-
 .../filefilter/IOFileFilterAbstractTestCase.java   |  132 +-
 .../io/filefilter/OrFileFilterTestCase.java        |    8 +-
 .../commons/io/input/BOMInputStreamTest.java       |   74 +-
 .../commons/io/input/BoundedInputStreamTest.java   |   58 +-
 .../apache/commons/io/input/BoundedReaderTest.java |  168 +-
 .../io/input/CharSequenceInputStreamTest.java      |  134 +-
 .../commons/io/input/CharSequenceReaderTest.java   |  176 +-
 .../io/input/ClassLoaderObjectInputStreamTest.java |  100 +-
 .../commons/io/input/CountingInputStreamTest.java  |  116 +-
 .../io/input/MarkShieldInputStreamTest.java        |   40 +-
 .../commons/io/input/NullInputStreamTest.java      |  182 +-
 .../apache/commons/io/input/NullReaderTest.java    |  176 +-
 .../commons/io/input/QueueInputStreamTest.java     |   60 +-
 .../io/input/RandomAccessFileInputStreamTest.java  |   60 +-
 .../commons/io/input/ReaderInputStreamTest.java    |  122 +-
 .../ReversedLinesFileReaderTestParamBlockSize.java |  210 +--
 .../input/ReversedLinesFileReaderTestSimple.java   |   12 +-
 .../commons/io/input/SequenceReaderTest.java       |   16 +-
 .../commons/io/input/TaggedInputStreamTest.java    |   50 +-
 .../apache/commons/io/input/TaggedReaderTest.java  |   48 +-
 .../org/apache/commons/io/input/TailerTest.java    |  430 ++---
 .../commons/io/input/TeeInputStreamTest.java       |  126 +-
 .../io/input/UnixLineEndingInputStreamTest.java    |   38 +-
 .../io/input/WindowsLineEndingInputStreamTest.java |   30 +-
 .../commons/io/input/XmlStreamReaderTest.java      |  556 +++----
 .../io/input/XmlStreamReaderUtilitiesTest.java     |  370 ++---
 .../buffer/CircularBufferInputStreamTest.java      |   46 +-
 .../io/input/compatibility/XmlStreamReader.java    |  778 ++++-----
 .../XmlStreamReaderUtilitiesCompatibilityTest.java |   18 +-
 .../io/monitor/AbstractMonitorTestCase.java        |   64 +-
 .../commons/io/monitor/CollectionFileListener.java |   56 +-
 .../io/monitor/FileAlterationMonitorTestCase.java  |  140 +-
 .../io/monitor/FileAlterationObserverTestCase.java |  154 +-
 .../io/output/AppendableOutputStreamTest.java      |   14 +-
 .../io/output/ByteArrayOutputStreamTestCase.java   |  316 ++--
 .../commons/io/output/ChunkedOutputStreamTest.java |   28 +-
 .../commons/io/output/ChunkedWriterTest.java       |   34 +-
 .../commons/io/output/ClosedOutputStreamTest.java  |   16 +-
 .../apache/commons/io/output/ClosedWriterTest.java |   16 +-
 .../io/output/CountingOutputStreamTest.java        |   12 +-
 .../commons/io/output/LockableFileWriterTest.java  |  114 +-
 .../apache/commons/io/output/ProxyWriterTest.java  |  198 +--
 .../commons/io/output/StringBuilderWriterTest.java |   46 +-
 .../commons/io/output/TaggedOutputStreamTest.java  |   36 +-
 .../apache/commons/io/output/TaggedWriterTest.java |   36 +-
 .../commons/io/output/TeeOutputStreamTest.java     |   26 +-
 .../commons/io/output/WriterOutputStreamTest.java  |  102 +-
 .../commons/io/output/XmlStreamWriterTest.java     |   88 +-
 .../serialization/AbstractCloseableListTest.java   |   22 +-
 .../io/serialization/MockSerializedClass.java      |   10 +-
 .../io/serialization/MoreComplexObjectTest.java    |   30 +-
 .../serialization/RegexpClassNameMatcherTest.java  |   24 +-
 .../ValidatingObjectInputStreamTest.java           |  170 +-
 .../io/test/ThrowOnFlushAndCloseOutputStream.java  |   18 +-
 91 files changed, 6514 insertions(+), 6514 deletions(-)

diff --git a/src/test/java/org/apache/commons/io/ByteOrderMarkTestCase.java b/src/test/java/org/apache/commons/io/ByteOrderMarkTestCase.java
index 90e7ab4..5e15db4 100644
--- a/src/test/java/org/apache/commons/io/ByteOrderMarkTestCase.java
+++ b/src/test/java/org/apache/commons/io/ByteOrderMarkTestCase.java
@@ -56,12 +56,33 @@ public class ByteOrderMarkTestCase  {
         assertNotNull(Charset.forName(ByteOrderMark.UTF_32LE.getCharsetName()));
     }
 
-    /** Test {@link ByteOrderMark#length()} */
+    /** Test Errors */
     @Test
-    public void testLength() {
-        assertEquals(1, TEST_BOM_1.length(), "test1 length");
-        assertEquals(2, TEST_BOM_2.length(), "test2 length");
-        assertEquals(3, TEST_BOM_3.length(), "test3 length");
+    public void errors() {
+        try {
+            new ByteOrderMark(null, 1,2,3);
+            fail("null charset name, expected IllegalArgumentException");
+        } catch (final IllegalArgumentException e) {
+            // expected
+        }
+        try {
+            new ByteOrderMark("", 1,2,3);
+            fail("no charset name, expected IllegalArgumentException");
+        } catch (final IllegalArgumentException e) {
+            // expected
+        }
+        try {
+            new ByteOrderMark("a", (int[])null);
+            fail("null bytes, expected IllegalArgumentException");
+        } catch (final IllegalArgumentException e) {
+            // expected
+        }
+        try {
+            new ByteOrderMark("b");
+            fail("empty bytes, expected IllegalArgumentException");
+        } catch (final IllegalArgumentException e) {
+            // expected
+        }
     }
 
     /** Test {@link ByteOrderMark#get(int)} */
@@ -109,33 +130,12 @@ public class ByteOrderMarkTestCase  {
         assertEquals(bomClassHash + 6, TEST_BOM_3.hashCode(), "hash test3 ");
     }
 
-    /** Test Errors */
+    /** Test {@link ByteOrderMark#length()} */
     @Test
-    public void errors() {
-        try {
-            new ByteOrderMark(null, 1,2,3);
-            fail("null charset name, expected IllegalArgumentException");
-        } catch (final IllegalArgumentException e) {
-            // expected
-        }
-        try {
-            new ByteOrderMark("", 1,2,3);
-            fail("no charset name, expected IllegalArgumentException");
-        } catch (final IllegalArgumentException e) {
-            // expected
-        }
-        try {
-            new ByteOrderMark("a", (int[])null);
-            fail("null bytes, expected IllegalArgumentException");
-        } catch (final IllegalArgumentException e) {
-            // expected
-        }
-        try {
-            new ByteOrderMark("b");
-            fail("empty bytes, expected IllegalArgumentException");
-        } catch (final IllegalArgumentException e) {
-            // expected
-        }
+    public void testLength() {
+        assertEquals(1, TEST_BOM_1.length(), "test1 length");
+        assertEquals(2, TEST_BOM_2.length(), "test2 length");
+        assertEquals(3, TEST_BOM_3.length(), "test3 length");
     }
 
     /** Test {@link ByteOrderMark#toString()} */
diff --git a/src/test/java/org/apache/commons/io/CharsetsTestCase.java b/src/test/java/org/apache/commons/io/CharsetsTestCase.java
index 9ffae56..fda6504 100644
--- a/src/test/java/org/apache/commons/io/CharsetsTestCase.java
+++ b/src/test/java/org/apache/commons/io/CharsetsTestCase.java
@@ -33,6 +33,11 @@ import org.junit.jupiter.api.Test;
 public class CharsetsTestCase {
 
     @Test
+    public void testIso8859_1() {
+        assertEquals("ISO-8859-1", Charsets.ISO_8859_1.name());
+    }
+
+    @Test
     public void testRequiredCharsets() {
         final SortedMap<String, Charset> requiredCharsets = Charsets.requiredCharsets();
         // test for what we expect to be there as of Java 6
@@ -46,11 +51,6 @@ public class CharsetsTestCase {
     }
 
     @Test
-    public void testIso8859_1() {
-        assertEquals("ISO-8859-1", Charsets.ISO_8859_1.name());
-    }
-
-    @Test
     public void testToCharset() {
         assertEquals(Charset.defaultCharset(), Charsets.toCharset((String) null));
         assertEquals(Charset.defaultCharset(), Charsets.toCharset((Charset) null));
diff --git a/src/test/java/org/apache/commons/io/CopyUtilsTest.java b/src/test/java/org/apache/commons/io/CopyUtilsTest.java
index 9d1e3a3..af71861 100644
--- a/src/test/java/org/apache/commons/io/CopyUtilsTest.java
+++ b/src/test/java/org/apache/commons/io/CopyUtilsTest.java
@@ -59,12 +59,6 @@ public class CopyUtilsTest {
     // ----------------------------------------------------------------
 
     @Test
-    public void testCtor() {
-        new CopyUtils();
-        // Nothing to assert, the constructor is public and does not blow up.
-    }
-
-    @Test
     public void copy_byteArrayToOutputStream() throws Exception {
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         final OutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, false, true);
@@ -88,32 +82,6 @@ public class CopyUtilsTest {
         assertArrayEquals(inData, baout.toByteArray(), "Content differs");
     }
 
-    @Test
-    public void testCopy_byteArrayToWriterWithEncoding() throws Exception {
-        final String inDataStr = "data";
-        final String charsetName = "UTF-8";
-        final StringWriter writer = new StringWriter();
-        CopyUtils.copy(inDataStr.getBytes(charsetName), writer, charsetName);
-        assertEquals(inDataStr, writer.toString());
-    }
-
-    @SuppressWarnings("resource") // 'in' is deliberately not closed
-    @Test
-    public void testCopy_inputStreamToOutputStream() throws Exception {
-        InputStream in = new ByteArrayInputStream(inData);
-        in = new ThrowOnCloseInputStream(in);
-
-        final ByteArrayOutputStream baout = new ByteArrayOutputStream();
-        final OutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, false, true);
-
-        final int count = CopyUtils.copy(in, out);
-
-        assertEquals(0, in.available(), "Not all bytes were read");
-        assertEquals(inData.length, baout.size(), "Sizes differ");
-        assertArrayEquals(inData, baout.toByteArray(), "Content differs");
-        assertEquals(inData.length, count);
-    }
-
     @SuppressWarnings("resource") // 'in' is deliberately not closed
     @Test
     public void copy_inputStreamToWriter() throws Exception {
@@ -143,28 +111,6 @@ public class CopyUtilsTest {
 
     @SuppressWarnings("resource") // 'in' is deliberately not closed
     @Test
-    public void testCopy_readerToOutputStream() throws Exception {
-        InputStream in = new ByteArrayInputStream(inData);
-        in = new ThrowOnCloseInputStream(in);
-        final Reader reader = new java.io.InputStreamReader(in, StandardCharsets.US_ASCII);
-
-        final ByteArrayOutputStream baout = new ByteArrayOutputStream();
-        final OutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, false, true);
-
-        CopyUtils.copy(reader, out);
-        //Note: this method *does* flush. It is equivalent to:
-        //  OutputStreamWriter _out = new OutputStreamWriter(fout);
-        //  IOUtils.copy( fin, _out, 4096 ); // copy( Reader, Writer, int );
-        //  _out.flush();
-        //  out = fout;
-
-        // Note: rely on the method to flush
-        assertEquals(inData.length, baout.size(), "Sizes differ");
-        assertArrayEquals(inData, baout.toByteArray(), "Content differs");
-    }
-
-    @SuppressWarnings("resource") // 'in' is deliberately not closed
-    @Test
     public void copy_readerToWriter() throws Exception {
         InputStream in = new ByteArrayInputStream(inData);
         in = new ThrowOnCloseInputStream(in);
@@ -215,4 +161,58 @@ public class CopyUtilsTest {
         assertArrayEquals(inData, baout.toByteArray(), "Content differs");
     }
 
+    @Test
+    public void testCopy_byteArrayToWriterWithEncoding() throws Exception {
+        final String inDataStr = "data";
+        final String charsetName = "UTF-8";
+        final StringWriter writer = new StringWriter();
+        CopyUtils.copy(inDataStr.getBytes(charsetName), writer, charsetName);
+        assertEquals(inDataStr, writer.toString());
+    }
+
+    @SuppressWarnings("resource") // 'in' is deliberately not closed
+    @Test
+    public void testCopy_inputStreamToOutputStream() throws Exception {
+        InputStream in = new ByteArrayInputStream(inData);
+        in = new ThrowOnCloseInputStream(in);
+
+        final ByteArrayOutputStream baout = new ByteArrayOutputStream();
+        final OutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, false, true);
+
+        final int count = CopyUtils.copy(in, out);
+
+        assertEquals(0, in.available(), "Not all bytes were read");
+        assertEquals(inData.length, baout.size(), "Sizes differ");
+        assertArrayEquals(inData, baout.toByteArray(), "Content differs");
+        assertEquals(inData.length, count);
+    }
+
+    @SuppressWarnings("resource") // 'in' is deliberately not closed
+    @Test
+    public void testCopy_readerToOutputStream() throws Exception {
+        InputStream in = new ByteArrayInputStream(inData);
+        in = new ThrowOnCloseInputStream(in);
+        final Reader reader = new java.io.InputStreamReader(in, StandardCharsets.US_ASCII);
+
+        final ByteArrayOutputStream baout = new ByteArrayOutputStream();
+        final OutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, false, true);
+
+        CopyUtils.copy(reader, out);
+        //Note: this method *does* flush. It is equivalent to:
+        //  OutputStreamWriter _out = new OutputStreamWriter(fout);
+        //  IOUtils.copy( fin, _out, 4096 ); // copy( Reader, Writer, int );
+        //  _out.flush();
+        //  out = fout;
+
+        // Note: rely on the method to flush
+        assertEquals(inData.length, baout.size(), "Sizes differ");
+        assertArrayEquals(inData, baout.toByteArray(), "Content differs");
+    }
+
+    @Test
+    public void testCtor() {
+        new CopyUtils();
+        // Nothing to assert, the constructor is public and does not blow up.
+    }
+
 } // CopyUtilsTest
diff --git a/src/test/java/org/apache/commons/io/DemuxTestCase.java b/src/test/java/org/apache/commons/io/DemuxTestCase.java
index c58af77..f9b525d 100644
--- a/src/test/java/org/apache/commons/io/DemuxTestCase.java
+++ b/src/test/java/org/apache/commons/io/DemuxTestCase.java
@@ -36,104 +36,6 @@ import org.junit.jupiter.api.Test;
  * Basic unit tests for the multiplexing streams.
  */
 public class DemuxTestCase {
-    private static final String T1 = "Thread1";
-    private static final String T2 = "Thread2";
-    private static final String T3 = "Thread3";
-    private static final String T4 = "Thread4";
-
-    private static final String DATA1 = "Data for thread1";
-    private static final String DATA2 = "Data for thread2";
-    private static final String DATA3 = "Data for thread3";
-    private static final String DATA4 = "Data for thread4";
-
-    private static final Random c_random = new Random();
-    private final HashMap<String, ByteArrayOutputStream> outputMap = new HashMap<>();
-    private final HashMap<String, Thread> threadMap = new HashMap<>();
-
-    private String getOutput(final String threadName) {
-        final ByteArrayOutputStream output =
-                outputMap.get(threadName);
-        assertNotNull(output, "getOutput()");
-
-        return output.toString(StandardCharsets.UTF_8);
-    }
-
-    private String getInput(final String threadName) {
-        final ReaderThread thread = (ReaderThread) threadMap.get(threadName);
-        assertNotNull(thread, "getInput()");
-
-        return thread.getData();
-    }
-
-    private void doStart() {
-        for (final String name : threadMap.keySet()) {
-            final Thread thread = threadMap.get(name);
-            thread.start();
-        }
-    }
-
-    private void doJoin()
-            throws Exception {
-        for (final String name : threadMap.keySet()) {
-            final Thread thread = threadMap.get(name);
-            thread.join();
-        }
-    }
-
-    private void startWriter(final String name,
-                             final String data,
-                             final DemuxOutputStream demux) {
-        final ByteArrayOutputStream output = new ByteArrayOutputStream();
-        outputMap.put(name, output);
-        final WriterThread thread =
-                new WriterThread(name, data, output, demux);
-        threadMap.put(name, thread);
-    }
-
-    private void startReader(final String name,
-                             final String data,
-                             final DemuxInputStream demux) {
-        final InputStream input = new StringInputStream(data);
-        final ReaderThread thread = new ReaderThread(name, input, demux);
-        threadMap.put(name, thread);
-    }
-
-    @Test
-    public void testOutputStream()
-            throws Exception {
-        final DemuxOutputStream output = new DemuxOutputStream();
-        startWriter(T1, DATA1, output);
-        startWriter(T2, DATA2, output);
-        startWriter(T3, DATA3, output);
-        startWriter(T4, DATA4, output);
-
-        doStart();
-        doJoin();
-
-        assertEquals(DATA1, getOutput(T1), "Data1");
-        assertEquals(DATA2, getOutput(T2), "Data2");
-        assertEquals(DATA3, getOutput(T3), "Data3");
-        assertEquals(DATA4, getOutput(T4), "Data4");
-    }
-
-    @Test
-    public void testInputStream()
-            throws Exception {
-        final DemuxInputStream input = new DemuxInputStream();
-        startReader(T1, DATA1, input);
-        startReader(T2, DATA2, input);
-        startReader(T3, DATA3, input);
-        startReader(T4, DATA4, input);
-
-        doStart();
-        doJoin();
-
-        assertEquals(DATA1, getInput(T1), "Data1");
-        assertEquals(DATA2, getInput(T2), "Data2");
-        assertEquals(DATA3, getInput(T3), "Data3");
-        assertEquals(DATA4, getInput(T4), "Data4");
-    }
-
     private static class ReaderThread
             extends Thread {
         private final StringBuffer stringBuffer = new StringBuffer();
@@ -171,7 +73,6 @@ public class DemuxTestCase {
             }
         }
     }
-
     private static class WriterThread
             extends Thread {
         private final byte[] byteArray;
@@ -203,5 +104,104 @@ public class DemuxTestCase {
             }
         }
     }
+    private static final String T1 = "Thread1";
+    private static final String T2 = "Thread2";
+
+    private static final String T3 = "Thread3";
+    private static final String T4 = "Thread4";
+    private static final String DATA1 = "Data for thread1";
+    private static final String DATA2 = "Data for thread2";
+
+    private static final String DATA3 = "Data for thread3";
+    private static final String DATA4 = "Data for thread4";
+    private static final Random c_random = new Random();
+
+    private final HashMap<String, ByteArrayOutputStream> outputMap = new HashMap<>();
+
+    private final HashMap<String, Thread> threadMap = new HashMap<>();
+
+    private void doJoin()
+            throws Exception {
+        for (final String name : threadMap.keySet()) {
+            final Thread thread = threadMap.get(name);
+            thread.join();
+        }
+    }
+
+    private void doStart() {
+        for (final String name : threadMap.keySet()) {
+            final Thread thread = threadMap.get(name);
+            thread.start();
+        }
+    }
+
+    private String getInput(final String threadName) {
+        final ReaderThread thread = (ReaderThread) threadMap.get(threadName);
+        assertNotNull(thread, "getInput()");
+
+        return thread.getData();
+    }
+
+    private String getOutput(final String threadName) {
+        final ByteArrayOutputStream output =
+                outputMap.get(threadName);
+        assertNotNull(output, "getOutput()");
+
+        return output.toString(StandardCharsets.UTF_8);
+    }
+
+    private void startReader(final String name,
+                             final String data,
+                             final DemuxInputStream demux) {
+        final InputStream input = new StringInputStream(data);
+        final ReaderThread thread = new ReaderThread(name, input, demux);
+        threadMap.put(name, thread);
+    }
+
+    private void startWriter(final String name,
+                             final String data,
+                             final DemuxOutputStream demux) {
+        final ByteArrayOutputStream output = new ByteArrayOutputStream();
+        outputMap.put(name, output);
+        final WriterThread thread =
+                new WriterThread(name, data, output, demux);
+        threadMap.put(name, thread);
+    }
+
+    @Test
+    public void testInputStream()
+            throws Exception {
+        final DemuxInputStream input = new DemuxInputStream();
+        startReader(T1, DATA1, input);
+        startReader(T2, DATA2, input);
+        startReader(T3, DATA3, input);
+        startReader(T4, DATA4, input);
+
+        doStart();
+        doJoin();
+
+        assertEquals(DATA1, getInput(T1), "Data1");
+        assertEquals(DATA2, getInput(T2), "Data2");
+        assertEquals(DATA3, getInput(T3), "Data3");
+        assertEquals(DATA4, getInput(T4), "Data4");
+    }
+
+    @Test
+    public void testOutputStream()
+            throws Exception {
+        final DemuxOutputStream output = new DemuxOutputStream();
+        startWriter(T1, DATA1, output);
+        startWriter(T2, DATA2, output);
+        startWriter(T3, DATA3, output);
+        startWriter(T4, DATA4, output);
+
+        doStart();
+        doJoin();
+
+        assertEquals(DATA1, getOutput(T1), "Data1");
+        assertEquals(DATA2, getOutput(T2), "Data2");
+        assertEquals(DATA3, getOutput(T3), "Data3");
+        assertEquals(DATA4, getOutput(T4), "Data4");
+    }
 }
 
diff --git a/src/test/java/org/apache/commons/io/DirectoryWalkerTestCase.java b/src/test/java/org/apache/commons/io/DirectoryWalkerTestCase.java
index ed38068..7280b48 100644
--- a/src/test/java/org/apache/commons/io/DirectoryWalkerTestCase.java
+++ b/src/test/java/org/apache/commons/io/DirectoryWalkerTestCase.java
@@ -41,18 +41,203 @@ import org.junit.jupiter.api.Test;
  */
 public class DirectoryWalkerTestCase {
 
+    /**
+     * Test DirectoryWalker implementation that finds files in a directory hierarchy
+     * applying a file filter.
+     */
+    static class TestCancelWalker extends DirectoryWalker<File> {
+        private final String cancelFileName;
+        private final boolean suppressCancel;
+
+        TestCancelWalker(final String cancelFileName,final boolean suppressCancel) {
+            this.cancelFileName = cancelFileName;
+            this.suppressCancel = suppressCancel;
+        }
+
+        /** find files. */
+        protected List<File> find(final File startDirectory) throws IOException {
+           final List<File> results = new ArrayList<>();
+           walk(startDirectory, results);
+           return results;
+        }
+
+        /** Handles Cancel. */
+        @Override
+        protected void handleCancelled(final File startDirectory, final Collection<File> results,
+                       final CancelException cancel) throws IOException {
+            if (!suppressCancel) {
+                super.handleCancelled(startDirectory, results, cancel);
+            }
+        }
+
+        /** Handles a directory end by adding the File to the result set. */
+        @Override
+        protected void handleDirectoryEnd(final File directory, final int depth, final Collection<File> results) throws IOException {
+            results.add(directory);
+            if (cancelFileName.equals(directory.getName())) {
+                throw new CancelException(directory, depth);
+            }
+        }
+
+        /** Handles a file by adding the File to the result set. */
+        @Override
+        protected void handleFile(final File file, final int depth, final Collection<File> results) throws IOException {
+            results.add(file);
+            if (cancelFileName.equals(file.getName())) {
+                throw new CancelException(file, depth);
+            }
+        }
+    }
+    /**
+     * Test DirectoryWalker implementation that always returns false
+     * from handleDirectoryStart()
+     */
+    private static class TestFalseFileFinder extends TestFileFinder {
+
+        protected TestFalseFileFinder(final FileFilter filter, final int depthLimit) {
+            super(filter, depthLimit);
+        }
+
+        /** Always returns false. */
+        @Override
+        protected boolean handleDirectory(final File directory, final int depth, final Collection<File> results) {
+            return false;
+        }
+    }
+    /**
+     * Test DirectoryWalker implementation that finds files in a directory hierarchy
+     * applying a file filter.
+     */
+    private static class TestFileFinder extends DirectoryWalker<File> {
+
+        protected TestFileFinder(final FileFilter filter, final int depthLimit) {
+            super(filter, depthLimit);
+        }
+
+        protected TestFileFinder(final IOFileFilter dirFilter, final IOFileFilter fileFilter, final int depthLimit) {
+            super(dirFilter, fileFilter, depthLimit);
+        }
+
+        /** find files. */
+        protected List<File> find(final File startDirectory) {
+           final List<File> results = new ArrayList<>();
+           try {
+               walk(startDirectory, results);
+           } catch(final IOException ex) {
+               fail(ex.toString());
+           }
+           return results;
+        }
+
+        /** Handles a directory end by adding the File to the result set. */
+        @Override
+        protected void handleDirectoryEnd(final File directory, final int depth, final Collection<File> results) {
+            results.add(directory);
+        }
+
+        /** Handles a file by adding the File to the result set. */
+        @Override
+        protected void handleFile(final File file, final int depth, final Collection<File> results) {
+            results.add(file);
+        }
+    }
+    /**
+     * Test DirectoryWalker implementation that finds files in a directory hierarchy
+     * applying a file filter.
+     */
+    private static class TestFileFinderString extends DirectoryWalker<String> {
+
+        protected TestFileFinderString(final FileFilter filter, final int depthLimit) {
+            super(filter, depthLimit);
+        }
+
+        /** find files. */
+        protected List<String> find(final File startDirectory) {
+           final List<String> results = new ArrayList<>();
+           try {
+               walk(startDirectory, results);
+           } catch(final IOException ex) {
+               fail(ex.toString());
+           }
+           return results;
+        }
+
+        /** Handles a file by adding the File to the result set. */
+        @Override
+        protected void handleFile(final File file, final int depth, final Collection<String> results) {
+            results.add(file.toString());
+        }
+    }
+    /**
+     * Test DirectoryWalker implementation that finds files in a directory hierarchy
+     * applying a file filter.
+     */
+    static class TestMultiThreadCancelWalker extends DirectoryWalker<File> {
+        private final String cancelFileName;
+        private final boolean suppressCancel;
+        private boolean cancelled;
+        public List<File> results;
+
+        TestMultiThreadCancelWalker(final String cancelFileName, final boolean suppressCancel) {
+            this.cancelFileName = cancelFileName;
+            this.suppressCancel = suppressCancel;
+        }
+
+        /** find files. */
+        protected List<File> find(final File startDirectory) throws IOException {
+           results = new ArrayList<>();
+           walk(startDirectory, results);
+           return results;
+        }
+
+        /** Handles Cancel. */
+        @Override
+        protected void handleCancelled(final File startDirectory, final Collection<File> results,
+                       final CancelException cancel) throws IOException {
+            if (!suppressCancel) {
+                super.handleCancelled(startDirectory, results, cancel);
+            }
+        }
+
+        /** Handles a directory end by adding the File to the result set. */
+        @Override
+        protected void handleDirectoryEnd(final File directory, final int depth, final Collection<File> results) throws IOException {
+            results.add(directory);
+            assertFalse(cancelled);
+            if (cancelFileName.equals(directory.getName())) {
+                cancelled = true;
+            }
+        }
+
+        /** Handles a file by adding the File to the result set. */
+        @Override
+        protected void handleFile(final File file, final int depth, final Collection<File> results) throws IOException {
+            results.add(file);
+            assertFalse(cancelled);
+            if (cancelFileName.equals(file.getName())) {
+                cancelled = true;
+            }
+        }
+
+        /** Handles Cancelled. */
+        @Override
+        protected boolean handleIsCancelled(final File file, final int depth, final Collection<File> results) throws IOException {
+            return cancelled;
+        }
+    }
     // Directories
     private static final File current      = new File(".");
     private static final File javaDir      = new File("src/main/java");
     private static final File orgDir       = new File(javaDir, "org");
+
     private static final File apacheDir    = new File(orgDir, "apache");
     private static final File commonsDir   = new File(apacheDir, "commons");
     private static final File ioDir        = new File(commonsDir, "io");
     private static final File outputDir    = new File(ioDir, "output");
     private static final File[] dirs       = {orgDir, apacheDir, commonsDir, ioDir, outputDir};
-
     // Files
     private static final File filenameUtils = new File(ioDir, "FilenameUtils.java");
+
     private static final File ioUtils       = new File(ioDir, "IOUtils.java");
     private static final File proxyWriter   = new File(outputDir, "ProxyWriter.java");
     private static final File nullStream    = new File(outputDir, "NullOutputStream.java");
@@ -61,14 +246,113 @@ public class DirectoryWalkerTestCase {
 
     // Filters
     private static final IOFileFilter dirsFilter        = createNameFilter(dirs);
+
+
     private static final IOFileFilter iofilesFilter     = createNameFilter(ioFiles);
+
     private static final IOFileFilter outputFilesFilter = createNameFilter(outputFiles);
+
     private static final IOFileFilter ioDirAndFilesFilter = dirsFilter.or(iofilesFilter);
+
     private static final IOFileFilter dirsAndFilesFilter = ioDirAndFilesFilter.or(outputFilesFilter);
 
     // Filter to exclude SVN files
     private static final IOFileFilter NOT_SVN = FileFilterUtils.makeSVNAware(null);
 
+    /**
+     * Create a name filter containing the names of the files
+     * in the array.
+     */
+    private static IOFileFilter createNameFilter(final File[] files) {
+        final String[] names = new String[files.length];
+        for (int i = 0; i < files.length; i++) {
+            names[i] = files[i].getName();
+        }
+        return new NameFileFilter(names);
+    }
+
+    /**
+     * Check the files in the array are in the results list.
+     */
+    private void checkContainsFiles(final String prefix, final File[] files, final Collection<File> results) {
+        for (int i = 0; i < files.length; i++) {
+            assertTrue(results.contains(files[i]), prefix + "["+i+"] " + files[i]);
+        }
+    }
+
+    private void checkContainsString(final String prefix, final File[] files, final Collection<String> results) {
+        for (int i = 0; i < files.length; i++) {
+            assertTrue(results.contains(files[i].toString()), prefix + "["+i+"] " + files[i]);
+        }
+    }
+
+    /**
+     * Extract the directories.
+     */
+    private List<File> directoriesOnly(final Collection<File> results) {
+        final List<File> list = new ArrayList<>(results.size());
+        for (final File file : results) {
+            if (file.isDirectory()) {
+                list.add(file);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Extract the files.
+     */
+    private List<File> filesOnly(final Collection<File> results) {
+        final List<File> list = new ArrayList<>(results.size());
+        for (final File file : results) {
+            if (file.isFile()) {
+                list.add(file);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Test Cancel
+     */
+    @Test
+    public void testCancel() {
+        String cancelName = null;
+
+        // Cancel on a file
+        try {
+            cancelName = "DirectoryWalker.java";
+            new TestCancelWalker(cancelName, false).find(javaDir);
+            fail("CancelException not thrown for '" + cancelName + "'");
+        } catch (final DirectoryWalker.CancelException cancel) {
+            assertEquals(cancelName, cancel.getFile().getName(), "File:  " + cancelName);
+            assertEquals(5, cancel.getDepth(), "Depth: " + cancelName);
+        } catch(final IOException ex) {
+            fail("IOException: " + cancelName + " " + ex);
+        }
+
+        // Cancel on a directory
+        try {
+            cancelName = "commons";
+            new TestCancelWalker(cancelName, false).find(javaDir);
+            fail("CancelException not thrown for '" + cancelName + "'");
+        } catch (final DirectoryWalker.CancelException cancel) {
+            assertEquals(cancelName, cancel.getFile().getName(), "File:  " + cancelName);
+            assertEquals(3, cancel.getDepth(), "Depth: " + cancelName);
+        } catch(final IOException ex) {
+            fail("IOException: " + cancelName + " " + ex);
+        }
+
+        // Suppress CancelException (use same file name as preceding test)
+        try {
+            final List<File> results = new TestCancelWalker(cancelName, true).find(javaDir);
+            final File lastFile = results.get(results.size() - 1);
+            assertEquals(cancelName, lastFile.getName(), "Suppress:  " + cancelName);
+        } catch(final IOException ex) {
+            fail("Suppress threw " + ex);
+        }
+
+    }
 
     /**
      * Test Filtering
@@ -83,6 +367,8 @@ public class DirectoryWalkerTestCase {
         checkContainsFiles("Output File", outputFiles, results);
     }
 
+    // ------------ Convenience Test Methods ------------------------------------
+
     /**
      * Test Filtering and limit to depth 0
      */
@@ -177,36 +463,21 @@ public class DirectoryWalkerTestCase {
         checkContainsFiles("[DirAndFile4] File", ioFiles, resultFiles);
     }
 
-    /**
-     * Test Limiting to current directory
-     */
-    @Test
-    public void testLimitToCurrent() {
-        final List<File> results = new TestFileFinder(null, 0).find(current);
-        assertEquals(1, results.size(), "Result Size");
-        assertTrue(results.contains(new File(".")), "Current Dir");
-    }
+    // ------------ Test DirectoryWalker implementation --------------------------
 
     /**
-     * test an invalid start directory
+     * Test Filtering
      */
     @Test
-    public void testMissingStartDirectory() {
-
-        // TODO is this what we want with invalid directory?
-        final File invalidDir = new File("invalid-dir");
-        final List<File> results = new TestFileFinder(null, -1).find(invalidDir);
-        assertEquals(1, results.size(), "Result Size");
-        assertTrue(results.contains(invalidDir), "Current Dir");
-
-        try {
-            new TestFileFinder(null, -1).find(null);
-            fail("Null start directory didn't throw Exception");
-        } catch (final NullPointerException ignore) {
-            // expected result
-        }
+    public void testFilterString() {
+        final List<String> results = new TestFileFinderString(dirsAndFilesFilter, -1).find(javaDir);
+        assertEquals(results.size(), outputFiles.length + ioFiles.length, "Result Size");
+        checkContainsString("IO File", ioFiles, results);
+        checkContainsString("Output File", outputFiles, results);
     }
 
+    // ------------ Test DirectoryWalker implementation --------------------------
+
     /**
      * test an invalid start directory
      */
@@ -218,101 +489,36 @@ public class DirectoryWalkerTestCase {
 
     }
 
-    // ------------ Convenience Test Methods ------------------------------------
-
-    /**
-     * Check the files in the array are in the results list.
-     */
-    private void checkContainsFiles(final String prefix, final File[] files, final Collection<File> results) {
-        for (int i = 0; i < files.length; i++) {
-            assertTrue(results.contains(files[i]), prefix + "["+i+"] " + files[i]);
-        }
-    }
-
-    private void checkContainsString(final String prefix, final File[] files, final Collection<String> results) {
-        for (int i = 0; i < files.length; i++) {
-            assertTrue(results.contains(files[i].toString()), prefix + "["+i+"] " + files[i]);
-        }
-    }
-
-    /**
-     * Extract the directories.
-     */
-    private List<File> directoriesOnly(final Collection<File> results) {
-        final List<File> list = new ArrayList<>(results.size());
-        for (final File file : results) {
-            if (file.isDirectory()) {
-                list.add(file);
-            }
-        }
-        return list;
-    }
-
-    /**
-     * Extract the files.
-     */
-    private List<File> filesOnly(final Collection<File> results) {
-        final List<File> list = new ArrayList<>(results.size());
-        for (final File file : results) {
-            if (file.isFile()) {
-                list.add(file);
-            }
-        }
-        return list;
-    }
+    // ------------ Test DirectoryWalker implementation --------------------------
 
     /**
-     * Create a name filter containing the names of the files
-     * in the array.
-     */
-    private static IOFileFilter createNameFilter(final File[] files) {
-        final String[] names = new String[files.length];
-        for (int i = 0; i < files.length; i++) {
-            names[i] = files[i].getName();
-        }
-        return new NameFileFilter(names);
+     * Test Limiting to current directory
+     */
+    @Test
+    public void testLimitToCurrent() {
+        final List<File> results = new TestFileFinder(null, 0).find(current);
+        assertEquals(1, results.size(), "Result Size");
+        assertTrue(results.contains(new File(".")), "Current Dir");
     }
 
     /**
-     * Test Cancel
+     * test an invalid start directory
      */
     @Test
-    public void testCancel() {
-        String cancelName = null;
-
-        // Cancel on a file
-        try {
-            cancelName = "DirectoryWalker.java";
-            new TestCancelWalker(cancelName, false).find(javaDir);
-            fail("CancelException not thrown for '" + cancelName + "'");
-        } catch (final DirectoryWalker.CancelException cancel) {
-            assertEquals(cancelName, cancel.getFile().getName(), "File:  " + cancelName);
-            assertEquals(5, cancel.getDepth(), "Depth: " + cancelName);
-        } catch(final IOException ex) {
-            fail("IOException: " + cancelName + " " + ex);
-        }
+    public void testMissingStartDirectory() {
 
-        // Cancel on a directory
-        try {
-            cancelName = "commons";
-            new TestCancelWalker(cancelName, false).find(javaDir);
-            fail("CancelException not thrown for '" + cancelName + "'");
-        } catch (final DirectoryWalker.CancelException cancel) {
-            assertEquals(cancelName, cancel.getFile().getName(), "File:  " + cancelName);
-            assertEquals(3, cancel.getDepth(), "Depth: " + cancelName);
-        } catch(final IOException ex) {
-            fail("IOException: " + cancelName + " " + ex);
-        }
+        // TODO is this what we want with invalid directory?
+        final File invalidDir = new File("invalid-dir");
+        final List<File> results = new TestFileFinder(null, -1).find(invalidDir);
+        assertEquals(1, results.size(), "Result Size");
+        assertTrue(results.contains(invalidDir), "Current Dir");
 
-        // Suppress CancelException (use same file name as preceding test)
         try {
-            final List<File> results = new TestCancelWalker(cancelName, true).find(javaDir);
-            final File lastFile = results.get(results.size() - 1);
-            assertEquals(cancelName, lastFile.getName(), "Suppress:  " + cancelName);
-        } catch(final IOException ex) {
-            fail("Suppress threw " + ex);
+            new TestFileFinder(null, -1).find(null);
+            fail("Null start directory didn't throw Exception");
+        } catch (final NullPointerException ignore) {
+            // expected result
         }
-
     }
 
     /**
@@ -359,210 +565,4 @@ public class DirectoryWalkerTestCase {
 
     }
 
-    /**
-     * Test Filtering
-     */
-    @Test
-    public void testFilterString() {
-        final List<String> results = new TestFileFinderString(dirsAndFilesFilter, -1).find(javaDir);
-        assertEquals(results.size(), outputFiles.length + ioFiles.length, "Result Size");
-        checkContainsString("IO File", ioFiles, results);
-        checkContainsString("Output File", outputFiles, results);
-    }
-
-    // ------------ Test DirectoryWalker implementation --------------------------
-
-    /**
-     * Test DirectoryWalker implementation that finds files in a directory hierarchy
-     * applying a file filter.
-     */
-    private static class TestFileFinder extends DirectoryWalker<File> {
-
-        protected TestFileFinder(final FileFilter filter, final int depthLimit) {
-            super(filter, depthLimit);
-        }
-
-        protected TestFileFinder(final IOFileFilter dirFilter, final IOFileFilter fileFilter, final int depthLimit) {
-            super(dirFilter, fileFilter, depthLimit);
-        }
-
-        /** find files. */
-        protected List<File> find(final File startDirectory) {
-           final List<File> results = new ArrayList<>();
-           try {
-               walk(startDirectory, results);
-           } catch(final IOException ex) {
-               fail(ex.toString());
-           }
-           return results;
-        }
-
-        /** Handles a directory end by adding the File to the result set. */
-        @Override
-        protected void handleDirectoryEnd(final File directory, final int depth, final Collection<File> results) {
-            results.add(directory);
-        }
-
-        /** Handles a file by adding the File to the result set. */
-        @Override
-        protected void handleFile(final File file, final int depth, final Collection<File> results) {
-            results.add(file);
-        }
-    }
-
-    // ------------ Test DirectoryWalker implementation --------------------------
-
-    /**
-     * Test DirectoryWalker implementation that always returns false
-     * from handleDirectoryStart()
-     */
-    private static class TestFalseFileFinder extends TestFileFinder {
-
-        protected TestFalseFileFinder(final FileFilter filter, final int depthLimit) {
-            super(filter, depthLimit);
-        }
-
-        /** Always returns false. */
-        @Override
-        protected boolean handleDirectory(final File directory, final int depth, final Collection<File> results) {
-            return false;
-        }
-    }
-
-    // ------------ Test DirectoryWalker implementation --------------------------
-
-    /**
-     * Test DirectoryWalker implementation that finds files in a directory hierarchy
-     * applying a file filter.
-     */
-    static class TestCancelWalker extends DirectoryWalker<File> {
-        private final String cancelFileName;
-        private final boolean suppressCancel;
-
-        TestCancelWalker(final String cancelFileName,final boolean suppressCancel) {
-            this.cancelFileName = cancelFileName;
-            this.suppressCancel = suppressCancel;
-        }
-
-        /** find files. */
-        protected List<File> find(final File startDirectory) throws IOException {
-           final List<File> results = new ArrayList<>();
-           walk(startDirectory, results);
-           return results;
-        }
-
-        /** Handles a directory end by adding the File to the result set. */
-        @Override
-        protected void handleDirectoryEnd(final File directory, final int depth, final Collection<File> results) throws IOException {
-            results.add(directory);
-            if (cancelFileName.equals(directory.getName())) {
-                throw new CancelException(directory, depth);
-            }
-        }
-
-        /** Handles a file by adding the File to the result set. */
-        @Override
-        protected void handleFile(final File file, final int depth, final Collection<File> results) throws IOException {
-            results.add(file);
-            if (cancelFileName.equals(file.getName())) {
-                throw new CancelException(file, depth);
-            }
-        }
-
-        /** Handles Cancel. */
-        @Override
-        protected void handleCancelled(final File startDirectory, final Collection<File> results,
-                       final CancelException cancel) throws IOException {
-            if (!suppressCancel) {
-                super.handleCancelled(startDirectory, results, cancel);
-            }
-        }
-    }
-
-    /**
-     * Test DirectoryWalker implementation that finds files in a directory hierarchy
-     * applying a file filter.
-     */
-    static class TestMultiThreadCancelWalker extends DirectoryWalker<File> {
-        private final String cancelFileName;
-        private final boolean suppressCancel;
-        private boolean cancelled;
-        public List<File> results;
-
-        TestMultiThreadCancelWalker(final String cancelFileName, final boolean suppressCancel) {
-            this.cancelFileName = cancelFileName;
-            this.suppressCancel = suppressCancel;
-        }
-
-        /** find files. */
-        protected List<File> find(final File startDirectory) throws IOException {
-           results = new ArrayList<>();
-           walk(startDirectory, results);
-           return results;
-        }
-
-        /** Handles a directory end by adding the File to the result set. */
-        @Override
-        protected void handleDirectoryEnd(final File directory, final int depth, final Collection<File> results) throws IOException {
-            results.add(directory);
-            assertFalse(cancelled);
-            if (cancelFileName.equals(directory.getName())) {
-                cancelled = true;
-            }
-        }
-
-        /** Handles a file by adding the File to the result set. */
-        @Override
-        protected void handleFile(final File file, final int depth, final Collection<File> results) throws IOException {
-            results.add(file);
-            assertFalse(cancelled);
-            if (cancelFileName.equals(file.getName())) {
-                cancelled = true;
-            }
-        }
-
-        /** Handles Cancelled. */
-        @Override
-        protected boolean handleIsCancelled(final File file, final int depth, final Collection<File> results) throws IOException {
-            return cancelled;
-        }
-
-        /** Handles Cancel. */
-        @Override
-        protected void handleCancelled(final File startDirectory, final Collection<File> results,
-                       final CancelException cancel) throws IOException {
-            if (!suppressCancel) {
-                super.handleCancelled(startDirectory, results, cancel);
-            }
-        }
-    }
-
-    /**
-     * Test DirectoryWalker implementation that finds files in a directory hierarchy
-     * applying a file filter.
-     */
-    private static class TestFileFinderString extends DirectoryWalker<String> {
-
-        protected TestFileFinderString(final FileFilter filter, final int depthLimit) {
-            super(filter, depthLimit);
-        }
-
-        /** find files. */
-        protected List<String> find(final File startDirectory) {
-           final List<String> results = new ArrayList<>();
-           try {
-               walk(startDirectory, results);
-           } catch(final IOException ex) {
-               fail(ex.toString());
-           }
-           return results;
-        }
-
-        /** Handles a file by adding the File to the result set. */
-        @Override
-        protected void handleFile(final File file, final int depth, final Collection<String> results) {
-            results.add(file.toString());
-        }
-    }
-
 }
diff --git a/src/test/java/org/apache/commons/io/DirectoryWalkerTestCaseJava4.java b/src/test/java/org/apache/commons/io/DirectoryWalkerTestCaseJava4.java
index 4885c12..e5159ad 100644
--- a/src/test/java/org/apache/commons/io/DirectoryWalkerTestCaseJava4.java
+++ b/src/test/java/org/apache/commons/io/DirectoryWalkerTestCaseJava4.java
@@ -42,34 +42,302 @@ import org.junit.jupiter.api.Test;
 @SuppressWarnings({"unchecked", "rawtypes"}) // Java4
 public class DirectoryWalkerTestCaseJava4 {
 
+    /**
+     * Test DirectoryWalker implementation that finds files in a directory hierarchy
+     * applying a file filter.
+     */
+    static class TestCancelWalker extends DirectoryWalker {
+        private final String cancelFileName;
+        private final boolean suppressCancel;
+
+        TestCancelWalker(final String cancelFileName, final boolean suppressCancel) {
+            this.cancelFileName = cancelFileName;
+            this.suppressCancel = suppressCancel;
+        }
+
+        /**
+         * find files.
+         */
+        protected List find(final File startDirectory) throws IOException {
+            final List results = new ArrayList();
+            walk(startDirectory, results);
+            return results;
+        }
+
+        /**
+         * Handles Cancel.
+         */
+        @Override
+        protected void handleCancelled(final File startDirectory, final Collection results,
+                                       final CancelException cancel) throws IOException {
+            if (!suppressCancel) {
+                super.handleCancelled(startDirectory, results, cancel);
+            }
+        }
+
+        /**
+         * Handles a directory end by adding the File to the result set.
+         */
+        @Override
+        protected void handleDirectoryEnd(final File directory, final int depth, final Collection results) throws IOException {
+            results.add(directory);
+            if (cancelFileName.equals(directory.getName())) {
+                throw new CancelException(directory, depth);
+            }
+        }
+
+        /**
+         * Handles a file by adding the File to the result set.
+         */
+        @Override
+        protected void handleFile(final File file, final int depth, final Collection results) throws IOException {
+            results.add(file);
+            if (cancelFileName.equals(file.getName())) {
+                throw new CancelException(file, depth);
+            }
+        }
+    }
+    /**
+     * Test DirectoryWalker implementation that always returns false
+     * from handleDirectoryStart()
+     */
+    private static class TestFalseFileFinder extends TestFileFinder {
+
+        protected TestFalseFileFinder(final FileFilter filter, final int depthLimit) {
+            super(filter, depthLimit);
+        }
+
+        /**
+         * Always returns false.
+         */
+        @Override
+        protected boolean handleDirectory(final File directory, final int depth, final Collection results) {
+            return false;
+        }
+    }
+    /**
+     * Test DirectoryWalker implementation that finds files in a directory hierarchy
+     * applying a file filter.
+     */
+    private static class TestFileFinder extends DirectoryWalker {
+
+        protected TestFileFinder(final FileFilter filter, final int depthLimit) {
+            super(filter, depthLimit);
+        }
+
+        protected TestFileFinder(final IOFileFilter dirFilter, final IOFileFilter fileFilter, final int depthLimit) {
+            super(dirFilter, fileFilter, depthLimit);
+        }
+
+        /**
+         * find files.
+         */
+        protected List<File> find(final File startDirectory) {
+            final List<File> results = new ArrayList<>();
+            try {
+                walk(startDirectory, results);
+            } catch (final IOException ex) {
+                fail(ex.toString());
+            }
+            return results;
+        }
+
+        /**
+         * Handles a directory end by adding the File to the result set.
+         */
+        @Override
+        protected void handleDirectoryEnd(final File directory, final int depth, final Collection results) {
+            results.add(directory);
+        }
+
+        /**
+         * Handles a file by adding the File to the result set.
+         */
+        @Override
+        protected void handleFile(final File file, final int depth, final Collection results) {
+            results.add(file);
+        }
+    }
+    /**
+     * Test DirectoryWalker implementation that finds files in a directory hierarchy
+     * applying a file filter.
+     */
+    static class TestMultiThreadCancelWalker extends DirectoryWalker {
+        private final String cancelFileName;
+        private final boolean suppressCancel;
+        private boolean cancelled;
+        public List results;
+
+        TestMultiThreadCancelWalker(final String cancelFileName, final boolean suppressCancel) {
+            this.cancelFileName = cancelFileName;
+            this.suppressCancel = suppressCancel;
+        }
+
+        /**
+         * find files.
+         */
+        protected List find(final File startDirectory) throws IOException {
+            results = new ArrayList();
+            walk(startDirectory, results);
+            return results;
+        }
+
+        /**
+         * Handles Cancel.
+         */
+        @Override
+        protected void handleCancelled(final File startDirectory, final Collection results,
+                                       final CancelException cancel) throws IOException {
+            if (!suppressCancel) {
+                super.handleCancelled(startDirectory, results, cancel);
+            }
+        }
+
+        /**
+         * Handles a directory end by adding the File to the result set.
+         */
+        @Override
+        protected void handleDirectoryEnd(final File directory, final int depth, final Collection results) throws IOException {
+            results.add(directory);
+            assertFalse(cancelled);
+            if (cancelFileName.equals(directory.getName())) {
+                cancelled = true;
+            }
+        }
+
+        /**
+         * Handles a file by adding the File to the result set.
+         */
+        @Override
+        protected void handleFile(final File file, final int depth, final Collection results) throws IOException {
+            results.add(file);
+            assertFalse(cancelled);
+            if (cancelFileName.equals(file.getName())) {
+                cancelled = true;
+            }
+        }
+
+        /**
+         * Handles Cancelled.
+         */
+        @Override
+        protected boolean handleIsCancelled(final File file, final int depth, final Collection results) throws IOException {
+            return cancelled;
+        }
+    }
     // Directories
     private static final File current = new File(".");
     private static final File javaDir = new File("src/main/java");
     private static final File orgDir = new File(javaDir, "org");
     private static final File apacheDir = new File(orgDir, "apache");
+
     private static final File commonsDir = new File(apacheDir, "commons");
     private static final File ioDir = new File(commonsDir, "io");
     private static final File outputDir = new File(ioDir, "output");
     private static final File[] dirs = {orgDir, apacheDir, commonsDir, ioDir, outputDir};
-
     // Files
     private static final File filenameUtils = new File(ioDir, "FilenameUtils.java");
     private static final File ioUtils = new File(ioDir, "IOUtils.java");
+
     private static final File proxyWriter = new File(outputDir, "ProxyWriter.java");
     private static final File nullStream = new File(outputDir, "NullOutputStream.java");
     private static final File[] ioFiles = {filenameUtils, ioUtils};
     private static final File[] outputFiles = {proxyWriter, nullStream};
-
     // Filters
     private static final IOFileFilter dirsFilter = createNameFilter(dirs);
+
     private static final IOFileFilter iofilesFilter = createNameFilter(ioFiles);
+
+
     private static final IOFileFilter outputFilesFilter = createNameFilter(outputFiles);
+
     private static final IOFileFilter ioDirAndFilesFilter = new OrFileFilter(dirsFilter, iofilesFilter);
+
     private static final IOFileFilter dirsAndFilesFilter = new OrFileFilter(ioDirAndFilesFilter, outputFilesFilter);
 
     // Filter to exclude SVN files
     private static final IOFileFilter NOT_SVN = FileFilterUtils.makeSVNAware(null);
 
+    /**
+     * Create a name filter containing the names of the files
+     * in the array.
+     */
+    private static IOFileFilter createNameFilter(final File[] files) {
+        final String[] names = new String[files.length];
+        for (int i = 0; i < files.length; i++) {
+            names[i] = files[i].getName();
+        }
+        return new NameFileFilter(names);
+    }
+
+    /**
+     * Check the files in the array are in the results list.
+     */
+    private void checkContainsFiles(final String prefix, final File[] files, final Collection results) {
+        for (int i = 0; i < files.length; i++) {
+            assertTrue(results.contains(files[i]), prefix + "[" + i + "] " + files[i]);
+        }
+    }
+
+    /**
+     * Extract the directories.
+     */
+    private List directoriesOnly(final Collection<File> results) {
+        final List list = new ArrayList(results.size());
+        for (final File file : results) {
+            if (file.isDirectory()) {
+                list.add(file);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Extract the files.
+     */
+    private List filesOnly(final Collection<File> results) {
+        final List list = new ArrayList(results.size());
+        for (final File file : results) {
+            if (file.isFile()) {
+                list.add(file);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * Test Cancel
+     * @throws IOException
+     */
+    @Test
+    public void testCancel() throws IOException {
+        String cancelName = null;
+
+        // Cancel on a file
+        try {
+            cancelName = "DirectoryWalker.java";
+            new TestCancelWalker(cancelName, false).find(javaDir);
+            fail("CancelException not thrown for '" + cancelName + "'");
+        } catch (final DirectoryWalker.CancelException cancel) {
+            assertEquals(cancelName, cancel.getFile().getName(), "File:  " + cancelName);
+            assertEquals(5, cancel.getDepth(), "Depth: " + cancelName);
+        }
+
+        // Cancel on a directory
+        try {
+            cancelName = "commons";
+            new TestCancelWalker(cancelName, false).find(javaDir);
+            fail("CancelException not thrown for '" + cancelName + "'");
+        } catch (final DirectoryWalker.CancelException cancel) {
+            assertEquals(cancelName, cancel.getFile().getName(), "File:  " + cancelName);
+            assertEquals(3, cancel.getDepth(), "Depth: " + cancelName);
+        }
+
+        // Suppress CancelException (use same file name as preceding test)
+        final List results = new TestCancelWalker(cancelName, true).find(javaDir);
+        final File lastFile = (File) results.get(results.size() - 1);
+        assertEquals(cancelName, lastFile.getName(), "Suppress:  " + cancelName);
+    }
 
     /**
      * Test Filtering
@@ -105,6 +373,8 @@ public class DirectoryWalkerTestCaseJava4 {
         assertTrue(results.contains(orgDir), "[B] Org Dir");
     }
 
+    // ------------ Convenience Test Methods ------------------------------------
+
     /**
      * Test Filtering and limit to depth 3
      */
@@ -178,128 +448,51 @@ public class DirectoryWalkerTestCaseJava4 {
         checkContainsFiles("[DirAndFile4] File", ioFiles, resultFiles);
     }
 
-    /**
-     * Test Limiting to current directory
-     */
-    @Test
-    public void testLimitToCurrent() {
-        final List<File> results = new TestFileFinder(null, 0).find(current);
-        assertEquals(1, results.size(), "Result Size");
-        assertTrue(results.contains(new File(".")), "Current Dir");
-    }
-
-    /**
-     * test an invalid start directory
-     */
-    @Test
-    public void testMissingStartDirectory() {
-
-        // TODO is this what we want with invalid directory?
-        final File invalidDir = new File("invalid-dir");
-        final List<File> results = new TestFileFinder(null, -1).find(invalidDir);
-        assertEquals(1, results.size(), "Result Size");
-        assertTrue(results.contains(invalidDir), "Current Dir");
-
-        try {
-            new TestFileFinder(null, -1).find(null);
-            fail("Null start directory didn't throw Exception");
-        } catch (final NullPointerException ignore) {
-            // expected result
-        }
-    }
-
-    /**
-     * test an invalid start directory
-     */
-    @Test
-    public void testHandleStartDirectoryFalse() {
-
-        final List<File> results = new TestFalseFileFinder(null, -1).find(current);
-        assertEquals(0, results.size(), "Result Size");
-
-    }
-
-    // ------------ Convenience Test Methods ------------------------------------
-
-    /**
-     * Check the files in the array are in the results list.
-     */
-    private void checkContainsFiles(final String prefix, final File[] files, final Collection results) {
-        for (int i = 0; i < files.length; i++) {
-            assertTrue(results.contains(files[i]), prefix + "[" + i + "] " + files[i]);
-        }
-    }
-
-    /**
-     * Extract the directories.
-     */
-    private List directoriesOnly(final Collection<File> results) {
-        final List list = new ArrayList(results.size());
-        for (final File file : results) {
-            if (file.isDirectory()) {
-                list.add(file);
-            }
-        }
-        return list;
-    }
+    // ------------ Test DirectoryWalker implementation --------------------------
+
+    /**
+     * test an invalid start directory
+     */
+    @Test
+    public void testHandleStartDirectoryFalse() {
+
+        final List<File> results = new TestFalseFileFinder(null, -1).find(current);
+        assertEquals(0, results.size(), "Result Size");
 
-    /**
-     * Extract the files.
-     */
-    private List filesOnly(final Collection<File> results) {
-        final List list = new ArrayList(results.size());
-        for (final File file : results) {
-            if (file.isFile()) {
-                list.add(file);
-            }
-        }
-        return list;
     }
 
+    // ------------ Test DirectoryWalker implementation --------------------------
+
     /**
-     * Create a name filter containing the names of the files
-     * in the array.
+     * Test Limiting to current directory
      */
-    private static IOFileFilter createNameFilter(final File[] files) {
-        final String[] names = new String[files.length];
-        for (int i = 0; i < files.length; i++) {
-            names[i] = files[i].getName();
-        }
-        return new NameFileFilter(names);
+    @Test
+    public void testLimitToCurrent() {
+        final List<File> results = new TestFileFinder(null, 0).find(current);
+        assertEquals(1, results.size(), "Result Size");
+        assertTrue(results.contains(new File(".")), "Current Dir");
     }
 
+    // ------------ Test DirectoryWalker implementation --------------------------
+
     /**
-     * Test Cancel
-     * @throws IOException
+     * test an invalid start directory
      */
     @Test
-    public void testCancel() throws IOException {
-        String cancelName = null;
+    public void testMissingStartDirectory() {
 
-        // Cancel on a file
-        try {
-            cancelName = "DirectoryWalker.java";
-            new TestCancelWalker(cancelName, false).find(javaDir);
-            fail("CancelException not thrown for '" + cancelName + "'");
-        } catch (final DirectoryWalker.CancelException cancel) {
-            assertEquals(cancelName, cancel.getFile().getName(), "File:  " + cancelName);
-            assertEquals(5, cancel.getDepth(), "Depth: " + cancelName);
-        }
+        // TODO is this what we want with invalid directory?
+        final File invalidDir = new File("invalid-dir");
+        final List<File> results = new TestFileFinder(null, -1).find(invalidDir);
+        assertEquals(1, results.size(), "Result Size");
+        assertTrue(results.contains(invalidDir), "Current Dir");
 
-        // Cancel on a directory
         try {
-            cancelName = "commons";
-            new TestCancelWalker(cancelName, false).find(javaDir);
-            fail("CancelException not thrown for '" + cancelName + "'");
-        } catch (final DirectoryWalker.CancelException cancel) {
-            assertEquals(cancelName, cancel.getFile().getName(), "File:  " + cancelName);
-            assertEquals(3, cancel.getDepth(), "Depth: " + cancelName);
+            new TestFileFinder(null, -1).find(null);
+            fail("Null start directory didn't throw Exception");
+        } catch (final NullPointerException ignore) {
+            // expected result
         }
-
-        // Suppress CancelException (use same file name as preceding test)
-        final List results = new TestCancelWalker(cancelName, true).find(javaDir);
-        final File lastFile = (File) results.get(results.size() - 1);
-        assertEquals(cancelName, lastFile.getName(), "Suppress:  " + cancelName);
     }
 
     /**
@@ -339,197 +532,4 @@ public class DirectoryWalkerTestCaseJava4 {
 
     }
 
-    // ------------ Test DirectoryWalker implementation --------------------------
-
-    /**
-     * Test DirectoryWalker implementation that finds files in a directory hierarchy
-     * applying a file filter.
-     */
-    private static class TestFileFinder extends DirectoryWalker {
-
-        protected TestFileFinder(final FileFilter filter, final int depthLimit) {
-            super(filter, depthLimit);
-        }
-
-        protected TestFileFinder(final IOFileFilter dirFilter, final IOFileFilter fileFilter, final int depthLimit) {
-            super(dirFilter, fileFilter, depthLimit);
-        }
-
-        /**
-         * find files.
-         */
-        protected List<File> find(final File startDirectory) {
-            final List<File> results = new ArrayList<>();
-            try {
-                walk(startDirectory, results);
-            } catch (final IOException ex) {
-                fail(ex.toString());
-            }
-            return results;
-        }
-
-        /**
-         * Handles a directory end by adding the File to the result set.
-         */
-        @Override
-        protected void handleDirectoryEnd(final File directory, final int depth, final Collection results) {
-            results.add(directory);
-        }
-
-        /**
-         * Handles a file by adding the File to the result set.
-         */
-        @Override
-        protected void handleFile(final File file, final int depth, final Collection results) {
-            results.add(file);
-        }
-    }
-
-    // ------------ Test DirectoryWalker implementation --------------------------
-
-    /**
-     * Test DirectoryWalker implementation that always returns false
-     * from handleDirectoryStart()
-     */
-    private static class TestFalseFileFinder extends TestFileFinder {
-
-        protected TestFalseFileFinder(final FileFilter filter, final int depthLimit) {
-            super(filter, depthLimit);
-        }
-
-        /**
-         * Always returns false.
-         */
-        @Override
-        protected boolean handleDirectory(final File directory, final int depth, final Collection results) {
-            return false;
-        }
-    }
-
-    // ------------ Test DirectoryWalker implementation --------------------------
-
-    /**
-     * Test DirectoryWalker implementation that finds files in a directory hierarchy
-     * applying a file filter.
-     */
-    static class TestCancelWalker extends DirectoryWalker {
-        private final String cancelFileName;
-        private final boolean suppressCancel;
-
-        TestCancelWalker(final String cancelFileName, final boolean suppressCancel) {
-            this.cancelFileName = cancelFileName;
-            this.suppressCancel = suppressCancel;
-        }
-
-        /**
-         * find files.
-         */
-        protected List find(final File startDirectory) throws IOException {
-            final List results = new ArrayList();
-            walk(startDirectory, results);
-            return results;
-        }
-
-        /**
-         * Handles a directory end by adding the File to the result set.
-         */
-        @Override
-        protected void handleDirectoryEnd(final File directory, final int depth, final Collection results) throws IOException {
-            results.add(directory);
-            if (cancelFileName.equals(directory.getName())) {
-                throw new CancelException(directory, depth);
-            }
-        }
-
-        /**
-         * Handles a file by adding the File to the result set.
-         */
-        @Override
-        protected void handleFile(final File file, final int depth, final Collection results) throws IOException {
-            results.add(file);
-            if (cancelFileName.equals(file.getName())) {
-                throw new CancelException(file, depth);
-            }
-        }
-
-        /**
-         * Handles Cancel.
-         */
-        @Override
-        protected void handleCancelled(final File startDirectory, final Collection results,
-                                       final CancelException cancel) throws IOException {
-            if (!suppressCancel) {
-                super.handleCancelled(startDirectory, results, cancel);
-            }
-        }
-    }
-
-    /**
-     * Test DirectoryWalker implementation that finds files in a directory hierarchy
-     * applying a file filter.
-     */
-    static class TestMultiThreadCancelWalker extends DirectoryWalker {
-        private final String cancelFileName;
-        private final boolean suppressCancel;
-        private boolean cancelled;
-        public List results;
-
-        TestMultiThreadCancelWalker(final String cancelFileName, final boolean suppressCancel) {
-            this.cancelFileName = cancelFileName;
-            this.suppressCancel = suppressCancel;
-        }
-
-        /**
-         * find files.
-         */
-        protected List find(final File startDirectory) throws IOException {
-            results = new ArrayList();
-            walk(startDirectory, results);
-            return results;
-        }
-
-        /**
-         * Handles a directory end by adding the File to the result set.
-         */
-        @Override
-        protected void handleDirectoryEnd(final File directory, final int depth, final Collection results) throws IOException {
-            results.add(directory);
-            assertFalse(cancelled);
-            if (cancelFileName.equals(directory.getName())) {
-                cancelled = true;
-            }
-        }
-
-        /**
-         * Handles a file by adding the File to the result set.
-         */
-        @Override
-        protected void handleFile(final File file, final int depth, final Collection results) throws IOException {
-            results.add(file);
-            assertFalse(cancelled);
-            if (cancelFileName.equals(file.getName())) {
-                cancelled = true;
-            }
-        }
-
-        /**
-         * Handles Cancelled.
-         */
-        @Override
-        protected boolean handleIsCancelled(final File file, final int depth, final Collection results) throws IOException {
-            return cancelled;
-        }
-
-        /**
-         * Handles Cancel.
-         */
-        @Override
-        protected void handleCancelled(final File startDirectory, final Collection results,
-                                       final CancelException cancel) throws IOException {
-            if (!suppressCancel) {
-                super.handleCancelled(startDirectory, results, cancel);
-            }
-        }
-    }
-
 }
diff --git a/src/test/java/org/apache/commons/io/EndianUtilsTest.java b/src/test/java/org/apache/commons/io/EndianUtilsTest.java
index 884a1ca..4902c4d 100644
--- a/src/test/java/org/apache/commons/io/EndianUtilsTest.java
+++ b/src/test/java/org/apache/commons/io/EndianUtilsTest.java
@@ -49,61 +49,43 @@ public class EndianUtilsTest  {
     }
 
     @Test
-    public void testSwapShort() {
-        assertEquals( (short) 0, EndianUtils.swapShort( (short) 0 ) );
-        assertEquals( (short) 0x0201, EndianUtils.swapShort( (short) 0x0102 ) );
-        assertEquals( (short) 0xffff, EndianUtils.swapShort( (short) 0xffff ) );
-        assertEquals( (short) 0x0102, EndianUtils.swapShort( (short) 0x0201 ) );
-    }
-
-    @Test
-    public void testSwapInteger() {
-        assertEquals( 0, EndianUtils.swapInteger( 0 ) );
-        assertEquals( 0x04030201, EndianUtils.swapInteger( 0x01020304 ) );
-        assertEquals( 0x01000000, EndianUtils.swapInteger( 0x00000001 ) );
-        assertEquals( 0x00000001, EndianUtils.swapInteger( 0x01000000 ) );
-        assertEquals( 0x11111111, EndianUtils.swapInteger( 0x11111111 ) );
-        assertEquals( 0xabcdef10, EndianUtils.swapInteger( 0x10efcdab ) );
-        assertEquals( 0xab, EndianUtils.swapInteger( 0xab000000 ) );
-    }
+    public void testReadSwappedDouble() throws IOException {
+        final byte[] bytes = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };
+        final double d1 = Double.longBitsToDouble( 0x0102030405060708L );
+        final double d2 = EndianUtils.readSwappedDouble( bytes, 0 );
+        assertEquals( d1, d2, 0.0 );
 
-    @Test
-    public void testSwapLong() {
-        assertEquals( 0, EndianUtils.swapLong( 0 ) );
-        assertEquals( 0x0807060504030201L, EndianUtils.swapLong( 0x0102030405060708L ) );
-        assertEquals( 0xffffffffffffffffL, EndianUtils.swapLong( 0xffffffffffffffffL ) );
-        assertEquals( 0xab, EndianUtils.swapLong( 0xab00000000000000L ) );
+        final ByteArrayInputStream input = new ByteArrayInputStream(bytes);
+        assertEquals( d1, EndianUtils.readSwappedDouble( input ), 0.0 );
     }
 
     @Test
-    public void testSwapFloat() {
-        assertEquals( 0.0f, EndianUtils.swapFloat( 0.0f ), 0.0 );
+    public void testReadSwappedFloat() throws IOException {
+        final byte[] bytes = { 0x04, 0x03, 0x02, 0x01 };
         final float f1 = Float.intBitsToFloat( 0x01020304 );
-        final float f2 = Float.intBitsToFloat( 0x04030201 );
-        assertEquals( f2, EndianUtils.swapFloat( f1 ), 0.0 );
+        final float f2 = EndianUtils.readSwappedFloat( bytes, 0 );
+        assertEquals( f1, f2, 0.0 );
+
+        final ByteArrayInputStream input = new ByteArrayInputStream(bytes);
+        assertEquals( f1, EndianUtils.readSwappedFloat( input ), 0.0 );
     }
 
     @Test
-    public void testSwapDouble() {
-        assertEquals( 0.0, EndianUtils.swapDouble( 0.0 ), 0.0 );
-        final double d1 = Double.longBitsToDouble( 0x0102030405060708L );
-        final double d2 = Double.longBitsToDouble( 0x0807060504030201L );
-        assertEquals( d2, EndianUtils.swapDouble( d1 ), 0.0 );
+    public void testReadSwappedInteger() throws IOException {
+        final byte[] bytes = { 0x04, 0x03, 0x02, 0x01 };
+        assertEquals( 0x01020304, EndianUtils.readSwappedInteger( bytes, 0 ) );
+
+        final ByteArrayInputStream input = new ByteArrayInputStream(bytes);
+        assertEquals( 0x01020304, EndianUtils.readSwappedInteger( input ) );
     }
 
-    /**
-     * Tests all swapXxxx methods for symmetry when going from one endian
-     * to another and back again.
-     */
     @Test
-    public void testSymmetry() {
-        assertEquals( (short) 0x0102, EndianUtils.swapShort( EndianUtils.swapShort( (short) 0x0102 ) ) );
-        assertEquals( 0x01020304, EndianUtils.swapInteger( EndianUtils.swapInteger( 0x01020304 ) ) );
-        assertEquals( 0x0102030405060708L, EndianUtils.swapLong( EndianUtils.swapLong( 0x0102030405060708L ) ) );
-        final float f1 = Float.intBitsToFloat( 0x01020304 );
-        assertEquals( f1, EndianUtils.swapFloat( EndianUtils.swapFloat( f1 ) ), 0.0 );
-        final double d1 = Double.longBitsToDouble( 0x0102030405060708L );
-        assertEquals( d1, EndianUtils.swapDouble( EndianUtils.swapDouble( d1 ) ), 0.0 );
+    public void testReadSwappedLong() throws IOException {
+        final byte[] bytes = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };
+        assertEquals( 0x0102030405060708L, EndianUtils.readSwappedLong( bytes, 0 ) );
+
+        final ByteArrayInputStream input = new ByteArrayInputStream(bytes);
+        assertEquals( 0x0102030405060708L, EndianUtils.readSwappedLong( input ) );
     }
 
     @Test
@@ -116,17 +98,12 @@ public class EndianUtilsTest  {
     }
 
     @Test
-    public void testWriteSwappedShort() throws IOException {
-        byte[] bytes = new byte[2];
-        EndianUtils.writeSwappedShort( bytes, 0, (short) 0x0102 );
-        assertEquals( 0x02, bytes[0] );
-        assertEquals( 0x01, bytes[1] );
+    public void testReadSwappedUnsignedInteger() throws IOException {
+        final byte[] bytes = { 0x04, 0x03, 0x02, 0x01 };
+        assertEquals( 0x0000000001020304L, EndianUtils.readSwappedUnsignedInteger( bytes, 0 ) );
 
-        final ByteArrayOutputStream baos = new ByteArrayOutputStream(2);
-        EndianUtils.writeSwappedShort( baos, (short) 0x0102 );
-        bytes = baos.toByteArray();
-        assertEquals( 0x02, bytes[0] );
-        assertEquals( 0x01, bytes[1] );
+        final ByteArrayInputStream input = new ByteArrayInputStream(bytes);
+        assertEquals( 0x0000000001020304L, EndianUtils.readSwappedUnsignedInteger( input ) );
     }
 
     @Test
@@ -139,54 +116,104 @@ public class EndianUtilsTest  {
     }
 
     @Test
-    public void testReadSwappedInteger() throws IOException {
-        final byte[] bytes = { 0x04, 0x03, 0x02, 0x01 };
-        assertEquals( 0x01020304, EndianUtils.readSwappedInteger( bytes, 0 ) );
+    public void testSwapDouble() {
+        assertEquals( 0.0, EndianUtils.swapDouble( 0.0 ), 0.0 );
+        final double d1 = Double.longBitsToDouble( 0x0102030405060708L );
+        final double d2 = Double.longBitsToDouble( 0x0807060504030201L );
+        assertEquals( d2, EndianUtils.swapDouble( d1 ), 0.0 );
+    }
 
-        final ByteArrayInputStream input = new ByteArrayInputStream(bytes);
-        assertEquals( 0x01020304, EndianUtils.readSwappedInteger( input ) );
+    @Test
+    public void testSwapFloat() {
+        assertEquals( 0.0f, EndianUtils.swapFloat( 0.0f ), 0.0 );
+        final float f1 = Float.intBitsToFloat( 0x01020304 );
+        final float f2 = Float.intBitsToFloat( 0x04030201 );
+        assertEquals( f2, EndianUtils.swapFloat( f1 ), 0.0 );
     }
 
     @Test
-    public void testWriteSwappedInteger() throws IOException {
-        byte[] bytes = new byte[4];
-        EndianUtils.writeSwappedInteger( bytes, 0, 0x01020304 );
-        assertEquals( 0x04, bytes[0] );
-        assertEquals( 0x03, bytes[1] );
-        assertEquals( 0x02, bytes[2] );
-        assertEquals( 0x01, bytes[3] );
+    public void testSwapInteger() {
+        assertEquals( 0, EndianUtils.swapInteger( 0 ) );
+        assertEquals( 0x04030201, EndianUtils.swapInteger( 0x01020304 ) );
+        assertEquals( 0x01000000, EndianUtils.swapInteger( 0x00000001 ) );
+        assertEquals( 0x00000001, EndianUtils.swapInteger( 0x01000000 ) );
+        assertEquals( 0x11111111, EndianUtils.swapInteger( 0x11111111 ) );
+        assertEquals( 0xabcdef10, EndianUtils.swapInteger( 0x10efcdab ) );
+        assertEquals( 0xab, EndianUtils.swapInteger( 0xab000000 ) );
+    }
 
-        final ByteArrayOutputStream baos = new ByteArrayOutputStream(4);
-        EndianUtils.writeSwappedInteger( baos, 0x01020304 );
-        bytes = baos.toByteArray();
-        assertEquals( 0x04, bytes[0] );
-        assertEquals( 0x03, bytes[1] );
-        assertEquals( 0x02, bytes[2] );
-        assertEquals( 0x01, bytes[3] );
+    @Test
+    public void testSwapLong() {
+        assertEquals( 0, EndianUtils.swapLong( 0 ) );
+        assertEquals( 0x0807060504030201L, EndianUtils.swapLong( 0x0102030405060708L ) );
+        assertEquals( 0xffffffffffffffffL, EndianUtils.swapLong( 0xffffffffffffffffL ) );
+        assertEquals( 0xab, EndianUtils.swapLong( 0xab00000000000000L ) );
     }
 
     @Test
-    public void testReadSwappedUnsignedInteger() throws IOException {
-        final byte[] bytes = { 0x04, 0x03, 0x02, 0x01 };
-        assertEquals( 0x0000000001020304L, EndianUtils.readSwappedUnsignedInteger( bytes, 0 ) );
+    public void testSwapShort() {
+        assertEquals( (short) 0, EndianUtils.swapShort( (short) 0 ) );
+        assertEquals( (short) 0x0201, EndianUtils.swapShort( (short) 0x0102 ) );
+        assertEquals( (short) 0xffff, EndianUtils.swapShort( (short) 0xffff ) );
+        assertEquals( (short) 0x0102, EndianUtils.swapShort( (short) 0x0201 ) );
+    }
 
-        final ByteArrayInputStream input = new ByteArrayInputStream(bytes);
-        assertEquals( 0x0000000001020304L, EndianUtils.readSwappedUnsignedInteger( input ) );
+    /**
+     * Tests all swapXxxx methods for symmetry when going from one endian
+     * to another and back again.
+     */
+    @Test
+    public void testSymmetry() {
+        assertEquals( (short) 0x0102, EndianUtils.swapShort( EndianUtils.swapShort( (short) 0x0102 ) ) );
+        assertEquals( 0x01020304, EndianUtils.swapInteger( EndianUtils.swapInteger( 0x01020304 ) ) );
+        assertEquals( 0x0102030405060708L, EndianUtils.swapLong( EndianUtils.swapLong( 0x0102030405060708L ) ) );
+        final float f1 = Float.intBitsToFloat( 0x01020304 );
+        assertEquals( f1, EndianUtils.swapFloat( EndianUtils.swapFloat( f1 ) ), 0.0 );
+        final double d1 = Double.longBitsToDouble( 0x0102030405060708L );
+        assertEquals( d1, EndianUtils.swapDouble( EndianUtils.swapDouble( d1 ) ), 0.0 );
     }
 
+    // tests #IO-101
     @Test
-    public void testReadSwappedLong() throws IOException {
-        final byte[] bytes = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };
-        assertEquals( 0x0102030405060708L, EndianUtils.readSwappedLong( bytes, 0 ) );
+    public void testSymmetryOfLong() {
 
-        final ByteArrayInputStream input = new ByteArrayInputStream(bytes);
-        assertEquals( 0x0102030405060708L, EndianUtils.readSwappedLong( input ) );
+        final double[] tests = {34.345, -345.5645, 545.12, 10.043, 7.123456789123};
+        for (final double test : tests) {
+
+            // testing the real problem
+            byte[] buffer = new byte[8];
+            final long ln1 = Double.doubleToLongBits( test );
+            EndianUtils.writeSwappedLong(buffer, 0, ln1);
+            final long ln2 = EndianUtils.readSwappedLong(buffer, 0);
+            assertEquals( ln1, ln2 );
+
+            // testing the bug report
+            buffer = new byte[8];
+            EndianUtils.writeSwappedDouble(buffer, 0, test);
+            final double val = EndianUtils.readSwappedDouble(buffer, 0);
+            assertEquals( test, val, 0 );
+        }
     }
 
+    // tests #IO-117
     @Test
-    public void testWriteSwappedLong() throws IOException {
+    public void testUnsignedOverrun() throws Exception {
+        final byte[] target = { 0, 0, 0, (byte)0x80 };
+        final long expected = 0x80000000L;
+
+        long actual = EndianUtils.readSwappedUnsignedInteger(target, 0);
+        assertEquals(expected, actual, "readSwappedUnsignedInteger(byte[], int) was incorrect");
+
+        final ByteArrayInputStream in = new ByteArrayInputStream(target);
+        actual = EndianUtils.readSwappedUnsignedInteger(in);
+        assertEquals(expected, actual, "readSwappedUnsignedInteger(InputStream) was incorrect");
+    }
+
+    @Test
+    public void testWriteSwappedDouble() throws IOException {
         byte[] bytes = new byte[8];
-        EndianUtils.writeSwappedLong( bytes, 0, 0x0102030405060708L );
+        final double d1 = Double.longBitsToDouble( 0x0102030405060708L );
+        EndianUtils.writeSwappedDouble( bytes, 0, d1 );
         assertEquals( 0x08, bytes[0] );
         assertEquals( 0x07, bytes[1] );
         assertEquals( 0x06, bytes[2] );
@@ -197,7 +224,7 @@ public class EndianUtilsTest  {
         assertEquals( 0x01, bytes[7] );
 
         final ByteArrayOutputStream baos = new ByteArrayOutputStream(8);
-        EndianUtils.writeSwappedLong( baos, 0x0102030405060708L );
+        EndianUtils.writeSwappedDouble( baos, d1 );
         bytes = baos.toByteArray();
         assertEquals( 0x08, bytes[0] );
         assertEquals( 0x07, bytes[1] );
@@ -210,17 +237,6 @@ public class EndianUtilsTest  {
     }
 
     @Test
-    public void testReadSwappedFloat() throws IOException {
-        final byte[] bytes = { 0x04, 0x03, 0x02, 0x01 };
-        final float f1 = Float.intBitsToFloat( 0x01020304 );
-        final float f2 = EndianUtils.readSwappedFloat( bytes, 0 );
-        assertEquals( f1, f2, 0.0 );
-
-        final ByteArrayInputStream input = new ByteArrayInputStream(bytes);
-        assertEquals( f1, EndianUtils.readSwappedFloat( input ), 0.0 );
-    }
-
-    @Test
     public void testWriteSwappedFloat() throws IOException {
         byte[] bytes = new byte[4];
         final float f1 = Float.intBitsToFloat( 0x01020304 );
@@ -240,21 +256,27 @@ public class EndianUtilsTest  {
     }
 
     @Test
-    public void testReadSwappedDouble() throws IOException {
-        final byte[] bytes = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };
-        final double d1 = Double.longBitsToDouble( 0x0102030405060708L );
-        final double d2 = EndianUtils.readSwappedDouble( bytes, 0 );
-        assertEquals( d1, d2, 0.0 );
+    public void testWriteSwappedInteger() throws IOException {
+        byte[] bytes = new byte[4];
+        EndianUtils.writeSwappedInteger( bytes, 0, 0x01020304 );
+        assertEquals( 0x04, bytes[0] );
+        assertEquals( 0x03, bytes[1] );
+        assertEquals( 0x02, bytes[2] );
+        assertEquals( 0x01, bytes[3] );
 
-        final ByteArrayInputStream input = new ByteArrayInputStream(bytes);
-        assertEquals( d1, EndianUtils.readSwappedDouble( input ), 0.0 );
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream(4);
+        EndianUtils.writeSwappedInteger( baos, 0x01020304 );
+        bytes = baos.toByteArray();
+        assertEquals( 0x04, bytes[0] );
+        assertEquals( 0x03, bytes[1] );
+        assertEquals( 0x02, bytes[2] );
+        assertEquals( 0x01, bytes[3] );
     }
 
     @Test
-    public void testWriteSwappedDouble() throws IOException {
+    public void testWriteSwappedLong() throws IOException {
         byte[] bytes = new byte[8];
-        final double d1 = Double.longBitsToDouble( 0x0102030405060708L );
-        EndianUtils.writeSwappedDouble( bytes, 0, d1 );
+        EndianUtils.writeSwappedLong( bytes, 0, 0x0102030405060708L );
         assertEquals( 0x08, bytes[0] );
         assertEquals( 0x07, bytes[1] );
         assertEquals( 0x06, bytes[2] );
@@ -265,7 +287,7 @@ public class EndianUtilsTest  {
         assertEquals( 0x01, bytes[7] );
 
         final ByteArrayOutputStream baos = new ByteArrayOutputStream(8);
-        EndianUtils.writeSwappedDouble( baos, d1 );
+        EndianUtils.writeSwappedLong( baos, 0x0102030405060708L );
         bytes = baos.toByteArray();
         assertEquals( 0x08, bytes[0] );
         assertEquals( 0x07, bytes[1] );
@@ -277,40 +299,18 @@ public class EndianUtilsTest  {
         assertEquals( 0x01, bytes[7] );
     }
 
-    // tests #IO-101
-    @Test
-    public void testSymmetryOfLong() {
-
-        final double[] tests = {34.345, -345.5645, 545.12, 10.043, 7.123456789123};
-        for (final double test : tests) {
-
-            // testing the real problem
-            byte[] buffer = new byte[8];
-            final long ln1 = Double.doubleToLongBits( test );
-            EndianUtils.writeSwappedLong(buffer, 0, ln1);
-            final long ln2 = EndianUtils.readSwappedLong(buffer, 0);
-            assertEquals( ln1, ln2 );
-
-            // testing the bug report
-            buffer = new byte[8];
-            EndianUtils.writeSwappedDouble(buffer, 0, test);
-            final double val = EndianUtils.readSwappedDouble(buffer, 0);
-            assertEquals( test, val, 0 );
-        }
-    }
-
-    // tests #IO-117
     @Test
-    public void testUnsignedOverrun() throws Exception {
-        final byte[] target = { 0, 0, 0, (byte)0x80 };
-        final long expected = 0x80000000L;
-
-        long actual = EndianUtils.readSwappedUnsignedInteger(target, 0);
-        assertEquals(expected, actual, "readSwappedUnsignedInteger(byte[], int) was incorrect");
+    public void testWriteSwappedShort() throws IOException {
+        byte[] bytes = new byte[2];
+        EndianUtils.writeSwappedShort( bytes, 0, (short) 0x0102 );
+        assertEquals( 0x02, bytes[0] );
+        assertEquals( 0x01, bytes[1] );
 
-        final ByteArrayInputStream in = new ByteArrayInputStream(target);
-        actual = EndianUtils.readSwappedUnsignedInteger(in);
-        assertEquals(expected, actual, "readSwappedUnsignedInteger(InputStream) was incorrect");
+        final ByteArrayOutputStream baos = new ByteArrayOutputStream(2);
+        EndianUtils.writeSwappedShort( baos, (short) 0x0102 );
+        bytes = baos.toByteArray();
+        assertEquals( 0x02, bytes[0] );
+        assertEquals( 0x01, bytes[1] );
     }
 
 }
diff --git a/src/test/java/org/apache/commons/io/FileCleaningTrackerTestCase.java b/src/test/java/org/apache/commons/io/FileCleaningTrackerTestCase.java
index 1b3b5c5..b4fc722 100644
--- a/src/test/java/org/apache/commons/io/FileCleaningTrackerTestCase.java
+++ b/src/test/java/org/apache/commons/io/FileCleaningTrackerTestCase.java
@@ -47,12 +47,23 @@ public class FileCleaningTrackerTestCase {
     @TempDir
     public File temporaryFolder;
 
+    private File testFile;
+
+    private FileCleaningTracker theInstance;
     protected FileCleaningTracker newInstance() {
         return new FileCleaningTracker();
     }
 
-    private File testFile;
-    private FileCleaningTracker theInstance;
+    private void pauseForDeleteToComplete(File file) {
+        int count = 0;
+        while(file.exists() && count++ < 40) {
+            try {
+                TestUtils.sleep(500L);
+            } catch (final InterruptedException ignore) {
+            }
+            file = new File(file.getPath());
+        }
+    }
 
     /**
      */
@@ -62,6 +73,13 @@ public class FileCleaningTrackerTestCase {
         theInstance = newInstance();
     }
 
+    private String showFailures() {
+        if (theInstance.deleteFailures.size() == 1) {
+            return "[Delete Failed: " + theInstance.deleteFailures.get(0) + "]";
+        }
+        return "[Delete Failures: " + theInstance.deleteFailures.size() + "]";
+    }
+
     @AfterEach
     public void tearDown() {
 
@@ -86,29 +104,6 @@ public class FileCleaningTrackerTestCase {
     }
 
     @Test
-    public void testFileCleanerFile() throws Exception {
-        final String path = testFile.getPath();
-
-        assertFalse(testFile.exists());
-        RandomAccessFile r = new RandomAccessFile(testFile, "rw");
-        assertTrue(testFile.exists());
-
-        assertEquals(0, theInstance.getTrackCount());
-        theInstance.track(path, r);
-        assertEquals(1, theInstance.getTrackCount());
-
-        r.close();
-        testFile = null;
-        r = null;
-
-        waitUntilTrackCount();
-        pauseForDeleteToComplete(new File(path));
-
-        assertEquals(0, theInstance.getTrackCount());
-        assertFalse(new File(path).exists(), showFailures());
-    }
-
-    @Test
     public void testFileCleanerDirectory() throws Exception {
         TestUtils.createFile(testFile, 100);
         assertTrue(testFile.exists());
@@ -129,26 +124,6 @@ public class FileCleaningTrackerTestCase {
     }
 
     @Test
-    public void testFileCleanerDirectory_NullStrategy() throws Exception {
-        TestUtils.createFile(testFile, 100);
-        assertTrue(testFile.exists());
-        assertTrue(temporaryFolder.exists());
-
-        Object obj = new Object();
-        assertEquals(0, theInstance.getTrackCount());
-        theInstance.track(temporaryFolder, obj, null);
-        assertEquals(1, theInstance.getTrackCount());
-
-        obj = null;
-
-        waitUntilTrackCount();
-
-        assertEquals(0, theInstance.getTrackCount());
-        assertTrue(testFile.exists());  // not deleted, as dir not empty
-        assertTrue(testFile.getParentFile().exists());  // not deleted, as dir not empty
-    }
-
-    @Test
     public void testFileCleanerDirectory_ForceStrategy() throws Exception {
         if (!testFile.getParentFile().exists()) {
             throw new IOException("Cannot create file " + testFile
@@ -177,45 +152,23 @@ public class FileCleaningTrackerTestCase {
     }
 
     @Test
-    public void testFileCleanerNull() {
-        try {
-            theInstance.track((File) null, new Object());
-            fail();
-        } catch (final NullPointerException ex) {
-            // expected
-        }
-        try {
-            theInstance.track((File) null, new Object(), FileDeleteStrategy.NORMAL);
-            fail();
-        } catch (final NullPointerException ex) {
-            // expected
-        }
-        try {
-            theInstance.track((String) null, new Object());
-            fail();
-        } catch (final NullPointerException ex) {
-            // expected
-        }
-        try {
-            theInstance.track((String) null, new Object(), FileDeleteStrategy.NORMAL);
-            fail();
-        } catch (final NullPointerException ex) {
-            // expected
-        }
-    }
+    public void testFileCleanerDirectory_NullStrategy() throws Exception {
+        TestUtils.createFile(testFile, 100);
+        assertTrue(testFile.exists());
+        assertTrue(temporaryFolder.exists());
 
-    @Test
-    public void testFileCleanerExitWhenFinishedFirst() throws Exception {
-        assertFalse(theInstance.exitWhenFinished);
-        theInstance.exitWhenFinished();
-        assertTrue(theInstance.exitWhenFinished);
-        assertNull(theInstance.reaper);
+        Object obj = new Object();
+        assertEquals(0, theInstance.getTrackCount());
+        theInstance.track(temporaryFolder, obj, null);
+        assertEquals(1, theInstance.getTrackCount());
+
+        obj = null;
 
         waitUntilTrackCount();
 
         assertEquals(0, theInstance.getTrackCount());
-        assertTrue(theInstance.exitWhenFinished);
-        assertNull(theInstance.reaper);
+        assertTrue(testFile.exists());  // not deleted, as dir not empty
+        assertTrue(testFile.getParentFile().exists());  // not deleted, as dir not empty
     }
 
     @Test
@@ -304,21 +257,68 @@ public class FileCleaningTrackerTestCase {
         assertFalse(theInstance.reaper.isAlive());
     }
 
-    private void pauseForDeleteToComplete(File file) {
-        int count = 0;
-        while(file.exists() && count++ < 40) {
-            try {
-                TestUtils.sleep(500L);
-            } catch (final InterruptedException ignore) {
-            }
-            file = new File(file.getPath());
-        }
+    @Test
+    public void testFileCleanerExitWhenFinishedFirst() throws Exception {
+        assertFalse(theInstance.exitWhenFinished);
+        theInstance.exitWhenFinished();
+        assertTrue(theInstance.exitWhenFinished);
+        assertNull(theInstance.reaper);
+
+        waitUntilTrackCount();
+
+        assertEquals(0, theInstance.getTrackCount());
+        assertTrue(theInstance.exitWhenFinished);
+        assertNull(theInstance.reaper);
     }
-    private String showFailures() {
-        if (theInstance.deleteFailures.size() == 1) {
-            return "[Delete Failed: " + theInstance.deleteFailures.get(0) + "]";
+
+    @Test
+    public void testFileCleanerFile() throws Exception {
+        final String path = testFile.getPath();
+
+        assertFalse(testFile.exists());
+        RandomAccessFile r = new RandomAccessFile(testFile, "rw");
+        assertTrue(testFile.exists());
+
+        assertEquals(0, theInstance.getTrackCount());
+        theInstance.track(path, r);
+        assertEquals(1, theInstance.getTrackCount());
+
+        r.close();
+        testFile = null;
+        r = null;
+
+        waitUntilTrackCount();
+        pauseForDeleteToComplete(new File(path));
+
+        assertEquals(0, theInstance.getTrackCount());
+        assertFalse(new File(path).exists(), showFailures());
+    }
+    @Test
+    public void testFileCleanerNull() {
+        try {
+            theInstance.track((File) null, new Object());
+            fail();
+        } catch (final NullPointerException ex) {
+            // expected
+        }
+        try {
+            theInstance.track((File) null, new Object(), FileDeleteStrategy.NORMAL);
+            fail();
+        } catch (final NullPointerException ex) {
+            // expected
+        }
+        try {
+            theInstance.track((String) null, new Object());
+            fail();
+        } catch (final NullPointerException ex) {
+            // expected
+        }
+        try {
+            theInstance.track((String) null, new Object(), FileDeleteStrategy.NORMAL);
+            fail();
+        } catch (final NullPointerException ex) {
+            // expected
         }
-        return "[Delete Failures: " + theInstance.deleteFailures.size() + "]";
     }
 
     private void waitUntilTrackCount() throws Exception {
diff --git a/src/test/java/org/apache/commons/io/FileDeleteStrategyTestCase.java b/src/test/java/org/apache/commons/io/FileDeleteStrategyTestCase.java
index b433f1e..a89a751 100644
--- a/src/test/java/org/apache/commons/io/FileDeleteStrategyTestCase.java
+++ b/src/test/java/org/apache/commons/io/FileDeleteStrategyTestCase.java
@@ -40,7 +40,7 @@ public class FileDeleteStrategyTestCase {
     public File temporaryFolder;
 
     @Test
-    public void testDeleteNormal() throws Exception {
+    public void testDeleteForce() throws Exception {
         final File baseDir = temporaryFolder;
         final File subDir = new File(baseDir, "test");
         assertTrue(subDir.mkdir());
@@ -57,28 +57,16 @@ public class FileDeleteStrategyTestCase {
         assertTrue(subDir.exists());
         assertTrue(subFile.exists());
         // delete dir
-        try {
-            FileDeleteStrategy.NORMAL.delete(subDir);
-            fail();
-        } catch (final IOException ex) {
-            // expected
-        }
-        assertTrue(subDir.exists());
-        assertTrue(subFile.exists());
-        // delete file
-        FileDeleteStrategy.NORMAL.delete(subFile);
-        assertTrue(subDir.exists());
-        assertFalse(subFile.exists());
-        // delete dir
-        FileDeleteStrategy.NORMAL.delete(subDir);
+        FileDeleteStrategy.FORCE.delete(subDir);
         assertFalse(subDir.exists());
+        assertFalse(subFile.exists());
         // delete dir
-        FileDeleteStrategy.NORMAL.delete(subDir);  // no error
+        FileDeleteStrategy.FORCE.delete(subDir);  // no error
         assertFalse(subDir.exists());
     }
 
     @Test
-    public void testDeleteQuietlyNormal() throws Exception {
+    public void testDeleteNormal() throws Exception {
         final File baseDir = temporaryFolder;
         final File subDir = new File(baseDir, "test");
         assertTrue(subDir.mkdir());
@@ -95,23 +83,39 @@ public class FileDeleteStrategyTestCase {
         assertTrue(subDir.exists());
         assertTrue(subFile.exists());
         // delete dir
-        assertFalse(FileDeleteStrategy.NORMAL.deleteQuietly(subDir));
+        try {
+            FileDeleteStrategy.NORMAL.delete(subDir);
+            fail();
+        } catch (final IOException ex) {
+            // expected
+        }
         assertTrue(subDir.exists());
         assertTrue(subFile.exists());
         // delete file
-        assertTrue(FileDeleteStrategy.NORMAL.deleteQuietly(subFile));
+        FileDeleteStrategy.NORMAL.delete(subFile);
         assertTrue(subDir.exists());
         assertFalse(subFile.exists());
         // delete dir
-        assertTrue(FileDeleteStrategy.NORMAL.deleteQuietly(subDir));
+        FileDeleteStrategy.NORMAL.delete(subDir);
         assertFalse(subDir.exists());
         // delete dir
-        assertTrue(FileDeleteStrategy.NORMAL.deleteQuietly(subDir));  // no error
+        FileDeleteStrategy.NORMAL.delete(subDir);  // no error
         assertFalse(subDir.exists());
     }
 
     @Test
-    public void testDeleteForce() throws Exception {
+    public void testDeleteNull() throws Exception {
+        try {
+            FileDeleteStrategy.NORMAL.delete(null);
+            fail();
+        } catch (final NullPointerException ex) {
+            // expected
+        }
+        assertTrue(FileDeleteStrategy.NORMAL.deleteQuietly(null));
+    }
+
+    @Test
+    public void testDeleteQuietlyNormal() throws Exception {
         final File baseDir = temporaryFolder;
         final File subDir = new File(baseDir, "test");
         assertTrue(subDir.mkdir());
@@ -128,23 +132,19 @@ public class FileDeleteStrategyTestCase {
         assertTrue(subDir.exists());
         assertTrue(subFile.exists());
         // delete dir
-        FileDeleteStrategy.FORCE.delete(subDir);
-        assertFalse(subDir.exists());
+        assertFalse(FileDeleteStrategy.NORMAL.deleteQuietly(subDir));
+        assertTrue(subDir.exists());
+        assertTrue(subFile.exists());
+        // delete file
+        assertTrue(FileDeleteStrategy.NORMAL.deleteQuietly(subFile));
+        assertTrue(subDir.exists());
         assertFalse(subFile.exists());
         // delete dir
-        FileDeleteStrategy.FORCE.delete(subDir);  // no error
+        assertTrue(FileDeleteStrategy.NORMAL.deleteQuietly(subDir));
+        assertFalse(subDir.exists());
+        // delete dir
+        assertTrue(FileDeleteStrategy.NORMAL.deleteQuietly(subDir));  // no error
         assertFalse(subDir.exists());
-    }
-
-    @Test
-    public void testDeleteNull() throws Exception {
-        try {
-            FileDeleteStrategy.NORMAL.delete(null);
-            fail();
-        } catch (final NullPointerException ex) {
-            // expected
-        }
-        assertTrue(FileDeleteStrategy.NORMAL.deleteQuietly(null));
     }
 
     @Test
diff --git a/src/test/java/org/apache/commons/io/FileSystemUtilsTestCase.java b/src/test/java/org/apache/commons/io/FileSystemUtilsTestCase.java
index 23681e2..bcc4b9c 100644
--- a/src/test/java/org/apache/commons/io/FileSystemUtilsTestCase.java
+++ b/src/test/java/org/apache/commons/io/FileSystemUtilsTestCase.java
@@ -40,6 +40,59 @@ import org.junit.jupiter.api.Test;
 @SuppressWarnings("deprecation") // testing deprecated class
 public class FileSystemUtilsTestCase {
 
+    static class MockFileSystemUtils extends FileSystemUtils {
+        private final int exitCode;
+        private final byte[] bytes;
+        private final String cmd;
+
+        public MockFileSystemUtils(final int exitCode, final String lines) {
+            this(exitCode, lines, null);
+        }
+
+        public MockFileSystemUtils(final int exitCode, final String lines, final String cmd) {
+            this.exitCode = exitCode;
+            this.bytes = lines.getBytes();
+            this.cmd = cmd;
+        }
+
+        @Override
+        Process openProcess(final String[] params) {
+            if (cmd != null) {
+                assertEquals(cmd, params[params.length - 1]);
+            }
+            return new Process() {
+                @Override
+                public void destroy() {
+                }
+
+                @Override
+                public int exitValue() {
+                    return exitCode;
+                }
+
+                @Override
+                public InputStream getErrorStream() {
+                    return null;
+                }
+
+                @Override
+                public InputStream getInputStream() {
+                    return new ByteArrayInputStream(bytes);
+                }
+
+                @Override
+                public OutputStream getOutputStream() {
+                    return null;
+                }
+
+                @Override
+                public int waitFor() throws InterruptedException {
+                    return exitCode;
+                }
+            };
+        }
+    }
+
     private static final Duration NEG_1_TIMEOUT = Duration.ofMillis(-1);
 
     @Test
@@ -92,32 +145,32 @@ public class FileSystemUtilsTestCase {
     }
 
     @Test
-    public void testGetFreeSpaceOS_String_NullPath() throws Exception {
+    public void testGetFreeSpaceOS_String_InitError() throws Exception {
         final FileSystemUtils fsu = new FileSystemUtils();
         try {
-            fsu.freeSpaceOS(null, 1, false, NEG_1_TIMEOUT);
+            fsu.freeSpaceOS("", -1, false, NEG_1_TIMEOUT);
             fail();
-        } catch (final IllegalArgumentException ignore) {
+        } catch (final IllegalStateException ignore) {
         }
         try {
-            fsu.freeSpaceOS(null, 1, true, NEG_1_TIMEOUT);
+            fsu.freeSpaceOS("", -1, true, NEG_1_TIMEOUT);
             fail();
-        } catch (final IllegalArgumentException ignore) {
+        } catch (final IllegalStateException ignore) {
         }
     }
 
     @Test
-    public void testGetFreeSpaceOS_String_InitError() throws Exception {
+    public void testGetFreeSpaceOS_String_NullPath() throws Exception {
         final FileSystemUtils fsu = new FileSystemUtils();
         try {
-            fsu.freeSpaceOS("", -1, false, NEG_1_TIMEOUT);
+            fsu.freeSpaceOS(null, 1, false, NEG_1_TIMEOUT);
             fail();
-        } catch (final IllegalStateException ignore) {
+        } catch (final IllegalArgumentException ignore) {
         }
         try {
-            fsu.freeSpaceOS("", -1, true, NEG_1_TIMEOUT);
+            fsu.freeSpaceOS(null, 1, true, NEG_1_TIMEOUT);
             fail();
-        } catch (final IllegalStateException ignore) {
+        } catch (final IllegalArgumentException ignore) {
         }
     }
 
@@ -137,233 +190,215 @@ public class FileSystemUtilsTestCase {
     }
 
     @Test
-    public void testGetFreeSpaceOS_String_Windows() throws Exception {
+    public void testGetFreeSpaceOS_String_Unix() throws Exception {
         final FileSystemUtils fsu = new FileSystemUtils() {
             @Override
-            protected long freeSpaceWindows(final String path, final Duration timeout) throws IOException {
-                return 12345L;
+            protected long freeSpaceUnix(final String path, final boolean kb, final boolean posix, final Duration timeout) throws IOException {
+                return kb ? 12345L : 54321;
             }
         };
-        assertEquals(12345L, fsu.freeSpaceOS("", 1, false, NEG_1_TIMEOUT));
-        assertEquals(12345L / 1024, fsu.freeSpaceOS("", 1, true, NEG_1_TIMEOUT));
+        assertEquals(54321L, fsu.freeSpaceOS("", 2, false, NEG_1_TIMEOUT));
+        assertEquals(12345L, fsu.freeSpaceOS("", 2, true, NEG_1_TIMEOUT));
     }
 
     @Test
-    public void testGetFreeSpaceOS_String_Unix() throws Exception {
+    public void testGetFreeSpaceOS_String_Windows() throws Exception {
         final FileSystemUtils fsu = new FileSystemUtils() {
             @Override
-            protected long freeSpaceUnix(final String path, final boolean kb, final boolean posix, final Duration timeout) throws IOException {
-                return kb ? 12345L : 54321;
+            protected long freeSpaceWindows(final String path, final Duration timeout) throws IOException {
+                return 12345L;
             }
         };
-        assertEquals(54321L, fsu.freeSpaceOS("", 2, false, NEG_1_TIMEOUT));
-        assertEquals(12345L, fsu.freeSpaceOS("", 2, true, NEG_1_TIMEOUT));
+        assertEquals(12345L, fsu.freeSpaceOS("", 1, false, NEG_1_TIMEOUT));
+        assertEquals(12345L / 1024, fsu.freeSpaceOS("", 1, true, NEG_1_TIMEOUT));
     }
 
     @Test
-    public void testGetFreeSpaceWindows_String_ParseCommaFormatBytes() throws Exception {
-        // this is the format of response when calling dir /c
-        // we have now switched to dir /-c, so we should never get this
+    public void testGetFreeSpaceUnix_String_EmptyPath() throws Exception {
         final String lines =
-                " Volume in drive C is HDD\n" +
-                        " Volume Serial Number is XXXX-YYYY\n" +
-                        "\n" +
-                        " Directory of C:\\Documents and Settings\\Xxxx\n" +
-                        "\n" +
-                        "19/08/2005  22:43    <DIR>          .\n" +
-                        "19/08/2005  22:43    <DIR>          ..\n" +
-                        "11/08/2005  01:07                81 build.properties\n" +
-                        "17/08/2005  21:44    <DIR>          Desktop\n" +
-                        "               7 File(s)        180,260 bytes\n" +
-                        "              10 Dir(s)  41,411,551,232 bytes free";
+                "Filesystem           1K-blocks      Used Available Use% Mounted on\n" +
+                        "xxx:/home/users/s     14428928  12956424   1472504  90% /home/users/s";
         final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
-        assertEquals(41411551232L, fsu.freeSpaceWindows("", NEG_1_TIMEOUT));
+        try {
+            fsu.freeSpaceUnix("", false, false, NEG_1_TIMEOUT);
+            fail();
+        } catch (final IllegalArgumentException ignore) {
+        }
+        try {
+            fsu.freeSpaceUnix("", true, false, NEG_1_TIMEOUT);
+            fail();
+        } catch (final IllegalArgumentException ignore) {
+        }
+        try {
+            fsu.freeSpaceUnix("", true, true, NEG_1_TIMEOUT);
+            fail();
+        } catch (final IllegalArgumentException ignore) {
+        }
+        try {
+            fsu.freeSpaceUnix("", false, true, NEG_1_TIMEOUT);
+            fail();
+        } catch (final IllegalArgumentException ignore) {
+        }
+
     }
 
     @Test
-    public void testGetFreeSpaceWindows_String_ParseCommaFormatBytes_Big() throws Exception {
-        // test with very large free space
-        final String lines =
-                " Volume in drive C is HDD\n" +
-                        " Volume Serial Number is XXXX-YYYY\n" +
-                        "\n" +
-                        " Directory of C:\\Documents and Settings\\Xxxx\n" +
-                        "\n" +
-                        "19/08/2005  22:43    <DIR>          .\n" +
-                        "19/08/2005  22:43    <DIR>          ..\n" +
-                        "11/08/2005  01:07                81 build.properties\n" +
-                        "17/08/2005  21:44    <DIR>          Desktop\n" +
-                        "               7 File(s)        180,260 bytes\n" +
-                        "              10 Dir(s)  141,411,551,232 bytes free";
+
+    public void testGetFreeSpaceUnix_String_EmptyResponse() {
+        final String lines = "";
         final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
-        assertEquals(141411551232L, fsu.freeSpaceWindows("", NEG_1_TIMEOUT));
+        try {
+            fsu.freeSpaceUnix("/home/users/s", false, false, NEG_1_TIMEOUT);
+            fail();
+        } catch (final IOException ignore) {
+        }
+        try {
+            fsu.freeSpaceUnix("/home/users/s", true, false, NEG_1_TIMEOUT);
+            fail();
+        } catch (final IOException ignore) {
+        }
+        try {
+            fsu.freeSpaceUnix("/home/users/s", false, true, NEG_1_TIMEOUT);
+            fail();
+        } catch (final IOException ignore) {
+        }
+        try {
+            fsu.freeSpaceUnix("/home/users/s", true, true, NEG_1_TIMEOUT);
+            fail();
+        } catch (final IOException ignore) {
+        }
     }
 
     @Test
-    public void testGetFreeSpaceWindows_String_ParseCommaFormatBytes_Small() throws Exception {
-        // test with very large free space
+    public void testGetFreeSpaceUnix_String_InvalidResponse1() {
         final String lines =
-                " Volume in drive C is HDD\n" +
-                        " Volume Serial Number is XXXX-YYYY\n" +
-                        "\n" +
-                        " Directory of C:\\Documents and Settings\\Xxxx\n" +
-                        "\n" +
-                        "19/08/2005  22:43    <DIR>          .\n" +
-                        "19/08/2005  22:43    <DIR>          ..\n" +
-                        "11/08/2005  01:07                81 build.properties\n" +
-                        "17/08/2005  21:44    <DIR>          Desktop\n" +
-                        "               7 File(s)        180,260 bytes\n" +
-                        "              10 Dir(s)  1,232 bytes free";
+                "Filesystem           1K-blocks      Used Available Use% Mounted on\n" +
+                        "                      14428928  12956424       100";
         final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
-        assertEquals(1232L, fsu.freeSpaceWindows("", NEG_1_TIMEOUT));
+        try {
+            fsu.freeSpaceUnix("/home/users/s", false, false, NEG_1_TIMEOUT);
+            fail();
+        } catch (final IOException ignore) {
+        }
+        try {
+            fsu.freeSpaceUnix("/home/users/s", true, false, NEG_1_TIMEOUT);
+            fail();
+        } catch (final IOException ignore) {
+        }
+        try {
+            fsu.freeSpaceUnix("/home/users/s", false, true, NEG_1_TIMEOUT);
+            fail();
+        } catch (final IOException ignore) {
+        }
+        try {
+            fsu.freeSpaceUnix("/home/users/s", true, true, NEG_1_TIMEOUT);
+            fail();
+        } catch (final IOException ignore) {
+        }
     }
 
     @Test
-    public void testGetFreeSpaceWindows_String_EmptyPath() throws Exception {
+    public void testGetFreeSpaceUnix_String_InvalidResponse2() {
         final String lines =
-                " Volume in drive C is HDD\n" +
-                        " Volume Serial Number is XXXX-YYYY\n" +
-                        "\n" +
-                        " Directory of C:\\Documents and Settings\\Xxxx\n" +
-                        "\n" +
-                        "19/08/2005  22:43    <DIR>          .\n" +
-                        "19/08/2005  22:43    <DIR>          ..\n" +
-                        "11/08/2005  01:07                81 build.properties\n" +
-                        "17/08/2005  21:44    <DIR>          Desktop\n" +
-                        "               7 File(s)         180260 bytes\n" +
-                        "              10 Dir(s)     41411551232 bytes free";
-        final FileSystemUtils fsu = new MockFileSystemUtils(0, lines, "dir /a /-c ");
-        assertEquals(41411551232L, fsu.freeSpaceWindows("", NEG_1_TIMEOUT));
+                "Filesystem           1K-blocks      Used Available Use% Mounted on\n" +
+                        "xxx:/home/users/s     14428928  12956424   nnnnnnn  90% /home/users/s";
+        final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
+        try {
+            fsu.freeSpaceUnix("/home/users/s", false, false, NEG_1_TIMEOUT);
+            fail();
+        } catch (final IOException ignore) {
+        }
+        try {
+            fsu.freeSpaceUnix("/home/users/s", true, false, NEG_1_TIMEOUT);
+            fail();
+        } catch (final IOException ignore) {
+        }
+        try {
+            fsu.freeSpaceUnix("/home/users/s", false, true, NEG_1_TIMEOUT);
+            fail();
+        } catch (final IOException ignore) {
+        }
+        try {
+            fsu.freeSpaceUnix("/home/users/s", true, true, NEG_1_TIMEOUT);
+            fail();
+        } catch (final IOException ignore) {
+        }
     }
 
     @Test
-    public void testGetFreeSpaceWindows_String_NormalResponse() throws Exception {
+    public void testGetFreeSpaceUnix_String_InvalidResponse3() {
         final String lines =
-                " Volume in drive C is HDD\n" +
-                        " Volume Serial Number is XXXX-YYYY\n" +
-                        "\n" +
-                        " Directory of C:\\Documents and Settings\\Xxxx\n" +
-                        "\n" +
-                        "19/08/2005  22:43    <DIR>          .\n" +
-                        "19/08/2005  22:43    <DIR>          ..\n" +
-                        "11/08/2005  01:07                81 build.properties\n" +
-                        "17/08/2005  21:44    <DIR>          Desktop\n" +
-                        "               7 File(s)         180260 bytes\n" +
-                        "              10 Dir(s)     41411551232 bytes free";
-        final FileSystemUtils fsu = new MockFileSystemUtils(0, lines, "dir /a /-c \"C:\"");
-        assertEquals(41411551232L, fsu.freeSpaceWindows("C:", NEG_1_TIMEOUT));
-    }
-
-    @Test
-    public void testGetFreeSpaceWindows_String_StripDrive() throws Exception {
-        final String lines =
-                " Volume in drive C is HDD\n" +
-                        " Volume Serial Number is XXXX-YYYY\n" +
-                        "\n" +
-                        " Directory of C:\\Documents and Settings\\Xxxx\n" +
-                        "\n" +
-                        "19/08/2005  22:43    <DIR>          .\n" +
-                        "19/08/2005  22:43    <DIR>          ..\n" +
-                        "11/08/2005  01:07                81 build.properties\n" +
-                        "17/08/2005  21:44    <DIR>          Desktop\n" +
-                        "               7 File(s)         180260 bytes\n" +
-                        "              10 Dir(s)     41411551232 bytes free";
-        final FileSystemUtils fsu = new MockFileSystemUtils(0, lines, "dir /a /-c \"C:\\somedir\"");
-        assertEquals(41411551232L, fsu.freeSpaceWindows("C:\\somedir", NEG_1_TIMEOUT));
-    }
-
-    @Test
-    public void testGetFreeSpaceWindows_String_quoted() throws Exception {
-        final String lines =
-                " Volume in drive C is HDD\n" +
-                        " Volume Serial Number is XXXX-YYYY\n" +
-                        "\n" +
-                        " Directory of C:\\Documents and Settings\\Xxxx\n" +
-                        "\n" +
-                        "19/08/2005  22:43    <DIR>          .\n" +
-                        "19/08/2005  22:43    <DIR>          ..\n" +
-                        "11/08/2005  01:07                81 build.properties\n" +
-                        "17/08/2005  21:44    <DIR>          Desktop\n" +
-                        "               7 File(s)         180260 bytes\n" +
-                        "              10 Dir(s)     41411551232 bytes free";
-        final FileSystemUtils fsu = new MockFileSystemUtils(0, lines, "dir /a /-c \"C:\\somedir\"");
-        assertEquals(41411551232L, fsu.freeSpaceWindows("\"C:\\somedir\"", NEG_1_TIMEOUT));
-    }
-
-    @Test
-    public void testGetFreeSpaceWindows_String_EmptyResponse() {
-        final String lines = "";
+                "Filesystem           1K-blocks      Used Available Use% Mounted on\n" +
+                        "xxx:/home/users/s     14428928  12956424        -1  90% /home/users/s";
         final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
         try {
-            fsu.freeSpaceWindows("C:", NEG_1_TIMEOUT);
+            fsu.freeSpaceUnix("/home/users/s", false, false, NEG_1_TIMEOUT);
+            fail();
+        } catch (final IOException ignore) {
+        }
+        try {
+            fsu.freeSpaceUnix("/home/users/s", true, false, NEG_1_TIMEOUT);
+            fail();
+        } catch (final IOException ignore) {
+        }
+        try {
+            fsu.freeSpaceUnix("/home/users/s", false, true, NEG_1_TIMEOUT);
+            fail();
+        } catch (final IOException ignore) {
+        }
+        try {
+            fsu.freeSpaceUnix("/home/users/s", true, true, NEG_1_TIMEOUT);
             fail();
         } catch (final IOException ignore) {
         }
     }
 
     @Test
-    public void testGetFreeSpaceWindows_String_EmptyMultiLineResponse() {
-        final String lines = "\n\n";
-        final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
-        assertThrows(IOException.class, () -> fsu.freeSpaceWindows("C:", NEG_1_TIMEOUT));
-    }
-
-    @Test
-    public void testGetFreeSpaceWindows_String_InvalidTextResponse() {
-        final String lines = "BlueScreenOfDeath";
-        final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
-        assertThrows(IOException.class, () -> fsu.freeSpaceWindows("C:", NEG_1_TIMEOUT));
-    }
-
-    @Test
-    public void testGetFreeSpaceWindows_String_NoSuchDirectoryResponse() {
-        final String lines =
-                " Volume in drive C is HDD\n" +
-                        " Volume Serial Number is XXXX-YYYY\n" +
-                        "\n" +
-                        " Directory of C:\\Documents and Settings\\empty" +
-                        "\n";
-        final FileSystemUtils fsu = new MockFileSystemUtils(1, lines);
-        assertThrows(IOException.class, () -> fsu.freeSpaceWindows("C:", NEG_1_TIMEOUT));
-    }
-
-    @Test
-    public void testGetFreeSpaceUnix_String_EmptyPath() throws Exception {
+    public void testGetFreeSpaceUnix_String_InvalidResponse4() {
         final String lines =
                 "Filesystem           1K-blocks      Used Available Use% Mounted on\n" +
-                        "xxx:/home/users/s     14428928  12956424   1472504  90% /home/users/s";
+                        "xxx-yyyyyyy-zzz:/home/users/s";
         final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
         try {
-            fsu.freeSpaceUnix("", false, false, NEG_1_TIMEOUT);
+            fsu.freeSpaceUnix("/home/users/s", false, false, NEG_1_TIMEOUT);
             fail();
-        } catch (final IllegalArgumentException ignore) {
+        } catch (final IOException ignore) {
         }
         try {
-            fsu.freeSpaceUnix("", true, false, NEG_1_TIMEOUT);
+            fsu.freeSpaceUnix("/home/users/s", true, false, NEG_1_TIMEOUT);
             fail();
-        } catch (final IllegalArgumentException ignore) {
+        } catch (final IOException ignore) {
         }
         try {
-            fsu.freeSpaceUnix("", true, true, NEG_1_TIMEOUT);
+            fsu.freeSpaceUnix("/home/users/s", false, true, NEG_1_TIMEOUT);
             fail();
-        } catch (final IllegalArgumentException ignore) {
+        } catch (final IOException ignore) {
         }
         try {
-            fsu.freeSpaceUnix("", false, true, NEG_1_TIMEOUT);
+            fsu.freeSpaceUnix("/home/users/s", true, true, NEG_1_TIMEOUT);
             fail();
-        } catch (final IllegalArgumentException ignore) {
+        } catch (final IOException ignore) {
         }
+    }
 
+    @Test
+    public void testGetFreeSpaceUnix_String_LongResponse() throws Exception {
+        final String lines =
+                "Filesystem           1K-blocks      Used Available Use% Mounted on\n" +
+                        "xxx-yyyyyyy-zzz:/home/users/s\n" +
+                        "                      14428928  12956424   1472504  90% /home/users/s";
+        final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
+        assertEquals(1472504L, fsu.freeSpaceUnix("/home/users/s", false, false, NEG_1_TIMEOUT));
     }
 
     @Test
-    public void testGetFreeSpaceUnix_String_NormalResponseLinux() throws Exception {
-        // from Sourceforge 'GNU bash, version 2.05b.0(1)-release (i386-redhat-linux-gnu)'
+    public void testGetFreeSpaceUnix_String_LongResponseKb() throws Exception {
         final String lines =
                 "Filesystem           1K-blocks      Used Available Use% Mounted on\n" +
-                        "/dev/xxx                497944    308528    189416  62% /";
+                        "xxx-yyyyyyy-zzz:/home/users/s\n" +
+                        "                      14428928  12956424   1472504  90% /home/users/s";
         final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
-        assertEquals(189416L, fsu.freeSpaceUnix("/", false, false, NEG_1_TIMEOUT));
+        assertEquals(1472504L, fsu.freeSpaceUnix("/home/users/s", true, false, NEG_1_TIMEOUT));
     }
 
     @Test
@@ -377,17 +412,6 @@ public class FileSystemUtilsTestCase {
     }
 
     @Test
-    public void testGetFreeSpaceUnix_String_NormalResponseKbLinux() throws Exception {
-        // from Sourceforge 'GNU bash, version 2.05b.0(1)-release (i386-redhat-linux-gnu)'
-        // df, df -k and df -kP are all identical
-        final String lines =
-                "Filesystem           1K-blocks      Used Available Use% Mounted on\n" +
-                        "/dev/xxx                497944    308528    189416  62% /";
-        final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
-        assertEquals(189416L, fsu.freeSpaceUnix("/", true, false, NEG_1_TIMEOUT));
-    }
-
-    @Test
     public void testGetFreeSpaceUnix_String_NormalResponseKbFreeBSD() throws Exception {
         // from Apache 'FreeBSD 6.1-RELEASE (SMP-turbo)'
         // df and df -k are identical, but df -kP uses 512 blocks (not relevant as not used)
@@ -399,6 +423,17 @@ public class FileSystemUtilsTestCase {
     }
 
     @Test
+    public void testGetFreeSpaceUnix_String_NormalResponseKbLinux() throws Exception {
+        // from Sourceforge 'GNU bash, version 2.05b.0(1)-release (i386-redhat-linux-gnu)'
+        // df, df -k and df -kP are all identical
+        final String lines =
+                "Filesystem           1K-blocks      Used Available Use% Mounted on\n" +
+                        "/dev/xxx                497944    308528    189416  62% /";
+        final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
+        assertEquals(189416L, fsu.freeSpaceUnix("/", true, false, NEG_1_TIMEOUT));
+    }
+
+    @Test
     public void testGetFreeSpaceUnix_String_NormalResponseKbSolaris() throws Exception {
         // from IO-91 - ' SunOS et 5.10 Generic_118822-25 sun4u sparc SUNW,Ultra-4'
         // non-kb response does not contain free space - see IO-91
@@ -410,214 +445,179 @@ public class FileSystemUtilsTestCase {
     }
 
     @Test
-    public void testGetFreeSpaceUnix_String_LongResponse() throws Exception {
+    public void testGetFreeSpaceUnix_String_NormalResponseLinux() throws Exception {
+        // from Sourceforge 'GNU bash, version 2.05b.0(1)-release (i386-redhat-linux-gnu)'
         final String lines =
                 "Filesystem           1K-blocks      Used Available Use% Mounted on\n" +
-                        "xxx-yyyyyyy-zzz:/home/users/s\n" +
-                        "                      14428928  12956424   1472504  90% /home/users/s";
+                        "/dev/xxx                497944    308528    189416  62% /";
         final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
-        assertEquals(1472504L, fsu.freeSpaceUnix("/home/users/s", false, false, NEG_1_TIMEOUT));
+        assertEquals(189416L, fsu.freeSpaceUnix("/", false, false, NEG_1_TIMEOUT));
     }
 
     @Test
-    public void testGetFreeSpaceUnix_String_LongResponseKb() throws Exception {
-        final String lines =
-                "Filesystem           1K-blocks      Used Available Use% Mounted on\n" +
-                        "xxx-yyyyyyy-zzz:/home/users/s\n" +
-                        "                      14428928  12956424   1472504  90% /home/users/s";
+    public void testGetFreeSpaceWindows_String_EmptyMultiLineResponse() {
+        final String lines = "\n\n";
         final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
-        assertEquals(1472504L, fsu.freeSpaceUnix("/home/users/s", true, false, NEG_1_TIMEOUT));
+        assertThrows(IOException.class, () -> fsu.freeSpaceWindows("C:", NEG_1_TIMEOUT));
     }
+
     @Test
+    public void testGetFreeSpaceWindows_String_EmptyPath() throws Exception {
+        final String lines =
+                " Volume in drive C is HDD\n" +
+                        " Volume Serial Number is XXXX-YYYY\n" +
+                        "\n" +
+                        " Directory of C:\\Documents and Settings\\Xxxx\n" +
+                        "\n" +
+                        "19/08/2005  22:43    <DIR>          .\n" +
+                        "19/08/2005  22:43    <DIR>          ..\n" +
+                        "11/08/2005  01:07                81 build.properties\n" +
+                        "17/08/2005  21:44    <DIR>          Desktop\n" +
+                        "               7 File(s)         180260 bytes\n" +
+                        "              10 Dir(s)     41411551232 bytes free";
+        final FileSystemUtils fsu = new MockFileSystemUtils(0, lines, "dir /a /-c ");
+        assertEquals(41411551232L, fsu.freeSpaceWindows("", NEG_1_TIMEOUT));
+    }
 
-    public void testGetFreeSpaceUnix_String_EmptyResponse() {
+    @Test
+    public void testGetFreeSpaceWindows_String_EmptyResponse() {
         final String lines = "";
         final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
         try {
-            fsu.freeSpaceUnix("/home/users/s", false, false, NEG_1_TIMEOUT);
-            fail();
-        } catch (final IOException ignore) {
-        }
-        try {
-            fsu.freeSpaceUnix("/home/users/s", true, false, NEG_1_TIMEOUT);
-            fail();
-        } catch (final IOException ignore) {
-        }
-        try {
-            fsu.freeSpaceUnix("/home/users/s", false, true, NEG_1_TIMEOUT);
-            fail();
-        } catch (final IOException ignore) {
-        }
-        try {
-            fsu.freeSpaceUnix("/home/users/s", true, true, NEG_1_TIMEOUT);
+            fsu.freeSpaceWindows("C:", NEG_1_TIMEOUT);
             fail();
         } catch (final IOException ignore) {
         }
     }
 
     @Test
-    public void testGetFreeSpaceUnix_String_InvalidResponse1() {
-        final String lines =
-                "Filesystem           1K-blocks      Used Available Use% Mounted on\n" +
-                        "                      14428928  12956424       100";
+    public void testGetFreeSpaceWindows_String_InvalidTextResponse() {
+        final String lines = "BlueScreenOfDeath";
         final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
-        try {
-            fsu.freeSpaceUnix("/home/users/s", false, false, NEG_1_TIMEOUT);
-            fail();
-        } catch (final IOException ignore) {
-        }
-        try {
-            fsu.freeSpaceUnix("/home/users/s", true, false, NEG_1_TIMEOUT);
-            fail();
-        } catch (final IOException ignore) {
-        }
-        try {
-            fsu.freeSpaceUnix("/home/users/s", false, true, NEG_1_TIMEOUT);
-            fail();
-        } catch (final IOException ignore) {
-        }
-        try {
-            fsu.freeSpaceUnix("/home/users/s", true, true, NEG_1_TIMEOUT);
-            fail();
-        } catch (final IOException ignore) {
-        }
+        assertThrows(IOException.class, () -> fsu.freeSpaceWindows("C:", NEG_1_TIMEOUT));
     }
 
     @Test
-    public void testGetFreeSpaceUnix_String_InvalidResponse2() {
+    public void testGetFreeSpaceWindows_String_NormalResponse() throws Exception {
         final String lines =
-                "Filesystem           1K-blocks      Used Available Use% Mounted on\n" +
-                        "xxx:/home/users/s     14428928  12956424   nnnnnnn  90% /home/users/s";
-        final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
-        try {
-            fsu.freeSpaceUnix("/home/users/s", false, false, NEG_1_TIMEOUT);
-            fail();
-        } catch (final IOException ignore) {
-        }
-        try {
-            fsu.freeSpaceUnix("/home/users/s", true, false, NEG_1_TIMEOUT);
-            fail();
-        } catch (final IOException ignore) {
-        }
-        try {
-            fsu.freeSpaceUnix("/home/users/s", false, true, NEG_1_TIMEOUT);
-            fail();
-        } catch (final IOException ignore) {
-        }
-        try {
-            fsu.freeSpaceUnix("/home/users/s", true, true, NEG_1_TIMEOUT);
-            fail();
-        } catch (final IOException ignore) {
-        }
+                " Volume in drive C is HDD\n" +
+                        " Volume Serial Number is XXXX-YYYY\n" +
+                        "\n" +
+                        " Directory of C:\\Documents and Settings\\Xxxx\n" +
+                        "\n" +
+                        "19/08/2005  22:43    <DIR>          .\n" +
+                        "19/08/2005  22:43    <DIR>          ..\n" +
+                        "11/08/2005  01:07                81 build.properties\n" +
+                        "17/08/2005  21:44    <DIR>          Desktop\n" +
+                        "               7 File(s)         180260 bytes\n" +
+                        "              10 Dir(s)     41411551232 bytes free";
+        final FileSystemUtils fsu = new MockFileSystemUtils(0, lines, "dir /a /-c \"C:\"");
+        assertEquals(41411551232L, fsu.freeSpaceWindows("C:", NEG_1_TIMEOUT));
+    }
+    @Test
+    public void testGetFreeSpaceWindows_String_NoSuchDirectoryResponse() {
+        final String lines =
+                " Volume in drive C is HDD\n" +
+                        " Volume Serial Number is XXXX-YYYY\n" +
+                        "\n" +
+                        " Directory of C:\\Documents and Settings\\empty" +
+                        "\n";
+        final FileSystemUtils fsu = new MockFileSystemUtils(1, lines);
+        assertThrows(IOException.class, () -> fsu.freeSpaceWindows("C:", NEG_1_TIMEOUT));
     }
 
     @Test
-    public void testGetFreeSpaceUnix_String_InvalidResponse3() {
+    public void testGetFreeSpaceWindows_String_ParseCommaFormatBytes() throws Exception {
+        // this is the format of response when calling dir /c
+        // we have now switched to dir /-c, so we should never get this
         final String lines =
-                "Filesystem           1K-blocks      Used Available Use% Mounted on\n" +
-                        "xxx:/home/users/s     14428928  12956424        -1  90% /home/users/s";
+                " Volume in drive C is HDD\n" +
+                        " Volume Serial Number is XXXX-YYYY\n" +
+                        "\n" +
+                        " Directory of C:\\Documents and Settings\\Xxxx\n" +
+                        "\n" +
+                        "19/08/2005  22:43    <DIR>          .\n" +
+                        "19/08/2005  22:43    <DIR>          ..\n" +
+                        "11/08/2005  01:07                81 build.properties\n" +
+                        "17/08/2005  21:44    <DIR>          Desktop\n" +
+                        "               7 File(s)        180,260 bytes\n" +
+                        "              10 Dir(s)  41,411,551,232 bytes free";
         final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
-        try {
-            fsu.freeSpaceUnix("/home/users/s", false, false, NEG_1_TIMEOUT);
-            fail();
-        } catch (final IOException ignore) {
-        }
-        try {
-            fsu.freeSpaceUnix("/home/users/s", true, false, NEG_1_TIMEOUT);
-            fail();
-        } catch (final IOException ignore) {
-        }
-        try {
-            fsu.freeSpaceUnix("/home/users/s", false, true, NEG_1_TIMEOUT);
-            fail();
-        } catch (final IOException ignore) {
-        }
-        try {
-            fsu.freeSpaceUnix("/home/users/s", true, true, NEG_1_TIMEOUT);
-            fail();
-        } catch (final IOException ignore) {
-        }
+        assertEquals(41411551232L, fsu.freeSpaceWindows("", NEG_1_TIMEOUT));
     }
 
     @Test
-    public void testGetFreeSpaceUnix_String_InvalidResponse4() {
+    public void testGetFreeSpaceWindows_String_ParseCommaFormatBytes_Big() throws Exception {
+        // test with very large free space
         final String lines =
-                "Filesystem           1K-blocks      Used Available Use% Mounted on\n" +
-                        "xxx-yyyyyyy-zzz:/home/users/s";
+                " Volume in drive C is HDD\n" +
+                        " Volume Serial Number is XXXX-YYYY\n" +
+                        "\n" +
+                        " Directory of C:\\Documents and Settings\\Xxxx\n" +
+                        "\n" +
+                        "19/08/2005  22:43    <DIR>          .\n" +
+                        "19/08/2005  22:43    <DIR>          ..\n" +
+                        "11/08/2005  01:07                81 build.properties\n" +
+                        "17/08/2005  21:44    <DIR>          Desktop\n" +
+                        "               7 File(s)        180,260 bytes\n" +
+                        "              10 Dir(s)  141,411,551,232 bytes free";
         final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
-        try {
-            fsu.freeSpaceUnix("/home/users/s", false, false, NEG_1_TIMEOUT);
-            fail();
-        } catch (final IOException ignore) {
-        }
-        try {
-            fsu.freeSpaceUnix("/home/users/s", true, false, NEG_1_TIMEOUT);
-            fail();
-        } catch (final IOException ignore) {
-        }
-        try {
-            fsu.freeSpaceUnix("/home/users/s", false, true, NEG_1_TIMEOUT);
-            fail();
-        } catch (final IOException ignore) {
-        }
-        try {
-            fsu.freeSpaceUnix("/home/users/s", true, true, NEG_1_TIMEOUT);
-            fail();
-        } catch (final IOException ignore) {
-        }
+        assertEquals(141411551232L, fsu.freeSpaceWindows("", NEG_1_TIMEOUT));
     }
 
-    static class MockFileSystemUtils extends FileSystemUtils {
-        private final int exitCode;
-        private final byte[] bytes;
-        private final String cmd;
-
-        public MockFileSystemUtils(final int exitCode, final String lines) {
-            this(exitCode, lines, null);
-        }
-
-        public MockFileSystemUtils(final int exitCode, final String lines, final String cmd) {
-            this.exitCode = exitCode;
-            this.bytes = lines.getBytes();
-            this.cmd = cmd;
-        }
-
-        @Override
-        Process openProcess(final String[] params) {
-            if (cmd != null) {
-                assertEquals(cmd, params[params.length - 1]);
-            }
-            return new Process() {
-                @Override
-                public InputStream getErrorStream() {
-                    return null;
-                }
-
-                @Override
-                public InputStream getInputStream() {
-                    return new ByteArrayInputStream(bytes);
-                }
-
-                @Override
-                public OutputStream getOutputStream() {
-                    return null;
-                }
-
-                @Override
-                public int waitFor() throws InterruptedException {
-                    return exitCode;
-                }
+    @Test
+    public void testGetFreeSpaceWindows_String_ParseCommaFormatBytes_Small() throws Exception {
+        // test with very large free space
+        final String lines =
+                " Volume in drive C is HDD\n" +
+                        " Volume Serial Number is XXXX-YYYY\n" +
+                        "\n" +
+                        " Directory of C:\\Documents and Settings\\Xxxx\n" +
+                        "\n" +
+                        "19/08/2005  22:43    <DIR>          .\n" +
+                        "19/08/2005  22:43    <DIR>          ..\n" +
+                        "11/08/2005  01:07                81 build.properties\n" +
+                        "17/08/2005  21:44    <DIR>          Desktop\n" +
+                        "               7 File(s)        180,260 bytes\n" +
+                        "              10 Dir(s)  1,232 bytes free";
+        final FileSystemUtils fsu = new MockFileSystemUtils(0, lines);
+        assertEquals(1232L, fsu.freeSpaceWindows("", NEG_1_TIMEOUT));
+    }
 
-                @Override
-                public int exitValue() {
-                    return exitCode;
-                }
+    @Test
+    public void testGetFreeSpaceWindows_String_quoted() throws Exception {
+        final String lines =
+                " Volume in drive C is HDD\n" +
+                        " Volume Serial Number is XXXX-YYYY\n" +
+                        "\n" +
+                        " Directory of C:\\Documents and Settings\\Xxxx\n" +
+                        "\n" +
+                        "19/08/2005  22:43    <DIR>          .\n" +
+                        "19/08/2005  22:43    <DIR>          ..\n" +
+                        "11/08/2005  01:07                81 build.properties\n" +
+                        "17/08/2005  21:44    <DIR>          Desktop\n" +
+                        "               7 File(s)         180260 bytes\n" +
+                        "              10 Dir(s)     41411551232 bytes free";
+        final FileSystemUtils fsu = new MockFileSystemUtils(0, lines, "dir /a /-c \"C:\\somedir\"");
+        assertEquals(41411551232L, fsu.freeSpaceWindows("\"C:\\somedir\"", NEG_1_TIMEOUT));
+    }
 
-                @Override
-                public void destroy() {
-                }
-            };
-        }
+    @Test
+    public void testGetFreeSpaceWindows_String_StripDrive() throws Exception {
+        final String lines =
+                " Volume in drive C is HDD\n" +
+                        " Volume Serial Number is XXXX-YYYY\n" +
+                        "\n" +
+                        " Directory of C:\\Documents and Settings\\Xxxx\n" +
+                        "\n" +
+                        "19/08/2005  22:43    <DIR>          .\n" +
+                        "19/08/2005  22:43    <DIR>          ..\n" +
+                        "11/08/2005  01:07                81 build.properties\n" +
+                        "17/08/2005  21:44    <DIR>          Desktop\n" +
+                        "               7 File(s)         180260 bytes\n" +
+                        "              10 Dir(s)     41411551232 bytes free";
+        final FileSystemUtils fsu = new MockFileSystemUtils(0, lines, "dir /a /-c \"C:\\somedir\"");
+        assertEquals(41411551232L, fsu.freeSpaceWindows("C:\\somedir", NEG_1_TIMEOUT));
     }
 
 }
diff --git a/src/test/java/org/apache/commons/io/FileUtilsCleanDirectoryTestCase.java b/src/test/java/org/apache/commons/io/FileUtilsCleanDirectoryTestCase.java
index 1ab9737..893eb63 100644
--- a/src/test/java/org/apache/commons/io/FileUtilsCleanDirectoryTestCase.java
+++ b/src/test/java/org/apache/commons/io/FileUtilsCleanDirectoryTestCase.java
@@ -43,22 +43,32 @@ public class FileUtilsCleanDirectoryTestCase {
     @TempDir
     public File top;
 
-    // -----------------------------------------------------------------------
-    @Test
-    public void testCleanEmpty() throws Exception {
-        assertEquals(0, top.list().length);
+    /** Only runs on Linux. */
+    private boolean chmod(final File file, final int mode, final boolean recurse) throws InterruptedException {
+        final List<String> args = new ArrayList<>();
+        args.add("chmod");
 
-        FileUtils.cleanDirectory(top);
+        if (recurse) {
+            args.add("-R");
+        }
 
-        assertEquals(0, top.list().length);
+        args.add(Integer.toString(mode));
+        args.add(file.getAbsolutePath());
+
+        final Process proc;
+
+        try {
+            proc = Runtime.getRuntime().exec(args.toArray(new String[args.size()]));
+        } catch (final IOException e) {
+            return false;
+        }
+        return proc.waitFor() == 0;
     }
 
+    // -----------------------------------------------------------------------
     @Test
-    public void testDeletesRegular() throws Exception {
-        FileUtils.touch(new File(top, "regular"));
-        FileUtils.touch(new File(top, ".hidden"));
-
-        assertEquals(2, top.list().length);
+    public void testCleanEmpty() throws Exception {
+        assertEquals(0, top.list().length);
 
         FileUtils.cleanDirectory(top);
 
@@ -80,22 +90,16 @@ public class FileUtilsCleanDirectoryTestCase {
         assertEquals(0, top.list().length);
     }
 
-    @DisabledOnOs(OS.WINDOWS)
     @Test
-    public void testThrowsOnNullList() throws Exception {
-        // test wont work if we can't restrict permissions on the
-        // directory, so skip it.
-        assumeTrue(chmod(top, 0, false));
+    public void testDeletesRegular() throws Exception {
+        FileUtils.touch(new File(top, "regular"));
+        FileUtils.touch(new File(top, ".hidden"));
 
-        try {
-            // cleanDirectory calls forceDelete
-            FileUtils.cleanDirectory(top);
-            fail("expected IOException");
-        } catch (final IOException e) {
-            assertEquals("Unknown I/O error listing contents of directory: " + top.getAbsolutePath(), e.getMessage());
-        } finally {
-            chmod(top, 755, false);
-        }
+        assertEquals(2, top.list().length);
+
+        FileUtils.cleanDirectory(top);
+
+        assertEquals(0, top.list().length);
     }
 
     @DisabledOnOs(OS.WINDOWS)
@@ -118,26 +122,22 @@ public class FileUtilsCleanDirectoryTestCase {
         }
     }
 
-    /** Only runs on Linux. */
-    private boolean chmod(final File file, final int mode, final boolean recurse) throws InterruptedException {
-        final List<String> args = new ArrayList<>();
-        args.add("chmod");
-
-        if (recurse) {
-            args.add("-R");
-        }
-
-        args.add(Integer.toString(mode));
-        args.add(file.getAbsolutePath());
-
-        final Process proc;
+    @DisabledOnOs(OS.WINDOWS)
+    @Test
+    public void testThrowsOnNullList() throws Exception {
+        // test wont work if we can't restrict permissions on the
+        // directory, so skip it.
+        assumeTrue(chmod(top, 0, false));
 
         try {
-            proc = Runtime.getRuntime().exec(args.toArray(new String[args.size()]));
+            // cleanDirectory calls forceDelete
+            FileUtils.cleanDirectory(top);
+            fail("expected IOException");
         } catch (final IOException e) {
-            return false;
+            assertEquals("Unknown I/O error listing contents of directory: " + top.getAbsolutePath(), e.getMessage());
+        } finally {
+            chmod(top, 755, false);
         }
-        return proc.waitFor() == 0;
     }
 
 }
diff --git a/src/test/java/org/apache/commons/io/FileUtilsCleanSymlinksTestCase.java b/src/test/java/org/apache/commons/io/FileUtilsCleanSymlinksTestCase.java
index bb2c146..f557035 100644
--- a/src/test/java/org/apache/commons/io/FileUtilsCleanSymlinksTestCase.java
+++ b/src/test/java/org/apache/commons/io/FileUtilsCleanSymlinksTestCase.java
@@ -36,38 +36,19 @@ public class FileUtilsCleanSymlinksTestCase {
     @TempDir
     public File top;
 
-    @Test
-    public void testCleanDirWithSymlinkFile() throws Exception {
-        if (System.getProperty("os.name").startsWith("Win")) {
-            // Can't use "ln" for symlinks on the command line in Windows.
-            return;
-        }
-
-        final File realOuter = new File(top, "realouter");
-        assertTrue(realOuter.mkdirs());
-
-        final File realInner = new File(realOuter, "realinner");
-        assertTrue(realInner.mkdirs());
-
-        final File realFile = new File(realInner, "file1");
-        FileUtils.touch(realFile);
-        assertEquals(1, realInner.list().length);
-
-        final File randomFile = new File(top, "randomfile");
-        FileUtils.touch(randomFile);
-
-        final File symlinkFile = new File(realInner, "fakeinner");
-        assertTrue(setupSymlink(randomFile, symlinkFile));
+    private boolean setupSymlink(final File res, final File link) throws Exception {
+        // create symlink
+        final List<String> args = new ArrayList<>();
+        args.add("ln");
+        args.add("-s");
 
-        assertEquals(2, realInner.list().length);
+        args.add(res.getAbsolutePath());
+        args.add(link.getAbsolutePath());
 
-        // assert contents of the real directory were removed including the symlink
-        FileUtils.cleanDirectory(realOuter);
-        assertEquals(0, realOuter.list().length);
+        final Process proc;
 
-        // ensure that the contents of the symlink were NOT removed.
-        assertTrue(randomFile.exists());
-        assertFalse(symlinkFile.exists());
+        proc = Runtime.getRuntime().exec(args.toArray(new String[args.size()]));
+        return proc.waitFor() == 0;
     }
 
 
@@ -146,59 +127,61 @@ public class FileUtilsCleanSymlinksTestCase {
     }
 
     @Test
-    public void testStillClearsIfGivenDirectoryIsASymlink() throws Exception {
+    public void testCleanDirWithSymlinkFile() throws Exception {
         if (System.getProperty("os.name").startsWith("Win")) {
             // Can't use "ln" for symlinks on the command line in Windows.
             return;
         }
 
-        final File randomDirectory = new File(top, "randomDir");
-        assertTrue(randomDirectory.mkdirs());
-
-        FileUtils.touch(new File(randomDirectory, "randomfile"));
-        assertEquals(1, randomDirectory.list().length);
+        final File realOuter = new File(top, "realouter");
+        assertTrue(realOuter.mkdirs());
 
-        final File symlinkDirectory = new File(top, "fakeDir");
-        assertTrue(setupSymlink(randomDirectory, symlinkDirectory));
+        final File realInner = new File(realOuter, "realinner");
+        assertTrue(realInner.mkdirs());
 
-        FileUtils.cleanDirectory(symlinkDirectory);
-        assertEquals(0, symlinkDirectory.list().length);
-        assertEquals(0, randomDirectory.list().length);
-    }
+        final File realFile = new File(realInner, "file1");
+        FileUtils.touch(realFile);
+        assertEquals(1, realInner.list().length);
 
+        final File randomFile = new File(top, "randomfile");
+        FileUtils.touch(randomFile);
 
-    @Test
-    public void testIdentifiesSymlinkDir() throws Exception {
-        if (System.getProperty("os.name").startsWith("Win")) {
-            // Can't use "ln" for symlinks on the command line in Windows.
-            return;
-        }
+        final File symlinkFile = new File(realInner, "fakeinner");
+        assertTrue(setupSymlink(randomFile, symlinkFile));
 
-        final File randomDirectory = new File(top, "randomDir");
-        assertTrue(randomDirectory.mkdirs());
+        assertEquals(2, realInner.list().length);
 
-        final File symlinkDirectory = new File(top, "fakeDir");
-        assertTrue(setupSymlink(randomDirectory, symlinkDirectory));
+        // assert contents of the real directory were removed including the symlink
+        FileUtils.cleanDirectory(realOuter);
+        assertEquals(0, realOuter.list().length);
 
-        assertTrue(FileUtils.isSymlink(symlinkDirectory));
-        assertFalse(FileUtils.isSymlink(randomDirectory));
+        // ensure that the contents of the symlink were NOT removed.
+        assertTrue(randomFile.exists());
+        assertFalse(symlinkFile.exists());
     }
 
+
     @Test
-    public void testIdentifiesSymlinkFile() throws Exception {
+    public void testCorrectlyIdentifySymlinkWithParentSymLink() throws Exception {
         if (System.getProperty("os.name").startsWith("Win")) {
             // Can't use "ln" for symlinks on the command line in Windows.
             return;
         }
 
-        final File randomFile = new File(top, "randomfile");
-        FileUtils.touch(randomFile);
+        final File realParent = new File(top, "realparent");
+        assertTrue(realParent.mkdirs());
 
-        final File symlinkFile = new File(top, "fakeinner");
-        assertTrue(setupSymlink(randomFile, symlinkFile));
+        final File symlinkParentDirectory = new File(top, "fakeparent");
+        assertTrue(setupSymlink(realParent, symlinkParentDirectory));
 
-        assertTrue(FileUtils.isSymlink(symlinkFile));
-        assertFalse(FileUtils.isSymlink(randomFile));
+        final File realChild = new File(symlinkParentDirectory, "realChild");
+        assertTrue(realChild.mkdirs());
+
+        final File symlinkChild = new File(symlinkParentDirectory, "fakeChild");
+        assertTrue(setupSymlink(realChild, symlinkChild));
+
+        assertTrue(FileUtils.isSymlink(symlinkChild));
+        assertFalse(FileUtils.isSymlink(realChild));
     }
 
     @Test
@@ -222,41 +205,58 @@ public class FileUtilsCleanSymlinksTestCase {
     }
 
     @Test
-    public void testCorrectlyIdentifySymlinkWithParentSymLink() throws Exception {
+    public void testIdentifiesSymlinkDir() throws Exception {
         if (System.getProperty("os.name").startsWith("Win")) {
             // Can't use "ln" for symlinks on the command line in Windows.
             return;
         }
 
-        final File realParent = new File(top, "realparent");
-        assertTrue(realParent.mkdirs());
+        final File randomDirectory = new File(top, "randomDir");
+        assertTrue(randomDirectory.mkdirs());
 
-        final File symlinkParentDirectory = new File(top, "fakeparent");
-        assertTrue(setupSymlink(realParent, symlinkParentDirectory));
+        final File symlinkDirectory = new File(top, "fakeDir");
+        assertTrue(setupSymlink(randomDirectory, symlinkDirectory));
 
-        final File realChild = new File(symlinkParentDirectory, "realChild");
-        assertTrue(realChild.mkdirs());
+        assertTrue(FileUtils.isSymlink(symlinkDirectory));
+        assertFalse(FileUtils.isSymlink(randomDirectory));
+    }
 
-        final File symlinkChild = new File(symlinkParentDirectory, "fakeChild");
-        assertTrue(setupSymlink(realChild, symlinkChild));
+    @Test
+    public void testIdentifiesSymlinkFile() throws Exception {
+        if (System.getProperty("os.name").startsWith("Win")) {
+            // Can't use "ln" for symlinks on the command line in Windows.
+            return;
+        }
 
-        assertTrue(FileUtils.isSymlink(symlinkChild));
-        assertFalse(FileUtils.isSymlink(realChild));
+        final File randomFile = new File(top, "randomfile");
+        FileUtils.touch(randomFile);
+
+        final File symlinkFile = new File(top, "fakeinner");
+        assertTrue(setupSymlink(randomFile, symlinkFile));
+
+        assertTrue(FileUtils.isSymlink(symlinkFile));
+        assertFalse(FileUtils.isSymlink(randomFile));
     }
 
-    private boolean setupSymlink(final File res, final File link) throws Exception {
-        // create symlink
-        final List<String> args = new ArrayList<>();
-        args.add("ln");
-        args.add("-s");
+    @Test
+    public void testStillClearsIfGivenDirectoryIsASymlink() throws Exception {
+        if (System.getProperty("os.name").startsWith("Win")) {
+            // Can't use "ln" for symlinks on the command line in Windows.
+            return;
+        }
 
-        args.add(res.getAbsolutePath());
-        args.add(link.getAbsolutePath());
+        final File randomDirectory = new File(top, "randomDir");
+        assertTrue(randomDirectory.mkdirs());
 
-        final Process proc;
+        FileUtils.touch(new File(randomDirectory, "randomfile"));
+        assertEquals(1, randomDirectory.list().length);
 
-        proc = Runtime.getRuntime().exec(args.toArray(new String[args.size()]));
-        return proc.waitFor() == 0;
+        final File symlinkDirectory = new File(top, "fakeDir");
+        assertTrue(setupSymlink(randomDirectory, symlinkDirectory));
+
+        FileUtils.cleanDirectory(symlinkDirectory);
+        assertEquals(0, symlinkDirectory.list().length);
+        assertEquals(0, randomDirectory.list().length);
     }
 
 }
diff --git a/src/test/java/org/apache/commons/io/FileUtilsCopyToFileTestCase.java b/src/test/java/org/apache/commons/io/FileUtilsCopyToFileTestCase.java
index 9d68003..c4b0e55 100644
--- a/src/test/java/org/apache/commons/io/FileUtilsCopyToFileTestCase.java
+++ b/src/test/java/org/apache/commons/io/FileUtilsCopyToFileTestCase.java
@@ -31,6 +31,25 @@ import org.junit.jupiter.api.io.TempDir;
  */
 public class FileUtilsCopyToFileTestCase {
 
+    private class CheckingInputStream extends ByteArrayInputStream {
+        private boolean closed;
+
+        public CheckingInputStream(final byte[] data) {
+            super(data);
+            closed = false;
+        }
+
+        @Override
+        public void close() throws IOException {
+            super.close();
+            closed = true;
+        }
+
+        public boolean isClosed() {
+            return closed;
+        }
+    }
+
     @TempDir
     public File temporaryFolder;
 
@@ -50,51 +69,32 @@ public class FileUtilsCopyToFileTestCase {
     }
 
     /**
-     * Tests that {@code copyToFile(InputStream, File)} does not close the input stream.
+     * Tests that {@code copyInputStreamToFile(InputStream, File)} closes the input stream.
      *
      * @throws IOException
-     * @see FileUtils#copyToFile(InputStream, File)
      * @see FileUtils#copyInputStreamToFile(InputStream, File)
+     * @see FileUtils#copyToFile(InputStream, File)
      */
     @Test
-    public void testCopyToFile() throws IOException {
+    public void testCopyInputStreamToFile() throws IOException {
         try(CheckingInputStream inputStream = new CheckingInputStream(testData)) {
-            FileUtils.copyToFile(inputStream, testFile);
-            assertFalse(inputStream.isClosed(), "inputStream should NOT be closed");
+            FileUtils.copyInputStreamToFile(inputStream, testFile);
+            assertTrue(inputStream.isClosed(), "inputStream should be closed");
         }
     }
 
     /**
-     * Tests that {@code copyInputStreamToFile(InputStream, File)} closes the input stream.
+     * Tests that {@code copyToFile(InputStream, File)} does not close the input stream.
      *
      * @throws IOException
-     * @see FileUtils#copyInputStreamToFile(InputStream, File)
      * @see FileUtils#copyToFile(InputStream, File)
+     * @see FileUtils#copyInputStreamToFile(InputStream, File)
      */
     @Test
-    public void testCopyInputStreamToFile() throws IOException {
+    public void testCopyToFile() throws IOException {
         try(CheckingInputStream inputStream = new CheckingInputStream(testData)) {
-            FileUtils.copyInputStreamToFile(inputStream, testFile);
-            assertTrue(inputStream.isClosed(), "inputStream should be closed");
-        }
-    }
-
-    private class CheckingInputStream extends ByteArrayInputStream {
-        private boolean closed;
-
-        public CheckingInputStream(final byte[] data) {
-            super(data);
-            closed = false;
-        }
-
-        @Override
-        public void close() throws IOException {
-            super.close();
-            closed = true;
-        }
-
-        public boolean isClosed() {
-            return closed;
+            FileUtils.copyToFile(inputStream, testFile);
+            assertFalse(inputStream.isClosed(), "inputStream should NOT be closed");
         }
     }
 }
diff --git a/src/test/java/org/apache/commons/io/FileUtilsDirectoryContainsTestCase.java b/src/test/java/org/apache/commons/io/FileUtilsDirectoryContainsTestCase.java
index 89a320e..d834fe7 100644
--- a/src/test/java/org/apache/commons/io/FileUtilsDirectoryContainsTestCase.java
+++ b/src/test/java/org/apache/commons/io/FileUtilsDirectoryContainsTestCase.java
@@ -124,19 +124,23 @@ public class FileUtilsDirectoryContainsTestCase {
     }
 
     @Test
-    public void testSameFile() throws IOException {
-        try {
-            assertTrue(FileUtils.directoryContains(file1, file1));
-            fail("Expected " + IllegalArgumentException.class.getName());
-        } catch (final IllegalArgumentException e) {
-            // expected
-        }
+    public void testFileDoesNotExist() throws IOException {
+        assertFalse(FileUtils.directoryContains(top, null));
+        final File file = new File("DOESNOTEXIST");
+        assertFalse(file.exists());
+        assertFalse(FileUtils.directoryContains(top, file));
     }
 
+    /**
+     * Test to demonstrate a file which does not exist returns false
+     * @throws IOException If an I/O error occurs
+     */
     @Test
-    public void testIO466() throws IOException {
-            final File fooFile = new File(directory1.getParent(), "directory1.txt");
-            assertFalse(FileUtils.directoryContains(directory1, fooFile));
+    public void testFileDoesNotExistBug() throws IOException {
+        final File file = new File(top, "DOESNOTEXIST");
+        assertTrue(top.exists(), "Check directory exists");
+        assertFalse(file.exists(), "Check file does not exist");
+        assertFalse(FileUtils.directoryContains(top, file), "Directory does not contain unrealized file");
     }
 
     @Test
@@ -153,23 +157,19 @@ public class FileUtilsDirectoryContainsTestCase {
     }
 
     @Test
-    public void testFileDoesNotExist() throws IOException {
-        assertFalse(FileUtils.directoryContains(top, null));
-        final File file = new File("DOESNOTEXIST");
-        assertFalse(file.exists());
-        assertFalse(FileUtils.directoryContains(top, file));
+    public void testIO466() throws IOException {
+            final File fooFile = new File(directory1.getParent(), "directory1.txt");
+            assertFalse(FileUtils.directoryContains(directory1, fooFile));
     }
 
-    /**
-     * Test to demonstrate a file which does not exist returns false
-     * @throws IOException If an I/O error occurs
-     */
     @Test
-    public void testFileDoesNotExistBug() throws IOException {
-        final File file = new File(top, "DOESNOTEXIST");
-        assertTrue(top.exists(), "Check directory exists");
-        assertFalse(file.exists(), "Check file does not exist");
-        assertFalse(FileUtils.directoryContains(top, file), "Directory does not contain unrealized file");
+    public void testSameFile() throws IOException {
+        try {
+            assertTrue(FileUtils.directoryContains(file1, file1));
+            fail("Expected " + IllegalArgumentException.class.getName());
+        } catch (final IllegalArgumentException e) {
+            // expected
+        }
     }
 
     @Test
diff --git a/src/test/java/org/apache/commons/io/FileUtilsFileNewerTestCase.java b/src/test/java/org/apache/commons/io/FileUtilsFileNewerTestCase.java
index 82badd3..25bc737 100644
--- a/src/test/java/org/apache/commons/io/FileUtilsFileNewerTestCase.java
+++ b/src/test/java/org/apache/commons/io/FileUtilsFileNewerTestCase.java
@@ -38,12 +38,12 @@ import org.junit.jupiter.api.io.TempDir;
  */
 public class FileUtilsFileNewerTestCase {
 
-    @TempDir
-    public File temporaryFolder;
-
     // Test data
     private static final int FILE1_SIZE = 1;
+
     private static final int FILE2_SIZE = 1024 * 4 + 1;
+    @TempDir
+    public File temporaryFolder;
 
     private File testFile1;
     private File testFile2;
@@ -90,25 +90,6 @@ public class FileUtilsFileNewerTestCase {
     }
 
     /**
-     * Tests the {@code isFileNewer(File, *)} methods which a not existing file.
-     *
-     * @throws IOException if an I/O error occurs.
-     *
-     * @see FileUtils#isFileNewer(File, long)
-     * @see FileUtils#isFileNewer(File, Date)
-     * @see FileUtils#isFileNewer(File, File)
-     */
-    @Test
-    public void testIsFileNewerImaginaryFile() throws IOException {
-        final File imaginaryFile = new File(temporaryFolder, "imaginaryFile");
-        if (imaginaryFile.exists()) {
-            throw new IllegalStateException("The imaginary File exists");
-        }
-
-        testIsFileNewer("imaginary file can be newer", imaginaryFile, FileUtils.lastModifiedFileTime(testFile2), false);
-    }
-
-    /**
      * Tests the {@code isFileNewer(File, *)} methods which the specified conditions.
      *
      * Creates :
@@ -138,14 +119,22 @@ public class FileUtilsFileNewerTestCase {
     }
 
     /**
-     * Tests the {@code isFileNewer(File, long)} method without specifying a {@code File}.
-     * <p>
-     * The test is successful if the method throws an {@code IllegalArgumentException}.
-     * </p>
+     * Tests the {@code isFileNewer(File, *)} methods which a not existing file.
+     *
+     * @throws IOException if an I/O error occurs.
+     *
+     * @see FileUtils#isFileNewer(File, long)
+     * @see FileUtils#isFileNewer(File, Date)
+     * @see FileUtils#isFileNewer(File, File)
      */
     @Test
-    public void testIsFileNewerNoFile() {
-        assertThrows(NullPointerException.class, () -> FileUtils.isFileNewer(null, 0), "file");
+    public void testIsFileNewerImaginaryFile() throws IOException {
+        final File imaginaryFile = new File(temporaryFolder, "imaginaryFile");
+        if (imaginaryFile.exists()) {
+            throw new IllegalStateException("The imaginary File exists");
+        }
+
+        testIsFileNewer("imaginary file can be newer", imaginaryFile, FileUtils.lastModifiedFileTime(testFile2), false);
     }
 
     /**
@@ -160,6 +149,17 @@ public class FileUtilsFileNewerTestCase {
     }
 
     /**
+     * Tests the {@code isFileNewer(File, long)} method without specifying a {@code File}.
+     * <p>
+     * The test is successful if the method throws an {@code IllegalArgumentException}.
+     * </p>
+     */
+    @Test
+    public void testIsFileNewerNoFile() {
+        assertThrows(NullPointerException.class, () -> FileUtils.isFileNewer(null, 0), "file");
+    }
+
+    /**
      * Tests the {@code isFileNewer(File, File)} method without specifying a reference {@code File}.
      * <p>
      * The test is successful if the method throws an {@code IllegalArgumentException}.
diff --git a/src/test/java/org/apache/commons/io/FileUtilsListFilesTestCase.java b/src/test/java/org/apache/commons/io/FileUtilsListFilesTestCase.java
index a3905b2..8d70c3d 100644
--- a/src/test/java/org/apache/commons/io/FileUtilsListFilesTestCase.java
+++ b/src/test/java/org/apache/commons/io/FileUtilsListFilesTestCase.java
@@ -40,6 +40,22 @@ public class FileUtilsListFilesTestCase {
     @TempDir
     public File temporaryFolder;
 
+    private Collection<String> filesToFilenames(final Collection<File> files) {
+        final Collection<String> filenames = new ArrayList<>(files.size());
+        for (final File file : files) {
+            filenames.add(file.getName());
+        }
+        return filenames;
+    }
+
+    private Collection<String> filesToFilenames(final Iterator<File> files) {
+        final Collection<String> filenames = new ArrayList<>();
+        while (files.hasNext()) {
+            filenames.add(files.next().getName());
+        }
+        return filenames;
+    }
+
     @SuppressWarnings("ResultOfMethodCallIgnored")
     @BeforeEach
     public void setUp() throws Exception {
@@ -72,22 +88,6 @@ public class FileUtilsListFilesTestCase {
         FileUtils.touch(file);
     }
 
-    private Collection<String> filesToFilenames(final Collection<File> files) {
-        final Collection<String> filenames = new ArrayList<>(files.size());
-        for (final File file : files) {
-            filenames.add(file.getName());
-        }
-        return filenames;
-    }
-
-    private Collection<String> filesToFilenames(final Iterator<File> files) {
-        final Collection<String> filenames = new ArrayList<>();
-        while (files.hasNext()) {
-            filenames.add(files.next().getName());
-        }
-        return filenames;
-    }
-
     @Test
     public void testIterateFilesByExtension() {
         final String[] extensions = { "xml", "txt" };
@@ -114,31 +114,6 @@ public class FileUtilsListFilesTestCase {
     }
 
     @Test
-    public void testListFilesByExtension() {
-        final String[] extensions = {"xml", "txt"};
-
-        Collection<File> files = FileUtils.listFiles(temporaryFolder, extensions, false);
-        assertEquals(1, files.size());
-        Collection<String> filenames = filesToFilenames(files);
-        assertTrue(filenames.contains("dummy-build.xml"));
-        assertFalse(filenames.contains("README"));
-        assertFalse(filenames.contains("dummy-file.txt"));
-
-        files = FileUtils.listFiles(temporaryFolder, extensions, true);
-        filenames = filesToFilenames(files);
-        assertEquals(4, filenames.size());
-        assertTrue(filenames.contains("dummy-file.txt"));
-        assertFalse(filenames.contains("dummy-index.html"));
-
-        files = FileUtils.listFiles(temporaryFolder, null, false);
-        assertEquals(2, files.size());
-        filenames = filesToFilenames(files);
-        assertTrue(filenames.contains("dummy-build.xml"));
-        assertTrue(filenames.contains("README"));
-        assertFalse(filenames.contains("dummy-file.txt"));
-    }
-
-    @Test
     public void testListFiles() {
         Collection<File> files;
         Collection<String> filenames;
@@ -189,5 +164,30 @@ public class FileUtilsListFilesTestCase {
         }
     }
 
+    @Test
+    public void testListFilesByExtension() {
+        final String[] extensions = {"xml", "txt"};
+
+        Collection<File> files = FileUtils.listFiles(temporaryFolder, extensions, false);
+        assertEquals(1, files.size());
+        Collection<String> filenames = filesToFilenames(files);
+        assertTrue(filenames.contains("dummy-build.xml"));
+        assertFalse(filenames.contains("README"));
+        assertFalse(filenames.contains("dummy-file.txt"));
+
+        files = FileUtils.listFiles(temporaryFolder, extensions, true);
+        filenames = filesToFilenames(files);
+        assertEquals(4, filenames.size());
+        assertTrue(filenames.contains("dummy-file.txt"));
+        assertFalse(filenames.contains("dummy-index.html"));
+
+        files = FileUtils.listFiles(temporaryFolder, null, false);
+        assertEquals(2, files.size());
+        filenames = filesToFilenames(files);
+        assertTrue(filenames.contains("dummy-build.xml"));
+        assertTrue(filenames.contains("README"));
+        assertFalse(filenames.contains("dummy-file.txt"));
+    }
+
 
 }
diff --git a/src/test/java/org/apache/commons/io/FileUtilsTestCase.java b/src/test/java/org/apache/commons/io/FileUtilsTestCase.java
index 8bf4b57..64704b3 100644
--- a/src/test/java/org/apache/commons/io/FileUtilsTestCase.java
+++ b/src/test/java/org/apache/commons/io/FileUtilsTestCase.java
@@ -1275,6 +1275,38 @@ public class FileUtilsTestCase {
         //TODO Maybe test copy to itself like for copyFile()
     }
 
+    /**
+     * Tests a directory with one file of size 0.
+     */
+    @Test
+    public void testCountFolders1FileSize0() throws IOException {
+        assertEquals(0, FileUtils.sizeOfDirectory(Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-0").toFile()));
+    }
+
+    /**
+     * Tests a directory with one file of size 1.
+     */
+    @Test
+    public void testCountFolders1FileSize1() throws IOException {
+        assertEquals(1, FileUtils.sizeOfDirectory(Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-1").toFile()));
+    }
+
+    /**
+     * Tests a directory with two subdirectories, each containing one file of size 1.
+     */
+    @Test
+    public void testCountFolders2FileSize2() throws IOException {
+        assertEquals(2, FileUtils.sizeOfDirectory(Paths.get("src/test/resources/org/apache/commons/io/dirs-2-file-size-2").toFile()));
+    }
+
+    /**
+     * Tests a directory with two subdirectories, each containing one file of size 1.
+     */
+    @Test
+    public void testCountFolders2FileSize4() throws IOException {
+        assertEquals(8, FileUtils.sizeOfDirectory(Paths.get("src/test/resources/org/apache/commons/io/dirs-2-file-size-4").toFile()));
+    }
+
     @Test
     public void testDecodeUrl() {
         assertEquals("", FileUtils.decodeUrl(""));
@@ -1346,6 +1378,8 @@ public class FileUtilsTestCase {
         assertFalse(testFile.exists(), "Check No Exist");
     }
 
+    // copyToDirectory
+
     @Test
     public void testDeleteQuietlyFile() throws IOException {
         final File testFile = new File(temporaryFolder, "testDeleteQuietlyFile");
@@ -1417,8 +1451,6 @@ public class FileUtilsTestCase {
 
     }
 
-    // copyToDirectory
-
     @Test
     public void testForceDeleteAFile1() throws Exception {
         final File destination = new File(temporaryFolder, "copy1.txt");
@@ -1456,6 +1488,8 @@ public class FileUtilsTestCase {
         assertFalse(testDirectory.exists(), "TestDirectory must not exist");
     }
 
+    // forceDelete
+
     @Test
     public void testForceDeleteReadOnlyFile() throws Exception {
         File destination = File.createTempFile("test-", ".txt");
@@ -1515,6 +1549,8 @@ public class FileUtilsTestCase {
         assertFalse(testFile.exists());
     }
 
+    // copyFileToDirectory
+
     @Test
     public void testGetFile() {
         final File expected_A = new File("src");
@@ -1531,8 +1567,6 @@ public class FileUtilsTestCase {
         }
     }
 
-    // forceDelete
-
     @Test
     public void testGetFile_Parent() {
         final File parent = new File("parent");
@@ -1556,6 +1590,8 @@ public class FileUtilsTestCase {
         }
     }
 
+    // forceDelete
+
     @Test
     public void testGetTempDirectory() {
         final File tempDirectory = new File(System.getProperty("java.io.tmpdir"));
@@ -1568,8 +1604,6 @@ public class FileUtilsTestCase {
                 FileUtils.getTempDirectoryPath());
     }
 
-    // copyFileToDirectory
-
     @Test
     public void testGetUserDirectory() {
         final File userDirectory = new File(System.getProperty("user.home"));
@@ -1582,8 +1616,6 @@ public class FileUtilsTestCase {
                 FileUtils.getUserDirectoryPath());
     }
 
-    // forceDelete
-
     // This test relies on FileUtils.copyFile using File.length to check the output size
     @Test
     public void testIncorrectOutputSize() {
@@ -2507,6 +2539,7 @@ public class FileUtilsTestCase {
         assertEquals("Hello /u1234", data);
     }
 
+
     @Test
     public void testReadFileToStringWithEncoding() throws Exception {
         final File file = new File(temporaryFolder, "read.obj");
@@ -2601,7 +2634,6 @@ public class FileUtilsTestCase {
                 "Unexpected directory size");
     }
 
-
     @Test
     public void testSizeOfDirectory() throws Exception {
         final File file = new File(temporaryFolder, getName());
@@ -2997,6 +3029,7 @@ public class FileUtilsTestCase {
         assertEquals(expected, actual);
     }
 
+
     @Test
     public void testWriteLines_4arg() throws Exception {
         final Object[] data = {
@@ -3050,7 +3083,6 @@ public class FileUtilsTestCase {
         assertEquals(expected, actual);
     }
 
-
     @Test
     public void testWriteLines_4argsWithAppendOptionTrue_ShouldNotDeletePreviousFileLines() throws Exception {
         final File file = TestUtils.newFile(temporaryFolder, "lines.txt");
@@ -3228,36 +3260,4 @@ public class FileUtilsTestCase {
         assertEquals(expected, actual);
     }
 
-    /**
-     * Tests a directory with one file of size 0.
-     */
-    @Test
-    public void testCountFolders1FileSize0() throws IOException {
-        assertEquals(0, FileUtils.sizeOfDirectory(Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-0").toFile()));
-    }
-
-    /**
-     * Tests a directory with one file of size 1.
-     */
-    @Test
-    public void testCountFolders1FileSize1() throws IOException {
-        assertEquals(1, FileUtils.sizeOfDirectory(Paths.get("src/test/resources/org/apache/commons/io/dirs-1-file-size-1").toFile()));
-    }
-
-    /**
-     * Tests a directory with two subdirectories, each containing one file of size 1.
-     */
-    @Test
-    public void testCountFolders2FileSize2() throws IOException {
-        assertEquals(2, FileUtils.sizeOfDirectory(Paths.get("src/test/resources/org/apache/commons/io/dirs-2-file-size-2").toFile()));
-    }
-
-    /**
-     * Tests a directory with two subdirectories, each containing one file of size 1.
-     */
-    @Test
-    public void testCountFolders2FileSize4() throws IOException {
-        assertEquals(8, FileUtils.sizeOfDirectory(Paths.get("src/test/resources/org/apache/commons/io/dirs-2-file-size-4").toFile()));
-    }
-
 }
diff --git a/src/test/java/org/apache/commons/io/FileUtilsWaitForTestCase.java b/src/test/java/org/apache/commons/io/FileUtilsWaitForTestCase.java
index a751064..a0b1f47 100644
--- a/src/test/java/org/apache/commons/io/FileUtilsWaitForTestCase.java
+++ b/src/test/java/org/apache/commons/io/FileUtilsWaitForTestCase.java
@@ -38,11 +38,6 @@ public class FileUtilsWaitForTestCase {
     }
 
     @Test
-    public void testWaitForNegativeDuration() {
-        FileUtils.waitFor(FileUtils.current(), -1);
-    }
-
-    @Test
     public void testWaitForInterrupted() throws InterruptedException {
         final AtomicBoolean wasInterrupted = new AtomicBoolean(false);
         final CountDownLatch started = new CountDownLatch(1);
@@ -58,4 +53,9 @@ public class FileUtilsWaitForTestCase {
         assertTrue(wasInterrupted.get());
     }
 
+    @Test
+    public void testWaitForNegativeDuration() {
+        FileUtils.waitFor(FileUtils.current(), -1);
+    }
+
 }
diff --git a/src/test/java/org/apache/commons/io/FilenameUtilsTestCase.java b/src/test/java/org/apache/commons/io/FilenameUtilsTestCase.java
index fc39d66..03fa509 100644
--- a/src/test/java/org/apache/commons/io/FilenameUtilsTestCase.java
+++ b/src/test/java/org/apache/commons/io/FilenameUtilsTestCase.java
@@ -44,11 +44,11 @@ import org.junit.jupiter.api.io.TempDir;
  */
 public class FilenameUtilsTestCase {
 
-    @TempDir
-    public File temporaryFolder;
-
     private static final String SEP = "" + File.separatorChar;
+
     private static final boolean WINDOWS = File.separatorChar == '\\';
+    @TempDir
+    public File temporaryFolder;
 
     private File testFile1;
     private File testFile2;
@@ -98,450 +98,428 @@ public class FilenameUtilsTestCase {
     }
 
     @Test
-    public void testNormalize() {
-        assertNull(FilenameUtils.normalize(null));
-        assertNull(FilenameUtils.normalize(":"));
-        assertNull(FilenameUtils.normalize("1:\\a\\b\\c.txt"));
-        assertNull(FilenameUtils.normalize("1:"));
-        assertNull(FilenameUtils.normalize("1:a"));
-        assertNull(FilenameUtils.normalize("\\\\\\a\\b\\c.txt"));
-        assertNull(FilenameUtils.normalize("\\\\a"));
-
-        assertEquals("a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("a\\b/c.txt"));
-        assertEquals("" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("\\a\\b/c.txt"));
-        assertEquals("C:" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("C:\\a\\b/c.txt"));
-        assertEquals("" + SEP + "" + SEP + "server" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("\\\\server\\a\\b/c.txt"));
-        assertEquals("~" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("~\\a\\b/c.txt"));
-        assertEquals("~user" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("~user\\a\\b/c.txt"));
-
-        assertEquals("a" + SEP + "c", FilenameUtils.normalize("a/b/../c"));
-        assertEquals("c", FilenameUtils.normalize("a/b/../../c"));
-        assertEquals("c" + SEP, FilenameUtils.normalize("a/b/../../c/"));
-        assertNull(FilenameUtils.normalize("a/b/../../../c"));
-        assertEquals("a" + SEP, FilenameUtils.normalize("a/b/.."));
-        assertEquals("a" + SEP, FilenameUtils.normalize("a/b/../"));
-        assertEquals("", FilenameUtils.normalize("a/b/../.."));
-        assertEquals("", FilenameUtils.normalize("a/b/../../"));
-        assertNull(FilenameUtils.normalize("a/b/../../.."));
-        assertEquals("a" + SEP + "d", FilenameUtils.normalize("a/b/../c/../d"));
-        assertEquals("a" + SEP + "d" + SEP, FilenameUtils.normalize("a/b/../c/../d/"));
-        assertEquals("a" + SEP + "b" + SEP + "d", FilenameUtils.normalize("a/b//d"));
-        assertEquals("a" + SEP + "b" + SEP, FilenameUtils.normalize("a/b/././."));
-        assertEquals("a" + SEP + "b" + SEP, FilenameUtils.normalize("a/b/./././"));
-        assertEquals("a" + SEP, FilenameUtils.normalize("./a/"));
-        assertEquals("a", FilenameUtils.normalize("./a"));
-        assertEquals("", FilenameUtils.normalize("./"));
-        assertEquals("", FilenameUtils.normalize("."));
-        assertNull(FilenameUtils.normalize("../a"));
-        assertNull(FilenameUtils.normalize(".."));
-        assertEquals("", FilenameUtils.normalize(""));
-
-        assertEquals(SEP + "a", FilenameUtils.normalize("/a"));
-        assertEquals(SEP + "a" + SEP, FilenameUtils.normalize("/a/"));
-        assertEquals(SEP + "a" + SEP + "c", FilenameUtils.normalize("/a/b/../c"));
-        assertEquals(SEP + "c", FilenameUtils.normalize("/a/b/../../c"));
-        assertNull(FilenameUtils.normalize("/a/b/../../../c"));
-        assertEquals(SEP + "a" + SEP, FilenameUtils.normalize("/a/b/.."));
-        assertEquals(SEP + "", FilenameUtils.normalize("/a/b/../.."));
-        assertNull(FilenameUtils.normalize("/a/b/../../.."));
-        assertEquals(SEP + "a" + SEP + "d", FilenameUtils.normalize("/a/b/../c/../d"));
-        assertEquals(SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalize("/a/b//d"));
-        assertEquals(SEP + "a" + SEP + "b" + SEP, FilenameUtils.normalize("/a/b/././."));
-        assertEquals(SEP + "a", FilenameUtils.normalize("/./a"));
-        assertEquals(SEP + "", FilenameUtils.normalize("/./"));
-        assertEquals(SEP + "", FilenameUtils.normalize("/."));
-        assertNull(FilenameUtils.normalize("/../a"));
-        assertNull(FilenameUtils.normalize("/.."));
-        assertEquals(SEP + "", FilenameUtils.normalize("/"));
-
-        assertEquals("~" + SEP + "a", FilenameUtils.normalize("~/a"));
-        assertEquals("~" + SEP + "a" + SEP, FilenameUtils.normalize("~/a/"));
-        assertEquals("~" + SEP + "a" + SEP + "c", FilenameUtils.normalize("~/a/b/../c"));
-        assertEquals("~" + SEP + "c", FilenameUtils.normalize("~/a/b/../../c"));
-        assertNull(FilenameUtils.normalize("~/a/b/../../../c"));
-        assertEquals("~" + SEP + "a" + SEP, FilenameUtils.normalize("~/a/b/.."));
-        assertEquals("~" + SEP + "", FilenameUtils.normalize("~/a/b/../.."));
-        assertNull(FilenameUtils.normalize("~/a/b/../../.."));
-        assertEquals("~" + SEP + "a" + SEP + "d", FilenameUtils.normalize("~/a/b/../c/../d"));
-        assertEquals("~" + SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalize("~/a/b//d"));
-        assertEquals("~" + SEP + "a" + SEP + "b" + SEP, FilenameUtils.normalize("~/a/b/././."));
-        assertEquals("~" + SEP + "a", FilenameUtils.normalize("~/./a"));
-        assertEquals("~" + SEP, FilenameUtils.normalize("~/./"));
-        assertEquals("~" + SEP, FilenameUtils.normalize("~/."));
-        assertNull(FilenameUtils.normalize("~/../a"));
-        assertNull(FilenameUtils.normalize("~/.."));
-        assertEquals("~" + SEP, FilenameUtils.normalize("~/"));
-        assertEquals("~" + SEP, FilenameUtils.normalize("~"));
-
-        assertEquals("~user" + SEP + "a", FilenameUtils.normalize("~user/a"));
-        assertEquals("~user" + SEP + "a" + SEP, FilenameUtils.normalize("~user/a/"));
-        assertEquals("~user" + SEP + "a" + SEP + "c", FilenameUtils.normalize("~user/a/b/../c"));
-        assertEquals("~user" + SEP + "c", FilenameUtils.normalize("~user/a/b/../../c"));
-        assertNull(FilenameUtils.normalize("~user/a/b/../../../c"));
-        assertEquals("~user" + SEP + "a" + SEP, FilenameUtils.normalize("~user/a/b/.."));
-        assertEquals("~user" + SEP + "", FilenameUtils.normalize("~user/a/b/../.."));
-        assertNull(FilenameUtils.normalize("~user/a/b/../../.."));
-        assertEquals("~user" + SEP + "a" + SEP + "d", FilenameUtils.normalize("~user/a/b/../c/../d"));
-        assertEquals("~user" + SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalize("~user/a/b//d"));
-        assertEquals("~user" + SEP + "a" + SEP + "b" + SEP, FilenameUtils.normalize("~user/a/b/././."));
-        assertEquals("~user" + SEP + "a", FilenameUtils.normalize("~user/./a"));
-        assertEquals("~user" + SEP + "", FilenameUtils.normalize("~user/./"));
-        assertEquals("~user" + SEP + "", FilenameUtils.normalize("~user/."));
-        assertNull(FilenameUtils.normalize("~user/../a"));
-        assertNull(FilenameUtils.normalize("~user/.."));
-        assertEquals("~user" + SEP, FilenameUtils.normalize("~user/"));
-        assertEquals("~user" + SEP, FilenameUtils.normalize("~user"));
+    public void testConcat() {
+        assertNull(FilenameUtils.concat("", null));
+        assertNull(FilenameUtils.concat(null, null));
+        assertNull(FilenameUtils.concat(null, ""));
+        assertNull(FilenameUtils.concat(null, "a"));
+        assertEquals(SEP + "a", FilenameUtils.concat(null, "/a"));
 
-        assertEquals("C:" + SEP + "a", FilenameUtils.normalize("C:/a"));
-        assertEquals("C:" + SEP + "a" + SEP, FilenameUtils.normalize("C:/a/"));
-        assertEquals("C:" + SEP + "a" + SEP + "c", FilenameUtils.normalize("C:/a/b/../c"));
-        assertEquals("C:" + SEP + "c", FilenameUtils.normalize("C:/a/b/../../c"));
-        assertNull(FilenameUtils.normalize("C:/a/b/../../../c"));
-        assertEquals("C:" + SEP + "a" + SEP, FilenameUtils.normalize("C:/a/b/.."));
-        assertEquals("C:" + SEP + "", FilenameUtils.normalize("C:/a/b/../.."));
-        assertNull(FilenameUtils.normalize("C:/a/b/../../.."));
-        assertEquals("C:" + SEP + "a" + SEP + "d", FilenameUtils.normalize("C:/a/b/../c/../d"));
-        assertEquals("C:" + SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalize("C:/a/b//d"));
-        assertEquals("C:" + SEP + "a" + SEP + "b" + SEP, FilenameUtils.normalize("C:/a/b/././."));
-        assertEquals("C:" + SEP + "a", FilenameUtils.normalize("C:/./a"));
-        assertEquals("C:" + SEP + "", FilenameUtils.normalize("C:/./"));
-        assertEquals("C:" + SEP + "", FilenameUtils.normalize("C:/."));
-        assertNull(FilenameUtils.normalize("C:/../a"));
-        assertNull(FilenameUtils.normalize("C:/.."));
-        assertEquals("C:" + SEP + "", FilenameUtils.normalize("C:/"));
+        assertNull(FilenameUtils.concat("", ":")); // invalid prefix
+        assertNull(FilenameUtils.concat(":", "")); // invalid prefix
 
-        assertEquals("C:" + "a", FilenameUtils.normalize("C:a"));
-        assertEquals("C:" + "a" + SEP, FilenameUtils.normalize("C:a/"));
-        assertEquals("C:" + "a" + SEP + "c", FilenameUtils.normalize("C:a/b/../c"));
-        assertEquals("C:" + "c", FilenameUtils.normalize("C:a/b/../../c"));
-        assertNull(FilenameUtils.normalize("C:a/b/../../../c"));
-        assertEquals("C:" + "a" + SEP, FilenameUtils.normalize("C:a/b/.."));
-        assertEquals("C:" + "", FilenameUtils.normalize("C:a/b/../.."));
-        assertNull(FilenameUtils.normalize("C:a/b/../../.."));
-        assertEquals("C:" + "a" + SEP + "d", FilenameUtils.normalize("C:a/b/../c/../d"));
-        assertEquals("C:" + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalize("C:a/b//d"));
-        assertEquals("C:" + "a" + SEP + "b" + SEP, FilenameUtils.normalize("C:a/b/././."));
-        assertEquals("C:" + "a", FilenameUtils.normalize("C:./a"));
-        assertEquals("C:" + "", FilenameUtils.normalize("C:./"));
-        assertEquals("C:" + "", FilenameUtils.normalize("C:."));
-        assertNull(FilenameUtils.normalize("C:../a"));
-        assertNull(FilenameUtils.normalize("C:.."));
-        assertEquals("C:" + "", FilenameUtils.normalize("C:"));
+        assertEquals("f" + SEP, FilenameUtils.concat("", "f/"));
+        assertEquals("f", FilenameUtils.concat("", "f"));
+        assertEquals("a" + SEP + "f" + SEP, FilenameUtils.concat("a/", "f/"));
+        assertEquals("a" + SEP + "f", FilenameUtils.concat("a", "f"));
+        assertEquals("a" + SEP + "b" + SEP + "f" + SEP, FilenameUtils.concat("a/b/", "f/"));
+        assertEquals("a" + SEP + "b" + SEP + "f", FilenameUtils.concat("a/b", "f"));
 
-        assertEquals(SEP + SEP + "server" + SEP + "a", FilenameUtils.normalize("//server/a"));
-        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP, FilenameUtils.normalize("//server/a/"));
-        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP + "c", FilenameUtils.normalize("//server/a/b/../c"));
-        assertEquals(SEP + SEP + "server" + SEP + "c", FilenameUtils.normalize("//server/a/b/../../c"));
-        assertNull(FilenameUtils.normalize("//server/a/b/../../../c"));
-        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP, FilenameUtils.normalize("//server/a/b/.."));
-        assertEquals(SEP + SEP + "server" + SEP + "", FilenameUtils.normalize("//server/a/b/../.."));
-        assertNull(FilenameUtils.normalize("//server/a/b/../../.."));
-        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP + "d", FilenameUtils.normalize("//server/a/b/../c/../d"));
-        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalize("//server/a/b//d"));
-        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP + "b" + SEP, FilenameUtils.normalize("//server/a/b/././."));
-        assertEquals(SEP + SEP + "server" + SEP + "a", FilenameUtils.normalize("//server/./a"));
-        assertEquals(SEP + SEP + "server" + SEP + "", FilenameUtils.normalize("//server/./"));
-        assertEquals(SEP + SEP + "server" + SEP + "", FilenameUtils.normalize("//server/."));
-        assertNull(FilenameUtils.normalize("//server/../a"));
-        assertNull(FilenameUtils.normalize("//server/.."));
-        assertEquals(SEP + SEP + "server" + SEP + "", FilenameUtils.normalize("//server/"));
+        assertEquals("a" + SEP + "f" + SEP, FilenameUtils.concat("a/b/", "../f/"));
+        assertEquals("a" + SEP + "f", FilenameUtils.concat("a/b", "../f"));
+        assertEquals("a" + SEP + "c" + SEP + "g" + SEP, FilenameUtils.concat("a/b/../c/", "f/../g/"));
+        assertEquals("a" + SEP + "c" + SEP + "g", FilenameUtils.concat("a/b/../c", "f/../g"));
 
-        assertEquals(SEP + SEP + "127.0.0.1" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("\\\\127.0.0.1\\a\\b\\c.txt"));
-        assertEquals(SEP + SEP + "::1" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("\\\\::1\\a\\b\\c.txt"));
-        assertEquals(SEP + SEP + "1::" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("\\\\1::\\a\\b\\c.txt"));
-        assertEquals(SEP + SEP + "server.example.org" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("\\\\server.example.org\\a\\b\\c.txt"));
-        assertEquals(SEP + SEP + "server.sub.example.org" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("\\\\server.sub.example.org\\a\\b\\c.txt"));
-        assertEquals(SEP + SEP + "server." + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("\\\\server.\\a\\b\\c.txt"));
-        assertEquals(SEP + SEP + "1::127.0.0.1" + SEP + "a" + SEP + "b" + SEP + "c.txt",
-            FilenameUtils.normalize("\\\\1::127.0.0.1\\a\\b\\c.txt"));
+        assertEquals("a" + SEP + "c.txt" + SEP + "f", FilenameUtils.concat("a/c.txt", "f"));
 
-        // not valid IPv4 addresses but technically a valid "reg-name"s according to RFC1034
-        assertEquals(SEP + SEP + "127.0.0.256" + SEP + "a" + SEP + "b" + SEP + "c.txt",
-            FilenameUtils.normalize("\\\\127.0.0.256\\a\\b\\c.txt"));
-        assertEquals(SEP + SEP + "127.0.0.01" + SEP + "a" + SEP + "b" + SEP + "c.txt",
-            FilenameUtils.normalize("\\\\127.0.0.01\\a\\b\\c.txt"));
+        assertEquals(SEP + "f" + SEP, FilenameUtils.concat("", "/f/"));
+        assertEquals(SEP + "f", FilenameUtils.concat("", "/f"));
+        assertEquals(SEP + "f" + SEP, FilenameUtils.concat("a/", "/f/"));
+        assertEquals(SEP + "f", FilenameUtils.concat("a", "/f"));
 
-        assertNull(FilenameUtils.normalize("\\\\-server\\a\\b\\c.txt"));
-        assertNull(FilenameUtils.normalize("\\\\.\\a\\b\\c.txt"));
-        assertNull(FilenameUtils.normalize("\\\\..\\a\\b\\c.txt"));
-        assertNull(FilenameUtils.normalize("\\\\127.0..1\\a\\b\\c.txt"));
-        assertNull(FilenameUtils.normalize("\\\\::1::2\\a\\b\\c.txt"));
-        assertNull(FilenameUtils.normalize("\\\\:1\\a\\b\\c.txt"));
-        assertNull(FilenameUtils.normalize("\\\\1:\\a\\b\\c.txt"));
-        assertNull(FilenameUtils.normalize("\\\\1:2:3:4:5:6:7:8:9\\a\\b\\c.txt"));
-        assertNull(FilenameUtils.normalize("\\\\g:2:3:4:5:6:7:8\\a\\b\\c.txt"));
-        assertNull(FilenameUtils.normalize("\\\\1ffff:2:3:4:5:6:7:8\\a\\b\\c.txt"));
-        assertNull(FilenameUtils.normalize("\\\\1:2\\a\\b\\c.txt"));
-        // IO-556
-        assertNull(FilenameUtils.normalize("//../foo"));
-        assertNull(FilenameUtils.normalize("\\\\..\\foo"));
+        assertEquals(SEP + "c" + SEP + "d", FilenameUtils.concat("a/b/", "/c/d"));
+        assertEquals("C:c" + SEP + "d", FilenameUtils.concat("a/b/", "C:c/d"));
+        assertEquals("C:" + SEP + "c" + SEP + "d", FilenameUtils.concat("a/b/", "C:/c/d"));
+        assertEquals("~" + SEP + "c" + SEP + "d", FilenameUtils.concat("a/b/", "~/c/d"));
+        assertEquals("~user" + SEP + "c" + SEP + "d", FilenameUtils.concat("a/b/", "~user/c/d"));
+        assertEquals("~" + SEP, FilenameUtils.concat("a/b/", "~"));
+        assertEquals("~user" + SEP, FilenameUtils.concat("a/b/", "~user"));
     }
 
-    /**
-     */
+    //-----------------------------------------------------------------------
     @Test
-    public void testNormalize_with_nullbytes() {
-        try {
-            assertEquals("a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("a\\b/c\u0000.txt"));
-        } catch (final IllegalArgumentException ignore) {
-        }
+    public void testDirectoryContains() throws IOException {
+        assertTrue(FilenameUtils.directoryContains("/foo", "/foo/bar"));
+        assertTrue(FilenameUtils.directoryContains("/foo/", "/foo/bar"));
+        assertTrue(FilenameUtils.directoryContains("C:\\foo", "C:\\foo\\bar"));
+        assertTrue(FilenameUtils.directoryContains("C:\\foo\\", "C:\\foo\\bar"));
 
-        try {
-            assertEquals("a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("\u0000a\\b/c.txt"));
-        } catch (final IllegalArgumentException ignore) {
-        }
+        assertFalse(FilenameUtils.directoryContains("/foo", "/foo"));
+        assertFalse(FilenameUtils.directoryContains("/foo", "/foobar"));
+        assertFalse(FilenameUtils.directoryContains("C:\\foo", "C:\\foobar"));
+        assertFalse(FilenameUtils.directoryContains("/foo", null));
+        assertFalse(FilenameUtils.directoryContains("", ""));
+        assertFalse(FilenameUtils.directoryContains("", "/foo"));
+        assertFalse(FilenameUtils.directoryContains("/foo", ""));
     }
 
     @Test
-    public void testNormalizeUnixWin() {
-
-        // Normalize (Unix Separator)
-        assertEquals("/a/c/", FilenameUtils.normalize("/a/b/../c/", true));
-        assertEquals("/a/c/", FilenameUtils.normalize("\\a\\b\\..\\c\\", true));
+    public void testEquals() {
+        assertTrue(FilenameUtils.equals(null, null));
+        assertFalse(FilenameUtils.equals(null, ""));
+        assertFalse(FilenameUtils.equals("", null));
+        assertTrue(FilenameUtils.equals("", ""));
+        assertTrue(FilenameUtils.equals("file.txt", "file.txt"));
+        assertFalse(FilenameUtils.equals("file.txt", "FILE.TXT"));
+        assertFalse(FilenameUtils.equals("a\\b\\file.txt", "a/b/file.txt"));
+    }
 
-        // Normalize (Windows Separator)
-        assertEquals("\\a\\c\\", FilenameUtils.normalize("/a/b/../c/", false));
-        assertEquals("\\a\\c\\", FilenameUtils.normalize("\\a\\b\\..\\c\\", false));
+    @Test
+    public void testEquals_fullControl() {
+        assertFalse(FilenameUtils.equals("file.txt", "FILE.TXT", true, IOCase.SENSITIVE));
+        assertTrue(FilenameUtils.equals("file.txt", "FILE.TXT", true, IOCase.INSENSITIVE));
+        assertEquals(WINDOWS, FilenameUtils.equals("file.txt", "FILE.TXT", true, IOCase.SYSTEM));
+        assertFalse(FilenameUtils.equals("file.txt", "FILE.TXT", true, null));
     }
 
     @Test
-    public void testNormalizeNoEndSeparator() {
-        assertNull(FilenameUtils.normalizeNoEndSeparator(null));
-        assertNull(FilenameUtils.normalizeNoEndSeparator(":"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("1:\\a\\b\\c.txt"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("1:"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("1:a"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("\\\\\\a\\b\\c.txt"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("\\\\a"));
+    public void testEqualsNormalized() {
+        assertTrue(FilenameUtils.equalsNormalized(null, null));
+        assertFalse(FilenameUtils.equalsNormalized(null, ""));
+        assertFalse(FilenameUtils.equalsNormalized("", null));
+        assertTrue(FilenameUtils.equalsNormalized("", ""));
+        assertTrue(FilenameUtils.equalsNormalized("file.txt", "file.txt"));
+        assertFalse(FilenameUtils.equalsNormalized("file.txt", "FILE.TXT"));
+        assertTrue(FilenameUtils.equalsNormalized("a\\b\\file.txt", "a/b/file.txt"));
+        assertFalse(FilenameUtils.equalsNormalized("a/b/", "a/b"));
+    }
 
-        assertEquals("a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalizeNoEndSeparator("a\\b/c.txt"));
-        assertEquals("" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalizeNoEndSeparator("\\a\\b/c.txt"));
-        assertEquals("C:" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalizeNoEndSeparator("C:\\a\\b/c.txt"));
-        assertEquals("" + SEP + "" + SEP + "server" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalizeNoEndSeparator("\\\\server\\a\\b/c.txt"));
-        assertEquals("~" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalizeNoEndSeparator("~\\a\\b/c.txt"));
-        assertEquals("~user" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalizeNoEndSeparator("~user\\a\\b/c.txt"));
-        assertEquals("C:" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalizeNoEndSeparator("C:\\\\a\\\\b\\\\c.txt"));
+    /**
+     * Test for https://issues.apache.org/jira/browse/IO-128
+     */
+    @Test
+    public void testEqualsNormalizedError_IO_128() {
+        assertFalse(FilenameUtils.equalsNormalizedOnSystem("//file.txt", "file.txt"));
+        assertFalse(FilenameUtils.equalsNormalizedOnSystem("file.txt", "//file.txt"));
+        assertFalse(FilenameUtils.equalsNormalizedOnSystem("//file.txt", "//file.txt"));
+    }
 
-        assertEquals("a" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("a/b/../c"));
-        assertEquals("c", FilenameUtils.normalizeNoEndSeparator("a/b/../../c"));
-        assertEquals("c", FilenameUtils.normalizeNoEndSeparator("a/b/../../c/"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("a/b/../../../c"));
-        assertEquals("a", FilenameUtils.normalizeNoEndSeparator("a/b/.."));
-        assertEquals("a", FilenameUtils.normalizeNoEndSeparator("a/b/../"));
-        assertEquals("", FilenameUtils.normalizeNoEndSeparator("a/b/../.."));
-        assertEquals("", FilenameUtils.normalizeNoEndSeparator("a/b/../../"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("a/b/../../.."));
-        assertEquals("a" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("a/b/../c/../d"));
-        assertEquals("a" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("a/b/../c/../d/"));
-        assertEquals("a" + SEP + "b" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("a/b//d"));
-        assertEquals("a" + SEP + "b", FilenameUtils.normalizeNoEndSeparator("a/b/././."));
-        assertEquals("a" + SEP + "b", FilenameUtils.normalizeNoEndSeparator("a/b/./././"));
-        assertEquals("a", FilenameUtils.normalizeNoEndSeparator("./a/"));
-        assertEquals("a", FilenameUtils.normalizeNoEndSeparator("./a"));
-        assertEquals("", FilenameUtils.normalizeNoEndSeparator("./"));
-        assertEquals("", FilenameUtils.normalizeNoEndSeparator("."));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("../a"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator(".."));
-        assertEquals("", FilenameUtils.normalizeNoEndSeparator(""));
+    @Test
+    public void testEqualsNormalizedOnSystem() {
+        assertTrue(FilenameUtils.equalsNormalizedOnSystem(null, null));
+        assertFalse(FilenameUtils.equalsNormalizedOnSystem(null, ""));
+        assertFalse(FilenameUtils.equalsNormalizedOnSystem("", null));
+        assertTrue(FilenameUtils.equalsNormalizedOnSystem("", ""));
+        assertTrue(FilenameUtils.equalsNormalizedOnSystem("file.txt", "file.txt"));
+        assertEquals(WINDOWS, FilenameUtils.equalsNormalizedOnSystem("file.txt", "FILE.TXT"));
+        assertTrue(FilenameUtils.equalsNormalizedOnSystem("a\\b\\file.txt", "a/b/file.txt"));
+        assertFalse(FilenameUtils.equalsNormalizedOnSystem("a/b/", "a/b"));
+    }
 
-        assertEquals(SEP + "a", FilenameUtils.normalizeNoEndSeparator("/a"));
-        assertEquals(SEP + "a", FilenameUtils.normalizeNoEndSeparator("/a/"));
-        assertEquals(SEP + "a" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("/a/b/../c"));
-        assertEquals(SEP + "c", FilenameUtils.normalizeNoEndSeparator("/a/b/../../c"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("/a/b/../../../c"));
-        assertEquals(SEP + "a", FilenameUtils.normalizeNoEndSeparator("/a/b/.."));
-        assertEquals(SEP + "", FilenameUtils.normalizeNoEndSeparator("/a/b/../.."));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("/a/b/../../.."));
-        assertEquals(SEP + "a" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("/a/b/../c/../d"));
-        assertEquals(SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("/a/b//d"));
-        assertEquals(SEP + "a" + SEP + "b", FilenameUtils.normalizeNoEndSeparator("/a/b/././."));
-        assertEquals(SEP + "a", FilenameUtils.normalizeNoEndSeparator("/./a"));
-        assertEquals(SEP + "", FilenameUtils.normalizeNoEndSeparator("/./"));
-        assertEquals(SEP + "", FilenameUtils.normalizeNoEndSeparator("/."));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("/../a"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("/.."));
-        assertEquals(SEP + "", FilenameUtils.normalizeNoEndSeparator("/"));
+    @Test
+    public void testEqualsOnSystem() {
+        assertTrue(FilenameUtils.equalsOnSystem(null, null));
+        assertFalse(FilenameUtils.equalsOnSystem(null, ""));
+        assertFalse(FilenameUtils.equalsOnSystem("", null));
+        assertTrue(FilenameUtils.equalsOnSystem("", ""));
+        assertTrue(FilenameUtils.equalsOnSystem("file.txt", "file.txt"));
+        assertEquals(WINDOWS, FilenameUtils.equalsOnSystem("file.txt", "FILE.TXT"));
+        assertFalse(FilenameUtils.equalsOnSystem("a\\b\\file.txt", "a/b/file.txt"));
+    }
 
-        assertEquals("~" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("~/a"));
-        assertEquals("~" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("~/a/"));
-        assertEquals("~" + SEP + "a" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("~/a/b/../c"));
-        assertEquals("~" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("~/a/b/../../c"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("~/a/b/../../../c"));
-        assertEquals("~" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("~/a/b/.."));
-        assertEquals("~" + SEP + "", FilenameUtils.normalizeNoEndSeparator("~/a/b/../.."));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("~/a/b/../../.."));
-        assertEquals("~" + SEP + "a" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("~/a/b/../c/../d"));
-        assertEquals("~" + SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("~/a/b//d"));
-        assertEquals("~" + SEP + "a" + SEP + "b", FilenameUtils.normalizeNoEndSeparator("~/a/b/././."));
-        assertEquals("~" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("~/./a"));
-        assertEquals("~" + SEP, FilenameUtils.normalizeNoEndSeparator("~/./"));
-        assertEquals("~" + SEP, FilenameUtils.normalizeNoEndSeparator("~/."));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("~/../a"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("~/.."));
-        assertEquals("~" + SEP, FilenameUtils.normalizeNoEndSeparator("~/"));
-        assertEquals("~" + SEP, FilenameUtils.normalizeNoEndSeparator("~"));
+    @Test
+    public void testGetBaseName() {
+        assertNull(FilenameUtils.getBaseName(null));
+        assertEquals("noseperator", FilenameUtils.getBaseName("noseperator.inthispath"));
+        assertEquals("c", FilenameUtils.getBaseName("a/b/c.txt"));
+        assertEquals("c", FilenameUtils.getBaseName("a/b/c"));
+        assertEquals("", FilenameUtils.getBaseName("a/b/c/"));
+        assertEquals("c", FilenameUtils.getBaseName("a\\b\\c"));
+        assertEquals("file.txt", FilenameUtils.getBaseName("file.txt.bak"));
+    }
 
-        assertEquals("~user" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("~user/a"));
-        assertEquals("~user" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("~user/a/"));
-        assertEquals("~user" + SEP + "a" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("~user/a/b/../c"));
-        assertEquals("~user" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("~user/a/b/../../c"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("~user/a/b/../../../c"));
-        assertEquals("~user" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("~user/a/b/.."));
-        assertEquals("~user" + SEP + "", FilenameUtils.normalizeNoEndSeparator("~user/a/b/../.."));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("~user/a/b/../../.."));
-        assertEquals("~user" + SEP + "a" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("~user/a/b/../c/../d"));
-        assertEquals("~user" + SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("~user/a/b//d"));
-        assertEquals("~user" + SEP + "a" + SEP + "b", FilenameUtils.normalizeNoEndSeparator("~user/a/b/././."));
-        assertEquals("~user" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("~user/./a"));
-        assertEquals("~user" + SEP + "", FilenameUtils.normalizeNoEndSeparator("~user/./"));
-        assertEquals("~user" + SEP + "", FilenameUtils.normalizeNoEndSeparator("~user/."));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("~user/../a"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("~user/.."));
-        assertEquals("~user" + SEP, FilenameUtils.normalizeNoEndSeparator("~user/"));
-        assertEquals("~user" + SEP, FilenameUtils.normalizeNoEndSeparator("~user"));
+    @Test
+    public void testGetBaseName_with_nullByte() {
+        try {
+            assertEquals("file.txt", FilenameUtils.getBaseName("fil\u0000e.txt.bak"));
+        } catch (final IllegalArgumentException ignore) {
 
-        assertEquals("C:" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("C:/a"));
-        assertEquals("C:" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("C:/a/"));
-        assertEquals("C:" + SEP + "a" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("C:/a/b/../c"));
-        assertEquals("C:" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("C:/a/b/../../c"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("C:/a/b/../../../c"));
-        assertEquals("C:" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("C:/a/b/.."));
-        assertEquals("C:" + SEP + "", FilenameUtils.normalizeNoEndSeparator("C:/a/b/../.."));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("C:/a/b/../../.."));
-        assertEquals("C:" + SEP + "a" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("C:/a/b/../c/../d"));
-        assertEquals("C:" + SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("C:/a/b//d"));
-        assertEquals("C:" + SEP + "a" + SEP + "b", FilenameUtils.normalizeNoEndSeparator("C:/a/b/././."));
-        assertEquals("C:" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("C:/./a"));
-        assertEquals("C:" + SEP + "", FilenameUtils.normalizeNoEndSeparator("C:/./"));
-        assertEquals("C:" + SEP + "", FilenameUtils.normalizeNoEndSeparator("C:/."));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("C:/../a"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("C:/.."));
-        assertEquals("C:" + SEP + "", FilenameUtils.normalizeNoEndSeparator("C:/"));
+        }
+    }
 
-        assertEquals("C:" + "a", FilenameUtils.normalizeNoEndSeparator("C:a"));
-        assertEquals("C:" + "a", FilenameUtils.normalizeNoEndSeparator("C:a/"));
-        assertEquals("C:" + "a" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("C:a/b/../c"));
-        assertEquals("C:" + "c", FilenameUtils.normalizeNoEndSeparator("C:a/b/../../c"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("C:a/b/../../../c"));
-        assertEquals("C:" + "a", FilenameUtils.normalizeNoEndSeparator("C:a/b/.."));
-        assertEquals("C:" + "", FilenameUtils.normalizeNoEndSeparator("C:a/b/../.."));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("C:a/b/../../.."));
-        assertEquals("C:" + "a" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("C:a/b/../c/../d"));
-        assertEquals("C:" + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("C:a/b//d"));
-        assertEquals("C:" + "a" + SEP + "b", FilenameUtils.normalizeNoEndSeparator("C:a/b/././."));
-        assertEquals("C:" + "a", FilenameUtils.normalizeNoEndSeparator("C:./a"));
-        assertEquals("C:" + "", FilenameUtils.normalizeNoEndSeparator("C:./"));
-        assertEquals("C:" + "", FilenameUtils.normalizeNoEndSeparator("C:."));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("C:../a"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("C:.."));
-        assertEquals("C:" + "", FilenameUtils.normalizeNoEndSeparator("C:"));
+    @Test
+    public void testGetExtension() {
+        assertNull(FilenameUtils.getExtension(null));
+        assertEquals("ext", FilenameUtils.getExtension("file.ext"));
+        assertEquals("", FilenameUtils.getExtension("README"));
+        assertEquals("com", FilenameUtils.getExtension("domain.dot.com"));
+        assertEquals("jpeg", FilenameUtils.getExtension("image.jpeg"));
+        assertEquals("", FilenameUtils.getExtension("a.b/c"));
+        assertEquals("txt", FilenameUtils.getExtension("a.b/c.txt"));
+        assertEquals("", FilenameUtils.getExtension("a/b/c"));
+        assertEquals("", FilenameUtils.getExtension("a.b\\c"));
+        assertEquals("txt", FilenameUtils.getExtension("a.b\\c.txt"));
+        assertEquals("", FilenameUtils.getExtension("a\\b\\c"));
+        assertEquals("", FilenameUtils.getExtension("C:\\temp\\foo.bar\\README"));
+        assertEquals("ext", FilenameUtils.getExtension("../filename.ext"));
 
-        assertEquals(SEP + SEP + "server" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("//server/a"));
-        assertEquals(SEP + SEP + "server" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("//server/a/"));
-        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("//server/a/b/../c"));
-        assertEquals(SEP + SEP + "server" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("//server/a/b/../../c"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("//server/a/b/../../../c"));
-        assertEquals(SEP + SEP + "server" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("//server/a/b/.."));
-        assertEquals(SEP + SEP + "server" + SEP + "", FilenameUtils.normalizeNoEndSeparator("//server/a/b/../.."));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("//server/a/b/../../.."));
-        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("//server/a/b/../c/../d"));
-        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("//server/a/b//d"));
-        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP + "b", FilenameUtils.normalizeNoEndSeparator("//server/a/b/././."));
-        assertEquals(SEP + SEP + "server" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("//server/./a"));
-        assertEquals(SEP + SEP + "server" + SEP + "", FilenameUtils.normalizeNoEndSeparator("//server/./"));
-        assertEquals(SEP + SEP + "server" + SEP + "", FilenameUtils.normalizeNoEndSeparator("//server/."));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("//server/../a"));
-        assertNull(FilenameUtils.normalizeNoEndSeparator("//server/.."));
-        assertEquals(SEP + SEP + "server" + SEP + "", FilenameUtils.normalizeNoEndSeparator("//server/"));
+        if (FilenameUtils.isSystemWindows()) {
+            // Special case handling for NTFS ADS names
+        	try {
+        		FilenameUtils.getExtension("foo.exe:bar.txt");
+        		throw new AssertionError("Expected Exception");
+        	} catch (final IllegalArgumentException e) {
+        		assertEquals("NTFS ADS separator (':') in file name is forbidden.", e.getMessage());
+        	}
+        } else {
+        	// Upwards compatibility:
+        	assertEquals("txt", FilenameUtils.getExtension("foo.exe:bar.txt"));
+        }
     }
 
     @Test
-    public void testNormalizeNoEndSeparatorUnixWin() {
+    public void testGetFullPath() {
+        assertNull(FilenameUtils.getFullPath(null));
+        assertEquals("", FilenameUtils.getFullPath("noseperator.inthispath"));
+        assertEquals("a/b/", FilenameUtils.getFullPath("a/b/c.txt"));
+        assertEquals("a/b/", FilenameUtils.getFullPath("a/b/c"));
+        assertEquals("a/b/c/", FilenameUtils.getFullPath("a/b/c/"));
+        assertEquals("a\\b\\", FilenameUtils.getFullPath("a\\b\\c"));
 
-        // Normalize (Unix Separator)
-        assertEquals("/a/c", FilenameUtils.normalizeNoEndSeparator("/a/b/../c/", true));
-        assertEquals("/a/c", FilenameUtils.normalizeNoEndSeparator("\\a\\b\\..\\c\\", true));
+        assertNull(FilenameUtils.getFullPath(":"));
+        assertNull(FilenameUtils.getFullPath("1:/a/b/c.txt"));
+        assertNull(FilenameUtils.getFullPath("1:"));
+        assertNull(FilenameUtils.getFullPath("1:a"));
+        assertNull(FilenameUtils.getFullPath("///a/b/c.txt"));
+        assertNull(FilenameUtils.getFullPath("//a"));
 
-        // Normalize (Windows Separator)
-        assertEquals("\\a\\c", FilenameUtils.normalizeNoEndSeparator("/a/b/../c/", false));
-        assertEquals("\\a\\c", FilenameUtils.normalizeNoEndSeparator("\\a\\b\\..\\c\\", false));
+        assertEquals("", FilenameUtils.getFullPath(""));
+
+        if (SystemUtils.IS_OS_WINDOWS) {
+            assertEquals("C:", FilenameUtils.getFullPath("C:"));
+        }
+        if (SystemUtils.IS_OS_LINUX) {
+            assertEquals("", FilenameUtils.getFullPath("C:"));
+        }
+
+        assertEquals("C:/", FilenameUtils.getFullPath("C:/"));
+        assertEquals("//server/", FilenameUtils.getFullPath("//server/"));
+        assertEquals("~/", FilenameUtils.getFullPath("~"));
+        assertEquals("~/", FilenameUtils.getFullPath("~/"));
+        assertEquals("~user/", FilenameUtils.getFullPath("~user"));
+        assertEquals("~user/", FilenameUtils.getFullPath("~user/"));
+
+        assertEquals("a/b/", FilenameUtils.getFullPath("a/b/c.txt"));
+        assertEquals("/a/b/", FilenameUtils.getFullPath("/a/b/c.txt"));
+        assertEquals("C:", FilenameUtils.getFullPath("C:a"));
+        assertEquals("C:a/b/", FilenameUtils.getFullPath("C:a/b/c.txt"));
+        assertEquals("C:/a/b/", FilenameUtils.getFullPath("C:/a/b/c.txt"));
+        assertEquals("//server/a/b/", FilenameUtils.getFullPath("//server/a/b/c.txt"));
+        assertEquals("~/a/b/", FilenameUtils.getFullPath("~/a/b/c.txt"));
+        assertEquals("~user/a/b/", FilenameUtils.getFullPath("~user/a/b/c.txt"));
     }
 
     @Test
-    public void testConcat() {
-        assertNull(FilenameUtils.concat("", null));
-        assertNull(FilenameUtils.concat(null, null));
-        assertNull(FilenameUtils.concat(null, ""));
-        assertNull(FilenameUtils.concat(null, "a"));
-        assertEquals(SEP + "a", FilenameUtils.concat(null, "/a"));
+    public void testGetFullPathNoEndSeparator() {
+        assertNull(FilenameUtils.getFullPathNoEndSeparator(null));
+        assertEquals("", FilenameUtils.getFullPathNoEndSeparator("noseperator.inthispath"));
+        assertEquals("a/b", FilenameUtils.getFullPathNoEndSeparator("a/b/c.txt"));
+        assertEquals("a/b", FilenameUtils.getFullPathNoEndSeparator("a/b/c"));
+        assertEquals("a/b/c", FilenameUtils.getFullPathNoEndSeparator("a/b/c/"));
+        assertEquals("a\\b", FilenameUtils.getFullPathNoEndSeparator("a\\b\\c"));
 
-        assertNull(FilenameUtils.concat("", ":")); // invalid prefix
-        assertNull(FilenameUtils.concat(":", "")); // invalid prefix
+        assertNull(FilenameUtils.getFullPathNoEndSeparator(":"));
+        assertNull(FilenameUtils.getFullPathNoEndSeparator("1:/a/b/c.txt"));
+        assertNull(FilenameUtils.getFullPathNoEndSeparator("1:"));
+        assertNull(FilenameUtils.getFullPathNoEndSeparator("1:a"));
+        assertNull(FilenameUtils.getFullPathNoEndSeparator("///a/b/c.txt"));
+        assertNull(FilenameUtils.getFullPathNoEndSeparator("//a"));
 
-        assertEquals("f" + SEP, FilenameUtils.concat("", "f/"));
-        assertEquals("f", FilenameUtils.concat("", "f"));
-        assertEquals("a" + SEP + "f" + SEP, FilenameUtils.concat("a/", "f/"));
-        assertEquals("a" + SEP + "f", FilenameUtils.concat("a", "f"));
-        assertEquals("a" + SEP + "b" + SEP + "f" + SEP, FilenameUtils.concat("a/b/", "f/"));
-        assertEquals("a" + SEP + "b" + SEP + "f", FilenameUtils.concat("a/b", "f"));
+        assertEquals("", FilenameUtils.getFullPathNoEndSeparator(""));
 
-        assertEquals("a" + SEP + "f" + SEP, FilenameUtils.concat("a/b/", "../f/"));
-        assertEquals("a" + SEP + "f", FilenameUtils.concat("a/b", "../f"));
-        assertEquals("a" + SEP + "c" + SEP + "g" + SEP, FilenameUtils.concat("a/b/../c/", "f/../g/"));
-        assertEquals("a" + SEP + "c" + SEP + "g", FilenameUtils.concat("a/b/../c", "f/../g"));
+        if (SystemUtils.IS_OS_WINDOWS) {
+            assertEquals("C:", FilenameUtils.getFullPathNoEndSeparator("C:"));
+        }
+        if (SystemUtils.IS_OS_LINUX) {
+            assertEquals("", FilenameUtils.getFullPathNoEndSeparator("C:"));
+        }
 
-        assertEquals("a" + SEP + "c.txt" + SEP + "f", FilenameUtils.concat("a/c.txt", "f"));
+        assertEquals("C:/", FilenameUtils.getFullPathNoEndSeparator("C:/"));
+        assertEquals("//server/", FilenameUtils.getFullPathNoEndSeparator("//server/"));
+        assertEquals("~", FilenameUtils.getFullPathNoEndSeparator("~"));
+        assertEquals("~/", FilenameUtils.getFullPathNoEndSeparator("~/"));
+        assertEquals("~user", FilenameUtils.getFullPathNoEndSeparator("~user"));
+        assertEquals("~user/", FilenameUtils.getFullPathNoEndSeparator("~user/"));
 
-        assertEquals(SEP + "f" + SEP, FilenameUtils.concat("", "/f/"));
-        assertEquals(SEP + "f", FilenameUtils.concat("", "/f"));
-        assertEquals(SEP + "f" + SEP, FilenameUtils.concat("a/", "/f/"));
-        assertEquals(SEP + "f", FilenameUtils.concat("a", "/f"));
+        assertEquals("a/b", FilenameUtils.getFullPathNoEndSeparator("a/b/c.txt"));
+        assertEquals("/a/b", FilenameUtils.getFullPathNoEndSeparator("/a/b/c.txt"));
+        assertEquals("C:", FilenameUtils.getFullPathNoEndSeparator("C:a"));
+        assertEquals("C:a/b", FilenameUtils.getFullPathNoEndSeparator("C:a/b/c.txt"));
+        assertEquals("C:/a/b", FilenameUtils.getFullPathNoEndSeparator("C:/a/b/c.txt"));
+        assertEquals("//server/a/b", FilenameUtils.getFullPathNoEndSeparator("//server/a/b/c.txt"));
+        assertEquals("~/a/b", FilenameUtils.getFullPathNoEndSeparator("~/a/b/c.txt"));
+        assertEquals("~user/a/b", FilenameUtils.getFullPathNoEndSeparator("~user/a/b/c.txt"));
+    }
+
+    /**
+     * Test for https://issues.apache.org/jira/browse/IO-248
+     */
+    @Test
+    public void testGetFullPathNoEndSeparator_IO_248() {
+
+        // Test single separator
+        assertEquals("/", FilenameUtils.getFullPathNoEndSeparator("/"));
+        assertEquals("\\", FilenameUtils.getFullPathNoEndSeparator("\\"));
+
+        // Test one level directory
+        assertEquals("/", FilenameUtils.getFullPathNoEndSeparator("/abc"));
+        assertEquals("\\", FilenameUtils.getFullPathNoEndSeparator("\\abc"));
+
+        // Test one level directory
+        assertEquals("/abc", FilenameUtils.getFullPathNoEndSeparator("/abc/xyz"));
+        assertEquals("\\abc", FilenameUtils.getFullPathNoEndSeparator("\\abc\\xyz"));
+    }
+
+    @Test
+    public void testGetName() {
+        assertNull(FilenameUtils.getName(null));
+        assertEquals("noseperator.inthispath", FilenameUtils.getName("noseperator.inthispath"));
+        assertEquals("c.txt", FilenameUtils.getName("a/b/c.txt"));
+        assertEquals("c", FilenameUtils.getName("a/b/c"));
+        assertEquals("", FilenameUtils.getName("a/b/c/"));
+        assertEquals("c", FilenameUtils.getName("a\\b\\c"));
+    }
+
+    @Test
+    public void testGetPath() {
+        assertNull(FilenameUtils.getPath(null));
+        assertEquals("", FilenameUtils.getPath("noseperator.inthispath"));
+        assertEquals("", FilenameUtils.getPath("/noseperator.inthispath"));
+        assertEquals("", FilenameUtils.getPath("\\noseperator.inthispath"));
+        assertEquals("a/b/", FilenameUtils.getPath("a/b/c.txt"));
+        assertEquals("a/b/", FilenameUtils.getPath("a/b/c"));
+        assertEquals("a/b/c/", FilenameUtils.getPath("a/b/c/"));
+        assertEquals("a\\b\\", FilenameUtils.getPath("a\\b\\c"));
+
+        assertNull(FilenameUtils.getPath(":"));
+        assertNull(FilenameUtils.getPath("1:/a/b/c.txt"));
+        assertNull(FilenameUtils.getPath("1:"));
+        assertNull(FilenameUtils.getPath("1:a"));
+        assertNull(FilenameUtils.getPath("///a/b/c.txt"));
+        assertNull(FilenameUtils.getPath("//a"));
+
+        assertEquals("", FilenameUtils.getPath(""));
+        assertEquals("", FilenameUtils.getPath("C:"));
+        assertEquals("", FilenameUtils.getPath("C:/"));
+        assertEquals("", FilenameUtils.getPath("//server/"));
+        assertEquals("", FilenameUtils.getPath("~"));
+        assertEquals("", FilenameUtils.getPath("~/"));
+        assertEquals("", FilenameUtils.getPath("~user"));
+        assertEquals("", FilenameUtils.getPath("~user/"));
+
+        assertEquals("a/b/", FilenameUtils.getPath("a/b/c.txt"));
+        assertEquals("a/b/", FilenameUtils.getPath("/a/b/c.txt"));
+        assertEquals("", FilenameUtils.getPath("C:a"));
+        assertEquals("a/b/", FilenameUtils.getPath("C:a/b/c.txt"));
+        assertEquals("a/b/", FilenameUtils.getPath("C:/a/b/c.txt"));
+        assertEquals("a/b/", FilenameUtils.getPath("//server/a/b/c.txt"));
+        assertEquals("a/b/", FilenameUtils.getPath("~/a/b/c.txt"));
+        assertEquals("a/b/", FilenameUtils.getPath("~user/a/b/c.txt"));
+    }
+
+
+    @Test
+    public void testGetPath_with_nullbyte() {
+        assertThrows(IllegalArgumentException.class, () -> FilenameUtils.getPath("~user/a/\u0000b/c.txt"));
+    }
+
+    @Test
+    public void testGetPathNoEndSeparator() {
+        assertNull(FilenameUtils.getPath(null));
+        assertEquals("", FilenameUtils.getPath("noseperator.inthispath"));
+        assertEquals("", FilenameUtils.getPathNoEndSeparator("/noseperator.inthispath"));
+        assertEquals("", FilenameUtils.getPathNoEndSeparator("\\noseperator.inthispath"));
+        assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("a/b/c.txt"));
+        assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("a/b/c"));
+        assertEquals("a/b/c", FilenameUtils.getPathNoEndSeparator("a/b/c/"));
+        assertEquals("a\\b", FilenameUtils.getPathNoEndSeparator("a\\b\\c"));
+
+        assertNull(FilenameUtils.getPathNoEndSeparator(":"));
+        assertNull(FilenameUtils.getPathNoEndSeparator("1:/a/b/c.txt"));
+        assertNull(FilenameUtils.getPathNoEndSeparator("1:"));
+        assertNull(FilenameUtils.getPathNoEndSeparator("1:a"));
+        assertNull(FilenameUtils.getPathNoEndSeparator("///a/b/c.txt"));
+        assertNull(FilenameUtils.getPathNoEndSeparator("//a"));
+
+        assertEquals("", FilenameUtils.getPathNoEndSeparator(""));
+        assertEquals("", FilenameUtils.getPathNoEndSeparator("C:"));
+        assertEquals("", FilenameUtils.getPathNoEndSeparator("C:/"));
+        assertEquals("", FilenameUtils.getPathNoEndSeparator("//server/"));
+        assertEquals("", FilenameUtils.getPathNoEndSeparator("~"));
+        assertEquals("", FilenameUtils.getPathNoEndSeparator("~/"));
+        assertEquals("", FilenameUtils.getPathNoEndSeparator("~user"));
+        assertEquals("", FilenameUtils.getPathNoEndSeparator("~user/"));
+
+        assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("a/b/c.txt"));
+        assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("/a/b/c.txt"));
+        assertEquals("", FilenameUtils.getPathNoEndSeparator("C:a"));
+        assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("C:a/b/c.txt"));
+        assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("C:/a/b/c.txt"));
+        assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("//server/a/b/c.txt"));
+        assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("~/a/b/c.txt"));
+        assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("~user/a/b/c.txt"));
+    }
+
+    @Test
+    public void testGetPathNoEndSeparator_with_null_byte() {
+        try {
+            assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("~user/a\u0000/b/c.txt"));
+        } catch (final IllegalArgumentException ignore) {
+
+        }
+    }
+
+    @Test
+    public void testGetPrefix() {
+        assertNull(FilenameUtils.getPrefix(null));
+        assertNull(FilenameUtils.getPrefix(":"));
+        assertNull(FilenameUtils.getPrefix("1:\\a\\b\\c.txt"));
+        assertNull(FilenameUtils.getPrefix("1:"));
+        assertNull(FilenameUtils.getPrefix("1:a"));
+        assertNull(FilenameUtils.getPrefix("\\\\\\a\\b\\c.txt"));
+        assertNull(FilenameUtils.getPrefix("\\\\a"));
+
+        assertEquals("", FilenameUtils.getPrefix(""));
+        assertEquals("\\", FilenameUtils.getPrefix("\\"));
+
+        if (SystemUtils.IS_OS_WINDOWS) {
+            assertEquals("C:", FilenameUtils.getPrefix("C:"));
+        }
+        if (SystemUtils.IS_OS_LINUX) {
+            assertEquals("", FilenameUtils.getPrefix("C:"));
+        }
+
+        assertEquals("C:\\", FilenameUtils.getPrefix("C:\\"));
+        assertEquals("//server/", FilenameUtils.getPrefix("//server/"));
+        assertEquals("~/", FilenameUtils.getPrefix("~"));
+        assertEquals("~/", FilenameUtils.getPrefix("~/"));
+        assertEquals("~user/", FilenameUtils.getPrefix("~user"));
+        assertEquals("~user/", FilenameUtils.getPrefix("~user/"));
+
+        assertEquals("", FilenameUtils.getPrefix("a\\b\\c.txt"));
+        assertEquals("\\", FilenameUtils.getPrefix("\\a\\b\\c.txt"));
+        assertEquals("C:\\", FilenameUtils.getPrefix("C:\\a\\b\\c.txt"));
+        assertEquals("\\\\server\\", FilenameUtils.getPrefix("\\\\server\\a\\b\\c.txt"));
 
-        assertEquals(SEP + "c" + SEP + "d", FilenameUtils.concat("a/b/", "/c/d"));
-        assertEquals("C:c" + SEP + "d", FilenameUtils.concat("a/b/", "C:c/d"));
-        assertEquals("C:" + SEP + "c" + SEP + "d", FilenameUtils.concat("a/b/", "C:/c/d"));
-        assertEquals("~" + SEP + "c" + SEP + "d", FilenameUtils.concat("a/b/", "~/c/d"));
-        assertEquals("~user" + SEP + "c" + SEP + "d", FilenameUtils.concat("a/b/", "~user/c/d"));
-        assertEquals("~" + SEP, FilenameUtils.concat("a/b/", "~"));
-        assertEquals("~user" + SEP, FilenameUtils.concat("a/b/", "~user"));
-    }
+        assertEquals("", FilenameUtils.getPrefix("a/b/c.txt"));
+        assertEquals("/", FilenameUtils.getPrefix("/a/b/c.txt"));
+        assertEquals("C:/", FilenameUtils.getPrefix("C:/a/b/c.txt"));
+        assertEquals("//server/", FilenameUtils.getPrefix("//server/a/b/c.txt"));
+        assertEquals("~/", FilenameUtils.getPrefix("~/a/b/c.txt"));
+        assertEquals("~user/", FilenameUtils.getPrefix("~user/a/b/c.txt"));
 
-    @Test
-    public void testSeparatorsToUnix() {
-        assertNull(FilenameUtils.separatorsToUnix(null));
-        assertEquals("/a/b/c", FilenameUtils.separatorsToUnix("/a/b/c"));
-        assertEquals("/a/b/c.txt", FilenameUtils.separatorsToUnix("/a/b/c.txt"));
-        assertEquals("/a/b/c", FilenameUtils.separatorsToUnix("/a/b\\c"));
-        assertEquals("/a/b/c", FilenameUtils.separatorsToUnix("\\a\\b\\c"));
-        assertEquals("D:/a/b/c", FilenameUtils.separatorsToUnix("D:\\a\\b\\c"));
+        assertEquals("", FilenameUtils.getPrefix("a\\b\\c.txt"));
+        assertEquals("\\", FilenameUtils.getPrefix("\\a\\b\\c.txt"));
+        assertEquals("~\\", FilenameUtils.getPrefix("~\\a\\b\\c.txt"));
+        assertEquals("~user\\", FilenameUtils.getPrefix("~user\\a\\b\\c.txt"));
     }
 
     @Test
-    public void testSeparatorsToWindows() {
-        assertNull(FilenameUtils.separatorsToWindows(null));
-        assertEquals("\\a\\b\\c", FilenameUtils.separatorsToWindows("\\a\\b\\c"));
-        assertEquals("\\a\\b\\c.txt", FilenameUtils.separatorsToWindows("\\a\\b\\c.txt"));
-        assertEquals("\\a\\b\\c", FilenameUtils.separatorsToWindows("\\a\\b/c"));
-        assertEquals("\\a\\b\\c", FilenameUtils.separatorsToWindows("/a/b/c"));
-        assertEquals("D:\\a\\b\\c", FilenameUtils.separatorsToWindows("D:/a/b/c"));
-    }
+    public void testGetPrefix_with_nullbyte() {
+        try {
+            assertEquals("~user\\", FilenameUtils.getPrefix("~u\u0000ser\\a\\b\\c.txt"));
+        } catch (final IllegalArgumentException ignore) {
 
-    @Test
-    public void testSeparatorsToSystem() {
-        if (WINDOWS) {
-            assertNull(FilenameUtils.separatorsToSystem(null));
-            assertEquals("\\a\\b\\c", FilenameUtils.separatorsToSystem("\\a\\b\\c"));
-            assertEquals("\\a\\b\\c.txt", FilenameUtils.separatorsToSystem("\\a\\b\\c.txt"));
-            assertEquals("\\a\\b\\c", FilenameUtils.separatorsToSystem("\\a\\b/c"));
-            assertEquals("\\a\\b\\c", FilenameUtils.separatorsToSystem("/a/b/c"));
-            assertEquals("D:\\a\\b\\c", FilenameUtils.separatorsToSystem("D:/a/b/c"));
-        } else {
-            assertNull(FilenameUtils.separatorsToSystem(null));
-            assertEquals("/a/b/c", FilenameUtils.separatorsToSystem("/a/b/c"));
-            assertEquals("/a/b/c.txt", FilenameUtils.separatorsToSystem("/a/b/c.txt"));
-            assertEquals("/a/b/c", FilenameUtils.separatorsToSystem("/a/b\\c"));
-            assertEquals("/a/b/c", FilenameUtils.separatorsToSystem("\\a\\b\\c"));
-            assertEquals("D:/a/b/c", FilenameUtils.separatorsToSystem("D:\\a\\b\\c"));
         }
     }
 
@@ -609,14 +587,6 @@ public class FilenameUtilsTestCase {
     }
 
     @Test
-    public void testIndexOfLastSeparator() {
-        assertEquals(-1, FilenameUtils.indexOfLastSeparator(null));
-        assertEquals(-1, FilenameUtils.indexOfLastSeparator("noseperator.inthispath"));
-        assertEquals(3, FilenameUtils.indexOfLastSeparator("a/b/c"));
-        assertEquals(3, FilenameUtils.indexOfLastSeparator("a\\b\\c"));
-    }
-
-    @Test
     public void testIndexOfExtension() {
         assertEquals(-1, FilenameUtils.indexOfExtension(null));
         assertEquals(-1, FilenameUtils.indexOfExtension("file"));
@@ -643,318 +613,537 @@ public class FilenameUtilsTestCase {
     }
 
     @Test
-    public void testGetPrefix() {
-        assertNull(FilenameUtils.getPrefix(null));
-        assertNull(FilenameUtils.getPrefix(":"));
-        assertNull(FilenameUtils.getPrefix("1:\\a\\b\\c.txt"));
-        assertNull(FilenameUtils.getPrefix("1:"));
-        assertNull(FilenameUtils.getPrefix("1:a"));
-        assertNull(FilenameUtils.getPrefix("\\\\\\a\\b\\c.txt"));
-        assertNull(FilenameUtils.getPrefix("\\\\a"));
+    public void testIndexOfLastSeparator() {
+        assertEquals(-1, FilenameUtils.indexOfLastSeparator(null));
+        assertEquals(-1, FilenameUtils.indexOfLastSeparator("noseperator.inthispath"));
+        assertEquals(3, FilenameUtils.indexOfLastSeparator("a/b/c"));
+        assertEquals(3, FilenameUtils.indexOfLastSeparator("a\\b\\c"));
+    }
 
-        assertEquals("", FilenameUtils.getPrefix(""));
-        assertEquals("\\", FilenameUtils.getPrefix("\\"));
+    @Test
+    public void testInjectionFailure() {
+        try {
+            assertEquals("c", FilenameUtils.getName("a\\b\\\u0000c"));
+        } catch (final IllegalArgumentException ignore) {
 
-        if (SystemUtils.IS_OS_WINDOWS) {
-            assertEquals("C:", FilenameUtils.getPrefix("C:"));
-        }
-        if (SystemUtils.IS_OS_LINUX) {
-            assertEquals("", FilenameUtils.getPrefix("C:"));
         }
+    }
 
-        assertEquals("C:\\", FilenameUtils.getPrefix("C:\\"));
-        assertEquals("//server/", FilenameUtils.getPrefix("//server/"));
-        assertEquals("~/", FilenameUtils.getPrefix("~"));
-        assertEquals("~/", FilenameUtils.getPrefix("~/"));
-        assertEquals("~user/", FilenameUtils.getPrefix("~user"));
-        assertEquals("~user/", FilenameUtils.getPrefix("~user/"));
+    @Test
+    public void testIsExtension() {
+        assertFalse(FilenameUtils.isExtension(null, (String) null));
+        assertFalse(FilenameUtils.isExtension("file.txt", (String) null));
+        assertTrue(FilenameUtils.isExtension("file", (String) null));
+        assertFalse(FilenameUtils.isExtension("file.txt", ""));
+        assertTrue(FilenameUtils.isExtension("file", ""));
+        assertTrue(FilenameUtils.isExtension("file.txt", "txt"));
+        assertFalse(FilenameUtils.isExtension("file.txt", "rtf"));
 
-        assertEquals("", FilenameUtils.getPrefix("a\\b\\c.txt"));
-        assertEquals("\\", FilenameUtils.getPrefix("\\a\\b\\c.txt"));
-        assertEquals("C:\\", FilenameUtils.getPrefix("C:\\a\\b\\c.txt"));
-        assertEquals("\\\\server\\", FilenameUtils.getPrefix("\\\\server\\a\\b\\c.txt"));
+        assertFalse(FilenameUtils.isExtension("a/b/file.txt", (String) null));
+        assertFalse(FilenameUtils.isExtension("a/b/file.txt", ""));
+        assertTrue(FilenameUtils.isExtension("a/b/file.txt", "txt"));
+        assertFalse(FilenameUtils.isExtension("a/b/file.txt", "rtf"));
 
-        assertEquals("", FilenameUtils.getPrefix("a/b/c.txt"));
-        assertEquals("/", FilenameUtils.getPrefix("/a/b/c.txt"));
-        assertEquals("C:/", FilenameUtils.getPrefix("C:/a/b/c.txt"));
-        assertEquals("//server/", FilenameUtils.getPrefix("//server/a/b/c.txt"));
-        assertEquals("~/", FilenameUtils.getPrefix("~/a/b/c.txt"));
-        assertEquals("~user/", FilenameUtils.getPrefix("~user/a/b/c.txt"));
+        assertFalse(FilenameUtils.isExtension("a.b/file.txt", (String) null));
+        assertFalse(FilenameUtils.isExtension("a.b/file.txt", ""));
+        assertTrue(FilenameUtils.isExtension("a.b/file.txt", "txt"));
+        assertFalse(FilenameUtils.isExtension("a.b/file.txt", "rtf"));
 
-        assertEquals("", FilenameUtils.getPrefix("a\\b\\c.txt"));
-        assertEquals("\\", FilenameUtils.getPrefix("\\a\\b\\c.txt"));
-        assertEquals("~\\", FilenameUtils.getPrefix("~\\a\\b\\c.txt"));
-        assertEquals("~user\\", FilenameUtils.getPrefix("~user\\a\\b\\c.txt"));
+        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt", (String) null));
+        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt", ""));
+        assertTrue(FilenameUtils.isExtension("a\\b\\file.txt", "txt"));
+        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt", "rtf"));
+
+        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", (String) null));
+        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", ""));
+        assertTrue(FilenameUtils.isExtension("a.b\\file.txt", "txt"));
+        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", "rtf"));
+
+        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", "TXT"));
     }
 
     @Test
-    public void testGetPrefix_with_nullbyte() {
+    public void testIsExtension_injection() {
         try {
-            assertEquals("~user\\", FilenameUtils.getPrefix("~u\u0000ser\\a\\b\\c.txt"));
+            FilenameUtils.isExtension("a.b\\fi\u0000le.txt", "TXT");
+            fail("Should throw IAE");
         } catch (final IllegalArgumentException ignore) {
-
         }
     }
 
     @Test
-    public void testGetPath() {
-        assertNull(FilenameUtils.getPath(null));
-        assertEquals("", FilenameUtils.getPath("noseperator.inthispath"));
-        assertEquals("", FilenameUtils.getPath("/noseperator.inthispath"));
-        assertEquals("", FilenameUtils.getPath("\\noseperator.inthispath"));
-        assertEquals("a/b/", FilenameUtils.getPath("a/b/c.txt"));
-        assertEquals("a/b/", FilenameUtils.getPath("a/b/c"));
-        assertEquals("a/b/c/", FilenameUtils.getPath("a/b/c/"));
-        assertEquals("a\\b\\", FilenameUtils.getPath("a\\b\\c"));
+    public void testIsExtensionArray() {
+        assertFalse(FilenameUtils.isExtension(null, (String[]) null));
+        assertFalse(FilenameUtils.isExtension("file.txt", (String[]) null));
+        assertTrue(FilenameUtils.isExtension("file", (String[]) null));
+        assertFalse(FilenameUtils.isExtension("file.txt"));
+        assertTrue(FilenameUtils.isExtension("file.txt", new String[]{"txt"}));
+        assertFalse(FilenameUtils.isExtension("file.txt", new String[]{"rtf"}));
+        assertTrue(FilenameUtils.isExtension("file", "rtf", ""));
+        assertTrue(FilenameUtils.isExtension("file.txt", "rtf", "txt"));
 
-        assertNull(FilenameUtils.getPath(":"));
-        assertNull(FilenameUtils.getPath("1:/a/b/c.txt"));
-        assertNull(FilenameUtils.getPath("1:"));
-        assertNull(FilenameUtils.getPath("1:a"));
-        assertNull(FilenameUtils.getPath("///a/b/c.txt"));
-        assertNull(FilenameUtils.getPath("//a"));
+        assertFalse(FilenameUtils.isExtension("a/b/file.txt", (String[]) null));
+        assertFalse(FilenameUtils.isExtension("a/b/file.txt"));
+        assertTrue(FilenameUtils.isExtension("a/b/file.txt", new String[]{"txt"}));
+        assertFalse(FilenameUtils.isExtension("a/b/file.txt", new String[]{"rtf"}));
+        assertTrue(FilenameUtils.isExtension("a/b/file.txt", "rtf", "txt"));
 
-        assertEquals("", FilenameUtils.getPath(""));
-        assertEquals("", FilenameUtils.getPath("C:"));
-        assertEquals("", FilenameUtils.getPath("C:/"));
-        assertEquals("", FilenameUtils.getPath("//server/"));
-        assertEquals("", FilenameUtils.getPath("~"));
-        assertEquals("", FilenameUtils.getPath("~/"));
-        assertEquals("", FilenameUtils.getPath("~user"));
-        assertEquals("", FilenameUtils.getPath("~user/"));
+        assertFalse(FilenameUtils.isExtension("a.b/file.txt", (String[]) null));
+        assertFalse(FilenameUtils.isExtension("a.b/file.txt"));
+        assertTrue(FilenameUtils.isExtension("a.b/file.txt", new String[]{"txt"}));
+        assertFalse(FilenameUtils.isExtension("a.b/file.txt", new String[]{"rtf"}));
+        assertTrue(FilenameUtils.isExtension("a.b/file.txt", "rtf", "txt"));
 
-        assertEquals("a/b/", FilenameUtils.getPath("a/b/c.txt"));
-        assertEquals("a/b/", FilenameUtils.getPath("/a/b/c.txt"));
-        assertEquals("", FilenameUtils.getPath("C:a"));
-        assertEquals("a/b/", FilenameUtils.getPath("C:a/b/c.txt"));
-        assertEquals("a/b/", FilenameUtils.getPath("C:/a/b/c.txt"));
-        assertEquals("a/b/", FilenameUtils.getPath("//server/a/b/c.txt"));
-        assertEquals("a/b/", FilenameUtils.getPath("~/a/b/c.txt"));
-        assertEquals("a/b/", FilenameUtils.getPath("~user/a/b/c.txt"));
-    }
+        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt", (String[]) null));
+        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt"));
+        assertTrue(FilenameUtils.isExtension("a\\b\\file.txt", new String[]{"txt"}));
+        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt", new String[]{"rtf"}));
+        assertTrue(FilenameUtils.isExtension("a\\b\\file.txt", "rtf", "txt"));
 
-    @Test
-    public void testGetPath_with_nullbyte() {
-        assertThrows(IllegalArgumentException.class, () -> FilenameUtils.getPath("~user/a/\u0000b/c.txt"));
-    }
+        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", (String[]) null));
+        assertFalse(FilenameUtils.isExtension("a.b\\file.txt"));
+        assertTrue(FilenameUtils.isExtension("a.b\\file.txt", new String[]{"txt"}));
+        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", new String[]{"rtf"}));
+        assertTrue(FilenameUtils.isExtension("a.b\\file.txt", "rtf", "txt"));
 
+        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", new String[]{"TXT"}));
+        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", "TXT", "RTF"));
+    }
 
     @Test
-    public void testGetPathNoEndSeparator() {
-        assertNull(FilenameUtils.getPath(null));
-        assertEquals("", FilenameUtils.getPath("noseperator.inthispath"));
-        assertEquals("", FilenameUtils.getPathNoEndSeparator("/noseperator.inthispath"));
-        assertEquals("", FilenameUtils.getPathNoEndSeparator("\\noseperator.inthispath"));
-        assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("a/b/c.txt"));
-        assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("a/b/c"));
-        assertEquals("a/b/c", FilenameUtils.getPathNoEndSeparator("a/b/c/"));
-        assertEquals("a\\b", FilenameUtils.getPathNoEndSeparator("a\\b\\c"));
+    public void testIsExtensionCollection() {
+        assertFalse(FilenameUtils.isExtension(null, (Collection<String>) null));
+        assertFalse(FilenameUtils.isExtension("file.txt", (Collection<String>) null));
+        assertTrue(FilenameUtils.isExtension("file", (Collection<String>) null));
+        assertFalse(FilenameUtils.isExtension("file.txt", new ArrayList<>()));
+        assertTrue(FilenameUtils.isExtension("file.txt", new ArrayList<>(Arrays.asList("txt"))));
+        assertFalse(FilenameUtils.isExtension("file.txt", new ArrayList<>(Arrays.asList("rtf"))));
+        assertTrue(FilenameUtils.isExtension("file", new ArrayList<>(Arrays.asList("rtf", ""))));
+        assertTrue(FilenameUtils.isExtension("file.txt", new ArrayList<>(Arrays.asList("rtf", "txt"))));
 
-        assertNull(FilenameUtils.getPathNoEndSeparator(":"));
-        assertNull(FilenameUtils.getPathNoEndSeparator("1:/a/b/c.txt"));
-        assertNull(FilenameUtils.getPathNoEndSeparator("1:"));
-        assertNull(FilenameUtils.getPathNoEndSeparator("1:a"));
-        assertNull(FilenameUtils.getPathNoEndSeparator("///a/b/c.txt"));
-        assertNull(FilenameUtils.getPathNoEndSeparator("//a"));
+        assertFalse(FilenameUtils.isExtension("a/b/file.txt", (Collection<String>) null));
+        assertFalse(FilenameUtils.isExtension("a/b/file.txt", new ArrayList<>()));
+        assertTrue(FilenameUtils.isExtension("a/b/file.txt", new ArrayList<>(Arrays.asList("txt"))));
+        assertFalse(FilenameUtils.isExtension("a/b/file.txt", new ArrayList<>(Arrays.asList("rtf"))));
+        assertTrue(FilenameUtils.isExtension("a/b/file.txt", new ArrayList<>(Arrays.asList("rtf", "txt"))));
 
-        assertEquals("", FilenameUtils.getPathNoEndSeparator(""));
-        assertEquals("", FilenameUtils.getPathNoEndSeparator("C:"));
-        assertEquals("", FilenameUtils.getPathNoEndSeparator("C:/"));
-        assertEquals("", FilenameUtils.getPathNoEndSeparator("//server/"));
-        assertEquals("", FilenameUtils.getPathNoEndSeparator("~"));
-        assertEquals("", FilenameUtils.getPathNoEndSeparator("~/"));
-        assertEquals("", FilenameUtils.getPathNoEndSeparator("~user"));
-        assertEquals("", FilenameUtils.getPathNoEndSeparator("~user/"));
+        assertFalse(FilenameUtils.isExtension("a.b/file.txt", (Collection<String>) null));
+        assertFalse(FilenameUtils.isExtension("a.b/file.txt", new ArrayList<>()));
+        assertTrue(FilenameUtils.isExtension("a.b/file.txt", new ArrayList<>(Arrays.asList("txt"))));
+        assertFalse(FilenameUtils.isExtension("a.b/file.txt", new ArrayList<>(Arrays.asList("rtf"))));
+        assertTrue(FilenameUtils.isExtension("a.b/file.txt", new ArrayList<>(Arrays.asList("rtf", "txt"))));
 
-        assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("a/b/c.txt"));
-        assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("/a/b/c.txt"));
-        assertEquals("", FilenameUtils.getPathNoEndSeparator("C:a"));
-        assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("C:a/b/c.txt"));
-        assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("C:/a/b/c.txt"));
-        assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("//server/a/b/c.txt"));
-        assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("~/a/b/c.txt"));
-        assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("~user/a/b/c.txt"));
-    }
+        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt", (Collection<String>) null));
+        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt", new ArrayList<>()));
+        assertTrue(FilenameUtils.isExtension("a\\b\\file.txt", new ArrayList<>(Arrays.asList("txt"))));
+        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt", new ArrayList<>(Arrays.asList("rtf"))));
+        assertTrue(FilenameUtils.isExtension("a\\b\\file.txt", new ArrayList<>(Arrays.asList("rtf", "txt"))));
 
-    @Test
-    public void testGetPathNoEndSeparator_with_null_byte() {
-        try {
-            assertEquals("a/b", FilenameUtils.getPathNoEndSeparator("~user/a\u0000/b/c.txt"));
-        } catch (final IllegalArgumentException ignore) {
+        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", (Collection<String>) null));
+        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", new ArrayList<>()));
+        assertTrue(FilenameUtils.isExtension("a.b\\file.txt", new ArrayList<>(Arrays.asList("txt"))));
+        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", new ArrayList<>(Arrays.asList("rtf"))));
+        assertTrue(FilenameUtils.isExtension("a.b\\file.txt", new ArrayList<>(Arrays.asList("rtf", "txt"))));
 
-        }
+        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", new ArrayList<>(Arrays.asList("TXT"))));
+        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", new ArrayList<>(Arrays.asList("TXT", "RTF"))));
     }
 
     @Test
-    public void testGetFullPath() {
-        assertNull(FilenameUtils.getFullPath(null));
-        assertEquals("", FilenameUtils.getFullPath("noseperator.inthispath"));
-        assertEquals("a/b/", FilenameUtils.getFullPath("a/b/c.txt"));
-        assertEquals("a/b/", FilenameUtils.getFullPath("a/b/c"));
-        assertEquals("a/b/c/", FilenameUtils.getFullPath("a/b/c/"));
-        assertEquals("a\\b\\", FilenameUtils.getFullPath("a\\b\\c"));
+    public void testIsExtensionVarArgs() {
+        assertTrue(FilenameUtils.isExtension("file.txt", "txt"));
+        assertFalse(FilenameUtils.isExtension("file.txt", "rtf"));
+        assertTrue(FilenameUtils.isExtension("file", "rtf", ""));
+        assertTrue(FilenameUtils.isExtension("file.txt", "rtf", "txt"));
 
-        assertNull(FilenameUtils.getFullPath(":"));
-        assertNull(FilenameUtils.getFullPath("1:/a/b/c.txt"));
-        assertNull(FilenameUtils.getFullPath("1:"));
-        assertNull(FilenameUtils.getFullPath("1:a"));
-        assertNull(FilenameUtils.getFullPath("///a/b/c.txt"));
-        assertNull(FilenameUtils.getFullPath("//a"));
+        assertTrue(FilenameUtils.isExtension("a/b/file.txt", "txt"));
+        assertFalse(FilenameUtils.isExtension("a/b/file.txt", "rtf"));
+        assertTrue(FilenameUtils.isExtension("a/b/file.txt", "rtf", "txt"));
 
-        assertEquals("", FilenameUtils.getFullPath(""));
+        assertTrue(FilenameUtils.isExtension("a.b/file.txt", "txt"));
+        assertFalse(FilenameUtils.isExtension("a.b/file.txt", "rtf"));
+        assertTrue(FilenameUtils.isExtension("a.b/file.txt", "rtf", "txt"));
 
-        if (SystemUtils.IS_OS_WINDOWS) {
-            assertEquals("C:", FilenameUtils.getFullPath("C:"));
-        }
-        if (SystemUtils.IS_OS_LINUX) {
-            assertEquals("", FilenameUtils.getFullPath("C:"));
-        }
+        assertTrue(FilenameUtils.isExtension("a\\b\\file.txt", "txt"));
+        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt", "rtf"));
+        assertTrue(FilenameUtils.isExtension("a\\b\\file.txt", "rtf", "txt"));
 
-        assertEquals("C:/", FilenameUtils.getFullPath("C:/"));
-        assertEquals("//server/", FilenameUtils.getFullPath("//server/"));
-        assertEquals("~/", FilenameUtils.getFullPath("~"));
-        assertEquals("~/", FilenameUtils.getFullPath("~/"));
-        assertEquals("~user/", FilenameUtils.getFullPath("~user"));
-        assertEquals("~user/", FilenameUtils.getFullPath("~user/"));
+        assertTrue(FilenameUtils.isExtension("a.b\\file.txt", "txt"));
+        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", "rtf"));
+        assertTrue(FilenameUtils.isExtension("a.b\\file.txt", "rtf", "txt"));
 
-        assertEquals("a/b/", FilenameUtils.getFullPath("a/b/c.txt"));
-        assertEquals("/a/b/", FilenameUtils.getFullPath("/a/b/c.txt"));
-        assertEquals("C:", FilenameUtils.getFullPath("C:a"));
-        assertEquals("C:a/b/", FilenameUtils.getFullPath("C:a/b/c.txt"));
-        assertEquals("C:/a/b/", FilenameUtils.getFullPath("C:/a/b/c.txt"));
-        assertEquals("//server/a/b/", FilenameUtils.getFullPath("//server/a/b/c.txt"));
-        assertEquals("~/a/b/", FilenameUtils.getFullPath("~/a/b/c.txt"));
-        assertEquals("~user/a/b/", FilenameUtils.getFullPath("~user/a/b/c.txt"));
+        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", "TXT"));
+        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", "TXT", "RTF"));
     }
 
     @Test
-    public void testGetFullPathNoEndSeparator() {
-        assertNull(FilenameUtils.getFullPathNoEndSeparator(null));
-        assertEquals("", FilenameUtils.getFullPathNoEndSeparator("noseperator.inthispath"));
-        assertEquals("a/b", FilenameUtils.getFullPathNoEndSeparator("a/b/c.txt"));
-        assertEquals("a/b", FilenameUtils.getFullPathNoEndSeparator("a/b/c"));
-        assertEquals("a/b/c", FilenameUtils.getFullPathNoEndSeparator("a/b/c/"));
-        assertEquals("a\\b", FilenameUtils.getFullPathNoEndSeparator("a\\b\\c"));
+    public void testNormalize() {
+        assertNull(FilenameUtils.normalize(null));
+        assertNull(FilenameUtils.normalize(":"));
+        assertNull(FilenameUtils.normalize("1:\\a\\b\\c.txt"));
+        assertNull(FilenameUtils.normalize("1:"));
+        assertNull(FilenameUtils.normalize("1:a"));
+        assertNull(FilenameUtils.normalize("\\\\\\a\\b\\c.txt"));
+        assertNull(FilenameUtils.normalize("\\\\a"));
 
-        assertNull(FilenameUtils.getFullPathNoEndSeparator(":"));
-        assertNull(FilenameUtils.getFullPathNoEndSeparator("1:/a/b/c.txt"));
-        assertNull(FilenameUtils.getFullPathNoEndSeparator("1:"));
-        assertNull(FilenameUtils.getFullPathNoEndSeparator("1:a"));
-        assertNull(FilenameUtils.getFullPathNoEndSeparator("///a/b/c.txt"));
-        assertNull(FilenameUtils.getFullPathNoEndSeparator("//a"));
+        assertEquals("a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("a\\b/c.txt"));
+        assertEquals("" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("\\a\\b/c.txt"));
+        assertEquals("C:" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("C:\\a\\b/c.txt"));
+        assertEquals("" + SEP + "" + SEP + "server" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("\\\\server\\a\\b/c.txt"));
+        assertEquals("~" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("~\\a\\b/c.txt"));
+        assertEquals("~user" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("~user\\a\\b/c.txt"));
 
-        assertEquals("", FilenameUtils.getFullPathNoEndSeparator(""));
+        assertEquals("a" + SEP + "c", FilenameUtils.normalize("a/b/../c"));
+        assertEquals("c", FilenameUtils.normalize("a/b/../../c"));
+        assertEquals("c" + SEP, FilenameUtils.normalize("a/b/../../c/"));
+        assertNull(FilenameUtils.normalize("a/b/../../../c"));
+        assertEquals("a" + SEP, FilenameUtils.normalize("a/b/.."));
+        assertEquals("a" + SEP, FilenameUtils.normalize("a/b/../"));
+        assertEquals("", FilenameUtils.normalize("a/b/../.."));
+        assertEquals("", FilenameUtils.normalize("a/b/../../"));
+        assertNull(FilenameUtils.normalize("a/b/../../.."));
+        assertEquals("a" + SEP + "d", FilenameUtils.normalize("a/b/../c/../d"));
+        assertEquals("a" + SEP + "d" + SEP, FilenameUtils.normalize("a/b/../c/../d/"));
+        assertEquals("a" + SEP + "b" + SEP + "d", FilenameUtils.normalize("a/b//d"));
+        assertEquals("a" + SEP + "b" + SEP, FilenameUtils.normalize("a/b/././."));
+        assertEquals("a" + SEP + "b" + SEP, FilenameUtils.normalize("a/b/./././"));
+        assertEquals("a" + SEP, FilenameUtils.normalize("./a/"));
+        assertEquals("a", FilenameUtils.normalize("./a"));
+        assertEquals("", FilenameUtils.normalize("./"));
+        assertEquals("", FilenameUtils.normalize("."));
+        assertNull(FilenameUtils.normalize("../a"));
+        assertNull(FilenameUtils.normalize(".."));
+        assertEquals("", FilenameUtils.normalize(""));
 
-        if (SystemUtils.IS_OS_WINDOWS) {
-            assertEquals("C:", FilenameUtils.getFullPathNoEndSeparator("C:"));
-        }
-        if (SystemUtils.IS_OS_LINUX) {
-            assertEquals("", FilenameUtils.getFullPathNoEndSeparator("C:"));
-        }
+        assertEquals(SEP + "a", FilenameUtils.normalize("/a"));
+        assertEquals(SEP + "a" + SEP, FilenameUtils.normalize("/a/"));
+        assertEquals(SEP + "a" + SEP + "c", FilenameUtils.normalize("/a/b/../c"));
+        assertEquals(SEP + "c", FilenameUtils.normalize("/a/b/../../c"));
+        assertNull(FilenameUtils.normalize("/a/b/../../../c"));
+        assertEquals(SEP + "a" + SEP, FilenameUtils.normalize("/a/b/.."));
+        assertEquals(SEP + "", FilenameUtils.normalize("/a/b/../.."));
+        assertNull(FilenameUtils.normalize("/a/b/../../.."));
+        assertEquals(SEP + "a" + SEP + "d", FilenameUtils.normalize("/a/b/../c/../d"));
+        assertEquals(SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalize("/a/b//d"));
+        assertEquals(SEP + "a" + SEP + "b" + SEP, FilenameUtils.normalize("/a/b/././."));
+        assertEquals(SEP + "a", FilenameUtils.normalize("/./a"));
+        assertEquals(SEP + "", FilenameUtils.normalize("/./"));
+        assertEquals(SEP + "", FilenameUtils.normalize("/."));
+        assertNull(FilenameUtils.normalize("/../a"));
+        assertNull(FilenameUtils.normalize("/.."));
+        assertEquals(SEP + "", FilenameUtils.normalize("/"));
 
-        assertEquals("C:/", FilenameUtils.getFullPathNoEndSeparator("C:/"));
-        assertEquals("//server/", FilenameUtils.getFullPathNoEndSeparator("//server/"));
-        assertEquals("~", FilenameUtils.getFullPathNoEndSeparator("~"));
-        assertEquals("~/", FilenameUtils.getFullPathNoEndSeparator("~/"));
-        assertEquals("~user", FilenameUtils.getFullPathNoEndSeparator("~user"));
-        assertEquals("~user/", FilenameUtils.getFullPathNoEndSeparator("~user/"));
+        assertEquals("~" + SEP + "a", FilenameUtils.normalize("~/a"));
+        assertEquals("~" + SEP + "a" + SEP, FilenameUtils.normalize("~/a/"));
+        assertEquals("~" + SEP + "a" + SEP + "c", FilenameUtils.normalize("~/a/b/../c"));
+        assertEquals("~" + SEP + "c", FilenameUtils.normalize("~/a/b/../../c"));
+        assertNull(FilenameUtils.normalize("~/a/b/../../../c"));
+        assertEquals("~" + SEP + "a" + SEP, FilenameUtils.normalize("~/a/b/.."));
+        assertEquals("~" + SEP + "", FilenameUtils.normalize("~/a/b/../.."));
+        assertNull(FilenameUtils.normalize("~/a/b/../../.."));
+        assertEquals("~" + SEP + "a" + SEP + "d", FilenameUtils.normalize("~/a/b/../c/../d"));
+        assertEquals("~" + SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalize("~/a/b//d"));
+        assertEquals("~" + SEP + "a" + SEP + "b" + SEP, FilenameUtils.normalize("~/a/b/././."));
+        assertEquals("~" + SEP + "a", FilenameUtils.normalize("~/./a"));
+        assertEquals("~" + SEP, FilenameUtils.normalize("~/./"));
+        assertEquals("~" + SEP, FilenameUtils.normalize("~/."));
+        assertNull(FilenameUtils.normalize("~/../a"));
+        assertNull(FilenameUtils.normalize("~/.."));
+        assertEquals("~" + SEP, FilenameUtils.normalize("~/"));
+        assertEquals("~" + SEP, FilenameUtils.normalize("~"));
 
-        assertEquals("a/b", FilenameUtils.getFullPathNoEndSeparator("a/b/c.txt"));
-        assertEquals("/a/b", FilenameUtils.getFullPathNoEndSeparator("/a/b/c.txt"));
-        assertEquals("C:", FilenameUtils.getFullPathNoEndSeparator("C:a"));
-        assertEquals("C:a/b", FilenameUtils.getFullPathNoEndSeparator("C:a/b/c.txt"));
-        assertEquals("C:/a/b", FilenameUtils.getFullPathNoEndSeparator("C:/a/b/c.txt"));
-        assertEquals("//server/a/b", FilenameUtils.getFullPathNoEndSeparator("//server/a/b/c.txt"));
-        assertEquals("~/a/b", FilenameUtils.getFullPathNoEndSeparator("~/a/b/c.txt"));
-        assertEquals("~user/a/b", FilenameUtils.getFullPathNoEndSeparator("~user/a/b/c.txt"));
-    }
+        assertEquals("~user" + SEP + "a", FilenameUtils.normalize("~user/a"));
+        assertEquals("~user" + SEP + "a" + SEP, FilenameUtils.normalize("~user/a/"));
+        assertEquals("~user" + SEP + "a" + SEP + "c", FilenameUtils.normalize("~user/a/b/../c"));
+        assertEquals("~user" + SEP + "c", FilenameUtils.normalize("~user/a/b/../../c"));
+        assertNull(FilenameUtils.normalize("~user/a/b/../../../c"));
+        assertEquals("~user" + SEP + "a" + SEP, FilenameUtils.normalize("~user/a/b/.."));
+        assertEquals("~user" + SEP + "", FilenameUtils.normalize("~user/a/b/../.."));
+        assertNull(FilenameUtils.normalize("~user/a/b/../../.."));
+        assertEquals("~user" + SEP + "a" + SEP + "d", FilenameUtils.normalize("~user/a/b/../c/../d"));
+        assertEquals("~user" + SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalize("~user/a/b//d"));
+        assertEquals("~user" + SEP + "a" + SEP + "b" + SEP, FilenameUtils.normalize("~user/a/b/././."));
+        assertEquals("~user" + SEP + "a", FilenameUtils.normalize("~user/./a"));
+        assertEquals("~user" + SEP + "", FilenameUtils.normalize("~user/./"));
+        assertEquals("~user" + SEP + "", FilenameUtils.normalize("~user/."));
+        assertNull(FilenameUtils.normalize("~user/../a"));
+        assertNull(FilenameUtils.normalize("~user/.."));
+        assertEquals("~user" + SEP, FilenameUtils.normalize("~user/"));
+        assertEquals("~user" + SEP, FilenameUtils.normalize("~user"));
 
-    /**
-     * Test for https://issues.apache.org/jira/browse/IO-248
-     */
-    @Test
-    public void testGetFullPathNoEndSeparator_IO_248() {
+        assertEquals("C:" + SEP + "a", FilenameUtils.normalize("C:/a"));
+        assertEquals("C:" + SEP + "a" + SEP, FilenameUtils.normalize("C:/a/"));
+        assertEquals("C:" + SEP + "a" + SEP + "c", FilenameUtils.normalize("C:/a/b/../c"));
+        assertEquals("C:" + SEP + "c", FilenameUtils.normalize("C:/a/b/../../c"));
+        assertNull(FilenameUtils.normalize("C:/a/b/../../../c"));
+        assertEquals("C:" + SEP + "a" + SEP, FilenameUtils.normalize("C:/a/b/.."));
+        assertEquals("C:" + SEP + "", FilenameUtils.normalize("C:/a/b/../.."));
+        assertNull(FilenameUtils.normalize("C:/a/b/../../.."));
+        assertEquals("C:" + SEP + "a" + SEP + "d", FilenameUtils.normalize("C:/a/b/../c/../d"));
+        assertEquals("C:" + SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalize("C:/a/b//d"));
+        assertEquals("C:" + SEP + "a" + SEP + "b" + SEP, FilenameUtils.normalize("C:/a/b/././."));
+        assertEquals("C:" + SEP + "a", FilenameUtils.normalize("C:/./a"));
+        assertEquals("C:" + SEP + "", FilenameUtils.normalize("C:/./"));
+        assertEquals("C:" + SEP + "", FilenameUtils.normalize("C:/."));
+        assertNull(FilenameUtils.normalize("C:/../a"));
+        assertNull(FilenameUtils.normalize("C:/.."));
+        assertEquals("C:" + SEP + "", FilenameUtils.normalize("C:/"));
 
-        // Test single separator
-        assertEquals("/", FilenameUtils.getFullPathNoEndSeparator("/"));
-        assertEquals("\\", FilenameUtils.getFullPathNoEndSeparator("\\"));
+        assertEquals("C:" + "a", FilenameUtils.normalize("C:a"));
+        assertEquals("C:" + "a" + SEP, FilenameUtils.normalize("C:a/"));
+        assertEquals("C:" + "a" + SEP + "c", FilenameUtils.normalize("C:a/b/../c"));
+        assertEquals("C:" + "c", FilenameUtils.normalize("C:a/b/../../c"));
+        assertNull(FilenameUtils.normalize("C:a/b/../../../c"));
+        assertEquals("C:" + "a" + SEP, FilenameUtils.normalize("C:a/b/.."));
+        assertEquals("C:" + "", FilenameUtils.normalize("C:a/b/../.."));
+        assertNull(FilenameUtils.normalize("C:a/b/../../.."));
+        assertEquals("C:" + "a" + SEP + "d", FilenameUtils.normalize("C:a/b/../c/../d"));
+        assertEquals("C:" + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalize("C:a/b//d"));
+        assertEquals("C:" + "a" + SEP + "b" + SEP, FilenameUtils.normalize("C:a/b/././."));
+        assertEquals("C:" + "a", FilenameUtils.normalize("C:./a"));
+        assertEquals("C:" + "", FilenameUtils.normalize("C:./"));
+        assertEquals("C:" + "", FilenameUtils.normalize("C:."));
+        assertNull(FilenameUtils.normalize("C:../a"));
+        assertNull(FilenameUtils.normalize("C:.."));
+        assertEquals("C:" + "", FilenameUtils.normalize("C:"));
+
+        assertEquals(SEP + SEP + "server" + SEP + "a", FilenameUtils.normalize("//server/a"));
+        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP, FilenameUtils.normalize("//server/a/"));
+        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP + "c", FilenameUtils.normalize("//server/a/b/../c"));
+        assertEquals(SEP + SEP + "server" + SEP + "c", FilenameUtils.normalize("//server/a/b/../../c"));
+        assertNull(FilenameUtils.normalize("//server/a/b/../../../c"));
+        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP, FilenameUtils.normalize("//server/a/b/.."));
+        assertEquals(SEP + SEP + "server" + SEP + "", FilenameUtils.normalize("//server/a/b/../.."));
+        assertNull(FilenameUtils.normalize("//server/a/b/../../.."));
+        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP + "d", FilenameUtils.normalize("//server/a/b/../c/../d"));
+        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalize("//server/a/b//d"));
+        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP + "b" + SEP, FilenameUtils.normalize("//server/a/b/././."));
+        assertEquals(SEP + SEP + "server" + SEP + "a", FilenameUtils.normalize("//server/./a"));
+        assertEquals(SEP + SEP + "server" + SEP + "", FilenameUtils.normalize("//server/./"));
+        assertEquals(SEP + SEP + "server" + SEP + "", FilenameUtils.normalize("//server/."));
+        assertNull(FilenameUtils.normalize("//server/../a"));
+        assertNull(FilenameUtils.normalize("//server/.."));
+        assertEquals(SEP + SEP + "server" + SEP + "", FilenameUtils.normalize("//server/"));
 
-        // Test one level directory
-        assertEquals("/", FilenameUtils.getFullPathNoEndSeparator("/abc"));
-        assertEquals("\\", FilenameUtils.getFullPathNoEndSeparator("\\abc"));
+        assertEquals(SEP + SEP + "127.0.0.1" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("\\\\127.0.0.1\\a\\b\\c.txt"));
+        assertEquals(SEP + SEP + "::1" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("\\\\::1\\a\\b\\c.txt"));
+        assertEquals(SEP + SEP + "1::" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("\\\\1::\\a\\b\\c.txt"));
+        assertEquals(SEP + SEP + "server.example.org" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("\\\\server.example.org\\a\\b\\c.txt"));
+        assertEquals(SEP + SEP + "server.sub.example.org" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("\\\\server.sub.example.org\\a\\b\\c.txt"));
+        assertEquals(SEP + SEP + "server." + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("\\\\server.\\a\\b\\c.txt"));
+        assertEquals(SEP + SEP + "1::127.0.0.1" + SEP + "a" + SEP + "b" + SEP + "c.txt",
+            FilenameUtils.normalize("\\\\1::127.0.0.1\\a\\b\\c.txt"));
 
-        // Test one level directory
-        assertEquals("/abc", FilenameUtils.getFullPathNoEndSeparator("/abc/xyz"));
-        assertEquals("\\abc", FilenameUtils.getFullPathNoEndSeparator("\\abc\\xyz"));
-    }
+        // not valid IPv4 addresses but technically a valid "reg-name"s according to RFC1034
+        assertEquals(SEP + SEP + "127.0.0.256" + SEP + "a" + SEP + "b" + SEP + "c.txt",
+            FilenameUtils.normalize("\\\\127.0.0.256\\a\\b\\c.txt"));
+        assertEquals(SEP + SEP + "127.0.0.01" + SEP + "a" + SEP + "b" + SEP + "c.txt",
+            FilenameUtils.normalize("\\\\127.0.0.01\\a\\b\\c.txt"));
 
-    @Test
-    public void testGetName() {
-        assertNull(FilenameUtils.getName(null));
-        assertEquals("noseperator.inthispath", FilenameUtils.getName("noseperator.inthispath"));
-        assertEquals("c.txt", FilenameUtils.getName("a/b/c.txt"));
-        assertEquals("c", FilenameUtils.getName("a/b/c"));
-        assertEquals("", FilenameUtils.getName("a/b/c/"));
-        assertEquals("c", FilenameUtils.getName("a\\b\\c"));
+        assertNull(FilenameUtils.normalize("\\\\-server\\a\\b\\c.txt"));
+        assertNull(FilenameUtils.normalize("\\\\.\\a\\b\\c.txt"));
+        assertNull(FilenameUtils.normalize("\\\\..\\a\\b\\c.txt"));
+        assertNull(FilenameUtils.normalize("\\\\127.0..1\\a\\b\\c.txt"));
+        assertNull(FilenameUtils.normalize("\\\\::1::2\\a\\b\\c.txt"));
+        assertNull(FilenameUtils.normalize("\\\\:1\\a\\b\\c.txt"));
+        assertNull(FilenameUtils.normalize("\\\\1:\\a\\b\\c.txt"));
+        assertNull(FilenameUtils.normalize("\\\\1:2:3:4:5:6:7:8:9\\a\\b\\c.txt"));
+        assertNull(FilenameUtils.normalize("\\\\g:2:3:4:5:6:7:8\\a\\b\\c.txt"));
+        assertNull(FilenameUtils.normalize("\\\\1ffff:2:3:4:5:6:7:8\\a\\b\\c.txt"));
+        assertNull(FilenameUtils.normalize("\\\\1:2\\a\\b\\c.txt"));
+        // IO-556
+        assertNull(FilenameUtils.normalize("//../foo"));
+        assertNull(FilenameUtils.normalize("\\\\..\\foo"));
     }
 
+    /**
+     */
     @Test
-    public void testInjectionFailure() {
+    public void testNormalize_with_nullbytes() {
         try {
-            assertEquals("c", FilenameUtils.getName("a\\b\\\u0000c"));
+            assertEquals("a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("a\\b/c\u0000.txt"));
         } catch (final IllegalArgumentException ignore) {
+        }
 
+        try {
+            assertEquals("a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalize("\u0000a\\b/c.txt"));
+        } catch (final IllegalArgumentException ignore) {
         }
     }
 
     @Test
-    public void testGetBaseName() {
-        assertNull(FilenameUtils.getBaseName(null));
-        assertEquals("noseperator", FilenameUtils.getBaseName("noseperator.inthispath"));
-        assertEquals("c", FilenameUtils.getBaseName("a/b/c.txt"));
-        assertEquals("c", FilenameUtils.getBaseName("a/b/c"));
-        assertEquals("", FilenameUtils.getBaseName("a/b/c/"));
-        assertEquals("c", FilenameUtils.getBaseName("a\\b\\c"));
-        assertEquals("file.txt", FilenameUtils.getBaseName("file.txt.bak"));
+    public void testNormalizeNoEndSeparator() {
+        assertNull(FilenameUtils.normalizeNoEndSeparator(null));
+        assertNull(FilenameUtils.normalizeNoEndSeparator(":"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("1:\\a\\b\\c.txt"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("1:"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("1:a"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("\\\\\\a\\b\\c.txt"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("\\\\a"));
+
+        assertEquals("a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalizeNoEndSeparator("a\\b/c.txt"));
+        assertEquals("" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalizeNoEndSeparator("\\a\\b/c.txt"));
+        assertEquals("C:" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalizeNoEndSeparator("C:\\a\\b/c.txt"));
+        assertEquals("" + SEP + "" + SEP + "server" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalizeNoEndSeparator("\\\\server\\a\\b/c.txt"));
+        assertEquals("~" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalizeNoEndSeparator("~\\a\\b/c.txt"));
+        assertEquals("~user" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalizeNoEndSeparator("~user\\a\\b/c.txt"));
+        assertEquals("C:" + SEP + "a" + SEP + "b" + SEP + "c.txt", FilenameUtils.normalizeNoEndSeparator("C:\\\\a\\\\b\\\\c.txt"));
+
+        assertEquals("a" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("a/b/../c"));
+        assertEquals("c", FilenameUtils.normalizeNoEndSeparator("a/b/../../c"));
+        assertEquals("c", FilenameUtils.normalizeNoEndSeparator("a/b/../../c/"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("a/b/../../../c"));
+        assertEquals("a", FilenameUtils.normalizeNoEndSeparator("a/b/.."));
+        assertEquals("a", FilenameUtils.normalizeNoEndSeparator("a/b/../"));
+        assertEquals("", FilenameUtils.normalizeNoEndSeparator("a/b/../.."));
+        assertEquals("", FilenameUtils.normalizeNoEndSeparator("a/b/../../"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("a/b/../../.."));
+        assertEquals("a" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("a/b/../c/../d"));
+        assertEquals("a" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("a/b/../c/../d/"));
+        assertEquals("a" + SEP + "b" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("a/b//d"));
+        assertEquals("a" + SEP + "b", FilenameUtils.normalizeNoEndSeparator("a/b/././."));
+        assertEquals("a" + SEP + "b", FilenameUtils.normalizeNoEndSeparator("a/b/./././"));
+        assertEquals("a", FilenameUtils.normalizeNoEndSeparator("./a/"));
+        assertEquals("a", FilenameUtils.normalizeNoEndSeparator("./a"));
+        assertEquals("", FilenameUtils.normalizeNoEndSeparator("./"));
+        assertEquals("", FilenameUtils.normalizeNoEndSeparator("."));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("../a"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator(".."));
+        assertEquals("", FilenameUtils.normalizeNoEndSeparator(""));
+
+        assertEquals(SEP + "a", FilenameUtils.normalizeNoEndSeparator("/a"));
+        assertEquals(SEP + "a", FilenameUtils.normalizeNoEndSeparator("/a/"));
+        assertEquals(SEP + "a" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("/a/b/../c"));
+        assertEquals(SEP + "c", FilenameUtils.normalizeNoEndSeparator("/a/b/../../c"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("/a/b/../../../c"));
+        assertEquals(SEP + "a", FilenameUtils.normalizeNoEndSeparator("/a/b/.."));
+        assertEquals(SEP + "", FilenameUtils.normalizeNoEndSeparator("/a/b/../.."));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("/a/b/../../.."));
+        assertEquals(SEP + "a" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("/a/b/../c/../d"));
+        assertEquals(SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("/a/b//d"));
+        assertEquals(SEP + "a" + SEP + "b", FilenameUtils.normalizeNoEndSeparator("/a/b/././."));
+        assertEquals(SEP + "a", FilenameUtils.normalizeNoEndSeparator("/./a"));
+        assertEquals(SEP + "", FilenameUtils.normalizeNoEndSeparator("/./"));
+        assertEquals(SEP + "", FilenameUtils.normalizeNoEndSeparator("/."));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("/../a"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("/.."));
+        assertEquals(SEP + "", FilenameUtils.normalizeNoEndSeparator("/"));
+
+        assertEquals("~" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("~/a"));
+        assertEquals("~" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("~/a/"));
+        assertEquals("~" + SEP + "a" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("~/a/b/../c"));
+        assertEquals("~" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("~/a/b/../../c"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("~/a/b/../../../c"));
+        assertEquals("~" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("~/a/b/.."));
+        assertEquals("~" + SEP + "", FilenameUtils.normalizeNoEndSeparator("~/a/b/../.."));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("~/a/b/../../.."));
+        assertEquals("~" + SEP + "a" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("~/a/b/../c/../d"));
+        assertEquals("~" + SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("~/a/b//d"));
+        assertEquals("~" + SEP + "a" + SEP + "b", FilenameUtils.normalizeNoEndSeparator("~/a/b/././."));
+        assertEquals("~" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("~/./a"));
+        assertEquals("~" + SEP, FilenameUtils.normalizeNoEndSeparator("~/./"));
+        assertEquals("~" + SEP, FilenameUtils.normalizeNoEndSeparator("~/."));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("~/../a"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("~/.."));
+        assertEquals("~" + SEP, FilenameUtils.normalizeNoEndSeparator("~/"));
+        assertEquals("~" + SEP, FilenameUtils.normalizeNoEndSeparator("~"));
+
+        assertEquals("~user" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("~user/a"));
+        assertEquals("~user" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("~user/a/"));
+        assertEquals("~user" + SEP + "a" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("~user/a/b/../c"));
+        assertEquals("~user" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("~user/a/b/../../c"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("~user/a/b/../../../c"));
+        assertEquals("~user" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("~user/a/b/.."));
+        assertEquals("~user" + SEP + "", FilenameUtils.normalizeNoEndSeparator("~user/a/b/../.."));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("~user/a/b/../../.."));
+        assertEquals("~user" + SEP + "a" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("~user/a/b/../c/../d"));
+        assertEquals("~user" + SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("~user/a/b//d"));
+        assertEquals("~user" + SEP + "a" + SEP + "b", FilenameUtils.normalizeNoEndSeparator("~user/a/b/././."));
+        assertEquals("~user" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("~user/./a"));
+        assertEquals("~user" + SEP + "", FilenameUtils.normalizeNoEndSeparator("~user/./"));
+        assertEquals("~user" + SEP + "", FilenameUtils.normalizeNoEndSeparator("~user/."));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("~user/../a"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("~user/.."));
+        assertEquals("~user" + SEP, FilenameUtils.normalizeNoEndSeparator("~user/"));
+        assertEquals("~user" + SEP, FilenameUtils.normalizeNoEndSeparator("~user"));
+
+        assertEquals("C:" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("C:/a"));
+        assertEquals("C:" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("C:/a/"));
+        assertEquals("C:" + SEP + "a" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("C:/a/b/../c"));
+        assertEquals("C:" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("C:/a/b/../../c"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("C:/a/b/../../../c"));
+        assertEquals("C:" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("C:/a/b/.."));
+        assertEquals("C:" + SEP + "", FilenameUtils.normalizeNoEndSeparator("C:/a/b/../.."));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("C:/a/b/../../.."));
+        assertEquals("C:" + SEP + "a" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("C:/a/b/../c/../d"));
+        assertEquals("C:" + SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("C:/a/b//d"));
+        assertEquals("C:" + SEP + "a" + SEP + "b", FilenameUtils.normalizeNoEndSeparator("C:/a/b/././."));
+        assertEquals("C:" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("C:/./a"));
+        assertEquals("C:" + SEP + "", FilenameUtils.normalizeNoEndSeparator("C:/./"));
+        assertEquals("C:" + SEP + "", FilenameUtils.normalizeNoEndSeparator("C:/."));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("C:/../a"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("C:/.."));
+        assertEquals("C:" + SEP + "", FilenameUtils.normalizeNoEndSeparator("C:/"));
+
+        assertEquals("C:" + "a", FilenameUtils.normalizeNoEndSeparator("C:a"));
+        assertEquals("C:" + "a", FilenameUtils.normalizeNoEndSeparator("C:a/"));
+        assertEquals("C:" + "a" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("C:a/b/../c"));
+        assertEquals("C:" + "c", FilenameUtils.normalizeNoEndSeparator("C:a/b/../../c"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("C:a/b/../../../c"));
+        assertEquals("C:" + "a", FilenameUtils.normalizeNoEndSeparator("C:a/b/.."));
+        assertEquals("C:" + "", FilenameUtils.normalizeNoEndSeparator("C:a/b/../.."));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("C:a/b/../../.."));
+        assertEquals("C:" + "a" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("C:a/b/../c/../d"));
+        assertEquals("C:" + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("C:a/b//d"));
+        assertEquals("C:" + "a" + SEP + "b", FilenameUtils.normalizeNoEndSeparator("C:a/b/././."));
+        assertEquals("C:" + "a", FilenameUtils.normalizeNoEndSeparator("C:./a"));
+        assertEquals("C:" + "", FilenameUtils.normalizeNoEndSeparator("C:./"));
+        assertEquals("C:" + "", FilenameUtils.normalizeNoEndSeparator("C:."));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("C:../a"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("C:.."));
+        assertEquals("C:" + "", FilenameUtils.normalizeNoEndSeparator("C:"));
+
+        assertEquals(SEP + SEP + "server" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("//server/a"));
+        assertEquals(SEP + SEP + "server" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("//server/a/"));
+        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("//server/a/b/../c"));
+        assertEquals(SEP + SEP + "server" + SEP + "c", FilenameUtils.normalizeNoEndSeparator("//server/a/b/../../c"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("//server/a/b/../../../c"));
+        assertEquals(SEP + SEP + "server" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("//server/a/b/.."));
+        assertEquals(SEP + SEP + "server" + SEP + "", FilenameUtils.normalizeNoEndSeparator("//server/a/b/../.."));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("//server/a/b/../../.."));
+        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("//server/a/b/../c/../d"));
+        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP + "b" + SEP + "d", FilenameUtils.normalizeNoEndSeparator("//server/a/b//d"));
+        assertEquals(SEP + SEP + "server" + SEP + "a" + SEP + "b", FilenameUtils.normalizeNoEndSeparator("//server/a/b/././."));
+        assertEquals(SEP + SEP + "server" + SEP + "a", FilenameUtils.normalizeNoEndSeparator("//server/./a"));
+        assertEquals(SEP + SEP + "server" + SEP + "", FilenameUtils.normalizeNoEndSeparator("//server/./"));
+        assertEquals(SEP + SEP + "server" + SEP + "", FilenameUtils.normalizeNoEndSeparator("//server/."));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("//server/../a"));
+        assertNull(FilenameUtils.normalizeNoEndSeparator("//server/.."));
+        assertEquals(SEP + SEP + "server" + SEP + "", FilenameUtils.normalizeNoEndSeparator("//server/"));
     }
 
     @Test
-    public void testGetBaseName_with_nullByte() {
-        try {
-            assertEquals("file.txt", FilenameUtils.getBaseName("fil\u0000e.txt.bak"));
-        } catch (final IllegalArgumentException ignore) {
+    public void testNormalizeNoEndSeparatorUnixWin() {
 
-        }
+        // Normalize (Unix Separator)
+        assertEquals("/a/c", FilenameUtils.normalizeNoEndSeparator("/a/b/../c/", true));
+        assertEquals("/a/c", FilenameUtils.normalizeNoEndSeparator("\\a\\b\\..\\c\\", true));
+
+        // Normalize (Windows Separator)
+        assertEquals("\\a\\c", FilenameUtils.normalizeNoEndSeparator("/a/b/../c/", false));
+        assertEquals("\\a\\c", FilenameUtils.normalizeNoEndSeparator("\\a\\b\\..\\c\\", false));
     }
 
     @Test
-    public void testGetExtension() {
-        assertNull(FilenameUtils.getExtension(null));
-        assertEquals("ext", FilenameUtils.getExtension("file.ext"));
-        assertEquals("", FilenameUtils.getExtension("README"));
-        assertEquals("com", FilenameUtils.getExtension("domain.dot.com"));
-        assertEquals("jpeg", FilenameUtils.getExtension("image.jpeg"));
-        assertEquals("", FilenameUtils.getExtension("a.b/c"));
-        assertEquals("txt", FilenameUtils.getExtension("a.b/c.txt"));
-        assertEquals("", FilenameUtils.getExtension("a/b/c"));
-        assertEquals("", FilenameUtils.getExtension("a.b\\c"));
-        assertEquals("txt", FilenameUtils.getExtension("a.b\\c.txt"));
-        assertEquals("", FilenameUtils.getExtension("a\\b\\c"));
-        assertEquals("", FilenameUtils.getExtension("C:\\temp\\foo.bar\\README"));
-        assertEquals("ext", FilenameUtils.getExtension("../filename.ext"));
-
-        if (FilenameUtils.isSystemWindows()) {
-            // Special case handling for NTFS ADS names
-        	try {
-        		FilenameUtils.getExtension("foo.exe:bar.txt");
-        		throw new AssertionError("Expected Exception");
-        	} catch (final IllegalArgumentException e) {
-        		assertEquals("NTFS ADS separator (':') in file name is forbidden.", e.getMessage());
-        	}
-        } else {
-        	// Upwards compatibility:
-        	assertEquals("txt", FilenameUtils.getExtension("foo.exe:bar.txt"));
-        }
+    public void testNormalizeUnixWin() {
+
+        // Normalize (Unix Separator)
+        assertEquals("/a/c/", FilenameUtils.normalize("/a/b/../c/", true));
+        assertEquals("/a/c/", FilenameUtils.normalize("\\a\\b\\..\\c\\", true));
+
+        // Normalize (Windows Separator)
+        assertEquals("\\a\\c\\", FilenameUtils.normalize("/a/b/../c/", false));
+        assertEquals("\\a\\c\\", FilenameUtils.normalize("\\a\\b\\..\\c\\", false));
     }
 
     @Test
@@ -975,230 +1164,41 @@ public class FilenameUtilsTestCase {
     }
 
     @Test
-    public void testEquals() {
-        assertTrue(FilenameUtils.equals(null, null));
-        assertFalse(FilenameUtils.equals(null, ""));
-        assertFalse(FilenameUtils.equals("", null));
-        assertTrue(FilenameUtils.equals("", ""));
-        assertTrue(FilenameUtils.equals("file.txt", "file.txt"));
-        assertFalse(FilenameUtils.equals("file.txt", "FILE.TXT"));
-        assertFalse(FilenameUtils.equals("a\\b\\file.txt", "a/b/file.txt"));
-    }
-
-    @Test
-    public void testEqualsOnSystem() {
-        assertTrue(FilenameUtils.equalsOnSystem(null, null));
-        assertFalse(FilenameUtils.equalsOnSystem(null, ""));
-        assertFalse(FilenameUtils.equalsOnSystem("", null));
-        assertTrue(FilenameUtils.equalsOnSystem("", ""));
-        assertTrue(FilenameUtils.equalsOnSystem("file.txt", "file.txt"));
-        assertEquals(WINDOWS, FilenameUtils.equalsOnSystem("file.txt", "FILE.TXT"));
-        assertFalse(FilenameUtils.equalsOnSystem("a\\b\\file.txt", "a/b/file.txt"));
-    }
-
-    @Test
-    public void testEqualsNormalized() {
-        assertTrue(FilenameUtils.equalsNormalized(null, null));
-        assertFalse(FilenameUtils.equalsNormalized(null, ""));
-        assertFalse(FilenameUtils.equalsNormalized("", null));
-        assertTrue(FilenameUtils.equalsNormalized("", ""));
-        assertTrue(FilenameUtils.equalsNormalized("file.txt", "file.txt"));
-        assertFalse(FilenameUtils.equalsNormalized("file.txt", "FILE.TXT"));
-        assertTrue(FilenameUtils.equalsNormalized("a\\b\\file.txt", "a/b/file.txt"));
-        assertFalse(FilenameUtils.equalsNormalized("a/b/", "a/b"));
-    }
-
-    @Test
-    public void testEqualsNormalizedOnSystem() {
-        assertTrue(FilenameUtils.equalsNormalizedOnSystem(null, null));
-        assertFalse(FilenameUtils.equalsNormalizedOnSystem(null, ""));
-        assertFalse(FilenameUtils.equalsNormalizedOnSystem("", null));
-        assertTrue(FilenameUtils.equalsNormalizedOnSystem("", ""));
-        assertTrue(FilenameUtils.equalsNormalizedOnSystem("file.txt", "file.txt"));
-        assertEquals(WINDOWS, FilenameUtils.equalsNormalizedOnSystem("file.txt", "FILE.TXT"));
-        assertTrue(FilenameUtils.equalsNormalizedOnSystem("a\\b\\file.txt", "a/b/file.txt"));
-        assertFalse(FilenameUtils.equalsNormalizedOnSystem("a/b/", "a/b"));
-    }
-
-    /**
-     * Test for https://issues.apache.org/jira/browse/IO-128
-     */
-    @Test
-    public void testEqualsNormalizedError_IO_128() {
-        assertFalse(FilenameUtils.equalsNormalizedOnSystem("//file.txt", "file.txt"));
-        assertFalse(FilenameUtils.equalsNormalizedOnSystem("file.txt", "//file.txt"));
-        assertFalse(FilenameUtils.equalsNormalizedOnSystem("//file.txt", "//file.txt"));
-    }
-
-    @Test
-    public void testEquals_fullControl() {
-        assertFalse(FilenameUtils.equals("file.txt", "FILE.TXT", true, IOCase.SENSITIVE));
-        assertTrue(FilenameUtils.equals("file.txt", "FILE.TXT", true, IOCase.INSENSITIVE));
-        assertEquals(WINDOWS, FilenameUtils.equals("file.txt", "FILE.TXT", true, IOCase.SYSTEM));
-        assertFalse(FilenameUtils.equals("file.txt", "FILE.TXT", true, null));
-    }
-
-    @Test
-    public void testIsExtension() {
-        assertFalse(FilenameUtils.isExtension(null, (String) null));
-        assertFalse(FilenameUtils.isExtension("file.txt", (String) null));
-        assertTrue(FilenameUtils.isExtension("file", (String) null));
-        assertFalse(FilenameUtils.isExtension("file.txt", ""));
-        assertTrue(FilenameUtils.isExtension("file", ""));
-        assertTrue(FilenameUtils.isExtension("file.txt", "txt"));
-        assertFalse(FilenameUtils.isExtension("file.txt", "rtf"));
-
-        assertFalse(FilenameUtils.isExtension("a/b/file.txt", (String) null));
-        assertFalse(FilenameUtils.isExtension("a/b/file.txt", ""));
-        assertTrue(FilenameUtils.isExtension("a/b/file.txt", "txt"));
-        assertFalse(FilenameUtils.isExtension("a/b/file.txt", "rtf"));
-
-        assertFalse(FilenameUtils.isExtension("a.b/file.txt", (String) null));
-        assertFalse(FilenameUtils.isExtension("a.b/file.txt", ""));
-        assertTrue(FilenameUtils.isExtension("a.b/file.txt", "txt"));
-        assertFalse(FilenameUtils.isExtension("a.b/file.txt", "rtf"));
-
-        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt", (String) null));
-        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt", ""));
-        assertTrue(FilenameUtils.isExtension("a\\b\\file.txt", "txt"));
-        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt", "rtf"));
-
-        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", (String) null));
-        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", ""));
-        assertTrue(FilenameUtils.isExtension("a.b\\file.txt", "txt"));
-        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", "rtf"));
-
-        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", "TXT"));
-    }
-
-    @Test
-    public void testIsExtension_injection() {
-        try {
-            FilenameUtils.isExtension("a.b\\fi\u0000le.txt", "TXT");
-            fail("Should throw IAE");
-        } catch (final IllegalArgumentException ignore) {
+    public void testSeparatorsToSystem() {
+        if (WINDOWS) {
+            assertNull(FilenameUtils.separatorsToSystem(null));
+            assertEquals("\\a\\b\\c", FilenameUtils.separatorsToSystem("\\a\\b\\c"));
+            assertEquals("\\a\\b\\c.txt", FilenameUtils.separatorsToSystem("\\a\\b\\c.txt"));
+            assertEquals("\\a\\b\\c", FilenameUtils.separatorsToSystem("\\a\\b/c"));
+            assertEquals("\\a\\b\\c", FilenameUtils.separatorsToSystem("/a/b/c"));
+            assertEquals("D:\\a\\b\\c", FilenameUtils.separatorsToSystem("D:/a/b/c"));
+        } else {
+            assertNull(FilenameUtils.separatorsToSystem(null));
+            assertEquals("/a/b/c", FilenameUtils.separatorsToSystem("/a/b/c"));
+            assertEquals("/a/b/c.txt", FilenameUtils.separatorsToSystem("/a/b/c.txt"));
+            assertEquals("/a/b/c", FilenameUtils.separatorsToSystem("/a/b\\c"));
+            assertEquals("/a/b/c", FilenameUtils.separatorsToSystem("\\a\\b\\c"));
+            assertEquals("D:/a/b/c", FilenameUtils.separatorsToSystem("D:\\a\\b\\c"));
         }
     }
 
     @Test
-    public void testIsExtensionArray() {
-        assertFalse(FilenameUtils.isExtension(null, (String[]) null));
-        assertFalse(FilenameUtils.isExtension("file.txt", (String[]) null));
-        assertTrue(FilenameUtils.isExtension("file", (String[]) null));
-        assertFalse(FilenameUtils.isExtension("file.txt"));
-        assertTrue(FilenameUtils.isExtension("file.txt", new String[]{"txt"}));
-        assertFalse(FilenameUtils.isExtension("file.txt", new String[]{"rtf"}));
-        assertTrue(FilenameUtils.isExtension("file", "rtf", ""));
-        assertTrue(FilenameUtils.isExtension("file.txt", "rtf", "txt"));
-
-        assertFalse(FilenameUtils.isExtension("a/b/file.txt", (String[]) null));
-        assertFalse(FilenameUtils.isExtension("a/b/file.txt"));
-        assertTrue(FilenameUtils.isExtension("a/b/file.txt", new String[]{"txt"}));
-        assertFalse(FilenameUtils.isExtension("a/b/file.txt", new String[]{"rtf"}));
-        assertTrue(FilenameUtils.isExtension("a/b/file.txt", "rtf", "txt"));
-
-        assertFalse(FilenameUtils.isExtension("a.b/file.txt", (String[]) null));
-        assertFalse(FilenameUtils.isExtension("a.b/file.txt"));
-        assertTrue(FilenameUtils.isExtension("a.b/file.txt", new String[]{"txt"}));
-        assertFalse(FilenameUtils.isExtension("a.b/file.txt", new String[]{"rtf"}));
-        assertTrue(FilenameUtils.isExtension("a.b/file.txt", "rtf", "txt"));
-
-        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt", (String[]) null));
-        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt"));
-        assertTrue(FilenameUtils.isExtension("a\\b\\file.txt", new String[]{"txt"}));
-        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt", new String[]{"rtf"}));
-        assertTrue(FilenameUtils.isExtension("a\\b\\file.txt", "rtf", "txt"));
-
-        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", (String[]) null));
-        assertFalse(FilenameUtils.isExtension("a.b\\file.txt"));
-        assertTrue(FilenameUtils.isExtension("a.b\\file.txt", new String[]{"txt"}));
-        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", new String[]{"rtf"}));
-        assertTrue(FilenameUtils.isExtension("a.b\\file.txt", "rtf", "txt"));
-
-        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", new String[]{"TXT"}));
-        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", "TXT", "RTF"));
-    }
-
-    @Test
-    public void testIsExtensionVarArgs() {
-        assertTrue(FilenameUtils.isExtension("file.txt", "txt"));
-        assertFalse(FilenameUtils.isExtension("file.txt", "rtf"));
-        assertTrue(FilenameUtils.isExtension("file", "rtf", ""));
-        assertTrue(FilenameUtils.isExtension("file.txt", "rtf", "txt"));
-
-        assertTrue(FilenameUtils.isExtension("a/b/file.txt", "txt"));
-        assertFalse(FilenameUtils.isExtension("a/b/file.txt", "rtf"));
-        assertTrue(FilenameUtils.isExtension("a/b/file.txt", "rtf", "txt"));
-
-        assertTrue(FilenameUtils.isExtension("a.b/file.txt", "txt"));
-        assertFalse(FilenameUtils.isExtension("a.b/file.txt", "rtf"));
-        assertTrue(FilenameUtils.isExtension("a.b/file.txt", "rtf", "txt"));
-
-        assertTrue(FilenameUtils.isExtension("a\\b\\file.txt", "txt"));
-        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt", "rtf"));
-        assertTrue(FilenameUtils.isExtension("a\\b\\file.txt", "rtf", "txt"));
-
-        assertTrue(FilenameUtils.isExtension("a.b\\file.txt", "txt"));
-        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", "rtf"));
-        assertTrue(FilenameUtils.isExtension("a.b\\file.txt", "rtf", "txt"));
-
-        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", "TXT"));
-        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", "TXT", "RTF"));
-    }
-
-    @Test
-    public void testIsExtensionCollection() {
-        assertFalse(FilenameUtils.isExtension(null, (Collection<String>) null));
-        assertFalse(FilenameUtils.isExtension("file.txt", (Collection<String>) null));
-        assertTrue(FilenameUtils.isExtension("file", (Collection<String>) null));
-        assertFalse(FilenameUtils.isExtension("file.txt", new ArrayList<>()));
-        assertTrue(FilenameUtils.isExtension("file.txt", new ArrayList<>(Arrays.asList("txt"))));
-        assertFalse(FilenameUtils.isExtension("file.txt", new ArrayList<>(Arrays.asList("rtf"))));
-        assertTrue(FilenameUtils.isExtension("file", new ArrayList<>(Arrays.asList("rtf", ""))));
-        assertTrue(FilenameUtils.isExtension("file.txt", new ArrayList<>(Arrays.asList("rtf", "txt"))));
-
-        assertFalse(FilenameUtils.isExtension("a/b/file.txt", (Collection<String>) null));
-        assertFalse(FilenameUtils.isExtension("a/b/file.txt", new ArrayList<>()));
-        assertTrue(FilenameUtils.isExtension("a/b/file.txt", new ArrayList<>(Arrays.asList("txt"))));
-        assertFalse(FilenameUtils.isExtension("a/b/file.txt", new ArrayList<>(Arrays.asList("rtf"))));
-        assertTrue(FilenameUtils.isExtension("a/b/file.txt", new ArrayList<>(Arrays.asList("rtf", "txt"))));
-
-        assertFalse(FilenameUtils.isExtension("a.b/file.txt", (Collection<String>) null));
-        assertFalse(FilenameUtils.isExtension("a.b/file.txt", new ArrayList<>()));
-        assertTrue(FilenameUtils.isExtension("a.b/file.txt", new ArrayList<>(Arrays.asList("txt"))));
-        assertFalse(FilenameUtils.isExtension("a.b/file.txt", new ArrayList<>(Arrays.asList("rtf"))));
-        assertTrue(FilenameUtils.isExtension("a.b/file.txt", new ArrayList<>(Arrays.asList("rtf", "txt"))));
-
-        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt", (Collection<String>) null));
-        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt", new ArrayList<>()));
-        assertTrue(FilenameUtils.isExtension("a\\b\\file.txt", new ArrayList<>(Arrays.asList("txt"))));
-        assertFalse(FilenameUtils.isExtension("a\\b\\file.txt", new ArrayList<>(Arrays.asList("rtf"))));
-        assertTrue(FilenameUtils.isExtension("a\\b\\file.txt", new ArrayList<>(Arrays.asList("rtf", "txt"))));
-
-        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", (Collection<String>) null));
-        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", new ArrayList<>()));
-        assertTrue(FilenameUtils.isExtension("a.b\\file.txt", new ArrayList<>(Arrays.asList("txt"))));
-        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", new ArrayList<>(Arrays.asList("rtf"))));
-        assertTrue(FilenameUtils.isExtension("a.b\\file.txt", new ArrayList<>(Arrays.asList("rtf", "txt"))));
-
-        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", new ArrayList<>(Arrays.asList("TXT"))));
-        assertFalse(FilenameUtils.isExtension("a.b\\file.txt", new ArrayList<>(Arrays.asList("TXT", "RTF"))));
+    public void testSeparatorsToUnix() {
+        assertNull(FilenameUtils.separatorsToUnix(null));
+        assertEquals("/a/b/c", FilenameUtils.separatorsToUnix("/a/b/c"));
+        assertEquals("/a/b/c.txt", FilenameUtils.separatorsToUnix("/a/b/c.txt"));
+        assertEquals("/a/b/c", FilenameUtils.separatorsToUnix("/a/b\\c"));
+        assertEquals("/a/b/c", FilenameUtils.separatorsToUnix("\\a\\b\\c"));
+        assertEquals("D:/a/b/c", FilenameUtils.separatorsToUnix("D:\\a\\b\\c"));
     }
 
-    //-----------------------------------------------------------------------
     @Test
-    public void testDirectoryContains() throws IOException {
-        assertTrue(FilenameUtils.directoryContains("/foo", "/foo/bar"));
-        assertTrue(FilenameUtils.directoryContains("/foo/", "/foo/bar"));
-        assertTrue(FilenameUtils.directoryContains("C:\\foo", "C:\\foo\\bar"));
-        assertTrue(FilenameUtils.directoryContains("C:\\foo\\", "C:\\foo\\bar"));
-
-        assertFalse(FilenameUtils.directoryContains("/foo", "/foo"));
-        assertFalse(FilenameUtils.directoryContains("/foo", "/foobar"));
-        assertFalse(FilenameUtils.directoryContains("C:\\foo", "C:\\foobar"));
-        assertFalse(FilenameUtils.directoryContains("/foo", null));
-        assertFalse(FilenameUtils.directoryContains("", ""));
-        assertFalse(FilenameUtils.directoryContains("", "/foo"));
-        assertFalse(FilenameUtils.directoryContains("/foo", ""));
+    public void testSeparatorsToWindows() {
+        assertNull(FilenameUtils.separatorsToWindows(null));
+        assertEquals("\\a\\b\\c", FilenameUtils.separatorsToWindows("\\a\\b\\c"));
+        assertEquals("\\a\\b\\c.txt", FilenameUtils.separatorsToWindows("\\a\\b\\c.txt"));
+        assertEquals("\\a\\b\\c", FilenameUtils.separatorsToWindows("\\a\\b/c"));
+        assertEquals("\\a\\b\\c", FilenameUtils.separatorsToWindows("/a/b/c"));
+        assertEquals("D:\\a\\b\\c", FilenameUtils.separatorsToWindows("D:/a/b/c"));
     }
 }
diff --git a/src/test/java/org/apache/commons/io/FilenameUtilsWildcardTestCase.java b/src/test/java/org/apache/commons/io/FilenameUtilsWildcardTestCase.java
index 9405c75..651d1ec 100644
--- a/src/test/java/org/apache/commons/io/FilenameUtilsWildcardTestCase.java
+++ b/src/test/java/org/apache/commons/io/FilenameUtilsWildcardTestCase.java
@@ -33,6 +33,68 @@ public class FilenameUtilsWildcardTestCase {
     // Testing:
     //   FilenameUtils.wildcardMatch(String,String)
 
+    private void assertMatch(final String text, final String wildcard, final boolean expected) {
+        assertEquals(expected, FilenameUtils.wildcardMatch(text, wildcard), text + " " + wildcard);
+    }
+
+    /**
+     * See https://issues.apache.org/jira/browse/IO-246
+     */
+    @Test
+    public void test_IO_246() {
+
+        // Tests for "*?"
+        assertMatch("aaa", "aa*?", true);
+        // these ought to work as well, but "*?" does not work properly at present
+//      assertMatch("aaa", "a*?", true);
+//      assertMatch("aaa", "*?", true);
+
+        // Tests for "?*"
+        assertMatch("",    "?*",   false);
+        assertMatch("a",   "a?*",  false);
+        assertMatch("aa",  "aa?*", false);
+        assertMatch("a",   "?*",   true);
+        assertMatch("aa",  "?*",   true);
+        assertMatch("aaa", "?*",   true);
+
+        // Test ending on "?"
+        assertMatch("",    "?", false);
+        assertMatch("a",   "a?", false);
+        assertMatch("aa",  "aa?", false);
+        assertMatch("aab", "aa?", true);
+        assertMatch("aaa", "*a", true);
+    }
+
+    @Test
+    public void testLocaleIndependence() {
+        final Locale orig = Locale.getDefault();
+
+        final Locale[] locales = Locale.getAvailableLocales();
+
+        final String[][] data = {
+            { "I", "i"},
+            { "i", "I"},
+            { "i", "\u0130"},
+            { "i", "\u0131"},
+            { "\u03A3", "\u03C2"},
+            { "\u03A3", "\u03C3"},
+            { "\u03C2", "\u03C3"},
+        };
+
+        try {
+            for (int i = 0; i < data.length; i++) {
+                for (final Locale locale : locales) {
+                    Locale.setDefault(locale);
+                    assertTrue(data[i][0].equalsIgnoreCase(data[i][1]), "Test data corrupt: " + i);
+                    final boolean match = FilenameUtils.wildcardMatch(data[i][0], data[i][1], IOCase.INSENSITIVE);
+                    assertTrue(match, Locale.getDefault().toString() + ": " + i);
+                }
+            }
+        } finally {
+            Locale.setDefault(orig);
+        }
+    }
+
     @Test
     public void testMatch() {
         assertFalse(FilenameUtils.wildcardMatch(null, "Foo"));
@@ -59,83 +121,6 @@ public class FilenameUtilsWildcardTestCase {
         assertFalse(FilenameUtils.wildcardMatch("FOOBAR", "Foo*"));
     }
 
-    @Test
-    public void testMatchOnSystem() {
-        assertFalse(FilenameUtils.wildcardMatchOnSystem(null, "Foo"));
-        assertFalse(FilenameUtils.wildcardMatchOnSystem("Foo", null));
-        assertTrue(FilenameUtils.wildcardMatchOnSystem(null, null));
-        assertTrue(FilenameUtils.wildcardMatchOnSystem("Foo", "Foo"));
-        assertTrue(FilenameUtils.wildcardMatchOnSystem("", ""));
-        assertTrue(FilenameUtils.wildcardMatchOnSystem("Foo", "Fo*"));
-        assertTrue(FilenameUtils.wildcardMatchOnSystem("Foo", "Fo?"));
-        assertTrue(FilenameUtils.wildcardMatchOnSystem("Foo Bar and Catflap", "Fo*"));
-        assertTrue(FilenameUtils.wildcardMatchOnSystem("New Bookmarks", "N?w ?o?k??r?s"));
-        assertFalse(FilenameUtils.wildcardMatchOnSystem("Foo", "Bar"));
-        assertTrue(FilenameUtils.wildcardMatchOnSystem("Foo Bar Foo", "F*o Bar*"));
-        assertTrue(FilenameUtils.wildcardMatchOnSystem("Adobe Acrobat Installer", "Ad*er"));
-        assertTrue(FilenameUtils.wildcardMatchOnSystem("Foo", "*Foo"));
-        assertTrue(FilenameUtils.wildcardMatchOnSystem("BarFoo", "*Foo"));
-        assertTrue(FilenameUtils.wildcardMatchOnSystem("Foo", "Foo*"));
-        assertTrue(FilenameUtils.wildcardMatchOnSystem("FooBar", "Foo*"));
-        assertEquals(WINDOWS, FilenameUtils.wildcardMatchOnSystem("FOO", "*Foo"));
-        assertEquals(WINDOWS, FilenameUtils.wildcardMatchOnSystem("BARFOO", "*Foo"));
-        assertEquals(WINDOWS, FilenameUtils.wildcardMatchOnSystem("FOO", "Foo*"));
-        assertEquals(WINDOWS, FilenameUtils.wildcardMatchOnSystem("FOOBAR", "Foo*"));
-    }
-
-    @Test
-    public void testMatchCaseSpecified() {
-        assertFalse(FilenameUtils.wildcardMatch(null, "Foo", IOCase.SENSITIVE));
-        assertFalse(FilenameUtils.wildcardMatch("Foo", null, IOCase.SENSITIVE));
-        assertTrue(FilenameUtils.wildcardMatch(null, null, IOCase.SENSITIVE));
-        assertTrue(FilenameUtils.wildcardMatch("Foo", "Foo", IOCase.SENSITIVE));
-        assertTrue(FilenameUtils.wildcardMatch("", "", IOCase.SENSITIVE));
-        assertTrue(FilenameUtils.wildcardMatch("Foo", "Fo*", IOCase.SENSITIVE));
-        assertTrue(FilenameUtils.wildcardMatch("Foo", "Fo?", IOCase.SENSITIVE));
-        assertTrue(FilenameUtils.wildcardMatch("Foo Bar and Catflap", "Fo*", IOCase.SENSITIVE));
-        assertTrue(FilenameUtils.wildcardMatch("New Bookmarks", "N?w ?o?k??r?s", IOCase.SENSITIVE));
-        assertFalse(FilenameUtils.wildcardMatch("Foo", "Bar", IOCase.SENSITIVE));
-        assertTrue(FilenameUtils.wildcardMatch("Foo Bar Foo", "F*o Bar*", IOCase.SENSITIVE));
-        assertTrue(FilenameUtils.wildcardMatch("Adobe Acrobat Installer", "Ad*er", IOCase.SENSITIVE));
-        assertTrue(FilenameUtils.wildcardMatch("Foo", "*Foo", IOCase.SENSITIVE));
-        assertTrue(FilenameUtils.wildcardMatch("Foo", "Foo*", IOCase.SENSITIVE));
-        assertTrue(FilenameUtils.wildcardMatch("Foo", "*Foo", IOCase.SENSITIVE));
-        assertTrue(FilenameUtils.wildcardMatch("BarFoo", "*Foo", IOCase.SENSITIVE));
-        assertTrue(FilenameUtils.wildcardMatch("Foo", "Foo*", IOCase.SENSITIVE));
-        assertTrue(FilenameUtils.wildcardMatch("FooBar", "Foo*", IOCase.SENSITIVE));
-
-        assertFalse(FilenameUtils.wildcardMatch("FOO", "*Foo", IOCase.SENSITIVE));
-        assertFalse(FilenameUtils.wildcardMatch("BARFOO", "*Foo", IOCase.SENSITIVE));
-        assertFalse(FilenameUtils.wildcardMatch("FOO", "Foo*", IOCase.SENSITIVE));
-        assertFalse(FilenameUtils.wildcardMatch("FOOBAR", "Foo*", IOCase.SENSITIVE));
-        assertTrue(FilenameUtils.wildcardMatch("FOO", "*Foo", IOCase.INSENSITIVE));
-        assertTrue(FilenameUtils.wildcardMatch("BARFOO", "*Foo", IOCase.INSENSITIVE));
-        assertTrue(FilenameUtils.wildcardMatch("FOO", "Foo*", IOCase.INSENSITIVE));
-        assertTrue(FilenameUtils.wildcardMatch("FOOBAR", "Foo*", IOCase.INSENSITIVE));
-        assertEquals(WINDOWS, FilenameUtils.wildcardMatch("FOO", "*Foo", IOCase.SYSTEM));
-        assertEquals(WINDOWS, FilenameUtils.wildcardMatch("BARFOO", "*Foo", IOCase.SYSTEM));
-        assertEquals(WINDOWS, FilenameUtils.wildcardMatch("FOO", "Foo*", IOCase.SYSTEM));
-        assertEquals(WINDOWS, FilenameUtils.wildcardMatch("FOOBAR", "Foo*", IOCase.SYSTEM));
-    }
-
-    @Test
-    public void testSplitOnTokens() {
-        assertArrayEquals(new String[] { "Ad", "*", "er" }, FilenameUtils.splitOnTokens("Ad*er"));
-        assertArrayEquals(new String[] { "Ad", "?", "er" }, FilenameUtils.splitOnTokens("Ad?er"));
-        assertArrayEquals(new String[] { "Test", "*", "?", "One" }, FilenameUtils.splitOnTokens("Test*?One"));
-        assertArrayEquals(new String[] { "Test", "?", "*", "One" }, FilenameUtils.splitOnTokens("Test?*One"));
-        assertArrayEquals(new String[] { "*" }, FilenameUtils.splitOnTokens("****"));
-        assertArrayEquals(new String[] { "*", "?", "?", "*" }, FilenameUtils.splitOnTokens("*??*"));
-        assertArrayEquals(new String[] { "*", "?", "*", "?", "*" }, FilenameUtils.splitOnTokens("*?**?*"));
-        assertArrayEquals(new String[] { "*", "?", "*", "?", "*" }, FilenameUtils.splitOnTokens("*?***?*"));
-        assertArrayEquals(new String[] { "h", "?", "?", "*" }, FilenameUtils.splitOnTokens("h??*"));
-        assertArrayEquals(new String[] { "" }, FilenameUtils.splitOnTokens(""));
-    }
-
-    private void assertMatch(final String text, final String wildcard, final boolean expected) {
-        assertEquals(expected, FilenameUtils.wildcardMatch(text, wildcard), text + " " + wildcard);
-    }
-
     // A separate set of tests, added to this batch
     @Test
     public void testMatch2() {
@@ -184,62 +169,77 @@ public class FilenameUtilsWildcardTestCase {
         assertMatch("log.log.abc.log.abc.d", "*log?abc?d", true);
     }
 
-    /**
-     * See https://issues.apache.org/jira/browse/IO-246
-     */
     @Test
-    public void test_IO_246() {
-
-        // Tests for "*?"
-        assertMatch("aaa", "aa*?", true);
-        // these ought to work as well, but "*?" does not work properly at present
-//      assertMatch("aaa", "a*?", true);
-//      assertMatch("aaa", "*?", true);
-
-        // Tests for "?*"
-        assertMatch("",    "?*",   false);
-        assertMatch("a",   "a?*",  false);
-        assertMatch("aa",  "aa?*", false);
-        assertMatch("a",   "?*",   true);
-        assertMatch("aa",  "?*",   true);
-        assertMatch("aaa", "?*",   true);
+    public void testMatchCaseSpecified() {
+        assertFalse(FilenameUtils.wildcardMatch(null, "Foo", IOCase.SENSITIVE));
+        assertFalse(FilenameUtils.wildcardMatch("Foo", null, IOCase.SENSITIVE));
+        assertTrue(FilenameUtils.wildcardMatch(null, null, IOCase.SENSITIVE));
+        assertTrue(FilenameUtils.wildcardMatch("Foo", "Foo", IOCase.SENSITIVE));
+        assertTrue(FilenameUtils.wildcardMatch("", "", IOCase.SENSITIVE));
+        assertTrue(FilenameUtils.wildcardMatch("Foo", "Fo*", IOCase.SENSITIVE));
+        assertTrue(FilenameUtils.wildcardMatch("Foo", "Fo?", IOCase.SENSITIVE));
+        assertTrue(FilenameUtils.wildcardMatch("Foo Bar and Catflap", "Fo*", IOCase.SENSITIVE));
+        assertTrue(FilenameUtils.wildcardMatch("New Bookmarks", "N?w ?o?k??r?s", IOCase.SENSITIVE));
+        assertFalse(FilenameUtils.wildcardMatch("Foo", "Bar", IOCase.SENSITIVE));
+        assertTrue(FilenameUtils.wildcardMatch("Foo Bar Foo", "F*o Bar*", IOCase.SENSITIVE));
+        assertTrue(FilenameUtils.wildcardMatch("Adobe Acrobat Installer", "Ad*er", IOCase.SENSITIVE));
+        assertTrue(FilenameUtils.wildcardMatch("Foo", "*Foo", IOCase.SENSITIVE));
+        assertTrue(FilenameUtils.wildcardMatch("Foo", "Foo*", IOCase.SENSITIVE));
+        assertTrue(FilenameUtils.wildcardMatch("Foo", "*Foo", IOCase.SENSITIVE));
+        assertTrue(FilenameUtils.wildcardMatch("BarFoo", "*Foo", IOCase.SENSITIVE));
+        assertTrue(FilenameUtils.wildcardMatch("Foo", "Foo*", IOCase.SENSITIVE));
+        assertTrue(FilenameUtils.wildcardMatch("FooBar", "Foo*", IOCase.SENSITIVE));
 
-        // Test ending on "?"
-        assertMatch("",    "?", false);
-        assertMatch("a",   "a?", false);
-        assertMatch("aa",  "aa?", false);
-        assertMatch("aab", "aa?", true);
-        assertMatch("aaa", "*a", true);
+        assertFalse(FilenameUtils.wildcardMatch("FOO", "*Foo", IOCase.SENSITIVE));
+        assertFalse(FilenameUtils.wildcardMatch("BARFOO", "*Foo", IOCase.SENSITIVE));
+        assertFalse(FilenameUtils.wildcardMatch("FOO", "Foo*", IOCase.SENSITIVE));
+        assertFalse(FilenameUtils.wildcardMatch("FOOBAR", "Foo*", IOCase.SENSITIVE));
+        assertTrue(FilenameUtils.wildcardMatch("FOO", "*Foo", IOCase.INSENSITIVE));
+        assertTrue(FilenameUtils.wildcardMatch("BARFOO", "*Foo", IOCase.INSENSITIVE));
+        assertTrue(FilenameUtils.wildcardMatch("FOO", "Foo*", IOCase.INSENSITIVE));
+        assertTrue(FilenameUtils.wildcardMatch("FOOBAR", "Foo*", IOCase.INSENSITIVE));
+        assertEquals(WINDOWS, FilenameUtils.wildcardMatch("FOO", "*Foo", IOCase.SYSTEM));
+        assertEquals(WINDOWS, FilenameUtils.wildcardMatch("BARFOO", "*Foo", IOCase.SYSTEM));
+        assertEquals(WINDOWS, FilenameUtils.wildcardMatch("FOO", "Foo*", IOCase.SYSTEM));
+        assertEquals(WINDOWS, FilenameUtils.wildcardMatch("FOOBAR", "Foo*", IOCase.SYSTEM));
     }
 
     @Test
-    public void testLocaleIndependence() {
-        final Locale orig = Locale.getDefault();
-
-        final Locale[] locales = Locale.getAvailableLocales();
-
-        final String[][] data = {
-            { "I", "i"},
-            { "i", "I"},
-            { "i", "\u0130"},
-            { "i", "\u0131"},
-            { "\u03A3", "\u03C2"},
-            { "\u03A3", "\u03C3"},
-            { "\u03C2", "\u03C3"},
-        };
+    public void testMatchOnSystem() {
+        assertFalse(FilenameUtils.wildcardMatchOnSystem(null, "Foo"));
+        assertFalse(FilenameUtils.wildcardMatchOnSystem("Foo", null));
+        assertTrue(FilenameUtils.wildcardMatchOnSystem(null, null));
+        assertTrue(FilenameUtils.wildcardMatchOnSystem("Foo", "Foo"));
+        assertTrue(FilenameUtils.wildcardMatchOnSystem("", ""));
+        assertTrue(FilenameUtils.wildcardMatchOnSystem("Foo", "Fo*"));
+        assertTrue(FilenameUtils.wildcardMatchOnSystem("Foo", "Fo?"));
+        assertTrue(FilenameUtils.wildcardMatchOnSystem("Foo Bar and Catflap", "Fo*"));
+        assertTrue(FilenameUtils.wildcardMatchOnSystem("New Bookmarks", "N?w ?o?k??r?s"));
+        assertFalse(FilenameUtils.wildcardMatchOnSystem("Foo", "Bar"));
+        assertTrue(FilenameUtils.wildcardMatchOnSystem("Foo Bar Foo", "F*o Bar*"));
+        assertTrue(FilenameUtils.wildcardMatchOnSystem("Adobe Acrobat Installer", "Ad*er"));
+        assertTrue(FilenameUtils.wildcardMatchOnSystem("Foo", "*Foo"));
+        assertTrue(FilenameUtils.wildcardMatchOnSystem("BarFoo", "*Foo"));
+        assertTrue(FilenameUtils.wildcardMatchOnSystem("Foo", "Foo*"));
+        assertTrue(FilenameUtils.wildcardMatchOnSystem("FooBar", "Foo*"));
+        assertEquals(WINDOWS, FilenameUtils.wildcardMatchOnSystem("FOO", "*Foo"));
+        assertEquals(WINDOWS, FilenameUtils.wildcardMatchOnSystem("BARFOO", "*Foo"));
+        assertEquals(WINDOWS, FilenameUtils.wildcardMatchOnSystem("FOO", "Foo*"));
+        assertEquals(WINDOWS, FilenameUtils.wildcardMatchOnSystem("FOOBAR", "Foo*"));
+    }
 
-        try {
-            for (int i = 0; i < data.length; i++) {
-                for (final Locale locale : locales) {
-                    Locale.setDefault(locale);
-                    assertTrue(data[i][0].equalsIgnoreCase(data[i][1]), "Test data corrupt: " + i);
-                    final boolean match = FilenameUtils.wildcardMatch(data[i][0], data[i][1], IOCase.INSENSITIVE);
-                    assertTrue(match, Locale.getDefault().toString() + ": " + i);
-                }
-            }
-        } finally {
-            Locale.setDefault(orig);
-        }
+    @Test
+    public void testSplitOnTokens() {
+        assertArrayEquals(new String[] { "Ad", "*", "er" }, FilenameUtils.splitOnTokens("Ad*er"));
+        assertArrayEquals(new String[] { "Ad", "?", "er" }, FilenameUtils.splitOnTokens("Ad?er"));
+        assertArrayEquals(new String[] { "Test", "*", "?", "One" }, FilenameUtils.splitOnTokens("Test*?One"));
+        assertArrayEquals(new String[] { "Test", "?", "*", "One" }, FilenameUtils.splitOnTokens("Test?*One"));
+        assertArrayEquals(new String[] { "*" }, FilenameUtils.splitOnTokens("****"));
+        assertArrayEquals(new String[] { "*", "?", "?", "*" }, FilenameUtils.splitOnTokens("*??*"));
+        assertArrayEquals(new String[] { "*", "?", "*", "?", "*" }, FilenameUtils.splitOnTokens("*?**?*"));
+        assertArrayEquals(new String[] { "*", "?", "*", "?", "*" }, FilenameUtils.splitOnTokens("*?***?*"));
+        assertArrayEquals(new String[] { "h", "?", "?", "*" }, FilenameUtils.splitOnTokens("h??*"));
+        assertArrayEquals(new String[] { "" }, FilenameUtils.splitOnTokens(""));
     }
 
 }
diff --git a/src/test/java/org/apache/commons/io/HexDumpTest.java b/src/test/java/org/apache/commons/io/HexDumpTest.java
index cef0b5c..3f915d0 100644
--- a/src/test/java/org/apache/commons/io/HexDumpTest.java
+++ b/src/test/java/org/apache/commons/io/HexDumpTest.java
@@ -30,16 +30,6 @@ import org.junit.jupiter.api.Test;
  */
 public class HexDumpTest {
 
-    private char toHex(final int n) {
-        final char[] hexChars =
-                {
-                    '0', '1', '2', '3', '4', '5', '6', '7',
-                    '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
-                };
-
-        return hexChars[n % 16];
-    }
-
     @Test
     public void testDump()
             throws IOException {
@@ -231,4 +221,14 @@ public class HexDumpTest {
         }
         return rval;
     }
+
+    private char toHex(final int n) {
+        final char[] hexChars =
+                {
+                    '0', '1', '2', '3', '4', '5', '6', '7',
+                    '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+                };
+
+        return hexChars[n % 16];
+    }
 }
diff --git a/src/test/java/org/apache/commons/io/IOCaseTestCase.java b/src/test/java/org/apache/commons/io/IOCaseTestCase.java
index ba77237..16d9606 100644
--- a/src/test/java/org/apache/commons/io/IOCaseTestCase.java
+++ b/src/test/java/org/apache/commons/io/IOCaseTestCase.java
@@ -38,48 +38,33 @@ public class IOCaseTestCase {
 
     private static final boolean WINDOWS = File.separatorChar == '\\';
 
-    @Test
-    public void test_forName() {
-        assertEquals(IOCase.SENSITIVE, IOCase.forName("Sensitive"));
-        assertEquals(IOCase.INSENSITIVE, IOCase.forName("Insensitive"));
-        assertEquals(IOCase.SYSTEM, IOCase.forName("System"));
-        try {
-            IOCase.forName("Blah");
-            fail();
-        } catch (final IllegalArgumentException ignore) {}
-        try {
-            IOCase.forName(null);
-            fail();
-        } catch (final IllegalArgumentException ignore) {}
-    }
+    private IOCase serialize(final IOCase value) throws Exception {
+        final ByteArrayOutputStream buf = new ByteArrayOutputStream();
+        final ObjectOutputStream out = new ObjectOutputStream(buf);
+        out.writeObject(value);
+        out.flush();
+        out.close();
 
-    @Test
-    public void test_serialization() throws Exception {
-        assertSame(IOCase.SENSITIVE, serialize(IOCase.SENSITIVE));
-        assertSame(IOCase.INSENSITIVE, serialize(IOCase.INSENSITIVE));
-        assertSame(IOCase.SYSTEM, serialize(IOCase.SYSTEM));
+        final ByteArrayInputStream bufin = new ByteArrayInputStream(buf.toByteArray());
+        final ObjectInputStream in = new ObjectInputStream(bufin);
+        return (IOCase) in.readObject();
     }
 
     @Test
-    public void test_getName() {
-        assertEquals("Sensitive", IOCase.SENSITIVE.getName());
-        assertEquals("Insensitive", IOCase.INSENSITIVE.getName());
-        assertEquals("System", IOCase.SYSTEM.getName());
-    }
+    public void test_checkCompare_case() {
+        assertEquals(0, IOCase.SENSITIVE.checkCompareTo("ABC", "ABC"));
+        assertTrue(IOCase.SENSITIVE.checkCompareTo("ABC", "abc") < 0);
+        assertTrue(IOCase.SENSITIVE.checkCompareTo("abc", "ABC") > 0);
 
-    @Test
-    public void test_toString() {
-        assertEquals("Sensitive", IOCase.SENSITIVE.toString());
-        assertEquals("Insensitive", IOCase.INSENSITIVE.toString());
-        assertEquals("System", IOCase.SYSTEM.toString());
-    }
+        assertEquals(0, IOCase.INSENSITIVE.checkCompareTo("ABC", "ABC"));
+        assertEquals(0, IOCase.INSENSITIVE.checkCompareTo("ABC", "abc"));
+        assertEquals(0, IOCase.INSENSITIVE.checkCompareTo("abc", "ABC"));
 
-    @Test
-    public void test_isCaseSensitive() {
-        assertTrue(IOCase.SENSITIVE.isCaseSensitive());
-        assertFalse(IOCase.INSENSITIVE.isCaseSensitive());
-        assertEquals(!WINDOWS, IOCase.SYSTEM.isCaseSensitive());
+        assertEquals(0, IOCase.SYSTEM.checkCompareTo("ABC", "ABC"));
+        assertEquals(WINDOWS, IOCase.SYSTEM.checkCompareTo("ABC", "abc") == 0);
+        assertEquals(WINDOWS, IOCase.SYSTEM.checkCompareTo("abc", "ABC") == 0);
     }
+
     @Test
     public void test_checkCompare_functionality() {
         assertTrue(IOCase.SENSITIVE.checkCompareTo("ABC", "") > 0);
@@ -104,20 +89,44 @@ public class IOCaseTestCase {
     }
 
     @Test
-    public void test_checkCompare_case() {
-        assertEquals(0, IOCase.SENSITIVE.checkCompareTo("ABC", "ABC"));
-        assertTrue(IOCase.SENSITIVE.checkCompareTo("ABC", "abc") < 0);
-        assertTrue(IOCase.SENSITIVE.checkCompareTo("abc", "ABC") > 0);
+    public void test_checkEndsWith_case() {
+        assertTrue(IOCase.SENSITIVE.checkEndsWith("ABC", "BC"));
+        assertFalse(IOCase.SENSITIVE.checkEndsWith("ABC", "Bc"));
 
-        assertEquals(0, IOCase.INSENSITIVE.checkCompareTo("ABC", "ABC"));
-        assertEquals(0, IOCase.INSENSITIVE.checkCompareTo("ABC", "abc"));
-        assertEquals(0, IOCase.INSENSITIVE.checkCompareTo("abc", "ABC"));
+        assertTrue(IOCase.INSENSITIVE.checkEndsWith("ABC", "BC"));
+        assertTrue(IOCase.INSENSITIVE.checkEndsWith("ABC", "Bc"));
 
-        assertEquals(0, IOCase.SYSTEM.checkCompareTo("ABC", "ABC"));
-        assertEquals(WINDOWS, IOCase.SYSTEM.checkCompareTo("ABC", "abc") == 0);
-        assertEquals(WINDOWS, IOCase.SYSTEM.checkCompareTo("abc", "ABC") == 0);
+        assertTrue(IOCase.SYSTEM.checkEndsWith("ABC", "BC"));
+        assertEquals(WINDOWS, IOCase.SYSTEM.checkEndsWith("ABC", "Bc"));
     }
 
+    @Test
+    public void test_checkEndsWith_functionality() {
+        assertTrue(IOCase.SENSITIVE.checkEndsWith("ABC", ""));
+        assertFalse(IOCase.SENSITIVE.checkEndsWith("ABC", "A"));
+        assertFalse(IOCase.SENSITIVE.checkEndsWith("ABC", "AB"));
+        assertTrue(IOCase.SENSITIVE.checkEndsWith("ABC", "ABC"));
+        assertTrue(IOCase.SENSITIVE.checkEndsWith("ABC", "BC"));
+        assertTrue(IOCase.SENSITIVE.checkEndsWith("ABC", "C"));
+        assertFalse(IOCase.SENSITIVE.checkEndsWith("ABC", "ABCD"));
+        assertFalse(IOCase.SENSITIVE.checkEndsWith("", "ABC"));
+        assertTrue(IOCase.SENSITIVE.checkEndsWith("", ""));
+
+        assertFalse(IOCase.SENSITIVE.checkEndsWith("ABC", null));
+        assertFalse(IOCase.SENSITIVE.checkEndsWith(null, "ABC"));
+        assertFalse(IOCase.SENSITIVE.checkEndsWith(null, null));
+    }
+    @Test
+    public void test_checkEquals_case() {
+        assertTrue(IOCase.SENSITIVE.checkEquals("ABC", "ABC"));
+        assertFalse(IOCase.SENSITIVE.checkEquals("ABC", "Abc"));
+
+        assertTrue(IOCase.INSENSITIVE.checkEquals("ABC", "ABC"));
+        assertTrue(IOCase.INSENSITIVE.checkEquals("ABC", "Abc"));
+
+        assertTrue(IOCase.SYSTEM.checkEquals("ABC", "ABC"));
+        assertEquals(WINDOWS, IOCase.SYSTEM.checkEquals("ABC", "Abc"));
+    }
 
     @Test
     public void test_checkEquals_functionality() {
@@ -145,74 +154,17 @@ public class IOCaseTestCase {
         } catch (final NullPointerException ignore) {}
     }
 
-    @Test
-    public void test_checkEquals_case() {
-        assertTrue(IOCase.SENSITIVE.checkEquals("ABC", "ABC"));
-        assertFalse(IOCase.SENSITIVE.checkEquals("ABC", "Abc"));
-
-        assertTrue(IOCase.INSENSITIVE.checkEquals("ABC", "ABC"));
-        assertTrue(IOCase.INSENSITIVE.checkEquals("ABC", "Abc"));
-
-        assertTrue(IOCase.SYSTEM.checkEquals("ABC", "ABC"));
-        assertEquals(WINDOWS, IOCase.SYSTEM.checkEquals("ABC", "Abc"));
-    }
-
-    @Test
-    public void test_checkStartsWith_functionality() {
-        assertTrue(IOCase.SENSITIVE.checkStartsWith("ABC", ""));
-        assertTrue(IOCase.SENSITIVE.checkStartsWith("ABC", "A"));
-        assertTrue(IOCase.SENSITIVE.checkStartsWith("ABC", "AB"));
-        assertTrue(IOCase.SENSITIVE.checkStartsWith("ABC", "ABC"));
-        assertFalse(IOCase.SENSITIVE.checkStartsWith("ABC", "BC"));
-        assertFalse(IOCase.SENSITIVE.checkStartsWith("ABC", "C"));
-        assertFalse(IOCase.SENSITIVE.checkStartsWith("ABC", "ABCD"));
-        assertFalse(IOCase.SENSITIVE.checkStartsWith("", "ABC"));
-        assertTrue(IOCase.SENSITIVE.checkStartsWith("", ""));
-
-        assertFalse(IOCase.SENSITIVE.checkStartsWith("ABC", null));
-        assertFalse(IOCase.SENSITIVE.checkStartsWith(null, "ABC"));
-        assertFalse(IOCase.SENSITIVE.checkStartsWith(null, null));
-    }
-
-    @Test
-    public void test_checkStartsWith_case() {
-        assertTrue(IOCase.SENSITIVE.checkStartsWith("ABC", "AB"));
-        assertFalse(IOCase.SENSITIVE.checkStartsWith("ABC", "Ab"));
-
-        assertTrue(IOCase.INSENSITIVE.checkStartsWith("ABC", "AB"));
-        assertTrue(IOCase.INSENSITIVE.checkStartsWith("ABC", "Ab"));
-
-        assertTrue(IOCase.SYSTEM.checkStartsWith("ABC", "AB"));
-        assertEquals(WINDOWS, IOCase.SYSTEM.checkStartsWith("ABC", "Ab"));
-    }
-
-    @Test
-    public void test_checkEndsWith_functionality() {
-        assertTrue(IOCase.SENSITIVE.checkEndsWith("ABC", ""));
-        assertFalse(IOCase.SENSITIVE.checkEndsWith("ABC", "A"));
-        assertFalse(IOCase.SENSITIVE.checkEndsWith("ABC", "AB"));
-        assertTrue(IOCase.SENSITIVE.checkEndsWith("ABC", "ABC"));
-        assertTrue(IOCase.SENSITIVE.checkEndsWith("ABC", "BC"));
-        assertTrue(IOCase.SENSITIVE.checkEndsWith("ABC", "C"));
-        assertFalse(IOCase.SENSITIVE.checkEndsWith("ABC", "ABCD"));
-        assertFalse(IOCase.SENSITIVE.checkEndsWith("", "ABC"));
-        assertTrue(IOCase.SENSITIVE.checkEndsWith("", ""));
-
-        assertFalse(IOCase.SENSITIVE.checkEndsWith("ABC", null));
-        assertFalse(IOCase.SENSITIVE.checkEndsWith(null, "ABC"));
-        assertFalse(IOCase.SENSITIVE.checkEndsWith(null, null));
-    }
 
     @Test
-    public void test_checkEndsWith_case() {
-        assertTrue(IOCase.SENSITIVE.checkEndsWith("ABC", "BC"));
-        assertFalse(IOCase.SENSITIVE.checkEndsWith("ABC", "Bc"));
+    public void test_checkIndexOf_case() {
+        assertEquals(1,  IOCase.SENSITIVE.checkIndexOf("ABC", 0, "BC"));
+        assertEquals(-1, IOCase.SENSITIVE.checkIndexOf("ABC", 0, "Bc"));
 
-        assertTrue(IOCase.INSENSITIVE.checkEndsWith("ABC", "BC"));
-        assertTrue(IOCase.INSENSITIVE.checkEndsWith("ABC", "Bc"));
+        assertEquals(1, IOCase.INSENSITIVE.checkIndexOf("ABC", 0, "BC"));
+        assertEquals(1, IOCase.INSENSITIVE.checkIndexOf("ABC", 0, "Bc"));
 
-        assertTrue(IOCase.SYSTEM.checkEndsWith("ABC", "BC"));
-        assertEquals(WINDOWS, IOCase.SYSTEM.checkEndsWith("ABC", "Bc"));
+        assertEquals(1, IOCase.SYSTEM.checkIndexOf("ABC", 0, "BC"));
+        assertEquals(WINDOWS ? 1 : -1, IOCase.SYSTEM.checkIndexOf("ABC", 0, "Bc"));
     }
 
     @Test
@@ -269,15 +221,15 @@ public class IOCaseTestCase {
     }
 
     @Test
-    public void test_checkIndexOf_case() {
-        assertEquals(1,  IOCase.SENSITIVE.checkIndexOf("ABC", 0, "BC"));
-        assertEquals(-1, IOCase.SENSITIVE.checkIndexOf("ABC", 0, "Bc"));
+    public void test_checkRegionMatches_case() {
+        assertTrue(IOCase.SENSITIVE.checkRegionMatches("ABC", 0, "AB"));
+        assertFalse(IOCase.SENSITIVE.checkRegionMatches("ABC", 0, "Ab"));
 
-        assertEquals(1, IOCase.INSENSITIVE.checkIndexOf("ABC", 0, "BC"));
-        assertEquals(1, IOCase.INSENSITIVE.checkIndexOf("ABC", 0, "Bc"));
+        assertTrue(IOCase.INSENSITIVE.checkRegionMatches("ABC", 0, "AB"));
+        assertTrue(IOCase.INSENSITIVE.checkRegionMatches("ABC", 0, "Ab"));
 
-        assertEquals(1, IOCase.SYSTEM.checkIndexOf("ABC", 0, "BC"));
-        assertEquals(WINDOWS ? 1 : -1, IOCase.SYSTEM.checkIndexOf("ABC", 0, "Bc"));
+        assertTrue(IOCase.SYSTEM.checkRegionMatches("ABC", 0, "AB"));
+        assertEquals(WINDOWS, IOCase.SYSTEM.checkRegionMatches("ABC", 0, "Ab"));
     }
 
     @Test
@@ -329,27 +281,75 @@ public class IOCaseTestCase {
     }
 
     @Test
-    public void test_checkRegionMatches_case() {
-        assertTrue(IOCase.SENSITIVE.checkRegionMatches("ABC", 0, "AB"));
-        assertFalse(IOCase.SENSITIVE.checkRegionMatches("ABC", 0, "Ab"));
+    public void test_checkStartsWith_case() {
+        assertTrue(IOCase.SENSITIVE.checkStartsWith("ABC", "AB"));
+        assertFalse(IOCase.SENSITIVE.checkStartsWith("ABC", "Ab"));
 
-        assertTrue(IOCase.INSENSITIVE.checkRegionMatches("ABC", 0, "AB"));
-        assertTrue(IOCase.INSENSITIVE.checkRegionMatches("ABC", 0, "Ab"));
+        assertTrue(IOCase.INSENSITIVE.checkStartsWith("ABC", "AB"));
+        assertTrue(IOCase.INSENSITIVE.checkStartsWith("ABC", "Ab"));
 
-        assertTrue(IOCase.SYSTEM.checkRegionMatches("ABC", 0, "AB"));
-        assertEquals(WINDOWS, IOCase.SYSTEM.checkRegionMatches("ABC", 0, "Ab"));
+        assertTrue(IOCase.SYSTEM.checkStartsWith("ABC", "AB"));
+        assertEquals(WINDOWS, IOCase.SYSTEM.checkStartsWith("ABC", "Ab"));
     }
 
-    private IOCase serialize(final IOCase value) throws Exception {
-        final ByteArrayOutputStream buf = new ByteArrayOutputStream();
-        final ObjectOutputStream out = new ObjectOutputStream(buf);
-        out.writeObject(value);
-        out.flush();
-        out.close();
+    @Test
+    public void test_checkStartsWith_functionality() {
+        assertTrue(IOCase.SENSITIVE.checkStartsWith("ABC", ""));
+        assertTrue(IOCase.SENSITIVE.checkStartsWith("ABC", "A"));
+        assertTrue(IOCase.SENSITIVE.checkStartsWith("ABC", "AB"));
+        assertTrue(IOCase.SENSITIVE.checkStartsWith("ABC", "ABC"));
+        assertFalse(IOCase.SENSITIVE.checkStartsWith("ABC", "BC"));
+        assertFalse(IOCase.SENSITIVE.checkStartsWith("ABC", "C"));
+        assertFalse(IOCase.SENSITIVE.checkStartsWith("ABC", "ABCD"));
+        assertFalse(IOCase.SENSITIVE.checkStartsWith("", "ABC"));
+        assertTrue(IOCase.SENSITIVE.checkStartsWith("", ""));
 
-        final ByteArrayInputStream bufin = new ByteArrayInputStream(buf.toByteArray());
-        final ObjectInputStream in = new ObjectInputStream(bufin);
-        return (IOCase) in.readObject();
+        assertFalse(IOCase.SENSITIVE.checkStartsWith("ABC", null));
+        assertFalse(IOCase.SENSITIVE.checkStartsWith(null, "ABC"));
+        assertFalse(IOCase.SENSITIVE.checkStartsWith(null, null));
+    }
+
+    @Test
+    public void test_forName() {
+        assertEquals(IOCase.SENSITIVE, IOCase.forName("Sensitive"));
+        assertEquals(IOCase.INSENSITIVE, IOCase.forName("Insensitive"));
+        assertEquals(IOCase.SYSTEM, IOCase.forName("System"));
+        try {
+            IOCase.forName("Blah");
+            fail();
+        } catch (final IllegalArgumentException ignore) {}
+        try {
+            IOCase.forName(null);
+            fail();
+        } catch (final IllegalArgumentException ignore) {}
+    }
+
+    @Test
+    public void test_getName() {
+        assertEquals("Sensitive", IOCase.SENSITIVE.getName());
+        assertEquals("Insensitive", IOCase.INSENSITIVE.getName());
+        assertEquals("System", IOCase.SYSTEM.getName());
+    }
+
+    @Test
+    public void test_isCaseSensitive() {
+        assertTrue(IOCase.SENSITIVE.isCaseSensitive());
+        assertFalse(IOCase.INSENSITIVE.isCaseSensitive());
+        assertEquals(!WINDOWS, IOCase.SYSTEM.isCaseSensitive());
+    }
+
+    @Test
+    public void test_serialization() throws Exception {
+        assertSame(IOCase.SENSITIVE, serialize(IOCase.SENSITIVE));
+        assertSame(IOCase.INSENSITIVE, serialize(IOCase.INSENSITIVE));
+        assertSame(IOCase.SYSTEM, serialize(IOCase.SYSTEM));
+    }
+
+    @Test
+    public void test_toString() {
+        assertEquals("Sensitive", IOCase.SENSITIVE.toString());
+        assertEquals("Insensitive", IOCase.INSENSITIVE.toString());
+        assertEquals("System", IOCase.SYSTEM.toString());
     }
 
 }
diff --git a/src/test/java/org/apache/commons/io/IOUtilsTestCase.java b/src/test/java/org/apache/commons/io/IOUtilsTestCase.java
index 30fa881..0e5b6b6 100644
--- a/src/test/java/org/apache/commons/io/IOUtilsTestCase.java
+++ b/src/test/java/org/apache/commons/io/IOUtilsTestCase.java
@@ -1500,22 +1500,22 @@ public class IOUtilsTestCase {
     }
 
     @Test
-    public void testToByteArray_InputStream_SizeZero() throws Exception {
+    public void testToByteArray_InputStream_SizeOne() throws Exception {
 
-        try (InputStream fin =Files.newInputStream(testFilePath)) {
-            final byte[] out = IOUtils.toByteArray(fin, 0);
+        try (InputStream fin = Files.newInputStream(testFilePath)) {
+            final byte[] out = IOUtils.toByteArray(fin, 1);
             assertNotNull(out, "Out cannot be null");
-            assertEquals(0, out.length, "Out length must be 0");
+            assertEquals(1, out.length, "Out length must be 1");
         }
     }
 
     @Test
-    public void testToByteArray_InputStream_SizeOne() throws Exception {
+    public void testToByteArray_InputStream_SizeZero() throws Exception {
 
-        try (InputStream fin = Files.newInputStream(testFilePath)) {
-            final byte[] out = IOUtils.toByteArray(fin, 1);
+        try (InputStream fin =Files.newInputStream(testFilePath)) {
+            final byte[] out = IOUtils.toByteArray(fin, 0);
             assertNotNull(out, "Out cannot be null");
-            assertEquals(1, out.length, "Out length must be 1");
+            assertEquals(0, out.length, "Out length must be 0");
         }
     }
 
diff --git a/src/test/java/org/apache/commons/io/IOUtilsWriteTestCase.java b/src/test/java/org/apache/commons/io/IOUtilsWriteTestCase.java
index 399e7af..dba3467 100644
--- a/src/test/java/org/apache/commons/io/IOUtilsWriteTestCase.java
+++ b/src/test/java/org/apache/commons/io/IOUtilsWriteTestCase.java
@@ -94,56 +94,48 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWrite_byteArrayToWriter_nullData() throws Exception {
+    public void testWrite_byteArrayToWriter_Encoding() throws Exception {
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         @SuppressWarnings("resource") // deliberately not closed
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
         final Writer writer = new OutputStreamWriter(baout, StandardCharsets.US_ASCII);
 
-        IOUtils.write((byte[]) null, writer);
+        IOUtils.write(inData, writer, "UTF8");
         out.off();
         writer.flush();
 
-        assertEquals(0, baout.size(), "Sizes differ");
-    }
-
-    @Test
-    public void testWrite_byteArrayToWriter_nullWriter() throws Exception {
-        try {
-            IOUtils.write(inData, (Writer) null);
-            fail();
-        } catch (final NullPointerException ignore) {
-        }
+        byte[] bytes = baout.toByteArray();
+        bytes = new String(bytes, StandardCharsets.UTF_8).getBytes(StandardCharsets.US_ASCII);
+        assertArrayEquals(inData, bytes, "Content differs");
     }
 
     @Test
-    public void testWrite_byteArrayToWriter_Encoding() throws Exception {
+    public void testWrite_byteArrayToWriter_Encoding_nullData() throws Exception {
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         @SuppressWarnings("resource") // deliberately not closed
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
         final Writer writer = new OutputStreamWriter(baout, StandardCharsets.US_ASCII);
 
-        IOUtils.write(inData, writer, "UTF8");
+        IOUtils.write(null, writer, "UTF8");
         out.off();
         writer.flush();
 
-        byte[] bytes = baout.toByteArray();
-        bytes = new String(bytes, StandardCharsets.UTF_8).getBytes(StandardCharsets.US_ASCII);
-        assertArrayEquals(inData, bytes, "Content differs");
+        assertEquals(0, baout.size(), "Sizes differ");
     }
 
     @Test
-    public void testWrite_byteArrayToWriter_Encoding_nullData() throws Exception {
+    public void testWrite_byteArrayToWriter_Encoding_nullEncoding() throws Exception {
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         @SuppressWarnings("resource") // deliberately not closed
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
         final Writer writer = new OutputStreamWriter(baout, StandardCharsets.US_ASCII);
 
-        IOUtils.write(null, writer, "UTF8");
+        IOUtils.write(inData, writer, (String) null);
         out.off();
         writer.flush();
 
-        assertEquals(0, baout.size(), "Sizes differ");
+        assertEquals(inData.length, baout.size(), "Sizes differ");
+        assertArrayEquals(inData, baout.toByteArray(), "Content differs");
     }
 
     @Test
@@ -156,65 +148,51 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWrite_byteArrayToWriter_Encoding_nullEncoding() throws Exception {
+    public void testWrite_byteArrayToWriter_nullData() throws Exception {
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         @SuppressWarnings("resource") // deliberately not closed
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
         final Writer writer = new OutputStreamWriter(baout, StandardCharsets.US_ASCII);
 
-        IOUtils.write(inData, writer, (String) null);
+        IOUtils.write((byte[]) null, writer);
         out.off();
         writer.flush();
 
-        assertEquals(inData.length, baout.size(), "Sizes differ");
-        assertArrayEquals(inData, baout.toByteArray(), "Content differs");
+        assertEquals(0, baout.size(), "Sizes differ");
     }
 
     @Test
-    public void testWrite_charSequenceToOutputStream() throws Exception {
-        final CharSequence csq = new StringBuilder(new String(inData, StandardCharsets.US_ASCII));
-
-        final ByteArrayOutputStream baout = new ByteArrayOutputStream();
-        final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
-
-        IOUtils.write(csq, out);
-        out.off();
-        out.flush();
-
-        assertEquals(inData.length, baout.size(), "Sizes differ");
-        assertArrayEquals(inData, baout.toByteArray(), "Content differs");
+    public void testWrite_byteArrayToWriter_nullWriter() throws Exception {
+        try {
+            IOUtils.write(inData, (Writer) null);
+            fail();
+        } catch (final NullPointerException ignore) {
+        }
     }
 
     @Test
-    public void testWrite_charSequenceToOutputStream_nullData() throws Exception {
+    public void testWrite_charArrayToOutputStream() throws Exception {
+        final String str = new String(inData, StandardCharsets.US_ASCII);
+
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
 
-        IOUtils.write((CharSequence) null, out);
+        IOUtils.write(str.toCharArray(), out);
         out.off();
         out.flush();
 
-        assertEquals(0, baout.size(), "Sizes differ");
-    }
-
-    @Test
-    public void testWrite_charSequenceToOutputStream_nullStream() throws Exception {
-        final CharSequence csq = new StringBuilder(new String(inData, StandardCharsets.US_ASCII));
-        try {
-            IOUtils.write(csq, (OutputStream) null);
-            fail();
-        } catch (final NullPointerException ignore) {
-        }
+        assertEquals(inData.length, baout.size(), "Sizes differ");
+        assertArrayEquals(inData, baout.toByteArray(), "Content differs");
     }
 
     @Test
-    public void testWrite_charSequenceToOutputStream_Encoding() throws Exception {
-        final CharSequence csq = new StringBuilder(new String(inData, StandardCharsets.US_ASCII));
+    public void testWrite_charArrayToOutputStream_Encoding() throws Exception {
+        final String str = new String(inData, StandardCharsets.US_ASCII);
 
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
 
-        IOUtils.write(csq, out, "UTF16");
+        IOUtils.write(str.toCharArray(), out, "UTF16");
         out.off();
         out.flush();
 
@@ -224,11 +202,11 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWrite_charSequenceToOutputStream_Encoding_nullData() throws Exception {
+    public void testWrite_charArrayToOutputStream_Encoding_nullData() throws Exception {
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
 
-        IOUtils.write((CharSequence) null, out);
+        IOUtils.write((char[]) null, out);
         out.off();
         out.flush();
 
@@ -236,23 +214,35 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWrite_charSequenceToOutputStream_Encoding_nullStream() throws Exception {
-        final CharSequence csq = new StringBuilder(new String(inData, StandardCharsets.US_ASCII));
+    public void testWrite_charArrayToOutputStream_Encoding_nullStream() throws Exception {
+        final String str = new String(inData, StandardCharsets.US_ASCII);
         try {
-            IOUtils.write(csq, (OutputStream) null);
+            IOUtils.write(str.toCharArray(), (OutputStream) null);
             fail();
         } catch (final NullPointerException ignore) {
         }
     }
 
     @Test
-    public void testWrite_charSequenceToOutputStream_nullEncoding() throws Exception {
-        final CharSequence csq = new StringBuilder(new String(inData, StandardCharsets.US_ASCII));
+    public void testWrite_charArrayToOutputStream_nullData() throws Exception {
+        final ByteArrayOutputStream baout = new ByteArrayOutputStream();
+        final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
+
+        IOUtils.write((char[]) null, out);
+        out.off();
+        out.flush();
+
+        assertEquals(0, baout.size(), "Sizes differ");
+    }
+
+    @Test
+    public void testWrite_charArrayToOutputStream_nullEncoding() throws Exception {
+        final String str = new String(inData, StandardCharsets.US_ASCII);
 
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
 
-        IOUtils.write(csq, out, (String) null);
+        IOUtils.write(str.toCharArray(), out, (String) null);
         out.off();
         out.flush();
 
@@ -261,15 +251,25 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWrite_charSequenceToWriter() throws Exception {
-        final CharSequence csq = new StringBuilder(new String(inData, StandardCharsets.US_ASCII));
+    public void testWrite_charArrayToOutputStream_nullStream() throws Exception {
+        final String str = new String(inData, StandardCharsets.US_ASCII);
+        try {
+            IOUtils.write(str.toCharArray(), (OutputStream) null);
+            fail();
+        } catch (final NullPointerException ignore) {
+        }
+    }
+
+    @Test
+    public void testWrite_charArrayToWriter() throws Exception {
+        final String str = new String(inData, StandardCharsets.US_ASCII);
 
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         @SuppressWarnings("resource") // deliberately not closed
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
         final Writer writer = new OutputStreamWriter(baout, StandardCharsets.US_ASCII);
 
-        IOUtils.write(csq, writer);
+        IOUtils.write(str.toCharArray(), writer);
         out.off();
         writer.flush();
 
@@ -278,13 +278,13 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWrite_charSequenceToWriter_Encoding_nullData() throws Exception {
+    public void testWrite_charArrayToWriter_Encoding_nullData() throws Exception {
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         @SuppressWarnings("resource") // deliberately not closed
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
         final Writer writer = new OutputStreamWriter(baout, StandardCharsets.US_ASCII);
 
-        IOUtils.write((CharSequence) null, writer);
+        IOUtils.write((char[]) null, writer);
         out.off();
         writer.flush();
 
@@ -292,23 +292,23 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWrite_charSequenceToWriter_Encoding_nullStream() throws Exception {
-        final CharSequence csq = new StringBuilder(new String(inData, StandardCharsets.US_ASCII));
+    public void testWrite_charArrayToWriter_Encoding_nullStream() throws Exception {
+        final String str = new String(inData, StandardCharsets.US_ASCII);
         try {
-            IOUtils.write(csq, (Writer) null);
+            IOUtils.write(str.toCharArray(), (Writer) null);
             fail();
         } catch (final NullPointerException ignore) {
         }
     }
 
     @Test
-    public void testWrite_stringToOutputStream() throws Exception {
-        final String str = new String(inData, StandardCharsets.US_ASCII);
+    public void testWrite_charSequenceToOutputStream() throws Exception {
+        final CharSequence csq = new StringBuilder(new String(inData, StandardCharsets.US_ASCII));
 
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
 
-        IOUtils.write(str, out);
+        IOUtils.write(csq, out);
         out.off();
         out.flush();
 
@@ -317,35 +317,13 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWrite_stringToOutputStream_nullData() throws Exception {
-        final ByteArrayOutputStream baout = new ByteArrayOutputStream();
-        final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
-
-        IOUtils.write((String) null, out);
-        out.off();
-        out.flush();
-
-        assertEquals(0, baout.size(), "Sizes differ");
-    }
-
-    @Test
-    public void testWrite_stringToOutputStream_nullStream() throws Exception {
-        final String str = new String(inData, StandardCharsets.US_ASCII);
-        try {
-            IOUtils.write(str, (OutputStream) null);
-            fail();
-        } catch (final NullPointerException ignore) {
-        }
-    }
-
-    @Test
-    public void testWrite_stringToOutputStream_Encoding() throws Exception {
-        final String str = new String(inData, StandardCharsets.US_ASCII);
+    public void testWrite_charSequenceToOutputStream_Encoding() throws Exception {
+        final CharSequence csq = new StringBuilder(new String(inData, StandardCharsets.US_ASCII));
 
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
 
-        IOUtils.write(str, out, "UTF16");
+        IOUtils.write(csq, out, "UTF16");
         out.off();
         out.flush();
 
@@ -355,11 +333,11 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWrite_stringToOutputStream_Encoding_nullData() throws Exception {
+    public void testWrite_charSequenceToOutputStream_Encoding_nullData() throws Exception {
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
 
-        IOUtils.write((String) null, out);
+        IOUtils.write((CharSequence) null, out);
         out.off();
         out.flush();
 
@@ -367,23 +345,35 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWrite_stringToOutputStream_Encoding_nullStream() throws Exception {
-        final String str = new String(inData, StandardCharsets.US_ASCII);
+    public void testWrite_charSequenceToOutputStream_Encoding_nullStream() throws Exception {
+        final CharSequence csq = new StringBuilder(new String(inData, StandardCharsets.US_ASCII));
         try {
-            IOUtils.write(str, (OutputStream) null);
+            IOUtils.write(csq, (OutputStream) null);
             fail();
         } catch (final NullPointerException ignore) {
         }
     }
 
     @Test
-    public void testWrite_stringToOutputStream_nullEncoding() throws Exception {
-        final String str = new String(inData, StandardCharsets.US_ASCII);
+    public void testWrite_charSequenceToOutputStream_nullData() throws Exception {
+        final ByteArrayOutputStream baout = new ByteArrayOutputStream();
+        final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
+
+        IOUtils.write((CharSequence) null, out);
+        out.off();
+        out.flush();
+
+        assertEquals(0, baout.size(), "Sizes differ");
+    }
+
+    @Test
+    public void testWrite_charSequenceToOutputStream_nullEncoding() throws Exception {
+        final CharSequence csq = new StringBuilder(new String(inData, StandardCharsets.US_ASCII));
 
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
 
-        IOUtils.write(str, out, (String) null);
+        IOUtils.write(csq, out, (String) null);
         out.off();
         out.flush();
 
@@ -392,15 +382,25 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWrite_stringToWriter() throws Exception {
-        final String str = new String(inData, StandardCharsets.US_ASCII);
+    public void testWrite_charSequenceToOutputStream_nullStream() throws Exception {
+        final CharSequence csq = new StringBuilder(new String(inData, StandardCharsets.US_ASCII));
+        try {
+            IOUtils.write(csq, (OutputStream) null);
+            fail();
+        } catch (final NullPointerException ignore) {
+        }
+    }
+
+    @Test
+    public void testWrite_charSequenceToWriter() throws Exception {
+        final CharSequence csq = new StringBuilder(new String(inData, StandardCharsets.US_ASCII));
 
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         @SuppressWarnings("resource") // deliberately not closed
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
         final Writer writer = new OutputStreamWriter(baout, StandardCharsets.US_ASCII);
 
-        IOUtils.write(str, writer);
+        IOUtils.write(csq, writer);
         out.off();
         writer.flush();
 
@@ -409,13 +409,13 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWrite_stringToWriter_Encoding_nullData() throws Exception {
+    public void testWrite_charSequenceToWriter_Encoding_nullData() throws Exception {
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         @SuppressWarnings("resource") // deliberately not closed
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
         final Writer writer = new OutputStreamWriter(baout, StandardCharsets.US_ASCII);
 
-        IOUtils.write((String) null, writer);
+        IOUtils.write((CharSequence) null, writer);
         out.off();
         writer.flush();
 
@@ -423,23 +423,23 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWrite_stringToWriter_Encoding_nullStream() throws Exception {
-        final String str = new String(inData, StandardCharsets.US_ASCII);
+    public void testWrite_charSequenceToWriter_Encoding_nullStream() throws Exception {
+        final CharSequence csq = new StringBuilder(new String(inData, StandardCharsets.US_ASCII));
         try {
-            IOUtils.write(str, (Writer) null);
+            IOUtils.write(csq, (Writer) null);
             fail();
         } catch (final NullPointerException ignore) {
         }
     }
 
     @Test
-    public void testWrite_charArrayToOutputStream() throws Exception {
+    public void testWrite_stringToOutputStream() throws Exception {
         final String str = new String(inData, StandardCharsets.US_ASCII);
 
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
 
-        IOUtils.write(str.toCharArray(), out);
+        IOUtils.write(str, out);
         out.off();
         out.flush();
 
@@ -448,35 +448,13 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWrite_charArrayToOutputStream_nullData() throws Exception {
-        final ByteArrayOutputStream baout = new ByteArrayOutputStream();
-        final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
-
-        IOUtils.write((char[]) null, out);
-        out.off();
-        out.flush();
-
-        assertEquals(0, baout.size(), "Sizes differ");
-    }
-
-    @Test
-    public void testWrite_charArrayToOutputStream_nullStream() throws Exception {
-        final String str = new String(inData, StandardCharsets.US_ASCII);
-        try {
-            IOUtils.write(str.toCharArray(), (OutputStream) null);
-            fail();
-        } catch (final NullPointerException ignore) {
-        }
-    }
-
-    @Test
-    public void testWrite_charArrayToOutputStream_Encoding() throws Exception {
+    public void testWrite_stringToOutputStream_Encoding() throws Exception {
         final String str = new String(inData, StandardCharsets.US_ASCII);
 
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
 
-        IOUtils.write(str.toCharArray(), out, "UTF16");
+        IOUtils.write(str, out, "UTF16");
         out.off();
         out.flush();
 
@@ -486,11 +464,11 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWrite_charArrayToOutputStream_Encoding_nullData() throws Exception {
+    public void testWrite_stringToOutputStream_Encoding_nullData() throws Exception {
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
 
-        IOUtils.write((char[]) null, out);
+        IOUtils.write((String) null, out);
         out.off();
         out.flush();
 
@@ -498,23 +476,35 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWrite_charArrayToOutputStream_Encoding_nullStream() throws Exception {
+    public void testWrite_stringToOutputStream_Encoding_nullStream() throws Exception {
         final String str = new String(inData, StandardCharsets.US_ASCII);
         try {
-            IOUtils.write(str.toCharArray(), (OutputStream) null);
+            IOUtils.write(str, (OutputStream) null);
             fail();
         } catch (final NullPointerException ignore) {
         }
     }
 
     @Test
-    public void testWrite_charArrayToOutputStream_nullEncoding() throws Exception {
+    public void testWrite_stringToOutputStream_nullData() throws Exception {
+        final ByteArrayOutputStream baout = new ByteArrayOutputStream();
+        final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
+
+        IOUtils.write((String) null, out);
+        out.off();
+        out.flush();
+
+        assertEquals(0, baout.size(), "Sizes differ");
+    }
+
+    @Test
+    public void testWrite_stringToOutputStream_nullEncoding() throws Exception {
         final String str = new String(inData, StandardCharsets.US_ASCII);
 
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
 
-        IOUtils.write(str.toCharArray(), out, (String) null);
+        IOUtils.write(str, out, (String) null);
         out.off();
         out.flush();
 
@@ -523,7 +513,17 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWrite_charArrayToWriter() throws Exception {
+    public void testWrite_stringToOutputStream_nullStream() throws Exception {
+        final String str = new String(inData, StandardCharsets.US_ASCII);
+        try {
+            IOUtils.write(str, (OutputStream) null);
+            fail();
+        } catch (final NullPointerException ignore) {
+        }
+    }
+
+    @Test
+    public void testWrite_stringToWriter() throws Exception {
         final String str = new String(inData, StandardCharsets.US_ASCII);
 
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
@@ -531,7 +531,7 @@ public class IOUtilsWriteTestCase {
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
         final Writer writer = new OutputStreamWriter(baout, StandardCharsets.US_ASCII);
 
-        IOUtils.write(str.toCharArray(), writer);
+        IOUtils.write(str, writer);
         out.off();
         writer.flush();
 
@@ -540,13 +540,13 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWrite_charArrayToWriter_Encoding_nullData() throws Exception {
+    public void testWrite_stringToWriter_Encoding_nullData() throws Exception {
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         @SuppressWarnings("resource") // deliberately not closed
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, true, true);
         final Writer writer = new OutputStreamWriter(baout, StandardCharsets.US_ASCII);
 
-        IOUtils.write((char[]) null, writer);
+        IOUtils.write((String) null, writer);
         out.off();
         writer.flush();
 
@@ -554,10 +554,10 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWrite_charArrayToWriter_Encoding_nullStream() throws Exception {
+    public void testWrite_stringToWriter_Encoding_nullStream() throws Exception {
         final String str = new String(inData, StandardCharsets.US_ASCII);
         try {
-            IOUtils.write(str.toCharArray(), (Writer) null);
+            IOUtils.write(str, (Writer) null);
             fail();
         } catch (final NullPointerException ignore) {
         }
@@ -583,77 +583,56 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWriteLines_OutputStream_nullData() throws Exception {
+    public void testWriteLines_OutputStream_Encoding() throws Exception {
+        final Object[] data = {
+                "hello\u8364", new StringBuffer("world"), "", "this is", null, "some text"};
+        final List<Object> list = Arrays.asList(data);
+
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, false, true);
 
-        IOUtils.writeLines(null, "*", out);
+        IOUtils.writeLines(list, "*", out, "UTF-8");
+
         out.off();
         out.flush();
 
-        assertEquals(0, baout.size(), "Sizes differ");
+        final String expected = "hello\u8364*world**this is**some text*";
+        final String actual = baout.toString("UTF-8");
+        assertEquals(expected, actual);
     }
 
     @Test
-    public void testWriteLines_OutputStream_nullSeparator() throws Exception {
-        final Object[] data = {"hello", "world"};
-        final List<Object> list = Arrays.asList(data);
-
+    public void testWriteLines_OutputStream_Encoding_nullData() throws Exception {
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, false, true);
 
-        IOUtils.writeLines(list, null, out);
+        IOUtils.writeLines(null, "*", out, "US-ASCII");
         out.off();
         out.flush();
 
-        final String expected = "hello" + System.lineSeparator() + "world" + System.lineSeparator();
-        final String actual = baout.toString();
-        assertEquals(expected, actual);
-    }
-
-    @Test
-    public void testWriteLines_OutputStream_nullStream() throws Exception {
-        final Object[] data = {"hello", "world"};
-        final List<Object> list = Arrays.asList(data);
-        try {
-            IOUtils.writeLines(list, "*", (OutputStream) null);
-            fail();
-        } catch (final NullPointerException ignore) {
-        }
+        assertEquals(0, baout.size(), "Sizes differ");
     }
 
     @Test
-    public void testWriteLines_OutputStream_Encoding() throws Exception {
+    public void testWriteLines_OutputStream_Encoding_nullEncoding() throws Exception {
         final Object[] data = {
-                "hello\u8364", new StringBuffer("world"), "", "this is", null, "some text"};
+                "hello", new StringBuffer("world"), "", "this is", null, "some text"};
         final List<Object> list = Arrays.asList(data);
 
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, false, true);
 
-        IOUtils.writeLines(list, "*", out, "UTF-8");
+        IOUtils.writeLines(list, "*", out, (String) null);
 
         out.off();
         out.flush();
 
-        final String expected = "hello\u8364*world**this is**some text*";
-        final String actual = baout.toString("UTF-8");
+        final String expected = "hello*world**this is**some text*";
+        final String actual = baout.toString();
         assertEquals(expected, actual);
     }
 
     @Test
-    public void testWriteLines_OutputStream_Encoding_nullData() throws Exception {
-        final ByteArrayOutputStream baout = new ByteArrayOutputStream();
-        final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, false, true);
-
-        IOUtils.writeLines(null, "*", out, "US-ASCII");
-        out.off();
-        out.flush();
-
-        assertEquals(0, baout.size(), "Sizes differ");
-    }
-
-    @Test
     public void testWriteLines_OutputStream_Encoding_nullSeparator() throws Exception {
         final Object[] data = {"hello", "world"};
         final List<Object> list = Arrays.asList(data);
@@ -682,25 +661,46 @@ public class IOUtilsWriteTestCase {
     }
 
     @Test
-    public void testWriteLines_OutputStream_Encoding_nullEncoding() throws Exception {
-        final Object[] data = {
-                "hello", new StringBuffer("world"), "", "this is", null, "some text"};
+    public void testWriteLines_OutputStream_nullData() throws Exception {
+        final ByteArrayOutputStream baout = new ByteArrayOutputStream();
+        final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, false, true);
+
+        IOUtils.writeLines(null, "*", out);
+        out.off();
+        out.flush();
+
+        assertEquals(0, baout.size(), "Sizes differ");
+    }
+
+    @Test
+    public void testWriteLines_OutputStream_nullSeparator() throws Exception {
+        final Object[] data = {"hello", "world"};
         final List<Object> list = Arrays.asList(data);
 
         final ByteArrayOutputStream baout = new ByteArrayOutputStream();
         final ThrowOnFlushAndCloseOutputStream out = new ThrowOnFlushAndCloseOutputStream(baout, false, true);
 
-        IOUtils.writeLines(list, "*", out, (String) null);
-
+        IOUtils.writeLines(list, null, out);
         out.off();
         out.flush();
 
-        final String expected = "hello*world**this is**some text*";
+        final String expected = "hello" + System.lineSeparator() + "world" + System.lineSeparator();
         final String actual = baout.toString();
         assertEquals(expected, actual);
     }
 
     @Test
+    public void testWriteLines_OutputStream_nullStream() throws Exception {
+        final Object[] data = {"hello", "world"};
+        final List<Object> list = Arrays.asList(data);
+        try {
+            IOUtils.writeLines(list, "*", (OutputStream) null);
+            fail();
+        } catch (final NullPointerException ignore) {
+        }
+    }
+
+    @Test
     public void testWriteLines_Writer() throws Exception {
         final Object[] data = {
                 "hello", new StringBuffer("world"), "", "this is", null, "some text"};
diff --git a/src/test/java/org/apache/commons/io/LineIteratorTestCase.java b/src/test/java/org/apache/commons/io/LineIteratorTestCase.java
index 82831ca..bad2b33 100644
--- a/src/test/java/org/apache/commons/io/LineIteratorTestCase.java
+++ b/src/test/java/org/apache/commons/io/LineIteratorTestCase.java
@@ -110,6 +110,62 @@ public class LineIteratorTestCase {
 
     // -----------------------------------------------------------------------
 
+    /**
+     * Utility method to create and test a file with a specified number of lines.
+     *
+     * @param lineCount the lines to create in the test file
+     *
+     * @throws IOException If an I/O error occurs while creating the file
+     */
+    private void doTestFileWithSpecifiedLines(final int lineCount) throws IOException {
+        final String encoding = "UTF-8";
+
+        final String fileName = "LineIterator-" + lineCount + "-test.txt";
+        final File testFile = new File(temporaryFolder, fileName);
+        final List<String> lines = createLinesFile(testFile, encoding, lineCount);
+
+        try (final LineIterator iterator = FileUtils.lineIterator(testFile, encoding)) {
+            assertThrows(UnsupportedOperationException.class, iterator::remove);
+
+            int idx = 0;
+            while (iterator.hasNext()) {
+                final String line = iterator.next();
+                assertEquals(lines.get(idx), line, "Comparing line " + idx);
+                assertTrue(idx < lines.size(), "Exceeded expected idx=" + idx + " size=" + lines.size());
+                idx++;
+            }
+            assertEquals(idx, lines.size(), "Line Count doesn't match");
+
+            // try calling next() after file processed
+            assertThrows(NoSuchElementException.class, iterator::next);
+            assertThrows(NoSuchElementException.class, iterator::nextLine);
+        }
+    }
+
+    @Test
+    public void testCloseEarly() throws Exception {
+        final String encoding = "UTF-8";
+
+        final File testFile = new File(temporaryFolder, "LineIterator-closeEarly.txt");
+        createLinesFile(testFile, encoding, 3);
+
+        try (final LineIterator iterator = FileUtils.lineIterator(testFile, encoding)) {
+            // get
+            assertNotNull("Line expected", iterator.next());
+            assertTrue(iterator.hasNext(), "More expected");
+
+            // close
+            iterator.close();
+            assertFalse(iterator.hasNext(), "No more expected");
+            assertThrows(NoSuchElementException.class, iterator::next);
+            assertThrows(NoSuchElementException.class, iterator::nextLine);
+            // try closing again
+            iterator.close();
+            assertThrows(NoSuchElementException.class, iterator::next);
+            assertThrows(NoSuchElementException.class, iterator::nextLine);
+        }
+    }
+
     @Test
     public void testConstructor() {
         assertThrows(IllegalArgumentException.class, () -> {
@@ -118,47 +174,68 @@ public class LineIteratorTestCase {
         });
     }
 
-    @Test
-    public void testZeroLines() throws Exception {
-        doTestFileWithSpecifiedLines(0);
-    }
+    private void testFiltering(final List<String> lines, final Reader reader) {
+        final LineIterator iterator = new LineIterator(reader) {
+            @Override
+            protected boolean isValidLine(final String line) {
+                final char c = line.charAt(line.length() - 1);
+                return (c - 48) % 3 != 1;
+            }
+        };
+        try {
+            assertThrows(UnsupportedOperationException.class, iterator::remove);
 
-    @Test
-    public void testOneLines() throws Exception {
-        doTestFileWithSpecifiedLines(1);
-    }
+            int idx = 0;
+            int actualLines = 0;
+            while (iterator.hasNext()) {
+                final String line = iterator.next();
+                actualLines++;
+                assertEquals(lines.get(idx), line, "Comparing line " + idx);
+                assertTrue(idx < lines.size(), "Exceeded expected idx=" + idx + " size=" + lines.size());
+                idx++;
+                if (idx % 3 == 1) {
+                    idx++;
+                }
+            }
+            assertEquals(9, lines.size(), "Line Count doesn't match");
+            assertEquals(9, idx, "Line Count doesn't match");
+            assertEquals(6, actualLines, "Line Count doesn't match");
 
-    @Test
-    public void testTwoLines() throws Exception {
-        doTestFileWithSpecifiedLines(2);
+            // try calling next() after file processed
+            assertThrows(NoSuchElementException.class, iterator::next);
+            assertThrows(NoSuchElementException.class, iterator::nextLine);
+        } finally {
+            try {
+                IOUtils.close(iterator);
+            } catch (final IOException ignored) {
+                // Ignored
+            }
+        }
     }
 
     @Test
-    public void testThreeLines() throws Exception {
-        doTestFileWithSpecifiedLines(3);
-    }
+    public void testFilteringBufferedReader() throws Exception {
+        final String encoding = "UTF-8";
 
-    @Test
-    public void testMissingFile() throws Exception {
-        final File testFile = new File(temporaryFolder, "dummy-missing-file.txt");
-        assertThrows(NoSuchFileException.class, () -> FileUtils.lineIterator(testFile, "UTF-8"));
+        final String fileName = "LineIterator-Filter-test.txt";
+        final File testFile = new File(temporaryFolder, fileName);
+        final List<String> lines = createLinesFile(testFile, encoding, 9);
+
+        final Reader reader = new BufferedReader(Files.newBufferedReader(testFile.toPath()));
+        this.testFiltering(lines, reader);
     }
 
+    // -----------------------------------------------------------------------
     @Test
-    public void testValidEncoding() throws Exception {
+    public void testFilteringFileReader() throws Exception {
         final String encoding = "UTF-8";
 
-        final File testFile = new File(temporaryFolder, "LineIterator-validEncoding.txt");
-        createLinesFile(testFile, encoding, 3);
+        final String fileName = "LineIterator-Filter-test.txt";
+        final File testFile = new File(temporaryFolder, fileName);
+        final List<String> lines = createLinesFile(testFile, encoding, 9);
 
-        try (final LineIterator iterator = FileUtils.lineIterator(testFile, encoding)) {
-            int count = 0;
-            while (iterator.hasNext()) {
-                assertNotNull(iterator.next());
-                count++;
-            }
-            assertEquals(3, count);
-        }
+        final Reader reader = Files.newBufferedReader(testFile.toPath());
+        this.testFiltering(lines, reader);
     }
 
     @Test
@@ -172,6 +249,12 @@ public class LineIteratorTestCase {
     }
 
     @Test
+    public void testMissingFile() throws Exception {
+        final File testFile = new File(temporaryFolder, "dummy-missing-file.txt");
+        assertThrows(NoSuchFileException.class, () -> FileUtils.lineIterator(testFile, "UTF-8"));
+    }
+
+    @Test
     public void testNextLineOnlyDefaultEncoding() throws Exception {
         final File testFile = new File(temporaryFolder, "LineIterator-nextOnly.txt");
         final List<String> lines = createLinesFile(testFile, 3);
@@ -234,123 +317,40 @@ public class LineIteratorTestCase {
     }
 
     @Test
-    public void testCloseEarly() throws Exception {
-        final String encoding = "UTF-8";
-
-        final File testFile = new File(temporaryFolder, "LineIterator-closeEarly.txt");
-        createLinesFile(testFile, encoding, 3);
-
-        try (final LineIterator iterator = FileUtils.lineIterator(testFile, encoding)) {
-            // get
-            assertNotNull("Line expected", iterator.next());
-            assertTrue(iterator.hasNext(), "More expected");
-
-            // close
-            iterator.close();
-            assertFalse(iterator.hasNext(), "No more expected");
-            assertThrows(NoSuchElementException.class, iterator::next);
-            assertThrows(NoSuchElementException.class, iterator::nextLine);
-            // try closing again
-            iterator.close();
-            assertThrows(NoSuchElementException.class, iterator::next);
-            assertThrows(NoSuchElementException.class, iterator::nextLine);
-        }
+    public void testOneLines() throws Exception {
+        doTestFileWithSpecifiedLines(1);
     }
 
-    /**
-     * Utility method to create and test a file with a specified number of lines.
-     *
-     * @param lineCount the lines to create in the test file
-     *
-     * @throws IOException If an I/O error occurs while creating the file
-     */
-    private void doTestFileWithSpecifiedLines(final int lineCount) throws IOException {
-        final String encoding = "UTF-8";
-
-        final String fileName = "LineIterator-" + lineCount + "-test.txt";
-        final File testFile = new File(temporaryFolder, fileName);
-        final List<String> lines = createLinesFile(testFile, encoding, lineCount);
-
-        try (final LineIterator iterator = FileUtils.lineIterator(testFile, encoding)) {
-            assertThrows(UnsupportedOperationException.class, iterator::remove);
-
-            int idx = 0;
-            while (iterator.hasNext()) {
-                final String line = iterator.next();
-                assertEquals(lines.get(idx), line, "Comparing line " + idx);
-                assertTrue(idx < lines.size(), "Exceeded expected idx=" + idx + " size=" + lines.size());
-                idx++;
-            }
-            assertEquals(idx, lines.size(), "Line Count doesn't match");
-
-            // try calling next() after file processed
-            assertThrows(NoSuchElementException.class, iterator::next);
-            assertThrows(NoSuchElementException.class, iterator::nextLine);
-        }
+    @Test
+    public void testThreeLines() throws Exception {
+        doTestFileWithSpecifiedLines(3);
     }
 
-    // -----------------------------------------------------------------------
     @Test
-    public void testFilteringFileReader() throws Exception {
-        final String encoding = "UTF-8";
-
-        final String fileName = "LineIterator-Filter-test.txt";
-        final File testFile = new File(temporaryFolder, fileName);
-        final List<String> lines = createLinesFile(testFile, encoding, 9);
-
-        final Reader reader = Files.newBufferedReader(testFile.toPath());
-        this.testFiltering(lines, reader);
+    public void testTwoLines() throws Exception {
+        doTestFileWithSpecifiedLines(2);
     }
 
     @Test
-    public void testFilteringBufferedReader() throws Exception {
+    public void testValidEncoding() throws Exception {
         final String encoding = "UTF-8";
 
-        final String fileName = "LineIterator-Filter-test.txt";
-        final File testFile = new File(temporaryFolder, fileName);
-        final List<String> lines = createLinesFile(testFile, encoding, 9);
-
-        final Reader reader = new BufferedReader(Files.newBufferedReader(testFile.toPath()));
-        this.testFiltering(lines, reader);
-    }
-
-    private void testFiltering(final List<String> lines, final Reader reader) {
-        final LineIterator iterator = new LineIterator(reader) {
-            @Override
-            protected boolean isValidLine(final String line) {
-                final char c = line.charAt(line.length() - 1);
-                return (c - 48) % 3 != 1;
-            }
-        };
-        try {
-            assertThrows(UnsupportedOperationException.class, iterator::remove);
+        final File testFile = new File(temporaryFolder, "LineIterator-validEncoding.txt");
+        createLinesFile(testFile, encoding, 3);
 
-            int idx = 0;
-            int actualLines = 0;
+        try (final LineIterator iterator = FileUtils.lineIterator(testFile, encoding)) {
+            int count = 0;
             while (iterator.hasNext()) {
-                final String line = iterator.next();
-                actualLines++;
-                assertEquals(lines.get(idx), line, "Comparing line " + idx);
-                assertTrue(idx < lines.size(), "Exceeded expected idx=" + idx + " size=" + lines.size());
-                idx++;
-                if (idx % 3 == 1) {
-                    idx++;
-                }
-            }
-            assertEquals(9, lines.size(), "Line Count doesn't match");
-            assertEquals(9, idx, "Line Count doesn't match");
-            assertEquals(6, actualLines, "Line Count doesn't match");
-
-            // try calling next() after file processed
-            assertThrows(NoSuchElementException.class, iterator::next);
-            assertThrows(NoSuchElementException.class, iterator::nextLine);
-        } finally {
-            try {
-                IOUtils.close(iterator);
-            } catch (final IOException ignored) {
-                // Ignored
+                assertNotNull(iterator.next());
+                count++;
             }
+            assertEquals(3, count);
         }
     }
 
+    @Test
+    public void testZeroLines() throws Exception {
+        doTestFileWithSpecifiedLines(0);
+    }
+
 }
diff --git a/src/test/java/org/apache/commons/io/SelectorAdapter.java b/src/test/java/org/apache/commons/io/SelectorAdapter.java
index c4623d4..2008908 100644
--- a/src/test/java/org/apache/commons/io/SelectorAdapter.java
+++ b/src/test/java/org/apache/commons/io/SelectorAdapter.java
@@ -29,13 +29,12 @@ import java.util.Set;
 public class SelectorAdapter extends Selector {
 
     @Override
-    public boolean isOpen() {
-        return false;
+    public void close() throws IOException {
     }
 
     @Override
-    public SelectorProvider provider() {
-        return null;
+    public boolean isOpen() {
+        return false;
     }
 
     @Override
@@ -44,12 +43,12 @@ public class SelectorAdapter extends Selector {
     }
 
     @Override
-    public Set<SelectionKey> selectedKeys() {
+    public SelectorProvider provider() {
         return null;
     }
 
     @Override
-    public int selectNow() throws IOException {
+    public int select() throws IOException {
         return 0;
     }
 
@@ -59,17 +58,18 @@ public class SelectorAdapter extends Selector {
     }
 
     @Override
-    public int select() throws IOException {
-        return 0;
+    public Set<SelectionKey> selectedKeys() {
+        return null;
     }
 
     @Override
-    public Selector wakeup() {
-        return null;
+    public int selectNow() throws IOException {
+        return 0;
     }
 
     @Override
-    public void close() throws IOException {
+    public Selector wakeup() {
+        return null;
     }
 
 }
diff --git a/src/test/java/org/apache/commons/io/TestResources.java b/src/test/java/org/apache/commons/io/TestResources.java
index 44d634a..7753d91 100644
--- a/src/test/java/org/apache/commons/io/TestResources.java
+++ b/src/test/java/org/apache/commons/io/TestResources.java
@@ -35,6 +35,10 @@ public class TestResources {
         return new File(getURI(fileName));
     }
 
+    public static InputStream getInputStream(final String fileName) {
+        return TestResources.class.getResourceAsStream(ROOT + fileName);
+    }
+
     public static Path getPath(final String fileName) throws URISyntaxException {
         return Paths.get(getURI(fileName));
     }
@@ -46,8 +50,4 @@ public class TestResources {
     public static URL getURL(final String fileName) {
         return TestResources.class.getResource(ROOT + fileName);
     }
-
-    public static InputStream getInputStream(final String fileName) {
-        return TestResources.class.getResourceAsStream(ROOT + fileName);
-    }
 }
diff --git a/src/test/java/org/apache/commons/io/ThreadMonitorTestCase.java b/src/test/java/org/apache/commons/io/ThreadMonitorTestCase.java
index e3009e2..3be1ba2 100644
--- a/src/test/java/org/apache/commons/io/ThreadMonitorTestCase.java
+++ b/src/test/java/org/apache/commons/io/ThreadMonitorTestCase.java
@@ -30,21 +30,6 @@ import org.junit.jupiter.api.Test;
 public class ThreadMonitorTestCase {
 
     /**
-     * Test timeout.
-     */
-    @Test
-    public void testTimeout() {
-        try {
-            final Thread monitor = ThreadMonitor.start(Duration.ofMillis(100));
-            TestUtils.sleep(200);
-            ThreadMonitor.stop(monitor);
-            fail("Expected InterruptedException");
-        } catch (final InterruptedException e) {
-            // expected result - timeout
-        }
-    }
-
-    /**
      * Test task completed before timeout.
      */
     @Test
@@ -84,5 +69,20 @@ public class ThreadMonitorTestCase {
             fail("Timeout 0, threw " + e);
         }
     }
+
+    /**
+     * Test timeout.
+     */
+    @Test
+    public void testTimeout() {
+        try {
+            final Thread monitor = ThreadMonitor.start(Duration.ofMillis(100));
+            TestUtils.sleep(200);
+            ThreadMonitor.stop(monitor);
+            fail("Expected InterruptedException");
+        } catch (final InterruptedException e) {
+            // expected result - timeout
+        }
+    }
 }
 
diff --git a/src/test/java/org/apache/commons/io/comparator/ComparatorAbstractTestCase.java b/src/test/java/org/apache/commons/io/comparator/ComparatorAbstractTestCase.java
index 5a1c3e8..a9a9e89 100644
--- a/src/test/java/org/apache/commons/io/comparator/ComparatorAbstractTestCase.java
+++ b/src/test/java/org/apache/commons/io/comparator/ComparatorAbstractTestCase.java
@@ -77,14 +77,6 @@ public abstract class ComparatorAbstractTestCase {
     }
 
     /**
-     * Test comparator array sort is null safe.
-     */
-    @Test
-    public void testSortArrayNull() {
-        assertNull(comparator.sort((File[])null));
-    }
-
-    /**
      * Test the comparator array sort.
      */
     @Test
@@ -100,6 +92,14 @@ public abstract class ComparatorAbstractTestCase {
     }
 
     /**
+     * Test comparator array sort is null safe.
+     */
+    @Test
+    public void testSortArrayNull() {
+        assertNull(comparator.sort((File[])null));
+    }
+
+    /**
      * Test the comparator array sort.
      */
     @Test
diff --git a/src/test/java/org/apache/commons/io/comparator/CompositeFileComparatorTest.java b/src/test/java/org/apache/commons/io/comparator/CompositeFileComparatorTest.java
index 673763e..284cf04 100644
--- a/src/test/java/org/apache/commons/io/comparator/CompositeFileComparatorTest.java
+++ b/src/test/java/org/apache/commons/io/comparator/CompositeFileComparatorTest.java
@@ -36,6 +36,43 @@ import org.junit.jupiter.api.Test;
  */
 public class CompositeFileComparatorTest extends ComparatorAbstractTestCase {
 
+    /**
+     * Test Constructor with null array
+     */
+    @Test
+    public void constructorArray_Null() {
+        final Comparator<File> c = new CompositeFileComparator((Comparator<File>[])null);
+        assertEquals(0, c.compare(lessFile, moreFile), "less,more");
+        assertEquals(0, c.compare(moreFile, lessFile), "more,less");
+        assertEquals("CompositeFileComparator{}", c.toString(), "toString");
+    }
+
+    /**
+     * Test Constructor with null Iterable
+     */
+    @Test
+    public void constructorIterable_Null() {
+        final Comparator<File> c = new CompositeFileComparator((Iterable<Comparator<File>>)null);
+        assertEquals(0, c.compare(lessFile, moreFile), "less,more");
+        assertEquals(0, c.compare(moreFile, lessFile), "more,less");
+        assertEquals("CompositeFileComparator{}", c.toString(), "toString");
+    }
+
+    /**
+     * Test Constructor with null Iterable
+     */
+    @Test
+    public void constructorIterable_order() {
+        final List<Comparator<File>> list = new ArrayList<>();
+        list.add(SizeFileComparator.SIZE_COMPARATOR);
+        list.add(ExtensionFileComparator.EXTENSION_COMPARATOR);
+        final Comparator<File> c = new CompositeFileComparator(list);
+
+        assertEquals(0, c.compare(equalFile1, equalFile2), "equal");
+        assertTrue(c.compare(lessFile, moreFile) < 0, "less");
+        assertTrue(c.compare(moreFile, lessFile) > 0, "more");
+    }
+
     @BeforeEach
     public void setUp() throws Exception {
         comparator = new CompositeFileComparator(SizeFileComparator.SIZE_COMPARATOR, ExtensionFileComparator.EXTENSION_COMPARATOR);
@@ -78,41 +115,4 @@ public class CompositeFileComparatorTest extends ComparatorAbstractTestCase {
             TestUtils.generateTestData(output, 48);
         }
     }
-
-    /**
-     * Test Constructor with null Iterable
-     */
-    @Test
-    public void constructorIterable_order() {
-        final List<Comparator<File>> list = new ArrayList<>();
-        list.add(SizeFileComparator.SIZE_COMPARATOR);
-        list.add(ExtensionFileComparator.EXTENSION_COMPARATOR);
-        final Comparator<File> c = new CompositeFileComparator(list);
-
-        assertEquals(0, c.compare(equalFile1, equalFile2), "equal");
-        assertTrue(c.compare(lessFile, moreFile) < 0, "less");
-        assertTrue(c.compare(moreFile, lessFile) > 0, "more");
-    }
-
-    /**
-     * Test Constructor with null Iterable
-     */
-    @Test
-    public void constructorIterable_Null() {
-        final Comparator<File> c = new CompositeFileComparator((Iterable<Comparator<File>>)null);
-        assertEquals(0, c.compare(lessFile, moreFile), "less,more");
-        assertEquals(0, c.compare(moreFile, lessFile), "more,less");
-        assertEquals("CompositeFileComparator{}", c.toString(), "toString");
-    }
-
-    /**
-     * Test Constructor with null array
-     */
-    @Test
-    public void constructorArray_Null() {
-        final Comparator<File> c = new CompositeFileComparator((Comparator<File>[])null);
-        assertEquals(0, c.compare(lessFile, moreFile), "less,more");
-        assertEquals(0, c.compare(moreFile, lessFile), "more,less");
-        assertEquals("CompositeFileComparator{}", c.toString(), "toString");
-    }
 }
diff --git a/src/test/java/org/apache/commons/io/comparator/SizeFileComparatorTest.java b/src/test/java/org/apache/commons/io/comparator/SizeFileComparatorTest.java
index 8f43f8e..07f75ee 100644
--- a/src/test/java/org/apache/commons/io/comparator/SizeFileComparatorTest.java
+++ b/src/test/java/org/apache/commons/io/comparator/SizeFileComparatorTest.java
@@ -84,19 +84,19 @@ public class SizeFileComparatorTest extends ComparatorAbstractTestCase {
      * Test a file which doesn't exist.
      */
     @Test
-    public void testNonexistantFile() {
-        final File nonexistantFile = new File(new File("."), "nonexistant.txt");
-        assertFalse(nonexistantFile.exists());
-        assertTrue(comparator.compare(nonexistantFile, moreFile) < 0, "less");
+    public void testCompareDirectorySizes() {
+        assertEquals(0, comparator.compare(smallerDir, largerDir), "sumDirectoryContents=false");
+        assertEquals(-1, SizeFileComparator.SIZE_SUMDIR_COMPARATOR.compare(smallerDir, largerDir), "less");
+        assertEquals(1, SizeFileComparator.SIZE_SUMDIR_REVERSE.compare(smallerDir, largerDir), "less");
     }
 
     /**
      * Test a file which doesn't exist.
      */
     @Test
-    public void testCompareDirectorySizes() {
-        assertEquals(0, comparator.compare(smallerDir, largerDir), "sumDirectoryContents=false");
-        assertEquals(-1, SizeFileComparator.SIZE_SUMDIR_COMPARATOR.compare(smallerDir, largerDir), "less");
-        assertEquals(1, SizeFileComparator.SIZE_SUMDIR_REVERSE.compare(smallerDir, largerDir), "less");
+    public void testNonexistantFile() {
+        final File nonexistantFile = new File(new File("."), "nonexistant.txt");
+        assertFalse(nonexistantFile.exists());
+        assertTrue(comparator.compare(nonexistantFile, moreFile) < 0, "less");
     }
 }
diff --git a/src/test/java/org/apache/commons/io/file/CountersEqualsAndHashCodeTest.java b/src/test/java/org/apache/commons/io/file/CountersEqualsAndHashCodeTest.java
index 2419af2..8901c9e 100644
--- a/src/test/java/org/apache/commons/io/file/CountersEqualsAndHashCodeTest.java
+++ b/src/test/java/org/apache/commons/io/file/CountersEqualsAndHashCodeTest.java
@@ -88,14 +88,14 @@ public class CountersEqualsAndHashCodeTest {
     }
 
     @Test
-    public void testLongCounterMixEquals() {
-        testEquals(Counters.longCounter(), Counters.bigIntegerCounter());
-        testEquals(Counters.bigIntegerCounter(), Counters.longCounter());
+    public void testLongCounterHashCodes() {
+        testHashCodes(Counters.longCounter(), Counters.longCounter());
     }
 
     @Test
-    public void testLongCounterHashCodes() {
-        testHashCodes(Counters.longCounter(), Counters.longCounter());
+    public void testLongCounterMixEquals() {
+        testEquals(Counters.longCounter(), Counters.bigIntegerCounter());
+        testEquals(Counters.bigIntegerCounter(), Counters.longCounter());
     }
 
     @Test
diff --git a/src/test/java/org/apache/commons/io/file/CountingPathVisitorTest.java b/src/test/java/org/apache/commons/io/file/CountingPathVisitorTest.java
index 5c853ac..4aa719e 100644
--- a/src/test/java/org/apache/commons/io/file/CountingPathVisitorTest.java
+++ b/src/test/java/org/apache/commons/io/file/CountingPathVisitorTest.java
@@ -32,6 +32,11 @@ import org.junit.jupiter.params.provider.MethodSource;
  */
 public class CountingPathVisitorTest extends TestArguments {
 
+    private void checkZeroCounts(final CountingPathVisitor visitor) {
+        Assertions.assertEquals(CountingPathVisitor.withLongCounters(), visitor);
+        Assertions.assertEquals(CountingPathVisitor.withBigIntegerCounters(), visitor);
+    }
+
     /**
      * Tests an empty folder.
      */
@@ -80,11 +85,6 @@ public class CountingPathVisitorTest extends TestArguments {
                 "src/test/resources/org/apache/commons/io/dirs-2-file-size-2"));
     }
 
-    private void checkZeroCounts(final CountingPathVisitor visitor) {
-        Assertions.assertEquals(CountingPathVisitor.withLongCounters(), visitor);
-        Assertions.assertEquals(CountingPathVisitor.withBigIntegerCounters(), visitor);
-    }
-
     @ParameterizedTest
     @MethodSource("countingPathVisitors")
     void testToString(final CountingPathVisitor visitor) {
diff --git a/src/test/java/org/apache/commons/io/file/PathUtilsContentEqualsTest.java b/src/test/java/org/apache/commons/io/file/PathUtilsContentEqualsTest.java
index 653a7ce..6fed6e8 100644
--- a/src/test/java/org/apache/commons/io/file/PathUtilsContentEqualsTest.java
+++ b/src/test/java/org/apache/commons/io/file/PathUtilsContentEqualsTest.java
@@ -40,53 +40,59 @@ public class PathUtilsContentEqualsTest {
     }
 
     @Test
-    public void testFileContentEquals() throws Exception {
+    public void testDirectoryAndFileContentEquals() throws Exception {
         // Non-existent files
         final Path path1 = new File(temporaryFolder, getName()).toPath();
         final Path path2 = new File(temporaryFolder, getName() + "2").toPath();
-        assertTrue(PathUtils.fileContentEquals(null, null));
-        assertFalse(PathUtils.fileContentEquals(null, path1));
-        assertFalse(PathUtils.fileContentEquals(path1, null));
+        assertTrue(PathUtils.directoryAndFileContentEquals(null, null));
+        assertFalse(PathUtils.directoryAndFileContentEquals(null, path1));
+        assertFalse(PathUtils.directoryAndFileContentEquals(path1, null));
         // both don't exist
-        assertTrue(PathUtils.fileContentEquals(path1, path1));
-        assertTrue(PathUtils.fileContentEquals(path1, path2));
-        assertTrue(PathUtils.fileContentEquals(path2, path2));
-        assertTrue(PathUtils.fileContentEquals(path2, path1));
-
-        // Directories
-        try {
-            PathUtils.fileContentEquals(temporaryFolder.toPath(), temporaryFolder.toPath());
-            fail("Comparing directories should fail with an IOException");
-        } catch (final IOException ioe) {
-            // expected
+        assertTrue(PathUtils.directoryAndFileContentEquals(path1, path1));
+        assertTrue(PathUtils.directoryAndFileContentEquals(path1, path2));
+        assertTrue(PathUtils.directoryAndFileContentEquals(path2, path2));
+        assertTrue(PathUtils.directoryAndFileContentEquals(path2, path1));
+        // Tree equals true tests
+        {
+            // Trees of files only that contain the same files.
+            final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-files-only/directory-files-only1");
+            final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-files-only/directory-files-only2");
+            assertTrue(PathUtils.directoryAndFileContentEquals(dir1, dir2));
+            assertTrue(PathUtils.directoryAndFileContentEquals(dir2, dir2));
+            assertTrue(PathUtils.directoryAndFileContentEquals(dir1, dir1));
+            assertTrue(PathUtils.directoryAndFileContentEquals(dir2, dir2));
+        }
+        {
+            // Trees of directories containing other directories.
+            final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-then-files/dir1");
+            final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-then-files/dir2");
+            assertTrue(PathUtils.directoryAndFileContentEquals(dir1, dir2));
+            assertTrue(PathUtils.directoryAndFileContentEquals(dir2, dir2));
+            assertTrue(PathUtils.directoryAndFileContentEquals(dir1, dir1));
+            assertTrue(PathUtils.directoryAndFileContentEquals(dir2, dir2));
+        }
+        {
+            // Trees of directories containing other directories and files.
+            final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files/dirs-and-files1");
+            final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files/dirs-and-files1");
+            assertTrue(PathUtils.directoryAndFileContentEquals(dir1, dir2));
+            assertTrue(PathUtils.directoryAndFileContentEquals(dir2, dir2));
+            assertTrue(PathUtils.directoryAndFileContentEquals(dir1, dir1));
+            assertTrue(PathUtils.directoryAndFileContentEquals(dir2, dir2));
+        }
+        // Tree equals false tests
+        {
+            final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files/dirs-and-files1/directory-files-only1");
+            final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files/dirs-and-files1/");
+            assertFalse(PathUtils.directoryAndFileContentEquals(dir1, dir2));
+            assertFalse(PathUtils.directoryAndFileContentEquals(dir2, dir1));
+        }
+        {
+            final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files");
+            final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-then-files");
+            assertFalse(PathUtils.directoryAndFileContentEquals(dir1, dir2));
+            assertFalse(PathUtils.directoryAndFileContentEquals(dir2, dir1));
         }
-
-        // Different files
-        final Path objFile1 = Paths.get(temporaryFolder.getAbsolutePath(), getName() + ".object");
-        objFile1.toFile().deleteOnExit();
-        PathUtils.copyFile(getClass().getResource("/java/lang/Object.class"), objFile1);
-
-        final Path objFile1b = Paths.get(temporaryFolder.getAbsolutePath(), getName() + ".object2");
-        objFile1b.toFile().deleteOnExit();
-        PathUtils.copyFile(getClass().getResource("/java/lang/Object.class"), objFile1b);
-
-        final Path objFile2 = Paths.get(temporaryFolder.getAbsolutePath(), getName() + ".collection");
-        objFile2.toFile().deleteOnExit();
-        PathUtils.copyFile(getClass().getResource("/java/util/Collection.class"), objFile2);
-
-        assertFalse(PathUtils.fileContentEquals(objFile1, objFile2));
-        assertFalse(PathUtils.fileContentEquals(objFile1b, objFile2));
-        assertTrue(PathUtils.fileContentEquals(objFile1, objFile1b));
-
-        assertTrue(PathUtils.fileContentEquals(objFile1, objFile1));
-        assertTrue(PathUtils.fileContentEquals(objFile1b, objFile1b));
-        assertTrue(PathUtils.fileContentEquals(objFile2, objFile2));
-
-        // Equal files
-        Files.createFile(path1);
-        Files.createFile(path2);
-        assertTrue(PathUtils.fileContentEquals(path1, path1));
-        assertTrue(PathUtils.fileContentEquals(path1, path2));
     }
 
     @Test
@@ -146,59 +152,53 @@ public class PathUtilsContentEqualsTest {
     }
 
     @Test
-    public void testDirectoryAndFileContentEquals() throws Exception {
+    public void testFileContentEquals() throws Exception {
         // Non-existent files
         final Path path1 = new File(temporaryFolder, getName()).toPath();
         final Path path2 = new File(temporaryFolder, getName() + "2").toPath();
-        assertTrue(PathUtils.directoryAndFileContentEquals(null, null));
-        assertFalse(PathUtils.directoryAndFileContentEquals(null, path1));
-        assertFalse(PathUtils.directoryAndFileContentEquals(path1, null));
+        assertTrue(PathUtils.fileContentEquals(null, null));
+        assertFalse(PathUtils.fileContentEquals(null, path1));
+        assertFalse(PathUtils.fileContentEquals(path1, null));
         // both don't exist
-        assertTrue(PathUtils.directoryAndFileContentEquals(path1, path1));
-        assertTrue(PathUtils.directoryAndFileContentEquals(path1, path2));
-        assertTrue(PathUtils.directoryAndFileContentEquals(path2, path2));
-        assertTrue(PathUtils.directoryAndFileContentEquals(path2, path1));
-        // Tree equals true tests
-        {
-            // Trees of files only that contain the same files.
-            final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-files-only/directory-files-only1");
-            final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-files-only/directory-files-only2");
-            assertTrue(PathUtils.directoryAndFileContentEquals(dir1, dir2));
-            assertTrue(PathUtils.directoryAndFileContentEquals(dir2, dir2));
-            assertTrue(PathUtils.directoryAndFileContentEquals(dir1, dir1));
-            assertTrue(PathUtils.directoryAndFileContentEquals(dir2, dir2));
-        }
-        {
-            // Trees of directories containing other directories.
-            final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-then-files/dir1");
-            final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-then-files/dir2");
-            assertTrue(PathUtils.directoryAndFileContentEquals(dir1, dir2));
-            assertTrue(PathUtils.directoryAndFileContentEquals(dir2, dir2));
-            assertTrue(PathUtils.directoryAndFileContentEquals(dir1, dir1));
-            assertTrue(PathUtils.directoryAndFileContentEquals(dir2, dir2));
-        }
-        {
-            // Trees of directories containing other directories and files.
-            final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files/dirs-and-files1");
-            final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files/dirs-and-files1");
-            assertTrue(PathUtils.directoryAndFileContentEquals(dir1, dir2));
-            assertTrue(PathUtils.directoryAndFileContentEquals(dir2, dir2));
-            assertTrue(PathUtils.directoryAndFileContentEquals(dir1, dir1));
-            assertTrue(PathUtils.directoryAndFileContentEquals(dir2, dir2));
-        }
-        // Tree equals false tests
-        {
-            final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files/dirs-and-files1/directory-files-only1");
-            final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files/dirs-and-files1/");
-            assertFalse(PathUtils.directoryAndFileContentEquals(dir1, dir2));
-            assertFalse(PathUtils.directoryAndFileContentEquals(dir2, dir1));
-        }
-        {
-            final Path dir1 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-and-files");
-            final Path dir2 = Paths.get("src/test/resources/dir-equals-tests/dir-equals-dirs-then-files");
-            assertFalse(PathUtils.directoryAndFileContentEquals(dir1, dir2));
-            assertFalse(PathUtils.directoryAndFileContentEquals(dir2, dir1));
+        assertTrue(PathUtils.fileContentEquals(path1, path1));
+        assertTrue(PathUtils.fileContentEquals(path1, path2));
+        assertTrue(PathUtils.fileContentEquals(path2, path2));
+        assertTrue(PathUtils.fileContentEquals(path2, path1));
+
+        // Directories
+        try {
+            PathUtils.fileContentEquals(temporaryFolder.toPath(), temporaryFolder.toPath());
+            fail("Comparing directories should fail with an IOException");
+        } catch (final IOException ioe) {
+            // expected
         }
+
+        // Different files
+        final Path objFile1 = Paths.get(temporaryFolder.getAbsolutePath(), getName() + ".object");
+        objFile1.toFile().deleteOnExit();
+        PathUtils.copyFile(getClass().getResource("/java/lang/Object.class"), objFile1);
+
+        final Path objFile1b = Paths.get(temporaryFolder.getAbsolutePath(), getName() + ".object2");
+        objFile1b.toFile().deleteOnExit();
+        PathUtils.copyFile(getClass().getResource("/java/lang/Object.class"), objFile1b);
+
+        final Path objFile2 = Paths.get(temporaryFolder.getAbsolutePath(), getName() + ".collection");
+        objFile2.toFile().deleteOnExit();
+        PathUtils.copyFile(getClass().getResource("/java/util/Collection.class"), objFile2);
+
+        assertFalse(PathUtils.fileContentEquals(objFile1, objFile2));
+        assertFalse(PathUtils.fileContentEquals(objFile1b, objFile2));
+        assertTrue(PathUtils.fileContentEquals(objFile1, objFile1b));
+
+        assertTrue(PathUtils.fileContentEquals(objFile1, objFile1));
+        assertTrue(PathUtils.fileContentEquals(objFile1b, objFile1b));
+        assertTrue(PathUtils.fileContentEquals(objFile2, objFile2));
+
+        // Equal files
+        Files.createFile(path1);
+        Files.createFile(path2);
+        assertTrue(PathUtils.fileContentEquals(path1, path1));
+        assertTrue(PathUtils.fileContentEquals(path1, path2));
     }
 
 }
diff --git a/src/test/java/org/apache/commons/io/file/PathUtilsDeleteFileTest.java b/src/test/java/org/apache/commons/io/file/PathUtilsDeleteFileTest.java
index 863a265..badc727 100644
--- a/src/test/java/org/apache/commons/io/file/PathUtilsDeleteFileTest.java
+++ b/src/test/java/org/apache/commons/io/file/PathUtilsDeleteFileTest.java
@@ -57,6 +57,22 @@ public class PathUtilsDeleteFileTest {
         tempDir = Files.createTempDirectory(getClass().getCanonicalName());
     }
 
+    @Test
+    public void testDeleteBrokenLink() throws IOException {
+        assumeFalse(SystemUtils.IS_OS_WINDOWS);
+
+        final Path missingFile = tempDir.resolve("missing.txt");
+        final Path brokenLink = tempDir.resolve("broken.txt");
+        Files.createSymbolicLink(brokenLink, missingFile);
+
+        assertTrue(Files.exists(brokenLink, LinkOption.NOFOLLOW_LINKS));
+        assertFalse(Files.exists(missingFile, LinkOption.NOFOLLOW_LINKS));
+
+        PathUtils.deleteFile(brokenLink);
+
+        assertFalse(Files.exists(brokenLink, LinkOption.NOFOLLOW_LINKS), "Symbolic link not removed");
+    }
+
     /**
      * Tests a directory with one file of size 0.
      */
@@ -147,20 +163,4 @@ public class PathUtilsDeleteFileTest {
         // This will throw if not empty.
         Files.deleteIfExists(tempDir);
     }
-
-    @Test
-    public void testDeleteBrokenLink() throws IOException {
-        assumeFalse(SystemUtils.IS_OS_WINDOWS);
-
-        final Path missingFile = tempDir.resolve("missing.txt");
-        final Path brokenLink = tempDir.resolve("broken.txt");
-        Files.createSymbolicLink(brokenLink, missingFile);
-
-        assertTrue(Files.exists(brokenLink, LinkOption.NOFOLLOW_LINKS));
-        assertFalse(Files.exists(missingFile, LinkOption.NOFOLLOW_LINKS));
-
-        PathUtils.deleteFile(brokenLink);
-
-        assertFalse(Files.exists(brokenLink, LinkOption.NOFOLLOW_LINKS), "Symbolic link not removed");
-    }
 }
diff --git a/src/test/java/org/apache/commons/io/filefilter/AndFileFilterTestCase.java b/src/test/java/org/apache/commons/io/filefilter/AndFileFilterTestCase.java
index 612b7ff..68a7533 100644
--- a/src/test/java/org/apache/commons/io/filefilter/AndFileFilterTestCase.java
+++ b/src/test/java/org/apache/commons/io/filefilter/AndFileFilterTestCase.java
@@ -69,13 +69,13 @@ public class AndFileFilterTestCase extends ConditionalFileFilterAbstractTestCase
   }
 
   @Override
-  protected List<Boolean> getFileResults() {
-    return this.testFileResults;
+  protected List<Boolean> getFilenameResults() {
+    return this.testFilenameResults;
   }
 
   @Override
-  protected List<Boolean> getFilenameResults() {
-    return this.testFilenameResults;
+  protected List<Boolean> getFileResults() {
+    return this.testFileResults;
   }
 
   @Override
@@ -93,6 +93,20 @@ public class AndFileFilterTestCase extends ConditionalFileFilterAbstractTestCase
     return WORKING_PATH_NAME_PROPERTY_KEY;
   }
 
+  @Test
+  public void setTestFiltersClearsOld() {
+    // test that new filters correctly clear old filters
+    final List<IOFileFilter> simpleEmptyFileFilter = Collections.singletonList(EmptyFileFilter.EMPTY);
+    final AndFileFilter andFileFilter = new AndFileFilter(simpleEmptyFileFilter);
+    // make sure the filters at this point are the same
+    assertEquals(simpleEmptyFileFilter, andFileFilter.getFileFilters());
+
+    final List<IOFileFilter> simpleNonEmptyFilter = Collections.singletonList(EmptyFileFilter.NOT_EMPTY);
+    // when calling the setter the filters should reference the new filters
+    andFileFilter.setFileFilters(simpleNonEmptyFilter);
+    assertEquals(simpleNonEmptyFilter, andFileFilter.getFileFilters());
+  }
+
   @BeforeEach
   public void setUpTestFilters() {
     // filters
@@ -298,18 +312,4 @@ public class AndFileFilterTestCase extends ConditionalFileFilterAbstractTestCase
       testFilenameResults.add(9, Boolean.FALSE);
     }
   }
-
-  @Test
-  public void setTestFiltersClearsOld() {
-    // test that new filters correctly clear old filters
-    final List<IOFileFilter> simpleEmptyFileFilter = Collections.singletonList(EmptyFileFilter.EMPTY);
-    final AndFileFilter andFileFilter = new AndFileFilter(simpleEmptyFileFilter);
-    // make sure the filters at this point are the same
-    assertEquals(simpleEmptyFileFilter, andFileFilter.getFileFilters());
-
-    final List<IOFileFilter> simpleNonEmptyFilter = Collections.singletonList(EmptyFileFilter.NOT_EMPTY);
-    // when calling the setter the filters should reference the new filters
-    andFileFilter.setFileFilters(simpleNonEmptyFilter);
-    assertEquals(simpleNonEmptyFilter, andFileFilter.getFileFilters());
-  }
 }
diff --git a/src/test/java/org/apache/commons/io/filefilter/ConditionalFileFilterAbstractTestCase.java b/src/test/java/org/apache/commons/io/filefilter/ConditionalFileFilterAbstractTestCase.java
index 3d78f97..e9ebf0e 100644
--- a/src/test/java/org/apache/commons/io/filefilter/ConditionalFileFilterAbstractTestCase.java
+++ b/src/test/java/org/apache/commons/io/filefilter/ConditionalFileFilterAbstractTestCase.java
@@ -38,6 +38,26 @@ public abstract class ConditionalFileFilterAbstractTestCase extends IOFileFilter
     private File file;
     private File workingPath;
 
+    protected abstract IOFileFilter buildFilterUsingAdd(List<IOFileFilter> filters);
+
+    protected abstract IOFileFilter buildFilterUsingConstructor(List<IOFileFilter> filters);
+
+    protected abstract ConditionalFileFilter getConditionalFileFilter();
+
+    protected abstract String getDefaultWorkingPath();
+
+    protected abstract List<boolean[]> getFalseResults();
+
+    protected abstract List<Boolean> getFilenameResults();
+
+    protected abstract List<Boolean> getFileResults();
+
+    protected abstract List<List<IOFileFilter>> getTestFilters();
+
+    protected abstract List<boolean[]> getTrueResults();
+
+    protected abstract String getWorkingPathNamePropertyKey();
+
     @BeforeEach
     public void setUp() {
         this.workingPath = determineWorkingDirectoryPath(this.getWorkingPathNamePropertyKey(), this.getDefaultWorkingPath());
@@ -72,30 +92,7 @@ public abstract class ConditionalFileFilterAbstractTestCase extends IOFileFilter
     }
 
     @Test
-    public void testRemove() {
-        final List<TesterTrueFileFilter> filters = new ArrayList<>();
-        final ConditionalFileFilter fileFilter = this.getConditionalFileFilter();
-        filters.add(new TesterTrueFileFilter());
-        filters.add(new TesterTrueFileFilter());
-        filters.add(new TesterTrueFileFilter());
-        filters.add(new TesterTrueFileFilter());
-        for (final TesterTrueFileFilter filter : filters) {
-            fileFilter.removeFileFilter(filter);
-            assertFalse(fileFilter.getFileFilters().contains(filter), "file filter removed");
-        }
-        assertEquals(0, fileFilter.getFileFilters().size(), "file filters count");
-    }
-
-    @Test
-    public void testNoFilters() {
-        final ConditionalFileFilter fileFilter = this.getConditionalFileFilter();
-        final File file = new File(this.workingPath, TEST_FILE_NAME_PREFIX + 1 + TEST_FILE_TYPE);
-        assertFileFiltering(1, (IOFileFilter) fileFilter, file, false);
-        assertFilenameFiltering(1, (IOFileFilter) fileFilter, file, false);
-    }
-
-    @Test
-    public void testFilterBuiltUsingConstructor() {
+    public void testFilterBuiltUsingAdd() {
         final List<List<IOFileFilter>> testFilters = this.getTestFilters();
         final List<boolean[]> testTrueResults = this.getTrueResults();
         final List<boolean[]> testFalseResults = this.getFalseResults();
@@ -110,7 +107,7 @@ public abstract class ConditionalFileFilterAbstractTestCase extends IOFileFilter
             final boolean filenameResults = testFilenameResults.get(i);
 
             // Test conditional AND filter created by passing filters to the constructor
-            final IOFileFilter filter = this.buildFilterUsingConstructor(filters);
+            final IOFileFilter filter = this.buildFilterUsingAdd(filters);
 
             // Test as a file filter
             resetTrueFilters(this.trueFilters);
@@ -129,7 +126,7 @@ public abstract class ConditionalFileFilterAbstractTestCase extends IOFileFilter
     }
 
     @Test
-    public void testFilterBuiltUsingAdd() {
+    public void testFilterBuiltUsingConstructor() {
         final List<List<IOFileFilter>> testFilters = this.getTestFilters();
         final List<boolean[]> testTrueResults = this.getTrueResults();
         final List<boolean[]> testFalseResults = this.getFalseResults();
@@ -144,7 +141,7 @@ public abstract class ConditionalFileFilterAbstractTestCase extends IOFileFilter
             final boolean filenameResults = testFilenameResults.get(i);
 
             // Test conditional AND filter created by passing filters to the constructor
-            final IOFileFilter filter = this.buildFilterUsingAdd(filters);
+            final IOFileFilter filter = this.buildFilterUsingConstructor(filters);
 
             // Test as a file filter
             resetTrueFilters(this.trueFilters);
@@ -162,23 +159,26 @@ public abstract class ConditionalFileFilterAbstractTestCase extends IOFileFilter
         }
     }
 
-    protected abstract ConditionalFileFilter getConditionalFileFilter();
-
-    protected abstract IOFileFilter buildFilterUsingAdd(List<IOFileFilter> filters);
-
-    protected abstract IOFileFilter buildFilterUsingConstructor(List<IOFileFilter> filters);
-
-    protected abstract List<List<IOFileFilter>> getTestFilters();
-
-    protected abstract List<boolean[]> getTrueResults();
-
-    protected abstract List<boolean[]> getFalseResults();
-
-    protected abstract List<Boolean> getFileResults();
-
-    protected abstract List<Boolean> getFilenameResults();
-
-    protected abstract String getWorkingPathNamePropertyKey();
+    @Test
+    public void testNoFilters() {
+        final ConditionalFileFilter fileFilter = this.getConditionalFileFilter();
+        final File file = new File(this.workingPath, TEST_FILE_NAME_PREFIX + 1 + TEST_FILE_TYPE);
+        assertFileFiltering(1, (IOFileFilter) fileFilter, file, false);
+        assertFilenameFiltering(1, (IOFileFilter) fileFilter, file, false);
+    }
 
-    protected abstract String getDefaultWorkingPath();
+    @Test
+    public void testRemove() {
+        final List<TesterTrueFileFilter> filters = new ArrayList<>();
+        final ConditionalFileFilter fileFilter = this.getConditionalFileFilter();
+        filters.add(new TesterTrueFileFilter());
+        filters.add(new TesterTrueFileFilter());
+        filters.add(new TesterTrueFileFilter());
+        filters.add(new TesterTrueFileFilter());
+        for (final TesterTrueFileFilter filter : filters) {
+            fileFilter.removeFileFilter(filter);
+            assertFalse(fileFilter.getFileFilters().contains(filter), "file filter removed");
+        }
+        assertEquals(0, fileFilter.getFileFilters().size(), "file filters count");
+    }
 }
diff --git a/src/test/java/org/apache/commons/io/filefilter/IOFileFilterAbstractTestCase.java b/src/test/java/org/apache/commons/io/filefilter/IOFileFilterAbstractTestCase.java
index b0d5dea..a90cc4c 100644
--- a/src/test/java/org/apache/commons/io/filefilter/IOFileFilterAbstractTestCase.java
+++ b/src/test/java/org/apache/commons/io/filefilter/IOFileFilterAbstractTestCase.java
@@ -22,6 +22,72 @@ import java.io.File;
 
 public abstract class IOFileFilterAbstractTestCase {
 
+    class TesterFalseFileFilter extends FalseFileFilter {
+
+        private static final long serialVersionUID = -3603047664010401872L;
+        private boolean invoked;
+
+        @Override
+        public boolean accept(final File file) {
+            setInvoked(true);
+            return super.accept(file);
+        }
+
+        @Override
+        public boolean accept(final File file, final String str) {
+            setInvoked(true);
+            return super.accept(file, str);
+        }
+
+        public boolean isInvoked() {
+            return this.invoked;
+        }
+
+        public void reset() {
+            setInvoked(false);
+        }
+
+        public void setInvoked(final boolean invoked) {
+            this.invoked = invoked;
+        }
+    }
+
+    class TesterTrueFileFilter extends TrueFileFilter {
+
+        private static final long serialVersionUID = 1828930358172422914L;
+        private boolean invoked;
+
+        @Override
+        public boolean accept(final File file) {
+            setInvoked(true);
+            return super.accept(file);
+        }
+
+        @Override
+        public boolean accept(final File file, final String str) {
+            setInvoked(true);
+            return super.accept(file, str);
+        }
+
+        public boolean isInvoked() {
+            return this.invoked;
+        }
+
+        public void reset() {
+            setInvoked(false);
+        }
+
+        public void setInvoked(final boolean invoked) {
+            this.invoked = invoked;
+        }
+    }
+
+    public static void assertFalseFiltersInvoked(final int testNumber, final TesterFalseFileFilter[] filters, final boolean[] invoked) {
+        for (int i = 1; i < filters.length; i++) {
+            assertEquals(invoked[i - 1], filters[i].isInvoked(), "test " + testNumber + " filter " + i + " invoked");
+        }
+    }
+
     public static void assertFileFiltering(final int testNumber, final IOFileFilter filter, final File file, final boolean expected) {
         assertEquals(expected, filter.accept(file),
                 "test " + testNumber + " Filter(File) " + filter.getClass().getName() + " not " + expected + " for " + file);
@@ -56,12 +122,6 @@ public abstract class IOFileFilterAbstractTestCase {
         }
     }
 
-    public static void assertFalseFiltersInvoked(final int testNumber, final TesterFalseFileFilter[] filters, final boolean[] invoked) {
-        for (int i = 1; i < filters.length; i++) {
-            assertEquals(invoked[i - 1], filters[i].isInvoked(), "test " + testNumber + " filter " + i + " invoked");
-        }
-    }
-
     public static File determineWorkingDirectoryPath(final String key, final String defaultPath) {
         // Look for a system property to specify the working directory
         final String workingPathName = System.getProperty(key, defaultPath);
@@ -83,64 +143,4 @@ public abstract class IOFileFilterAbstractTestCase {
             }
         }
     }
-
-    class TesterTrueFileFilter extends TrueFileFilter {
-
-        private static final long serialVersionUID = 1828930358172422914L;
-        private boolean invoked;
-
-        @Override
-        public boolean accept(final File file) {
-            setInvoked(true);
-            return super.accept(file);
-        }
-
-        @Override
-        public boolean accept(final File file, final String str) {
-            setInvoked(true);
-            return super.accept(file, str);
-        }
-
-        public boolean isInvoked() {
-            return this.invoked;
-        }
-
-        public void setInvoked(final boolean invoked) {
-            this.invoked = invoked;
-        }
-
-        public void reset() {
-            setInvoked(false);
-        }
-    }
-
-    class TesterFalseFileFilter extends FalseFileFilter {
-
-        private static final long serialVersionUID = -3603047664010401872L;
-        private boolean invoked;
-
-        @Override
-        public boolean accept(final File file) {
-            setInvoked(true);
-            return super.accept(file);
-        }
-
-        @Override
-        public boolean accept(final File file, final String str) {
-            setInvoked(true);
-            return super.accept(file, str);
-        }
-
-        public boolean isInvoked() {
-            return this.invoked;
-        }
-
-        public void setInvoked(final boolean invoked) {
-            this.invoked = invoked;
-        }
-
-        public void reset() {
-            setInvoked(false);
-        }
-    }
 }
diff --git a/src/test/java/org/apache/commons/io/filefilter/OrFileFilterTestCase.java b/src/test/java/org/apache/commons/io/filefilter/OrFileFilterTestCase.java
index 4194d91..bfd3531 100644
--- a/src/test/java/org/apache/commons/io/filefilter/OrFileFilterTestCase.java
+++ b/src/test/java/org/apache/commons/io/filefilter/OrFileFilterTestCase.java
@@ -65,13 +65,13 @@ public class OrFileFilterTestCase extends ConditionalFileFilterAbstractTestCase
   }
 
   @Override
-  protected List<Boolean> getFileResults() {
-    return this.testFileResults;
+  protected List<Boolean> getFilenameResults() {
+    return this.testFilenameResults;
   }
 
   @Override
-  protected List<Boolean> getFilenameResults() {
-    return this.testFilenameResults;
+  protected List<Boolean> getFileResults() {
+    return this.testFileResults;
   }
 
   @Override
diff --git a/src/test/java/org/apache/commons/io/input/BOMInputStreamTest.java b/src/test/java/org/apache/commons/io/input/BOMInputStreamTest.java
index cfb096f..fda2521 100644
--- a/src/test/java/org/apache/commons/io/input/BOMInputStreamTest.java
+++ b/src/test/java/org/apache/commons/io/input/BOMInputStreamTest.java
@@ -160,6 +160,24 @@ public class BOMInputStreamTest {
     //  Test cases
     //----------------------------------------------------------------------------
 
+    private boolean doesSaxSupportCharacterSet(final String charSetName) throws ParserConfigurationException, SAXException, IOException {
+        final DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+        try (final StringInputStream byteStream = new StringInputStream("<?xml version=\"1.0\" encoding=\"" + charSetName + "\"?><Z/>", charSetName)) {
+            final InputSource is = new InputSource(byteStream);
+            is.setEncoding(charSetName);
+            documentBuilder.parse(is);
+        } catch (final SAXParseException e) {
+            if (e.getMessage().contains(charSetName)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private boolean jvmAndSaxBothSupportCharset(final String charSetName) throws ParserConfigurationException, SAXException, IOException {
+        return Charset.isSupported(charSetName) &&  doesSaxSupportCharacterSet(charSetName);
+    }
+
     private void parseXml(final InputStream in) throws SAXException, IOException, ParserConfigurationException {
         final Document doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new InputSource(in));
         assertNotNull(doc);
@@ -194,6 +212,24 @@ public class BOMInputStreamTest {
     }
 
     @Test
+    public void skipReturnValueWithBom() throws IOException {
+        final byte[] baseData = { (byte) 0x31, (byte) 0x32, (byte) 0x33 };
+        try (final BOMInputStream is1 = new BOMInputStream(createUtf8DataStream(baseData, true))) {
+            assertEquals(2, is1.skip(2));
+            assertEquals((byte) 0x33, is1.read());
+        }
+    }
+
+    @Test
+    public void skipReturnValueWithoutBom() throws IOException {
+        final byte[] baseData = { (byte) 0x31, (byte) 0x32, (byte) 0x33 };
+        try (final BOMInputStream is2 = new BOMInputStream(createUtf8DataStream(baseData, false))) {
+            assertEquals(2, is2.skip(2)); // IO-428
+            assertEquals((byte) 0x33, is2.read());
+        }
+    }
+
+    @Test
     public void testAvailableWithBOM() throws Exception {
         final byte[] data = { 'A', 'B', 'C', 'D' };
         try (final InputStream in = new BOMInputStream(createUtf8DataStream(data, true))) {
@@ -678,6 +714,7 @@ public class BOMInputStreamTest {
         parseXml(createUtf8DataStream(data, true));
     }
 
+
     @Test
     public void testReadXmlWithoutBOMUtf32Be() throws Exception {
         assumeTrue(jvmAndSaxBothSupportCharset("UTF_32BE"), "JVM and SAX need to support UTF_32BE for this");
@@ -716,25 +753,6 @@ public class BOMInputStreamTest {
         }
     }
 
-
-    @Test
-    public void skipReturnValueWithBom() throws IOException {
-        final byte[] baseData = { (byte) 0x31, (byte) 0x32, (byte) 0x33 };
-        try (final BOMInputStream is1 = new BOMInputStream(createUtf8DataStream(baseData, true))) {
-            assertEquals(2, is1.skip(2));
-            assertEquals((byte) 0x33, is1.read());
-        }
-    }
-
-    @Test
-    public void skipReturnValueWithoutBom() throws IOException {
-        final byte[] baseData = { (byte) 0x31, (byte) 0x32, (byte) 0x33 };
-        try (final BOMInputStream is2 = new BOMInputStream(createUtf8DataStream(baseData, false))) {
-            assertEquals(2, is2.skip(2)); // IO-428
-            assertEquals((byte) 0x33, is2.read());
-        }
-    }
-
     @Test
     public void testSmallBufferWithBOM() throws Exception {
         final byte[] data = { 'A', 'B', 'C' };
@@ -771,22 +789,4 @@ public class BOMInputStreamTest {
             assertData(new byte[] { (byte) 0xEF, (byte) 0xBB, (byte) 0xBF, 'A', 'B' }, buf, len);
         }
     }
-
-    private boolean jvmAndSaxBothSupportCharset(final String charSetName) throws ParserConfigurationException, SAXException, IOException {
-        return Charset.isSupported(charSetName) &&  doesSaxSupportCharacterSet(charSetName);
-    }
-
-    private boolean doesSaxSupportCharacterSet(final String charSetName) throws ParserConfigurationException, SAXException, IOException {
-        final DocumentBuilder documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
-        try (final StringInputStream byteStream = new StringInputStream("<?xml version=\"1.0\" encoding=\"" + charSetName + "\"?><Z/>", charSetName)) {
-            final InputSource is = new InputSource(byteStream);
-            is.setEncoding(charSetName);
-            documentBuilder.parse(is);
-        } catch (final SAXParseException e) {
-            if (e.getMessage().contains(charSetName)) {
-                return false;
-            }
-        }
-        return true;
-    }
 }
diff --git a/src/test/java/org/apache/commons/io/input/BoundedInputStreamTest.java b/src/test/java/org/apache/commons/io/input/BoundedInputStreamTest.java
index f0e6c4e..ebe409b 100644
--- a/src/test/java/org/apache/commons/io/input/BoundedInputStreamTest.java
+++ b/src/test/java/org/apache/commons/io/input/BoundedInputStreamTest.java
@@ -29,32 +29,11 @@ import org.junit.jupiter.api.Test;
  */
 public class BoundedInputStreamTest {
 
-    @Test
-    public void testReadSingle() throws Exception {
-        BoundedInputStream bounded;
-        final byte[] helloWorld = "Hello World".getBytes();
-        final byte[] hello = "Hello".getBytes();
-
-        // limit = length
-        bounded = new BoundedInputStream(new ByteArrayInputStream(helloWorld), helloWorld.length);
-        for (int i = 0; i < helloWorld.length; i++) {
-            assertEquals(helloWorld[i], bounded.read(), "limit = length byte[" + i + "]");
-        }
-        assertEquals(-1, bounded.read(), "limit = length end");
-
-        // limit > length
-        bounded = new BoundedInputStream(new ByteArrayInputStream(helloWorld), helloWorld.length + 1);
-        for (int i = 0; i < helloWorld.length; i++) {
-            assertEquals(helloWorld[i], bounded.read(), "limit > length byte[" + i + "]");
-        }
-        assertEquals(-1, bounded.read(), "limit > length end");
-
-        // limit < length
-        bounded = new BoundedInputStream(new ByteArrayInputStream(helloWorld), hello.length);
-        for (int i = 0; i < hello.length; i++) {
-            assertEquals(hello[i], bounded.read(), "limit < length byte[" + i + "]");
+    private void compare(final String msg, final byte[] expected, final byte[] actual) {
+        assertEquals(expected.length, actual.length, msg + " length");
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals(expected[i], actual[i], msg + " byte[" + i + "]");
         }
-        assertEquals(-1, bounded.read(), "limit < length end");
     }
 
     @Test
@@ -80,10 +59,31 @@ public class BoundedInputStreamTest {
         compare("limit < length", hello, IOUtils.toByteArray(bounded));
     }
 
-    private void compare(final String msg, final byte[] expected, final byte[] actual) {
-        assertEquals(expected.length, actual.length, msg + " length");
-        for (int i = 0; i < expected.length; i++) {
-            assertEquals(expected[i], actual[i], msg + " byte[" + i + "]");
+    @Test
+    public void testReadSingle() throws Exception {
+        BoundedInputStream bounded;
+        final byte[] helloWorld = "Hello World".getBytes();
+        final byte[] hello = "Hello".getBytes();
+
+        // limit = length
+        bounded = new BoundedInputStream(new ByteArrayInputStream(helloWorld), helloWorld.length);
+        for (int i = 0; i < helloWorld.length; i++) {
+            assertEquals(helloWorld[i], bounded.read(), "limit = length byte[" + i + "]");
         }
+        assertEquals(-1, bounded.read(), "limit = length end");
+
+        // limit > length
+        bounded = new BoundedInputStream(new ByteArrayInputStream(helloWorld), helloWorld.length + 1);
+        for (int i = 0; i < helloWorld.length; i++) {
+            assertEquals(helloWorld[i], bounded.read(), "limit > length byte[" + i + "]");
+        }
+        assertEquals(-1, bounded.read(), "limit > length end");
+
+        // limit < length
+        bounded = new BoundedInputStream(new ByteArrayInputStream(helloWorld), hello.length);
+        for (int i = 0; i < hello.length; i++) {
+            assertEquals(hello[i], bounded.read(), "limit < length byte[" + i + "]");
+        }
+        assertEquals(-1, bounded.read(), "limit < length end");
     }
 }
diff --git a/src/test/java/org/apache/commons/io/input/BoundedReaderTest.java b/src/test/java/org/apache/commons/io/input/BoundedReaderTest.java
index e324682..e853d58 100644
--- a/src/test/java/org/apache/commons/io/input/BoundedReaderTest.java
+++ b/src/test/java/org/apache/commons/io/input/BoundedReaderTest.java
@@ -48,18 +48,32 @@ public class BoundedReaderTest {
     private final Reader shortReader = new BufferedReader(new StringReader("01"));
 
     @Test
-    public void readTillEnd() throws IOException {
-        try (final BoundedReader mr = new BoundedReader(sr, 3)) {
-            mr.read();
-            mr.read();
-            mr.read();
-            assertEquals(-1, mr.read());
+    public void closeTest() throws IOException {
+        final AtomicBoolean closed = new AtomicBoolean(false);
+        try (final Reader sr = new BufferedReader(new StringReader("01234567890")) {
+            @Override
+            public void close() throws IOException {
+                closed.set(true);
+                super.close();
+            }
+        }) {
+
+            try (final BoundedReader mr = new BoundedReader(sr, 3)) {
+                // nothing
+            }
         }
+        assertTrue(closed.get());
     }
 
     @Test
-    public void shortReader() throws IOException {
-        try (final BoundedReader mr = new BoundedReader(shortReader, 3)) {
+    public void markReset() throws IOException {
+        try (final BoundedReader mr = new BoundedReader(sr, 3)) {
+            mr.mark(3);
+            mr.read();
+            mr.read();
+            mr.read();
+            mr.reset();
+            mr.read();
             mr.read();
             mr.read();
             assertEquals(-1, mr.read());
@@ -67,37 +81,24 @@ public class BoundedReaderTest {
     }
 
     @Test
-    public void readMulti() throws IOException {
-        try (final BoundedReader mr = new BoundedReader(sr, 3)) {
-            final char[] cbuf = new char[4];
-            Arrays.fill(cbuf, 'X');
-            final int read = mr.read(cbuf, 0, 4);
-            assertEquals(3, read);
-            assertEquals('0', cbuf[0]);
-            assertEquals('1', cbuf[1]);
-            assertEquals('2', cbuf[2]);
-            assertEquals('X', cbuf[3]);
-        }
-    }
-
-    @Test
-    public void readMultiWithOffset() throws IOException {
+    public void markResetFromOffset1() throws IOException {
         try (final BoundedReader mr = new BoundedReader(sr, 3)) {
-            final char[] cbuf = new char[4];
-            Arrays.fill(cbuf, 'X');
-            final int read = mr.read(cbuf, 1, 2);
-            assertEquals(2, read);
-            assertEquals('X', cbuf[0]);
-            assertEquals('0', cbuf[1]);
-            assertEquals('1', cbuf[2]);
-            assertEquals('X', cbuf[3]);
+            mr.mark(3);
+            mr.read();
+            mr.read();
+            mr.read();
+            assertEquals(-1, mr.read());
+            mr.reset();
+            mr.mark(1);
+            mr.read();
+            assertEquals(-1, mr.read());
         }
     }
 
     @Test
-    public void markReset() throws IOException {
+    public void markResetMarkMore() throws IOException {
         try (final BoundedReader mr = new BoundedReader(sr, 3)) {
-            mr.mark(3);
+            mr.mark(4);
             mr.read();
             mr.read();
             mr.read();
@@ -132,29 +133,46 @@ public class BoundedReaderTest {
     }
 
     @Test
-    public void markResetFromOffset1() throws IOException {
+    public void readMulti() throws IOException {
         try (final BoundedReader mr = new BoundedReader(sr, 3)) {
-            mr.mark(3);
-            mr.read();
-            mr.read();
-            mr.read();
-            assertEquals(-1, mr.read());
-            mr.reset();
-            mr.mark(1);
-            mr.read();
-            assertEquals(-1, mr.read());
+            final char[] cbuf = new char[4];
+            Arrays.fill(cbuf, 'X');
+            final int read = mr.read(cbuf, 0, 4);
+            assertEquals(3, read);
+            assertEquals('0', cbuf[0]);
+            assertEquals('1', cbuf[1]);
+            assertEquals('2', cbuf[2]);
+            assertEquals('X', cbuf[3]);
         }
     }
 
     @Test
-    public void markResetMarkMore() throws IOException {
+    public void readMultiWithOffset() throws IOException {
+        try (final BoundedReader mr = new BoundedReader(sr, 3)) {
+            final char[] cbuf = new char[4];
+            Arrays.fill(cbuf, 'X');
+            final int read = mr.read(cbuf, 1, 2);
+            assertEquals(2, read);
+            assertEquals('X', cbuf[0]);
+            assertEquals('0', cbuf[1]);
+            assertEquals('1', cbuf[2]);
+            assertEquals('X', cbuf[3]);
+        }
+    }
+
+    @Test
+    public void readTillEnd() throws IOException {
         try (final BoundedReader mr = new BoundedReader(sr, 3)) {
-            mr.mark(4);
-            mr.read();
             mr.read();
             mr.read();
-            mr.reset();
             mr.read();
+            assertEquals(-1, mr.read());
+        }
+    }
+
+    @Test
+    public void shortReader() throws IOException {
+        try (final BoundedReader mr = new BoundedReader(shortReader, 3)) {
             mr.read();
             mr.read();
             assertEquals(-1, mr.read());
@@ -170,24 +188,6 @@ public class BoundedReaderTest {
         }
     }
 
-    @Test
-    public void closeTest() throws IOException {
-        final AtomicBoolean closed = new AtomicBoolean(false);
-        try (final Reader sr = new BufferedReader(new StringReader("01234567890")) {
-            @Override
-            public void close() throws IOException {
-                closed.set(true);
-                super.close();
-            }
-        }) {
-
-            try (final BoundedReader mr = new BoundedReader(sr, 3)) {
-                // nothing
-            }
-        }
-        assertTrue(closed.get());
-    }
-
     private void testLineNumberReader(final Reader source) throws IOException {
         try (LineNumberReader reader = new LineNumberReader(new BoundedReader(source, 10_000_000))) {
             while (reader.readLine() != null) {
@@ -196,14 +196,17 @@ public class BoundedReaderTest {
         }
     }
 
-    @Test
-    public void testLineNumberReaderAndStringReaderLastLineEolNo() {
-        assertTimeout(Duration.ofMillis(5000), () -> testLineNumberReader(new StringReader(STRING_END_NO_EOL)));
-    }
-
-    @Test
-    public void testLineNumberReaderAndStringReaderLastLineEolYes() {
-        assertTimeout(Duration.ofMillis(5000), () -> testLineNumberReader(new StringReader(STRING_END_EOL)));
+    public void testLineNumberReaderAndFileReaderLastLine(final String data) throws IOException {
+        final Path path = Files.createTempFile(getClass().getSimpleName(), ".txt");
+        try {
+            final File file = path.toFile();
+            FileUtils.write(file, data, StandardCharsets.ISO_8859_1);
+            try (Reader source = Files.newBufferedReader(file.toPath())) {
+                testLineNumberReader(source);
+            }
+        } finally {
+            Files.delete(path);
+        }
     }
 
     @Test
@@ -216,17 +219,14 @@ public class BoundedReaderTest {
         assertTimeout(Duration.ofMillis(5000), () -> testLineNumberReaderAndFileReaderLastLine(STRING_END_EOL));
     }
 
-    public void testLineNumberReaderAndFileReaderLastLine(final String data) throws IOException {
-        final Path path = Files.createTempFile(getClass().getSimpleName(), ".txt");
-        try {
-            final File file = path.toFile();
-            FileUtils.write(file, data, StandardCharsets.ISO_8859_1);
-            try (Reader source = Files.newBufferedReader(file.toPath())) {
-                testLineNumberReader(source);
-            }
-        } finally {
-            Files.delete(path);
-        }
+    @Test
+    public void testLineNumberReaderAndStringReaderLastLineEolNo() {
+        assertTimeout(Duration.ofMillis(5000), () -> testLineNumberReader(new StringReader(STRING_END_NO_EOL)));
+    }
+
+    @Test
+    public void testLineNumberReaderAndStringReaderLastLineEolYes() {
+        assertTimeout(Duration.ofMillis(5000), () -> testLineNumberReader(new StringReader(STRING_END_EOL)));
     }
 
     @Test
diff --git a/src/test/java/org/apache/commons/io/input/CharSequenceInputStreamTest.java b/src/test/java/org/apache/commons/io/input/CharSequenceInputStreamTest.java
index 3e995d9..d31a121 100644
--- a/src/test/java/org/apache/commons/io/input/CharSequenceInputStreamTest.java
+++ b/src/test/java/org/apache/commons/io/input/CharSequenceInputStreamTest.java
@@ -49,10 +49,76 @@ public class CharSequenceInputStreamTest {
 
     private final Random random = new Random();
 
+    private int checkAvail(final InputStream is, final int min) throws Exception {
+        final int available = is.available();
+        assertTrue(available >= min, "avail should be >= " + min + ", but was " + available);
+        return available;
+    }
+
     private Set<String> getRequiredCharsetNames() {
         return Charsets.requiredCharsets().keySet();
     }
 
+private boolean isAvailabilityTestableForCharset(final String csName) {
+        return Charset.forName(csName).canEncode()
+                && !"COMPOUND_TEXT".equalsIgnoreCase(csName) && !"x-COMPOUND_TEXT".equalsIgnoreCase(csName)
+                && !isOddBallLegacyCharsetThatDoesNotSupportFrenchCharacters(csName);
+    }
+
+    private boolean isOddBallLegacyCharsetThatDoesNotSupportFrenchCharacters(final String csName) {
+        return "x-IBM1388".equalsIgnoreCase(csName) ||
+                "ISO-2022-CN".equalsIgnoreCase(csName) ||
+                "ISO-2022-JP".equalsIgnoreCase(csName) ||
+                "Shift_JIS".equalsIgnoreCase(csName);
+    }
+
+    @Test
+    public void testAvailable() throws Exception {
+        for (final String csName : Charset.availableCharsets().keySet()) {
+            // prevent java.lang.UnsupportedOperationException at sun.nio.cs.ext.ISO2022_CN.newEncoder.
+            // also try and avoid the following Effor on Continuum
+//            java.lang.UnsupportedOperationException: null
+//            at java.nio.CharBuffer.array(CharBuffer.java:940)
+//            at sun.nio.cs.ext.COMPOUND_TEXT_Encoder.encodeLoop(COMPOUND_TEXT_Encoder.java:75)
+//            at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:544)
+//            at org.apache.commons.io.input.CharSequenceInputStream.fillBuffer(CharSequenceInputStream.java:120)
+//            at org.apache.commons.io.input.CharSequenceInputStream.read(CharSequenceInputStream.java:151)
+//            at org.apache.commons.io.input.CharSequenceInputStreamTest.testAvailableRead(CharSequenceInputStreamTest.java:412)
+//            at org.apache.commons.io.input.CharSequenceInputStreamTest.testAvailable(CharSequenceInputStreamTest.java:424)
+
+            try {
+                if (isAvailabilityTestableForCharset(csName)) {
+                    testAvailableSkip(csName);
+                    testAvailableRead(csName);
+                }
+            } catch (final UnsupportedOperationException e){
+                fail("Operation not supported for " + csName);
+            }
+        }
+    }
+
+    private void testAvailableRead(final String csName) throws Exception {
+        final String input = "test";
+        try (InputStream r = new CharSequenceInputStream(input, csName)) {
+            int available = checkAvail(r, input.length());
+            assertEquals(available - 1, r.skip(available - 1)); // skip all but one
+            available = checkAvail(r, 1);
+            final byte[] buff = new byte[available];
+            assertEquals(available, r.read(buff, 0, available));
+        }
+    }
+
+    private void testAvailableSkip(final String csName) throws Exception {
+        final String input = "test";
+        try (InputStream r = new CharSequenceInputStream(input, csName)) {
+            int available = checkAvail(r, input.length());
+            assertEquals(available - 1, r.skip(available - 1)); // skip all but one
+            available = checkAvail(r, 1);
+            assertEquals(1, r.skip(1));
+            available = checkAvail(r, 0);
+        }
+    }
+
     private void testBufferedRead(final String testString, final String charsetName) throws IOException {
         final byte[] expected = testString.getBytes(charsetName);
         try (InputStream in = new CharSequenceInputStream(testString, charsetName, 512)) {
@@ -78,7 +144,7 @@ public class CharSequenceInputStreamTest {
         }
     }
 
-//    Unfortunately checking canEncode does not seem to work for all charsets:
+    //    Unfortunately checking canEncode does not seem to work for all charsets:
 //    testBufferedRead_AvailableCharset(org.apache.commons.io.input.CharSequenceInputStreamTest)  Time elapsed: 0.682 sec  <<< ERROR!
 //    java.lang.UnsupportedOperationException: null
 //        at java.nio.CharBuffer.array(CharBuffer.java:940)
@@ -352,70 +418,4 @@ public class CharSequenceInputStreamTest {
     public void testSkip_UTF8() throws Exception {
         testSkip("UTF-8");
     }
-
-    private int checkAvail(final InputStream is, final int min) throws Exception {
-        final int available = is.available();
-        assertTrue(available >= min, "avail should be >= " + min + ", but was " + available);
-        return available;
-    }
-
-    private void testAvailableSkip(final String csName) throws Exception {
-        final String input = "test";
-        try (InputStream r = new CharSequenceInputStream(input, csName)) {
-            int available = checkAvail(r, input.length());
-            assertEquals(available - 1, r.skip(available - 1)); // skip all but one
-            available = checkAvail(r, 1);
-            assertEquals(1, r.skip(1));
-            available = checkAvail(r, 0);
-        }
-    }
-
-    private void testAvailableRead(final String csName) throws Exception {
-        final String input = "test";
-        try (InputStream r = new CharSequenceInputStream(input, csName)) {
-            int available = checkAvail(r, input.length());
-            assertEquals(available - 1, r.skip(available - 1)); // skip all but one
-            available = checkAvail(r, 1);
-            final byte[] buff = new byte[available];
-            assertEquals(available, r.read(buff, 0, available));
-        }
-    }
-
-    @Test
-    public void testAvailable() throws Exception {
-        for (final String csName : Charset.availableCharsets().keySet()) {
-            // prevent java.lang.UnsupportedOperationException at sun.nio.cs.ext.ISO2022_CN.newEncoder.
-            // also try and avoid the following Effor on Continuum
-//            java.lang.UnsupportedOperationException: null
-//            at java.nio.CharBuffer.array(CharBuffer.java:940)
-//            at sun.nio.cs.ext.COMPOUND_TEXT_Encoder.encodeLoop(COMPOUND_TEXT_Encoder.java:75)
-//            at java.nio.charset.CharsetEncoder.encode(CharsetEncoder.java:544)
-//            at org.apache.commons.io.input.CharSequenceInputStream.fillBuffer(CharSequenceInputStream.java:120)
-//            at org.apache.commons.io.input.CharSequenceInputStream.read(CharSequenceInputStream.java:151)
-//            at org.apache.commons.io.input.CharSequenceInputStreamTest.testAvailableRead(CharSequenceInputStreamTest.java:412)
-//            at org.apache.commons.io.input.CharSequenceInputStreamTest.testAvailable(CharSequenceInputStreamTest.java:424)
-
-            try {
-                if (isAvailabilityTestableForCharset(csName)) {
-                    testAvailableSkip(csName);
-                    testAvailableRead(csName);
-                }
-            } catch (final UnsupportedOperationException e){
-                fail("Operation not supported for " + csName);
-            }
-        }
-    }
-
-    private boolean isAvailabilityTestableForCharset(final String csName) {
-        return Charset.forName(csName).canEncode()
-                && !"COMPOUND_TEXT".equalsIgnoreCase(csName) && !"x-COMPOUND_TEXT".equalsIgnoreCase(csName)
-                && !isOddBallLegacyCharsetThatDoesNotSupportFrenchCharacters(csName);
-    }
-
-    private boolean isOddBallLegacyCharsetThatDoesNotSupportFrenchCharacters(final String csName) {
-        return "x-IBM1388".equalsIgnoreCase(csName) ||
-                "ISO-2022-CN".equalsIgnoreCase(csName) ||
-                "ISO-2022-JP".equalsIgnoreCase(csName) ||
-                "Shift_JIS".equalsIgnoreCase(csName);
-    }
 }
diff --git a/src/test/java/org/apache/commons/io/input/CharSequenceReaderTest.java b/src/test/java/org/apache/commons/io/input/CharSequenceReaderTest.java
index d81f99d..8ba0e0b 100644
--- a/src/test/java/org/apache/commons/io/input/CharSequenceReaderTest.java
+++ b/src/test/java/org/apache/commons/io/input/CharSequenceReaderTest.java
@@ -40,6 +40,18 @@ import org.junit.jupiter.api.Test;
 public class CharSequenceReaderTest {
     private static final char NONE = (new char[1])[0];
 
+    private void checkArray(final char[] expected, final char[] actual) {
+        for (int i = 0; i < expected.length; i++) {
+            assertEquals(expected[i], actual[i], "Compare[" +i + "]");
+        }
+    }
+
+    private void checkRead(final Reader reader, final String expected) throws IOException {
+        for (int i = 0; i < expected.length(); i++) {
+            assertEquals(expected.charAt(i), (char)reader.read(), "Read[" + i + "] of '" + expected + "'");
+        }
+    }
+
     @Test
     public void testClose() throws IOException {
         final Reader reader = new CharSequenceReader("FooBar");
@@ -54,47 +66,11 @@ public class CharSequenceReaderTest {
     }
 
     @Test
-    public void testReady() throws IOException {
-        final Reader reader = new CharSequenceReader("FooBar");
-        assertTrue(reader.ready());
-        reader.skip(3);
-        assertTrue(reader.ready());
-        checkRead(reader, "Bar");
-        assertFalse(reader.ready());
-        reader.reset();
-        assertTrue(reader.ready());
-        reader.skip(2);
-        assertTrue(reader.ready());
-        reader.skip(10);
-        assertFalse(reader.ready());
-        reader.close();
-        assertTrue(reader.ready());
-        reader.skip(20);
-        assertFalse(reader.ready());
-
-        final Reader subReader = new CharSequenceReader("xFooBarx", 1, 7);
-        assertTrue(subReader.ready());
-        subReader.skip(3);
-        assertTrue(subReader.ready());
-        checkRead(subReader, "Bar");
-        assertFalse(subReader.ready());
-        subReader.reset();
-        assertTrue(subReader.ready());
-        subReader.skip(2);
-        assertTrue(subReader.ready());
-        subReader.skip(10);
-        assertFalse(subReader.ready());
-        subReader.close();
-        assertTrue(subReader.ready());
-        subReader.skip(20);
-        assertFalse(subReader.ready());
-    }
-
-    @Test
-    public void testMarkSupported() throws Exception {
-        try (final Reader reader = new CharSequenceReader("FooBar")) {
-            assertTrue(reader.markSupported());
-        }
+    public void testConstructor() {
+        assertThrows(IllegalArgumentException.class, () -> new CharSequenceReader("FooBar", -1, 6),
+                "Expected exception not thrown for negative start.");
+        assertThrows(IllegalArgumentException.class, () -> new CharSequenceReader("FooBar", 1, 0),
+                "Expected exception not thrown for end before start.");
     }
 
     @Test
@@ -124,30 +100,10 @@ public class CharSequenceReaderTest {
     }
 
     @Test
-    public void testSkip() throws IOException {
-        final Reader reader = new CharSequenceReader("FooBar");
-        assertEquals(3, reader.skip(3));
-        checkRead(reader, "Bar");
-        assertEquals(0, reader.skip(3));
-        reader.reset();
-        assertEquals(2, reader.skip(2));
-        assertEquals(4, reader.skip(10));
-        assertEquals(0, reader.skip(1));
-        reader.close();
-        assertEquals(6, reader.skip(20));
-        assertEquals(-1, reader.read());
-
-        final Reader subReader = new CharSequenceReader("xFooBarx", 1, 7);
-        assertEquals(3, subReader.skip(3));
-        checkRead(subReader, "Bar");
-        assertEquals(0, subReader.skip(3));
-        subReader.reset();
-        assertEquals(2, subReader.skip(2));
-        assertEquals(4, subReader.skip(10));
-        assertEquals(0, subReader.skip(1));
-        subReader.close();
-        assertEquals(6, subReader.skip(20));
-        assertEquals(-1, subReader.read());
+    public void testMarkSupported() throws Exception {
+        try (final Reader reader = new CharSequenceReader("FooBar")) {
+            assertTrue(reader.markSupported());
+        }
     }
 
     @Test
@@ -239,31 +195,41 @@ public class CharSequenceReaderTest {
         }
     }
 
-    private void checkRead(final Reader reader, final String expected) throws IOException {
-        for (int i = 0; i < expected.length(); i++) {
-            assertEquals(expected.charAt(i), (char)reader.read(), "Read[" + i + "] of '" + expected + "'");
-        }
-    }
-
-    private void checkArray(final char[] expected, final char[] actual) {
-        for (int i = 0; i < expected.length; i++) {
-            assertEquals(expected[i], actual[i], "Compare[" +i + "]");
-        }
-    }
-
     @Test
-    public void testConstructor() {
-        assertThrows(IllegalArgumentException.class, () -> new CharSequenceReader("FooBar", -1, 6),
-                "Expected exception not thrown for negative start.");
-        assertThrows(IllegalArgumentException.class, () -> new CharSequenceReader("FooBar", 1, 0),
-                "Expected exception not thrown for end before start.");
-    }
+    public void testReady() throws IOException {
+        final Reader reader = new CharSequenceReader("FooBar");
+        assertTrue(reader.ready());
+        reader.skip(3);
+        assertTrue(reader.ready());
+        checkRead(reader, "Bar");
+        assertFalse(reader.ready());
+        reader.reset();
+        assertTrue(reader.ready());
+        reader.skip(2);
+        assertTrue(reader.ready());
+        reader.skip(10);
+        assertFalse(reader.ready());
+        reader.close();
+        assertTrue(reader.ready());
+        reader.skip(20);
+        assertFalse(reader.ready());
 
-    @Test
-    @SuppressWarnings("resource") // don't really need to close CharSequenceReader here
-    public void testToString() {
-        assertEquals("FooBar", new CharSequenceReader("FooBar").toString());
-        assertEquals("FooBar", new CharSequenceReader("xFooBarx", 1, 7).toString());
+        final Reader subReader = new CharSequenceReader("xFooBarx", 1, 7);
+        assertTrue(subReader.ready());
+        subReader.skip(3);
+        assertTrue(subReader.ready());
+        checkRead(subReader, "Bar");
+        assertFalse(subReader.ready());
+        subReader.reset();
+        assertTrue(subReader.ready());
+        subReader.skip(2);
+        assertTrue(subReader.ready());
+        subReader.skip(10);
+        assertFalse(subReader.ready());
+        subReader.close();
+        assertTrue(subReader.ready());
+        subReader.skip(20);
+        assertFalse(subReader.ready());
     }
 
     @Test
@@ -312,4 +278,38 @@ public class CharSequenceReaderTest {
             assertEquals(-1, reader.read());
         }
     }
+
+    @Test
+    public void testSkip() throws IOException {
+        final Reader reader = new CharSequenceReader("FooBar");
+        assertEquals(3, reader.skip(3));
+        checkRead(reader, "Bar");
+        assertEquals(0, reader.skip(3));
+        reader.reset();
+        assertEquals(2, reader.skip(2));
+        assertEquals(4, reader.skip(10));
+        assertEquals(0, reader.skip(1));
+        reader.close();
+        assertEquals(6, reader.skip(20));
+        assertEquals(-1, reader.read());
+
+        final Reader subReader = new CharSequenceReader("xFooBarx", 1, 7);
+        assertEquals(3, subReader.skip(3));
+        checkRead(subReader, "Bar");
+        assertEquals(0, subReader.skip(3));
+        subReader.reset();
+        assertEquals(2, subReader.skip(2));
+        assertEquals(4, subReader.skip(10));
+        assertEquals(0, subReader.skip(1));
+        subReader.close();
+        assertEquals(6, subReader.skip(20));
+        assertEquals(-1, subReader.read());
+    }
+
+    @Test
+    @SuppressWarnings("resource") // don't really need to close CharSequenceReader here
+    public void testToString() {
+        assertEquals("FooBar", new CharSequenceReader("FooBar").toString());
+        assertEquals("FooBar", new CharSequenceReader("xFooBarx", 1, 7).toString());
+    }
 }
diff --git a/src/test/java/org/apache/commons/io/input/ClassLoaderObjectInputStreamTest.java b/src/test/java/org/apache/commons/io/input/ClassLoaderObjectInputStreamTest.java
index 67b437c..69e0f77 100644
--- a/src/test/java/org/apache/commons/io/input/ClassLoaderObjectInputStreamTest.java
+++ b/src/test/java/org/apache/commons/io/input/ClassLoaderObjectInputStreamTest.java
@@ -39,6 +39,46 @@ public class ClassLoaderObjectInputStreamTest {
      */
 
 
+    private enum E {A, B, C}
+
+    private static class Test implements Serializable {
+        private static final long serialVersionUID = 1L;
+        private final int i;
+
+        private final Object o;
+
+        private final E e;
+
+        Test(final int i, final Object o) {
+            this.i = i;
+            this.e = E.A;
+            this.o = o;
+        }
+
+        private boolean equalObject(final Object other) {
+            if (this.o == null) {
+                return other == null;
+            }
+            return o.equals(other);
+        }
+
+        @Override
+        public boolean equals(final Object other) {
+            if (other instanceof Test) {
+                final Test tother = (Test) other;
+                return (this.i == tother.i)
+                        & (this.e == tother.e)
+                        & equalObject(tother.o);
+            }
+            return false;
+        }
+
+        @Override
+        public int hashCode() {
+            return super.hashCode();
+        }
+    }
+
     @org.junit.jupiter.api.Test
     public void testExpected() throws Exception {
 
@@ -76,71 +116,31 @@ public class ClassLoaderObjectInputStreamTest {
     }
 
     @org.junit.jupiter.api.Test
-    public void testPrimitiveLong() throws Exception {
+    public void testObject1() throws Exception {
 
         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
         final ObjectOutputStream oos = new ObjectOutputStream(baos);
 
-        final long input = 12345L;
-        oos.writeLong(input);
+        final Object input = new Test(123, null);
+        oos.writeObject(input);
         oos.close();
 
         final InputStream bais = new ByteArrayInputStream(baos.toByteArray());
         try (final ClassLoaderObjectInputStream clois = new ClassLoaderObjectInputStream(getClass().getClassLoader(),
                 bais)) {
-            final long result = clois.readLong();
+            final Object result = clois.readObject();
 
             assertEquals(input, result);
         }
... 6987 lines suppressed ...