Skip to content

Commit

Permalink
Add tests for compat functions, ensuring parity with the methods they…
Browse files Browse the repository at this point in the history
… replace.
  • Loading branch information
LossyDragon committed Dec 31, 2024
1 parent fb51550 commit 11a33cb
Show file tree
Hide file tree
Showing 2 changed files with 247 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package in.dragonbra.javasteam.util.compat;

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.io.ByteArrayOutputStream;
import java.nio.charset.StandardCharsets;

public class ByteArrayOutputStreamCompatTest {

@Test
public void testEmptyStream() {
var baos = new ByteArrayOutputStream();

var compatResult = ByteArrayOutputStreamCompat.toString(baos);
var standardResult = baos.toString();

Assertions.assertEquals("", compatResult);
Assertions.assertEquals("", standardResult);
Assertions.assertEquals(standardResult, compatResult);
}

@Test
public void testAsciiContent() {
var baos = new ByteArrayOutputStream();
var testString = "Hello, World!";

baos.write(testString.getBytes(StandardCharsets.UTF_8), 0, testString.length());

var compatResult = ByteArrayOutputStreamCompat.toString(baos);
var standardResult = baos.toString();

Assertions.assertEquals(testString, compatResult);
Assertions.assertEquals(testString, standardResult);
Assertions.assertEquals(standardResult, compatResult);
}

@Test
public void testUnicodeContent() {
var baos = new ByteArrayOutputStream();
var testString = "Hello, 世界! 👋";
var bytes = testString.getBytes(StandardCharsets.UTF_8);

baos.write(bytes, 0, bytes.length);

var compatResult = ByteArrayOutputStreamCompat.toString(baos);
var standardResult = baos.toString();

Assertions.assertEquals(testString, compatResult);
Assertions.assertEquals(testString, standardResult);
Assertions.assertEquals(standardResult, compatResult);
}

@Test
public void testLargeContent() {
var baos = new ByteArrayOutputStream();
var largeString = new StringBuilder();
for (int i = 0; i < 1000; i++) {
largeString.append("Line ").append(i).append("\n");
}
var testString = largeString.toString();
var bytes = testString.getBytes(StandardCharsets.UTF_8);
baos.write(bytes, 0, bytes.length);

var compatResult = ByteArrayOutputStreamCompat.toString(baos);
var standardResult = baos.toString();

Assertions.assertEquals(testString, compatResult);
Assertions.assertEquals(testString, standardResult);
Assertions.assertEquals(standardResult, compatResult);
}

@Test
public void testPartialWrites() {
var baos = new ByteArrayOutputStream();
var part1 = "Hello";
var part2 = ", ";
var part3 = "World!";

baos.write(part1.getBytes(StandardCharsets.UTF_8), 0, part1.length());
baos.write(part2.getBytes(StandardCharsets.UTF_8), 0, part2.length());
baos.write(part3.getBytes(StandardCharsets.UTF_8), 0, part3.length());

var expected = part1 + part2 + part3;
var compatResult = ByteArrayOutputStreamCompat.toString(baos);
var standardResult = baos.toString();

Assertions.assertEquals(expected, compatResult);
Assertions.assertEquals(expected, standardResult);
Assertions.assertEquals(standardResult, compatResult);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
package `in`.dragonbra.javasteam.util.compat

import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.ValueSource
import java.io.ByteArrayInputStream
import java.io.IOException
import java.io.InputStream
import kotlin.random.Random

/**
* [readNBytesCompat] methods are kotlin only extension functions for [InputStream].
* This test is in Kotlin to ensure functionality for the extension functions
*/
class InputStreamCompatTest {

private lateinit var testData: ByteArray
private lateinit var emptyStream: InputStream
private lateinit var normalStream: InputStream
private lateinit var largeStream: InputStream

@BeforeEach
fun setup() {
testData = Random.nextBytes(16384)
emptyStream = ByteArrayInputStream(ByteArray(0))
normalStream = ByteArrayInputStream(testData)
largeStream = ByteArrayInputStream(Random.nextBytes(1024 * 1024))
}

@Nested
inner class ReadNBytesCompatArrayTest {

@Test
fun `empty stream returns zero bytes`() {
val buffer = ByteArray(100)
val bytesRead = emptyStream.readNBytesCompat(buffer, 0, buffer.size)
Assertions.assertEquals(0, bytesRead)
}

@Test
fun `reading zero bytes returns zero`() {
val buffer = ByteArray(100)
val bytesRead = normalStream.readNBytesCompat(buffer, 0, 0)
Assertions.assertEquals(0, bytesRead)
}

@ParameterizedTest
@ValueSource(ints = [1, 100, 1000, 8192])
fun `reading n bytes matches JDK implementation`(n: Int) {
val compatBuffer = ByteArray(n)
val jdkBuffer = ByteArray(n)

val stream1 = ByteArrayInputStream(testData)
val stream2 = ByteArrayInputStream(testData)

val compatBytesRead = stream1.readNBytesCompat(compatBuffer, 0, n)
val jdkBytesRead = stream2.readNBytes(jdkBuffer, 0, n)

Assertions.assertArrayEquals(jdkBuffer, compatBuffer)
Assertions.assertEquals(jdkBytesRead, compatBytesRead)
}

@Test
fun `throws exception on negative length`() {
val buffer = ByteArray(100)
Assertions.assertThrows(IndexOutOfBoundsException::class.java) {
normalStream.readNBytesCompat(buffer, 0, -1)
}
}

@Test
fun `throws exception on invalid offset`() {
val buffer = ByteArray(100)
Assertions.assertThrows(IndexOutOfBoundsException::class.java) {
normalStream.readNBytesCompat(buffer, -1, 50)
}
Assertions.assertThrows(IndexOutOfBoundsException::class.java) {
normalStream.readNBytesCompat(buffer, 101, 50)
}
}
}

@Nested
inner class ReadNBytesCompatLengthTest {

@Test
fun `empty stream returns empty array`() {
val result = emptyStream.readNBytesCompat(100)
Assertions.assertEquals(0, result.size)
}

@Test
fun `reading zero bytes returns empty array`() {
val result = normalStream.readNBytesCompat(0)
Assertions.assertEquals(0, result.size)
}

@ParameterizedTest
@ValueSource(ints = [1, 100, 1000, 8192, 16384])
fun `reading n bytes matches JDK implementation`(n: Int) {
val stream1 = ByteArrayInputStream(testData)
val stream2 = ByteArrayInputStream(testData)

val compatResult = stream1.readNBytesCompat(n)
val jdkResult = stream2.readNBytes(n)

Assertions.assertArrayEquals(jdkResult, compatResult)
}

@Test
fun `throws exception on negative length`() {
Assertions.assertThrows(IllegalArgumentException::class.java) {
normalStream.readNBytesCompat(-1)
}
}

@Test
fun `handles large reads correctly`() {
val lengthToRead = 1024 * 1024
val result = largeStream.readNBytesCompat(lengthToRead)
Assertions.assertEquals(lengthToRead, result.size)
}

@Test
fun `partial read when EOF reached`() {
val result = normalStream.readNBytesCompat(testData.size * 2)
Assertions.assertEquals(testData.size, result.size)
Assertions.assertArrayEquals(testData, result)
}
}

@Nested
inner class ErrorConditionsTest {

@Test
fun `handles IOException from underlying stream`() {
val failingStream = object : InputStream() {
override fun read(): Int = throw IOException("Simulated failure")
override fun read(b: ByteArray, off: Int, len: Int): Int = throw IOException("Simulated failure")
}

Assertions.assertThrows(IOException::class.java) {
failingStream.readNBytesCompat(100)
}

Assertions.assertThrows(IOException::class.java) {
failingStream.readNBytesCompat(ByteArray(100), 0, 100)
}
}
}
}

0 comments on commit 11a33cb

Please sign in to comment.