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