1 // Protocol Buffers - Google's data interchange format 2 // Copyright 2008 Google Inc. All rights reserved. 3 // https://developers.google.com/protocol-buffers/ 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; 32 33 import protobuf_unittest.UnittestOptimizeFor; 34 import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize; 35 import protobuf_unittest.UnittestOptimizeFor.TestRequiredOptimizedForSize; 36 import protobuf_unittest.UnittestProto; 37 import protobuf_unittest.UnittestProto.ForeignMessage; 38 import protobuf_unittest.UnittestProto.TestAllTypes; 39 import protobuf_unittest.UnittestProto.TestEmptyMessage; 40 import protobuf_unittest.UnittestProto.TestParsingMerge; 41 import protobuf_unittest.UnittestProto.TestRequired; 42 import java.io.ByteArrayInputStream; 43 import java.io.ByteArrayOutputStream; 44 import java.io.IOException; 45 import java.io.InputStream; 46 import java.io.InterruptedIOException; 47 import junit.framework.TestCase; 48 49 /** 50 * Unit test for {@link Parser}. 51 * 52 * @author liujisi@google.com (Pherl Liu) 53 */ 54 public class ParserTest extends TestCase { testGeneratedMessageParserSingleton()55 public void testGeneratedMessageParserSingleton() throws Exception { 56 for (int i = 0; i < 10; i++) { 57 assertEquals(TestAllTypes.parser(), TestUtil.getAllSet().getParserForType()); 58 } 59 } 60 assertRoundTripEquals(MessageLite message, ExtensionRegistryLite registry)61 private void assertRoundTripEquals(MessageLite message, ExtensionRegistryLite registry) 62 throws Exception { 63 final byte[] data = message.toByteArray(); 64 final int offset = 20; 65 final int length = data.length; 66 final int padding = 30; 67 Parser<? extends MessageLite> parser = message.getParserForType(); 68 assertMessageEquals(message, parser.parseFrom(data, registry)); 69 assertMessageEquals( 70 message, 71 parser.parseFrom(generatePaddingArray(data, offset, padding), offset, length, registry)); 72 assertMessageEquals(message, parser.parseFrom(message.toByteString(), registry)); 73 assertMessageEquals(message, parser.parseFrom(new ByteArrayInputStream(data), registry)); 74 assertMessageEquals(message, parser.parseFrom(CodedInputStream.newInstance(data), registry)); 75 assertMessageEquals( 76 message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer(), registry)); 77 } 78 79 @SuppressWarnings("unchecked") assertRoundTripEquals(MessageLite message)80 private void assertRoundTripEquals(MessageLite message) throws Exception { 81 final byte[] data = message.toByteArray(); 82 final int offset = 20; 83 final int length = data.length; 84 final int padding = 30; 85 86 Parser<MessageLite> parser = (Parser<MessageLite>) message.getParserForType(); 87 assertMessageEquals(message, parser.parseFrom(data)); 88 assertMessageEquals( 89 message, parser.parseFrom(generatePaddingArray(data, offset, padding), offset, length)); 90 assertMessageEquals(message, parser.parseFrom(message.toByteString())); 91 assertMessageEquals(message, parser.parseFrom(new ByteArrayInputStream(data))); 92 assertMessageEquals(message, parser.parseFrom(CodedInputStream.newInstance(data))); 93 assertMessageEquals(message, parser.parseFrom(message.toByteString().asReadOnlyByteBuffer())); 94 } 95 assertMessageEquals(MessageLite expected, MessageLite actual)96 private void assertMessageEquals(MessageLite expected, MessageLite actual) throws Exception { 97 if (expected instanceof Message) { 98 assertEquals(expected, actual); 99 } else { 100 assertEquals(expected.toByteString(), actual.toByteString()); 101 } 102 } 103 generatePaddingArray(byte[] data, int offset, int padding)104 private byte[] generatePaddingArray(byte[] data, int offset, int padding) { 105 byte[] result = new byte[offset + data.length + padding]; 106 System.arraycopy(data, 0, result, offset, data.length); 107 return result; 108 } 109 testNormalMessage()110 public void testNormalMessage() throws Exception { 111 assertRoundTripEquals(TestUtil.getAllSet()); 112 } 113 114 testParsePartial()115 public void testParsePartial() throws Exception { 116 assertParsePartial(TestRequired.parser(), TestRequired.newBuilder().setA(1).buildPartial()); 117 } 118 assertParsePartial(Parser<T> parser, T partialMessage)119 private <T extends MessageLite> void assertParsePartial(Parser<T> parser, T partialMessage) 120 throws Exception { 121 final String errorString = "Should throw exceptions when the parsed message isn't initialized."; 122 123 // parsePartialFrom should pass. 124 byte[] data = partialMessage.toByteArray(); 125 assertEquals(partialMessage, parser.parsePartialFrom(data)); 126 assertEquals(partialMessage, parser.parsePartialFrom(partialMessage.toByteString())); 127 assertEquals(partialMessage, parser.parsePartialFrom(new ByteArrayInputStream(data))); 128 assertEquals(partialMessage, parser.parsePartialFrom(CodedInputStream.newInstance(data))); 129 130 // parseFrom(ByteArray) 131 try { 132 parser.parseFrom(partialMessage.toByteArray()); 133 fail(errorString); 134 } catch (InvalidProtocolBufferException e) { 135 // pass. 136 } 137 138 // parseFrom(ByteString) 139 try { 140 parser.parseFrom(partialMessage.toByteString()); 141 fail(errorString); 142 } catch (InvalidProtocolBufferException e) { 143 // pass. 144 } 145 146 // parseFrom(InputStream) 147 try { 148 parser.parseFrom(new ByteArrayInputStream(partialMessage.toByteArray())); 149 fail(errorString); 150 } catch (IOException e) { 151 // pass. 152 } 153 154 // parseFrom(CodedInputStream) 155 try { 156 parser.parseFrom(CodedInputStream.newInstance(partialMessage.toByteArray())); 157 fail(errorString); 158 } catch (IOException e) { 159 // pass. 160 } 161 } 162 testParseExtensions()163 public void testParseExtensions() throws Exception { 164 assertRoundTripEquals(TestUtil.getAllExtensionsSet(), TestUtil.getExtensionRegistry()); 165 } 166 testParsePacked()167 public void testParsePacked() throws Exception { 168 assertRoundTripEquals(TestUtil.getPackedSet()); 169 assertRoundTripEquals(TestUtil.getPackedExtensionsSet(), TestUtil.getExtensionRegistry()); 170 } 171 testParseDelimitedTo()172 public void testParseDelimitedTo() throws Exception { 173 // Write normal Message. 174 TestAllTypes normalMessage = TestUtil.getAllSet(); 175 ByteArrayOutputStream output = new ByteArrayOutputStream(); 176 normalMessage.writeDelimitedTo(output); 177 normalMessage.writeDelimitedTo(output); 178 179 InputStream input = new ByteArrayInputStream(output.toByteArray()); 180 assertMessageEquals(normalMessage, normalMessage.getParserForType().parseDelimitedFrom(input)); 181 assertMessageEquals(normalMessage, normalMessage.getParserForType().parseDelimitedFrom(input)); 182 } 183 testParseUnknownFields()184 public void testParseUnknownFields() throws Exception { 185 // All fields will be treated as unknown fields in emptyMessage. 186 TestEmptyMessage emptyMessage = 187 TestEmptyMessage.parser().parseFrom(TestUtil.getAllSet().toByteString()); 188 assertEquals(TestUtil.getAllSet().toByteString(), emptyMessage.toByteString()); 189 } 190 191 testOptimizeForSize()192 public void testOptimizeForSize() throws Exception { 193 TestOptimizedForSize.Builder builder = TestOptimizedForSize.newBuilder(); 194 builder.setI(12).setMsg(ForeignMessage.newBuilder().setC(34).build()); 195 builder.setExtension(TestOptimizedForSize.testExtension, 56); 196 builder.setExtension( 197 TestOptimizedForSize.testExtension2, 198 TestRequiredOptimizedForSize.newBuilder().setX(78).build()); 199 200 TestOptimizedForSize message = builder.build(); 201 ExtensionRegistry registry = ExtensionRegistry.newInstance(); 202 UnittestOptimizeFor.registerAllExtensions(registry); 203 204 assertRoundTripEquals(message, registry); 205 } 206 207 /** Helper method for {@link #testParsingMerge()}. */ assertMessageMerged(TestAllTypes allTypes)208 private void assertMessageMerged(TestAllTypes allTypes) throws Exception { 209 assertEquals(3, allTypes.getOptionalInt32()); 210 assertEquals(2, allTypes.getOptionalInt64()); 211 assertEquals("hello", allTypes.getOptionalString()); 212 } 213 testParsingMerge()214 public void testParsingMerge() throws Exception { 215 // Build messages. 216 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 217 TestAllTypes msg1 = builder.setOptionalInt32(1).build(); 218 builder.clear(); 219 TestAllTypes msg2 = builder.setOptionalInt64(2).build(); 220 builder.clear(); 221 TestAllTypes msg3 = builder.setOptionalInt32(3).setOptionalString("hello").build(); 222 223 // Build groups. 224 TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG1 = 225 TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder().setField1(msg1).build(); 226 TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG2 = 227 TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder().setField1(msg2).build(); 228 TestParsingMerge.RepeatedFieldsGenerator.Group1 optionalG3 = 229 TestParsingMerge.RepeatedFieldsGenerator.Group1.newBuilder().setField1(msg3).build(); 230 TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG1 = 231 TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder().setField1(msg1).build(); 232 TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG2 = 233 TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder().setField1(msg2).build(); 234 TestParsingMerge.RepeatedFieldsGenerator.Group2 repeatedG3 = 235 TestParsingMerge.RepeatedFieldsGenerator.Group2.newBuilder().setField1(msg3).build(); 236 237 // Assign and serialize RepeatedFieldsGenerator. 238 ByteString data = 239 TestParsingMerge.RepeatedFieldsGenerator.newBuilder() 240 .addField1(msg1) 241 .addField1(msg2) 242 .addField1(msg3) 243 .addField2(msg1) 244 .addField2(msg2) 245 .addField2(msg3) 246 .addField3(msg1) 247 .addField3(msg2) 248 .addField3(msg3) 249 .addGroup1(optionalG1) 250 .addGroup1(optionalG2) 251 .addGroup1(optionalG3) 252 .addGroup2(repeatedG1) 253 .addGroup2(repeatedG2) 254 .addGroup2(repeatedG3) 255 .addExt1(msg1) 256 .addExt1(msg2) 257 .addExt1(msg3) 258 .addExt2(msg1) 259 .addExt2(msg2) 260 .addExt2(msg3) 261 .build() 262 .toByteString(); 263 264 // Parse TestParsingMerge. 265 ExtensionRegistry registry = ExtensionRegistry.newInstance(); 266 UnittestProto.registerAllExtensions(registry); 267 TestParsingMerge parsingMerge = TestParsingMerge.parser().parseFrom(data, registry); 268 269 // Required and optional fields should be merged. 270 assertMessageMerged(parsingMerge.getRequiredAllTypes()); 271 assertMessageMerged(parsingMerge.getOptionalAllTypes()); 272 assertMessageMerged(parsingMerge.getOptionalGroup().getOptionalGroupAllTypes()); 273 assertMessageMerged(parsingMerge.getExtension(TestParsingMerge.optionalExt)); 274 275 // Repeated fields should not be merged. 276 assertEquals(3, parsingMerge.getRepeatedAllTypesCount()); 277 assertEquals(3, parsingMerge.getRepeatedGroupCount()); 278 assertEquals(3, parsingMerge.getExtensionCount(TestParsingMerge.repeatedExt)); 279 } 280 testParseDelimitedFrom_firstByteInterrupted_preservesCause()281 public void testParseDelimitedFrom_firstByteInterrupted_preservesCause() { 282 try { 283 TestAllTypes.parseDelimitedFrom( 284 new InputStream() { 285 @Override 286 public int read() throws IOException { 287 throw new InterruptedIOException(); 288 } 289 }); 290 fail("Expected InterruptedIOException"); 291 } catch (Exception e) { 292 assertEquals(InterruptedIOException.class, e.getClass()); 293 } 294 } 295 testParseDelimitedFrom_secondByteInterrupted_preservesCause()296 public void testParseDelimitedFrom_secondByteInterrupted_preservesCause() { 297 try { 298 TestAllTypes.parseDelimitedFrom( 299 new InputStream() { 300 private int i; 301 302 @Override 303 public int read() throws IOException { 304 switch (i++) { 305 case 0: 306 return 1; 307 case 1: 308 throw new InterruptedIOException(); 309 default: 310 throw new AssertionError(); 311 } 312 } 313 }); 314 fail("Expected InterruptedIOException"); 315 } catch (Exception e) { 316 assertEquals(InterruptedIOException.class, e.getClass()); 317 } 318 } 319 } 320