blob: 219ab00e80f683bb8ddc2bfdea6da6ee0070301b [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.commons.io.input;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.assertThrows;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.ObservableInputStream.Observer;
import org.apache.commons.io.output.NullOutputStream;
import org.junit.jupiter.api.Test;
/**
* Tests {@link ObservableInputStream}.
*/
public class ObservableInputStreamTest {
private static class DataViewObserver extends MethodCountObserver {
private byte[] buffer;
private int lastValue = -1;
private int length = -1;
private int offset = -1;
@Override
public void data(final byte[] buffer, final int offset, final int length) throws IOException {
this.buffer = buffer;
this.offset = offset;
this.length = length;
}
@Override
public void data(final int value) throws IOException {
super.data(value);
lastValue = value;
}
}
private static class LengthObserver extends Observer {
private long total;
@Override
public void data(final byte[] buffer, final int offset, final int length) throws IOException {
this.total += length;
}
@Override
public void data(final int value) throws IOException {
total++;
}
public long getTotal() {
return total;
}
}
private static class MethodCountObserver extends Observer {
private long closedCount;
private long dataBufferCount;
private long dataCount;
private long errorCount;
private long finishedCount;
@Override
public void closed() throws IOException {
closedCount++;
}
@Override
public void data(final byte[] buffer, final int offset, final int length) throws IOException {
dataBufferCount++;
}
@Override
public void data(final int value) throws IOException {
dataCount++;
}
@Override
public void error(final IOException exception) throws IOException {
errorCount++;
}
@Override
public void finished() throws IOException {
finishedCount++;
}
public long getClosedCount() {
return closedCount;
}
public long getDataBufferCount() {
return dataBufferCount;
}
public long getDataCount() {
return dataCount;
}
public long getErrorCount() {
return errorCount;
}
public long getFinishedCount() {
return finishedCount;
}
}
@Test
public void testBrokenInputStreamRead() throws IOException {
try (final ObservableInputStream ois = new ObservableInputStream(new BrokenInputStream())) {
assertThrows(IOException.class, () -> ois.read());
}
}
@Test
public void testBrokenInputStreamReadBuffer() throws IOException {
try (final ObservableInputStream ois = new ObservableInputStream(new BrokenInputStream())) {
assertThrows(IOException.class, () -> ois.read(new byte[1]));
}
}
@Test
public void testBrokenInputStreamReadSubBuffer() throws IOException {
try (final ObservableInputStream ois = new ObservableInputStream(new BrokenInputStream())) {
assertThrows(IOException.class, () -> ois.read(new byte[2], 0, 1));
}
}
/**
* Tests that {@link Observer#data(int)} is called.
*/
@Test
public void testDataByteCalled_add() throws Exception {
final byte[] buffer = MessageDigestCalculatingInputStreamTest
.generateRandomByteStream(IOUtils.DEFAULT_BUFFER_SIZE);
final DataViewObserver lko = new DataViewObserver();
try (final ObservableInputStream ois = new ObservableInputStream(new ByteArrayInputStream(buffer))) {
assertEquals(-1, lko.lastValue);
ois.read();
assertEquals(-1, lko.lastValue);
assertEquals(0, lko.getFinishedCount());
assertEquals(0, lko.getClosedCount());
ois.add(lko);
for (int i = 1; i < buffer.length; i++) {
final int result = ois.read();
assertEquals((byte) result, buffer[i]);
assertEquals(result, lko.lastValue);
assertEquals(0, lko.getFinishedCount());
assertEquals(0, lko.getClosedCount());
}
final int result = ois.read();
assertEquals(-1, result);
assertEquals(1, lko.getFinishedCount());
assertEquals(0, lko.getClosedCount());
ois.close();
assertEquals(1, lko.getFinishedCount());
assertEquals(1, lko.getClosedCount());
}
}
/**
* Tests that {@link Observer#data(int)} is called.
*/
@Test
public void testDataByteCalled_ctor() throws Exception {
final byte[] buffer = MessageDigestCalculatingInputStreamTest
.generateRandomByteStream(IOUtils.DEFAULT_BUFFER_SIZE);
final DataViewObserver lko = new DataViewObserver();
try (final ObservableInputStream ois = new ObservableInputStream(new ByteArrayInputStream(buffer), lko)) {
assertEquals(-1, lko.lastValue);
ois.read();
assertNotEquals(-1, lko.lastValue);
assertEquals(0, lko.getFinishedCount());
assertEquals(0, lko.getClosedCount());
for (int i = 1; i < buffer.length; i++) {
final int result = ois.read();
assertEquals((byte) result, buffer[i]);
assertEquals(result, lko.lastValue);
assertEquals(0, lko.getFinishedCount());
assertEquals(0, lko.getClosedCount());
}
final int result = ois.read();
assertEquals(-1, result);
assertEquals(1, lko.getFinishedCount());
assertEquals(0, lko.getClosedCount());
ois.close();
assertEquals(1, lko.getFinishedCount());
assertEquals(1, lko.getClosedCount());
}
}
/**
* Tests that {@link Observer#data(byte[],int,int)} is called.
*/
@Test
public void testDataBytesCalled() throws Exception {
final byte[] buffer = MessageDigestCalculatingInputStreamTest
.generateRandomByteStream(IOUtils.DEFAULT_BUFFER_SIZE);
try (final ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
final ObservableInputStream ois = new ObservableInputStream(bais)) {
final DataViewObserver observer = new DataViewObserver();
final byte[] readBuffer = new byte[23];
assertEquals(null, observer.buffer);
ois.read(readBuffer);
assertEquals(null, observer.buffer);
ois.add(observer);
for (;;) {
if (bais.available() >= 2048) {
final int result = ois.read(readBuffer);
if (result == -1) {
ois.close();
break;
}
assertEquals(readBuffer, observer.buffer);
assertEquals(0, observer.offset);
assertEquals(readBuffer.length, observer.length);
} else {
final int res = Math.min(11, bais.available());
final int result = ois.read(readBuffer, 1, 11);
if (result == -1) {
ois.close();
break;
}
assertEquals(readBuffer, observer.buffer);
assertEquals(1, observer.offset);
assertEquals(res, observer.length);
}
}
}
}
@Test
public void testGetObservers0() throws IOException {
try (final ObservableInputStream ois = new ObservableInputStream(new NullInputStream())) {
assertTrue(ois.getObservers().isEmpty());
}
}
@Test
public void testGetObservers1() throws IOException {
final DataViewObserver observer0 = new DataViewObserver();
try (final ObservableInputStream ois = new ObservableInputStream(new NullInputStream(), observer0)) {
assertEquals(observer0, ois.getObservers().get(0));
}
}
@Test
public void testGetObserversOrder() throws IOException {
final DataViewObserver observer0 = new DataViewObserver();
final DataViewObserver observer1 = new DataViewObserver();
try (final ObservableInputStream ois = new ObservableInputStream(new NullInputStream(), observer0, observer1)) {
assertEquals(observer0, ois.getObservers().get(0));
assertEquals(observer1, ois.getObservers().get(1));
}
}
private void testNotificationCallbacks(final int bufferSize) throws IOException {
final byte[] buffer = IOUtils.byteArray();
final LengthObserver lengthObserver = new LengthObserver();
final MethodCountObserver methodCountObserver = new MethodCountObserver();
try (final ObservableInputStream ois = new ObservableInputStream(new ByteArrayInputStream(buffer),
lengthObserver, methodCountObserver)) {
assertEquals(IOUtils.DEFAULT_BUFFER_SIZE,
IOUtils.copy(ois, NullOutputStream.NULL_OUTPUT_STREAM, bufferSize));
}
assertEquals(IOUtils.DEFAULT_BUFFER_SIZE, lengthObserver.getTotal());
assertEquals(1, methodCountObserver.getClosedCount());
assertEquals(1, methodCountObserver.getFinishedCount());
assertEquals(0, methodCountObserver.getErrorCount());
assertEquals(0, methodCountObserver.getDataCount());
assertEquals(buffer.length / bufferSize, methodCountObserver.getDataBufferCount());
}
@Test
public void testNotificationCallbacksBufferSize1() throws Exception {
testNotificationCallbacks(1);
}
@Test
public void testNotificationCallbacksBufferSize2() throws Exception {
testNotificationCallbacks(2);
}
@Test
public void testNotificationCallbacksBufferSizeDefault() throws Exception {
testNotificationCallbacks(IOUtils.DEFAULT_BUFFER_SIZE);
}
}