Merge pull request #6896 from thundernest/convert_to_kotlin
Convert `FixedLengthInputStream[Test]` to Kotlin
This commit is contained in:
commit
7c41c66f08
5 changed files with 357 additions and 351 deletions
|
@ -177,6 +177,7 @@ shared-jvm-androidtest-compose = [
|
|||
"androidx-compose-ui-test-junit4",
|
||||
]
|
||||
shared-jvm-test = [
|
||||
"kotlin-test",
|
||||
"junit",
|
||||
"assertk",
|
||||
"mockito-core",
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
|
||||
package com.fsck.k9.mail.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* A filtering InputStream that stops allowing reads after the given length has been read. This
|
||||
* is used to allow a client to read directly from an underlying protocol stream without reading
|
||||
* past where the protocol handler intended the client to read.
|
||||
*/
|
||||
public class FixedLengthInputStream extends InputStream {
|
||||
private final InputStream mIn;
|
||||
private final int mLength;
|
||||
private int mCount = 0;
|
||||
|
||||
public FixedLengthInputStream(InputStream in, int length) {
|
||||
this.mIn = in;
|
||||
this.mLength = length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int available() throws IOException {
|
||||
return mLength - mCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read() throws IOException {
|
||||
if (mCount >= mLength) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int d = mIn.read();
|
||||
if (d != -1) {
|
||||
mCount++;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b, int offset, int length) throws IOException {
|
||||
if (mCount >= mLength) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int d = mIn.read(b, offset, Math.min(mLength - mCount, length));
|
||||
if (d != -1) {
|
||||
mCount += d;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(byte[] b) throws IOException {
|
||||
return read(b, 0, b.length);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long skip(long n) throws IOException {
|
||||
long d = mIn.skip(Math.min(n, available()));
|
||||
if (d > 0) {
|
||||
mCount += d;
|
||||
}
|
||||
return d;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format(Locale.US, "FixedLengthInputStream(in=%s, length=%d)", mIn.toString(), mLength);
|
||||
}
|
||||
|
||||
public void skipRemaining() throws IOException {
|
||||
while (available() > 0) {
|
||||
skip(available());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package com.fsck.k9.mail.filter
|
||||
|
||||
import java.io.IOException
|
||||
import java.io.InputStream
|
||||
import java.util.Locale
|
||||
|
||||
/**
|
||||
* A filtering InputStream that stops allowing reads after the given length has been read. This
|
||||
* is used to allow a client to read directly from an underlying protocol stream without reading
|
||||
* past where the protocol handler intended the client to read.
|
||||
*/
|
||||
class FixedLengthInputStream(
|
||||
private val inputStream: InputStream,
|
||||
private val length: Int,
|
||||
) : InputStream() {
|
||||
private var numberOfBytesRead = 0
|
||||
|
||||
// TODO: Call available() on underlying InputStream if remainingBytes() > 0
|
||||
@Throws(IOException::class)
|
||||
override fun available(): Int {
|
||||
return remainingBytes()
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun read(): Int {
|
||||
if (remainingBytes() == 0) {
|
||||
return -1
|
||||
}
|
||||
|
||||
val byte = inputStream.read()
|
||||
if (byte != -1) {
|
||||
numberOfBytesRead++
|
||||
}
|
||||
|
||||
return byte
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun read(b: ByteArray, offset: Int, length: Int): Int {
|
||||
if (remainingBytes() == 0) {
|
||||
return -1
|
||||
}
|
||||
|
||||
val byte = inputStream.read(b, offset, length.coerceAtMost(remainingBytes()))
|
||||
if (byte != -1) {
|
||||
numberOfBytesRead += byte
|
||||
}
|
||||
|
||||
return byte
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun read(b: ByteArray): Int {
|
||||
return read(b, 0, b.size)
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
override fun skip(n: Long): Long {
|
||||
val numberOfSkippedBytes = inputStream.skip(n.coerceAtMost(remainingBytes().toLong()))
|
||||
if (numberOfSkippedBytes > 0) {
|
||||
numberOfBytesRead += numberOfSkippedBytes.toInt()
|
||||
}
|
||||
|
||||
return numberOfSkippedBytes
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun skipRemaining() {
|
||||
while (remainingBytes() > 0) {
|
||||
skip(remainingBytes().toLong())
|
||||
}
|
||||
}
|
||||
|
||||
private fun remainingBytes(): Int {
|
||||
return length - numberOfBytesRead
|
||||
}
|
||||
|
||||
override fun toString(): String {
|
||||
return String.format(Locale.ROOT, "FixedLengthInputStream(in=%s, length=%d)", inputStream.toString(), length)
|
||||
}
|
||||
}
|
|
@ -1,273 +0,0 @@
|
|||
package com.fsck.k9.mail.filter;
|
||||
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import okio.Buffer;
|
||||
import okio.ByteString;
|
||||
import okio.Okio;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
|
||||
public class FixedLengthInputStreamTest {
|
||||
@Test
|
||||
public void readingStream_shouldReturnDataUpToLimit() throws Exception {
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream("Hello world"), 5);
|
||||
|
||||
String readString = readStreamAsUtf8String(fixedLengthInputStream);
|
||||
|
||||
assertEquals("Hello", readString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readingStream_shouldNotConsumeMoreThanLimitFromUnderlyingInputStream() throws Exception {
|
||||
InputStream inputStream = inputStream("Hello world");
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream, 5);
|
||||
|
||||
exhaustStream(fixedLengthInputStream);
|
||||
|
||||
assertRemainingInputStreamEquals(" world", inputStream);
|
||||
}
|
||||
|
||||
@Test
|
||||
//TODO: Maybe this should throw. The underlying stream delivering less bytes than expected is most likely an error.
|
||||
public void readingStream_withLimitGreaterThanNumberOfBytesInUnderlyingInputStream() throws Exception {
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream("Hello World"), 100);
|
||||
|
||||
String readString = readStreamAsUtf8String(fixedLengthInputStream);
|
||||
|
||||
assertEquals("Hello World", readString);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void read_withOverSizedByteArray_shouldReturnDataUpToLimit() throws Exception {
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream("Hello World"), 6);
|
||||
|
||||
byte[] data = new byte[100];
|
||||
int numberOfBytesRead = fixedLengthInputStream.read(data);
|
||||
|
||||
assertEquals(6, numberOfBytesRead);
|
||||
assertEquals("Hello ", ByteString.of(data, 0, numberOfBytesRead).utf8());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void read_withOverSizedByteArray_shouldNotConsumeMoreThanLimitFromUnderlyingStream() throws Exception {
|
||||
InputStream inputStream = inputStream("Hello World");
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream, 6);
|
||||
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
fixedLengthInputStream.read(new byte[100]);
|
||||
|
||||
assertRemainingInputStreamEquals("World", inputStream);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void read_withByteArraySmallerThanLimit_shouldConsumeSizeOfByteArray() throws Exception {
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream("Hello World"), 6);
|
||||
|
||||
byte[] data = new byte[5];
|
||||
int numberOfBytesRead = fixedLengthInputStream.read(data);
|
||||
|
||||
assertEquals(5, numberOfBytesRead);
|
||||
assertEquals("Hello", ByteString.of(data).utf8());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void read_withOverSizedByteArrayInMiddleOfStream_shouldReturnDataUpToLimit() throws Exception {
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream("Hello World"), 6);
|
||||
consumeBytes(fixedLengthInputStream, 5);
|
||||
|
||||
byte[] data = new byte[10];
|
||||
int numberOfBytesRead = fixedLengthInputStream.read(data);
|
||||
|
||||
assertEquals(1, numberOfBytesRead);
|
||||
assertEquals(" ", ByteString.of(data, 0, numberOfBytesRead).utf8());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void read_withOverSizedByteArrayInMiddleOfStream_shouldNotConsumeMoreThanLimitFromUnderlyingStream()
|
||||
throws Exception {
|
||||
InputStream inputStream = inputStream("Hello World");
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream, 6);
|
||||
consumeBytes(fixedLengthInputStream, 5);
|
||||
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
fixedLengthInputStream.read(new byte[10]);
|
||||
|
||||
assertRemainingInputStreamEquals("World", inputStream);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void read_atStartOfStream() throws Exception {
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream("Word"), 2);
|
||||
|
||||
int readByte = fixedLengthInputStream.read();
|
||||
|
||||
assertEquals('W', (char) readByte);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void read_inMiddleOfStream() throws Exception {
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream("Word"), 2);
|
||||
consumeBytes(fixedLengthInputStream, 1);
|
||||
|
||||
int readByte = fixedLengthInputStream.read();
|
||||
|
||||
assertEquals('o', (char) readByte);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void read_atEndOfStream_shouldReturnMinusOne() throws Exception {
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream("Hello world"), 5);
|
||||
exhaustStream(fixedLengthInputStream);
|
||||
|
||||
int readByte = fixedLengthInputStream.read();
|
||||
|
||||
assertEquals(-1, readByte);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readArray_atEndOfStream_shouldReturnMinusOne() throws Exception {
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream("Hello world"), 5);
|
||||
exhaustStream(fixedLengthInputStream);
|
||||
|
||||
int numberOfBytesRead = fixedLengthInputStream.read(new byte[2]);
|
||||
|
||||
assertEquals(-1, numberOfBytesRead);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void readArrayWithOffset_atEndOfStream_shouldReturnMinusOne() throws Exception {
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream("Hello world"), 5);
|
||||
exhaustStream(fixedLengthInputStream);
|
||||
|
||||
int numberOfBytesRead = fixedLengthInputStream.read(new byte[2], 0, 2);
|
||||
|
||||
assertEquals(-1, numberOfBytesRead);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void available_atStartOfStream() throws Exception {
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream("Hello World"), 5);
|
||||
|
||||
int available = fixedLengthInputStream.available();
|
||||
|
||||
assertEquals(5, available);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void available_afterPartialRead() throws Exception {
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream("Hello World"), 5);
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
fixedLengthInputStream.read();
|
||||
|
||||
int available = fixedLengthInputStream.available();
|
||||
|
||||
assertEquals(4, available);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void available_afterPartialReadArray() throws Exception {
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream("Hello World"), 5);
|
||||
consumeBytes(fixedLengthInputStream, 2);
|
||||
|
||||
int available = fixedLengthInputStream.available();
|
||||
|
||||
assertEquals(3, available);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void available_afterStreamHasBeenExhausted() throws Exception {
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream("Hello World"), 5);
|
||||
exhaustStream(fixedLengthInputStream);
|
||||
|
||||
int available = fixedLengthInputStream.available();
|
||||
|
||||
assertEquals(0, available);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void available_afterSkip() throws Exception {
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream("Hello World"), 5);
|
||||
guaranteedSkip(fixedLengthInputStream, 2);
|
||||
|
||||
int available = fixedLengthInputStream.available();
|
||||
|
||||
assertEquals(3, available);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void available_afterSkipRemaining() throws Exception {
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream("Hello World"), 5);
|
||||
fixedLengthInputStream.skipRemaining();
|
||||
|
||||
int available = fixedLengthInputStream.available();
|
||||
|
||||
assertEquals(0, available);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skip_shouldConsumeBytes() throws IOException {
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream("Hello World"), 5);
|
||||
|
||||
guaranteedSkip(fixedLengthInputStream, 2);
|
||||
|
||||
assertRemainingInputStreamEquals("llo", fixedLengthInputStream);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipRemaining_shouldExhaustStream() throws IOException {
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream("Hello World"), 5);
|
||||
|
||||
fixedLengthInputStream.skipRemaining();
|
||||
|
||||
assertInputStreamExhausted(fixedLengthInputStream);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void skipRemaining_shouldNotConsumeMoreThanLimitFromUnderlyingInputStream() throws IOException {
|
||||
InputStream inputStream = inputStream("Hello World");
|
||||
FixedLengthInputStream fixedLengthInputStream = new FixedLengthInputStream(inputStream, 6);
|
||||
|
||||
fixedLengthInputStream.skipRemaining();
|
||||
|
||||
assertRemainingInputStreamEquals("World", inputStream);
|
||||
}
|
||||
|
||||
|
||||
private String readStreamAsUtf8String(InputStream inputStream) throws IOException {
|
||||
return Okio.buffer(Okio.source(inputStream)).readUtf8();
|
||||
}
|
||||
|
||||
private void exhaustStream(InputStream inputStream) throws IOException {
|
||||
Okio.buffer(Okio.source(inputStream)).readAll(Okio.blackhole());
|
||||
}
|
||||
|
||||
private void consumeBytes(InputStream inputStream, int numberOfBytes) throws IOException {
|
||||
int read = inputStream.read(new byte[numberOfBytes]);
|
||||
assertEquals(numberOfBytes, read);
|
||||
}
|
||||
|
||||
private void guaranteedSkip(InputStream inputStream, int numberOfBytesToSkip) throws IOException {
|
||||
int remaining = numberOfBytesToSkip;
|
||||
while (remaining > 0) {
|
||||
remaining -= inputStream.skip(remaining);
|
||||
}
|
||||
assertEquals(0, remaining);
|
||||
}
|
||||
|
||||
private void assertRemainingInputStreamEquals(String expected, InputStream inputStream) throws IOException {
|
||||
assertEquals(expected, readStreamAsUtf8String(inputStream));
|
||||
}
|
||||
|
||||
private void assertInputStreamExhausted(InputStream inputStream) throws IOException {
|
||||
assertEquals(-1, inputStream.read());
|
||||
}
|
||||
|
||||
private InputStream inputStream(String data) {
|
||||
return new Buffer().writeUtf8(data).inputStream();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,275 @@
|
|||
package com.fsck.k9.mail.filter
|
||||
|
||||
import assertk.Assert
|
||||
import assertk.all
|
||||
import assertk.assertThat
|
||||
import assertk.assertions.isEqualTo
|
||||
import java.io.InputStream
|
||||
import kotlin.test.Test
|
||||
import okio.blackholeSink
|
||||
import okio.buffer
|
||||
import okio.source
|
||||
|
||||
class FixedLengthInputStreamTest {
|
||||
@Test
|
||||
fun `reading stream should return data up to limit`() {
|
||||
val fixedLengthInputStream = createFixedLengthInputStream(data = "Hello world", length = 5)
|
||||
|
||||
val result = fixedLengthInputStream.readToString()
|
||||
|
||||
assertThat(result).isEqualTo("Hello")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `reading stream should not consume more than limit from underlying InputStream`() {
|
||||
val inputStream = "Hello world".byteInputStream()
|
||||
val fixedLengthInputStream = FixedLengthInputStream(inputStream, 5)
|
||||
|
||||
fixedLengthInputStream.exhaust()
|
||||
|
||||
assertThat(inputStream).readToString().isEqualTo(" world")
|
||||
}
|
||||
|
||||
// TODO: Maybe this should throw. The underlying stream delivering less bytes than expected is most likely an error.
|
||||
@Test
|
||||
fun `reading stream with limit greater than number of bytes in underlying InputStream`() {
|
||||
val fixedLengthInputStream = createFixedLengthInputStream(data = "Hello world", length = 100)
|
||||
|
||||
val result = fixedLengthInputStream.readToString()
|
||||
|
||||
assertThat(result).isEqualTo("Hello world")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `read() with oversized ByteArray should return data up to limit`() {
|
||||
val fixedLengthInputStream = createFixedLengthInputStream(data = "Hello World", length = 6)
|
||||
val data = ByteArray(100)
|
||||
|
||||
val result = fixedLengthInputStream.read(data)
|
||||
|
||||
assertThat(result).isEqualTo(6)
|
||||
assertThat(data).all {
|
||||
slice(0 until 6).asString().isEqualTo("Hello ")
|
||||
slice(6 until 100).isEqualTo(ByteArray(100 - 6))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `read() with oversized ByteArray should not consume more than limit from underlying InputStream`() {
|
||||
val inputStream = "Hello World".byteInputStream()
|
||||
val fixedLengthInputStream = FixedLengthInputStream(inputStream, 6)
|
||||
|
||||
fixedLengthInputStream.read(ByteArray(100))
|
||||
|
||||
assertThat(inputStream).readToString().isEqualTo("World")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `read() with ByteArray smaller than limit should consume size of ByteArray`() {
|
||||
val fixedLengthInputStream = createFixedLengthInputStream(data = "Hello World", length = 6)
|
||||
val data = ByteArray(5)
|
||||
|
||||
val result = fixedLengthInputStream.read(data)
|
||||
|
||||
assertThat(result).isEqualTo(5)
|
||||
assertThat(data).asString().isEqualTo("Hello")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `read() with oversized ByteArray in middle of stream should return data up to limit`() {
|
||||
val fixedLengthInputStream = createFixedLengthInputStream(data = "Hello World", length = 6)
|
||||
fixedLengthInputStream.consumeBytes(5)
|
||||
val data = ByteArray(10)
|
||||
|
||||
val result = fixedLengthInputStream.read(data)
|
||||
|
||||
assertThat(result).isEqualTo(1)
|
||||
assertThat(data).all {
|
||||
slice(0 until 1).asString().isEqualTo(" ")
|
||||
slice(1 until 10).isEqualTo(ByteArray(10 - 1))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `read() with oversized ByteArray in middle of stream should not read more than limit from underlying stream`() {
|
||||
val inputStream = "Hello World".byteInputStream()
|
||||
val fixedLengthInputStream = FixedLengthInputStream(inputStream, 6)
|
||||
fixedLengthInputStream.consumeBytes(5)
|
||||
|
||||
fixedLengthInputStream.read(ByteArray(10))
|
||||
|
||||
assertThat(inputStream).readToString().isEqualTo("World")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `read() at start of stream`() {
|
||||
val fixedLengthInputStream = createFixedLengthInputStream(data = "Word", length = 2)
|
||||
|
||||
val result = fixedLengthInputStream.read()
|
||||
|
||||
assertThat(result).isEqualTo('W'.code)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `read() in middle of stream`() {
|
||||
val fixedLengthInputStream = createFixedLengthInputStream(data = "Word", length = 2)
|
||||
fixedLengthInputStream.consumeBytes(1)
|
||||
|
||||
val result = fixedLengthInputStream.read()
|
||||
|
||||
assertThat(result).isEqualTo('o'.code)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `read() at end of stream should return -1`() {
|
||||
val fixedLengthInputStream = createFixedLengthInputStream(data = "Hello world", length = 5)
|
||||
fixedLengthInputStream.exhaust()
|
||||
|
||||
val result = fixedLengthInputStream.read()
|
||||
|
||||
assertThat(result).isEqualTo(-1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `read(ByteArray) at end of stream should return -1`() {
|
||||
val fixedLengthInputStream = createFixedLengthInputStream(data = "Hello world", length = 5)
|
||||
fixedLengthInputStream.exhaust()
|
||||
|
||||
val result = fixedLengthInputStream.read(ByteArray(2))
|
||||
|
||||
assertThat(result).isEqualTo(-1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `read(ByteArray) with offset at end of stream should return -1`() {
|
||||
val fixedLengthInputStream = createFixedLengthInputStream(data = "Hello world", length = 5)
|
||||
fixedLengthInputStream.exhaust()
|
||||
|
||||
val result = fixedLengthInputStream.read(ByteArray(2), 0, 2)
|
||||
|
||||
assertThat(result).isEqualTo(-1)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `available() at start of stream`() {
|
||||
val fixedLengthInputStream = createFixedLengthInputStream(data = "Hello world", length = 5)
|
||||
|
||||
val result = fixedLengthInputStream.available()
|
||||
|
||||
assertThat(result).isEqualTo(5)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `available() after partial read`() {
|
||||
val fixedLengthInputStream = createFixedLengthInputStream(data = "Hello world", length = 5)
|
||||
fixedLengthInputStream.read()
|
||||
|
||||
val result = fixedLengthInputStream.available()
|
||||
|
||||
assertThat(result).isEqualTo(4)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `available() after partial multi-byte read`() {
|
||||
val fixedLengthInputStream = createFixedLengthInputStream(data = "Hello world", length = 5)
|
||||
fixedLengthInputStream.consumeBytes(2)
|
||||
|
||||
val result = fixedLengthInputStream.available()
|
||||
|
||||
assertThat(result).isEqualTo(3)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `available() after stream has been exhausted`() {
|
||||
val fixedLengthInputStream = createFixedLengthInputStream(data = "Hello world", length = 5)
|
||||
fixedLengthInputStream.exhaust()
|
||||
|
||||
val result = fixedLengthInputStream.available()
|
||||
|
||||
assertThat(result).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `available() after skip()`() {
|
||||
val fixedLengthInputStream = createFixedLengthInputStream(data = "Hello world", length = 5)
|
||||
fixedLengthInputStream.guaranteedSkip(2)
|
||||
|
||||
val result = fixedLengthInputStream.available()
|
||||
|
||||
assertThat(result).isEqualTo(3)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `available() after skip remaining`() {
|
||||
val fixedLengthInputStream = createFixedLengthInputStream(data = "Hello world", length = 5)
|
||||
fixedLengthInputStream.skipRemaining()
|
||||
|
||||
val result = fixedLengthInputStream.available()
|
||||
|
||||
assertThat(result).isEqualTo(0)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `skip() should consume bytes`() {
|
||||
val fixedLengthInputStream = createFixedLengthInputStream(data = "Hello world", length = 5)
|
||||
|
||||
fixedLengthInputStream.guaranteedSkip(2)
|
||||
|
||||
assertThat(fixedLengthInputStream).readToString().isEqualTo("llo")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `skipRemaining() should exhaust stream`() {
|
||||
val fixedLengthInputStream = createFixedLengthInputStream(data = "Hello world", length = 5)
|
||||
|
||||
fixedLengthInputStream.skipRemaining()
|
||||
|
||||
assertThat(fixedLengthInputStream).isExhausted()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `skipRemaining() should not consume more than limit from underlying InputStream`() {
|
||||
val inputStream = "Hello World".byteInputStream()
|
||||
val fixedLengthInputStream = FixedLengthInputStream(inputStream, 6)
|
||||
|
||||
fixedLengthInputStream.skipRemaining()
|
||||
|
||||
assertThat(inputStream).readToString().isEqualTo("World")
|
||||
}
|
||||
|
||||
private fun createFixedLengthInputStream(data: String, length: Int): FixedLengthInputStream {
|
||||
return FixedLengthInputStream(data.byteInputStream(), length)
|
||||
}
|
||||
|
||||
private fun InputStream.guaranteedSkip(numberOfBytesToSkip: Int) {
|
||||
var remaining = numberOfBytesToSkip.toLong()
|
||||
while (remaining > 0) {
|
||||
remaining -= skip(remaining)
|
||||
}
|
||||
|
||||
assertThat(remaining).isEqualTo(0L)
|
||||
}
|
||||
|
||||
private fun InputStream.readToString(): String = source().buffer().readUtf8()
|
||||
|
||||
private fun InputStream.exhaust() {
|
||||
source().buffer().readAll(blackholeSink())
|
||||
}
|
||||
|
||||
private fun InputStream.consumeBytes(numberOfBytes: Int) {
|
||||
val numberOfBytesRead = read(ByteArray(numberOfBytes))
|
||||
|
||||
assertThat(numberOfBytesRead).isEqualTo(numberOfBytes)
|
||||
}
|
||||
|
||||
private fun Assert<InputStream>.isExhausted() = given { actual ->
|
||||
assertThat(actual.read()).isEqualTo(-1)
|
||||
assertThat(actual.available()).isEqualTo(0)
|
||||
}
|
||||
|
||||
private fun Assert<InputStream>.readToString() = transform { it.readToString() }
|
||||
|
||||
private fun Assert<ByteArray>.slice(range: IntRange) = transform { it.sliceArray(range) }
|
||||
|
||||
private fun Assert<ByteArray>.asString() = transform { String(it) }
|
||||
}
|
Loading…
Reference in a new issue