1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.io.channels;
19
20 import static org.apache.commons.lang3.ArrayUtils.EMPTY_BYTE_ARRAY;
21 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
22 import static org.junit.jupiter.api.Assertions.assertEquals;
23 import static org.junit.jupiter.api.Assertions.assertThrows;
24 import static org.junit.jupiter.api.Assertions.assertTrue;
25
26 import java.io.IOException;
27 import java.nio.ByteBuffer;
28 import java.nio.channels.ClosedChannelException;
29 import java.nio.channels.NonWritableChannelException;
30 import java.nio.channels.SeekableByteChannel;
31 import java.nio.charset.Charset;
32 import java.nio.charset.StandardCharsets;
33 import java.nio.file.StandardOpenOption;
34 import java.util.stream.Stream;
35
36 import org.apache.commons.io.IOUtils;
37 import org.apache.commons.io.function.IOSupplier;
38 import org.apache.commons.lang3.ArrayUtils;
39 import org.junit.jupiter.api.Test;
40 import org.junit.jupiter.params.ParameterizedTest;
41 import org.junit.jupiter.params.provider.Arguments;
42 import org.junit.jupiter.params.provider.MethodSource;
43
44
45
46
47 public class ByteArraySeekableByteChannelTest extends AbstractSeekableByteChannelTest {
48
49 private static final Charset CHARSET = StandardCharsets.UTF_8;
50 private static final String STRING = "Some data";
51 private static final byte[] BYTE_ARRAY = STRING.getBytes(CHARSET);
52
53 static Stream<Arguments> testConstructor() {
54 return Stream.of(
55 Arguments.of((IOSupplier<ByteArraySeekableByteChannel>) ByteArraySeekableByteChannel::new, EMPTY_BYTE_ARRAY, IOUtils.DEFAULT_BUFFER_SIZE),
56 Arguments.of((IOSupplier<ByteArraySeekableByteChannel>) () -> new ByteArraySeekableByteChannel(8), EMPTY_BYTE_ARRAY, 8),
57 Arguments.of((IOSupplier<ByteArraySeekableByteChannel>) () -> new ByteArraySeekableByteChannel(16), EMPTY_BYTE_ARRAY, 16),
58 Arguments.of((IOSupplier<ByteArraySeekableByteChannel>) () -> ByteArraySeekableByteChannel.wrap(EMPTY_BYTE_ARRAY), EMPTY_BYTE_ARRAY, 0),
59 Arguments.of((IOSupplier<ByteArraySeekableByteChannel>) () -> ByteArraySeekableByteChannel.wrap(BYTE_ARRAY), BYTE_ARRAY, BYTE_ARRAY.length));
60 }
61
62 static Stream<Arguments> testShouldResizeWhenWritingMoreDataThanCapacity() {
63 return Stream.of(
64
65 Arguments.of(EMPTY_BYTE_ARRAY, 1),
66
67 Arguments.of(new byte[8], 1),
68
69 Arguments.of(new byte[8], 20));
70 }
71
72 @Override
73 protected SeekableByteChannel createChannel() throws IOException {
74 return new ByteArraySeekableByteChannel();
75 }
76
77 @Test
78 void testBuilderDefaultConstructor() throws IOException {
79 try (ByteArraySeekableByteChannel channel = new ByteArraySeekableByteChannel.Builder().get()) {
80 assertEquals(0, channel.position());
81 assertEquals(0, channel.size());
82 assertEquals(0, channel.array().length);
83 }
84 }
85
86 @Test
87 void testBuilderDefaultMethod() throws IOException {
88 try (ByteArraySeekableByteChannel channel = ByteArraySeekableByteChannel.builder().get()) {
89 assertEquals(0, channel.position());
90 assertEquals(0, channel.size());
91 assertEquals(0, channel.array().length);
92 }
93 }
94
95 @Test
96 void testBuilderReadOnly() throws IOException {
97 try (ByteArraySeekableByteChannel channel = ByteArraySeekableByteChannel.builder()
98 .setByteArray(BYTE_ARRAY)
99 .setOpenOptions(StandardOpenOption.READ)
100 .get()) {
101 assertEquals(0, channel.position());
102 assertEquals(9, channel.size());
103 assertEquals(9, channel.array().length);
104 assertThrows(NonWritableChannelException.class, () -> channel.write(ByteBuffer.wrap(BYTE_ARRAY)));
105 assertThrows(NonWritableChannelException.class, () -> channel.truncate(0));
106 }
107 }
108
109 private void testBuilderReadWrite(final ByteArraySeekableByteChannel channel) throws ClosedChannelException, IOException {
110 assertEquals(0, channel.position());
111 assertEquals(9, channel.size());
112 assertEquals(9, channel.array().length);
113 channel.truncate(0);
114 assertEquals(0, channel.position());
115 channel.write(ByteBuffer.wrap(BYTE_ARRAY));
116 assertEquals(9, channel.size());
117 assertEquals(9, channel.array().length);
118 }
119
120 @Test
121 void testBuilderReadWriteExplict() throws IOException {
122 try (ByteArraySeekableByteChannel channel = ByteArraySeekableByteChannel.builder()
123 .setByteArray(BYTE_ARRAY)
124 .setOpenOptions(StandardOpenOption.READ, StandardOpenOption.WRITE)
125 .get()) {
126 testBuilderReadWrite(channel);
127 }
128 }
129
130 @Test
131 void testBuilderReadWriteImplicit() throws IOException {
132 try (ByteArraySeekableByteChannel channel = ByteArraySeekableByteChannel.builder()
133 .setByteArray(BYTE_ARRAY)
134 .get()) {
135 testBuilderReadWrite(channel);
136 }
137 }
138
139 @Test
140 void testBuilderSetByteArray() throws IOException {
141 try (ByteArraySeekableByteChannel channel = ByteArraySeekableByteChannel.builder()
142 .setByteArray(BYTE_ARRAY)
143 .get()) {
144 assertEquals(0, channel.position());
145 assertEquals(9, channel.size());
146 assertEquals(9, channel.array().length);
147 }
148 }
149
150 @Test
151 void testBuilderSetByteArrayEmpty() throws IOException {
152 try (ByteArraySeekableByteChannel channel = ByteArraySeekableByteChannel.builder()
153 .setByteArray(ArrayUtils.EMPTY_BYTE_ARRAY)
154 .get()) {
155 assertEquals(0, channel.position());
156 assertEquals(0, channel.size());
157 assertEquals(0, channel.array().length);
158 }
159 }
160
161 @Test
162 void testBuilderSetCharSequence() throws IOException {
163 try (ByteArraySeekableByteChannel channel = ByteArraySeekableByteChannel.builder()
164 .setCharSequence(STRING)
165 .setCharset(CHARSET)
166 .get()) {
167 assertEquals(0, channel.position());
168 assertEquals(9, channel.size());
169 assertEquals(9, channel.array().length);
170 }
171 }
172
173 @ParameterizedTest
174 @MethodSource
175 void testConstructor(final IOSupplier<ByteArraySeekableByteChannel> supplier, final byte[] expected, final int capacity) throws IOException {
176 try (ByteArraySeekableByteChannel channel = supplier.get()) {
177 assertEquals(0, channel.position());
178 assertEquals(expected.length, channel.size());
179 assertEquals(capacity, channel.array().length);
180 assertArrayEquals(expected, channel.toByteArray());
181 }
182 }
183
184 @Test
185 void testConstructorInvalid() {
186 assertThrows(IllegalArgumentException.class, () -> new ByteArraySeekableByteChannel(-1));
187 assertThrows(NullPointerException.class, () -> ByteArraySeekableByteChannel.wrap(null));
188 }
189
190 @Test
191 void testPositionBeyondSizeReadWrite() throws IOException {
192 final ByteBuffer buffer = ByteBuffer.allocate(1);
193 channel.position(channel.size() + 1);
194 assertEquals(channel.size() + 1, channel.position());
195 assertEquals(-1, channel.read(buffer));
196 channel.position(Integer.MAX_VALUE + 1L);
197 assertEquals(Integer.MAX_VALUE + 1L, channel.position());
198 assertEquals(-1, channel.read(buffer));
199
200 assertThrows(IOException.class, () -> channel.write(buffer));
201 assertThrows(IllegalArgumentException.class, () -> channel.position(-1));
202 assertThrows(IllegalArgumentException.class, () -> channel.position(Integer.MIN_VALUE));
203 assertThrows(IllegalArgumentException.class, () -> channel.position(Long.MIN_VALUE));
204 }
205
206 @ParameterizedTest
207 @MethodSource
208 void testShouldResizeWhenWritingMoreDataThanCapacity(final byte[] data, final int wanted) throws IOException {
209 try (ByteArraySeekableByteChannel c = ByteArraySeekableByteChannel.wrap(data)) {
210 c.position(data.length);
211 final ByteBuffer inData = ByteBuffer.wrap(new byte[wanted]);
212 final int writeCount = c.write(inData);
213 assertEquals(wanted, writeCount);
214 assertTrue(c.array().length >= data.length + wanted, "Capacity not increased sufficiently");
215 }
216 }
217
218 }