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 // https://developers.google.com/protocol-buffers/ |
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. |
(...skipping 17 matching lines...) Expand all Loading... |
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; |
32 | 32 |
33 import protobuf_unittest.UnittestProto.BoolMessage; | 33 import protobuf_unittest.UnittestProto.BoolMessage; |
34 import protobuf_unittest.UnittestProto.Int32Message; | 34 import protobuf_unittest.UnittestProto.Int32Message; |
35 import protobuf_unittest.UnittestProto.Int64Message; | 35 import protobuf_unittest.UnittestProto.Int64Message; |
36 import protobuf_unittest.UnittestProto.TestAllTypes; | 36 import protobuf_unittest.UnittestProto.TestAllTypes; |
37 import protobuf_unittest.UnittestProto.TestRecursiveMessage; | 37 import protobuf_unittest.UnittestProto.TestRecursiveMessage; |
| 38 |
| 39 import junit.framework.TestCase; |
| 40 |
38 import java.io.ByteArrayInputStream; | 41 import java.io.ByteArrayInputStream; |
39 import java.io.ByteArrayOutputStream; | 42 import java.io.ByteArrayOutputStream; |
40 import java.io.FilterInputStream; | 43 import java.io.FilterInputStream; |
41 import java.io.IOException; | 44 import java.io.IOException; |
42 import java.io.InputStream; | 45 import java.io.InputStream; |
43 import java.nio.ByteBuffer; | 46 import java.nio.ByteBuffer; |
44 import junit.framework.TestCase; | |
45 | 47 |
46 /** | 48 /** |
47 * Unit test for {@link CodedInputStream}. | 49 * Unit test for {@link CodedInputStream}. |
48 * | 50 * |
49 * @author kenton@google.com Kenton Varda | 51 * @author kenton@google.com Kenton Varda |
50 */ | 52 */ |
51 public class CodedInputStreamTest extends TestCase { | 53 public class CodedInputStreamTest extends TestCase { |
52 private enum InputType { | |
53 ARRAY { | |
54 @Override | |
55 CodedInputStream newDecoder(byte[] data, int blockSize) { | |
56 return CodedInputStream.newInstance(data); | |
57 } | |
58 }, | |
59 NIO_HEAP { | |
60 @Override | |
61 CodedInputStream newDecoder(byte[] data, int blockSize) { | |
62 return CodedInputStream.newInstance(ByteBuffer.wrap(data)); | |
63 } | |
64 }, | |
65 NIO_DIRECT { | |
66 @Override | |
67 CodedInputStream newDecoder(byte[] data, int blockSize) { | |
68 ByteBuffer buffer = ByteBuffer.allocateDirect(data.length); | |
69 buffer.put(data); | |
70 buffer.flip(); | |
71 return CodedInputStream.newInstance(buffer); | |
72 } | |
73 }, | |
74 STREAM { | |
75 @Override | |
76 CodedInputStream newDecoder(byte[] data, int blockSize) { | |
77 return CodedInputStream.newInstance(new SmallBlockInputStream(data, bloc
kSize)); | |
78 } | |
79 }; | |
80 | |
81 CodedInputStream newDecoder(byte[] data) { | |
82 return newDecoder(data, data.length); | |
83 } | |
84 | |
85 abstract CodedInputStream newDecoder(byte[] data, int blockSize); | |
86 } | |
87 | |
88 /** | 54 /** |
89 * Helper to construct a byte array from a bunch of bytes. The inputs are actu
ally ints so that I | 55 * Helper to construct a byte array from a bunch of bytes. The inputs are |
90 * can use hex notation and not get stupid errors about precision. | 56 * actually ints so that I can use hex notation and not get stupid errors |
| 57 * about precision. |
91 */ | 58 */ |
92 private byte[] bytes(int... bytesAsInts) { | 59 private byte[] bytes(int... bytesAsInts) { |
93 byte[] bytes = new byte[bytesAsInts.length]; | 60 byte[] bytes = new byte[bytesAsInts.length]; |
94 for (int i = 0; i < bytesAsInts.length; i++) { | 61 for (int i = 0; i < bytesAsInts.length; i++) { |
95 bytes[i] = (byte) bytesAsInts[i]; | 62 bytes[i] = (byte) bytesAsInts[i]; |
96 } | 63 } |
97 return bytes; | 64 return bytes; |
98 } | 65 } |
99 | 66 |
100 /** | 67 /** |
101 * An InputStream which limits the number of bytes it reads at a time. We use
this to make sure | 68 * An InputStream which limits the number of bytes it reads at a time. |
102 * that CodedInputStream doesn't screw up when reading in small blocks. | 69 * We use this to make sure that CodedInputStream doesn't screw up when |
| 70 * reading in small blocks. |
103 */ | 71 */ |
104 private static final class SmallBlockInputStream extends FilterInputStream { | 72 private static final class SmallBlockInputStream extends FilterInputStream { |
105 private final int blockSize; | 73 private final int blockSize; |
106 | 74 |
107 public SmallBlockInputStream(byte[] data, int blockSize) { | 75 public SmallBlockInputStream(byte[] data, int blockSize) { |
108 super(new ByteArrayInputStream(data)); | 76 this(new ByteArrayInputStream(data), blockSize); |
| 77 } |
| 78 |
| 79 public SmallBlockInputStream(InputStream in, int blockSize) { |
| 80 super(in); |
109 this.blockSize = blockSize; | 81 this.blockSize = blockSize; |
110 } | 82 } |
111 | 83 |
112 @Override | 84 @Override |
113 public int read(byte[] b) throws IOException { | 85 public int read(byte[] b) throws IOException { |
114 return super.read(b, 0, Math.min(b.length, blockSize)); | 86 return super.read(b, 0, Math.min(b.length, blockSize)); |
115 } | 87 } |
116 | 88 |
117 @Override | 89 @Override |
118 public int read(byte[] b, int off, int len) throws IOException { | 90 public int read(byte[] b, int off, int len) throws IOException { |
119 return super.read(b, off, Math.min(len, blockSize)); | 91 return super.read(b, off, Math.min(len, blockSize)); |
120 } | 92 } |
121 } | 93 } |
122 | 94 |
123 private void assertDataConsumed(String msg, byte[] data, CodedInputStream inpu
t) | 95 private void assertDataConsumed(byte[] data, CodedInputStream input) |
124 throws IOException { | 96 throws IOException { |
125 assertEquals(msg, data.length, input.getTotalBytesRead()); | 97 assertEquals(data.length, input.getTotalBytesRead()); |
126 assertTrue(msg, input.isAtEnd()); | 98 assertTrue(input.isAtEnd()); |
127 } | 99 } |
128 | 100 |
129 /** | 101 /** |
130 * Parses the given bytes using readRawVarint32() and readRawVarint64() and ch
ecks that the result | 102 * Parses the given bytes using readRawVarint32() and readRawVarint64() and |
131 * matches the given value. | 103 * checks that the result matches the given value. |
132 */ | 104 */ |
133 private void assertReadVarint(byte[] data, long value) throws Exception { | 105 private void assertReadVarint(byte[] data, long value) throws Exception { |
134 for (InputType inputType : InputType.values()) { | 106 CodedInputStream input = CodedInputStream.newInstance(data); |
135 // Try different block sizes. | 107 assertEquals((int) value, input.readRawVarint32()); |
136 for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { | 108 assertDataConsumed(data, input); |
137 CodedInputStream input = inputType.newDecoder(data, blockSize); | |
138 assertEquals(inputType.name(), (int) value, input.readRawVarint32()); | |
139 assertDataConsumed(inputType.name(), data, input); | |
140 | 109 |
141 input = inputType.newDecoder(data, blockSize); | 110 input = CodedInputStream.newInstance(data); |
142 assertEquals(inputType.name(), value, input.readRawVarint64()); | 111 assertEquals(value, input.readRawVarint64()); |
143 assertDataConsumed(inputType.name(), data, input); | 112 assertDataConsumed(data, input); |
144 | 113 |
145 input = inputType.newDecoder(data, blockSize); | 114 input = CodedInputStream.newInstance(data); |
146 assertEquals(inputType.name(), value, input.readRawVarint64SlowPath()); | 115 assertEquals(value, input.readRawVarint64SlowPath()); |
147 assertDataConsumed(inputType.name(), data, input); | 116 assertDataConsumed(data, input); |
148 | 117 |
149 input = inputType.newDecoder(data, blockSize); | 118 input = CodedInputStream.newInstance(data); |
150 assertTrue(inputType.name(), input.skipField(WireFormat.WIRETYPE_VARINT)
); | 119 assertTrue(input.skipField(WireFormat.WIRETYPE_VARINT)); |
151 assertDataConsumed(inputType.name(), data, input); | 120 assertDataConsumed(data, input); |
152 } | 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); |
153 } | 143 } |
154 | 144 |
155 // Try reading direct from an InputStream. We want to verify that it | 145 // Try reading direct from an InputStream. We want to verify that it |
156 // doesn't read past the end of the input, so we copy to a new, bigger | 146 // doesn't read past the end of the input, so we copy to a new, bigger |
157 // array first. | 147 // array first. |
158 byte[] longerData = new byte[data.length + 1]; | 148 byte[] longerData = new byte[data.length + 1]; |
159 System.arraycopy(data, 0, longerData, 0, data.length); | 149 System.arraycopy(data, 0, longerData, 0, data.length); |
160 InputStream rawInput = new ByteArrayInputStream(longerData); | 150 InputStream rawInput = new ByteArrayInputStream(longerData); |
161 assertEquals((int) value, CodedInputStream.readRawVarint32(rawInput)); | 151 assertEquals((int) value, CodedInputStream.readRawVarint32(rawInput)); |
162 assertEquals(1, rawInput.available()); | 152 assertEquals(1, rawInput.available()); |
163 } | 153 } |
164 | 154 |
165 /** | 155 /** |
166 * Parses the given bytes using readRawVarint32() and readRawVarint64() and ex
pects them to fail | 156 * Parses the given bytes using readRawVarint32() and readRawVarint64() and |
167 * with an InvalidProtocolBufferException whose description matches the given
one. | 157 * expects them to fail with an InvalidProtocolBufferException whose |
| 158 * description matches the given one. |
168 */ | 159 */ |
169 private void assertReadVarintFailure(InvalidProtocolBufferException expected,
byte[] data) | 160 private void assertReadVarintFailure( |
| 161 InvalidProtocolBufferException expected, byte[] data) |
170 throws Exception { | 162 throws Exception { |
171 for (InputType inputType : InputType.values()) { | 163 CodedInputStream input = CodedInputStream.newInstance(data); |
172 try { | 164 try { |
173 CodedInputStream input = inputType.newDecoder(data); | 165 input.readRawVarint32(); |
174 input.readRawVarint32(); | 166 fail("Should have thrown an exception."); |
175 fail(inputType.name() + ": Should have thrown an exception."); | 167 } catch (InvalidProtocolBufferException e) { |
176 } catch (InvalidProtocolBufferException e) { | 168 assertEquals(expected.getMessage(), e.getMessage()); |
177 assertEquals(inputType.name(), expected.getMessage(), e.getMessage()); | 169 } |
178 } | 170 |
179 try { | 171 input = CodedInputStream.newInstance(data); |
180 CodedInputStream input = inputType.newDecoder(data); | 172 try { |
181 input.readRawVarint64(); | 173 input.readRawVarint64(); |
182 fail(inputType.name() + ": Should have thrown an exception."); | 174 fail("Should have thrown an exception."); |
183 } catch (InvalidProtocolBufferException e) { | 175 } catch (InvalidProtocolBufferException e) { |
184 assertEquals(inputType.name(), expected.getMessage(), e.getMessage()); | 176 assertEquals(expected.getMessage(), e.getMessage()); |
185 } | 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()); |
186 } | 185 } |
187 | 186 |
188 // Make sure we get the same error when reading direct from an InputStream. | 187 // Make sure we get the same error when reading direct from an InputStream. |
189 try { | 188 try { |
190 CodedInputStream.readRawVarint32(new ByteArrayInputStream(data)); | 189 CodedInputStream.readRawVarint32(new ByteArrayInputStream(data)); |
191 fail("Should have thrown an exception."); | 190 fail("Should have thrown an exception."); |
192 } catch (InvalidProtocolBufferException e) { | 191 } catch (InvalidProtocolBufferException e) { |
193 assertEquals(expected.getMessage(), e.getMessage()); | 192 assertEquals(expected.getMessage(), e.getMessage()); |
194 } | 193 } |
195 } | 194 } |
196 | 195 |
197 /** Tests readRawVarint32() and readRawVarint64(). */ | 196 /** Tests readRawVarint32() and readRawVarint64(). */ |
198 public void testReadVarint() throws Exception { | 197 public void testReadVarint() throws Exception { |
199 assertReadVarint(bytes(0x00), 0); | 198 assertReadVarint(bytes(0x00), 0); |
200 assertReadVarint(bytes(0x01), 1); | 199 assertReadVarint(bytes(0x01), 1); |
201 assertReadVarint(bytes(0x7f), 127); | 200 assertReadVarint(bytes(0x7f), 127); |
202 // 14882 | 201 // 14882 |
203 assertReadVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7)); | 202 assertReadVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7)); |
204 // 2961488830 | 203 // 2961488830 |
205 assertReadVarint( | 204 assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b), |
206 bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b), | 205 (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | |
207 (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | (0x0bL << 28))
; | 206 (0x0bL << 28)); |
208 | 207 |
209 // 64-bit | 208 // 64-bit |
210 // 7256456126 | 209 // 7256456126 |
211 assertReadVarint( | 210 assertReadVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b), |
212 bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b), | 211 (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | |
213 (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | (0x1bL << 28))
; | 212 (0x1bL << 28)); |
214 // 41256202580718336 | 213 // 41256202580718336 |
215 assertReadVarint( | 214 assertReadVarint( |
216 bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49), | 215 bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49), |
217 (0x00 << 0) | 216 (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) | |
218 | (0x66 << 7) | 217 (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49)); |
219 | (0x6b << 14) | |
220 | (0x1c << 21) | |
221 | (0x43L << 28) | |
222 | (0x49L << 35) | |
223 | (0x24L << 42) | |
224 | (0x49L << 49)); | |
225 // 11964378330978735131 | 218 // 11964378330978735131 |
226 assertReadVarint( | 219 assertReadVarint( |
227 bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01), | 220 bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01), |
228 (0x1b << 0) | 221 (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | |
229 | (0x28 << 7) | 222 (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) | |
230 | (0x79 << 14) | 223 (0x05L << 49) | (0x26L << 56) | (0x01L << 63)); |
231 | (0x42 << 21) | |
232 | (0x3bL << 28) | |
233 | (0x56L << 35) | |
234 | (0x00L << 42) | |
235 | (0x05L << 49) | |
236 | (0x26L << 56) | |
237 | (0x01L << 63)); | |
238 | 224 |
239 // Failures | 225 // Failures |
240 assertReadVarintFailure( | 226 assertReadVarintFailure( |
241 InvalidProtocolBufferException.malformedVarint(), | 227 InvalidProtocolBufferException.malformedVarint(), |
242 bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00))
; | 228 bytes(0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, |
243 assertReadVarintFailure(InvalidProtocolBufferException.truncatedMessage(), b
ytes(0x80)); | 229 0x00)); |
| 230 assertReadVarintFailure( |
| 231 InvalidProtocolBufferException.truncatedMessage(), |
| 232 bytes(0x80)); |
244 } | 233 } |
245 | 234 |
246 /** | 235 /** |
247 * Parses the given bytes using readRawLittleEndian32() and checks that the re
sult matches the | 236 * Parses the given bytes using readRawLittleEndian32() and checks |
248 * given value. | 237 * that the result matches the given value. |
249 */ | 238 */ |
250 private void assertReadLittleEndian32(byte[] data, int value) throws Exception
{ | 239 private void assertReadLittleEndian32(byte[] data, int value) |
251 for (InputType inputType : InputType.values()) { | 240 throws Exception { |
252 // Try different block sizes. | 241 CodedInputStream input = CodedInputStream.newInstance(data); |
253 for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { | 242 assertEquals(value, input.readRawLittleEndian32()); |
254 CodedInputStream input = inputType.newDecoder(data, blockSize); | 243 assertTrue(input.isAtEnd()); |
255 assertEquals(inputType.name(), value, input.readRawLittleEndian32()); | 244 |
256 assertTrue(inputType.name(), input.isAtEnd()); | 245 // Try different block sizes. |
257 } | 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()); |
258 } | 251 } |
259 } | 252 } |
260 | 253 |
261 /** | 254 /** |
262 * Parses the given bytes using readRawLittleEndian64() and checks that the re
sult matches the | 255 * Parses the given bytes using readRawLittleEndian64() and checks |
263 * given value. | 256 * that the result matches the given value. |
264 */ | 257 */ |
265 private void assertReadLittleEndian64(byte[] data, long value) throws Exceptio
n { | 258 private void assertReadLittleEndian64(byte[] data, long value) |
266 for (InputType inputType : InputType.values()) { | 259 throws Exception { |
267 // Try different block sizes. | 260 CodedInputStream input = CodedInputStream.newInstance(data); |
268 for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { | 261 assertEquals(value, input.readRawLittleEndian64()); |
269 CodedInputStream input = inputType.newDecoder(data, blockSize); | 262 assertTrue(input.isAtEnd()); |
270 assertEquals(inputType.name(), value, input.readRawLittleEndian64()); | 263 |
271 assertTrue(inputType.name(), input.isAtEnd()); | 264 // Try different block sizes. |
272 } | 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()); |
273 } | 270 } |
274 } | 271 } |
275 | 272 |
276 /** Tests readRawLittleEndian32() and readRawLittleEndian64(). */ | 273 /** Tests readRawLittleEndian32() and readRawLittleEndian64(). */ |
277 public void testReadLittleEndian() throws Exception { | 274 public void testReadLittleEndian() throws Exception { |
278 assertReadLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678); | 275 assertReadLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678); |
279 assertReadLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0); | 276 assertReadLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0); |
280 | 277 |
281 assertReadLittleEndian64( | 278 assertReadLittleEndian64( |
282 bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12), 0x123456789abcdef
0L); | 279 bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12), |
| 280 0x123456789abcdef0L); |
283 assertReadLittleEndian64( | 281 assertReadLittleEndian64( |
284 bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef01234567
8L); | 282 bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), |
| 283 0x9abcdef012345678L); |
285 } | 284 } |
286 | 285 |
287 /** Test decodeZigZag32() and decodeZigZag64(). */ | 286 /** Test decodeZigZag32() and decodeZigZag64(). */ |
288 public void testDecodeZigZag() throws Exception { | 287 public void testDecodeZigZag() throws Exception { |
289 assertEquals(0, CodedInputStream.decodeZigZag32(0)); | 288 assertEquals( 0, CodedInputStream.decodeZigZag32(0)); |
290 assertEquals(-1, CodedInputStream.decodeZigZag32(1)); | 289 assertEquals(-1, CodedInputStream.decodeZigZag32(1)); |
291 assertEquals(1, CodedInputStream.decodeZigZag32(2)); | 290 assertEquals( 1, CodedInputStream.decodeZigZag32(2)); |
292 assertEquals(-2, CodedInputStream.decodeZigZag32(3)); | 291 assertEquals(-2, CodedInputStream.decodeZigZag32(3)); |
293 assertEquals(0x3FFFFFFF, CodedInputStream.decodeZigZag32(0x7FFFFFFE)); | 292 assertEquals(0x3FFFFFFF, CodedInputStream.decodeZigZag32(0x7FFFFFFE)); |
294 assertEquals(0xC0000000, CodedInputStream.decodeZigZag32(0x7FFFFFFF)); | 293 assertEquals(0xC0000000, CodedInputStream.decodeZigZag32(0x7FFFFFFF)); |
295 assertEquals(0x7FFFFFFF, CodedInputStream.decodeZigZag32(0xFFFFFFFE)); | 294 assertEquals(0x7FFFFFFF, CodedInputStream.decodeZigZag32(0xFFFFFFFE)); |
296 assertEquals(0x80000000, CodedInputStream.decodeZigZag32(0xFFFFFFFF)); | 295 assertEquals(0x80000000, CodedInputStream.decodeZigZag32(0xFFFFFFFF)); |
297 | 296 |
298 assertEquals(0, CodedInputStream.decodeZigZag64(0)); | 297 assertEquals( 0, CodedInputStream.decodeZigZag64(0)); |
299 assertEquals(-1, CodedInputStream.decodeZigZag64(1)); | 298 assertEquals(-1, CodedInputStream.decodeZigZag64(1)); |
300 assertEquals(1, CodedInputStream.decodeZigZag64(2)); | 299 assertEquals( 1, CodedInputStream.decodeZigZag64(2)); |
301 assertEquals(-2, CodedInputStream.decodeZigZag64(3)); | 300 assertEquals(-2, CodedInputStream.decodeZigZag64(3)); |
302 assertEquals(0x000000003FFFFFFFL, CodedInputStream.decodeZigZag64(0x00000000
7FFFFFFEL)); | 301 assertEquals(0x000000003FFFFFFFL, |
303 assertEquals(0xFFFFFFFFC0000000L, CodedInputStream.decodeZigZag64(0x00000000
7FFFFFFFL)); | 302 CodedInputStream.decodeZigZag64(0x000000007FFFFFFEL)); |
304 assertEquals(0x000000007FFFFFFFL, CodedInputStream.decodeZigZag64(0x00000000
FFFFFFFEL)); | 303 assertEquals(0xFFFFFFFFC0000000L, |
305 assertEquals(0xFFFFFFFF80000000L, CodedInputStream.decodeZigZag64(0x00000000
FFFFFFFFL)); | 304 CodedInputStream.decodeZigZag64(0x000000007FFFFFFFL)); |
306 assertEquals(0x7FFFFFFFFFFFFFFFL, CodedInputStream.decodeZigZag64(0xFFFFFFFF
FFFFFFFEL)); | 305 assertEquals(0x000000007FFFFFFFL, |
307 assertEquals(0x8000000000000000L, CodedInputStream.decodeZigZag64(0xFFFFFFFF
FFFFFFFFL)); | 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)); |
308 } | 313 } |
309 | 314 |
310 /** Tests reading and parsing a whole message with every field type. */ | 315 /** Tests reading and parsing a whole message with every field type. */ |
311 public void testReadWholeMessage() throws Exception { | 316 public void testReadWholeMessage() throws Exception { |
312 TestAllTypes message = TestUtil.getAllSet(); | 317 TestAllTypes message = TestUtil.getAllSet(); |
313 | 318 |
314 byte[] rawBytes = message.toByteArray(); | 319 byte[] rawBytes = message.toByteArray(); |
315 assertEquals(rawBytes.length, message.getSerializedSize()); | 320 assertEquals(rawBytes.length, message.getSerializedSize()); |
316 | 321 |
317 for (InputType inputType : InputType.values()) { | 322 TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes); |
318 // Try different block sizes. | 323 TestUtil.assertAllFieldsSet(message2); |
319 for (int blockSize = 1; blockSize < 256; blockSize *= 2) { | 324 |
320 TestAllTypes message2 = TestAllTypes.parseFrom(inputType.newDecoder(rawB
ytes, blockSize)); | 325 // Try different block sizes. |
321 TestUtil.assertAllFieldsSet(message2); | 326 for (int blockSize = 1; blockSize < 256; blockSize *= 2) { |
322 } | 327 message2 = TestAllTypes.parseFrom( |
| 328 new SmallBlockInputStream(rawBytes, blockSize)); |
| 329 TestUtil.assertAllFieldsSet(message2); |
323 } | 330 } |
324 } | 331 } |
325 | 332 |
326 /** Tests skipField(). */ | 333 /** Tests skipField(). */ |
327 public void testSkipWholeMessage() throws Exception { | 334 public void testSkipWholeMessage() throws Exception { |
328 TestAllTypes message = TestUtil.getAllSet(); | 335 TestAllTypes message = TestUtil.getAllSet(); |
329 byte[] rawBytes = message.toByteArray(); | 336 byte[] rawBytes = message.toByteArray(); |
330 | 337 |
331 InputType[] inputTypes = InputType.values(); | 338 // Create two parallel inputs. Parse one as unknown fields while using |
332 CodedInputStream[] inputs = new CodedInputStream[inputTypes.length]; | 339 // skipField() to skip each field on the other. Expect the same tags. |
333 for (int i = 0; i < inputs.length; ++i) { | 340 CodedInputStream input1 = CodedInputStream.newInstance(rawBytes); |
334 inputs[i] = inputTypes[i].newDecoder(rawBytes); | 341 CodedInputStream input2 = CodedInputStream.newInstance(rawBytes); |
335 } | |
336 UnknownFieldSet.Builder unknownFields = UnknownFieldSet.newBuilder(); | 342 UnknownFieldSet.Builder unknownFields = UnknownFieldSet.newBuilder(); |
337 | 343 |
338 while (true) { | 344 while (true) { |
339 CodedInputStream input1 = inputs[0]; | |
340 int tag = input1.readTag(); | 345 int tag = input1.readTag(); |
341 // Ensure that the rest match. | 346 assertEquals(tag, input2.readTag()); |
342 for (int i = 1; i < inputs.length; ++i) { | |
343 assertEquals(inputTypes[i].name(), tag, inputs[i].readTag()); | |
344 } | |
345 if (tag == 0) { | 347 if (tag == 0) { |
346 break; | 348 break; |
347 } | 349 } |
348 unknownFields.mergeFieldFrom(tag, input1); | 350 unknownFields.mergeFieldFrom(tag, input1); |
349 // Skip the field for the rest of the inputs. | 351 input2.skipField(tag); |
350 for (int i = 1; i < inputs.length; ++i) { | |
351 inputs[i].skipField(tag); | |
352 } | |
353 } | 352 } |
354 } | 353 } |
355 | 354 |
356 | 355 |
357 /** | 356 /** |
358 * Test that a bug in skipRawBytes() has been fixed: if the skip skips exactly
up to a limit, this | 357 * Test that a bug in skipRawBytes() has been fixed: if the skip skips |
359 * should not break things. | 358 * exactly up to a limit, this should not break things. |
360 */ | 359 */ |
361 public void testSkipRawBytesBug() throws Exception { | 360 public void testSkipRawBytesBug() throws Exception { |
362 byte[] rawBytes = new byte[] {1, 2}; | 361 byte[] rawBytes = new byte[] { 1, 2 }; |
363 for (InputType inputType : InputType.values()) { | 362 CodedInputStream input = CodedInputStream.newInstance(rawBytes); |
364 CodedInputStream input = inputType.newDecoder(rawBytes); | 363 |
365 int limit = input.pushLimit(1); | 364 int limit = input.pushLimit(1); |
366 input.skipRawBytes(1); | 365 input.skipRawBytes(1); |
367 input.popLimit(limit); | 366 input.popLimit(limit); |
368 assertEquals(inputType.name(), 2, input.readRawByte()); | 367 assertEquals(2, input.readRawByte()); |
369 } | |
370 } | 368 } |
371 | 369 |
372 /** | 370 /** |
373 * Test that a bug in skipRawBytes() has been fixed: if the skip skips past th
e end of a buffer | 371 * Test that a bug in skipRawBytes() has been fixed: if the skip skips |
374 * with a limit that has been set past the end of that buffer, this should not
break things. | 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. |
375 */ | 374 */ |
376 public void testSkipRawBytesPastEndOfBufferWithLimit() throws Exception { | 375 public void testSkipRawBytesPastEndOfBufferWithLimit() throws Exception { |
377 byte[] rawBytes = new byte[] {1, 2, 3, 4, 5}; | 376 byte[] rawBytes = new byte[] { 1, 2, 3, 4, 5 }; |
378 for (InputType inputType : InputType.values()) { | 377 CodedInputStream input = CodedInputStream.newInstance( |
379 CodedInputStream input = inputType.newDecoder(rawBytes); | 378 new SmallBlockInputStream(rawBytes, 3)); |
380 int limit = input.pushLimit(4); | 379 |
381 // In order to expose the bug we need to read at least one byte to prime t
he | 380 int limit = input.pushLimit(4); |
382 // buffer inside the CodedInputStream. | 381 // In order to expose the bug we need to read at least one byte to prime the |
383 assertEquals(inputType.name(), 1, input.readRawByte()); | 382 // buffer inside the CodedInputStream. |
384 // Skip to the end of the limit. | 383 assertEquals(1, input.readRawByte()); |
385 input.skipRawBytes(3); | 384 // Skip to the end of the limit. |
386 assertTrue(inputType.name(), input.isAtEnd()); | 385 input.skipRawBytes(3); |
387 input.popLimit(limit); | 386 assertTrue(input.isAtEnd()); |
388 assertEquals(inputType.name(), 5, input.readRawByte()); | 387 input.popLimit(limit); |
389 } | 388 assertEquals(5, input.readRawByte()); |
390 } | 389 } |
391 | 390 |
392 public void testReadHugeBlob() throws Exception { | 391 public void testReadHugeBlob() throws Exception { |
393 // Allocate and initialize a 1MB blob. | 392 // Allocate and initialize a 1MB blob. |
394 byte[] blob = new byte[1 << 20]; | 393 byte[] blob = new byte[1 << 20]; |
395 for (int i = 0; i < blob.length; i++) { | 394 for (int i = 0; i < blob.length; i++) { |
396 blob[i] = (byte) i; | 395 blob[i] = (byte) i; |
397 } | 396 } |
398 | 397 |
399 // Make a message containing it. | 398 // Make a message containing it. |
400 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); | 399 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); |
401 TestUtil.setAllFields(builder); | 400 TestUtil.setAllFields(builder); |
402 builder.setOptionalBytes(ByteString.copyFrom(blob)); | 401 builder.setOptionalBytes(ByteString.copyFrom(blob)); |
403 TestAllTypes message = builder.build(); | 402 TestAllTypes message = builder.build(); |
404 | 403 |
405 byte[] data = message.toByteArray(); | 404 // Serialize and parse it. Make sure to parse from an InputStream, not |
406 for (InputType inputType : InputType.values()) { | 405 // directly from a ByteString, so that CodedInputStream uses buffered |
407 // Serialize and parse it. Make sure to parse from an InputStream, not | 406 // reading. |
408 // directly from a ByteString, so that CodedInputStream uses buffered | 407 TestAllTypes message2 = |
409 // reading. | 408 TestAllTypes.parseFrom(message.toByteString().newInput()); |
410 TestAllTypes message2 = TestAllTypes.parseFrom(inputType.newDecoder(data))
; | |
411 | 409 |
412 assertEquals(inputType.name(), message.getOptionalBytes(), message2.getOpt
ionalBytes()); | 410 assertEquals(message.getOptionalBytes(), message2.getOptionalBytes()); |
413 | 411 |
414 // Make sure all the other fields were parsed correctly. | 412 // Make sure all the other fields were parsed correctly. |
415 TestAllTypes message3 = | 413 TestAllTypes message3 = TestAllTypes.newBuilder(message2) |
416 TestAllTypes.newBuilder(message2) | 414 .setOptionalBytes(TestUtil.getAllSet().getOptionalBytes()) |
417 .setOptionalBytes(TestUtil.getAllSet().getOptionalBytes()) | 415 .build(); |
418 .build(); | 416 TestUtil.assertAllFieldsSet(message3); |
419 TestUtil.assertAllFieldsSet(message3); | |
420 } | |
421 } | 417 } |
422 | 418 |
423 public void testReadMaliciouslyLargeBlob() throws Exception { | 419 public void testReadMaliciouslyLargeBlob() throws Exception { |
424 ByteString.Output rawOutput = ByteString.newOutput(); | 420 ByteString.Output rawOutput = ByteString.newOutput(); |
425 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); | 421 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); |
426 | 422 |
427 int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); | 423 int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); |
428 output.writeRawVarint32(tag); | 424 output.writeRawVarint32(tag); |
429 output.writeRawVarint32(0x7FFFFFFF); | 425 output.writeRawVarint32(0x7FFFFFFF); |
430 output.writeRawBytes(new byte[32]); // Pad with a few random bytes. | 426 output.writeRawBytes(new byte[32]); // Pad with a few random bytes. |
431 output.flush(); | 427 output.flush(); |
432 | 428 |
433 byte[] data = rawOutput.toByteString().toByteArray(); | 429 CodedInputStream input = rawOutput.toByteString().newCodedInput(); |
434 for (InputType inputType : InputType.values()) { | 430 assertEquals(tag, input.readTag()); |
435 CodedInputStream input = inputType.newDecoder(data); | 431 |
436 assertEquals(tag, input.readTag()); | 432 try { |
437 try { | 433 input.readBytes(); |
438 input.readBytes(); | 434 fail("Should have thrown an exception!"); |
439 fail(inputType.name() + ": Should have thrown an exception!"); | 435 } catch (InvalidProtocolBufferException e) { |
440 } catch (InvalidProtocolBufferException e) { | 436 // success. |
441 // success. | |
442 } | |
443 } | 437 } |
444 } | 438 } |
445 | 439 |
446 /** | |
447 * Test we can do messages that are up to CodedInputStream#DEFAULT_SIZE_LIMIT | |
448 * in size (2G or Integer#MAX_SIZE). | |
449 * @throws IOException | |
450 */ | |
451 public void testParseMessagesCloseTo2G() throws IOException { | |
452 byte[] serializedMessage = getBigSerializedMessage(); | |
453 // How many of these big messages do we need to take us near our 2G limit? | |
454 int count = Integer.MAX_VALUE / serializedMessage.length; | |
455 // Now make an inputstream that will fake a near 2G message of messages | |
456 // returning our big serialized message 'count' times. | |
457 InputStream is = new RepeatingInputStream(serializedMessage, count); | |
458 // Parse should succeed! | |
459 TestAllTypes.parseFrom(is); | |
460 } | |
461 | |
462 /** | |
463 * Test there is an exception if a message exceeds | |
464 * CodedInputStream#DEFAULT_SIZE_LIMIT in size (2G or Integer#MAX_SIZE). | |
465 * @throws IOException | |
466 */ | |
467 public void testParseMessagesOver2G() throws IOException { | |
468 byte[] serializedMessage = getBigSerializedMessage(); | |
469 // How many of these big messages do we need to take us near our 2G limit? | |
470 int count = Integer.MAX_VALUE / serializedMessage.length; | |
471 // Now add one to take us over the limit | |
472 count++; | |
473 // Now make an inputstream that will fake a near 2G message of messages | |
474 // returning our big serialized message 'count' times. | |
475 InputStream is = new RepeatingInputStream(serializedMessage, count); | |
476 try { | |
477 TestAllTypes.parseFrom(is); | |
478 fail("Should have thrown an exception!"); | |
479 } catch (InvalidProtocolBufferException e) { | |
480 assertTrue(e.getMessage().contains("too large")); | |
481 } | |
482 } | |
483 | |
484 /* | |
485 * @return A serialized big message. | |
486 */ | |
487 private static byte[] getBigSerializedMessage() { | |
488 byte[] value = new byte[16 * 1024 * 1024]; | |
489 ByteString bsValue = ByteString.wrap(value); | |
490 return TestAllTypes.newBuilder().setOptionalBytes(bsValue).build().toByteArr
ay(); | |
491 } | |
492 | |
493 /* | |
494 * An input stream that repeats a byte arrays' content a number of times. | |
495 * Simulates really large input without consuming loads of memory. Used above | |
496 * to test the parsing behavior when the input size exceeds 2G or close to it. | |
497 */ | |
498 private static class RepeatingInputStream extends InputStream { | |
499 private final byte[] serializedMessage; | |
500 private final int count; | |
501 private int index = 0; | |
502 private int offset = 0; | |
503 | |
504 RepeatingInputStream(byte[] serializedMessage, int count) { | |
505 this.serializedMessage = serializedMessage; | |
506 this.count = count; | |
507 } | |
508 | |
509 @Override | |
510 public int read() throws IOException { | |
511 if (this.offset == this.serializedMessage.length) { | |
512 this.index++; | |
513 this.offset = 0; | |
514 } | |
515 if (this.index == this.count) { | |
516 return -1; | |
517 } | |
518 return this.serializedMessage[offset++]; | |
519 } | |
520 } | |
521 | |
522 private TestRecursiveMessage makeRecursiveMessage(int depth) { | 440 private TestRecursiveMessage makeRecursiveMessage(int depth) { |
523 if (depth == 0) { | 441 if (depth == 0) { |
524 return TestRecursiveMessage.newBuilder().setI(5).build(); | 442 return TestRecursiveMessage.newBuilder().setI(5).build(); |
525 } else { | 443 } else { |
526 return TestRecursiveMessage.newBuilder().setA(makeRecursiveMessage(depth -
1)).build(); | 444 return TestRecursiveMessage.newBuilder() |
| 445 .setA(makeRecursiveMessage(depth - 1)).build(); |
527 } | 446 } |
528 } | 447 } |
529 | 448 |
530 private void assertMessageDepth(String msg, TestRecursiveMessage message, int
depth) { | 449 private void assertMessageDepth(TestRecursiveMessage message, int depth) { |
531 if (depth == 0) { | 450 if (depth == 0) { |
532 assertFalse(msg, message.hasA()); | 451 assertFalse(message.hasA()); |
533 assertEquals(msg, 5, message.getI()); | 452 assertEquals(5, message.getI()); |
534 } else { | 453 } else { |
535 assertTrue(msg, message.hasA()); | 454 assertTrue(message.hasA()); |
536 assertMessageDepth(msg, message.getA(), depth - 1); | 455 assertMessageDepth(message.getA(), depth - 1); |
537 } | 456 } |
538 } | 457 } |
539 | 458 |
540 public void testMaliciousRecursion() throws Exception { | 459 public void testMaliciousRecursion() throws Exception { |
541 byte[] data100 = makeRecursiveMessage(100).toByteArray(); | 460 ByteString data100 = makeRecursiveMessage(100).toByteString(); |
542 byte[] data101 = makeRecursiveMessage(101).toByteArray(); | 461 ByteString data101 = makeRecursiveMessage(101).toByteString(); |
543 | 462 |
544 for (InputType inputType : InputType.values()) { | 463 assertMessageDepth(TestRecursiveMessage.parseFrom(data100), 100); |
545 assertMessageDepth( | |
546 inputType.name(), TestRecursiveMessage.parseFrom(inputType.newDecoder(
data100)), 100); | |
547 | 464 |
548 try { | 465 try { |
549 TestRecursiveMessage.parseFrom(inputType.newDecoder(data101)); | 466 TestRecursiveMessage.parseFrom(data101); |
550 fail("Should have thrown an exception!"); | 467 fail("Should have thrown an exception!"); |
551 } catch (InvalidProtocolBufferException e) { | 468 } catch (InvalidProtocolBufferException e) { |
552 // success. | 469 // success. |
553 } | 470 } |
554 | 471 |
555 CodedInputStream input = inputType.newDecoder(data100); | 472 CodedInputStream input = data100.newCodedInput(); |
556 input.setRecursionLimit(8); | 473 input.setRecursionLimit(8); |
557 try { | 474 try { |
558 TestRecursiveMessage.parseFrom(input); | 475 TestRecursiveMessage.parseFrom(input); |
559 fail(inputType.name() + ": Should have thrown an exception!"); | 476 fail("Should have thrown an exception!"); |
560 } catch (InvalidProtocolBufferException e) { | 477 } catch (InvalidProtocolBufferException e) { |
561 // success. | 478 // success. |
562 } | |
563 } | 479 } |
564 } | 480 } |
565 | 481 |
566 private void checkSizeLimitExceeded(InvalidProtocolBufferException e) { | 482 private void checkSizeLimitExceeded(InvalidProtocolBufferException e) { |
567 assertEquals(InvalidProtocolBufferException.sizeLimitExceeded().getMessage()
, e.getMessage()); | 483 assertEquals( |
| 484 InvalidProtocolBufferException.sizeLimitExceeded().getMessage(), |
| 485 e.getMessage()); |
568 } | 486 } |
569 | 487 |
570 public void testSizeLimit() throws Exception { | 488 public void testSizeLimit() throws Exception { |
571 // NOTE: Size limit only applies to the stream-backed CIS. | 489 CodedInputStream input = CodedInputStream.newInstance( |
572 CodedInputStream input = | 490 new SmallBlockInputStream( |
573 CodedInputStream.newInstance( | 491 TestUtil.getAllSet().toByteString().newInput(), 16)); |
574 new SmallBlockInputStream(TestUtil.getAllSet().toByteArray(), 16)); | |
575 input.setSizeLimit(16); | 492 input.setSizeLimit(16); |
576 | 493 |
577 try { | 494 try { |
578 TestAllTypes.parseFrom(input); | 495 TestAllTypes.parseFrom(input); |
579 fail("Should have thrown an exception!"); | 496 fail("Should have thrown an exception!"); |
580 } catch (InvalidProtocolBufferException expected) { | 497 } catch (InvalidProtocolBufferException expected) { |
581 checkSizeLimitExceeded(expected); | 498 checkSizeLimitExceeded(expected); |
582 } | 499 } |
583 } | 500 } |
584 | 501 |
585 public void testResetSizeCounter() throws Exception { | 502 public void testResetSizeCounter() throws Exception { |
586 // NOTE: Size limit only applies to the stream-backed CIS. | 503 CodedInputStream input = CodedInputStream.newInstance( |
587 CodedInputStream input = | 504 new SmallBlockInputStream(new byte[256], 8)); |
588 CodedInputStream.newInstance(new SmallBlockInputStream(new byte[256], 8)
); | |
589 input.setSizeLimit(16); | 505 input.setSizeLimit(16); |
590 input.readRawBytes(16); | 506 input.readRawBytes(16); |
591 assertEquals(16, input.getTotalBytesRead()); | 507 assertEquals(16, input.getTotalBytesRead()); |
592 | 508 |
593 try { | 509 try { |
594 input.readRawByte(); | 510 input.readRawByte(); |
595 fail("Should have thrown an exception!"); | 511 fail("Should have thrown an exception!"); |
596 } catch (InvalidProtocolBufferException expected) { | 512 } catch (InvalidProtocolBufferException expected) { |
597 checkSizeLimitExceeded(expected); | 513 checkSizeLimitExceeded(expected); |
598 } | 514 } |
599 | 515 |
600 input.resetSizeCounter(); | 516 input.resetSizeCounter(); |
601 assertEquals(0, input.getTotalBytesRead()); | 517 assertEquals(0, input.getTotalBytesRead()); |
602 input.readRawByte(); // No exception thrown. | 518 input.readRawByte(); // No exception thrown. |
603 input.resetSizeCounter(); | 519 input.resetSizeCounter(); |
604 assertEquals(0, input.getTotalBytesRead()); | 520 assertEquals(0, input.getTotalBytesRead()); |
605 input.readRawBytes(16); | 521 input.readRawBytes(16); |
606 assertEquals(16, input.getTotalBytesRead()); | 522 assertEquals(16, input.getTotalBytesRead()); |
607 input.resetSizeCounter(); | 523 input.resetSizeCounter(); |
608 | 524 |
609 try { | 525 try { |
610 input.readRawBytes(17); // Hits limit again. | 526 input.readRawBytes(17); // Hits limit again. |
611 fail("Should have thrown an exception!"); | 527 fail("Should have thrown an exception!"); |
612 } catch (InvalidProtocolBufferException expected) { | 528 } catch (InvalidProtocolBufferException expected) { |
613 checkSizeLimitExceeded(expected); | 529 checkSizeLimitExceeded(expected); |
614 } | 530 } |
615 } | 531 } |
616 | 532 |
617 public void testSizeLimitMultipleMessages() throws Exception { | 533 public void testSizeLimitMultipleMessages() throws Exception { |
618 // NOTE: Size limit only applies to the stream-backed CIS. | |
619 byte[] bytes = new byte[256]; | 534 byte[] bytes = new byte[256]; |
620 for (int i = 0; i < bytes.length; i++) { | 535 for (int i = 0; i < bytes.length; i++) { |
621 bytes[i] = (byte) i; | 536 bytes[i] = (byte) i; |
622 } | 537 } |
623 CodedInputStream input = CodedInputStream.newInstance(new SmallBlockInputStr
eam(bytes, 7)); | 538 CodedInputStream input = CodedInputStream.newInstance( |
| 539 new SmallBlockInputStream(bytes, 7)); |
624 input.setSizeLimit(16); | 540 input.setSizeLimit(16); |
625 for (int i = 0; i < 256 / 16; i++) { | 541 for (int i = 0; i < 256 / 16; i++) { |
626 byte[] message = input.readRawBytes(16); | 542 byte[] message = input.readRawBytes(16); |
627 for (int j = 0; j < message.length; j++) { | 543 for (int j = 0; j < message.length; j++) { |
628 assertEquals(i * 16 + j, message[j] & 0xff); | 544 assertEquals(i * 16 + j, message[j] & 0xff); |
629 } | 545 } |
630 assertEquals(16, input.getTotalBytesRead()); | 546 assertEquals(16, input.getTotalBytesRead()); |
631 input.resetSizeCounter(); | 547 input.resetSizeCounter(); |
632 assertEquals(0, input.getTotalBytesRead()); | 548 assertEquals(0, input.getTotalBytesRead()); |
633 } | 549 } |
634 } | 550 } |
635 | 551 |
636 public void testReadString() throws Exception { | 552 public void testReadString() throws Exception { |
637 String lorem = "Lorem ipsum dolor sit amet "; | 553 String lorem = "Lorem ipsum dolor sit amet "; |
638 StringBuilder builder = new StringBuilder(); | 554 StringBuilder builder = new StringBuilder(); |
639 for (int i = 0; i < 4096; i += lorem.length()) { | 555 for (int i = 0; i < 4096; i += lorem.length()) { |
640 builder.append(lorem); | 556 builder.append(lorem); |
641 } | 557 } |
642 lorem = builder.toString().substring(0, 4096); | 558 lorem = builder.toString().substring(0, 4096); |
643 byte[] bytes = lorem.getBytes("UTF-8"); | 559 byte[] bytes = lorem.getBytes("UTF-8"); |
644 ByteString.Output rawOutput = ByteString.newOutput(); | 560 ByteString.Output rawOutput = ByteString.newOutput(); |
645 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.le
ngth); | 561 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.le
ngth); |
646 | 562 |
647 int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); | 563 int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); |
648 output.writeRawVarint32(tag); | 564 output.writeRawVarint32(tag); |
649 output.writeRawVarint32(bytes.length); | 565 output.writeRawVarint32(bytes.length); |
650 output.writeRawBytes(bytes); | 566 output.writeRawBytes(bytes); |
651 output.flush(); | 567 output.flush(); |
652 | 568 |
653 byte[] rawInput = rawOutput.toByteString().toByteArray(); | 569 CodedInputStream input = |
654 for (InputType inputType : InputType.values()) { | 570 CodedInputStream.newInstance( |
655 CodedInputStream input = inputType.newDecoder(rawInput); | 571 new ByteArrayInputStream(rawOutput.toByteString().toByteArray())); |
656 assertEquals(inputType.name(), tag, input.readTag()); | 572 assertEquals(tag, input.readTag()); |
657 String text = input.readString(); | 573 String text = input.readString(); |
658 assertEquals(inputType.name(), lorem, text); | 574 assertEquals(lorem, text); |
659 } | |
660 } | 575 } |
661 | 576 |
662 public void testReadStringRequireUtf8() throws Exception { | 577 public void testReadStringRequireUtf8() throws Exception { |
663 String lorem = "Lorem ipsum dolor sit amet "; | 578 String lorem = "Lorem ipsum dolor sit amet "; |
664 StringBuilder builder = new StringBuilder(); | 579 StringBuilder builder = new StringBuilder(); |
665 for (int i = 0; i < 4096; i += lorem.length()) { | 580 for (int i = 0; i < 4096; i += lorem.length()) { |
666 builder.append(lorem); | 581 builder.append(lorem); |
667 } | 582 } |
668 lorem = builder.toString().substring(0, 4096); | 583 lorem = builder.toString().substring(0, 4096); |
669 byte[] bytes = lorem.getBytes("UTF-8"); | 584 byte[] bytes = lorem.getBytes("UTF-8"); |
670 ByteString.Output rawOutput = ByteString.newOutput(); | 585 ByteString.Output rawOutput = ByteString.newOutput(); |
671 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.le
ngth); | 586 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput, bytes.le
ngth); |
672 | 587 |
673 int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); | 588 int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); |
674 output.writeRawVarint32(tag); | 589 output.writeRawVarint32(tag); |
675 output.writeRawVarint32(bytes.length); | 590 output.writeRawVarint32(bytes.length); |
676 output.writeRawBytes(bytes); | 591 output.writeRawBytes(bytes); |
677 output.flush(); | 592 output.flush(); |
678 | 593 |
679 byte[] rawInput = rawOutput.toByteString().toByteArray(); | 594 CodedInputStream input = |
680 for (InputType inputType : InputType.values()) { | 595 CodedInputStream.newInstance( |
681 CodedInputStream input = inputType.newDecoder(rawInput); | 596 new ByteArrayInputStream(rawOutput.toByteString().toByteArray())); |
682 assertEquals(inputType.name(), tag, input.readTag()); | 597 assertEquals(tag, input.readTag()); |
683 String text = input.readStringRequireUtf8(); | 598 String text = input.readStringRequireUtf8(); |
684 assertEquals(inputType.name(), lorem, text); | 599 assertEquals(lorem, text); |
685 } | |
686 } | 600 } |
687 | 601 |
688 /** | 602 /** |
689 * Tests that if we readString invalid UTF-8 bytes, no exception is thrown. In
stead, the invalid | 603 * Tests that if we readString invalid UTF-8 bytes, no exception |
690 * bytes are replaced with the Unicode "replacement character" U+FFFD. | 604 * is thrown. Instead, the invalid bytes are replaced with the Unicode |
| 605 * "replacement character" U+FFFD. |
691 */ | 606 */ |
692 public void testReadStringInvalidUtf8() throws Exception { | 607 public void testReadStringInvalidUtf8() throws Exception { |
693 ByteString.Output rawOutput = ByteString.newOutput(); | 608 ByteString.Output rawOutput = ByteString.newOutput(); |
694 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); | 609 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); |
695 | 610 |
696 int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); | 611 int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); |
697 output.writeRawVarint32(tag); | 612 output.writeRawVarint32(tag); |
698 output.writeRawVarint32(1); | 613 output.writeRawVarint32(1); |
699 output.writeRawBytes(new byte[] {(byte) 0x80}); | 614 output.writeRawBytes(new byte[] { (byte) 0x80 }); |
700 output.flush(); | 615 output.flush(); |
701 | 616 |
702 byte[] rawInput = rawOutput.toByteString().toByteArray(); | 617 CodedInputStream input = rawOutput.toByteString().newCodedInput(); |
703 for (InputType inputType : InputType.values()) { | 618 assertEquals(tag, input.readTag()); |
704 CodedInputStream input = inputType.newDecoder(rawInput); | 619 String text = input.readString(); |
705 assertEquals(inputType.name(), tag, input.readTag()); | 620 assertEquals(0xfffd, text.charAt(0)); |
706 String text = input.readString(); | |
707 assertEquals(inputType.name(), 0xfffd, text.charAt(0)); | |
708 } | |
709 } | 621 } |
710 | 622 |
711 /** | 623 /** |
712 * Tests that if we readStringRequireUtf8 invalid UTF-8 bytes, an InvalidProto
colBufferException | 624 * Tests that if we readStringRequireUtf8 invalid UTF-8 bytes, an |
713 * is thrown. | 625 * InvalidProtocolBufferException is thrown. |
714 */ | 626 */ |
715 public void testReadStringRequireUtf8InvalidUtf8() throws Exception { | 627 public void testReadStringRequireUtf8InvalidUtf8() throws Exception { |
716 ByteString.Output rawOutput = ByteString.newOutput(); | 628 ByteString.Output rawOutput = ByteString.newOutput(); |
717 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); | 629 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); |
718 | 630 |
719 int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); | 631 int tag = WireFormat.makeTag(1, WireFormat.WIRETYPE_LENGTH_DELIMITED); |
720 output.writeRawVarint32(tag); | 632 output.writeRawVarint32(tag); |
721 output.writeRawVarint32(1); | 633 output.writeRawVarint32(1); |
722 output.writeRawBytes(new byte[] {(byte) 0x80}); | 634 output.writeRawBytes(new byte[] { (byte) 0x80 }); |
723 output.flush(); | 635 output.flush(); |
724 | 636 |
725 byte[] rawInput = rawOutput.toByteString().toByteArray(); | 637 CodedInputStream input = rawOutput.toByteString().newCodedInput(); |
726 for (InputType inputType : InputType.values()) { | 638 assertEquals(tag, input.readTag()); |
727 CodedInputStream input = inputType.newDecoder(rawInput); | 639 try { |
728 assertEquals(tag, input.readTag()); | 640 input.readStringRequireUtf8(); |
729 try { | 641 fail("Expected invalid UTF-8 exception."); |
730 input.readStringRequireUtf8(); | 642 } catch (InvalidProtocolBufferException exception) { |
731 fail(inputType.name() + ": Expected invalid UTF-8 exception."); | 643 assertEquals("Protocol message had invalid UTF-8.", exception.getMessage()
); |
732 } catch (InvalidProtocolBufferException exception) { | |
733 assertEquals( | |
734 inputType.name(), "Protocol message had invalid UTF-8.", exception.g
etMessage()); | |
735 } | |
736 } | 644 } |
737 } | 645 } |
738 | 646 |
739 public void testReadFromSlice() throws Exception { | 647 public void testReadFromSlice() throws Exception { |
740 byte[] bytes = bytes(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); | 648 byte[] bytes = bytes(0, 1, 2, 3, 4, 5, 6, 7, 8, 9); |
741 CodedInputStream in = CodedInputStream.newInstance(bytes, 3, 5); | 649 CodedInputStream in = CodedInputStream.newInstance(bytes, 3, 5); |
742 assertEquals(0, in.getTotalBytesRead()); | 650 assertEquals(0, in.getTotalBytesRead()); |
743 for (int i = 3; i < 8; i++) { | 651 for (int i = 3; i < 8; i++) { |
744 assertEquals(i, in.readRawByte()); | 652 assertEquals(i, in.readRawByte()); |
745 assertEquals(i - 2, in.getTotalBytesRead()); | 653 assertEquals(i - 2, in.getTotalBytesRead()); |
746 } | 654 } |
747 // eof | 655 // eof |
748 assertEquals(0, in.readTag()); | 656 assertEquals(0, in.readTag()); |
749 assertEquals(5, in.getTotalBytesRead()); | 657 assertEquals(5, in.getTotalBytesRead()); |
750 } | 658 } |
751 | 659 |
752 public void testInvalidTag() throws Exception { | 660 public void testInvalidTag() throws Exception { |
753 // Any tag number which corresponds to field number zero is invalid and | 661 // Any tag number which corresponds to field number zero is invalid and |
754 // should throw InvalidProtocolBufferException. | 662 // should throw InvalidProtocolBufferException. |
755 for (InputType inputType : InputType.values()) { | 663 for (int i = 0; i < 8; i++) { |
756 for (int i = 0; i < 8; i++) { | 664 try { |
757 try { | 665 CodedInputStream.newInstance(bytes(i)).readTag(); |
758 inputType.newDecoder(bytes(i)).readTag(); | 666 fail("Should have thrown an exception."); |
759 fail(inputType.name() + ": Should have thrown an exception."); | 667 } catch (InvalidProtocolBufferException e) { |
760 } catch (InvalidProtocolBufferException e) { | 668 assertEquals(InvalidProtocolBufferException.invalidTag().getMessage(), |
761 assertEquals( | 669 e.getMessage()); |
762 inputType.name(), | |
763 InvalidProtocolBufferException.invalidTag().getMessage(), | |
764 e.getMessage()); | |
765 } | |
766 } | 670 } |
767 } | 671 } |
768 } | 672 } |
769 | 673 |
770 public void testReadByteArray() throws Exception { | 674 public void testReadByteArray() throws Exception { |
771 ByteString.Output rawOutput = ByteString.newOutput(); | 675 ByteString.Output rawOutput = ByteString.newOutput(); |
772 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); | 676 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); |
773 // Zero-sized bytes field. | 677 // Zero-sized bytes field. |
774 output.writeRawVarint32(0); | 678 output.writeRawVarint32(0); |
775 // One one-byte bytes field | 679 // One one-byte bytes field |
776 output.writeRawVarint32(1); | 680 output.writeRawVarint32(1); |
777 output.writeRawBytes(new byte[] {(byte) 23}); | 681 output.writeRawBytes(new byte[] { (byte) 23 }); |
778 // Another one-byte bytes field | 682 // Another one-byte bytes field |
779 output.writeRawVarint32(1); | 683 output.writeRawVarint32(1); |
780 output.writeRawBytes(new byte[] {(byte) 45}); | 684 output.writeRawBytes(new byte[] { (byte) 45 }); |
781 // A bytes field large enough that won't fit into the 4K buffer. | 685 // A bytes field large enough that won't fit into the 4K buffer. |
782 final int bytesLength = 16 * 1024; | 686 final int bytesLength = 16 * 1024; |
783 byte[] bytes = new byte[bytesLength]; | 687 byte[] bytes = new byte[bytesLength]; |
784 bytes[0] = (byte) 67; | 688 bytes[0] = (byte) 67; |
785 bytes[bytesLength - 1] = (byte) 89; | 689 bytes[bytesLength - 1] = (byte) 89; |
786 output.writeRawVarint32(bytesLength); | 690 output.writeRawVarint32(bytesLength); |
787 output.writeRawBytes(bytes); | 691 output.writeRawBytes(bytes); |
788 | 692 |
789 output.flush(); | 693 output.flush(); |
| 694 CodedInputStream inputStream = rawOutput.toByteString().newCodedInput(); |
790 | 695 |
791 byte[] rawInput = rawOutput.toByteString().toByteArray(); | 696 byte[] result = inputStream.readByteArray(); |
792 for (InputType inputType : InputType.values()) { | 697 assertEquals(0, result.length); |
793 CodedInputStream inputStream = inputType.newDecoder(rawInput); | 698 result = inputStream.readByteArray(); |
794 | 699 assertEquals(1, result.length); |
795 byte[] result = inputStream.readByteArray(); | 700 assertEquals((byte) 23, result[0]); |
796 assertEquals(inputType.name(), 0, result.length); | 701 result = inputStream.readByteArray(); |
797 result = inputStream.readByteArray(); | 702 assertEquals(1, result.length); |
798 assertEquals(inputType.name(), 1, result.length); | 703 assertEquals((byte) 45, result[0]); |
799 assertEquals(inputType.name(), (byte) 23, result[0]); | 704 result = inputStream.readByteArray(); |
800 result = inputStream.readByteArray(); | 705 assertEquals(bytesLength, result.length); |
801 assertEquals(inputType.name(), 1, result.length); | 706 assertEquals((byte) 67, result[0]); |
802 assertEquals(inputType.name(), (byte) 45, result[0]); | 707 assertEquals((byte) 89, result[bytesLength - 1]); |
803 result = inputStream.readByteArray(); | |
804 assertEquals(inputType.name(), bytesLength, result.length); | |
805 assertEquals(inputType.name(), (byte) 67, result[0]); | |
806 assertEquals(inputType.name(), (byte) 89, result[bytesLength - 1]); | |
807 } | |
808 } | 708 } |
809 | 709 |
810 public void testReadByteBuffer() throws Exception { | 710 public void testReadByteBuffer() throws Exception { |
811 ByteString.Output rawOutput = ByteString.newOutput(); | 711 ByteString.Output rawOutput = ByteString.newOutput(); |
812 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); | 712 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); |
813 // Zero-sized bytes field. | 713 // Zero-sized bytes field. |
814 output.writeRawVarint32(0); | 714 output.writeRawVarint32(0); |
815 // One one-byte bytes field | 715 // One one-byte bytes field |
816 output.writeRawVarint32(1); | 716 output.writeRawVarint32(1); |
817 output.writeRawBytes(new byte[] {(byte) 23}); | 717 output.writeRawBytes(new byte[]{(byte) 23}); |
818 // Another one-byte bytes field | 718 // Another one-byte bytes field |
819 output.writeRawVarint32(1); | 719 output.writeRawVarint32(1); |
820 output.writeRawBytes(new byte[] {(byte) 45}); | 720 output.writeRawBytes(new byte[]{(byte) 45}); |
821 // A bytes field large enough that won't fit into the 4K buffer. | 721 // A bytes field large enough that won't fit into the 4K buffer. |
822 final int bytesLength = 16 * 1024; | 722 final int bytesLength = 16 * 1024; |
823 byte[] bytes = new byte[bytesLength]; | 723 byte[] bytes = new byte[bytesLength]; |
824 bytes[0] = (byte) 67; | 724 bytes[0] = (byte) 67; |
825 bytes[bytesLength - 1] = (byte) 89; | 725 bytes[bytesLength - 1] = (byte) 89; |
826 output.writeRawVarint32(bytesLength); | 726 output.writeRawVarint32(bytesLength); |
827 output.writeRawBytes(bytes); | 727 output.writeRawBytes(bytes); |
828 | 728 |
829 output.flush(); | 729 output.flush(); |
| 730 CodedInputStream inputStream = rawOutput.toByteString().newCodedInput(); |
830 | 731 |
831 byte[] rawInput = rawOutput.toByteString().toByteArray(); | 732 ByteBuffer result = inputStream.readByteBuffer(); |
832 for (InputType inputType : InputType.values()) { | 733 assertEquals(0, result.capacity()); |
833 CodedInputStream inputStream = inputType.newDecoder(rawInput); | 734 result = inputStream.readByteBuffer(); |
834 | 735 assertEquals(1, result.capacity()); |
835 ByteBuffer result = inputStream.readByteBuffer(); | 736 assertEquals((byte) 23, result.get()); |
836 assertEquals(inputType.name(), 0, result.capacity()); | 737 result = inputStream.readByteBuffer(); |
837 result = inputStream.readByteBuffer(); | 738 assertEquals(1, result.capacity()); |
838 assertEquals(inputType.name(), 1, result.capacity()); | 739 assertEquals((byte) 45, result.get()); |
839 assertEquals(inputType.name(), (byte) 23, result.get()); | 740 result = inputStream.readByteBuffer(); |
840 result = inputStream.readByteBuffer(); | 741 assertEquals(bytesLength, result.capacity()); |
841 assertEquals(inputType.name(), 1, result.capacity()); | 742 assertEquals((byte) 67, result.get()); |
842 assertEquals(inputType.name(), (byte) 45, result.get()); | 743 result.position(bytesLength - 1); |
843 result = inputStream.readByteBuffer(); | 744 assertEquals((byte) 89, result.get()); |
844 assertEquals(inputType.name(), bytesLength, result.capacity()); | |
845 assertEquals(inputType.name(), (byte) 67, result.get()); | |
846 result.position(bytesLength - 1); | |
847 assertEquals(inputType.name(), (byte) 89, result.get()); | |
848 } | |
849 } | 745 } |
850 | 746 |
851 public void testReadByteBufferAliasing() throws Exception { | 747 public void testReadByteBufferAliasing() throws Exception { |
852 ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream(); | 748 ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream(); |
853 CodedOutputStream output = CodedOutputStream.newInstance(byteArrayStream); | 749 CodedOutputStream output = CodedOutputStream.newInstance(byteArrayStream); |
854 // Zero-sized bytes field. | 750 // Zero-sized bytes field. |
855 output.writeRawVarint32(0); | 751 output.writeRawVarint32(0); |
856 // One one-byte bytes field | 752 // One one-byte bytes field |
857 output.writeRawVarint32(1); | 753 output.writeRawVarint32(1); |
858 output.writeRawBytes(new byte[] {(byte) 23}); | 754 output.writeRawBytes(new byte[]{(byte) 23}); |
859 // Another one-byte bytes field | 755 // Another one-byte bytes field |
860 output.writeRawVarint32(1); | 756 output.writeRawVarint32(1); |
861 output.writeRawBytes(new byte[] {(byte) 45}); | 757 output.writeRawBytes(new byte[]{(byte) 45}); |
862 // A bytes field large enough that won't fit into the 4K buffer. | 758 // A bytes field large enough that won't fit into the 4K buffer. |
863 final int bytesLength = 16 * 1024; | 759 final int bytesLength = 16 * 1024; |
864 byte[] bytes = new byte[bytesLength]; | 760 byte[] bytes = new byte[bytesLength]; |
865 bytes[0] = (byte) 67; | 761 bytes[0] = (byte) 67; |
866 bytes[bytesLength - 1] = (byte) 89; | 762 bytes[bytesLength - 1] = (byte) 89; |
867 output.writeRawVarint32(bytesLength); | 763 output.writeRawVarint32(bytesLength); |
868 output.writeRawBytes(bytes); | 764 output.writeRawBytes(bytes); |
869 output.flush(); | 765 output.flush(); |
870 | |
871 byte[] data = byteArrayStream.toByteArray(); | 766 byte[] data = byteArrayStream.toByteArray(); |
872 | 767 |
873 for (InputType inputType : InputType.values()) { | 768 // Without aliasing |
874 if (inputType == InputType.STREAM) { | 769 CodedInputStream inputStream = CodedInputStream.newInstance(data); |
875 // Aliasing doesn't apply to stream-backed CIS. | 770 ByteBuffer result = inputStream.readByteBuffer(); |
876 continue; | 771 assertEquals(0, result.capacity()); |
877 } | 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()); |
878 | 786 |
879 // Without aliasing | 787 // Enable aliasing |
880 CodedInputStream inputStream = inputType.newDecoder(data); | 788 inputStream = CodedInputStream.newInstance(data); |
881 ByteBuffer result = inputStream.readByteBuffer(); | 789 inputStream.enableAliasing(true); |
882 assertEquals(inputType.name(), 0, result.capacity()); | 790 result = inputStream.readByteBuffer(); |
883 result = inputStream.readByteBuffer(); | 791 assertEquals(0, result.capacity()); |
884 assertTrue(inputType.name(), result.array() != data); | 792 result = inputStream.readByteBuffer(); |
885 assertEquals(inputType.name(), 1, result.capacity()); | 793 assertTrue(result.array() == data); |
886 assertEquals(inputType.name(), (byte) 23, result.get()); | 794 assertEquals(1, result.capacity()); |
887 result = inputStream.readByteBuffer(); | 795 assertEquals((byte) 23, result.get()); |
888 assertTrue(inputType.name(), result.array() != data); | 796 result = inputStream.readByteBuffer(); |
889 assertEquals(inputType.name(), 1, result.capacity()); | 797 assertTrue(result.array() == data); |
890 assertEquals(inputType.name(), (byte) 45, result.get()); | 798 assertEquals(1, result.capacity()); |
891 result = inputStream.readByteBuffer(); | 799 assertEquals((byte) 45, result.get()); |
892 assertTrue(inputType.name(), result.array() != data); | 800 result = inputStream.readByteBuffer(); |
893 assertEquals(inputType.name(), bytesLength, result.capacity()); | 801 assertTrue(result.array() == data); |
894 assertEquals(inputType.name(), (byte) 67, result.get()); | 802 assertEquals(bytesLength, result.capacity()); |
895 result.position(bytesLength - 1); | 803 assertEquals((byte) 67, result.get()); |
896 assertEquals(inputType.name(), (byte) 89, result.get()); | 804 result.position(bytesLength - 1); |
897 | 805 assertEquals((byte) 89, result.get()); |
898 // Enable aliasing | |
899 inputStream = inputType.newDecoder(data); | |
900 inputStream.enableAliasing(true); | |
901 result = inputStream.readByteBuffer(); | |
902 assertEquals(inputType.name(), 0, result.capacity()); | |
903 result = inputStream.readByteBuffer(); | |
904 if (result.hasArray()) { | |
905 assertTrue(inputType.name(), result.array() == data); | |
906 } | |
907 assertEquals(inputType.name(), 1, result.capacity()); | |
908 assertEquals(inputType.name(), (byte) 23, result.get()); | |
909 result = inputStream.readByteBuffer(); | |
910 if (result.hasArray()) { | |
911 assertTrue(inputType.name(), result.array() == data); | |
912 } | |
913 assertEquals(inputType.name(), 1, result.capacity()); | |
914 assertEquals(inputType.name(), (byte) 45, result.get()); | |
915 result = inputStream.readByteBuffer(); | |
916 if (result.hasArray()) { | |
917 assertTrue(inputType.name(), result.array() == data); | |
918 } | |
919 assertEquals(inputType.name(), bytesLength, result.capacity()); | |
920 assertEquals(inputType.name(), (byte) 67, result.get()); | |
921 result.position(bytesLength - 1); | |
922 assertEquals(inputType.name(), (byte) 89, result.get()); | |
923 } | |
924 } | 806 } |
925 | 807 |
926 public void testCompatibleTypes() throws Exception { | 808 public void testCompatibleTypes() throws Exception { |
927 long data = 0x100000000L; | 809 long data = 0x100000000L; |
928 Int64Message message = Int64Message.newBuilder().setData(data).build(); | 810 Int64Message message = Int64Message.newBuilder().setData(data).build(); |
929 byte[] serialized = message.toByteArray(); | 811 ByteString serialized = message.toByteString(); |
930 for (InputType inputType : InputType.values()) { | |
931 CodedInputStream inputStream = inputType.newDecoder(serialized); | |
932 | 812 |
933 // Test int64(long) is compatible with bool(boolean) | 813 // Test int64(long) is compatible with bool(boolean) |
934 BoolMessage msg2 = BoolMessage.parseFrom(inputStream); | 814 BoolMessage msg2 = BoolMessage.parseFrom(serialized); |
935 assertTrue(msg2.getData()); | 815 assertTrue(msg2.getData()); |
936 | 816 |
937 // Test int64(long) is compatible with int32(int) | 817 // Test int64(long) is compatible with int32(int) |
938 inputStream = inputType.newDecoder(serialized); | 818 Int32Message msg3 = Int32Message.parseFrom(serialized); |
939 Int32Message msg3 = Int32Message.parseFrom(inputStream); | 819 assertEquals((int) data, msg3.getData()); |
940 assertEquals((int) data, msg3.getData()); | |
941 } | |
942 } | |
943 | |
944 public void testSkipInvalidVarint_FastPath() throws Exception { | |
945 // Fast path: We have >= 10 bytes available. Ensure we properly recognize a
non-ending varint. | |
946 byte[] data = new byte[] {-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0}; | |
947 for (InputType inputType : InputType.values()) { | |
948 try { | |
949 CodedInputStream input = inputType.newDecoder(data); | |
950 input.skipField(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT)); | |
951 fail(inputType.name() + ": Should have thrown an exception."); | |
952 } catch (InvalidProtocolBufferException e) { | |
953 // Expected | |
954 } | |
955 } | |
956 } | |
957 | |
958 public void testSkipInvalidVarint_SlowPath() throws Exception { | |
959 // Slow path: < 10 bytes available. Ensure we properly recognize a non-endin
g varint. | |
960 byte[] data = new byte[] {-1, -1, -1, -1, -1, -1, -1, -1, -1}; | |
961 for (InputType inputType : InputType.values()) { | |
962 try { | |
963 CodedInputStream input = inputType.newDecoder(data); | |
964 input.skipField(WireFormat.makeTag(1, WireFormat.WIRETYPE_VARINT)); | |
965 fail(inputType.name() + ": Should have thrown an exception."); | |
966 } catch (InvalidProtocolBufferException e) { | |
967 // Expected | |
968 } | |
969 } | |
970 } | 820 } |
971 } | 821 } |
OLD | NEW |