1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.compress.archivers.zip;
18
19 import static org.junit.jupiter.api.Assertions.assertEquals;
20 import static org.junit.jupiter.api.Assertions.assertThrows;
21 import static org.mockito.ArgumentMatchers.any;
22 import static org.mockito.ArgumentMatchers.eq;
23 import static org.mockito.Mockito.mock;
24 import static org.mockito.Mockito.times;
25 import static org.mockito.Mockito.verify;
26 import static org.mockito.Mockito.when;
27
28 import java.io.IOException;
29 import java.nio.ByteBuffer;
30 import java.nio.channels.FileChannel;
31 import java.nio.channels.SeekableByteChannel;
32 import java.nio.charset.StandardCharsets;
33 import java.nio.file.Files;
34 import java.nio.file.Path;
35 import java.nio.file.StandardOpenOption;
36
37 import org.apache.commons.compress.AbstractTempDirTest;
38 import org.junit.jupiter.api.Test;
39
40
41
42
43 public class SeekableChannelRandomAccessOutputStreamTest extends AbstractTempDirTest {
44
45 @Test
46 public void testInitialization() throws IOException {
47 final Path file = newTempPath("testChannel");
48 try (SeekableChannelRandomAccessOutputStream stream = new SeekableChannelRandomAccessOutputStream(
49 Files.newByteChannel(file, StandardOpenOption.CREATE, StandardOpenOption.WRITE))) {
50 assertEquals(0, stream.position());
51 }
52 }
53
54 @Test
55 public void testWrite() throws IOException {
56 final FileChannel channel = mock(FileChannel.class);
57 final SeekableChannelRandomAccessOutputStream stream = new SeekableChannelRandomAccessOutputStream(channel);
58
59 when(channel.position()).thenReturn(11L);
60 when(channel.write((ByteBuffer) any())).thenAnswer(answer -> {
61 ((ByteBuffer) answer.getArgument(0)).position(5);
62 return 5;
63 }).thenAnswer(answer -> {
64 ((ByteBuffer) answer.getArgument(0)).position(6);
65 return 6;
66 });
67
68 stream.write("hello".getBytes(StandardCharsets.UTF_8));
69 stream.write("world\n".getBytes(StandardCharsets.UTF_8));
70
71 verify(channel, times(2)).write((ByteBuffer) any());
72
73 assertEquals(11, stream.position());
74 }
75
76 @Test
77 public void testWriteFullyAt_whenFullAtOnce_thenSucceed() throws IOException {
78 final SeekableByteChannel channel = mock(SeekableByteChannel.class);
79 final SeekableChannelRandomAccessOutputStream stream = new SeekableChannelRandomAccessOutputStream(channel);
80
81 when(channel.position()).thenReturn(50L).thenReturn(60L);
82 when(channel.write((ByteBuffer) any())).thenAnswer(answer -> {
83 ((ByteBuffer) answer.getArgument(0)).position(5);
84 return 5;
85 }).thenAnswer(answer -> {
86 ((ByteBuffer) answer.getArgument(0)).position(6);
87 return 6;
88 });
89
90 stream.writeFully("hello".getBytes(StandardCharsets.UTF_8), 20);
91 stream.writeFully("world\n".getBytes(StandardCharsets.UTF_8), 30);
92
93 verify(channel, times(2)).write((ByteBuffer) any());
94 verify(channel, times(1)).position(eq(50L));
95 verify(channel, times(1)).position(eq(60L));
96
97 assertEquals(60L, stream.position());
98 }
99
100 @Test
101 public void testWriteFullyAt_whenFullButPartial_thenSucceed() throws IOException {
102 final SeekableByteChannel channel = mock(SeekableByteChannel.class);
103 final SeekableChannelRandomAccessOutputStream stream = new SeekableChannelRandomAccessOutputStream(channel);
104
105 when(channel.position()).thenReturn(50L).thenReturn(60L);
106 when(channel.write((ByteBuffer) any())).thenAnswer(answer -> {
107 ((ByteBuffer) answer.getArgument(0)).position(3);
108 return 3;
109 }).thenAnswer(answer -> {
110 ((ByteBuffer) answer.getArgument(0)).position(5);
111 return 2;
112 }).thenAnswer(answer -> {
113 ((ByteBuffer) answer.getArgument(0)).position(6);
114 return 6;
115 });
116
117 stream.writeFully("hello".getBytes(StandardCharsets.UTF_8), 20);
118 stream.writeFully("world\n".getBytes(StandardCharsets.UTF_8), 30);
119
120 verify(channel, times(3)).write((ByteBuffer) any());
121 verify(channel, times(1)).position(eq(50L));
122 verify(channel, times(1)).position(eq(60L));
123
124 assertEquals(60L, stream.position());
125 }
126
127 @Test
128 public void testWriteFullyAt_whenPartial_thenFail() throws IOException {
129 final SeekableByteChannel channel = mock(SeekableByteChannel.class);
130 final SeekableChannelRandomAccessOutputStream stream = new SeekableChannelRandomAccessOutputStream(channel);
131
132 when(channel.position()).thenReturn(50L);
133 when(channel.write((ByteBuffer) any())).thenAnswer(answer -> {
134 ((ByteBuffer) answer.getArgument(0)).position(3);
135 return 3;
136 }).thenAnswer(answer -> 0);
137
138 assertThrows(IOException.class, () -> stream.writeFully("hello".getBytes(StandardCharsets.UTF_8), 20));
139
140 verify(channel, times(2)).write((ByteBuffer) any());
141
142 assertEquals(50L, stream.position());
143 }
144 }