| OLD | NEW |
| 1 // Protocol Buffers - Google's data interchange format | 1 // Protocol Buffers - Google's data interchange format |
| 2 // Copyright 2008 Google Inc. All rights reserved. | 2 // Copyright 2008 Google Inc. All rights reserved. |
| 3 // https://developers.google.com/protocol-buffers/ | 3 // http://code.google.com/p/protobuf/ |
| 4 // | 4 // |
| 5 // Redistribution and use in source and binary forms, with or without | 5 // Redistribution and use in source and binary forms, with or without |
| 6 // modification, are permitted provided that the following conditions are | 6 // modification, are permitted provided that the following conditions are |
| 7 // met: | 7 // met: |
| 8 // | 8 // |
| 9 // * Redistributions of source code must retain the above copyright | 9 // * Redistributions of source code must retain the above copyright |
| 10 // notice, this list of conditions and the following disclaimer. | 10 // notice, this list of conditions and the following disclaimer. |
| 11 // * Redistributions in binary form must reproduce the above | 11 // * Redistributions in binary form must reproduce the above |
| 12 // copyright notice, this list of conditions and the following disclaimer | 12 // copyright notice, this list of conditions and the following disclaimer |
| 13 // in the documentation and/or other materials provided with the | 13 // in the documentation and/or other materials provided with the |
| 14 // distribution. | 14 // distribution. |
| 15 // * Neither the name of Google Inc. nor the names of its | 15 // * Neither the name of Google Inc. nor the names of its |
| 16 // contributors may be used to endorse or promote products derived from | 16 // contributors may be used to endorse or promote products derived from |
| 17 // this software without specific prior written permission. | 17 // this software without specific prior written permission. |
| 18 // | 18 // |
| 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | 21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | 22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | 23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 30 | 30 |
| 31 package com.google.protobuf; | 31 package com.google.protobuf.test; |
| 32 import com.google.protobuf.*; |
| 32 | 33 |
| 33 import protobuf_unittest.UnittestProto.BoolMessage; | |
| 34 import protobuf_unittest.UnittestProto.Int32Message; | |
| 35 import protobuf_unittest.UnittestProto.Int64Message; | |
| 36 import protobuf_unittest.UnittestProto.TestAllTypes; | 34 import protobuf_unittest.UnittestProto.TestAllTypes; |
| 37 import protobuf_unittest.UnittestProto.TestRecursiveMessage; | 35 import protobuf_unittest.UnittestProto.TestRecursiveMessage; |
| 38 | 36 |
| 39 import junit.framework.TestCase; | 37 import junit.framework.TestCase; |
| 40 | 38 |
| 41 import java.io.ByteArrayInputStream; | 39 import java.io.ByteArrayInputStream; |
| 42 import java.io.ByteArrayOutputStream; | |
| 43 import java.io.FilterInputStream; | 40 import java.io.FilterInputStream; |
| 41 import java.io.InputStream; |
| 44 import java.io.IOException; | 42 import java.io.IOException; |
| 45 import java.io.InputStream; | |
| 46 import java.nio.ByteBuffer; | |
| 47 | 43 |
| 48 /** | 44 /** |
| 49 * Unit test for {@link CodedInputStream}. | 45 * Unit test for {@link CodedInputStream}. |
| 50 * | 46 * |
| 51 * @author kenton@google.com Kenton Varda | 47 * @author kenton@google.com Kenton Varda |
| 52 */ | 48 */ |
| 53 public class CodedInputStreamTest extends TestCase { | 49 public class CodedInputStreamTest extends TestCase { |
| 54 /** | 50 /** |
| 55 * Helper to construct a byte array from a bunch of bytes. The inputs are | 51 * 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 | 52 * actually ints so that I can use hex notation and not get stupid errors |
| (...skipping 17 matching lines...) Expand all Loading... |
| 74 | 70 |
| 75 public SmallBlockInputStream(byte[] data, int blockSize) { | 71 public SmallBlockInputStream(byte[] data, int blockSize) { |
| 76 this(new ByteArrayInputStream(data), blockSize); | 72 this(new ByteArrayInputStream(data), blockSize); |
| 77 } | 73 } |
| 78 | 74 |
| 79 public SmallBlockInputStream(InputStream in, int blockSize) { | 75 public SmallBlockInputStream(InputStream in, int blockSize) { |
| 80 super(in); | 76 super(in); |
| 81 this.blockSize = blockSize; | 77 this.blockSize = blockSize; |
| 82 } | 78 } |
| 83 | 79 |
| 84 @Override | |
| 85 public int read(byte[] b) throws IOException { | 80 public int read(byte[] b) throws IOException { |
| 86 return super.read(b, 0, Math.min(b.length, blockSize)); | 81 return super.read(b, 0, Math.min(b.length, blockSize)); |
| 87 } | 82 } |
| 88 | 83 |
| 89 @Override | |
| 90 public int read(byte[] b, int off, int len) throws IOException { | 84 public int read(byte[] b, int off, int len) throws IOException { |
| 91 return super.read(b, off, Math.min(len, blockSize)); | 85 return super.read(b, off, Math.min(len, blockSize)); |
| 92 } | 86 } |
| 93 } | 87 } |
| 94 | 88 |
| 95 private void assertDataConsumed(byte[] data, CodedInputStream input) | |
| 96 throws IOException { | |
| 97 assertEquals(data.length, input.getTotalBytesRead()); | |
| 98 assertTrue(input.isAtEnd()); | |
| 99 } | |
| 100 | |
| 101 /** | 89 /** |
| 102 * Parses the given bytes using readRawVarint32() and readRawVarint64() and | 90 * Parses the given bytes using readRawVarint32() and readRawVarint64() and |
| 103 * checks that the result matches the given value. | 91 * checks that the result matches the given value. |
| 104 */ | 92 */ |
| 105 private void assertReadVarint(byte[] data, long value) throws Exception { | 93 private void assertReadVarint(byte[] data, long value) throws Exception { |
| 106 CodedInputStream input = CodedInputStream.newInstance(data); | 94 CodedInputStream input = CodedInputStream.newInstance(data); |
| 107 assertEquals((int) value, input.readRawVarint32()); | 95 assertEquals((int)value, input.readRawVarint32()); |
| 108 assertDataConsumed(data, input); | |
| 109 | 96 |
| 110 input = CodedInputStream.newInstance(data); | 97 input = CodedInputStream.newInstance(data); |
| 111 assertEquals(value, input.readRawVarint64()); | 98 assertEquals(value, input.readRawVarint64()); |
| 112 assertDataConsumed(data, input); | 99 assertTrue(input.isAtEnd()); |
| 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 | 100 |
| 122 // Try different block sizes. | 101 // Try different block sizes. |
| 123 for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { | 102 for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { |
| 124 input = CodedInputStream.newInstance( | 103 input = CodedInputStream.newInstance( |
| 125 new SmallBlockInputStream(data, blockSize)); | 104 new SmallBlockInputStream(data, blockSize)); |
| 126 assertEquals((int) value, input.readRawVarint32()); | 105 assertEquals((int)value, input.readRawVarint32()); |
| 127 assertDataConsumed(data, input); | |
| 128 | 106 |
| 129 input = CodedInputStream.newInstance( | 107 input = CodedInputStream.newInstance( |
| 130 new SmallBlockInputStream(data, blockSize)); | 108 new SmallBlockInputStream(data, blockSize)); |
| 131 assertEquals(value, input.readRawVarint64()); | 109 assertEquals(value, input.readRawVarint64()); |
| 132 assertDataConsumed(data, input); | 110 assertTrue(input.isAtEnd()); |
| 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 } | 111 } |
| 144 | 112 |
| 145 // Try reading direct from an InputStream. We want to verify that it | 113 // 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 | 114 // doesn't read past the end of the input, so we copy to a new, bigger |
| 147 // array first. | 115 // array first. |
| 148 byte[] longerData = new byte[data.length + 1]; | 116 byte[] longerData = new byte[data.length + 1]; |
| 149 System.arraycopy(data, 0, longerData, 0, data.length); | 117 System.arraycopy(data, 0, longerData, 0, data.length); |
| 150 InputStream rawInput = new ByteArrayInputStream(longerData); | 118 InputStream rawInput = new ByteArrayInputStream(longerData); |
| 151 assertEquals((int) value, CodedInputStream.readRawVarint32(rawInput)); | |
| 152 assertEquals(1, rawInput.available()); | |
| 153 } | 119 } |
| 154 | 120 |
| 155 /** | 121 /** |
| 156 * Parses the given bytes using readRawVarint32() and readRawVarint64() and | 122 * Parses the given bytes using readRawVarint32() and readRawVarint64() and |
| 157 * expects them to fail with an InvalidProtocolBufferException whose | 123 * expects them to fail with an InvalidProtocolBufferException whose |
| 158 * description matches the given one. | 124 * description matches the given one. |
| 159 */ | 125 */ |
| 160 private void assertReadVarintFailure( | 126 private void assertReadVarintFailure( |
| 161 InvalidProtocolBufferException expected, byte[] data) | 127 InvalidProtocolBufferException expected, byte[] data) |
| 162 throws Exception { | 128 throws Exception { |
| 163 CodedInputStream input = CodedInputStream.newInstance(data); | 129 CodedInputStream input = CodedInputStream.newInstance(data); |
| 164 try { | 130 try { |
| 165 input.readRawVarint32(); | 131 input.readRawVarint32(); |
| 166 fail("Should have thrown an exception."); | 132 fail("Should have thrown an exception."); |
| 167 } catch (InvalidProtocolBufferException e) { | 133 } catch (InvalidProtocolBufferException e) { |
| 168 assertEquals(expected.getMessage(), e.getMessage()); | 134 assertEquals(expected.getMessage(), e.getMessage()); |
| 169 } | 135 } |
| 170 | 136 |
| 171 input = CodedInputStream.newInstance(data); | 137 input = CodedInputStream.newInstance(data); |
| 172 try { | 138 try { |
| 173 input.readRawVarint64(); | 139 input.readRawVarint64(); |
| 174 fail("Should have thrown an exception."); | 140 fail("Should have thrown an exception."); |
| 175 } catch (InvalidProtocolBufferException e) { | 141 } catch (InvalidProtocolBufferException e) { |
| 176 assertEquals(expected.getMessage(), e.getMessage()); | 142 assertEquals(expected.getMessage(), e.getMessage()); |
| 177 } | 143 } |
| 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 } | 144 } |
| 195 | 145 |
| 196 /** Tests readRawVarint32() and readRawVarint64(). */ | 146 /** Tests readRawVarint32() and readRawVarint64(). */ |
| 197 public void testReadVarint() throws Exception { | 147 public void testReadVarint() throws Exception { |
| 198 assertReadVarint(bytes(0x00), 0); | 148 assertReadVarint(bytes(0x00), 0); |
| 199 assertReadVarint(bytes(0x01), 1); | 149 assertReadVarint(bytes(0x01), 1); |
| 200 assertReadVarint(bytes(0x7f), 127); | 150 assertReadVarint(bytes(0x7f), 127); |
| 201 // 14882 | 151 // 14882 |
| 202 assertReadVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7)); | 152 assertReadVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7)); |
| 203 // 2961488830 | 153 // 2961488830 |
| (...skipping 10 matching lines...) Expand all Loading... |
| 214 assertReadVarint( | 164 assertReadVarint( |
| 215 bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49), | 165 bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49), |
| 216 (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) | | 166 (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) | |
| 217 (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49)); | 167 (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49)); |
| 218 // 11964378330978735131 | 168 // 11964378330978735131 |
| 219 assertReadVarint( | 169 assertReadVarint( |
| 220 bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01), | 170 bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01), |
| 221 (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | | 171 (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | |
| 222 (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) | | 172 (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) | |
| 223 (0x05L << 49) | (0x26L << 56) | (0x01L << 63)); | 173 (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 } | 174 } |
| 234 | 175 |
| 235 /** | 176 /** |
| 236 * Parses the given bytes using readRawLittleEndian32() and checks | 177 * Parses the given bytes using readRawLittleEndian32() and checks |
| 237 * that the result matches the given value. | 178 * that the result matches the given value. |
| 238 */ | 179 */ |
| 239 private void assertReadLittleEndian32(byte[] data, int value) | 180 private void assertReadLittleEndian32(byte[] data, int value) |
| 240 throws Exception { | 181 throws Exception { |
| 241 CodedInputStream input = CodedInputStream.newInstance(data); | 182 CodedInputStream input = CodedInputStream.newInstance(data); |
| 242 assertEquals(value, input.readRawLittleEndian32()); | 183 assertEquals(value, input.readRawLittleEndian32()); |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 345 int tag = input1.readTag(); | 286 int tag = input1.readTag(); |
| 346 assertEquals(tag, input2.readTag()); | 287 assertEquals(tag, input2.readTag()); |
| 347 if (tag == 0) { | 288 if (tag == 0) { |
| 348 break; | 289 break; |
| 349 } | 290 } |
| 350 unknownFields.mergeFieldFrom(tag, input1); | 291 unknownFields.mergeFieldFrom(tag, input1); |
| 351 input2.skipField(tag); | 292 input2.skipField(tag); |
| 352 } | 293 } |
| 353 } | 294 } |
| 354 | 295 |
| 355 | |
| 356 /** | 296 /** |
| 357 * Test that a bug in skipRawBytes() has been fixed: if the skip skips | 297 * Test that a bug in skipRawBytes() has been fixed: if the skip skips |
| 358 * exactly up to a limit, this should not break things. | 298 * exactly up to a limit, this should not break things. |
| 359 */ | 299 */ |
| 360 public void testSkipRawBytesBug() throws Exception { | 300 public void testSkipRawBytesBug() throws Exception { |
| 361 byte[] rawBytes = new byte[] { 1, 2 }; | 301 byte[] rawBytes = new byte[] { 1, 2 }; |
| 362 CodedInputStream input = CodedInputStream.newInstance(rawBytes); | 302 CodedInputStream input = CodedInputStream.newInstance(rawBytes); |
| 363 | 303 |
| 364 int limit = input.pushLimit(1); | 304 int limit = input.pushLimit(1); |
| 365 input.skipRawBytes(1); | 305 input.skipRawBytes(1); |
| (...skipping 19 matching lines...) Expand all Loading... |
| 385 input.skipRawBytes(3); | 325 input.skipRawBytes(3); |
| 386 assertTrue(input.isAtEnd()); | 326 assertTrue(input.isAtEnd()); |
| 387 input.popLimit(limit); | 327 input.popLimit(limit); |
| 388 assertEquals(5, input.readRawByte()); | 328 assertEquals(5, input.readRawByte()); |
| 389 } | 329 } |
| 390 | 330 |
| 391 public void testReadHugeBlob() throws Exception { | 331 public void testReadHugeBlob() throws Exception { |
| 392 // Allocate and initialize a 1MB blob. | 332 // Allocate and initialize a 1MB blob. |
| 393 byte[] blob = new byte[1 << 20]; | 333 byte[] blob = new byte[1 << 20]; |
| 394 for (int i = 0; i < blob.length; i++) { | 334 for (int i = 0; i < blob.length; i++) { |
| 395 blob[i] = (byte) i; | 335 blob[i] = (byte)i; |
| 396 } | 336 } |
| 397 | 337 |
| 398 // Make a message containing it. | 338 // Make a message containing it. |
| 399 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); | 339 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); |
| 400 TestUtil.setAllFields(builder); | 340 TestUtil.setAllFields(builder); |
| 401 builder.setOptionalBytes(ByteString.copyFrom(blob)); | 341 builder.setOptionalBytes(ByteString.copyFrom(blob)); |
| 402 TestAllTypes message = builder.build(); | 342 TestAllTypes message = builder.build(); |
| 403 | 343 |
| 404 // Serialize and parse it. Make sure to parse from an InputStream, not | 344 // Serialize and parse it. Make sure to parse from an InputStream, not |
| 405 // directly from a ByteString, so that CodedInputStream uses buffered | 345 // directly from a ByteString, so that CodedInputStream uses buffered |
| 406 // reading. | 346 // reading. |
| 407 TestAllTypes message2 = | 347 TestAllTypes message2 = |
| 408 TestAllTypes.parseFrom(message.toByteString().newInput()); | 348 TestAllTypes.parseFrom(message.toByteString().newInput()); |
| 409 | 349 |
| 410 assertEquals(message.getOptionalBytes(), message2.getOptionalBytes()); | 350 assertEquals(message.getOptionalBytes(), message2.getOptionalBytes()); |
| 411 | 351 |
| 412 // Make sure all the other fields were parsed correctly. | 352 // Make sure all the other fields were parsed correctly. |
| 413 TestAllTypes message3 = TestAllTypes.newBuilder(message2) | 353 TestAllTypes message3 = TestAllTypes.newBuilder(message2) |
| 414 .setOptionalBytes(TestUtil.getAllSet().getOptionalBytes()) | 354 .setOptionalBytes(TestUtil.getAllSet().getOptionalBytes()) |
| 415 .build(); | 355 .build(); |
| 416 TestUtil.assertAllFieldsSet(message3); | 356 TestUtil.assertAllFieldsSet(message3); |
| 417 } | 357 } |
| 418 | 358 |
| 359 public int makeTag(int number, int tag) { |
| 360 return (number << 3) + tag; |
| 361 } |
| 362 |
| 419 public void testReadMaliciouslyLargeBlob() throws Exception { | 363 public void testReadMaliciouslyLargeBlob() throws Exception { |
| 420 ByteString.Output rawOutput = ByteString.newOutput(); | 364 ByteString.Output rawOutput = ByteString.newOutput(); |
| 421 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); | 365 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); |
| 422 | 366 |
| 423 int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); | 367 int tag = makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); |
| 424 output.writeRawVarint32(tag); | 368 output.writeRawVarint32(tag); |
| 425 output.writeRawVarint32(0x7FFFFFFF); | 369 output.writeRawVarint32(0x7FFFFFFF); |
| 426 output.writeRawBytes(new byte[32]); // Pad with a few random bytes. | 370 output.writeRawBytes(new byte[32]); // Pad with a few random bytes. |
| 427 output.flush(); | 371 output.flush(); |
| 428 | 372 |
| 429 CodedInputStream input = rawOutput.toByteString().newCodedInput(); | 373 CodedInputStream input = rawOutput.toByteString().newCodedInput(); |
| 430 assertEquals(tag, input.readTag()); | 374 assertEquals(tag, input.readTag()); |
| 431 | 375 |
| 432 try { | 376 try { |
| 433 input.readBytes(); | 377 input.readBytes(); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 449 private void assertMessageDepth(TestRecursiveMessage message, int depth) { | 393 private void assertMessageDepth(TestRecursiveMessage message, int depth) { |
| 450 if (depth == 0) { | 394 if (depth == 0) { |
| 451 assertFalse(message.hasA()); | 395 assertFalse(message.hasA()); |
| 452 assertEquals(5, message.getI()); | 396 assertEquals(5, message.getI()); |
| 453 } else { | 397 } else { |
| 454 assertTrue(message.hasA()); | 398 assertTrue(message.hasA()); |
| 455 assertMessageDepth(message.getA(), depth - 1); | 399 assertMessageDepth(message.getA(), depth - 1); |
| 456 } | 400 } |
| 457 } | 401 } |
| 458 | 402 |
| 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 { | 403 public void testResetSizeCounter() throws Exception { |
| 503 CodedInputStream input = CodedInputStream.newInstance( | 404 CodedInputStream input = CodedInputStream.newInstance( |
| 504 new SmallBlockInputStream(new byte[256], 8)); | 405 new SmallBlockInputStream(new byte[256], 8)); |
| 505 input.setSizeLimit(16); | 406 input.setSizeLimit(16); |
| 506 input.readRawBytes(16); | 407 input.readRawBytes(16); |
| 507 assertEquals(16, input.getTotalBytesRead()); | 408 assertEquals(16, input.getTotalBytesRead()); |
| 508 | 409 |
| 509 try { | 410 try { |
| 510 input.readRawByte(); | 411 input.readRawByte(); |
| 511 fail("Should have thrown an exception!"); | 412 fail("Should have thrown an exception!"); |
| 512 } catch (InvalidProtocolBufferException expected) { | 413 } catch (InvalidProtocolBufferException e) { |
| 513 checkSizeLimitExceeded(expected); | 414 // success. |
| 514 } | 415 } |
| 515 | 416 |
| 516 input.resetSizeCounter(); | 417 input.resetSizeCounter(); |
| 517 assertEquals(0, input.getTotalBytesRead()); | 418 assertEquals(0, input.getTotalBytesRead()); |
| 518 input.readRawByte(); // No exception thrown. | 419 input.readRawByte(); // No exception thrown. |
| 519 input.resetSizeCounter(); | 420 input.resetSizeCounter(); |
| 520 assertEquals(0, input.getTotalBytesRead()); | 421 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.le
ngth); | |
| 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.le
ngth); | |
| 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 } | 422 } |
| 601 | 423 |
| 602 /** | 424 /** |
| 603 * Tests that if we readString invalid UTF-8 bytes, no exception | 425 * Tests that if we read an string that contains invalid UTF-8, no exception |
| 604 * is thrown. Instead, the invalid bytes are replaced with the Unicode | 426 * is thrown. Instead, the invalid bytes are replaced with the Unicode |
| 605 * "replacement character" U+FFFD. | 427 * "replacement character" U+FFFD. |
| 606 */ | 428 */ |
| 607 public void testReadStringInvalidUtf8() throws Exception { | 429 public void testReadInvalidUtf8() throws Exception { |
| 608 ByteString.Output rawOutput = ByteString.newOutput(); | 430 ByteString.Output rawOutput = ByteString.newOutput(); |
| 609 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); | 431 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); |
| 610 | 432 |
| 611 int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); | 433 int tag = makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); |
| 612 output.writeRawVarint32(tag); | 434 output.writeRawVarint32(tag); |
| 613 output.writeRawVarint32(1); | 435 output.writeRawVarint32(1); |
| 614 output.writeRawBytes(new byte[] { (byte) 0x80 }); | 436 output.writeRawBytes(new byte[] { (byte)0x80 }); |
| 615 output.flush(); | 437 output.flush(); |
| 616 | 438 |
| 617 CodedInputStream input = rawOutput.toByteString().newCodedInput(); | 439 CodedInputStream input = rawOutput.toByteString().newCodedInput(); |
| 618 assertEquals(tag, input.readTag()); | 440 assertEquals(tag, input.readTag()); |
| 619 String text = input.readString(); | 441 String text = input.readString(); |
| 620 assertEquals(0xfffd, text.charAt(0)); | 442 assertEquals(0xfffd, text.charAt(0)); |
| 621 } | 443 } |
| 622 | 444 |
| 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 { | 445 public void testReadFromSlice() throws Exception { |
| 648 byte[] bytes = bytes(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); | 446 byte[] bytes = bytes(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); |
| 649 CodedInputStream in = CodedInputStream.newInstance(bytes, 3, 5); | 447 CodedInputStream in = CodedInputStream.newInstance(bytes, 3, 5); |
| 650 assertEquals(0, in.getTotalBytesRead()); | 448 assertEquals(0, in.getTotalBytesRead()); |
| 651 for (int i = 3; i < 8; i++) { | 449 for (int i = 3; i < 8; i++) { |
| 652 assertEquals(i, in.readRawByte()); | 450 assertEquals(i, in.readRawByte()); |
| 653 assertEquals(i - 2, in.getTotalBytesRead()); | 451 assertEquals(i-2, in.getTotalBytesRead()); |
| 654 } | 452 } |
| 655 // eof | 453 // eof |
| 656 assertEquals(0, in.readTag()); | 454 assertEquals(0, in.readTag()); |
| 657 assertEquals(5, in.getTotalBytesRead()); | 455 assertEquals(5, in.getTotalBytesRead()); |
| 658 } | 456 } |
| 659 | 457 |
| 660 public void testInvalidTag() throws Exception { | 458 public void testInvalidTag() throws Exception { |
| 661 // Any tag number which corresponds to field number zero is invalid and | 459 // Any tag number which corresponds to field number zero is invalid and |
| 662 // should throw InvalidProtocolBufferException. | 460 // should throw InvalidProtocolBufferException. |
| 663 for (int i = 0; i < 8; i++) { | 461 for (int i = 0; i < 8; i++) { |
| 664 try { | 462 try { |
| 665 CodedInputStream.newInstance(bytes(i)).readTag(); | 463 CodedInputStream.newInstance(bytes(i)).readTag(); |
| 666 fail("Should have thrown an exception."); | 464 fail("Should have thrown an exception."); |
| 667 } catch (InvalidProtocolBufferException e) { | 465 } catch (InvalidProtocolBufferException e) { |
| 668 assertEquals(InvalidProtocolBufferException.invalidTag().getMessage(), | |
| 669 e.getMessage()); | |
| 670 } | 466 } |
| 671 } | 467 } |
| 672 } | 468 } |
| 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 } | 469 } |
| OLD | NEW |