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