Home | History | Annotate | Download | only in protobuf
      1 // Protocol Buffers - Google's data interchange format
      2 // Copyright 2008 Google Inc.  All rights reserved.
      3 // https://developers.google.com/protocol-buffers/
      4 //
      5 // Redistribution and use in source and binary forms, with or without
      6 // modification, are permitted provided that the following conditions are
      7 // met:
      8 //
      9 //     * Redistributions of source code must retain the above copyright
     10 // notice, this list of conditions and the following disclaimer.
     11 //     * Redistributions in binary form must reproduce the above
     12 // copyright notice, this list of conditions and the following disclaimer
     13 // in the documentation and/or other materials provided with the
     14 // distribution.
     15 //     * Neither the name of Google Inc. nor the names of its
     16 // contributors may be used to endorse or promote products derived from
     17 // this software without specific prior written permission.
     18 //
     19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     30 
     31 package com.google.protobuf;
     32 
     33 import protobuf_unittest.UnittestProto.BoolMessage;
     34 import protobuf_unittest.UnittestProto.Int32Message;
     35 import protobuf_unittest.UnittestProto.Int64Message;
     36 import protobuf_unittest.UnittestProto.TestAllTypes;
     37 import protobuf_unittest.UnittestProto.TestRecursiveMessage;
     38 
     39 import junit.framework.TestCase;
     40 
     41 import java.io.ByteArrayInputStream;
     42 import java.io.ByteArrayOutputStream;
     43 import java.io.FilterInputStream;
     44 import java.io.IOException;
     45 import java.io.InputStream;
     46 import java.nio.ByteBuffer;
     47 
     48 /**
     49  * Unit test for {@link CodedInputStream}.
     50  *
     51  * @author kenton (at) google.com Kenton Varda
     52  */
     53 public class CodedInputStreamTest extends TestCase {
     54   /**
     55    * Helper to construct a byte array from a bunch of bytes.  The inputs are
     56    * actually ints so that I can use hex notation and not get stupid errors
     57    * about precision.
     58    */
     59   private byte[] bytes(int... bytesAsInts) {
     60     byte[] bytes = new byte[bytesAsInts.length];
     61     for (int i = 0; i < bytesAsInts.length; i++) {
     62       bytes[i] = (byte) bytesAsInts[i];
     63     }
     64     return bytes;
     65   }
     66 
     67   /**
     68    * An InputStream which limits the number of bytes it reads at a time.
     69    * We use this to make sure that CodedInputStream doesn't screw up when
     70    * reading in small blocks.
     71    */
     72   private static final class SmallBlockInputStream extends FilterInputStream {
     73     private final int blockSize;
     74 
     75     public SmallBlockInputStream(byte[] data, int blockSize) {
     76       this(new ByteArrayInputStream(data), blockSize);
     77     }
     78 
     79     public SmallBlockInputStream(InputStream in, int blockSize) {
     80       super(in);
     81       this.blockSize = blockSize;
     82     }
     83 
     84     @Override
     85     public int read(byte[] b) throws IOException {
     86       return super.read(b, 0, Math.min(b.length, blockSize));
     87     }
     88 
     89     @Override
     90     public int read(byte[] b, int off, int len) throws IOException {
     91       return super.read(b, off, Math.min(len, blockSize));
     92     }
     93   }
     94 
     95   private void assertDataConsumed(byte[] data, CodedInputStream input)
     96       throws IOException {
     97     assertEquals(data.length, input.getTotalBytesRead());
     98     assertTrue(input.isAtEnd());
     99   }
    100 
    101   /**
    102    * Parses the given bytes using readRawVarint32() and readRawVarint64() and
    103    * checks that the result matches the given value.
    104    */
    105   private void assertReadVarint(byte[] data, long value) throws Exception {
    106     CodedInputStream input = CodedInputStream.newInstance(data);
    107     assertEquals((int) value, input.readRawVarint32());
    108     assertDataConsumed(data, input);
    109 
    110     input = CodedInputStream.newInstance(data);
    111     assertEquals(value, input.readRawVarint64());
    112     assertDataConsumed(data, input);
    113 
    114     input = CodedInputStream.newInstance(data);
    115     assertEquals(value, input.readRawVarint64SlowPath());
    116     assertDataConsumed(data, input);
    117 
    118     input = CodedInputStream.newInstance(data);
    119     assertTrue(input.skipField(WireFormat.WIRETYPE_VARINT));
    120     assertDataConsumed(data, input);
    121 
    122     // Try different block sizes.
    123     for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
    124       input = CodedInputStream.newInstance(
    125         new SmallBlockInputStream(data, blockSize));
    126       assertEquals((int) value, input.readRawVarint32());
    127       assertDataConsumed(data, input);
    128 
    129       input = CodedInputStream.newInstance(
    130         new SmallBlockInputStream(data, blockSize));
    131       assertEquals(value, input.readRawVarint64());
    132       assertDataConsumed(data, input);
    133 
    134       input = CodedInputStream.newInstance(
    135         new SmallBlockInputStream(data, blockSize));
    136       assertEquals(value, input.readRawVarint64SlowPath());
    137       assertDataConsumed(data, input);
    138 
    139       input = CodedInputStream.newInstance(
    140         new SmallBlockInputStream(data, blockSize));
    141       assertTrue(input.skipField(WireFormat.WIRETYPE_VARINT));
    142       assertDataConsumed(data, input);
    143     }
    144 
    145     // Try reading direct from an InputStream.  We want to verify that it
    146     // doesn't read past the end of the input, so we copy to a new, bigger
    147     // array first.
    148     byte[] longerData = new byte[data.length + 1];
    149     System.arraycopy(data, 0, longerData, 0, data.length);
    150     InputStream rawInput = new ByteArrayInputStream(longerData);
    151     assertEquals((int) value, CodedInputStream.readRawVarint32(rawInput));
    152     assertEquals(1, rawInput.available());
    153   }
    154 
    155   /**
    156    * Parses the given bytes using readRawVarint32() and readRawVarint64() and
    157    * expects them to fail with an InvalidProtocolBufferException whose
    158    * description matches the given one.
    159    */
    160   private void assertReadVarintFailure(
    161       InvalidProtocolBufferException expected, byte[] data)
    162       throws Exception {
    163     CodedInputStream input = CodedInputStream.newInstance(data);
    164     try {
    165       input.readRawVarint32();
    166       fail("Should have thrown an exception.");
    167     } catch (InvalidProtocolBufferException e) {
    168       assertEquals(expected.getMessage(), e.getMessage());
    169     }
    170 
    171     input = CodedInputStream.newInstance(data);
    172     try {
    173       input.readRawVarint64();
    174       fail("Should have thrown an exception.");
    175     } catch (InvalidProtocolBufferException e) {
    176       assertEquals(expected.getMessage(), e.getMessage());
    177     }
    178 
    179     input = CodedInputStream.newInstance(data);
    180     try {
    181       input.readRawVarint64SlowPath();
    182       fail("Should have thrown an exception.");
    183     } catch (InvalidProtocolBufferException e) {
    184       assertEquals(expected.getMessage(), e.getMessage());
    185     }
    186 
    187     // Make sure we get the same error when reading direct from an InputStream.
    188     try {
    189       CodedInputStream.readRawVarint32(new ByteArrayInputStream(data));
    190       fail("Should have thrown an exception.");
    191     } catch (InvalidProtocolBufferException e) {
    192       assertEquals(expected.getMessage(), e.getMessage());
    193     }
    194   }
    195 
    196   /** Tests readRawVarint32() and readRawVarint64(). */
    197   public void testReadVarint() throws Exception {
    198     assertReadVarint(bytes(0x00), 0);
    199     assertReadVarint(bytes(0x01), 1);
    200     assertReadVarint(bytes(0x7f), 127);
    201     // 14882
    202     assertReadVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
    203     // 2961488830
    204     assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
    205       (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
    206       (0x0bL << 28));
    207 
    208     // 64-bit
    209     // 7256456126
    210     assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
    211       (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
    212       (0x1bL << 28));
    213     // 41256202580718336
    214     assertReadVarint(
    215       bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
    216       (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
    217       (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
    218     // 11964378330978735131
    219     assertReadVarint(
    220       bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
    221       (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
    222       (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) |
    223       (0x05L << 49) | (0x26L << 56) | (0x01L << 63));
    224 
    225     // Failures
    226     assertReadVarintFailure(
    227       InvalidProtocolBufferException.malformedVarint(),
    228       bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
    229             0x00));
    230     assertReadVarintFailure(
    231       InvalidProtocolBufferException.truncatedMessage(),
    232       bytes(0x80));
    233   }
    234 
    235   /**
    236    * Parses the given bytes using readRawLittleEndian32() and checks
    237    * that the result matches the given value.
    238    */
    239   private void assertReadLittleEndian32(byte[] data, int value)
    240                                         throws Exception {
    241     CodedInputStream input = CodedInputStream.newInstance(data);
    242     assertEquals(value, input.readRawLittleEndian32());
    243     assertTrue(input.isAtEnd());
    244 
    245     // Try different block sizes.
    246     for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
    247       input = CodedInputStream.newInstance(
    248         new SmallBlockInputStream(data, blockSize));
    249       assertEquals(value, input.readRawLittleEndian32());
    250       assertTrue(input.isAtEnd());
    251     }
    252   }
    253 
    254   /**
    255    * Parses the given bytes using readRawLittleEndian64() and checks
    256    * that the result matches the given value.
    257    */
    258   private void assertReadLittleEndian64(byte[] data, long value)
    259                                         throws Exception {
    260     CodedInputStream input = CodedInputStream.newInstance(data);
    261     assertEquals(value, input.readRawLittleEndian64());
    262     assertTrue(input.isAtEnd());
    263 
    264     // Try different block sizes.
    265     for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
    266       input = CodedInputStream.newInstance(
    267         new SmallBlockInputStream(data, blockSize));
    268       assertEquals(value, input.readRawLittleEndian64());
    269       assertTrue(input.isAtEnd());
    270     }
    271   }
    272 
    273   /** Tests readRawLittleEndian32() and readRawLittleEndian64(). */
    274   public void testReadLittleEndian() throws Exception {
    275     assertReadLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
    276     assertReadLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
    277 
    278     assertReadLittleEndian64(
    279       bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
    280       0x123456789abcdef0L);
    281     assertReadLittleEndian64(
    282       bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a),
    283       0x9abcdef012345678L);
    284   }
    285 
    286   /** Test decodeZigZag32() and decodeZigZag64(). */
    287   public void testDecodeZigZag() throws Exception {
    288     assertEquals( 0, CodedInputStream.decodeZigZag32(0));
    289     assertEquals(-1, CodedInputStream.decodeZigZag32(1));
    290     assertEquals( 1, CodedInputStream.decodeZigZag32(2));
    291     assertEquals(-2, CodedInputStream.decodeZigZag32(3));
    292     assertEquals(0x3FFFFFFF, CodedInputStream.decodeZigZag32(0x7FFFFFFE));
    293     assertEquals(0xC0000000, CodedInputStream.decodeZigZag32(0x7FFFFFFF));
    294     assertEquals(0x7FFFFFFF, CodedInputStream.decodeZigZag32(0xFFFFFFFE));
    295     assertEquals(0x80000000, CodedInputStream.decodeZigZag32(0xFFFFFFFF));
    296 
    297     assertEquals( 0, CodedInputStream.decodeZigZag64(0));
    298     assertEquals(-1, CodedInputStream.decodeZigZag64(1));
    299     assertEquals( 1, CodedInputStream.decodeZigZag64(2));
    300     assertEquals(-2, CodedInputStream.decodeZigZag64(3));
    301     assertEquals(0x000000003FFFFFFFL,
    302                  CodedInputStream.decodeZigZag64(0x000000007FFFFFFEL));
    303     assertEquals(0xFFFFFFFFC0000000L,
    304                  CodedInputStream.decodeZigZag64(0x000000007FFFFFFFL));
    305     assertEquals(0x000000007FFFFFFFL,
    306                  CodedInputStream.decodeZigZag64(0x00000000FFFFFFFEL));
    307     assertEquals(0xFFFFFFFF80000000L,
    308                  CodedInputStream.decodeZigZag64(0x00000000FFFFFFFFL));
    309     assertEquals(0x7FFFFFFFFFFFFFFFL,
    310                  CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFEL));
    311     assertEquals(0x8000000000000000L,
    312                  CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFFL));
    313   }
    314 
    315   /** Tests reading and parsing a whole message with every field type. */
    316   public void testReadWholeMessage() throws Exception {
    317     TestAllTypes message = TestUtil.getAllSet();
    318 
    319     byte[] rawBytes = message.toByteArray();
    320     assertEquals(rawBytes.length, message.getSerializedSize());
    321 
    322     TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
    323     TestUtil.assertAllFieldsSet(message2);
    324 
    325     // Try different block sizes.
    326     for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
    327       message2 = TestAllTypes.parseFrom(
    328         new SmallBlockInputStream(rawBytes, blockSize));
    329       TestUtil.assertAllFieldsSet(message2);
    330     }
    331   }
    332 
    333   /** Tests skipField(). */
    334   public void testSkipWholeMessage() throws Exception {
    335     TestAllTypes message = TestUtil.getAllSet();
    336     byte[] rawBytes = message.toByteArray();
    337 
    338     // Create two parallel inputs.  Parse one as unknown fields while using
    339     // skipField() to skip each field on the other.  Expect the same tags.
    340     CodedInputStream input1 = CodedInputStream.newInstance(rawBytes);
    341     CodedInputStream input2 = CodedInputStream.newInstance(rawBytes);
    342     UnknownFieldSet.Builder unknownFields = UnknownFieldSet.newBuilder();
    343 
    344     while (true) {
    345       int tag = input1.readTag();
    346       assertEquals(tag, input2.readTag());
    347       if (tag == 0) {
    348         break;
    349       }
    350       unknownFields.mergeFieldFrom(tag, input1);
    351       input2.skipField(tag);
    352     }
    353   }
    354 
    355 
    356   /**
    357    * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
    358    * exactly up to a limit, this should not break things.
    359    */
    360   public void testSkipRawBytesBug() throws Exception {
    361     byte[] rawBytes = new byte[] { 1, 2 };
    362     CodedInputStream input = CodedInputStream.newInstance(rawBytes);
    363 
    364     int limit = input.pushLimit(1);
    365     input.skipRawBytes(1);
    366     input.popLimit(limit);
    367     assertEquals(2, input.readRawByte());
    368   }
    369 
    370   /**
    371    * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
    372    * past the end of a buffer with a limit that has been set past the end of
    373    * that buffer, this should not break things.
    374    */
    375   public void testSkipRawBytesPastEndOfBufferWithLimit() throws Exception {
    376     byte[] rawBytes = new byte[] { 1, 2, 3, 4, 5 };
    377     CodedInputStream input = CodedInputStream.newInstance(
    378         new SmallBlockInputStream(rawBytes, 3));
    379 
    380     int limit = input.pushLimit(4);
    381     // In order to expose the bug we need to read at least one byte to prime the
    382     // buffer inside the CodedInputStream.
    383     assertEquals(1, input.readRawByte());
    384     // Skip to the end of the limit.
    385     input.skipRawBytes(3);
    386     assertTrue(input.isAtEnd());
    387     input.popLimit(limit);
    388     assertEquals(5, input.readRawByte());
    389   }
    390 
    391   public void testReadHugeBlob() throws Exception {
    392     // Allocate and initialize a 1MB blob.
    393     byte[] blob = new byte[1 << 20];
    394     for (int i = 0; i < blob.length; i++) {
    395       blob[i] = (byte) i;
    396     }
    397 
    398     // Make a message containing it.
    399     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
    400     TestUtil.setAllFields(builder);
    401     builder.setOptionalBytes(ByteString.copyFrom(blob));
    402     TestAllTypes message = builder.build();
    403 
    404     // Serialize and parse it.  Make sure to parse from an InputStream, not
    405     // directly from a ByteString, so that CodedInputStream uses buffered
    406     // reading.
    407     TestAllTypes message2 =
    408       TestAllTypes.parseFrom(message.toByteString().newInput());
    409 
    410     assertEquals(message.getOptionalBytes(), message2.getOptionalBytes());
    411 
    412     // Make sure all the other fields were parsed correctly.
    413     TestAllTypes message3 = TestAllTypes.newBuilder(message2)
    414       .setOptionalBytes(TestUtil.getAllSet().getOptionalBytes())
    415       .build();
    416     TestUtil.assertAllFieldsSet(message3);
    417   }
    418 
    419   public void testReadMaliciouslyLargeBlob() throws Exception {
    420     ByteString.Output rawOutput = ByteString.newOutput();
    421     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
    422 
    423     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
    424     output.writeRawVarint32(tag);
    425     output.writeRawVarint32(0x7FFFFFFF);
    426     output.writeRawBytes(new byte[32]);  // Pad with a few random bytes.
    427     output.flush();
    428 
    429     CodedInputStream input = rawOutput.toByteString().newCodedInput();
    430     assertEquals(tag, input.readTag());
    431 
    432     try {
    433       input.readBytes();
    434       fail("Should have thrown an exception!");
    435     } catch (InvalidProtocolBufferException e) {
    436       // success.
    437     }
    438   }
    439 
    440   private TestRecursiveMessage makeRecursiveMessage(int depth) {
    441     if (depth == 0) {
    442       return TestRecursiveMessage.newBuilder().setI(5).build();
    443     } else {
    444       return TestRecursiveMessage.newBuilder()
    445         .setA(makeRecursiveMessage(depth - 1)).build();
    446     }
    447   }
    448 
    449   private void assertMessageDepth(TestRecursiveMessage message, int depth) {
    450     if (depth == 0) {
    451       assertFalse(message.hasA());
    452       assertEquals(5, message.getI());
    453     } else {
    454       assertTrue(message.hasA());
    455       assertMessageDepth(message.getA(), depth - 1);
    456     }
    457   }
    458 
    459   public void testMaliciousRecursion() throws Exception {
    460     ByteString data100 = makeRecursiveMessage(100).toByteString();
    461     ByteString data101 = makeRecursiveMessage(101).toByteString();
    462 
    463     assertMessageDepth(TestRecursiveMessage.parseFrom(data100), 100);
    464 
    465     try {
    466       TestRecursiveMessage.parseFrom(data101);
    467       fail("Should have thrown an exception!");
    468     } catch (InvalidProtocolBufferException e) {
    469       // success.
    470     }
    471 
    472     CodedInputStream input = data100.newCodedInput();
    473     input.setRecursionLimit(8);
    474     try {
    475       TestRecursiveMessage.parseFrom(input);
    476       fail("Should have thrown an exception!");
    477     } catch (InvalidProtocolBufferException e) {
    478       // success.
    479     }
    480   }
    481 
    482   private void checkSizeLimitExceeded(InvalidProtocolBufferException e) {
    483       assertEquals(
    484           InvalidProtocolBufferException.sizeLimitExceeded().getMessage(),
    485           e.getMessage());
    486   }
    487 
    488   public void testSizeLimit() throws Exception {
    489     CodedInputStream input = CodedInputStream.newInstance(
    490         new SmallBlockInputStream(
    491             TestUtil.getAllSet().toByteString().newInput(), 16));
    492     input.setSizeLimit(16);
    493 
    494     try {
    495       TestAllTypes.parseFrom(input);
    496       fail("Should have thrown an exception!");
    497     } catch (InvalidProtocolBufferException expected) {
    498       checkSizeLimitExceeded(expected);
    499     }
    500   }
    501 
    502   public void testResetSizeCounter() throws Exception {
    503     CodedInputStream input = CodedInputStream.newInstance(
    504         new SmallBlockInputStream(new byte[256], 8));
    505     input.setSizeLimit(16);
    506     input.readRawBytes(16);
    507     assertEquals(16, input.getTotalBytesRead());
    508 
    509     try {
    510       input.readRawByte();
    511       fail("Should have thrown an exception!");
    512     } catch (InvalidProtocolBufferException expected) {
    513       checkSizeLimitExceeded(expected);
    514     }
    515 
    516     input.resetSizeCounter();
    517     assertEquals(0, input.getTotalBytesRead());
    518     input.readRawByte();  // No exception thrown.
    519     input.resetSizeCounter();
    520     assertEquals(0, input.getTotalBytesRead());
    521     input.readRawBytes(16);
    522     assertEquals(16, input.getTotalBytesRead());
    523     input.resetSizeCounter();
    524 
    525     try {
    526       input.readRawBytes(17);  // Hits limit again.
    527       fail("Should have thrown an exception!");
    528     } catch (InvalidProtocolBufferException expected) {
    529       checkSizeLimitExceeded(expected);
    530     }
    531   }
    532 
    533   public void testSizeLimitMultipleMessages() throws Exception {
    534     byte[] bytes = new byte[256];
    535     for (int i = 0; i < bytes.length; i++) {
    536       bytes[i] = (byte) i;
    537     }
    538     CodedInputStream input = CodedInputStream.newInstance(
    539         new SmallBlockInputStream(bytes, 7));
    540     input.setSizeLimit(16);
    541     for (int i = 0; i < 256 / 16; i++) {
    542       byte[] message = input.readRawBytes(16);
    543       for (int j = 0; j < message.length; j++) {
    544         assertEquals(i * 16 + j, message[j] & 0xff);
    545       }
    546       assertEquals(16, input.getTotalBytesRead());
    547       input.resetSizeCounter();
    548       assertEquals(0, input.getTotalBytesRead());
    549     }
    550   }
    551 
    552   public void testReadString() throws Exception {
    553     String lorem = "Lorem ipsum dolor sit amet ";
    554     StringBuilder builder = new StringBuilder();
    555     for (int i = 0; i < 4096; i += lorem.length()) {
    556       builder.append(lorem);
    557     }
    558     lorem = builder.toString().substring(0, 4096);
    559     byte[] bytes = lorem.getBytes("UTF-8");
    560     ByteString.Output rawOutput = ByteString.newOutput();
    561     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
    562 
    563     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
    564     output.writeRawVarint32(tag);
    565     output.writeRawVarint32(bytes.length);
    566     output.writeRawBytes(bytes);
    567     output.flush();
    568 
    569     CodedInputStream input =
    570         CodedInputStream.newInstance(
    571             new ByteArrayInputStream(rawOutput.toByteString().toByteArray()));
    572     assertEquals(tag, input.readTag());
    573     String text = input.readString();
    574     assertEquals(lorem, text);
    575   }
    576 
    577   public void testReadStringRequireUtf8() throws Exception {
    578     String lorem = "Lorem ipsum dolor sit amet ";
    579     StringBuilder builder = new StringBuilder();
    580     for (int i = 0; i < 4096; i += lorem.length()) {
    581       builder.append(lorem);
    582     }
    583     lorem = builder.toString().substring(0, 4096);
    584     byte[] bytes = lorem.getBytes("UTF-8");
    585     ByteString.Output rawOutput = ByteString.newOutput();
    586     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.length);
    587 
    588     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
    589     output.writeRawVarint32(tag);
    590     output.writeRawVarint32(bytes.length);
    591     output.writeRawBytes(bytes);
    592     output.flush();
    593 
    594     CodedInputStream input =
    595         CodedInputStream.newInstance(
    596             new ByteArrayInputStream(rawOutput.toByteString().toByteArray()));
    597     assertEquals(tag, input.readTag());
    598     String text = input.readStringRequireUtf8();
    599     assertEquals(lorem, text);
    600   }
    601 
    602   /**
    603    * Tests that if we readString invalid UTF-8 bytes, no exception
    604    * is thrown.  Instead, the invalid bytes are replaced with the Unicode
    605    * "replacement character" U+FFFD.
    606    */
    607   public void testReadStringInvalidUtf8() throws Exception {
    608     ByteString.Output rawOutput = ByteString.newOutput();
    609     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
    610 
    611     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
    612     output.writeRawVarint32(tag);
    613     output.writeRawVarint32(1);
    614     output.writeRawBytes(new byte[] { (byte) 0x80 });
    615     output.flush();
    616 
    617     CodedInputStream input = rawOutput.toByteString().newCodedInput();
    618     assertEquals(tag, input.readTag());
    619     String text = input.readString();
    620     assertEquals(0xfffd, text.charAt(0));
    621   }
    622 
    623   /**
    624    * Tests that if we readStringRequireUtf8 invalid UTF-8 bytes, an
    625    * InvalidProtocolBufferException is thrown.
    626    */
    627   public void testReadStringRequireUtf8InvalidUtf8() throws Exception {
    628     ByteString.Output rawOutput = ByteString.newOutput();
    629     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
    630 
    631     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
    632     output.writeRawVarint32(tag);
    633     output.writeRawVarint32(1);
    634     output.writeRawBytes(new byte[] { (byte) 0x80 });
    635     output.flush();
    636 
    637     CodedInputStream input = rawOutput.toByteString().newCodedInput();
    638     assertEquals(tag, input.readTag());
    639     try {
    640       input.readStringRequireUtf8();
    641       fail("Expected invalid UTF-8 exception.");
    642     } catch (InvalidProtocolBufferException exception) {
    643       assertEquals("Protocol message had invalid UTF-8.", exception.getMessage());
    644     }
    645   }
    646 
    647   public void testReadFromSlice() throws Exception {
    648     byte[] bytes = bytes(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
    649     CodedInputStream in = CodedInputStream.newInstance(bytes, 3, 5);
    650     assertEquals(0, in.getTotalBytesRead());
    651     for (int i = 3; i < 8; i++) {
    652       assertEquals(i, in.readRawByte());
    653       assertEquals(i - 2, in.getTotalBytesRead());
    654     }
    655     // eof
    656     assertEquals(0, in.readTag());
    657     assertEquals(5, in.getTotalBytesRead());
    658   }
    659 
    660   public void testInvalidTag() throws Exception {
    661     // Any tag number which corresponds to field number zero is invalid and
    662     // should throw InvalidProtocolBufferException.
    663     for (int i = 0; i < 8; i++) {
    664       try {
    665         CodedInputStream.newInstance(bytes(i)).readTag();
    666         fail("Should have thrown an exception.");
    667       } catch (InvalidProtocolBufferException e) {
    668         assertEquals(InvalidProtocolBufferException.invalidTag().getMessage(),
    669                      e.getMessage());
    670       }
    671     }
    672   }
    673 
    674   public void testReadByteArray() throws Exception {
    675     ByteString.Output rawOutput = ByteString.newOutput();
    676     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
    677     // Zero-sized bytes field.
    678     output.writeRawVarint32(0);
    679     // One one-byte bytes field
    680     output.writeRawVarint32(1);
    681     output.writeRawBytes(new byte[] { (byte) 23 });
    682     // Another one-byte bytes field
    683     output.writeRawVarint32(1);
    684     output.writeRawBytes(new byte[] { (byte) 45 });
    685     // A bytes field large enough that won't fit into the 4K buffer.
    686     final int bytesLength = 16 * 1024;
    687     byte[] bytes = new byte[bytesLength];
    688     bytes[0] = (byte) 67;
    689     bytes[bytesLength - 1] = (byte) 89;
    690     output.writeRawVarint32(bytesLength);
    691     output.writeRawBytes(bytes);
    692 
    693     output.flush();
    694     CodedInputStream inputStream = rawOutput.toByteString().newCodedInput();
    695 
    696     byte[] result = inputStream.readByteArray();
    697     assertEquals(0, result.length);
    698     result = inputStream.readByteArray();
    699     assertEquals(1, result.length);
    700     assertEquals((byte) 23, result[0]);
    701     result = inputStream.readByteArray();
    702     assertEquals(1, result.length);
    703     assertEquals((byte) 45, result[0]);
    704     result = inputStream.readByteArray();
    705     assertEquals(bytesLength, result.length);
    706     assertEquals((byte) 67, result[0]);
    707     assertEquals((byte) 89, result[bytesLength - 1]);
    708   }
    709 
    710   public void testReadByteBuffer() throws Exception {
    711     ByteString.Output rawOutput = ByteString.newOutput();
    712     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
    713     // Zero-sized bytes field.
    714     output.writeRawVarint32(0);
    715     // One one-byte bytes field
    716     output.writeRawVarint32(1);
    717     output.writeRawBytes(new byte[]{(byte) 23});
    718     // Another one-byte bytes field
    719     output.writeRawVarint32(1);
    720     output.writeRawBytes(new byte[]{(byte) 45});
    721     // A bytes field large enough that won't fit into the 4K buffer.
    722     final int bytesLength = 16 * 1024;
    723     byte[] bytes = new byte[bytesLength];
    724     bytes[0] = (byte) 67;
    725     bytes[bytesLength - 1] = (byte) 89;
    726     output.writeRawVarint32(bytesLength);
    727     output.writeRawBytes(bytes);
    728 
    729     output.flush();
    730     CodedInputStream inputStream = rawOutput.toByteString().newCodedInput();
    731 
    732     ByteBuffer result = inputStream.readByteBuffer();
    733     assertEquals(0, result.capacity());
    734     result = inputStream.readByteBuffer();
    735     assertEquals(1, result.capacity());
    736     assertEquals((byte) 23, result.get());
    737     result = inputStream.readByteBuffer();
    738     assertEquals(1, result.capacity());
    739     assertEquals((byte) 45, result.get());
    740     result = inputStream.readByteBuffer();
    741     assertEquals(bytesLength, result.capacity());
    742     assertEquals((byte) 67, result.get());
    743     result.position(bytesLength - 1);
    744     assertEquals((byte) 89, result.get());
    745   }
    746 
    747   public void testReadByteBufferAliasing() throws Exception {
    748     ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
    749     CodedOutputStream output = CodedOutputStream.newInstance(byteArrayStream);
    750     // Zero-sized bytes field.
    751     output.writeRawVarint32(0);
    752     // One one-byte bytes field
    753     output.writeRawVarint32(1);
    754     output.writeRawBytes(new byte[]{(byte) 23});
    755     // Another one-byte bytes field
    756     output.writeRawVarint32(1);
    757     output.writeRawBytes(new byte[]{(byte) 45});
    758     // A bytes field large enough that won't fit into the 4K buffer.
    759     final int bytesLength = 16 * 1024;
    760     byte[] bytes = new byte[bytesLength];
    761     bytes[0] = (byte) 67;
    762     bytes[bytesLength - 1] = (byte) 89;
    763     output.writeRawVarint32(bytesLength);
    764     output.writeRawBytes(bytes);
    765     output.flush();
    766     byte[] data = byteArrayStream.toByteArray();
    767 
    768     // Without aliasing
    769     CodedInputStream inputStream = CodedInputStream.newInstance(data);
    770     ByteBuffer result = inputStream.readByteBuffer();
    771     assertEquals(0, result.capacity());
    772     result = inputStream.readByteBuffer();
    773     assertTrue(result.array() != data);
    774     assertEquals(1, result.capacity());
    775     assertEquals((byte) 23, result.get());
    776     result = inputStream.readByteBuffer();
    777     assertTrue(result.array() != data);
    778     assertEquals(1, result.capacity());
    779     assertEquals((byte) 45, result.get());
    780     result = inputStream.readByteBuffer();
    781     assertTrue(result.array() != data);
    782     assertEquals(bytesLength, result.capacity());
    783     assertEquals((byte) 67, result.get());
    784     result.position(bytesLength - 1);
    785     assertEquals((byte) 89, result.get());
    786 
    787     // Enable aliasing
    788     inputStream = CodedInputStream.newInstance(data);
    789     inputStream.enableAliasing(true);
    790     result = inputStream.readByteBuffer();
    791     assertEquals(0, result.capacity());
    792     result = inputStream.readByteBuffer();
    793     assertTrue(result.array() == data);
    794     assertEquals(1, result.capacity());
    795     assertEquals((byte) 23, result.get());
    796     result = inputStream.readByteBuffer();
    797     assertTrue(result.array() == data);
    798     assertEquals(1, result.capacity());
    799     assertEquals((byte) 45, result.get());
    800     result = inputStream.readByteBuffer();
    801     assertTrue(result.array() == data);
    802     assertEquals(bytesLength, result.capacity());
    803     assertEquals((byte) 67, result.get());
    804     result.position(bytesLength - 1);
    805     assertEquals((byte) 89, result.get());
    806   }
    807 
    808   public void testCompatibleTypes() throws Exception {
    809     long data = 0x100000000L;
    810     Int64Message message = Int64Message.newBuilder().setData(data).build();
    811     ByteString serialized = message.toByteString();
    812 
    813     // Test int64(long) is compatible with bool(boolean)
    814     BoolMessage msg2 = BoolMessage.parseFrom(serialized);
    815     assertTrue(msg2.getData());
    816 
    817     // Test int64(long) is compatible with int32(int)
    818     Int32Message msg3 = Int32Message.parseFrom(serialized);
    819     assertEquals((int) data, msg3.getData());
    820   }
    821 }
    822