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 com.google.protobuf.CodedOutputStream.OutOfSpaceException; | 33 import com.google.protobuf.CodedOutputStream.OutOfSpaceException; |
34 import protobuf_unittest.UnittestProto.SparseEnumMessage; | 34 import protobuf_unittest.UnittestProto.SparseEnumMessage; |
35 import protobuf_unittest.UnittestProto.TestAllTypes; | 35 import protobuf_unittest.UnittestProto.TestAllTypes; |
36 import protobuf_unittest.UnittestProto.TestPackedTypes; | 36 import protobuf_unittest.UnittestProto.TestPackedTypes; |
37 import protobuf_unittest.UnittestProto.TestSparseEnum; | 37 import protobuf_unittest.UnittestProto.TestSparseEnum; |
| 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.nio.ByteBuffer; | 43 import java.nio.ByteBuffer; |
41 import java.util.ArrayList; | 44 import java.util.ArrayList; |
42 import java.util.Arrays; | 45 import java.util.Arrays; |
43 import java.util.List; | 46 import java.util.List; |
44 import junit.framework.TestCase; | |
45 | 47 |
46 /** | 48 /** |
47 * Unit test for {@link CodedOutputStream}. | 49 * Unit test for {@link CodedOutputStream}. |
48 * | 50 * |
49 * @author kenton@google.com Kenton Varda | 51 * @author kenton@google.com Kenton Varda |
50 */ | 52 */ |
51 public class CodedOutputStreamTest extends TestCase { | 53 public class CodedOutputStreamTest extends TestCase { |
52 private interface Coder { | 54 private interface Coder { |
53 CodedOutputStream stream(); | 55 CodedOutputStream stream(); |
54 | 56 |
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
142 @Override | 144 @Override |
143 public OutputType getOutputType() { | 145 public OutputType getOutputType() { |
144 return OutputType.NIO_HEAP; | 146 return OutputType.NIO_HEAP; |
145 } | 147 } |
146 } | 148 } |
147 | 149 |
148 private static final class NioDirectCoder implements Coder { | 150 private static final class NioDirectCoder implements Coder { |
149 private final int initialPosition; | 151 private final int initialPosition; |
150 private final CodedOutputStream stream; | 152 private final CodedOutputStream stream; |
151 private final ByteBuffer buffer; | 153 private final ByteBuffer buffer; |
152 private final boolean unsafe; | |
153 | 154 |
154 NioDirectCoder(int size, boolean unsafe) { | 155 NioDirectCoder(int size) { |
155 this(size, 0, unsafe); | 156 this(size, 0); |
156 } | 157 } |
157 | 158 |
158 NioDirectCoder(int size, int initialPosition, boolean unsafe) { | 159 NioDirectCoder(int size, int initialPosition) { |
159 this.unsafe = unsafe; | |
160 this.initialPosition = initialPosition; | 160 this.initialPosition = initialPosition; |
161 buffer = ByteBuffer.allocateDirect(size); | 161 buffer = ByteBuffer.allocateDirect(size); |
162 buffer.position(initialPosition); | 162 buffer.position(initialPosition); |
163 stream = | 163 stream = CodedOutputStream.newInstance(buffer); |
164 unsafe | |
165 ? CodedOutputStream.newUnsafeInstance(buffer) | |
166 : CodedOutputStream.newSafeInstance(buffer); | |
167 } | 164 } |
168 | 165 |
169 @Override | 166 @Override |
170 public CodedOutputStream stream() { | 167 public CodedOutputStream stream() { |
171 return stream; | 168 return stream; |
172 } | 169 } |
173 | 170 |
174 @Override | 171 @Override |
175 public byte[] toByteArray() { | 172 public byte[] toByteArray() { |
176 ByteBuffer dup = buffer.duplicate(); | 173 ByteBuffer dup = buffer.duplicate(); |
177 dup.position(initialPosition); | 174 dup.position(initialPosition); |
178 dup.limit(buffer.position()); | 175 dup.limit(buffer.position()); |
179 | 176 |
180 byte[] bytes = new byte[dup.remaining()]; | 177 byte[] bytes = new byte[dup.remaining()]; |
181 dup.get(bytes); | 178 dup.get(bytes); |
182 return bytes; | 179 return bytes; |
183 } | 180 } |
184 | 181 |
185 @Override | 182 @Override |
186 public OutputType getOutputType() { | 183 public OutputType getOutputType() { |
187 return unsafe ? OutputType.NIO_DIRECT_SAFE : OutputType.NIO_DIRECT_UNSAFE; | 184 return OutputType.NIO_DIRECT; |
188 } | 185 } |
189 } | 186 } |
190 | 187 |
191 private enum OutputType { | 188 private enum OutputType { |
192 ARRAY() { | 189 ARRAY() { |
193 @Override | 190 @Override |
194 Coder newCoder(int size) { | 191 Coder newCoder(int size) { |
195 return new ArrayCoder(size); | 192 return new ArrayCoder(size); |
196 } | 193 } |
197 }, | 194 }, |
198 NIO_HEAP() { | 195 NIO_HEAP() { |
199 @Override | 196 @Override |
200 Coder newCoder(int size) { | 197 Coder newCoder(int size) { |
201 return new NioHeapCoder(size); | 198 return new NioHeapCoder(size); |
202 } | 199 } |
203 }, | 200 }, |
204 NIO_DIRECT_SAFE() { | 201 NIO_DIRECT() { |
205 @Override | 202 @Override |
206 Coder newCoder(int size) { | 203 Coder newCoder(int size) { |
207 return new NioDirectCoder(size, false); | 204 return new NioDirectCoder(size); |
208 } | |
209 }, | |
210 NIO_DIRECT_UNSAFE() { | |
211 @Override | |
212 Coder newCoder(int size) { | |
213 return new NioDirectCoder(size, true); | |
214 } | 205 } |
215 }, | 206 }, |
216 STREAM() { | 207 STREAM() { |
217 @Override | 208 @Override |
218 Coder newCoder(int size) { | 209 Coder newCoder(int size) { |
219 return new OutputStreamCoder(size); | 210 return new OutputStreamCoder(size); |
220 } | 211 } |
221 }; | 212 }; |
222 | 213 |
223 abstract Coder newCoder(int size); | 214 abstract Coder newCoder(int size); |
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
391 assertEquals(value.length * 1024, coder.stream().getTotalBytesWritten()); | 382 assertEquals(value.length * 1024, coder.stream().getTotalBytesWritten()); |
392 | 383 |
393 // Now write an encoded string. | 384 // Now write an encoded string. |
394 String string = | 385 String string = |
395 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs
tuvwxyz"; | 386 "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrs
tuvwxyz"; |
396 // Ensure we take the slower fast path. | 387 // Ensure we take the slower fast path. |
397 assertTrue(CodedOutputStream.computeUInt32SizeNoTag(string.length()) | 388 assertTrue(CodedOutputStream.computeUInt32SizeNoTag(string.length()) |
398 != CodedOutputStream.computeUInt32SizeNoTag(string.length() * Utf8.MAX_B
YTES_PER_CHAR)); | 389 != CodedOutputStream.computeUInt32SizeNoTag(string.length() * Utf8.MAX_B
YTES_PER_CHAR)); |
399 | 390 |
400 coder.stream().writeStringNoTag(string); | 391 coder.stream().writeStringNoTag(string); |
401 coder.stream().flush(); | |
402 int stringSize = CodedOutputStream.computeStringSizeNoTag(string); | 392 int stringSize = CodedOutputStream.computeStringSizeNoTag(string); |
403 | 393 |
404 // Verify that the total bytes written is correct | 394 // Verify that the total bytes written is correct |
405 assertEquals((value.length * 1024) + stringSize, coder.stream().getTotalByte
sWritten()); | 395 assertEquals((value.length * 1024) + stringSize, coder.stream().getTotalByte
sWritten()); |
406 } | 396 } |
407 | 397 |
408 // TODO(dweis): Write a comprehensive test suite for CodedOutputStream that co
vers more than just | 398 // TODO(dweis): Write a comprehensive test suite for CodedOutputStream that co
vers more than just |
409 // this case. | 399 // this case. |
410 public void testWriteStringNoTag_fastpath() throws Exception { | 400 public void testWriteStringNoTag_fastpath() throws Exception { |
411 int bufferSize = 153; | 401 int bufferSize = 153; |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
481 byte[] result = outputStream.toByteArray(); | 471 byte[] result = outputStream.toByteArray(); |
482 assertEquals(6, result.length); | 472 assertEquals(6, result.length); |
483 for (int i = 0; i < 5; i++) { | 473 for (int i = 0; i < 5; i++) { |
484 assertEquals(value[i], result[i]); | 474 assertEquals(value[i], result[i]); |
485 } | 475 } |
486 assertEquals(value[2], result[5]); | 476 assertEquals(value[2], result[5]); |
487 } | 477 } |
488 | 478 |
489 public void testWriteByteArrayWithOffsets() throws Exception { | 479 public void testWriteByteArrayWithOffsets() throws Exception { |
490 byte[] fullArray = bytes(0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88); | 480 byte[] fullArray = bytes(0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88); |
491 for (OutputType type : new OutputType[] {OutputType.ARRAY}) { | 481 byte[] destination = new byte[4]; |
492 Coder coder = type.newCoder(4); | 482 CodedOutputStream codedStream = CodedOutputStream.newInstance(destination); |
493 coder.stream().writeByteArrayNoTag(fullArray, 2, 2); | 483 codedStream.writeByteArrayNoTag(fullArray, 2, 2); |
494 assertEqualBytes(type, bytes(0x02, 0x33, 0x44), coder.toByteArray()); | 484 assertEqualBytes(OutputType.ARRAY, bytes(0x02, 0x33, 0x44, 0x00), destinatio
n); |
495 assertEquals(3, coder.stream().getTotalBytesWritten()); | 485 assertEquals(3, codedStream.getTotalBytesWritten()); |
496 } | |
497 } | 486 } |
498 | 487 |
499 public void testSerializeUtf8_MultipleSmallWrites() throws Exception { | 488 public void testSerializeUtf8_MultipleSmallWrites() throws Exception { |
500 final String source = "abcdefghijklmnopqrstuvwxyz"; | 489 final String source = "abcdefghijklmnopqrstuvwxyz"; |
501 | 490 |
502 // Generate the expected output if the source string is written 2 bytes at a
time. | 491 // Generate the expected output if the source string is written 2 bytes at a
time. |
503 ByteArrayOutputStream expectedBytesStream = new ByteArrayOutputStream(); | 492 ByteArrayOutputStream expectedBytesStream = new ByteArrayOutputStream(); |
504 for (int pos = 0; pos < source.length(); pos += 2) { | 493 for (int pos = 0; pos < source.length(); pos += 2) { |
505 String substr = source.substring(pos, pos + 2); | 494 String substr = source.substring(pos, pos + 2); |
506 expectedBytesStream.write(2); | 495 expectedBytesStream.write(2); |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
565 /** Regression test for https://github.com/google/protobuf/issues/292 */ | 554 /** Regression test for https://github.com/google/protobuf/issues/292 */ |
566 public void testCorrectExceptionThrowWhenEncodingStringsWithoutEnoughSpace() t
hrows Exception { | 555 public void testCorrectExceptionThrowWhenEncodingStringsWithoutEnoughSpace() t
hrows Exception { |
567 String testCase = "Foooooooo"; | 556 String testCase = "Foooooooo"; |
568 assertEquals( | 557 assertEquals( |
569 CodedOutputStream.computeUInt32SizeNoTag(testCase.length()), | 558 CodedOutputStream.computeUInt32SizeNoTag(testCase.length()), |
570 CodedOutputStream.computeUInt32SizeNoTag(testCase.length() * 3)); | 559 CodedOutputStream.computeUInt32SizeNoTag(testCase.length() * 3)); |
571 assertEquals(11, CodedOutputStream.computeStringSize(1, testCase)); | 560 assertEquals(11, CodedOutputStream.computeStringSize(1, testCase)); |
572 // Tag is one byte, varint describing string length is 1 byte, string length
is 9 bytes. | 561 // Tag is one byte, varint describing string length is 1 byte, string length
is 9 bytes. |
573 // An array of size 1 will cause a failure when trying to write the varint. | 562 // An array of size 1 will cause a failure when trying to write the varint. |
574 for (OutputType outputType : | 563 for (OutputType outputType : |
575 new OutputType[] { | 564 new OutputType[] {OutputType.ARRAY, OutputType.NIO_HEAP, OutputType.NIO_
DIRECT}) { |
576 OutputType.ARRAY, | |
577 OutputType.NIO_HEAP, | |
578 OutputType.NIO_DIRECT_SAFE, | |
579 OutputType.NIO_DIRECT_UNSAFE | |
580 }) { | |
581 for (int i = 0; i < 11; i++) { | 565 for (int i = 0; i < 11; i++) { |
582 Coder coder = outputType.newCoder(i); | 566 Coder coder = outputType.newCoder(i); |
583 try { | 567 try { |
584 coder.stream().writeString(1, testCase); | 568 coder.stream().writeString(1, testCase); |
585 fail("Should have thrown an out of space exception"); | 569 fail("Should have thrown an out of space exception"); |
586 } catch (CodedOutputStream.OutOfSpaceException expected) { | 570 } catch (CodedOutputStream.OutOfSpaceException expected) { |
587 } | 571 } |
588 } | 572 } |
589 } | 573 } |
590 } | 574 } |
(...skipping 17 matching lines...) Expand all Loading... |
608 for (int i : lengths) { | 592 for (int i : lengths) { |
609 testEncodingOfString(outputType, 'q', i); // 1 byte per char | 593 testEncodingOfString(outputType, 'q', i); // 1 byte per char |
610 testEncodingOfString(outputType, '\u07FF', i); // 2 bytes per char | 594 testEncodingOfString(outputType, '\u07FF', i); // 2 bytes per char |
611 testEncodingOfString(outputType, '\u0981', i); // 3 bytes per char | 595 testEncodingOfString(outputType, '\u0981', i); // 3 bytes per char |
612 } | 596 } |
613 } | 597 } |
614 } | 598 } |
615 | 599 |
616 public void testNioEncodersWithInitialOffsets() throws Exception { | 600 public void testNioEncodersWithInitialOffsets() throws Exception { |
617 String value = "abc"; | 601 String value = "abc"; |
618 for (Coder coder : | 602 for (Coder coder : new Coder[] {new NioHeapCoder(10, 2), new NioDirectCoder(
10, 2)}) { |
619 new Coder[] { | |
620 new NioHeapCoder(10, 2), new NioDirectCoder(10, 2, false), new NioDire
ctCoder(10, 2, true) | |
621 }) { | |
622 coder.stream().writeStringNoTag(value); | 603 coder.stream().writeStringNoTag(value); |
623 coder.stream().flush(); | 604 coder.stream().flush(); |
624 assertEqualBytes(coder.getOutputType(), new byte[] {3, 'a', 'b', 'c'}, cod
er.toByteArray()); | 605 assertEqualBytes(coder.getOutputType(), new byte[]{3, 'a', 'b', 'c'}, code
r.toByteArray()); |
625 } | 606 } |
626 } | 607 } |
627 | 608 |
628 /** | 609 /** |
629 * Parses the given bytes using writeRawLittleEndian32() and checks | 610 * Parses the given bytes using writeRawLittleEndian32() and checks |
630 * that the result matches the given value. | 611 * that the result matches the given value. |
631 */ | 612 */ |
632 private static void assertWriteLittleEndian32(byte[] data, int value) throws E
xception { | 613 private static void assertWriteLittleEndian32(byte[] data, int value) throws E
xception { |
633 for (OutputType outputType : OutputType.values()) { | 614 for (OutputType outputType : OutputType.values()) { |
634 Coder coder = outputType.newCoder(data.length); | 615 Coder coder = outputType.newCoder(data.length); |
(...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
786 coder.stream().writeUInt32NoTag((int) value); | 767 coder.stream().writeUInt32NoTag((int) value); |
787 coder.stream().flush(); | 768 coder.stream().flush(); |
788 byte[] bytes = coder.toByteArray(); | 769 byte[] bytes = coder.toByteArray(); |
789 assertEquals( | 770 assertEquals( |
790 outputType.name(), bytes.length, CodedOutputStream.computeUInt32SizeNo
Tag((int) value)); | 771 outputType.name(), bytes.length, CodedOutputStream.computeUInt32SizeNo
Tag((int) value)); |
791 CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputSt
ream(bytes)); | 772 CodedInputStream input = CodedInputStream.newInstance(new ByteArrayInputSt
ream(bytes)); |
792 assertEquals(outputType.name(), value, input.readRawVarint32()); | 773 assertEquals(outputType.name(), value, input.readRawVarint32()); |
793 } | 774 } |
794 } | 775 } |
795 } | 776 } |
OLD | NEW |