FileUtilsTestCase.java
/*
* JBoss, Home of Professional Open Source.
* Copyright 2025 Red Hat, Inc., and individual contributors
* as indicated by the @author tags.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.undertow.util;
import io.undertow.testutils.category.UnitTest;
import org.junit.Assert;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
/**
* @author Park Jaeon
*/
@Category(UnitTest.class)
public class FileUtilsTestCase {
@Test
public void testMultiByteCharactersAtBufferBoundary() {
StringBuilder sb = new StringBuilder();
// Create content larger than 1024 bytes (the old buffer size)
// Fill with ASCII 'a' characters up to position 1023
for (int i = 0; i < 1023; i++) {
sb.append('a');
}
// Add a 3-byte UTF-8 character (Chinese character) at position 1023-1025
// This would span across the 1024-byte boundary in the old implementation
sb.append('���'); // 3-byte UTF-8 character
// Add more content to ensure we're reading beyond the first buffer
for (int i = 0; i < 2000; i++) {
sb.append('b');
}
// Add some more multi-byte characters
sb.append(" Hello ������ Testing ����");
String expected = sb.toString();
InputStream stream = new ByteArrayInputStream(expected.getBytes(StandardCharsets.UTF_8));
String result = FileUtils.readFile(stream);
// The bug would cause replacement character (���) to appear instead of the correct character
Assert.assertFalse("Result should not contain replacement character (���)",
result.contains("\uFFFD"));
Assert.assertEquals("Content should be read correctly without corruption",
expected, result);
}
@Test
public void testEmojisAtBufferBoundary() {
StringBuilder sb = new StringBuilder();
// Fill up to just before 1024 bytes
for (int i = 0; i < 1022; i++) {
sb.append('x');
}
// Add 4-byte emoji that would span the boundary
sb.append("����"); // 4-byte UTF-8 character
// Add more content
for (int i = 0; i < 500; i++) {
sb.append('y');
}
String expected = sb.toString();
InputStream stream = new ByteArrayInputStream(expected.getBytes(StandardCharsets.UTF_8));
String result = FileUtils.readFile(stream);
Assert.assertFalse("Result should not contain replacement character",
result.contains("\uFFFD"));
Assert.assertEquals("Emoji should be preserved correctly", expected, result);
}
@Test
public void testLargeContentWithMultiByteCharacters() {
StringBuilder sb = new StringBuilder();
// Create content that's definitely larger than 1024 bytes and includes
// various multi-byte characters throughout
String testPattern = "Hello ������! Testing ���� multi-byte encoding. ";
// Repeat pattern to create large content (each pattern is ~50 bytes)
for (int i = 0; i < 100; i++) {
sb.append(testPattern);
sb.append(i).append(" ");
}
String expected = sb.toString();
Assert.assertTrue("Content should be larger than 1024 bytes",
expected.getBytes(StandardCharsets.UTF_8).length > 1024);
InputStream stream = new ByteArrayInputStream(expected.getBytes(StandardCharsets.UTF_8));
String result = FileUtils.readFile(stream);
Assert.assertEquals("Large content with multi-byte characters should be read correctly",
expected, result);
Assert.assertFalse("No replacement characters should be present",
result.contains("\uFFFD"));
}
}