| 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.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InterruptedIOException; |
| import java.io.OutputStream; |
| import java.nio.ByteBuffer; |
| import java.nio.channels.AsynchronousByteChannel; |
| import java.nio.channels.ClosedChannelException; |
| import java.nio.channels.NonWritableChannelException; |
| import java.nio.channels.ShutdownChannelGroupException; |
| import java.nio.channels.WritableByteChannel; |
| import java.util.concurrent.ExecutionException; |
| import java.util.concurrent.Future; |
| |
| import static java.nio.file.Files.readAllBytes; |
| 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(OutputStream)} and {@link Channels#newBufferedChannel(OutputStream)}. |
| */ |
| public class ChannelsWriterTest |
| { |
| @Rule |
| public final ExpectedException ee = ExpectedException.none(); |
| |
| @Rule |
| public final TemporaryFolder tmp = TemporaryFolder.builder() |
| .assureDeletion() |
| .build(); |
| |
| @Test |
| public void wrappedBuffer() throws Exception |
| { |
| final boolean[] isFlush = {false}; |
| ByteArrayOutputStream out = new ByteArrayOutputStream() |
| { |
| @Override |
| public void flush() throws IOException |
| { |
| isFlush[0] = true; |
| super.flush(); |
| } |
| }; |
| WritableByteChannel channel = Channels.newBufferedChannel( out ); |
| ByteBuffer bb = ByteBuffer.wrap( new byte[] {1, 2, 3} ); |
| int countWritten = channel.write( bb ); |
| assertThat( countWritten ) |
| .isEqualTo( 3 ); |
| |
| assertThat( out.toByteArray() ) |
| .hasSize( 3 ) |
| .isEqualTo( new byte[] {1, 2, 3} ); |
| |
| assertThat( isFlush ) |
| .hasSize( 1 ) |
| .containsOnly( true ); |
| |
| assertThat( bb.position() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.limit() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.capacity() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( channel.isOpen() ) |
| .isTrue(); |
| } |
| |
| @Test |
| public void bigBuffer() throws Exception |
| { |
| ByteArrayOutputStream out = new ByteArrayOutputStream(); |
| WritableByteChannel channel = Channels.newChannel( out ); |
| ByteBuffer bb = ByteBuffer.allocate( 4 ); |
| bb.put( (byte) 1 ); |
| bb.put( (byte) 2 ); |
| bb.put( (byte) 3 ); |
| int countWritten = channel.write( bb ); |
| assertThat( countWritten ).isEqualTo( 3 ); |
| assertThat( out.toByteArray() ) |
| .hasSize( 3 ) |
| .isEqualTo( new byte[] {1, 2, 3} ); |
| |
| assertThat( bb.position() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.limit() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.capacity() ) |
| .isEqualTo( 4 ); |
| |
| assertThat( channel.isOpen() ) |
| .isTrue(); |
| } |
| |
| @Test |
| public void bufferedChannel() throws Exception |
| { |
| ByteArrayOutputStream out = new ByteArrayOutputStream(); |
| WritableBufferedByteChannel channel = Channels.newBufferedChannel( out ); |
| ByteBuffer bb = ByteBuffer.allocate( 5 ); |
| bb.put( (byte) 1 ); |
| bb.put( (byte) 2 ); |
| bb.put( (byte) 3 ); |
| |
| channel.writeBuffered( bb ); |
| |
| assertThat( out.toByteArray() ) |
| .isEmpty(); |
| |
| channel.write( ByteBuffer.allocate( 0 ) ); |
| |
| assertThat( out.toByteArray() ) |
| .isEmpty(); |
| |
| channel.write( ByteBuffer.wrap( new byte[] {4} ) ); |
| |
| assertThat( out.toByteArray() ) |
| .hasSize( 4 ) |
| .isEqualTo( new byte[] {1, 2, 3, 4} ); |
| |
| assertThat( bb.position() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.limit() ) |
| .isEqualTo( 3 ); |
| |
| assertThat( bb.capacity() ) |
| .isEqualTo( 5 ); |
| |
| assertThat( channel.isOpen() ) |
| .isTrue(); |
| } |
| |
| @Test |
| public void shouldFailAfterClosed() throws IOException |
| { |
| ByteArrayOutputStream out = new ByteArrayOutputStream(); |
| WritableByteChannel channel = Channels.newChannel( out ); |
| channel.close(); |
| assertThat( channel.isOpen() ).isFalse(); |
| ee.expect( ClosedChannelException.class ); |
| channel.write( ByteBuffer.allocate( 0 ) ); |
| } |
| |
| @Test |
| public void shouldFailIfNotReadable() throws IOException |
| { |
| ByteArrayOutputStream out = new ByteArrayOutputStream(); |
| WritableByteChannel channel = Channels.newChannel( out ); |
| ee.expect( NonWritableChannelException.class ); |
| channel.write( ByteBuffer.allocate( 0 ).asReadOnlyBuffer() ); |
| } |
| |
| @Test |
| public void shouldFailIOnDirectBuffer() throws IOException |
| { |
| ByteArrayOutputStream out = new ByteArrayOutputStream(); |
| WritableByteChannel channel = Channels.newChannel( out ); |
| ee.expect( NonWritableChannelException.class ); |
| channel.write( ByteBuffer.allocateDirect( 0 ) ); |
| } |
| |
| @Test |
| public void shouldUseFileChannel() throws IOException |
| { |
| File f = tmp.newFile(); |
| FileOutputStream os = new FileOutputStream( f ); |
| WritableByteChannel channel = Channels.newChannel( os ); |
| ByteBuffer bb = ByteBuffer.wrap( new byte[] {1, 2, 3} ); |
| channel.write( bb ); |
| |
| assertThat( channel.isOpen() ) |
| .isTrue(); |
| |
| channel.close(); |
| |
| assertThat( channel.isOpen() ) |
| .isFalse(); |
| |
| assertThat( readAllBytes( f.toPath() ) ) |
| .hasSize( 3 ) |
| .isEqualTo( new byte[] {1, 2, 3} ); |
| } |
| |
| @Test( expected = IndexOutOfBoundsException.class ) |
| public void shouldValidateInput1() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| OutputStream os = Channels.newOutputStream( channel ); |
| os.write( new byte[0], -1, 0 ); |
| } |
| |
| @Test( expected = IndexOutOfBoundsException.class ) |
| public void shouldValidateInput2() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| OutputStream os = Channels.newOutputStream( channel ); |
| os.write( new byte[0], 0, -1 ); |
| } |
| |
| @Test( expected = IndexOutOfBoundsException.class ) |
| public void shouldValidateInput3() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| OutputStream os = Channels.newOutputStream( channel ); |
| os.write( new byte[0], 1, 0 ); |
| } |
| |
| @Test( expected = IndexOutOfBoundsException.class ) |
| public void shouldValidateInput4() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| OutputStream os = Channels.newOutputStream( channel ); |
| os.write( new byte[0], 0, 1 ); |
| } |
| |
| @Test |
| public void shouldClose() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| when( channel.isOpen() ).thenReturn( true ); |
| OutputStream os = Channels.newOutputStream( channel ); |
| os.close(); |
| verify( channel, times( 1 ) ).close(); |
| } |
| |
| @Test |
| public void shouldNotClose() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| when( channel.isOpen() ).thenReturn( false ); |
| OutputStream os = Channels.newOutputStream( channel ); |
| os.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(); |
| OutputStream os = Channels.newOutputStream( channel ); |
| os.close(); |
| verify( channel ).close(); |
| } |
| |
| @Test |
| public void shouldWriteZeroLength() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| OutputStream os = Channels.newOutputStream( channel ); |
| os.write( new byte[] { 5 }, 0, 0 ); |
| verifyZeroInteractions( channel ); |
| } |
| |
| @Test |
| public void shouldWriteArray() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| when( channel.write( any( ByteBuffer.class ) ) ) |
| .thenAnswer( new Answer<Future<Integer>>() |
| { |
| @Override |
| public Future<Integer> answer( InvocationOnMock invocation ) throws Throwable |
| { |
| ByteBuffer bb = (ByteBuffer) invocation.getArguments()[0]; |
| int i = 0; |
| for ( ; bb.hasRemaining(); i++ ) |
| { |
| bb.get(); |
| } |
| Future<Integer> future = mock( Future.class ); |
| when( future.get() ).thenReturn( i ); |
| return future; |
| } |
| } ); |
| |
| OutputStream os = Channels.newOutputStream( channel ); |
| ArgumentCaptor<ByteBuffer> captured = ArgumentCaptor.forClass( ByteBuffer.class ); |
| os.write( new byte[] { 1, 2, 3, 4, 5 }, 2, 2 ); |
| |
| verify( channel ).write( 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 shouldWrite() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| when( channel.write( any( ByteBuffer.class ) ) ) |
| .thenAnswer( new Answer<Future<Integer>>() |
| { |
| @Override |
| public Future<Integer> answer( InvocationOnMock invocation ) throws Throwable |
| { |
| ByteBuffer bb = (ByteBuffer) invocation.getArguments()[0]; |
| int i = 0; |
| for ( ; bb.hasRemaining(); i++ ) |
| { |
| bb.get(); |
| } |
| Future<Integer> future = mock( Future.class ); |
| when( future.get() ).thenReturn( i ); |
| return future; |
| } |
| } ); |
| |
| OutputStream os = Channels.newOutputStream( channel ); |
| ArgumentCaptor<ByteBuffer> captured = ArgumentCaptor.forClass( ByteBuffer.class ); |
| os.write( 3 ); |
| |
| verify( channel ).write( 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 shouldThrowExceptionOnWrite() throws Exception |
| { |
| AsynchronousByteChannel channel = mock( AsynchronousByteChannel.class ); |
| when( channel.write( any( ByteBuffer.class ) ) ) |
| .thenThrow( ShutdownChannelGroupException.class ); |
| OutputStream os = Channels.newOutputStream( channel ); |
| ee.expect( IOException.class ); |
| ee.expectCause( instanceOf( ShutdownChannelGroupException.class ) ); |
| os.write( 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.write( any( ByteBuffer.class ) ) ) |
| .thenReturn( future ); |
| OutputStream os = Channels.newOutputStream( channel ); |
| ee.expect( InterruptedIOException.class ); |
| os.write( 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.write( any( ByteBuffer.class ) ) ) |
| .thenReturn( future ); |
| OutputStream os = Channels.newOutputStream( channel ); |
| ee.expect( IOException.class ); |
| ee.expectCause( instanceOf( RuntimeException.class ) ); |
| ee.expectMessage( "msg" ); |
| os.write( 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.write( any( ByteBuffer.class ) ) ) |
| .thenReturn( future ); |
| OutputStream os = Channels.newOutputStream( channel ); |
| ee.expect( IOException.class ); |
| ee.expectMessage( "msg" ); |
| os.write( new byte[1], 0, 1 ); |
| } |
| } |