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