Upstream version 10.38.222.0
[platform/framework/web/crosswalk.git] / src / third_party / protobuf / java / src / test / java / com / google / protobuf / CodedInputStreamTest.java
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // http://code.google.com/p/protobuf/
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.TestAllTypes;
34 import protobuf_unittest.UnittestProto.TestRecursiveMessage;
35
36 import junit.framework.TestCase;
37
38 import java.io.ByteArrayInputStream;
39 import java.io.FilterInputStream;
40 import java.io.InputStream;
41 import java.io.IOException;
42
43 /**
44  * Unit test for {@link CodedInputStream}.
45  *
46  * @author kenton@google.com Kenton Varda
47  */
48 public class CodedInputStreamTest extends TestCase {
49   /**
50    * Helper to construct a byte array from a bunch of bytes.  The inputs are
51    * actually ints so that I can use hex notation and not get stupid errors
52    * about precision.
53    */
54   private byte[] bytes(int... bytesAsInts) {
55     byte[] bytes = new byte[bytesAsInts.length];
56     for (int i = 0; i < bytesAsInts.length; i++) {
57       bytes[i] = (byte) bytesAsInts[i];
58     }
59     return bytes;
60   }
61
62   /**
63    * An InputStream which limits the number of bytes it reads at a time.
64    * We use this to make sure that CodedInputStream doesn't screw up when
65    * reading in small blocks.
66    */
67   private static final class SmallBlockInputStream extends FilterInputStream {
68     private final int blockSize;
69
70     public SmallBlockInputStream(byte[] data, int blockSize) {
71       this(new ByteArrayInputStream(data), blockSize);
72     }
73
74     public SmallBlockInputStream(InputStream in, int blockSize) {
75       super(in);
76       this.blockSize = blockSize;
77     }
78
79     public int read(byte[] b) throws IOException {
80       return super.read(b, 0, Math.min(b.length, blockSize));
81     }
82
83     public int read(byte[] b, int off, int len) throws IOException {
84       return super.read(b, off, Math.min(len, blockSize));
85     }
86   }
87
88   /**
89    * Parses the given bytes using readRawVarint32() and readRawVarint64() and
90    * checks that the result matches the given value.
91    */
92   private void assertReadVarint(byte[] data, long value) throws Exception {
93     CodedInputStream input = CodedInputStream.newInstance(data);
94     assertEquals((int)value, input.readRawVarint32());
95
96     input = CodedInputStream.newInstance(data);
97     assertEquals(value, input.readRawVarint64());
98     assertTrue(input.isAtEnd());
99
100     // Try different block sizes.
101     for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
102       input = CodedInputStream.newInstance(
103         new SmallBlockInputStream(data, blockSize));
104       assertEquals((int)value, input.readRawVarint32());
105
106       input = CodedInputStream.newInstance(
107         new SmallBlockInputStream(data, blockSize));
108       assertEquals(value, input.readRawVarint64());
109       assertTrue(input.isAtEnd());
110     }
111
112     // Try reading direct from an InputStream.  We want to verify that it
113     // doesn't read past the end of the input, so we copy to a new, bigger
114     // array first.
115     byte[] longerData = new byte[data.length + 1];
116     System.arraycopy(data, 0, longerData, 0, data.length);
117     InputStream rawInput = new ByteArrayInputStream(longerData);
118     assertEquals((int)value, CodedInputStream.readRawVarint32(rawInput));
119     assertEquals(1, rawInput.available());
120   }
121
122   /**
123    * Parses the given bytes using readRawVarint32() and readRawVarint64() and
124    * expects them to fail with an InvalidProtocolBufferException whose
125    * description matches the given one.
126    */
127   private void assertReadVarintFailure(
128       InvalidProtocolBufferException expected, byte[] data)
129       throws Exception {
130     CodedInputStream input = CodedInputStream.newInstance(data);
131     try {
132       input.readRawVarint32();
133       fail("Should have thrown an exception.");
134     } catch (InvalidProtocolBufferException e) {
135       assertEquals(expected.getMessage(), e.getMessage());
136     }
137
138     input = CodedInputStream.newInstance(data);
139     try {
140       input.readRawVarint64();
141       fail("Should have thrown an exception.");
142     } catch (InvalidProtocolBufferException e) {
143       assertEquals(expected.getMessage(), e.getMessage());
144     }
145
146     // Make sure we get the same error when reading direct from an InputStream.
147     try {
148       CodedInputStream.readRawVarint32(new ByteArrayInputStream(data));
149       fail("Should have thrown an exception.");
150     } catch (InvalidProtocolBufferException e) {
151       assertEquals(expected.getMessage(), e.getMessage());
152     }
153   }
154
155   /** Tests readRawVarint32() and readRawVarint64(). */
156   public void testReadVarint() throws Exception {
157     assertReadVarint(bytes(0x00), 0);
158     assertReadVarint(bytes(0x01), 1);
159     assertReadVarint(bytes(0x7f), 127);
160     // 14882
161     assertReadVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7));
162     // 2961488830
163     assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b),
164       (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
165       (0x0bL << 28));
166
167     // 64-bit
168     // 7256456126
169     assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b),
170       (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) |
171       (0x1bL << 28));
172     // 41256202580718336
173     assertReadVarint(
174       bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49),
175       (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) |
176       (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49));
177     // 11964378330978735131
178     assertReadVarint(
179       bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01),
180       (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) |
181       (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) |
182       (0x05L << 49) | (0x26L << 56) | (0x01L << 63));
183
184     // Failures
185     assertReadVarintFailure(
186       InvalidProtocolBufferException.malformedVarint(),
187       bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
188             0x00));
189     assertReadVarintFailure(
190       InvalidProtocolBufferException.truncatedMessage(),
191       bytes(0x80));
192   }
193
194   /**
195    * Parses the given bytes using readRawLittleEndian32() and checks
196    * that the result matches the given value.
197    */
198   private void assertReadLittleEndian32(byte[] data, int value)
199                                         throws Exception {
200     CodedInputStream input = CodedInputStream.newInstance(data);
201     assertEquals(value, input.readRawLittleEndian32());
202     assertTrue(input.isAtEnd());
203
204     // Try different block sizes.
205     for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
206       input = CodedInputStream.newInstance(
207         new SmallBlockInputStream(data, blockSize));
208       assertEquals(value, input.readRawLittleEndian32());
209       assertTrue(input.isAtEnd());
210     }
211   }
212
213   /**
214    * Parses the given bytes using readRawLittleEndian64() and checks
215    * that the result matches the given value.
216    */
217   private void assertReadLittleEndian64(byte[] data, long value)
218                                         throws Exception {
219     CodedInputStream input = CodedInputStream.newInstance(data);
220     assertEquals(value, input.readRawLittleEndian64());
221     assertTrue(input.isAtEnd());
222
223     // Try different block sizes.
224     for (int blockSize = 1; blockSize <= 16; blockSize *= 2) {
225       input = CodedInputStream.newInstance(
226         new SmallBlockInputStream(data, blockSize));
227       assertEquals(value, input.readRawLittleEndian64());
228       assertTrue(input.isAtEnd());
229     }
230   }
231
232   /** Tests readRawLittleEndian32() and readRawLittleEndian64(). */
233   public void testReadLittleEndian() throws Exception {
234     assertReadLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678);
235     assertReadLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0);
236
237     assertReadLittleEndian64(
238       bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12),
239       0x123456789abcdef0L);
240     assertReadLittleEndian64(
241       bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a),
242       0x9abcdef012345678L);
243   }
244
245   /** Test decodeZigZag32() and decodeZigZag64(). */
246   public void testDecodeZigZag() throws Exception {
247     assertEquals( 0, CodedInputStream.decodeZigZag32(0));
248     assertEquals(-1, CodedInputStream.decodeZigZag32(1));
249     assertEquals( 1, CodedInputStream.decodeZigZag32(2));
250     assertEquals(-2, CodedInputStream.decodeZigZag32(3));
251     assertEquals(0x3FFFFFFF, CodedInputStream.decodeZigZag32(0x7FFFFFFE));
252     assertEquals(0xC0000000, CodedInputStream.decodeZigZag32(0x7FFFFFFF));
253     assertEquals(0x7FFFFFFF, CodedInputStream.decodeZigZag32(0xFFFFFFFE));
254     assertEquals(0x80000000, CodedInputStream.decodeZigZag32(0xFFFFFFFF));
255
256     assertEquals( 0, CodedInputStream.decodeZigZag64(0));
257     assertEquals(-1, CodedInputStream.decodeZigZag64(1));
258     assertEquals( 1, CodedInputStream.decodeZigZag64(2));
259     assertEquals(-2, CodedInputStream.decodeZigZag64(3));
260     assertEquals(0x000000003FFFFFFFL,
261                  CodedInputStream.decodeZigZag64(0x000000007FFFFFFEL));
262     assertEquals(0xFFFFFFFFC0000000L,
263                  CodedInputStream.decodeZigZag64(0x000000007FFFFFFFL));
264     assertEquals(0x000000007FFFFFFFL,
265                  CodedInputStream.decodeZigZag64(0x00000000FFFFFFFEL));
266     assertEquals(0xFFFFFFFF80000000L,
267                  CodedInputStream.decodeZigZag64(0x00000000FFFFFFFFL));
268     assertEquals(0x7FFFFFFFFFFFFFFFL,
269                  CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFEL));
270     assertEquals(0x8000000000000000L,
271                  CodedInputStream.decodeZigZag64(0xFFFFFFFFFFFFFFFFL));
272   }
273
274   /** Tests reading and parsing a whole message with every field type. */
275   public void testReadWholeMessage() throws Exception {
276     TestAllTypes message = TestUtil.getAllSet();
277
278     byte[] rawBytes = message.toByteArray();
279     assertEquals(rawBytes.length, message.getSerializedSize());
280
281     TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes);
282     TestUtil.assertAllFieldsSet(message2);
283
284     // Try different block sizes.
285     for (int blockSize = 1; blockSize < 256; blockSize *= 2) {
286       message2 = TestAllTypes.parseFrom(
287         new SmallBlockInputStream(rawBytes, blockSize));
288       TestUtil.assertAllFieldsSet(message2);
289     }
290   }
291
292   /** Tests skipField(). */
293   public void testSkipWholeMessage() throws Exception {
294     TestAllTypes message = TestUtil.getAllSet();
295     byte[] rawBytes = message.toByteArray();
296
297     // Create two parallel inputs.  Parse one as unknown fields while using
298     // skipField() to skip each field on the other.  Expect the same tags.
299     CodedInputStream input1 = CodedInputStream.newInstance(rawBytes);
300     CodedInputStream input2 = CodedInputStream.newInstance(rawBytes);
301     UnknownFieldSet.Builder unknownFields = UnknownFieldSet.newBuilder();
302
303     while (true) {
304       int tag = input1.readTag();
305       assertEquals(tag, input2.readTag());
306       if (tag == 0) {
307         break;
308       }
309       unknownFields.mergeFieldFrom(tag, input1);
310       input2.skipField(tag);
311     }
312   }
313
314   /**
315    * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
316    * exactly up to a limit, this should not break things.
317    */
318   public void testSkipRawBytesBug() throws Exception {
319     byte[] rawBytes = new byte[] { 1, 2 };
320     CodedInputStream input = CodedInputStream.newInstance(rawBytes);
321
322     int limit = input.pushLimit(1);
323     input.skipRawBytes(1);
324     input.popLimit(limit);
325     assertEquals(2, input.readRawByte());
326   }
327
328   /**
329    * Test that a bug in skipRawBytes() has been fixed:  if the skip skips
330    * past the end of a buffer with a limit that has been set past the end of
331    * that buffer, this should not break things.
332    */
333   public void testSkipRawBytesPastEndOfBufferWithLimit() throws Exception {
334     byte[] rawBytes = new byte[] { 1, 2, 3, 4, 5 };
335     CodedInputStream input = CodedInputStream.newInstance(
336         new SmallBlockInputStream(rawBytes, 3));
337
338     int limit = input.pushLimit(4);
339     // In order to expose the bug we need to read at least one byte to prime the
340     // buffer inside the CodedInputStream.
341     assertEquals(1, input.readRawByte());
342     // Skip to the end of the limit.
343     input.skipRawBytes(3);
344     assertTrue(input.isAtEnd());
345     input.popLimit(limit);
346     assertEquals(5, input.readRawByte());
347   }
348
349   public void testReadHugeBlob() throws Exception {
350     // Allocate and initialize a 1MB blob.
351     byte[] blob = new byte[1 << 20];
352     for (int i = 0; i < blob.length; i++) {
353       blob[i] = (byte)i;
354     }
355
356     // Make a message containing it.
357     TestAllTypes.Builder builder = TestAllTypes.newBuilder();
358     TestUtil.setAllFields(builder);
359     builder.setOptionalBytes(ByteString.copyFrom(blob));
360     TestAllTypes message = builder.build();
361
362     // Serialize and parse it.  Make sure to parse from an InputStream, not
363     // directly from a ByteString, so that CodedInputStream uses buffered
364     // reading.
365     TestAllTypes message2 =
366       TestAllTypes.parseFrom(message.toByteString().newInput());
367
368     assertEquals(message.getOptionalBytes(), message2.getOptionalBytes());
369
370     // Make sure all the other fields were parsed correctly.
371     TestAllTypes message3 = TestAllTypes.newBuilder(message2)
372       .setOptionalBytes(TestUtil.getAllSet().getOptionalBytes())
373       .build();
374     TestUtil.assertAllFieldsSet(message3);
375   }
376
377   public void testReadMaliciouslyLargeBlob() throws Exception {
378     ByteString.Output rawOutput = ByteString.newOutput();
379     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
380
381     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
382     output.writeRawVarint32(tag);
383     output.writeRawVarint32(0x7FFFFFFF);
384     output.writeRawBytes(new byte[32]);  // Pad with a few random bytes.
385     output.flush();
386
387     CodedInputStream input = rawOutput.toByteString().newCodedInput();
388     assertEquals(tag, input.readTag());
389
390     try {
391       input.readBytes();
392       fail("Should have thrown an exception!");
393     } catch (InvalidProtocolBufferException e) {
394       // success.
395     }
396   }
397
398   private TestRecursiveMessage makeRecursiveMessage(int depth) {
399     if (depth == 0) {
400       return TestRecursiveMessage.newBuilder().setI(5).build();
401     } else {
402       return TestRecursiveMessage.newBuilder()
403         .setA(makeRecursiveMessage(depth - 1)).build();
404     }
405   }
406
407   private void assertMessageDepth(TestRecursiveMessage message, int depth) {
408     if (depth == 0) {
409       assertFalse(message.hasA());
410       assertEquals(5, message.getI());
411     } else {
412       assertTrue(message.hasA());
413       assertMessageDepth(message.getA(), depth - 1);
414     }
415   }
416
417   public void testMaliciousRecursion() throws Exception {
418     ByteString data64 = makeRecursiveMessage(64).toByteString();
419     ByteString data65 = makeRecursiveMessage(65).toByteString();
420
421     assertMessageDepth(TestRecursiveMessage.parseFrom(data64), 64);
422
423     try {
424       TestRecursiveMessage.parseFrom(data65);
425       fail("Should have thrown an exception!");
426     } catch (InvalidProtocolBufferException e) {
427       // success.
428     }
429
430     CodedInputStream input = data64.newCodedInput();
431     input.setRecursionLimit(8);
432     try {
433       TestRecursiveMessage.parseFrom(input);
434       fail("Should have thrown an exception!");
435     } catch (InvalidProtocolBufferException e) {
436       // success.
437     }
438   }
439
440   public void testSizeLimit() throws Exception {
441     CodedInputStream input = CodedInputStream.newInstance(
442       TestUtil.getAllSet().toByteString().newInput());
443     input.setSizeLimit(16);
444
445     try {
446       TestAllTypes.parseFrom(input);
447       fail("Should have thrown an exception!");
448     } catch (InvalidProtocolBufferException e) {
449       // success.
450     }
451   }
452
453   public void testResetSizeCounter() throws Exception {
454     CodedInputStream input = CodedInputStream.newInstance(
455         new SmallBlockInputStream(new byte[256], 8));
456     input.setSizeLimit(16);
457     input.readRawBytes(16);
458     assertEquals(16, input.getTotalBytesRead());
459
460     try {
461       input.readRawByte();
462       fail("Should have thrown an exception!");
463     } catch (InvalidProtocolBufferException e) {
464       // success.
465     }
466
467     input.resetSizeCounter();
468     assertEquals(0, input.getTotalBytesRead());
469     input.readRawByte();  // No exception thrown.
470     input.resetSizeCounter();
471     assertEquals(0, input.getTotalBytesRead());
472
473     try {
474       input.readRawBytes(16);  // Hits limit again.
475       fail("Should have thrown an exception!");
476     } catch (InvalidProtocolBufferException e) {
477       // success.
478     }
479   }
480
481   /**
482    * Tests that if we read an string that contains invalid UTF-8, no exception
483    * is thrown.  Instead, the invalid bytes are replaced with the Unicode
484    * "replacement character" U+FFFD.
485    */
486   public void testReadInvalidUtf8() throws Exception {
487     ByteString.Output rawOutput = ByteString.newOutput();
488     CodedOutputStream output = CodedOutputStream.newInstance(rawOutput);
489
490     int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED);
491     output.writeRawVarint32(tag);
492     output.writeRawVarint32(1);
493     output.writeRawBytes(new byte[] { (byte)0x80 });
494     output.flush();
495
496     CodedInputStream input = rawOutput.toByteString().newCodedInput();
497     assertEquals(tag, input.readTag());
498     String text = input.readString();
499     assertEquals(0xfffd, text.charAt(0));
500   }
501
502   public void testReadFromSlice() throws Exception {
503     byte[] bytes = bytes(0, 1, 2, 3, 4, 5, 6, 7, 8, 9);
504     CodedInputStream in = CodedInputStream.newInstance(bytes, 3, 5);
505     assertEquals(0, in.getTotalBytesRead());
506     for (int i = 3; i < 8; i++) {
507       assertEquals(i, in.readRawByte());
508       assertEquals(i-2, in.getTotalBytesRead());
509     }
510     // eof
511     assertEquals(0, in.readTag());
512     assertEquals(5, in.getTotalBytesRead());
513   }
514
515   public void testInvalidTag() throws Exception {
516     // Any tag number which corresponds to field number zero is invalid and
517     // should throw InvalidProtocolBufferException.
518     for (int i = 0; i < 8; i++) {
519       try {
520         CodedInputStream.newInstance(bytes(i)).readTag();
521         fail("Should have thrown an exception.");
522       } catch (InvalidProtocolBufferException e) {
523         assertEquals(InvalidProtocolBufferException.invalidTag().getMessage(),
524                      e.getMessage());
525       }
526     }
527   }
528 }