| package org.apache.maven.surefire.api.util.internal; |
| |
| /* |
| * 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. |
| */ |
| |
| import org.junit.Rule; |
| import org.junit.Test; |
| import org.junit.rules.ExpectedException; |
| import org.junit.rules.TemporaryFolder; |
| import org.mockito.ArgumentCaptor; |
| import org.mockito.invocation.InvocationOnMock; |
| import org.mockito.stubbing.Answer; |
| |
| import java.io.ByteArrayInputStream; |
| import java.io.File; |
| import java.io.FileInputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.InterruptedIOException; |
| import java.nio.ByteBuffer; |
| import java.nio.channels.AsynchronousByteChannel; |
| import java.nio.channels.ClosedChannelException; |
| import java.nio.channels.NonReadableChannelException; |
| import java.nio.channels.ReadableByteChannel; |
| import java.nio.channels.ShutdownChannelGroupException; |
| import java.util.concurrent.ExecutionException; |
| import java.util.concurrent.Future; |
| |
| import static java.nio.file.Files.write; |
| import static org.fest.assertions.Assertions.assertThat; |
| import static org.hamcrest.Matchers.instanceOf; |
| import static org.mockito.ArgumentMatchers.any; |
| import static org.mockito.Mockito.doThrow; |
| import static org.mockito.Mockito.mock; |
| import static org.mockito.Mockito.never; |
| import static org.mockito.Mockito.times; |
| import static org.mockito.Mockito.verify; |
| import static org.mockito.Mockito.verifyNoMoreInteractions; |
| import static org.mockito.Mockito.verifyZeroInteractions; |
| import static org.mockito.Mockito.when; |
| |
| /** |
| * The tests for {@link Channels#newChannel(InputStream)} and {@link Channels#newBufferedChannel(InputStream)}. |
| */ |
| public class ChannelsReaderTest |
| { |
| @Rule |
| public final ExpectedException ee = ExpectedException.none(); |
| |
| @Rule |
| public final TemporaryFolder tmp = TemporaryFolder.builder() |
| .assureDeletion() |
| .build(); |
| |
| @Test |
| public void exactBufferSize() throws Exception |
| { |
| ByteArrayInputStream is = new ByteArrayInputStream( new byte[] {1, 2, 3} ); |
| ReadableByteChannel channel = Channels.newChannel( is ); |
| ByteBuffer bb = ByteBuffer.allocate( 3 ); |
| |
| int countWritten = channel.read( bb ); |
| |
| assertThat( countWritten ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.arrayOffset() ) |
| .isEqualTo( 0 ); |
| |
| assertThat( bb.position() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.remaining() ) |
| .isEqualTo( 0 ); |
| |
| assertThat( bb.limit() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.capacity() ) |
| .isEqualTo( 3 ); |
| |
| bb.flip(); |
| |
| assertThat( bb.arrayOffset() ) |
| .isEqualTo( 0 ); |
| |
| assertThat( bb.position() ) |
| .isEqualTo( 0 ); |
| |
| assertThat( bb.remaining() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.limit() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.capacity() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.array() ) |
| .isEqualTo( new byte[] {1, 2, 3} ); |
| |
| assertThat( channel.isOpen() ) |
| .isTrue(); |
| |
| channel.close(); |
| |
| assertThat( channel.isOpen() ) |
| .isFalse(); |
| } |
| |
| @Test |
| public void bufferedChannel() throws Exception |
| { |
| ByteArrayInputStream is = new ByteArrayInputStream( new byte[] {1, 2, 3} ); |
| ReadableByteChannel channel = Channels.newBufferedChannel( is ); |
| ByteBuffer bb = ByteBuffer.allocate( 4 ); |
| |
| int countWritten = channel.read( bb ); |
| |
| assertThat( countWritten ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.arrayOffset() ) |
| .isEqualTo( 0 ); |
| |
| assertThat( bb.position() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.remaining() ) |
| .isEqualTo( 1 ); |
| |
| assertThat( bb.limit() ) |
| .isEqualTo( 4 ); |
| |
| assertThat( bb.capacity() ) |
| .isEqualTo( 4 ); |
| |
| bb.flip(); |
| |
| assertThat( bb.arrayOffset() ) |
| .isEqualTo( 0 ); |
| |
| assertThat( bb.position() ) |
| .isEqualTo( 0 ); |
| |
| assertThat( bb.remaining() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.limit() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.capacity() ) |
| .isEqualTo( 4 ); |
| |
| assertThat( bb.array() ) |
| .isEqualTo( new byte[] {1, 2, 3, 0} ); |
| |
| assertThat( channel.isOpen() ) |
| .isTrue(); |
| |
| channel.close(); |
| |
| assertThat( channel.isOpen() ) |
| .isFalse(); |
| } |
| |
| @Test |
| public void biggerBuffer() throws Exception |
| { |
| ByteArrayInputStream is = new ByteArrayInputStream( new byte[] {1, 2, 3} ); |
| ReadableByteChannel channel = Channels.newChannel( is ); |
| ByteBuffer bb = ByteBuffer.allocate( 4 ); |
| |
| int countWritten = channel.read( bb ); |
| |
| assertThat( countWritten ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.arrayOffset() ) |
| .isEqualTo( 0 ); |
| |
| assertThat( bb.position() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.remaining() ) |
| .isEqualTo( 1 ); |
| |
| assertThat( bb.limit() ) |
| .isEqualTo( 4 ); |
| |
| assertThat( bb.capacity() ) |
| .isEqualTo( 4 ); |
| |
| bb.flip(); |
| |
| assertThat( bb.arrayOffset() ) |
| .isEqualTo( 0 ); |
| |
| assertThat( bb.position() ) |
| .isEqualTo( 0 ); |
| |
| assertThat( bb.remaining() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.limit() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.capacity() ) |
| .isEqualTo( 4 ); |
| |
| assertThat( bb.array() ) |
| .isEqualTo( new byte[] {1, 2, 3, 0} ); |
| |
| assertThat( channel.isOpen() ) |
| .isTrue(); |
| |
| channel.close(); |
| |
| assertThat( channel.isOpen() ) |
| .isFalse(); |
| } |
| |
| @Test |
| public void shouldFailAfterClosed() throws IOException |
| { |
| ByteArrayInputStream is = new ByteArrayInputStream( new byte[] {1, 2, 3} ); |
| ReadableByteChannel channel = Channels.newChannel( is ); |
| channel.close(); |
| assertThat( channel.isOpen() ).isFalse(); |
| ee.expect( ClosedChannelException.class ); |
| channel.read( ByteBuffer.allocate( 0 ) ); |
| } |
| |
| @Test |
| public void shouldFailIfNotReadable() throws IOException |
| { |
| ByteArrayInputStream is = new ByteArrayInputStream( new byte[] {1, 2, 3} ); |
| ReadableByteChannel channel = Channels.newChannel( is ); |
| ee.expect( NonReadableChannelException.class ); |
| channel.read( ByteBuffer.allocate( 0 ).asReadOnlyBuffer() ); |
| } |
| |
| @Test |
| public void shouldFailIOnDirectBuffer() throws IOException |
| { |
| ByteArrayInputStream is = new ByteArrayInputStream( new byte[] {1, 2, 3} ); |
| ReadableByteChannel channel = Channels.newChannel( is ); |
| ee.expect( NonReadableChannelException.class ); |
| channel.read( ByteBuffer.allocateDirect( 0 ) ); |
| } |
| |
| @Test |
| public void shouldUseFileChannel() throws IOException |
| { |
| File f = tmp.newFile(); |
| write( f.toPath(), new byte[] {1, 2, 3} ); |
| FileInputStream is = new FileInputStream( f ); |
| ReadableByteChannel channel = Channels.newChannel( is ); |
| ByteBuffer bb = ByteBuffer.allocate( 4 ); |
| int countWritten = channel.read( bb ); |
| |
| assertThat( channel.isOpen() ) |
| .isTrue(); |
| |
| channel.close(); |
| |
| assertThat( channel.isOpen() ) |
| .isFalse(); |
| |
| assertThat( countWritten ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.arrayOffset() ) |
| .isEqualTo( 0 ); |
| |
| assertThat( bb.position() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.remaining() ) |
| .isEqualTo( 1 ); |
| |
| assertThat( bb.limit() ) |
| .isEqualTo( 4 ); |
| |
| assertThat( bb.capacity() ) |
| .isEqualTo( 4 ); |
| |
| bb.flip(); |
| |
| assertThat( bb.arrayOffset() ) |
| .isEqualTo( 0 ); |
| |
| assertThat( bb.position() ) |
| .isEqualTo( 0 ); |
| |
| assertThat( bb.remaining() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.limit() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.capacity() ) |
| .isEqualTo( 4 ); |
| |
| assertThat( bb.array() ) |
| .isEqualTo( new byte[] {1, 2, 3, 0} ); |
| } |
| |
| @Test( expected = IndexOutOfBoundsException.class ) |
| public void shouldValidateInput1() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| InputStream is = Channels.newInputStream( channel ); |
| is.read( new byte[0], -1, 0 ); |
| } |
| |
| @Test( expected = IndexOutOfBoundsException.class ) |
| public void shouldValidateInput2() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| InputStream is = Channels.newInputStream( channel ); |
| is.read( new byte[0], 0, -1 ); |
| } |
| |
| @Test( expected = IndexOutOfBoundsException.class ) |
| public void shouldValidateInput3() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| InputStream is = Channels.newInputStream( channel ); |
| is.read( new byte[0], 1, 0 ); |
| } |
| |
| @Test( expected = IndexOutOfBoundsException.class ) |
| public void shouldValidateInput4() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| InputStream is = Channels.newInputStream( channel ); |
| is.read( new byte[0], 0, 1 ); |
| } |
| |
| @Test |
| public void shouldClose() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| when( channel.isOpen() ).thenReturn( true ); |
| InputStream is = Channels.newInputStream( channel ); |
| is.close(); |
| verify( channel, times( 1 ) ).close(); |
| } |
| |
| @Test |
| public void shouldNotClose() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| when( channel.isOpen() ).thenReturn( false ); |
| InputStream is = Channels.newInputStream( channel ); |
| is.close(); |
| verify( channel, never() ).close(); |
| } |
| |
| @Test |
| public void shouldAlreadyClosed() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| when( channel.isOpen() ).thenReturn( true ); |
| doThrow( ClosedChannelException.class ).when( channel ).close(); |
| InputStream is = Channels.newInputStream( channel ); |
| is.close(); |
| verify( channel ).close(); |
| } |
| |
| @Test |
| public void shouldReadZeroLength() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| InputStream is = Channels.newInputStream( channel ); |
| is.read( new byte[] { 5 }, 0, 0 ); |
| verifyZeroInteractions( channel ); |
| } |
| |
| @Test |
| public void shouldReadArray() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| when( channel.read( any( ByteBuffer.class ) ) ) |
| .thenAnswer( new Answer<Future<Integer>>() |
| { |
| @Override |
| public Future<Integer> answer( InvocationOnMock invocation ) throws Throwable |
| { |
| ByteBuffer bb = (ByteBuffer) invocation.getArguments()[0]; |
| bb.put( (byte) 3 ); |
| bb.put( (byte) 4 ); |
| Future<Integer> future = mock( Future.class ); |
| when( future.get() ).thenReturn( 2 ); |
| return future; |
| } |
| } ); |
| |
| InputStream is = Channels.newInputStream( channel ); |
| ArgumentCaptor<ByteBuffer> captured = ArgumentCaptor.forClass( ByteBuffer.class ); |
| byte[] b = new byte[] { 1, 2, 0, 0, 5 }; |
| is.read( b, 2, 2 ); |
| |
| verify( channel ).read( captured.capture() ); |
| verifyNoMoreInteractions( channel ); |
| |
| assertThat( captured.getAllValues() ) |
| .hasSize( 1 ); |
| |
| assertThat( captured.getAllValues().get( 0 ).array() ) |
| .containsOnly( new byte[] { 1, 2, 3, 4, 5 } ); |
| |
| assertThat( captured.getAllValues().get( 0 ).arrayOffset() ) |
| .isEqualTo( 0 ); |
| |
| assertThat( captured.getAllValues().get( 0 ).position() ) |
| .isEqualTo( 4 ); |
| |
| assertThat( captured.getAllValues().get( 0 ).limit() ) |
| .isEqualTo( 4 ); |
| |
| assertThat( captured.getAllValues().get( 0 ).capacity() ) |
| .isEqualTo( 5 ); |
| } |
| |
| @Test |
| public void shouldRead() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| when( channel.read( any( ByteBuffer.class ) ) ) |
| .thenAnswer( new Answer<Future<Integer>>() |
| { |
| @Override |
| public Future<Integer> answer( InvocationOnMock invocation ) throws Throwable |
| { |
| ByteBuffer bb = (ByteBuffer) invocation.getArguments()[0]; |
| bb.put( (byte) 3 ); |
| Future<Integer> future = mock( Future.class ); |
| when( future.get() ).thenReturn( 1 ); |
| return future; |
| } |
| } ); |
| |
| InputStream is = Channels.newInputStream( channel ); |
| ArgumentCaptor<ByteBuffer> captured = ArgumentCaptor.forClass( ByteBuffer.class ); |
| int b = is.read(); |
| assertThat( b ) |
| .isEqualTo( 3 ); |
| |
| verify( channel ).read( captured.capture() ); |
| verifyNoMoreInteractions( channel ); |
| |
| assertThat( captured.getAllValues() ) |
| .hasSize( 1 ); |
| |
| assertThat( captured.getAllValues().get( 0 ).array() ) |
| .containsOnly( new byte[] { 3 } ); |
| |
| assertThat( captured.getAllValues().get( 0 ).arrayOffset() ) |
| .isEqualTo( 0 ); |
| |
| assertThat( captured.getAllValues().get( 0 ).position() ) |
| .isEqualTo( 1 ); |
| |
| assertThat( captured.getAllValues().get( 0 ).limit() ) |
| .isEqualTo( 1 ); |
| |
| assertThat( captured.getAllValues().get( 0 ).capacity() ) |
| .isEqualTo( 1 ); |
| } |
| |
| @Test |
| public void shouldThrowExceptionOnRead() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| when( channel.read( any( ByteBuffer.class ) ) ) |
| .thenThrow( ShutdownChannelGroupException.class ); |
| InputStream is = Channels.newInputStream( channel ); |
| ee.expect( IOException.class ); |
| ee.expectCause( instanceOf( ShutdownChannelGroupException.class ) ); |
| is.read( new byte[1], 0, 1 ); |
| } |
| |
| @Test |
| public void shouldThrowExceptionOnFuture1() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| Future<Integer> future = mock( Future.class ); |
| when( future.get() ) |
| .thenThrow( new ExecutionException( new InterruptedIOException() ) ); |
| when( channel.read( any( ByteBuffer.class ) ) ) |
| .thenReturn( future ); |
| InputStream is = Channels.newInputStream( channel ); |
| ee.expect( InterruptedIOException.class ); |
| is.read( new byte[1], 0, 1 ); |
| } |
| |
| @Test |
| public void shouldThrowExceptionOnFuture2() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| Future<Integer> future = mock( Future.class ); |
| when( future.get() ) |
| .thenThrow( new ExecutionException( new RuntimeException( "msg" ) ) ); |
| when( channel.read( any( ByteBuffer.class ) ) ) |
| .thenReturn( future ); |
| InputStream is = Channels.newInputStream( channel ); |
| ee.expect( IOException.class ); |
| ee.expectCause( instanceOf( RuntimeException.class ) ); |
| ee.expectMessage( "msg" ); |
| is.read( new byte[1], 0, 1 ); |
| } |
| |
| @Test |
| public void shouldThrowExceptionOnFuture3() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| Future<Integer> future = mock( Future.class ); |
| when( future.get() ) |
| .thenThrow( new ExecutionException( "msg", null ) ); |
| when( channel.read( any( ByteBuffer.class ) ) ) |
| .thenReturn( future ); |
| InputStream is = Channels.newInputStream( channel ); |
| ee.expect( IOException.class ); |
| ee.expectMessage( "msg" ); |
| is.read( new byte[1], 0, 1 ); |
| } |
| } |