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@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    */
bytes(int... bytesAsInts)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 
SmallBlockInputStream(byte[] data, int blockSize)75     public SmallBlockInputStream(byte[] data, int blockSize) {
76       this(new ByteArrayInputStream(data), blockSize);
77     }
78 
SmallBlockInputStream(InputStream in, int blockSize)79     public SmallBlockInputStream(InputStream in, int blockSize) {
80       super(in);
81       this.blockSize = blockSize;
82     }
83 
84     @Override
read(byte[] b)85     public int read(byte[] b) throws IOException {
86       return super.read(b, 0, Math.min(b.length, blockSize));
87     }
88 
89     @Override
read(byte[] b, int off, int len)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 
assertDataConsumed(byte[] data, CodedInputStream input)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    */
assertReadVarint(byte[] data, long value)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    */
assertReadVarintFailure( InvalidProtocolBufferException expected, byte[] data)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(). */
testReadVarint()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    */
assertReadLittleEndian32(byte[] data, int value)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    */
assertReadLittleEndian64(byte[] data, long value)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(). */
testReadLittleEndian()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(). */
testDecodeZigZag()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. */
testReadWholeMessage()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(). */
testSkipWholeMessage()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    */
testSkipRawBytesBug()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    */
testSkipRawBytesPastEndOfBufferWithLimit()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 
testReadHugeBlob()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 
testReadMaliciouslyLargeBlob()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 
makeRecursiveMessage(int depth)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 
assertMessageDepth(TestRecursiveMessage message, int depth)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 
testMaliciousRecursion()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 
checkSizeLimitExceeded(InvalidProtocolBufferException e)482   private void checkSizeLimitExceeded(InvalidProtocolBufferException e) {
483       assertEquals(
484           InvalidProtocolBufferException.sizeLimitExceeded().getMessage(),
485           e.getMessage());
486   }
487 
testSizeLimit()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 
testResetSizeCounter()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 
testSizeLimitMultipleMessages()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 
testReadString()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 
testReadStringRequireUtf8()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    */
testReadStringInvalidUtf8()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    */
testReadStringRequireUtf8InvalidUtf8()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 
testReadFromSlice()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 
testInvalidTag()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 
testReadByteArray()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 
testReadByteBuffer()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 
testReadByteBufferAliasing()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 
testCompatibleTypes()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