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