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 6ca84c08bef64a754021613c64fc2b95e606cc3f
Author: Gary D. Gregory <garydgreg...@gmail.com>
AuthorDate: Sun Mar 2 08:52:54 2025 -0500

    Better tests for FileChannels.contentEquals()
---
 .../commons/io/channels/FileChannelsTest.java      | 125 ++++++++++++++++-----
 1 file changed, 95 insertions(+), 30 deletions(-)

diff --git a/src/test/java/org/apache/commons/io/channels/FileChannelsTest.java 
b/src/test/java/org/apache/commons/io/channels/FileChannelsTest.java
index 7a3b260ab..a8aef2ef3 100644
--- a/src/test/java/org/apache/commons/io/channels/FileChannelsTest.java
+++ b/src/test/java/org/apache/commons/io/channels/FileChannelsTest.java
@@ -25,88 +25,153 @@
 import java.io.FileInputStream;
 import java.io.IOException;
 import java.nio.channels.FileChannel;
+import java.nio.file.Files;
+import java.nio.file.Path;
 
 import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
 import org.apache.commons.io.file.AbstractTempDirTest;
+import org.apache.commons.lang3.ArrayUtils;
 import org.apache.commons.lang3.StringUtils;
-import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.MethodSource;
 
 /**
  * Tests {@link FileChannels}.
  */
 public class FileChannelsTest extends AbstractTempDirTest {
 
-    private static final int BUFFER_SIZE = 1024;
-    private static final String CONTENT = StringUtils.repeat("x", BUFFER_SIZE);
+    private static final int SMALL_BUFFER_SIZE = 1024;
+    private static final String CONTENT = StringUtils.repeat("x", 
SMALL_BUFFER_SIZE);
+
+    public static int[] getBufferSizes() {
+        // 1 and 2 are unusual and slow edge cases, but edge cases nonetheless.
+        return new int[] { 1, 2, IOUtils.DEFAULT_BUFFER_SIZE / 10, 
IOUtils.DEFAULT_BUFFER_SIZE, IOUtils.DEFAULT_BUFFER_SIZE * 10 };
+    }
+
+    private static byte reverse(final byte b) {
+        return (byte) (~b & 0xff);
+    }
 
     private boolean isEmpty(final File empty) {
         return empty.length() == 0;
     }
 
-    private void testContentEquals(final String content1, final String 
content2) throws IOException {
-        assertTrue(FileChannels.contentEquals(null, null, BUFFER_SIZE));
 
+    private FileChannel reset(final FileChannel fc) throws IOException {
+        return fc.position(0);
+    }
+
+    @ParameterizedTest()
+    @MethodSource("getBufferSizes")
+    public void testContentEquals(final int bufferSize) throws IOException {
+        final Path bigFile1 = Files.createTempFile(getClass().getSimpleName(), 
"-1.bin");
+        final Path bigFile2 = Files.createTempFile(getClass().getSimpleName(), 
"-2.bin");
+        final Path bigFile3 = Files.createTempFile(getClass().getSimpleName(), 
"-3.bin");
+        try {
+            // This length must match any restriction from the Surefire 
configuration.
+            final int newLength = 5_000_000;
+            final byte[] bytes1 = new byte[newLength];
+            final byte[] bytes2 = new byte[newLength];
+            // Make sure bytes1 and bytes2 are different despite the shuffle
+            ArrayUtils.shuffle(bytes1);
+            bytes1[0] = 1;
+            ArrayUtils.shuffle(bytes2);
+            bytes2[0] = 2;
+            Files.write(bigFile1, bytes1);
+            Files.write(bigFile2, bytes2);
+            try (FileChannel fc1 = FileChannel.open(bigFile1); FileChannel fc2 
= FileChannel.open(bigFile2)) {
+                assertFalse(FileChannels.contentEquals(fc1, fc2, bufferSize));
+                assertFalse(FileChannels.contentEquals(reset(fc2), reset(fc1), 
bufferSize));
+                assertTrue(FileChannels.contentEquals(reset(fc1), reset(fc1), 
bufferSize));
+            }
+            // Make the LAST byte different.
+            byte[] bytes3 = bytes1.clone();
+            final int last = bytes3.length - 1;
+            bytes3[last] = reverse(bytes3[last]);
+            Files.write(bigFile3, bytes3);
+            try (FileChannel fc1 = FileChannel.open(bigFile1); FileChannel fc3 
= FileChannel.open(bigFile3)) {
+                assertFalse(FileChannels.contentEquals(fc1, fc3, bufferSize));
+                assertFalse(FileChannels.contentEquals(reset(fc3), reset(fc1), 
bufferSize));
+            }
+            // Make a byte in the middle different
+            bytes3 = bytes1.clone();
+            final int middle = bytes3.length / 2;
+            bytes3[middle] = reverse(bytes3[middle]);
+            Files.write(bigFile3, bytes3);
+            try (FileChannel fc1 = FileChannel.open(bigFile1); FileChannel fc3 
= FileChannel.open(bigFile3)) {
+                assertFalse(FileChannels.contentEquals(fc1, fc3, bufferSize));
+                assertFalse(FileChannels.contentEquals(reset(fc3), reset(fc1), 
bufferSize));
+            }
+        } finally {
+            // Delete ASAP
+            Files.deleteIfExists(bigFile1);
+            Files.deleteIfExists(bigFile2);
+            Files.deleteIfExists(bigFile3);
+        }
+    }
+
+    private void testContentEquals(final String content1, final String 
content2, final int bufferSize) throws IOException {
+        assertTrue(FileChannels.contentEquals(null, null, bufferSize));
         // Prepare test files with same size but different content
         // (first 3 bytes are different, followed by a large amount of equal 
content)
         final File file1 = new File(tempDirFile, "test1.txt");
         final File file2 = new File(tempDirFile, "test2.txt");
         FileUtils.writeStringToFile(file1, content1, US_ASCII);
         FileUtils.writeStringToFile(file2, content2, US_ASCII);
-
         // File checksums are different
         assertNotEquals(FileUtils.checksumCRC32(file1), 
FileUtils.checksumCRC32(file2));
-
         try (FileInputStream stream1 = new FileInputStream(file1);
                 FileInputStream stream2 = new FileInputStream(file2);
                 FileChannel channel1 = stream1.getChannel();
                 FileChannel channel2 = stream2.getChannel()) {
-            assertFalse(FileChannels.contentEquals(channel1, channel2, 
BUFFER_SIZE));
+            assertFalse(FileChannels.contentEquals(channel1, channel2, 
bufferSize));
         }
         try (FileInputStream stream1 = new FileInputStream(file1);
                 FileInputStream stream2 = new FileInputStream(file2);
                 FileChannel channel1 = stream1.getChannel();
                 FileChannel channel2 = stream2.getChannel()) {
-            assertTrue(FileChannels.contentEquals(channel1, channel1, 
BUFFER_SIZE));
-            assertTrue(FileChannels.contentEquals(channel2, channel2, 
BUFFER_SIZE));
+            assertTrue(FileChannels.contentEquals(channel1, channel1, 
bufferSize));
+            assertTrue(FileChannels.contentEquals(channel2, channel2, 
bufferSize));
         }
     }
 
-    @Test
-    public void testContentEqualsDifferentPostfix() throws IOException {
-        testContentEquals(CONTENT + "ABC", CONTENT + "XYZ");
+    @ParameterizedTest()
+    @MethodSource("getBufferSizes")
+    public void testContentEqualsDifferentPostfix(final int bufferSize) throws 
IOException {
+        testContentEquals(CONTENT + "ABC", CONTENT + "XYZ", bufferSize);
     }
 
-    @Test
-    public void testContentEqualsDifferentPrefix() throws IOException {
-        testContentEquals("ABC" + CONTENT, "XYZ" + CONTENT);
+    @ParameterizedTest()
+    @MethodSource("getBufferSizes")
+    public void testContentEqualsDifferentPrefix(final int bufferSize) throws 
IOException {
+        testContentEquals("ABC" + CONTENT, "XYZ" + CONTENT, bufferSize);
     }
 
-    @Test
-    public void testContentEqualsEmpty() throws IOException {
-        assertTrue(FileChannels.contentEquals(null, null, BUFFER_SIZE));
-
+    @ParameterizedTest()
+    @MethodSource("getBufferSizes")
+    public void testContentEqualsEmpty(final int bufferSize) throws 
IOException {
+        assertTrue(FileChannels.contentEquals(null, null, bufferSize));
+        // setup fixtures
         final File empty = new File(tempDirFile, "empty.txt");
         final File notEmpty = new File(tempDirFile, "not-empty.txt");
         FileUtils.writeStringToFile(empty, StringUtils.EMPTY, US_ASCII);
         FileUtils.writeStringToFile(notEmpty, "X", US_ASCII);
         assertTrue(isEmpty(empty));
         assertFalse(isEmpty(notEmpty));
-
         // File checksums are different
         assertNotEquals(FileUtils.checksumCRC32(empty), 
FileUtils.checksumCRC32(notEmpty));
-
         try (FileInputStream streamEmpty = new FileInputStream(empty);
                 FileInputStream streamNotEmpty = new FileInputStream(notEmpty);
                 FileChannel channelEmpty = streamEmpty.getChannel();
                 FileChannel channelNotEmpty = streamNotEmpty.getChannel()) {
-            assertFalse(FileChannels.contentEquals(channelEmpty, 
channelNotEmpty, BUFFER_SIZE));
-            assertFalse(FileChannels.contentEquals(null, channelNotEmpty, 
BUFFER_SIZE));
-            assertFalse(FileChannels.contentEquals(channelNotEmpty, null, 
BUFFER_SIZE));
-            assertTrue(FileChannels.contentEquals(channelEmpty, channelEmpty, 
BUFFER_SIZE));
-            assertTrue(FileChannels.contentEquals(null, channelEmpty, 
BUFFER_SIZE));
-            assertTrue(FileChannels.contentEquals(channelEmpty, null, 
BUFFER_SIZE));
-            assertTrue(FileChannels.contentEquals(channelNotEmpty, 
channelNotEmpty, BUFFER_SIZE));
+            assertFalse(FileChannels.contentEquals(channelEmpty, 
channelNotEmpty, bufferSize));
+            assertFalse(FileChannels.contentEquals(null, channelNotEmpty, 
bufferSize));
+            assertFalse(FileChannels.contentEquals(channelNotEmpty, null, 
bufferSize));
+            assertTrue(FileChannels.contentEquals(channelEmpty, channelEmpty, 
bufferSize));
+            assertTrue(FileChannels.contentEquals(null, channelEmpty, 
bufferSize));
+            assertTrue(FileChannels.contentEquals(channelEmpty, null, 
bufferSize));
+            assertTrue(FileChannels.contentEquals(channelNotEmpty, 
channelNotEmpty, bufferSize));
         }
     }
-
 }

Reply via email to