1 /*
2  * Copyright (C) 2007 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.io;
18 
19 import static com.google.common.base.Charsets.UTF_16;
20 import com.google.common.base.Charsets;
21 import com.google.common.jdk5backport.Arrays;
22 
23 import java.io.ByteArrayInputStream;
24 import java.io.ByteArrayOutputStream;
25 import java.io.EOFException;
26 import java.io.FilterInputStream;
27 import java.io.IOException;
28 import java.io.InputStream;
29 import java.io.OutputStream;
30 import java.io.UnsupportedEncodingException;
31 import java.nio.channels.Channels;
32 import java.nio.channels.ReadableByteChannel;
33 import java.nio.channels.WritableByteChannel;
34 import java.util.zip.CRC32;
35 import java.util.zip.Checksum;
36 
37 /**
38  * Unit test for {@link ByteStreams}.
39  *
40  * @author Chris Nokleberg
41  */
42 public class ByteStreamsTest extends IoTestCase {
43 
testCopyChannel()44   public void testCopyChannel() throws IOException {
45     byte[] expected = newPreFilledByteArray(100);
46     ByteArrayOutputStream out = new ByteArrayOutputStream();
47     WritableByteChannel outChannel = Channels.newChannel(out);
48 
49     ReadableByteChannel inChannel =
50         Channels.newChannel(new ByteArrayInputStream(expected));
51     ByteStreams.copy(inChannel, outChannel);
52     assertEquals(expected, out.toByteArray());
53   }
54 
testReadFully()55   public void testReadFully() throws IOException {
56     byte[] b = new byte[10];
57 
58     try {
59       ByteStreams.readFully(newTestStream(10), null, 0, 10);
60       fail("expected exception");
61     } catch (NullPointerException e) {
62     }
63 
64     try {
65       ByteStreams.readFully(null, b, 0, 10);
66       fail("expected exception");
67     } catch (NullPointerException e) {
68     }
69 
70     try {
71       ByteStreams.readFully(newTestStream(10), b, -1, 10);
72       fail("expected exception");
73     } catch (IndexOutOfBoundsException e) {
74     }
75 
76     try {
77       ByteStreams.readFully(newTestStream(10), b, 0, -1);
78       fail("expected exception");
79     } catch (IndexOutOfBoundsException e) {
80     }
81 
82     try {
83       ByteStreams.readFully(newTestStream(10), b, 0, -1);
84       fail("expected exception");
85     } catch (IndexOutOfBoundsException e) {
86     }
87 
88     try {
89       ByteStreams.readFully(newTestStream(10), b, 2, 10);
90       fail("expected exception");
91     } catch (IndexOutOfBoundsException e) {
92     }
93 
94     try {
95       ByteStreams.readFully(newTestStream(5), b, 0, 10);
96       fail("expected exception");
97     } catch (EOFException e) {
98     }
99 
100     Arrays.fill(b, (byte) 0);
101     ByteStreams.readFully(newTestStream(10), b, 0, 0);
102     assertEquals(new byte[10], b);
103 
104     Arrays.fill(b, (byte) 0);
105     ByteStreams.readFully(newTestStream(10), b, 0, 10);
106     assertEquals(newPreFilledByteArray(10), b);
107 
108     Arrays.fill(b, (byte) 0);
109     ByteStreams.readFully(newTestStream(10), b, 0, 5);
110     assertEquals(new byte[]{0, 1, 2, 3, 4, 0, 0, 0, 0, 0}, b);
111   }
112 
testSkipFully()113   public void testSkipFully() throws IOException {
114     byte[] bytes = newPreFilledByteArray(100);
115     skipHelper(0, 0, new ByteArrayInputStream(bytes));
116     skipHelper(50, 50, new ByteArrayInputStream(bytes));
117     skipHelper(50, 50, new SlowSkipper(new ByteArrayInputStream(bytes), 1));
118     skipHelper(50, 50, new SlowSkipper(new ByteArrayInputStream(bytes), 0));
119     skipHelper(100, -1, new ByteArrayInputStream(bytes));
120     try {
121       skipHelper(101, 0, new ByteArrayInputStream(bytes));
122       fail("expected exception");
123     } catch (EOFException e) {
124     }
125   }
126 
skipHelper(long n, int expect, InputStream in)127   private static void skipHelper(long n, int expect, InputStream in)
128       throws IOException {
129     ByteStreams.skipFully(in, n);
130     assertEquals(expect, in.read());
131     in.close();
132   }
133 
134   private static final byte[] bytes =
135       new byte[] { 0x12, 0x34, 0x56, 0x78, 0x76, 0x54, 0x32, 0x10 };
136 
testNewDataInput_empty()137   public void testNewDataInput_empty() {
138     byte[] b = new byte[0];
139     ByteArrayDataInput in = ByteStreams.newDataInput(b);
140     try {
141       in.readInt();
142       fail("expected exception");
143     } catch (IllegalStateException expected) {
144     }
145   }
146 
testNewDataInput_normal()147   public void testNewDataInput_normal() {
148     ByteArrayDataInput in = ByteStreams.newDataInput(bytes);
149     assertEquals(0x12345678, in.readInt());
150     assertEquals(0x76543210, in.readInt());
151     try {
152       in.readInt();
153       fail("expected exception");
154     } catch (IllegalStateException expected) {
155     }
156   }
157 
testNewDataInput_readFully()158   public void testNewDataInput_readFully() {
159     ByteArrayDataInput in = ByteStreams.newDataInput(bytes);
160     byte[] actual = new byte[bytes.length];
161     in.readFully(actual);
162     assertEquals(bytes, actual);
163   }
164 
testNewDataInput_readFullyAndThenSome()165   public void testNewDataInput_readFullyAndThenSome() {
166     ByteArrayDataInput in = ByteStreams.newDataInput(bytes);
167     byte[] actual = new byte[bytes.length * 2];
168     try {
169       in.readFully(actual);
170       fail("expected exception");
171     } catch (IllegalStateException ex) {
172       assertTrue(ex.getCause() instanceof EOFException);
173     }
174   }
175 
testNewDataInput_readFullyWithOffset()176   public void testNewDataInput_readFullyWithOffset() {
177     ByteArrayDataInput in = ByteStreams.newDataInput(bytes);
178     byte[] actual = new byte[4];
179     in.readFully(actual, 2, 2);
180     assertEquals(0, actual[0]);
181     assertEquals(0, actual[1]);
182     assertEquals(bytes[0], actual[2]);
183     assertEquals(bytes[1], actual[3]);
184   }
185 
testNewDataInput_readLine()186   public void testNewDataInput_readLine() throws UnsupportedEncodingException {
187     ByteArrayDataInput in = ByteStreams.newDataInput(
188         "This is a line\r\nThis too\rand this\nand also this".getBytes(Charsets.UTF_8.name()));
189     assertEquals("This is a line", in.readLine());
190     assertEquals("This too", in.readLine());
191     assertEquals("and this", in.readLine());
192     assertEquals("and also this", in.readLine());
193   }
194 
testNewDataInput_readFloat()195   public void testNewDataInput_readFloat() {
196     byte[] data = {0x12, 0x34, 0x56, 0x78, 0x76, 0x54, 0x32, 0x10};
197     ByteArrayDataInput in = ByteStreams.newDataInput(data);
198     assertEquals(Float.intBitsToFloat(0x12345678), in.readFloat(), 0.0);
199     assertEquals(Float.intBitsToFloat(0x76543210), in.readFloat(), 0.0);
200   }
201 
testNewDataInput_readDouble()202   public void testNewDataInput_readDouble() {
203     byte[] data = {0x12, 0x34, 0x56, 0x78, 0x76, 0x54, 0x32, 0x10};
204     ByteArrayDataInput in = ByteStreams.newDataInput(data);
205     assertEquals(Double.longBitsToDouble(0x1234567876543210L), in.readDouble(), 0.0);
206   }
207 
testNewDataInput_readUTF()208   public void testNewDataInput_readUTF() throws UnsupportedEncodingException {
209     byte[] data = new byte[17];
210     data[1] = 15;
211     System.arraycopy("Kilroy was here".getBytes(Charsets.UTF_8.name()), 0, data, 2, 15);
212     ByteArrayDataInput in = ByteStreams.newDataInput(data);
213     assertEquals("Kilroy was here", in.readUTF());
214   }
215 
testNewDataInput_readChar()216   public void testNewDataInput_readChar() throws UnsupportedEncodingException {
217     byte[] data = "qed".getBytes(Charsets.UTF_16BE.name());
218     ByteArrayDataInput in = ByteStreams.newDataInput(data);
219     assertEquals('q', in.readChar());
220     assertEquals('e', in.readChar());
221     assertEquals('d', in.readChar());
222   }
223 
testNewDataInput_readUnsignedShort()224   public void testNewDataInput_readUnsignedShort() {
225     byte[] data = {0, 0, 0, 1, (byte) 0xFF, (byte) 0xFF, 0x12, 0x34};
226     ByteArrayDataInput in = ByteStreams.newDataInput(data);
227     assertEquals(0, in.readUnsignedShort());
228     assertEquals(1, in.readUnsignedShort());
229     assertEquals(65535, in.readUnsignedShort());
230     assertEquals(0x1234, in.readUnsignedShort());
231   }
232 
testNewDataInput_readLong()233   public void testNewDataInput_readLong() {
234     byte[] data = {0x12, 0x34, 0x56, 0x78, 0x76, 0x54, 0x32, 0x10};
235     ByteArrayDataInput in = ByteStreams.newDataInput(data);
236     assertEquals(0x1234567876543210L, in.readLong());
237   }
238 
testNewDataInput_readBoolean()239   public void testNewDataInput_readBoolean() {
240     ByteArrayDataInput in = ByteStreams.newDataInput(bytes);
241     assertTrue(in.readBoolean());
242   }
243 
testNewDataInput_readByte()244   public void testNewDataInput_readByte() {
245     ByteArrayDataInput in = ByteStreams.newDataInput(bytes);
246     for (int i = 0; i < bytes.length; i++) {
247       assertEquals(bytes[i], in.readByte());
248     }
249     try {
250       in.readByte();
251       fail("expected exception");
252     } catch (IllegalStateException ex) {
253       assertTrue(ex.getCause() instanceof EOFException);
254     }
255   }
256 
testNewDataInput_readUnsignedByte()257   public void testNewDataInput_readUnsignedByte() {
258     ByteArrayDataInput in = ByteStreams.newDataInput(bytes);
259     for (int i = 0; i < bytes.length; i++) {
260       assertEquals(bytes[i], in.readUnsignedByte());
261     }
262     try {
263       in.readUnsignedByte();
264       fail("expected exception");
265     } catch (IllegalStateException ex) {
266       assertTrue(ex.getCause() instanceof EOFException);
267     }
268   }
269 
testNewDataInput_offset()270   public void testNewDataInput_offset() {
271     ByteArrayDataInput in = ByteStreams.newDataInput(bytes, 2);
272     assertEquals(0x56787654, in.readInt());
273     try {
274       in.readInt();
275       fail("expected exception");
276     } catch (IllegalStateException expected) {
277     }
278   }
279 
testNewDataInput_skip()280   public void testNewDataInput_skip() {
281     ByteArrayDataInput in = ByteStreams.newDataInput(new byte[2]);
282     assertEquals(2, in.skipBytes(2));
283     assertEquals(0, in.skipBytes(1));
284   }
285 
testNewDataInput_BAIS()286   public void testNewDataInput_BAIS() {
287     ByteArrayInputStream bais = new ByteArrayInputStream(new byte[] {0x12, 0x34, 0x56, 0x78});
288     ByteArrayDataInput in = ByteStreams.newDataInput(bais);
289     assertEquals(0x12345678, in.readInt());
290   }
291 
testNewDataOutput_empty()292   public void testNewDataOutput_empty() {
293     ByteArrayDataOutput out = ByteStreams.newDataOutput();
294     assertEquals(0, out.toByteArray().length);
295   }
296 
testNewDataOutput_writeInt()297   public void testNewDataOutput_writeInt() {
298     ByteArrayDataOutput out = ByteStreams.newDataOutput();
299     out.writeInt(0x12345678);
300     out.writeInt(0x76543210);
301     assertEquals(bytes, out.toByteArray());
302   }
303 
testNewDataOutput_sized()304   public void testNewDataOutput_sized() {
305     ByteArrayDataOutput out = ByteStreams.newDataOutput(4);
306     out.writeInt(0x12345678);
307     out.writeInt(0x76543210);
308     assertEquals(bytes, out.toByteArray());
309   }
310 
testNewDataOutput_writeLong()311   public void testNewDataOutput_writeLong() {
312     ByteArrayDataOutput out = ByteStreams.newDataOutput();
313     out.writeLong(0x1234567876543210L);
314     assertEquals(bytes, out.toByteArray());
315   }
316 
testNewDataOutput_writeByteArray()317   public void testNewDataOutput_writeByteArray() {
318     ByteArrayDataOutput out = ByteStreams.newDataOutput();
319     out.write(bytes);
320     assertEquals(bytes, out.toByteArray());
321   }
322 
testNewDataOutput_writeByte()323   public void testNewDataOutput_writeByte() {
324     ByteArrayDataOutput out = ByteStreams.newDataOutput();
325     out.write(0x12);
326     out.writeByte(0x34);
327     assertEquals(new byte[] {0x12, 0x34}, out.toByteArray());
328   }
329 
testNewDataOutput_writeByteOffset()330   public void testNewDataOutput_writeByteOffset() {
331     ByteArrayDataOutput out = ByteStreams.newDataOutput();
332     out.write(bytes, 4, 2);
333     byte[] expected = {bytes[4], bytes[5]};
334     assertEquals(expected, out.toByteArray());
335   }
336 
testNewDataOutput_writeBoolean()337   public void testNewDataOutput_writeBoolean() {
338     ByteArrayDataOutput out = ByteStreams.newDataOutput();
339     out.writeBoolean(true);
340     out.writeBoolean(false);
341     byte[] expected = {(byte) 1, (byte) 0};
342     assertEquals(expected, out.toByteArray());
343   }
344 
testNewDataOutput_writeChar()345   public void testNewDataOutput_writeChar() {
346     ByteArrayDataOutput out = ByteStreams.newDataOutput();
347     out.writeChar('a');
348     assertEquals(new byte[] {0, 97}, out.toByteArray());
349   }
350 
testNewDataOutput_writeChars()351   public void testNewDataOutput_writeChars() throws UnsupportedEncodingException {
352     ByteArrayDataOutput out = ByteStreams.newDataOutput();
353     out.writeChars("r\u00C9sum\u00C9");
354     // need to remove byte order mark before comparing
355     byte[] expected = Arrays.copyOfRange("r\u00C9sum\u00C9".getBytes(UTF_16.name()), 2, 14);
356     assertEquals(expected, out.toByteArray());
357   }
358 
testNewDataOutput_writeUTF()359   public void testNewDataOutput_writeUTF() throws UnsupportedEncodingException {
360     ByteArrayDataOutput out = ByteStreams.newDataOutput();
361     out.writeUTF("r\u00C9sum\u00C9");
362     byte[] expected ="r\u00C9sum\u00C9".getBytes(Charsets.UTF_8.name());
363     byte[] actual = out.toByteArray();
364     // writeUTF writes the length of the string in 2 bytes
365     assertEquals(0, actual[0]);
366     assertEquals(expected.length, actual[1]);
367     assertEquals(expected, Arrays.copyOfRange(actual, 2, actual.length));
368   }
369 
testNewDataOutput_writeShort()370   public void testNewDataOutput_writeShort() {
371     ByteArrayDataOutput out = ByteStreams.newDataOutput();
372     out.writeShort(0x1234);
373     assertEquals(new byte[] {0x12, 0x34}, out.toByteArray());
374   }
375 
testNewDataOutput_writeDouble()376   public void testNewDataOutput_writeDouble() {
377     ByteArrayDataOutput out = ByteStreams.newDataOutput();
378     out.writeDouble(Double.longBitsToDouble(0x1234567876543210L));
379     assertEquals(bytes, out.toByteArray());
380   }
381 
testNewDataOutput_writeFloat()382   public void testNewDataOutput_writeFloat() {
383     ByteArrayDataOutput out = ByteStreams.newDataOutput();
384     out.writeFloat(Float.intBitsToFloat(0x12345678));
385     out.writeFloat(Float.intBitsToFloat(0x76543210));
386     assertEquals(bytes, out.toByteArray());
387   }
388 
testChecksum()389   public void testChecksum() throws IOException {
390     InputSupplier<ByteArrayInputStream> asciiBytes =
391         ByteStreams.newInputStreamSupplier(ASCII.getBytes(Charsets.US_ASCII.name()));
392     InputSupplier<ByteArrayInputStream> i18nBytes =
393         ByteStreams.newInputStreamSupplier(I18N.getBytes(Charsets.UTF_8.name()));
394 
395     Checksum checksum = new CRC32();
396     assertEquals(0L, checksum.getValue());
397     assertEquals(3145994718L, ByteStreams.getChecksum(asciiBytes, checksum));
398     assertEquals(0L, checksum.getValue());
399     assertEquals(3145994718L, ByteStreams.getChecksum(asciiBytes, checksum));
400     assertEquals(1138302340L, ByteStreams.getChecksum(i18nBytes, checksum));
401     assertEquals(0L, checksum.getValue());
402   }
403 
testNewDataOutput_BAOS()404   public void testNewDataOutput_BAOS() {
405     ByteArrayOutputStream baos = new ByteArrayOutputStream();
406     ByteArrayDataOutput out = ByteStreams.newDataOutput(baos);
407     out.writeInt(0x12345678);
408     assertEquals(4, baos.size());
409     assertEquals(new byte[] {0x12, 0x34, 0x56, 0x78}, baos.toByteArray());
410   }
411 
testToByteArray_withSize_givenCorrectSize()412   public void testToByteArray_withSize_givenCorrectSize() throws IOException {
413     InputStream in = newTestStream(100);
414     byte[] b = ByteStreams.toByteArray(in, 100);
415     assertEquals(100, b.length);
416   }
417 
testToByteArray_withSize_givenSmallerSize()418   public void testToByteArray_withSize_givenSmallerSize() throws IOException {
419     InputStream in = newTestStream(100);
420     byte[] b = ByteStreams.toByteArray(in, 80);
421     assertEquals(100, b.length);
422   }
423 
testToByteArray_withSize_givenLargerSize()424   public void testToByteArray_withSize_givenLargerSize() throws IOException {
425     InputStream in = newTestStream(100);
426     byte[] b = ByteStreams.toByteArray(in, 120);
427     assertEquals(100, b.length);
428   }
429 
testToByteArray_withSize_givenSizeZero()430   public void testToByteArray_withSize_givenSizeZero() throws IOException {
431     InputStream in = newTestStream(100);
432     byte[] b = ByteStreams.toByteArray(in, 0);
433     assertEquals(100, b.length);
434   }
435 
newTestStream(int n)436   private static InputStream newTestStream(int n) {
437     return new ByteArrayInputStream(newPreFilledByteArray(n));
438   }
439 
440   /** Stream that will skip a maximum number of bytes at a time. */
441   private static class SlowSkipper extends FilterInputStream {
442     private final long max;
443 
SlowSkipper(InputStream in, long max)444     public SlowSkipper(InputStream in, long max) {
445       super(in);
446       this.max = max;
447     }
448 
skip(long n)449     @Override public long skip(long n) throws IOException {
450       return super.skip(Math.min(max, n));
451     }
452   }
453 
testReadBytes()454   public void testReadBytes() throws IOException {
455     final byte[] array = newPreFilledByteArray(1000);
456     assertEquals(array, ByteStreams.readBytes(
457       new ByteArrayInputStream(array), new TestByteProcessor()));
458   }
459 
460   private class TestByteProcessor implements ByteProcessor<byte[]> {
461     private final ByteArrayOutputStream out = new ByteArrayOutputStream();
462 
463     @Override
processBytes(byte[] buf, int off, int len)464     public boolean processBytes(byte[] buf, int off, int len)
465         throws IOException {
466       out.write(buf, off, len);
467       return true;
468     }
469 
470     @Override
getResult()471     public byte[] getResult() {
472       return out.toByteArray();
473     }
474   }
475 
testByteProcessorStopEarly()476   public void testByteProcessorStopEarly() throws IOException {
477     byte[] array = newPreFilledByteArray(6000);
478     assertEquals((Integer) 42,
479         ByteStreams.readBytes(new ByteArrayInputStream(array),
480             new ByteProcessor<Integer>() {
481               @Override
482               public boolean processBytes(byte[] buf, int off, int len) {
483                 assertEquals(
484                     copyOfRange(buf, off, off + len),
485                     newPreFilledByteArray(4096));
486                 return false;
487               }
488 
489               @Override
490               public Integer getResult() {
491                 return 42;
492               }
493             }));
494   }
495 
testNullOutputStream()496   public void testNullOutputStream() throws Exception {
497     // create a null output stream
498     OutputStream nos = ByteStreams.nullOutputStream();
499     // write to the output stream
500     nos.write('n');
501     String test = "Test string for NullOutputStream";
502     nos.write(test.getBytes());
503     nos.write(test.getBytes(), 2, 10);
504     // nothing really to assert?
505     assertSame(ByteStreams.nullOutputStream(), ByteStreams.nullOutputStream());
506   }
507 
testLimit()508   public void testLimit() throws Exception {
509     byte[] big = newPreFilledByteArray(5);
510     InputStream bin = new ByteArrayInputStream(big);
511     InputStream lin = ByteStreams.limit(bin, 2);
512 
513     // also test available
514     lin.mark(2);
515     assertEquals(2, lin.available());
516     int read = lin.read();
517     assertEquals(big[0], read);
518     assertEquals(1, lin.available());
519     read = lin.read();
520     assertEquals(big[1], read);
521     assertEquals(0, lin.available());
522     read = lin.read();
523     assertEquals(-1, read);
524 
525     lin.reset();
526     byte[] small = new byte[5];
527     read = lin.read(small);
528     assertEquals(2, read);
529     assertEquals(big[0], small[0]);
530     assertEquals(big[1], small[1]);
531 
532     lin.reset();
533     read = lin.read(small, 2, 3);
534     assertEquals(2, read);
535     assertEquals(big[0], small[2]);
536     assertEquals(big[1], small[3]);
537   }
538 
testLimit_mark()539   public void testLimit_mark() throws Exception {
540     byte[] big = newPreFilledByteArray(5);
541     InputStream bin = new ByteArrayInputStream(big);
542     InputStream lin = ByteStreams.limit(bin, 2);
543 
544     int read = lin.read();
545     assertEquals(big[0], read);
546     lin.mark(2);
547 
548     read = lin.read();
549     assertEquals(big[1], read);
550     read = lin.read();
551     assertEquals(-1, read);
552 
553     lin.reset();
554     read = lin.read();
555     assertEquals(big[1], read);
556     read = lin.read();
557     assertEquals(-1, read);
558   }
559 
testLimit_skip()560   public void testLimit_skip() throws Exception {
561     byte[] big = newPreFilledByteArray(5);
562     InputStream bin = new ByteArrayInputStream(big);
563     InputStream lin = ByteStreams.limit(bin, 2);
564 
565     // also test available
566     lin.mark(2);
567     assertEquals(2, lin.available());
568     lin.skip(1);
569     assertEquals(1, lin.available());
570 
571     lin.reset();
572     assertEquals(2, lin.available());
573     lin.skip(3);
574     assertEquals(0, lin.available());
575   }
576 
testLimit_markNotSet()577   public void testLimit_markNotSet() {
578     byte[] big = newPreFilledByteArray(5);
579     InputStream bin = new ByteArrayInputStream(big);
580     InputStream lin = ByteStreams.limit(bin, 2);
581 
582     try {
583       lin.reset();
584       fail();
585     } catch (IOException expected) {
586       assertEquals("Mark not set", expected.getMessage());
587     }
588   }
589 
testLimit_markNotSupported()590   public void testLimit_markNotSupported() {
591     InputStream lin = ByteStreams.limit(new UnmarkableInputStream(), 2);
592 
593     try {
594       lin.reset();
595       fail();
596     } catch (IOException expected) {
597       assertEquals("Mark not supported", expected.getMessage());
598     }
599   }
600 
601   private static class UnmarkableInputStream extends InputStream {
602     @Override
read()603     public int read() throws IOException {
604       return 0;
605     }
606 
607     @Override
markSupported()608     public boolean markSupported() {
609       return false;
610     }
611   }
612 
copyOfRange(byte[] in, int from, int to)613   private static byte[] copyOfRange(byte[] in, int from, int to) {
614     byte[] out = new byte[to - from];
615     for (int i = 0; i < to - from; i++) {
616       out[i] = in[from + i];
617     }
618     return out;
619   }
620 
assertEquals(byte[] expected, byte[] actual)621   private static void assertEquals(byte[] expected, byte[] actual) {
622     assertTrue(Arrays.equals(expected, actual));
623   }
624 }
625