Home | History | Annotate | Download | only in okio
      1 /*
      2  * Copyright (C) 2014 Square, Inc.
      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 package okio;
     17 
     18 import java.io.EOFException;
     19 import java.io.IOException;
     20 import java.io.OutputStream;
     21 import java.math.BigInteger;
     22 import java.nio.charset.Charset;
     23 import java.util.Arrays;
     24 import java.util.List;
     25 import org.junit.Before;
     26 import org.junit.Test;
     27 import org.junit.runner.RunWith;
     28 import org.junit.runners.Parameterized;
     29 
     30 import static java.util.Arrays.asList;
     31 import static okio.TestUtil.repeat;
     32 import static okio.Util.UTF_8;
     33 import static org.junit.Assert.assertEquals;
     34 import static org.junit.Assert.fail;
     35 
     36 @RunWith(Parameterized.class)
     37 public class BufferedSinkTest {
     38   private interface Factory {
     39     BufferedSink create(Buffer data);
     40   }
     41 
     42   // ANDROID-BEGIN
     43   //  @Parameterized.Parameters(name = "{0}")
     44   @Parameterized.Parameters
     45   // ANDROID-END
     46   public static List<Object[]> parameters() {
     47     return Arrays.asList(new Object[] {
     48         new Factory() {
     49           @Override public BufferedSink create(Buffer data) {
     50             return data;
     51           }
     52 
     53           @Override public String toString() {
     54             return "Buffer";
     55           }
     56         }
     57     }, new Object[] {
     58         new Factory() {
     59           @Override public BufferedSink create(Buffer data) {
     60             return new RealBufferedSink(data);
     61           }
     62 
     63           @Override public String toString() {
     64             return "RealBufferedSink";
     65           }
     66         }
     67     });
     68   }
     69 
     70   // ANDROID-BEGIN
     71   //  @Parameterized.Parameter
     72   private final Factory factory;
     73   public BufferedSinkTest(Factory factory) {
     74     this.factory = factory;
     75   }
     76   // ANDROID-END
     77 
     78   private Buffer data;
     79   private BufferedSink sink;
     80 
     81   @Before public void setUp() {
     82     data = new Buffer();
     83     sink = factory.create(data);
     84   }
     85 
     86   @Test public void writeNothing() throws IOException {
     87     sink.writeUtf8("");
     88     sink.flush();
     89     assertEquals(0, data.size());
     90   }
     91 
     92   @Test public void writeBytes() throws Exception {
     93     sink.writeByte(0xab);
     94     sink.writeByte(0xcd);
     95     sink.flush();
     96     assertEquals("Buffer[size=2 data=abcd]", data.toString());
     97   }
     98 
     99   @Test public void writeLastByteInSegment() throws Exception {
    100     sink.writeUtf8(repeat('a', Segment.SIZE - 1));
    101     sink.writeByte(0x20);
    102     sink.writeByte(0x21);
    103     sink.flush();
    104     assertEquals(asList(Segment.SIZE, 1), data.segmentSizes());
    105     assertEquals(repeat('a', Segment.SIZE - 1), data.readUtf8(Segment.SIZE - 1));
    106     assertEquals("Buffer[size=2 data=2021]", data.toString());
    107   }
    108 
    109   @Test public void writeShort() throws Exception {
    110     sink.writeShort(0xabcd);
    111     sink.writeShort(0x4321);
    112     sink.flush();
    113     assertEquals("Buffer[size=4 data=abcd4321]", data.toString());
    114   }
    115 
    116   @Test public void writeShortLe() throws Exception {
    117     sink.writeShortLe(0xabcd);
    118     sink.writeShortLe(0x4321);
    119     sink.flush();
    120     assertEquals("Buffer[size=4 data=cdab2143]", data.toString());
    121   }
    122 
    123   @Test public void writeInt() throws Exception {
    124     sink.writeInt(0xabcdef01);
    125     sink.writeInt(0x87654321);
    126     sink.flush();
    127     assertEquals("Buffer[size=8 data=abcdef0187654321]", data.toString());
    128   }
    129 
    130   @Test public void writeLastIntegerInSegment() throws Exception {
    131     sink.writeUtf8(repeat('a', Segment.SIZE - 4));
    132     sink.writeInt(0xabcdef01);
    133     sink.writeInt(0x87654321);
    134     sink.flush();
    135     assertEquals(asList(Segment.SIZE, 4), data.segmentSizes());
    136     assertEquals(repeat('a', Segment.SIZE - 4), data.readUtf8(Segment.SIZE - 4));
    137     assertEquals("Buffer[size=8 data=abcdef0187654321]", data.toString());
    138   }
    139 
    140   @Test public void writeIntegerDoesNotQuiteFitInSegment() throws Exception {
    141     sink.writeUtf8(repeat('a', Segment.SIZE - 3));
    142     sink.writeInt(0xabcdef01);
    143     sink.writeInt(0x87654321);
    144     sink.flush();
    145     assertEquals(asList(Segment.SIZE - 3, 8), data.segmentSizes());
    146     assertEquals(repeat('a', Segment.SIZE - 3), data.readUtf8(Segment.SIZE - 3));
    147     assertEquals("Buffer[size=8 data=abcdef0187654321]", data.toString());
    148   }
    149 
    150   @Test public void writeIntLe() throws Exception {
    151     sink.writeIntLe(0xabcdef01);
    152     sink.writeIntLe(0x87654321);
    153     sink.flush();
    154     assertEquals("Buffer[size=8 data=01efcdab21436587]", data.toString());
    155   }
    156 
    157   @Test public void writeLong() throws Exception {
    158     sink.writeLong(0xabcdef0187654321L);
    159     sink.writeLong(0xcafebabeb0b15c00L);
    160     sink.flush();
    161     assertEquals("Buffer[size=16 data=abcdef0187654321cafebabeb0b15c00]", data.toString());
    162   }
    163 
    164   @Test public void writeLongLe() throws Exception {
    165     sink.writeLongLe(0xabcdef0187654321L);
    166     sink.writeLongLe(0xcafebabeb0b15c00L);
    167     sink.flush();
    168     assertEquals("Buffer[size=16 data=2143658701efcdab005cb1b0bebafeca]", data.toString());
    169   }
    170 
    171   @Test public void writeStringUtf8() throws IOException {
    172     sink.writeUtf8("transr");
    173     sink.flush();
    174     assertEquals(ByteString.decodeHex("74c999cb8872616ec999cb8c73c3b472"), data.readByteString());
    175   }
    176 
    177   @Test public void writeSubstringUtf8() throws IOException {
    178     sink.writeUtf8("transr", 3, 7);
    179     sink.flush();
    180     assertEquals(ByteString.decodeHex("72616ec999"), data.readByteString());
    181   }
    182 
    183   @Test public void writeStringWithCharset() throws IOException {
    184     sink.writeString("transr", Charset.forName("utf-32be"));
    185     sink.flush();
    186     assertEquals(ByteString.decodeHex("0000007400000259000002c800000072000000610000006e00000259"
    187         + "000002cc00000073000000f400000072"), data.readByteString());
    188   }
    189 
    190   @Test public void writeSubstringWithCharset() throws IOException {
    191     sink.writeString("transr", 3, 7, Charset.forName("utf-32be"));
    192     sink.flush();
    193     assertEquals(ByteString.decodeHex("00000072000000610000006e00000259"), data.readByteString());
    194   }
    195 
    196   @Test public void writeAll() throws Exception {
    197     Buffer source = new Buffer().writeUtf8("abcdef");
    198 
    199     assertEquals(6, sink.writeAll(source));
    200     assertEquals(0, source.size());
    201     sink.flush();
    202     assertEquals("abcdef", data.readUtf8());
    203   }
    204 
    205   @Test public void writeSource() throws Exception {
    206     Buffer source = new Buffer().writeUtf8("abcdef");
    207 
    208     // Force resolution of the Source method overload.
    209     sink.write((Source) source, 4);
    210     sink.flush();
    211     assertEquals("abcd", data.readUtf8());
    212     assertEquals("ef", source.readUtf8());
    213   }
    214 
    215   @Test public void writeSourceReadsFully() throws Exception {
    216     Source source = new ForwardingSource(new Buffer()) {
    217       @Override public long read(Buffer sink, long byteCount) throws IOException {
    218         sink.writeUtf8("abcd");
    219         return 4;
    220       }
    221     };
    222 
    223     sink.write(source, 8);
    224     sink.flush();
    225     assertEquals("abcdabcd", data.readUtf8());
    226   }
    227 
    228   @Test public void writeSourcePropagatesEof() throws IOException {
    229     Source source = new Buffer().writeUtf8("abcd");
    230 
    231     try {
    232       sink.write(source, 8);
    233       fail();
    234     } catch (EOFException expected) {
    235     }
    236 
    237     // Ensure that whatever was available was correctly written.
    238     sink.flush();
    239     assertEquals("abcd", data.readUtf8());
    240   }
    241 
    242   @Test public void writeSourceWithZeroIsNoOp() throws IOException {
    243     // This test ensures that a zero byte count never calls through to read the source. It may be
    244     // tied to something like a socket which will potentially block trying to read a segment when
    245     // ultimately we don't want any data.
    246     Source source = new ForwardingSource(new Buffer()) {
    247       @Override public long read(Buffer sink, long byteCount) throws IOException {
    248         throw new AssertionError();
    249       }
    250     };
    251     sink.write(source, 0);
    252     assertEquals(0, data.size());
    253   }
    254 
    255   @Test public void writeAllExhausted() throws Exception {
    256     Buffer source = new Buffer();
    257     assertEquals(0, sink.writeAll(source));
    258     assertEquals(0, source.size());
    259   }
    260 
    261   @Test public void closeEmitsBufferedBytes() throws IOException {
    262     sink.writeByte('a');
    263     sink.close();
    264     assertEquals('a', data.readByte());
    265   }
    266 
    267   @Test public void outputStream() throws Exception {
    268     OutputStream out = sink.outputStream();
    269     out.write('a');
    270     out.write(repeat('b', 9998).getBytes(UTF_8));
    271     out.write('c');
    272     out.flush();
    273     assertEquals("a" + repeat('b', 9998) + "c", data.readUtf8());
    274   }
    275 
    276   @Test public void outputStreamBounds() throws Exception {
    277     OutputStream out = sink.outputStream();
    278     try {
    279       out.write(new byte[100], 50, 51);
    280       fail();
    281     } catch (ArrayIndexOutOfBoundsException expected) {
    282     }
    283   }
    284 
    285   @Test public void longDecimalString() throws IOException {
    286     assertLongDecimalString(0);
    287     assertLongDecimalString(Long.MIN_VALUE);
    288     assertLongDecimalString(Long.MAX_VALUE);
    289 
    290     for (int i = 1; i < 20; i++) {
    291       long value = BigInteger.valueOf(10L).pow(i).longValue();
    292       assertLongDecimalString(value - 1);
    293       assertLongDecimalString(value);
    294     }
    295   }
    296 
    297   private void assertLongDecimalString(long value) throws IOException {
    298     sink.writeDecimalLong(value).writeUtf8("zzz").flush();
    299     String expected = Long.toString(value) + "zzz";
    300     String actual = data.readUtf8();
    301     assertEquals(value + " expected " + expected + " but was " + actual, actual, expected);
    302   }
    303 
    304   @Test public void longHexString() throws IOException {
    305     assertLongHexString(0);
    306     assertLongHexString(Long.MIN_VALUE);
    307     assertLongHexString(Long.MAX_VALUE);
    308 
    309     for (int i = 0; i < 16; i++) {
    310       assertLongHexString((1 << i) - 1);
    311       assertLongHexString(1 << i);
    312     }
    313   }
    314 
    315   private void assertLongHexString(long value) throws IOException {
    316     sink.writeHexadecimalUnsignedLong(value).writeUtf8("zzz").flush();
    317     String expected = String.format("%x", value) + "zzz";
    318     String actual = data.readUtf8();
    319     assertEquals(value + " expected " + expected + " but was " + actual, actual, expected);
    320   }
    321 }
    322