Home | History | Annotate | Download | only in io
      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 
    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 
    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 
    162   private void equalHelper(boolean expect, int size1, int size2)
    163       throws IOException {
    164     equalHelper(expect, newPreFilledByteArray(size1),
    165         newPreFilledByteArray(size2));
    166   }
    167 
    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 
    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 
    343   private static int getAndResetRecords(TestLogHandler logHandler) {
    344     int records = logHandler.getStoredLogRecords().size();
    345     logHandler.clear();
    346     return records;
    347   }
    348 
    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 
    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