1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.io.output;
18
19 import static org.junit.jupiter.api.Assertions.assertArrayEquals;
20 import static org.junit.jupiter.api.Assertions.assertEquals;
21 import static org.junit.jupiter.api.Assertions.assertSame;
22 import static org.junit.jupiter.api.Assertions.assertThrows;
23 import static org.junit.jupiter.api.Assertions.assertTrue;
24 import static org.junit.jupiter.api.Assertions.fail;
25
26 import java.io.ByteArrayInputStream;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.util.stream.Stream;
30
31 import org.apache.commons.io.IOUtils;
32 import org.apache.commons.io.function.IOFunction;
33 import org.apache.commons.io.input.ClosedInputStream;
34 import org.junit.jupiter.params.ParameterizedTest;
35 import org.junit.jupiter.params.provider.Arguments;
36 import org.junit.jupiter.params.provider.MethodSource;
37
38
39
40
41 public class ByteArrayOutputStreamTest {
42
43 private interface BAOSFactory<T extends AbstractByteArrayOutputStream> {
44 T newInstance();
45
46 T newInstance(final int size);
47 }
48
49 private static final class ByteArrayOutputStreamFactory implements BAOSFactory<ByteArrayOutputStream> {
50 @Override
51 public ByteArrayOutputStream newInstance() {
52 return new ByteArrayOutputStream();
53 }
54
55 @Override
56 public ByteArrayOutputStream newInstance(final int size) {
57 return new ByteArrayOutputStream(size);
58 }
59 }
60
61 private static final class UnsynchronizedByteArrayOutputStreamFactory implements BAOSFactory<UnsynchronizedByteArrayOutputStream> {
62 @Override
63 public UnsynchronizedByteArrayOutputStream newInstance() {
64 return new UnsynchronizedByteArrayOutputStream();
65 }
66
67 @Override
68 public UnsynchronizedByteArrayOutputStream newInstance(final int size) {
69 return new UnsynchronizedByteArrayOutputStream(size);
70 }
71 }
72
73 private static final byte[] DATA;
74
75 static {
76 DATA = new byte[64];
77 for (byte i = 0; i < 64; i++) {
78 DATA[i] = i;
79 }
80 }
81
82 private static Stream<Arguments> baosFactories() {
83 return Stream.of(Arguments.of(ByteArrayOutputStream.class.getSimpleName(), new ByteArrayOutputStreamFactory()),
84 Arguments.of(UnsynchronizedByteArrayOutputStream.class.getSimpleName(), new UnsynchronizedByteArrayOutputStreamFactory()));
85 }
86
87 private static boolean byteCmp(final byte[] src, final byte[] cmp) {
88 for (int i = 0; i < cmp.length; i++) {
89 if (src[i] != cmp[i]) {
90 return false;
91 }
92 }
93 return true;
94 }
95
96 private static Stream<Arguments> toBufferedInputStreamFunctionFactories() {
97 final IOFunction<InputStream, InputStream> syncBaosToBufferedInputStream = ByteArrayOutputStream::toBufferedInputStream;
98 final IOFunction<InputStream, InputStream> syncBaosToBufferedInputStreamWithSize = is -> ByteArrayOutputStream.toBufferedInputStream(is, 1024);
99 final IOFunction<InputStream, InputStream> unSyncBaosToBufferedInputStream = UnsynchronizedByteArrayOutputStream::toBufferedInputStream;
100 final IOFunction<InputStream, InputStream> unSyncBaosToBufferedInputStreamWithSize = is -> UnsynchronizedByteArrayOutputStream.toBufferedInputStream(is,
101 1024);
102
103 return Stream.of(Arguments.of("ByteArrayOutputStream.toBufferedInputStream(InputStream)", syncBaosToBufferedInputStream),
104 Arguments.of("ByteArrayOutputStream.toBufferedInputStream(InputStream, int)", syncBaosToBufferedInputStreamWithSize),
105 Arguments.of("UnsynchronizedByteArrayOutputStream.toBufferedInputStream(InputStream)", unSyncBaosToBufferedInputStream),
106 Arguments.of("UnsynchronizedByteArrayOutputStream.toBufferedInputStream(InputStream, int)", unSyncBaosToBufferedInputStreamWithSize));
107 }
108
109 private void checkByteArrays(final byte[] expected, final byte[] actual) {
110 if (expected.length != actual.length) {
111 fail("Resulting byte arrays are not equally long");
112 }
113 if (!byteCmp(expected, actual)) {
114 fail("Resulting byte arrays are not equal");
115 }
116 }
117
118 private void checkStreams(final AbstractByteArrayOutputStream actual, final java.io.ByteArrayOutputStream expected) {
119 assertEquals(expected.size(), actual.size(), "Sizes are not equal");
120 final byte[] buf = actual.toByteArray();
121 final byte[] refbuf = expected.toByteArray();
122 checkByteArrays(buf, refbuf);
123 }
124
125 @ParameterizedTest(name = "[{index}] {0}")
126 @MethodSource("baosFactories")
127 public void testInvalidParameterizedConstruction(final String baosName, final BAOSFactory<?> baosFactory) {
128 assertThrows(IllegalArgumentException.class, () -> baosFactory.newInstance(-1));
129 }
130
131 @ParameterizedTest(name = "[{index}] {0}")
132 @MethodSource("baosFactories")
133 public void testInvalidWriteLenUnder(final String baosName, final BAOSFactory<?> baosFactory) throws IOException {
134 try (AbstractByteArrayOutputStream baout = baosFactory.newInstance()) {
135 assertThrows(IndexOutOfBoundsException.class, () -> baout.write(new byte[1], 0, -1));
136 }
137 }
138
139 @ParameterizedTest(name = "[{index}] {0}")
140 @MethodSource("baosFactories")
141 public void testInvalidWriteOffsetAndLenOver(final String baosName, final BAOSFactory<?> baosFactory) throws IOException {
142 try (AbstractByteArrayOutputStream baout = baosFactory.newInstance()) {
143 assertThrows(IndexOutOfBoundsException.class, () -> baout.write(new byte[1], 0, 2));
144 }
145 }
146
147 @ParameterizedTest(name = "[{index}] {0}")
148 @MethodSource("baosFactories")
149 public void testInvalidWriteOffsetAndLenUnder(final String baosName, final BAOSFactory<?> baosFactory) throws IOException {
150 try (AbstractByteArrayOutputStream baout = baosFactory.newInstance()) {
151 assertThrows(IndexOutOfBoundsException.class, () -> baout.write(new byte[1], 1, -2));
152 }
153 }
154
155 @ParameterizedTest(name = "[{index}] {0}")
156 @MethodSource("baosFactories")
157 public void testInvalidWriteOffsetOver(final String baosName, final BAOSFactory<?> baosFactory) throws IOException {
158 try (AbstractByteArrayOutputStream baout = baosFactory.newInstance()) {
159 assertThrows(IndexOutOfBoundsException.class, () -> baout.write(IOUtils.EMPTY_BYTE_ARRAY, 1, 0));
160 }
161 }
162
163 @ParameterizedTest(name = "[{index}] {0}")
164 @MethodSource("baosFactories")
165 public void testInvalidWriteOffsetUnder(final String baosName, final BAOSFactory<?> baosFactory) throws IOException {
166 try (AbstractByteArrayOutputStream baout = baosFactory.newInstance()) {
167 assertThrows(IndexOutOfBoundsException.class, () -> baout.write(null, -1, 0));
168 }
169 }
170
171 @ParameterizedTest(name = "[{index}] {0}")
172 @MethodSource("baosFactories")
173 public void testStream(final String baosName, final BAOSFactory<?> baosFactory) throws Exception {
174 int written;
175
176
177
178 try (AbstractByteArrayOutputStream baout = baosFactory.newInstance(32);
179 final java.io.ByteArrayOutputStream ref = new java.io.ByteArrayOutputStream()) {
180
181
182 written = writeData(baout, ref, new int[] {4, 10, 22});
183 assertEquals(36, written);
184 checkStreams(baout, ref);
185
186
187 written = writeData(baout, ref, new int[] {20, 12});
188 assertEquals(32, written);
189 checkStreams(baout, ref);
190
191
192 baout.reset();
193 ref.reset();
194
195
196 written = writeData(baout, ref, new int[] {5, 47, 33, 60, 1, 0, 8});
197 assertEquals(155, written);
198 checkStreams(baout, ref);
199
200
201 baout.reset();
202 written = baout.write(new ByteArrayInputStream(ref.toByteArray()));
203 assertEquals(155, written);
204 checkStreams(baout, ref);
205
206
207
208 try (AbstractByteArrayOutputStream baout1 = baosFactory.newInstance(32)) {
209 ref.writeTo(baout1);
210 final java.io.ByteArrayOutputStream ref1 = new java.io.ByteArrayOutputStream();
211 baout.writeTo(ref1);
212 checkStreams(baout1, ref1);
213
214
215 final String baoutString = baout.toString("ASCII");
216 final String refString = ref.toString("ASCII");
217 assertEquals(refString, baoutString, "ASCII decoded String must be equal");
218
219
220
221 try (AbstractByteArrayOutputStream baos1 = baosFactory.newInstance();
222 final AbstractByteArrayOutputStream baos2 = baosFactory.newInstance()) {
223 assertSame(baos1.toByteArray(), baos2.toByteArray());
224 }
225 }
226 }
227 }
228
229 @ParameterizedTest(name = "[{index}] {0}")
230 @MethodSource("toBufferedInputStreamFunctionFactories")
231 public void testToBufferedInputStream(final String baosName, final IOFunction<InputStream, InputStream> toBufferedInputStreamFunction) throws IOException {
232 final byte[] data = {(byte) 0xCA, (byte) 0xFE, (byte) 0xBA, (byte) 0xBE};
233
234 try (ByteArrayInputStream bain = new ByteArrayInputStream(data)) {
235 assertEquals(data.length, bain.available());
236
237 try (InputStream buffered = toBufferedInputStreamFunction.apply(bain)) {
238 assertEquals(data.length, buffered.available());
239
240 assertArrayEquals(data, IOUtils.toByteArray(buffered));
241
242 }
243 }
244 }
245
246 @ParameterizedTest(name = "[{index}] {0}")
247 @MethodSource("toBufferedInputStreamFunctionFactories")
248 public void testToBufferedInputStreamEmpty(final String baosName, final IOFunction<InputStream, InputStream> toBufferedInputStreamFunction)
249 throws IOException {
250 try (ByteArrayInputStream bain = new ByteArrayInputStream(IOUtils.EMPTY_BYTE_ARRAY)) {
251 assertEquals(0, bain.available());
252
253 try (InputStream buffered = toBufferedInputStreamFunction.apply(bain)) {
254 assertEquals(0, buffered.available());
255
256 }
257 }
258 }
259
260 @ParameterizedTest(name = "[{index}] {0}")
261 @MethodSource("baosFactories")
262 public void testToInputStream(final String baosName, final BAOSFactory<?> baosFactory) throws IOException {
263 try (AbstractByteArrayOutputStream baout = baosFactory.newInstance();
264 final java.io.ByteArrayOutputStream ref = new java.io.ByteArrayOutputStream()) {
265
266
267 writeData(baout, ref, 32);
268 for (int i = 0; i < 128; i++) {
269 writeData(baout, ref, 64);
270 }
271
272
273 try (InputStream in = baout.toInputStream()) {
274 byte[] refData = ref.toByteArray();
275
276
277 writeData(baout, ref, new int[] {2, 4, 8, 16});
278
279
280 byte[] baoutData = IOUtils.toByteArray(in);
281 assertEquals(8224, baoutData.length);
282 checkByteArrays(refData, baoutData);
283
284
285 try (InputStream in2 = baout.toInputStream()) {
286 baoutData = IOUtils.toByteArray(in2);
287 }
288 refData = ref.toByteArray();
289 assertEquals(8254, baoutData.length);
290 checkByteArrays(refData, baoutData);
291 }
292 }
293 }
294
295 @ParameterizedTest(name = "[{index}] {0}")
296 @MethodSource("baosFactories")
297 public void testToInputStreamEmpty(final String baosName, final BAOSFactory<?> baosFactory) throws IOException {
298 try (AbstractByteArrayOutputStream baout = baosFactory.newInstance();
299
300 final InputStream in = baout.toInputStream()) {
301 assertEquals(0, in.available());
302 assertTrue(in instanceof ClosedInputStream);
303 }
304 }
305
306 @ParameterizedTest(name = "[{index}] {0}")
307 @MethodSource("baosFactories")
308 public void testToInputStreamWithReset(final String baosName, final BAOSFactory<?> baosFactory) throws IOException {
309
310 try (AbstractByteArrayOutputStream baout = baosFactory.newInstance();
311 final java.io.ByteArrayOutputStream ref = new java.io.ByteArrayOutputStream()) {
312
313
314 writeData(baout, ref, 32);
315 for (int i = 0; i < 128; i++) {
316 writeData(baout, ref, 64);
317 }
318
319
320 try (InputStream in = baout.toInputStream()) {
321 byte[] refData = ref.toByteArray();
322
323
324 baout.reset();
325 ref.reset();
326 writeData(baout, ref, new int[] {2, 4, 8, 16});
327
328
329 byte[] baoutData = IOUtils.toByteArray(in);
330 assertEquals(8224, baoutData.length);
331 checkByteArrays(refData, baoutData);
332
333
334 try (InputStream in2 = baout.toInputStream()) {
335 baoutData = IOUtils.toByteArray(in2);
336 }
337 refData = ref.toByteArray();
338 assertEquals(30, baoutData.length);
339 checkByteArrays(refData, baoutData);
340 }
341 }
342 }
343
344 @ParameterizedTest(name = "[{index}] {0}")
345 @MethodSource("baosFactories")
346 public void testWriteZero(final String baosName, final BAOSFactory<?> baosFactory) throws IOException {
347 try (AbstractByteArrayOutputStream baout = baosFactory.newInstance()) {
348 baout.write(IOUtils.EMPTY_BYTE_ARRAY, 0, 0);
349 assertTrue(true, "Dummy");
350 }
351 }
352
353 private int writeData(final AbstractByteArrayOutputStream baout, final java.io.ByteArrayOutputStream ref, final int count) {
354 if (count > DATA.length) {
355 throw new IllegalArgumentException("Requesting too many bytes");
356 }
357 if (count == 0) {
358 baout.write(100);
359 ref.write(100);
360 return 1;
361 }
362 baout.write(DATA, 0, count);
363 ref.write(DATA, 0, count);
364 return count;
365 }
366
367 private int writeData(final AbstractByteArrayOutputStream baout, final java.io.ByteArrayOutputStream ref, final int[] instructions) {
368 int written = 0;
369 for (final int instruction : instructions) {
370 written += writeData(baout, ref, instruction);
371 }
372 return written;
373 }
374 }