OLD | NEW |
| (Empty) |
1 // Protocol Buffers - Google's data interchange format | |
2 // Copyright 2008 Google Inc. All rights reserved. | |
3 // http://code.google.com/p/protobuf/ | |
4 // | |
5 // Redistribution and use in source and binary forms, with or without | |
6 // modification, are permitted provided that the following conditions are | |
7 // met: | |
8 // | |
9 // * Redistributions of source code must retain the above copyright | |
10 // notice, this list of conditions and the following disclaimer. | |
11 // * Redistributions in binary form must reproduce the above | |
12 // copyright notice, this list of conditions and the following disclaimer | |
13 // in the documentation and/or other materials provided with the | |
14 // distribution. | |
15 // * Neither the name of Google Inc. nor the names of its | |
16 // contributors may be used to endorse or promote products derived from | |
17 // this software without specific prior written permission. | |
18 // | |
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT | |
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | |
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | |
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | |
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | |
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
30 | |
31 package com.google.protobuf.test; | |
32 import com.google.protobuf.*; | |
33 | |
34 import protobuf_unittest.UnittestProto.SparseEnumMessage; | |
35 import protobuf_unittest.UnittestProto.TestAllTypes; | |
36 import protobuf_unittest.UnittestProto.TestPackedTypes; | |
37 import protobuf_unittest.UnittestProto.TestSparseEnum; | |
38 | |
39 import junit.framework.TestCase; | |
40 | |
41 import java.io.ByteArrayOutputStream; | |
42 import java.util.ArrayList; | |
43 import java.util.List; | |
44 | |
45 /** | |
46 * Unit test for {@link CodedOutputStream}. | |
47 * | |
48 * @author kenton@google.com Kenton Varda | |
49 */ | |
50 public class CodedOutputStreamTest extends TestCase { | |
51 /** | |
52 * Helper to construct a byte array from a bunch of bytes. The inputs are | |
53 * actually ints so that I can use hex notation and not get stupid errors | |
54 * about precision. | |
55 */ | |
56 private byte[] bytes(int... bytesAsInts) { | |
57 byte[] bytes = new byte[bytesAsInts.length]; | |
58 for (int i = 0; i < bytesAsInts.length; i++) { | |
59 bytes[i] = (byte) bytesAsInts[i]; | |
60 } | |
61 return bytes; | |
62 } | |
63 | |
64 /** Arrays.asList() does not work with arrays of primitives. :( */ | |
65 private List<Byte> toList(byte[] bytes) { | |
66 List<Byte> result = new ArrayList<Byte>(); | |
67 for (byte b : bytes) { | |
68 result.add(b); | |
69 } | |
70 return result; | |
71 } | |
72 | |
73 private void assertEqualBytes(byte[] a, byte[] b) { | |
74 assertEquals(toList(a), toList(b)); | |
75 } | |
76 | |
77 /** | |
78 * Writes the given value using writeRawVarint32() and writeRawVarint64() and | |
79 * checks that the result matches the given bytes. | |
80 */ | |
81 private void assertWriteVarint(byte[] data, long value) throws Exception { | |
82 // Only do 32-bit write if the value fits in 32 bits. | |
83 if ((value >>> 32) == 0) { | |
84 ByteArrayOutputStream rawOutput = new ByteArrayOutputStream(); | |
85 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); | |
86 output.writeRawVarint32((int) value); | |
87 output.flush(); | |
88 assertEqualBytes(data, rawOutput.toByteArray()); | |
89 | |
90 // Also try computing size. | |
91 assertEquals(data.length, | |
92 CodedOutputStream.computeRawVarint32Size((int) value)); | |
93 } | |
94 | |
95 { | |
96 ByteArrayOutputStream rawOutput = new ByteArrayOutputStream(); | |
97 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); | |
98 output.writeRawVarint64(value); | |
99 output.flush(); | |
100 assertEqualBytes(data, rawOutput.toByteArray()); | |
101 | |
102 // Also try computing size. | |
103 assertEquals(data.length, | |
104 CodedOutputStream.computeRawVarint64Size(value)); | |
105 } | |
106 | |
107 // Try different block sizes. | |
108 for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { | |
109 // Only do 32-bit write if the value fits in 32 bits. | |
110 if ((value >>> 32) == 0) { | |
111 ByteArrayOutputStream rawOutput = new ByteArrayOutputStream(); | |
112 CodedOutputStream output = | |
113 CodedOutputStream.newInstance(rawOutput, blockSize); | |
114 output.writeRawVarint32((int) value); | |
115 output.flush(); | |
116 assertEqualBytes(data, rawOutput.toByteArray()); | |
117 } | |
118 | |
119 { | |
120 ByteArrayOutputStream rawOutput = new ByteArrayOutputStream(); | |
121 CodedOutputStream output = | |
122 CodedOutputStream.newInstance(rawOutput, blockSize); | |
123 output.writeRawVarint64(value); | |
124 output.flush(); | |
125 assertEqualBytes(data, rawOutput.toByteArray()); | |
126 } | |
127 } | |
128 } | |
129 | |
130 /** Tests writeRawVarint32() and writeRawVarint64(). */ | |
131 public void testWriteVarint() throws Exception { | |
132 assertWriteVarint(bytes(0x00), 0); | |
133 assertWriteVarint(bytes(0x01), 1); | |
134 assertWriteVarint(bytes(0x7f), 127); | |
135 // 14882 | |
136 assertWriteVarint(bytes(0xa2, 0x74), (0x22 << 0) | (0x74 << 7)); | |
137 // 2961488830 | |
138 assertWriteVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x0b), | |
139 (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | | |
140 (0x0bL << 28)); | |
141 | |
142 // 64-bit | |
143 // 7256456126 | |
144 assertWriteVarint(bytes(0xbe, 0xf7, 0x92, 0x84, 0x1b), | |
145 (0x3e << 0) | (0x77 << 7) | (0x12 << 14) | (0x04 << 21) | | |
146 (0x1bL << 28)); | |
147 // 41256202580718336 | |
148 assertWriteVarint( | |
149 bytes(0x80, 0xe6, 0xeb, 0x9c, 0xc3, 0xc9, 0xa4, 0x49), | |
150 (0x00 << 0) | (0x66 << 7) | (0x6b << 14) | (0x1c << 21) | | |
151 (0x43L << 28) | (0x49L << 35) | (0x24L << 42) | (0x49L << 49)); | |
152 // 11964378330978735131 | |
153 assertWriteVarint( | |
154 bytes(0x9b, 0xa8, 0xf9, 0xc2, 0xbb, 0xd6, 0x80, 0x85, 0xa6, 0x01), | |
155 (0x1b << 0) | (0x28 << 7) | (0x79 << 14) | (0x42 << 21) | | |
156 (0x3bL << 28) | (0x56L << 35) | (0x00L << 42) | | |
157 (0x05L << 49) | (0x26L << 56) | (0x01L << 63)); | |
158 } | |
159 | |
160 /** | |
161 * Parses the given bytes using writeRawLittleEndian32() and checks | |
162 * that the result matches the given value. | |
163 */ | |
164 private void assertWriteLittleEndian32(byte[] data, int value) | |
165 throws Exception { | |
166 ByteArrayOutputStream rawOutput = new ByteArrayOutputStream(); | |
167 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); | |
168 output.writeRawLittleEndian32(value); | |
169 output.flush(); | |
170 assertEqualBytes(data, rawOutput.toByteArray()); | |
171 | |
172 // Try different block sizes. | |
173 for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { | |
174 rawOutput = new ByteArrayOutputStream(); | |
175 output = CodedOutputStream.newInstance(rawOutput, blockSize); | |
176 output.writeRawLittleEndian32(value); | |
177 output.flush(); | |
178 assertEqualBytes(data, rawOutput.toByteArray()); | |
179 } | |
180 } | |
181 | |
182 /** | |
183 * Parses the given bytes using writeRawLittleEndian64() and checks | |
184 * that the result matches the given value. | |
185 */ | |
186 private void assertWriteLittleEndian64(byte[] data, long value) | |
187 throws Exception { | |
188 ByteArrayOutputStream rawOutput = new ByteArrayOutputStream(); | |
189 CodedOutputStream output = CodedOutputStream.newInstance(rawOutput); | |
190 output.writeRawLittleEndian64(value); | |
191 output.flush(); | |
192 assertEqualBytes(data, rawOutput.toByteArray()); | |
193 | |
194 // Try different block sizes. | |
195 for (int blockSize = 1; blockSize <= 16; blockSize *= 2) { | |
196 rawOutput = new ByteArrayOutputStream(); | |
197 output = CodedOutputStream.newInstance(rawOutput, blockSize); | |
198 output.writeRawLittleEndian64(value); | |
199 output.flush(); | |
200 assertEqualBytes(data, rawOutput.toByteArray()); | |
201 } | |
202 } | |
203 | |
204 /** Tests writeRawLittleEndian32() and writeRawLittleEndian64(). */ | |
205 public void testWriteLittleEndian() throws Exception { | |
206 assertWriteLittleEndian32(bytes(0x78, 0x56, 0x34, 0x12), 0x12345678); | |
207 assertWriteLittleEndian32(bytes(0xf0, 0xde, 0xbc, 0x9a), 0x9abcdef0); | |
208 | |
209 assertWriteLittleEndian64( | |
210 bytes(0xf0, 0xde, 0xbc, 0x9a, 0x78, 0x56, 0x34, 0x12), | |
211 0x123456789abcdef0L); | |
212 assertWriteLittleEndian64( | |
213 bytes(0x78, 0x56, 0x34, 0x12, 0xf0, 0xde, 0xbc, 0x9a), | |
214 0x9abcdef012345678L); | |
215 } | |
216 | |
217 /** Test encodeZigZag32() and encodeZigZag64(). */ | |
218 public void testEncodeZigZag() throws Exception { | |
219 assertEquals(0, CodedOutputStream.encodeZigZag32( 0)); | |
220 assertEquals(1, CodedOutputStream.encodeZigZag32(-1)); | |
221 assertEquals(2, CodedOutputStream.encodeZigZag32( 1)); | |
222 assertEquals(3, CodedOutputStream.encodeZigZag32(-2)); | |
223 assertEquals(0x7FFFFFFE, CodedOutputStream.encodeZigZag32(0x3FFFFFFF)); | |
224 assertEquals(0x7FFFFFFF, CodedOutputStream.encodeZigZag32(0xC0000000)); | |
225 assertEquals(0xFFFFFFFE, CodedOutputStream.encodeZigZag32(0x7FFFFFFF)); | |
226 assertEquals(0xFFFFFFFF, CodedOutputStream.encodeZigZag32(0x80000000)); | |
227 | |
228 assertEquals(0, CodedOutputStream.encodeZigZag64( 0)); | |
229 assertEquals(1, CodedOutputStream.encodeZigZag64(-1)); | |
230 assertEquals(2, CodedOutputStream.encodeZigZag64( 1)); | |
231 assertEquals(3, CodedOutputStream.encodeZigZag64(-2)); | |
232 assertEquals(0x000000007FFFFFFEL, | |
233 CodedOutputStream.encodeZigZag64(0x000000003FFFFFFFL)); | |
234 assertEquals(0x000000007FFFFFFFL, | |
235 CodedOutputStream.encodeZigZag64(0xFFFFFFFFC0000000L)); | |
236 assertEquals(0x00000000FFFFFFFEL, | |
237 CodedOutputStream.encodeZigZag64(0x000000007FFFFFFFL)); | |
238 assertEquals(0x00000000FFFFFFFFL, | |
239 CodedOutputStream.encodeZigZag64(0xFFFFFFFF80000000L)); | |
240 assertEquals(0xFFFFFFFFFFFFFFFEL, | |
241 CodedOutputStream.encodeZigZag64(0x7FFFFFFFFFFFFFFFL)); | |
242 assertEquals(0xFFFFFFFFFFFFFFFFL, | |
243 CodedOutputStream.encodeZigZag64(0x8000000000000000L)); | |
244 | |
245 // Some easier-to-verify round-trip tests. The inputs (other than 0, 1, -1) | |
246 // were chosen semi-randomly via keyboard bashing. | |
247 assertEquals(0, | |
248 CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(0))); | |
249 assertEquals(1, | |
250 CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(1))); | |
251 assertEquals(-1, | |
252 CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-1))); | |
253 assertEquals(14927, | |
254 CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(14927))); | |
255 assertEquals(-3612, | |
256 CodedOutputStream.encodeZigZag32(CodedInputStream.decodeZigZag32(-3612))); | |
257 | |
258 assertEquals(0, | |
259 CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(0))); | |
260 assertEquals(1, | |
261 CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(1))); | |
262 assertEquals(-1, | |
263 CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-1))); | |
264 assertEquals(14927, | |
265 CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(14927))); | |
266 assertEquals(-3612, | |
267 CodedOutputStream.encodeZigZag64(CodedInputStream.decodeZigZag64(-3612))); | |
268 | |
269 assertEquals(856912304801416L, | |
270 CodedOutputStream.encodeZigZag64( | |
271 CodedInputStream.decodeZigZag64( | |
272 856912304801416L))); | |
273 assertEquals(-75123905439571256L, | |
274 CodedOutputStream.encodeZigZag64( | |
275 CodedInputStream.decodeZigZag64( | |
276 -75123905439571256L))); | |
277 } | |
278 | |
279 /** Tests writing a whole message with every field type. */ | |
280 public void testWriteWholeMessage() throws Exception { | |
281 TestAllTypes message = TestUtil.getAllSet(); | |
282 | |
283 byte[] rawBytes = message.toByteArray(); | |
284 assertEqualBytes(TestUtil.getGoldenMessage().toByteArray(), rawBytes); | |
285 | |
286 // Try different block sizes. | |
287 for (int blockSize = 1; blockSize < 256; blockSize *= 2) { | |
288 ByteArrayOutputStream rawOutput = new ByteArrayOutputStream(); | |
289 CodedOutputStream output = | |
290 CodedOutputStream.newInstance(rawOutput, blockSize); | |
291 message.writeTo(output); | |
292 output.flush(); | |
293 assertEqualBytes(rawBytes, rawOutput.toByteArray()); | |
294 } | |
295 } | |
296 | |
297 /** Tests writing a whole message with every packed field type. Ensures the | |
298 * wire format of packed fields is compatible with C++. */ | |
299 public void testWriteWholePackedFieldsMessage() throws Exception { | |
300 TestPackedTypes message = TestUtil.getPackedSet(); | |
301 | |
302 byte[] rawBytes = message.toByteArray(); | |
303 assertEqualBytes(TestUtil.getGoldenPackedFieldsMessage().toByteArray(), | |
304 rawBytes); | |
305 } | |
306 | |
307 /** Test writing a message containing a negative enum value. This used to | |
308 * fail because the size was not properly computed as a sign-extended varint. | |
309 */ | |
310 public void testWriteMessageWithNegativeEnumValue() throws Exception { | |
311 SparseEnumMessage message = SparseEnumMessage.newBuilder() | |
312 .setSparseEnum(TestSparseEnum.SPARSE_E) .build(); | |
313 assertTrue(message.getSparseEnum().getNumber() < 0); | |
314 byte[] rawBytes = message.toByteArray(); | |
315 SparseEnumMessage message2 = SparseEnumMessage.parseFrom(rawBytes); | |
316 assertEquals(TestSparseEnum.SPARSE_E, message2.getSparseEnum()); | |
317 } | |
318 } | |
OLD | NEW |