• 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.io.ByteStreams.copy;
20 import static com.google.common.io.ByteStreams.newInputStreamSupplier;
21 
22 import com.google.common.base.Charsets;
23 import com.google.common.base.Preconditions;
24 import com.google.common.collect.ImmutableSet;
25 import com.google.common.primitives.Bytes;
26 import com.google.common.testing.TestLogHandler;
27 
28 import java.io.ByteArrayInputStream;
29 import java.io.ByteArrayOutputStream;
30 import java.io.EOFException;
31 import java.io.FilterInputStream;
32 import java.io.FilterOutputStream;
33 import java.io.IOException;
34 import java.io.InputStream;
35 import java.io.OutputStream;
36 import java.nio.channels.Channels;
37 import java.nio.channels.ReadableByteChannel;
38 import java.nio.channels.WritableByteChannel;
39 import java.util.Arrays;
40 import java.util.Random;
41 
42 /**
43  * Unit test for {@link ByteStreams}.
44  *
45  * @author Chris Nokleberg
46  */
47 public class ByteStreamsTest extends IoTestCase {
48 
49   /** Provides an InputStream that throws an IOException on every read. */
50   static final InputSupplier<InputStream> BROKEN_READ
51       = new InputSupplier<InputStream>() {
52         @Override
53         public InputStream getInput() {
54           return new InputStream() {
55             @Override public int read() throws IOException {
56               throw new IOException("broken read");
57             }
58           };
59         }
60       };
61 
62   /** Provides an OutputStream that throws an IOException on every write. */
63   static final OutputSupplier<OutputStream> BROKEN_WRITE
64       = new OutputSupplier<OutputStream>() {
65         @Override
66         public OutputStream getOutput() {
67           return new OutputStream() {
68             @Override public void write(int b) throws IOException {
69               throw new IOException("broken write");
70             }
71           };
72         }
73       };
74 
75   /** Provides an InputStream that throws an IOException on close. */
76   static final InputSupplier<InputStream> BROKEN_CLOSE_INPUT =
77       new InputSupplier<InputStream>() {
78         @Override
79         public InputStream getInput() {
80           return new FilterInputStream(new ByteArrayInputStream(new byte[10])) {
81             @Override public void close() throws IOException {
82               throw new IOException("broken close input");
83             }
84           };
85         }
86       };
87 
88   /** Provides an OutputStream that throws an IOException on every close. */
89   static final OutputSupplier<OutputStream> BROKEN_CLOSE_OUTPUT =
90       new OutputSupplier<OutputStream>() {
91         @Override
92         public OutputStream getOutput() {
93           return new FilterOutputStream(new ByteArrayOutputStream()) {
94             @Override public void close() throws IOException {
95               throw new IOException("broken close output");
96             }
97           };
98         }
99       };
100 
101   /** Throws an IOException from getInput. */
102   static final InputSupplier<InputStream> BROKEN_GET_INPUT =
103       new InputSupplier<InputStream>() {
104         @Override
105         public InputStream getInput() throws IOException {
106           throw new IOException("broken get input");
107         }
108       };
109 
110   /** Throws an IOException from getOutput. */
111   static final OutputSupplier<OutputStream> BROKEN_GET_OUTPUT =
112       new OutputSupplier<OutputStream>() {
113         @Override
114         public OutputStream getOutput() throws IOException {
115           throw new IOException("broken get output");
116         }
117       };
118 
119   private static final ImmutableSet<InputSupplier<InputStream>> BROKEN_INPUTS =
120       ImmutableSet.of(BROKEN_CLOSE_INPUT, BROKEN_GET_INPUT, BROKEN_READ);
121   private static final ImmutableSet<OutputSupplier<OutputStream>> BROKEN_OUTPUTS
122       = ImmutableSet.of(BROKEN_CLOSE_OUTPUT, BROKEN_GET_OUTPUT, BROKEN_WRITE);
123 
testByteSuppliers()124   public void testByteSuppliers() throws IOException {
125     byte[] range = newPreFilledByteArray(200);
126     assertTrue(Arrays.equals(range,
127         ByteStreams.toByteArray(ByteStreams.newInputStreamSupplier(range))));
128 
129     byte[] subRange = ByteStreams.toByteArray(
130         ByteStreams.newInputStreamSupplier(range, 100, 50));
131     assertEquals(50, subRange.length);
132     assertEquals(100, subRange[0]);
133     assertEquals((byte) 149, subRange[subRange.length - 1]);
134   }
135 
testEqual()136   public void testEqual() throws IOException {
137     equalHelper(false, 0, 1);
138     equalHelper(false, 400, 10000);
139     equalHelper(false, 0x2000, 0x2001);
140     equalHelper(false, new byte[]{ 0 }, new byte[]{ 1 });
141 
142     byte[] mutate = newPreFilledByteArray(10000);
143     mutate[9000] = 0;
144     equalHelper(false, mutate, newPreFilledByteArray(10000));
145 
146     equalHelper(true, 0, 0);
147     equalHelper(true, 1, 1);
148     equalHelper(true, 400, 400);
149 
150     final byte[] tenK = newPreFilledByteArray(10000);
151     equalHelper(true, tenK, tenK);
152     assertTrue(ByteStreams.equal(ByteStreams.newInputStreamSupplier(tenK),
153         new InputSupplier<InputStream>() {
154           @Override
155           public InputStream getInput() {
156             return new RandomAmountInputStream(new ByteArrayInputStream(tenK),
157                 new Random(301));
158           }
159         }));
160   }
161 
equalHelper(boolean expect, int size1, int size2)162   private void equalHelper(boolean expect, int size1, int size2)
163       throws IOException {
164     equalHelper(expect, newPreFilledByteArray(size1),
165         newPreFilledByteArray(size2));
166   }
167 
equalHelper(boolean expect, byte[] a, byte[] b)168   private void equalHelper(boolean expect, byte[] a, byte[] b)
169       throws IOException {
170     assertEquals(expect, ByteStreams.equal(
171         ByteStreams.newInputStreamSupplier(a),
172         ByteStreams.newInputStreamSupplier(b)));
173   }
174 
testAlwaysCloses()175   public void testAlwaysCloses() throws IOException {
176     byte[] range = newPreFilledByteArray(100);
177     CheckCloseSupplier.Input<InputStream> okRead
178         = newCheckInput(ByteStreams.newInputStreamSupplier(range));
179     CheckCloseSupplier.Output<OutputStream> okWrite
180         = newCheckOutput(new OutputSupplier<OutputStream>() {
181           @Override
182           public OutputStream getOutput() {
183             return new ByteArrayOutputStream();
184           }
185         });
186 
187     CheckCloseSupplier.Input<InputStream> brokenRead
188         = newCheckInput(BROKEN_READ);
189     CheckCloseSupplier.Output<OutputStream> brokenWrite
190         = newCheckOutput(BROKEN_WRITE);
191 
192     // copy, both suppliers
193     ByteStreams.copy(okRead, okWrite);
194     assertTrue(okRead.areClosed());
195     assertTrue(okWrite.areClosed());
196 
197     try {
198       ByteStreams.copy(okRead, brokenWrite);
199       fail("expected exception");
200     } catch (IOException e) {
201       assertEquals("broken write", e.getMessage());
202     }
203     assertTrue(okRead.areClosed());
204     assertTrue(brokenWrite.areClosed());
205 
206     try {
207       ByteStreams.copy(brokenRead, okWrite);
208       fail("expected exception");
209     } catch (IOException e) {
210       assertEquals("broken read", e.getMessage());
211     }
212     assertTrue(brokenRead.areClosed());
213     assertTrue(okWrite.areClosed());
214 
215     try {
216       ByteStreams.copy(brokenRead, brokenWrite);
217       fail("expected exception");
218     } catch (IOException e) {
219       assertEquals("broken read", e.getMessage());
220     }
221     assertTrue(brokenRead.areClosed());
222     assertTrue(brokenWrite.areClosed());
223 
224     // copy, input supplier
225     OutputStream out = okWrite.getOutput();
226     ByteStreams.copy(okRead, out);
227     assertTrue(okRead.areClosed());
228     assertFalse(okWrite.areClosed());
229     out.close();
230 
231     out = brokenWrite.getOutput();
232     try {
233       ByteStreams.copy(okRead, out);
234       fail("expected exception");
235     } catch (IOException e) {
236       assertEquals("broken write", e.getMessage());
237     }
238     assertTrue(okRead.areClosed());
239     assertFalse(brokenWrite.areClosed());
240     out.close();
241 
242     out = okWrite.getOutput();
243     try {
244       ByteStreams.copy(brokenRead, out);
245       fail("expected exception");
246     } catch (IOException e) {
247       assertEquals("broken read", e.getMessage());
248     }
249     assertTrue(brokenRead.areClosed());
250     assertFalse(okWrite.areClosed());
251     out.close();
252 
253     out = brokenWrite.getOutput();
254     try {
255       ByteStreams.copy(brokenRead, out);
256       fail("expected exception");
257     } catch (IOException e) {
258       assertEquals("broken read", e.getMessage());
259     }
260     assertTrue(brokenRead.areClosed());
261     assertFalse(brokenWrite.areClosed());
262     out.close();
263 
264     // copy, output supplier
265     InputStream in = okRead.getInput();
266     ByteStreams.copy(in, okWrite);
267     assertFalse(okRead.areClosed());
268     assertTrue(okWrite.areClosed());
269     in.close();
270 
271     in = okRead.getInput();
272     try {
273       ByteStreams.copy(in, brokenWrite);
274       fail("expected exception");
275     } catch (IOException e) {
276       assertEquals("broken write", e.getMessage());
277     }
278     assertFalse(okRead.areClosed());
279     assertTrue(brokenWrite.areClosed());
280     in.close();
281 
282     in = brokenRead.getInput();
283     try {
284       ByteStreams.copy(in, okWrite);
285       fail("expected exception");
286     } catch (IOException e) {
287       assertEquals("broken read", e.getMessage());
288     }
289     assertFalse(brokenRead.areClosed());
290     assertTrue(okWrite.areClosed());
291     in.close();
292 
293     in = brokenRead.getInput();
294     try {
295       ByteStreams.copy(in, brokenWrite);
296       fail("expected exception");
297     } catch (IOException e) {
298       assertEquals("broken read", e.getMessage());
299     }
300     assertFalse(brokenRead.areClosed());
301     assertTrue(brokenWrite.areClosed());
302     in.close();
303 
304     // toByteArray
305     assertTrue(Arrays.equals(range, ByteStreams.toByteArray(okRead)));
306     assertTrue(okRead.areClosed());
307 
308     try {
309       ByteStreams.toByteArray(brokenRead);
310       fail("expected exception");
311     } catch (IOException e) {
312       assertEquals("broken read", e.getMessage());
313     }
314     assertTrue(brokenRead.areClosed());
315 
316     // equal
317     try {
318       ByteStreams.equal(brokenRead, okRead);
319       fail("expected exception");
320     } catch (IOException e) {
321       assertEquals("broken read", e.getMessage());
322     }
323     assertTrue(brokenRead.areClosed());
324 
325     try {
326       ByteStreams.equal(okRead, brokenRead);
327       fail("expected exception");
328     } catch (IOException e) {
329       assertEquals("broken read", e.getMessage());
330     }
331     assertTrue(brokenRead.areClosed());
332 
333     // write
334     try {
335       ByteStreams.write(new byte[10], brokenWrite);
336       fail("expected exception");
337     } catch (IOException e) {
338       assertEquals("broken write", e.getMessage());
339     }
340     assertTrue(brokenWrite.areClosed());
341   }
342 
getAndResetRecords(TestLogHandler logHandler)343   private static int getAndResetRecords(TestLogHandler logHandler) {
344     int records = logHandler.getStoredLogRecords().size();
345     logHandler.clear();
346     return records;
347   }
348 
runFailureTest( InputSupplier<? extends InputStream> in, OutputSupplier<OutputStream> out)349   private static void runFailureTest(
350       InputSupplier<? extends InputStream> in, OutputSupplier<OutputStream> out) {
351     try {
352       copy(in, out);
353       fail();
354     } catch (IOException expected) {
355     }
356   }
357 
newByteArrayOutputStreamSupplier()358   private static OutputSupplier<OutputStream> newByteArrayOutputStreamSupplier() {
359     return new OutputSupplier<OutputStream>() {
360       @Override public OutputStream getOutput() {
361         return new ByteArrayOutputStream();
362       }
363     };
364   }
365 
366   public void testWriteBytes() throws IOException {
367     final ByteArrayOutputStream out = new ByteArrayOutputStream();
368     byte[] expected = newPreFilledByteArray(100);
369     ByteStreams.write(expected, new OutputSupplier<OutputStream>() {
370       @Override public OutputStream getOutput() {
371         return out;
372       }
373     });
374     assertTrue(Arrays.equals(expected, out.toByteArray()));
375   }
376 
377   public void testCopy() throws Exception {
378     ByteArrayOutputStream out = new ByteArrayOutputStream();
379     byte[] expected = newPreFilledByteArray(100);
380     long num = ByteStreams.copy(new ByteArrayInputStream(expected), out);
381     assertEquals(100, num);
382     assertTrue(Arrays.equals(expected, out.toByteArray()));
383   }
384 
385   public void testCopyChannel() throws IOException {
386     byte[] expected = newPreFilledByteArray(100);
387     ByteArrayOutputStream out = new ByteArrayOutputStream();
388     WritableByteChannel outChannel = Channels.newChannel(out);
389 
390     ReadableByteChannel inChannel =
391         Channels.newChannel(new ByteArrayInputStream(expected));
392     ByteStreams.copy(inChannel, outChannel);
393     assertTrue(Arrays.equals(expected, out.toByteArray()));
394   }
395 
396   public void testReadFully() throws IOException {
397     byte[] b = new byte[10];
398 
399     try {
400       ByteStreams.readFully(newTestStream(10), null, 0, 10);
401       fail("expected exception");
402     } catch (NullPointerException e) {
403     }
404 
405     try {
406       ByteStreams.readFully(null, b, 0, 10);
407       fail("expected exception");
408     } catch (NullPointerException e) {
409     }
410 
411     try {
412       ByteStreams.readFully(newTestStream(10), b, -1, 10);
413       fail("expected exception");
414     } catch (IndexOutOfBoundsException e) {
415     }
416 
417     try {
418       ByteStreams.readFully(newTestStream(10), b, 0, -1);
419       fail("expected exception");
420     } catch (IndexOutOfBoundsException e) {
421     }
422 
423     try {
424       ByteStreams.readFully(newTestStream(10), b, 0, -1);
425       fail("expected exception");
426     } catch (IndexOutOfBoundsException e) {
427     }
428 
429     try {
430       ByteStreams.readFully(newTestStream(10), b, 2, 10);
431       fail("expected exception");
432     } catch (IndexOutOfBoundsException e) {
433     }
434 
435     try {
436       ByteStreams.readFully(newTestStream(5), b, 0, 10);
437       fail("expected exception");
438     } catch (EOFException e) {
439     }
440 
441     Arrays.fill(b, (byte) 0);
442     ByteStreams.readFully(newTestStream(10), b, 0, 0);
443     assertTrue(Arrays.equals(new byte[10], b));
444 
445     Arrays.fill(b, (byte) 0);
446     ByteStreams.readFully(newTestStream(10), b, 0, 10);
447     assertTrue(Arrays.equals(newPreFilledByteArray(10), b));
448 
449     Arrays.fill(b, (byte) 0);
450     ByteStreams.readFully(newTestStream(10), b, 0, 5);
451     assertTrue(Arrays.equals(new byte[]{0, 1, 2, 3, 4, 0, 0, 0, 0, 0}, b));
452   }
453 
454   public void testSkipFully() throws IOException {
455     byte[] bytes = newPreFilledByteArray(100);
456     skipHelper(0, 0, new ByteArrayInputStream(bytes));
457     skipHelper(50, 50, new ByteArrayInputStream(bytes));
458     skipHelper(50, 50, new SlowSkipper(new ByteArrayInputStream(bytes), 1));
459     skipHelper(50, 50, new SlowSkipper(new ByteArrayInputStream(bytes), 0));
460     skipHelper(100, -1, new ByteArrayInputStream(bytes));
461     try {
462       skipHelper(101, 0, new ByteArrayInputStream(bytes));
463       fail("expected exception");
464     } catch (EOFException e) {
465     }
466   }
467 
468   private void skipHelper(long n, int expect, InputStream in)
469       throws IOException {
470     ByteStreams.skipFully(in, n);
471     assertEquals(expect, in.read());
472     in.close();
473   }
474 
475   // TODO(user): rename; violates rule that only immutable things can be all caps
476   private static final byte[] BYTES = new byte[] {
477       0x12, 0x34, 0x56, 0x78, 0x76, 0x54, 0x32, 0x10 };
478 
479   public void testNewDataInput_empty() {
480     byte[] b = new byte[0];
481     ByteArrayDataInput in = ByteStreams.newDataInput(b);
482     try {
483       in.readInt();
484       fail();
485     } catch (IllegalStateException expected) {
486     }
487   }
488 
489   public void testNewDataInput_normal() {
490     ByteArrayDataInput in = ByteStreams.newDataInput(BYTES);
491     assertEquals(0x12345678, in.readInt());
492     assertEquals(0x76543210, in.readInt());
493     try {
494       in.readInt();
495       fail();
496     } catch (IllegalStateException expected) {
497     }
498   }
499 
500   public void testNewDataInput_readFully() {
501     ByteArrayDataInput in = ByteStreams.newDataInput(BYTES);
502     byte[] actual = new byte[BYTES.length];
503     in.readFully(actual);
504     assertEquals(BYTES, actual);
505   }
506 
507   public void testNewDataInput_readFullyAndThenSome() {
508     ByteArrayDataInput in = ByteStreams.newDataInput(BYTES);
509     byte[] actual = new byte[BYTES.length * 2];
510     try {
511       in.readFully(actual);
512       fail();
513     } catch (IllegalStateException ex) {
514       assertTrue(ex.getCause() instanceof EOFException);
515     }
516   }
517 
518   public void testNewDataInput_readFullyWithOffset() {
519     ByteArrayDataInput in = ByteStreams.newDataInput(BYTES);
520     byte[] actual = new byte[4];
521     in.readFully(actual, 2, 2);
522     assertEquals(0, actual[0]);
523     assertEquals(0, actual[1]);
524     assertEquals(BYTES[0], actual[2]);
525     assertEquals(BYTES[1], actual[3]);
526   }
527 
528   public void testNewDataInput_readLine() {
529     ByteArrayDataInput in = ByteStreams.newDataInput(
530         "This is a line\r\nThis too\rand this\nand also this".getBytes(Charsets.UTF_8));
531     assertEquals("This is a line", in.readLine());
532     assertEquals("This too", in.readLine());
533     assertEquals("and this", in.readLine());
534     assertEquals("and also this", in.readLine());
535   }
536 
537   public void testNewDataInput_readFloat() {
538     byte[] data = {0x12, 0x34, 0x56, 0x78, 0x76, 0x54, 0x32, 0x10};
539     ByteArrayDataInput in = ByteStreams.newDataInput(data);
540     assertEquals(Float.intBitsToFloat(0x12345678), in.readFloat(), 0.0);
541     assertEquals(Float.intBitsToFloat(0x76543210), in.readFloat(), 0.0);
542   }
543 
544   public void testNewDataInput_readDouble() {
545     byte[] data = {0x12, 0x34, 0x56, 0x78, 0x76, 0x54, 0x32, 0x10};
546     ByteArrayDataInput in = ByteStreams.newDataInput(data);
547     assertEquals(Double.longBitsToDouble(0x1234567876543210L), in.readDouble(), 0.0);
548   }
549 
550   public void testNewDataInput_readUTF() {
551     byte[] data = new byte[17];
552     data[1] = 15;
553     System.arraycopy("Kilroy was here".getBytes(Charsets.UTF_8), 0, data, 2, 15);
554     ByteArrayDataInput in = ByteStreams.newDataInput(data);
555     assertEquals("Kilroy was here", in.readUTF());
556   }
557 
558   public void testNewDataInput_readChar() {
559     byte[] data = "qed".getBytes(Charsets.UTF_16BE);
560     ByteArrayDataInput in = ByteStreams.newDataInput(data);
561     assertEquals('q', in.readChar());
562     assertEquals('e', in.readChar());
563     assertEquals('d', in.readChar());
564   }
565 
566   public void testNewDataInput_readUnsignedShort() {
567     byte[] data = {0, 0, 0, 1, (byte) 0xFF, (byte) 0xFF, 0x12, 0x34};
568     ByteArrayDataInput in = ByteStreams.newDataInput(data);
569     assertEquals(0, in.readUnsignedShort());
570     assertEquals(1, in.readUnsignedShort());
571     assertEquals(65535, in.readUnsignedShort());
572     assertEquals(0x1234, in.readUnsignedShort());
573   }
574 
575   public void testNewDataInput_readLong() {
576     byte[] data = {0x12, 0x34, 0x56, 0x78, 0x76, 0x54, 0x32, 0x10};
577     ByteArrayDataInput in = ByteStreams.newDataInput(data);
578     assertEquals(0x1234567876543210L, in.readLong());
579   }
580 
581   public void testNewDataInput_readBoolean() {
582     ByteArrayDataInput in = ByteStreams.newDataInput(BYTES);
583     assertTrue(in.readBoolean());
584   }
585 
586   public void testNewDataInput_readByte() {
587     ByteArrayDataInput in = ByteStreams.newDataInput(BYTES);
588     for (int i = 0; i < BYTES.length; i++) {
589       assertEquals(BYTES[i], in.readByte());
590     }
591     try {
592       in.readByte();
593       fail();
594     } catch (IllegalStateException ex) {
595       assertTrue(ex.getCause() instanceof EOFException);
596     }
597   }
598 
599   public void testNewDataInput_readUnsignedByte() {
600     ByteArrayDataInput in = ByteStreams.newDataInput(BYTES);
601     for (int i = 0; i < BYTES.length; i++) {
602       assertEquals(BYTES[i], in.readUnsignedByte());
603     }
604     try {
605       in.readUnsignedByte();
606       fail();
607     } catch (IllegalStateException ex) {
608       assertTrue(ex.getCause() instanceof EOFException);
609     }
610   }
611 
612   public void testNewDataInput_offset() {
613     ByteArrayDataInput in = ByteStreams.newDataInput(BYTES, 2);
614     assertEquals(0x56787654, in.readInt());
615     try {
616       in.readInt();
617       fail();
618     } catch (IllegalStateException expected) {
619     }
620   }
621 
622   public void testNewDataInput_skip() {
623     ByteArrayDataInput in = ByteStreams.newDataInput(new byte[2]);
624     in.skipBytes(2);
625     try {
626       in.skipBytes(1);
627     } catch (IllegalStateException expected) {
628     }
629   }
630 
631   public void testNewDataOutput_empty() {
632     ByteArrayDataOutput out = ByteStreams.newDataOutput();
633     assertEquals(0, out.toByteArray().length);
634   }
635 
636   public void testNewDataOutput_writeInt() {
637     ByteArrayDataOutput out = ByteStreams.newDataOutput();
638     out.writeInt(0x12345678);
639     out.writeInt(0x76543210);
640     assertTrue(Arrays.equals(BYTES, out.toByteArray()));
641   }
642 
643   public void testNewDataOutput_sized() {
644     ByteArrayDataOutput out = ByteStreams.newDataOutput(4);
645     out.writeInt(0x12345678);
646     out.writeInt(0x76543210);
647     assertTrue(Arrays.equals(BYTES, out.toByteArray()));
648   }
649 
650   public void testNewDataOutput_writeLong() {
651     ByteArrayDataOutput out = ByteStreams.newDataOutput();
652     out.writeLong(0x1234567876543210L);
653     assertTrue(Arrays.equals(BYTES, out.toByteArray()));
654   }
655 
656   public void testNewDataOutput_writeByteArray() {
657     ByteArrayDataOutput out = ByteStreams.newDataOutput();
658     out.write(BYTES);
659     assertTrue(Arrays.equals(BYTES, out.toByteArray()));
660   }
661 
662   public void testNewDataOutput_writeByte() {
663     ByteArrayDataOutput out = ByteStreams.newDataOutput();
664     out.write(0x12);
665     out.writeByte(0x34);
666     assertTrue(Arrays.equals(new byte[] {0x12, 0x34}, out.toByteArray()));
667   }
668 
669   public void testNewDataOutput_writeByteOffset() {
670     ByteArrayDataOutput out = ByteStreams.newDataOutput();
671     out.write(BYTES, 4, 2);
672     byte[] expected = {BYTES[4], BYTES[5]};
673     assertEquals(expected, out.toByteArray());
674   }
675 
676   public void testNewDataOutput_writeBoolean() {
677     ByteArrayDataOutput out = ByteStreams.newDataOutput();
678     out.writeBoolean(true);
679     out.writeBoolean(false);
680     byte[] expected = {(byte) 1, (byte) 0};
681     assertEquals(expected, out.toByteArray());
682   }
683 
684   public void testNewDataOutput_writeChar() {
685     ByteArrayDataOutput out = ByteStreams.newDataOutput();
686     out.writeChar('a');
687     assertTrue(Arrays.equals(new byte[] {0, 97}, out.toByteArray()));
688   }
689 
690   public void testNewDataOutput_writeChars() {
691     ByteArrayDataOutput out = ByteStreams.newDataOutput();
692     out.writeChars("r\u00C9sum\u00C9");
693     // need to remove byte order mark before comparing
694     byte[] expected = Arrays.copyOfRange("r\u00C9sum\u00C9".getBytes(Charsets.UTF_16), 2, 14);
695     assertEquals(expected, out.toByteArray());
696   }
697 
698   public void testNewDataOutput_writeUTF() {
699     ByteArrayDataOutput out = ByteStreams.newDataOutput();
700     out.writeUTF("r\u00C9sum\u00C9");
701     byte[] expected ="r\u00C9sum\u00C9".getBytes(Charsets.UTF_8);
702     byte[] actual = out.toByteArray();
703     // writeUTF writes the length of the string in 2 bytes
704     assertEquals(0, actual[0]);
705     assertEquals(expected.length, actual[1]);
706     assertEquals(expected, Arrays.copyOfRange(actual, 2, actual.length));
707   }
708 
709   public void testNewDataOutput_writeShort() {
710     ByteArrayDataOutput out = ByteStreams.newDataOutput();
711     out.writeShort(0x1234);
712     assertTrue(Arrays.equals(new byte[] {0x12, 0x34}, out.toByteArray()));
713   }
714 
715   public void testNewDataOutput_writeDouble() {
716     ByteArrayDataOutput out = ByteStreams.newDataOutput();
717     out.writeDouble(Double.longBitsToDouble(0x1234567876543210L));
718     assertEquals(BYTES, out.toByteArray());
719   }
720 
721   public void testNewDataOutput_writeFloat() {
722     ByteArrayDataOutput out = ByteStreams.newDataOutput();
723     out.writeFloat(Float.intBitsToFloat(0x12345678));
724     out.writeFloat(Float.intBitsToFloat(0x76543210));
725     assertEquals(BYTES, out.toByteArray());
726   }
727 
728   public void testLength() throws IOException {
729     lengthHelper(Long.MAX_VALUE);
730     lengthHelper(7);
731     lengthHelper(1);
732     lengthHelper(0);
733 
734     assertEquals(0, ByteStreams.length(
735         ByteStreams.newInputStreamSupplier(new byte[0])));
736   }
737 
738   private void lengthHelper(final long skipLimit) throws IOException {
739     assertEquals(100, ByteStreams.length(new InputSupplier<InputStream>() {
740       @Override
741       public InputStream getInput() {
742         return new SlowSkipper(new ByteArrayInputStream(new byte[100]),
743             skipLimit);
744       }
745     }));
746   }
747 
748   public void testSlice() throws IOException {
749     // Test preconditions
750     InputSupplier<? extends InputStream> supplier
751         = ByteStreams.newInputStreamSupplier(newPreFilledByteArray(100));
752     try {
753       ByteStreams.slice(supplier, -1, 10);
754       fail("expected exception");
755     } catch (IllegalArgumentException expected) {
756     }
757 
758     try {
759       ByteStreams.slice(supplier, 0, -1);
760       fail("expected exception");
761     } catch (IllegalArgumentException expected) {
762     }
763 
764     try {
765       ByteStreams.slice(null, 0, 10);
766       fail("expected exception");
767     } catch (NullPointerException expected) {
768     }
769 
770     sliceHelper(0, 0, 0, 0);
771     sliceHelper(0, 0, 1, 0);
772     sliceHelper(100, 0, 10, 10);
773     sliceHelper(100, 0, 100, 100);
774     sliceHelper(100, 5, 10, 10);
775     sliceHelper(100, 5, 100, 95);
776     sliceHelper(100, 100, 0, 0);
777     sliceHelper(100, 100, 10, 0);
778 
779     try {
780       sliceHelper(100, 101, 10, 0);
781       fail("expected exception");
782     } catch (EOFException expected) {
783     }
784   }
785 
786   /**
787    * @param input the size of the input stream
788    * @param offset the first argument to {@link ByteStreams#slice}
789    * @param length the second argument to {@link ByteStreams#slice}
790    * @param expectRead the number of bytes we expect to read
791    */
792   private static void sliceHelper(
793       int input, int offset, long length, int expectRead) throws IOException {
794     Preconditions.checkArgument(expectRead == (int)
795         Math.max(0, Math.min(input, offset + length) - offset));
796     InputSupplier<? extends InputStream> supplier
797         = ByteStreams.newInputStreamSupplier(newPreFilledByteArray(input));
798     assertTrue(Arrays.equals(
799         newPreFilledByteArray(offset, expectRead),
800         ByteStreams.toByteArray(ByteStreams.slice(supplier, offset, length))));
801   }
802 
803   private static InputStream newTestStream(int n) {
804     return new ByteArrayInputStream(newPreFilledByteArray(n));
805   }
806 
807   private static CheckCloseSupplier.Input<InputStream> newCheckInput(
808       InputSupplier<? extends InputStream> delegate) {
809     return new CheckCloseSupplier.Input<InputStream>(delegate) {
810       @Override protected InputStream wrap(InputStream object,
811           final Callback callback) {
812         return new FilterInputStream(object) {
813           @Override public void close() throws IOException {
814             callback.delegateClosed();
815             super.close();
816           }
817         };
818       }
819     };
820   }
821 
822   private static CheckCloseSupplier.Output<OutputStream> newCheckOutput(
823       OutputSupplier<? extends OutputStream> delegate) {
824     return new CheckCloseSupplier.Output<OutputStream>(delegate) {
825       @Override protected OutputStream wrap(OutputStream object,
826           final Callback callback) {
827         return new FilterOutputStream(object) {
828           @Override public void close() throws IOException {
829             callback.delegateClosed();
830             super.close();
831           }
832         };
833       }
834     };
835   }
836 
837   /** Stream that will skip a maximum number of bytes at a time. */
838   private static class SlowSkipper extends FilterInputStream {
839     private final long max;
840 
841     public SlowSkipper(InputStream in, long max) {
842       super(in);
843       this.max = max;
844     }
845 
846     @Override public long skip(long n) throws IOException {
847       return super.skip(Math.min(max, n));
848     }
849   }
850 
851   public void testByteProcessorStopEarly() throws IOException {
852     byte[] array = newPreFilledByteArray(6000);
853     assertEquals((Integer) 42,
854         ByteStreams.readBytes(ByteStreams.newInputStreamSupplier(array),
855             new ByteProcessor<Integer>() {
856               @Override
857               public boolean processBytes(byte[] buf, int off, int len) {
858                 assertTrue(Arrays.equals(
859                     copyOfRange(buf, off, off + len),
860                     newPreFilledByteArray(4096)));
861                 return false;
862               }
863 
864               @Override
865               public Integer getResult() {
866                 return 42;
867               }
868             }));
869   }
870 
871   private static byte[] copyOfRange(byte[] in, int from, int to) {
872     byte[] out = new byte[to - from];
873     for (int i = 0; i < to - from; i++) {
874       out[i] = in[from + i];
875     }
876     return out;
877   }
878 
879   private static void assertEquals(byte[] expected, byte[] actual) {
880     assertEquals(Bytes.asList(expected), Bytes.asList(actual));
881   }
882 }
883