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.UnittestMset.RawMessageSet; 34 import protobuf_unittest.UnittestMset.TestMessageSetExtension1; 35 import protobuf_unittest.UnittestMset.TestMessageSetExtension2; 36 import protobuf_unittest.UnittestProto; 37 import protobuf_unittest.UnittestProto.TestAllExtensions; 38 import protobuf_unittest.UnittestProto.TestAllTypes; 39 import protobuf_unittest.UnittestProto.TestExtensionInsideTable; 40 import protobuf_unittest.UnittestProto.TestFieldOrderings; 41 import protobuf_unittest.UnittestProto.TestOneof2; 42 import protobuf_unittest.UnittestProto.TestOneofBackwardsCompatible; 43 import protobuf_unittest.UnittestProto.TestPackedExtensions; 44 import protobuf_unittest.UnittestProto.TestPackedTypes; 45 import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet; 46 import java.io.ByteArrayInputStream; 47 import java.io.ByteArrayOutputStream; 48 import java.util.List; 49 import junit.framework.TestCase; 50 51 /** 52 * Tests related to parsing and serialization. 53 * 54 * @author kenton@google.com (Kenton Varda) 55 */ 56 public class WireFormatTest extends TestCase { 57 58 private static final int TYPE_ID_1 = 59 TestMessageSetExtension1.getDescriptor().getExtensions().get(0).getNumber(); 60 private static final int TYPE_ID_2 = 61 TestMessageSetExtension2.getDescriptor().getExtensions().get(0).getNumber(); 62 private static final int UNKNOWN_TYPE_ID = 1550055; 63 testSerialization()64 public void testSerialization() throws Exception { 65 TestAllTypes message = TestUtil.getAllSet(); 66 67 ByteString rawBytes = message.toByteString(); 68 assertEquals(rawBytes.size(), message.getSerializedSize()); 69 70 TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes); 71 72 TestUtil.assertAllFieldsSet(message2); 73 } 74 testSerializationPacked()75 public void testSerializationPacked() throws Exception { 76 TestPackedTypes message = TestUtil.getPackedSet(); 77 78 ByteString rawBytes = message.toByteString(); 79 assertEquals(rawBytes.size(), message.getSerializedSize()); 80 81 TestPackedTypes message2 = TestPackedTypes.parseFrom(rawBytes); 82 83 TestUtil.assertPackedFieldsSet(message2); 84 } 85 testSerializeExtensions()86 public void testSerializeExtensions() throws Exception { 87 // TestAllTypes and TestAllExtensions should have compatible wire formats, 88 // so if we serialize a TestAllExtensions then parse it as TestAllTypes 89 // it should work. 90 91 TestAllExtensions message = TestUtil.getAllExtensionsSet(); 92 ByteString rawBytes = message.toByteString(); 93 assertEquals(rawBytes.size(), message.getSerializedSize()); 94 95 TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes); 96 97 TestUtil.assertAllFieldsSet(message2); 98 } 99 testSerializePackedExtensions()100 public void testSerializePackedExtensions() throws Exception { 101 // TestPackedTypes and TestPackedExtensions should have compatible wire 102 // formats; check that they serialize to the same string. 103 TestPackedExtensions message = TestUtil.getPackedExtensionsSet(); 104 ByteString rawBytes = message.toByteString(); 105 106 TestPackedTypes message2 = TestUtil.getPackedSet(); 107 ByteString rawBytes2 = message2.toByteString(); 108 109 assertEquals(rawBytes, rawBytes2); 110 } 111 testSerializationPackedWithoutGetSerializedSize()112 public void testSerializationPackedWithoutGetSerializedSize() throws Exception { 113 // Write directly to an OutputStream, without invoking getSerializedSize() 114 // This used to be a bug where the size of a packed field was incorrect, 115 // since getSerializedSize() was never invoked. 116 TestPackedTypes message = TestUtil.getPackedSet(); 117 118 // Directly construct a CodedOutputStream around the actual OutputStream, 119 // in case writeTo(OutputStream output) invokes getSerializedSize(); 120 ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); 121 CodedOutputStream codedOutput = CodedOutputStream.newInstance(outputStream); 122 123 message.writeTo(codedOutput); 124 125 codedOutput.flush(); 126 127 TestPackedTypes message2 = TestPackedTypes.parseFrom(outputStream.toByteArray()); 128 129 TestUtil.assertPackedFieldsSet(message2); 130 } 131 testParseExtensions()132 public void testParseExtensions() throws Exception { 133 // TestAllTypes and TestAllExtensions should have compatible wire formats, 134 // so if we serialize a TestAllTypes then parse it as TestAllExtensions 135 // it should work. 136 137 TestAllTypes message = TestUtil.getAllSet(); 138 ByteString rawBytes = message.toByteString(); 139 140 ExtensionRegistryLite registry = TestUtil.getExtensionRegistry(); 141 142 TestAllExtensions message2 = TestAllExtensions.parseFrom(rawBytes, registry); 143 144 TestUtil.assertAllExtensionsSet(message2); 145 } 146 testParsePackedExtensions()147 public void testParsePackedExtensions() throws Exception { 148 // Ensure that packed extensions can be properly parsed. 149 TestPackedExtensions message = TestUtil.getPackedExtensionsSet(); 150 ByteString rawBytes = message.toByteString(); 151 152 ExtensionRegistryLite registry = TestUtil.getExtensionRegistry(); 153 154 TestPackedExtensions message2 = TestPackedExtensions.parseFrom(rawBytes, registry); 155 156 TestUtil.assertPackedExtensionsSet(message2); 157 } 158 testSerializeDelimited()159 public void testSerializeDelimited() throws Exception { 160 ByteArrayOutputStream output = new ByteArrayOutputStream(); 161 TestUtil.getAllSet().writeDelimitedTo(output); 162 output.write(12); 163 TestUtil.getPackedSet().writeDelimitedTo(output); 164 output.write(34); 165 166 ByteArrayInputStream input = new ByteArrayInputStream(output.toByteArray()); 167 168 TestUtil.assertAllFieldsSet(TestAllTypes.parseDelimitedFrom(input)); 169 assertEquals(12, input.read()); 170 TestUtil.assertPackedFieldsSet(TestPackedTypes.parseDelimitedFrom(input)); 171 assertEquals(34, input.read()); 172 assertEquals(-1, input.read()); 173 174 // We're at EOF, so parsing again should return null. 175 assertTrue(TestAllTypes.parseDelimitedFrom(input) == null); 176 } 177 assertFieldsInOrder(ByteString data)178 private void assertFieldsInOrder(ByteString data) throws Exception { 179 CodedInputStream input = data.newCodedInput(); 180 int previousTag = 0; 181 182 while (true) { 183 int tag = input.readTag(); 184 if (tag == 0) { 185 break; 186 } 187 188 assertTrue(tag > previousTag); 189 previousTag = tag; 190 input.skipField(tag); 191 } 192 } 193 testInterleavedFieldsAndExtensions()194 public void testInterleavedFieldsAndExtensions() throws Exception { 195 // Tests that fields are written in order even when extension ranges 196 // are interleaved with field numbers. 197 ByteString data = 198 TestFieldOrderings.newBuilder() 199 .setMyInt(1) 200 .setMyString("foo") 201 .setMyFloat(1.0F) 202 .setExtension(UnittestProto.myExtensionInt, 23) 203 .setExtension(UnittestProto.myExtensionString, "bar") 204 .build() 205 .toByteString(); 206 assertFieldsInOrder(data); 207 208 Descriptors.Descriptor descriptor = TestFieldOrderings.getDescriptor(); 209 ByteString dynamicData = 210 DynamicMessage.newBuilder(TestFieldOrderings.getDescriptor()) 211 .setField(descriptor.findFieldByName("my_int"), 1L) 212 .setField(descriptor.findFieldByName("my_string"), "foo") 213 .setField(descriptor.findFieldByName("my_float"), 1.0F) 214 .setField(UnittestProto.myExtensionInt.getDescriptor(), 23) 215 .setField(UnittestProto.myExtensionString.getDescriptor(), "bar") 216 .build() 217 .toByteString(); 218 assertFieldsInOrder(dynamicData); 219 } 220 getTestFieldOrderingsRegistry()221 private ExtensionRegistry getTestFieldOrderingsRegistry() { 222 ExtensionRegistry result = ExtensionRegistry.newInstance(); 223 result.add(UnittestProto.myExtensionInt); 224 result.add(UnittestProto.myExtensionString); 225 return result; 226 } 227 testParseMultipleExtensionRanges()228 public void testParseMultipleExtensionRanges() throws Exception { 229 // Make sure we can parse a message that contains multiple extensions 230 // ranges. 231 TestFieldOrderings source = 232 TestFieldOrderings.newBuilder() 233 .setMyInt(1) 234 .setMyString("foo") 235 .setMyFloat(1.0F) 236 .setExtension(UnittestProto.myExtensionInt, 23) 237 .setExtension(UnittestProto.myExtensionString, "bar") 238 .build(); 239 TestFieldOrderings dest = 240 TestFieldOrderings.parseFrom(source.toByteString(), getTestFieldOrderingsRegistry()); 241 assertEquals(source, dest); 242 } 243 getTestExtensionInsideTableRegistry()244 private static ExtensionRegistry getTestExtensionInsideTableRegistry() { 245 ExtensionRegistry result = ExtensionRegistry.newInstance(); 246 result.add(UnittestProto.testExtensionInsideTableExtension); 247 return result; 248 } 249 testExtensionInsideTable()250 public void testExtensionInsideTable() throws Exception { 251 // Make sure the extension within the range of table is parsed correctly in experimental 252 // runtime. 253 TestExtensionInsideTable source = 254 TestExtensionInsideTable.newBuilder() 255 .setField1(1) 256 .setExtension(UnittestProto.testExtensionInsideTableExtension, 23) 257 .build(); 258 TestExtensionInsideTable dest = 259 TestExtensionInsideTable.parseFrom( 260 source.toByteString(), getTestExtensionInsideTableRegistry()); 261 assertEquals(source, dest); 262 } 263 testParseMultipleExtensionRangesDynamic()264 public void testParseMultipleExtensionRangesDynamic() throws Exception { 265 // Same as above except with DynamicMessage. 266 Descriptors.Descriptor descriptor = TestFieldOrderings.getDescriptor(); 267 DynamicMessage source = 268 DynamicMessage.newBuilder(TestFieldOrderings.getDescriptor()) 269 .setField(descriptor.findFieldByName("my_int"), 1L) 270 .setField(descriptor.findFieldByName("my_string"), "foo") 271 .setField(descriptor.findFieldByName("my_float"), 1.0F) 272 .setField(UnittestProto.myExtensionInt.getDescriptor(), 23) 273 .setField(UnittestProto.myExtensionString.getDescriptor(), "bar") 274 .build(); 275 DynamicMessage dest = 276 DynamicMessage.parseFrom( 277 descriptor, source.toByteString(), getTestFieldOrderingsRegistry()); 278 assertEquals(source, dest); 279 } 280 testSerializeMessageSetEagerly()281 public void testSerializeMessageSetEagerly() throws Exception { 282 testSerializeMessageSetWithFlag(true); 283 } 284 testSerializeMessageSetNotEagerly()285 public void testSerializeMessageSetNotEagerly() throws Exception { 286 testSerializeMessageSetWithFlag(false); 287 } 288 testSerializeMessageSetWithFlag(boolean eagerParsing)289 private void testSerializeMessageSetWithFlag(boolean eagerParsing) throws Exception { 290 ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing); 291 // Set up a TestMessageSet with two known messages and an unknown one. 292 TestMessageSet messageSet = 293 TestMessageSet.newBuilder() 294 .setExtension( 295 TestMessageSetExtension1.messageSetExtension, 296 TestMessageSetExtension1.newBuilder().setI(123).build()) 297 .setExtension( 298 TestMessageSetExtension2.messageSetExtension, 299 TestMessageSetExtension2.newBuilder().setStr("foo").build()) 300 .setUnknownFields( 301 UnknownFieldSet.newBuilder() 302 .addField( 303 UNKNOWN_TYPE_ID, 304 UnknownFieldSet.Field.newBuilder() 305 .addLengthDelimited(ByteString.copyFromUtf8("bar")) 306 .build()) 307 .build()) 308 .build(); 309 310 ByteString data = messageSet.toByteString(); 311 312 // Parse back using RawMessageSet and check the contents. 313 RawMessageSet raw = RawMessageSet.parseFrom(data); 314 315 assertTrue(raw.getUnknownFields().asMap().isEmpty()); 316 317 assertEquals(3, raw.getItemCount()); 318 assertEquals(TYPE_ID_1, raw.getItem(0).getTypeId()); 319 assertEquals(TYPE_ID_2, raw.getItem(1).getTypeId()); 320 assertEquals(UNKNOWN_TYPE_ID, raw.getItem(2).getTypeId()); 321 322 TestMessageSetExtension1 message1 = 323 TestMessageSetExtension1.parseFrom(raw.getItem(0).getMessage()); 324 assertEquals(123, message1.getI()); 325 326 TestMessageSetExtension2 message2 = 327 TestMessageSetExtension2.parseFrom(raw.getItem(1).getMessage()); 328 assertEquals("foo", message2.getStr()); 329 330 assertEquals("bar", raw.getItem(2).getMessage().toStringUtf8()); 331 } 332 testParseMessageSetEagerly()333 public void testParseMessageSetEagerly() throws Exception { 334 testParseMessageSetWithFlag(true); 335 } 336 testParseMessageSetNotEagerly()337 public void testParseMessageSetNotEagerly() throws Exception { 338 testParseMessageSetWithFlag(false); 339 } 340 testParseMessageSetWithFlag(boolean eagerParsing)341 private void testParseMessageSetWithFlag(boolean eagerParsing) throws Exception { 342 ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing); 343 ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance(); 344 extensionRegistry.add(TestMessageSetExtension1.messageSetExtension); 345 extensionRegistry.add(TestMessageSetExtension2.messageSetExtension); 346 347 // Set up a RawMessageSet with two known messages and an unknown one. 348 RawMessageSet raw = 349 RawMessageSet.newBuilder() 350 .addItem( 351 RawMessageSet.Item.newBuilder() 352 .setTypeId(TYPE_ID_1) 353 .setMessage( 354 TestMessageSetExtension1.newBuilder().setI(123).build().toByteString()) 355 .build()) 356 .addItem( 357 RawMessageSet.Item.newBuilder() 358 .setTypeId(TYPE_ID_2) 359 .setMessage( 360 TestMessageSetExtension2.newBuilder().setStr("foo").build().toByteString()) 361 .build()) 362 .addItem( 363 RawMessageSet.Item.newBuilder() 364 .setTypeId(UNKNOWN_TYPE_ID) 365 .setMessage(ByteString.copyFromUtf8("bar")) 366 .build()) 367 .build(); 368 369 ByteString data = raw.toByteString(); 370 371 // Parse as a TestMessageSet and check the contents. 372 TestMessageSet messageSet = TestMessageSet.parseFrom(data, extensionRegistry); 373 374 assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI()); 375 assertEquals( 376 "foo", messageSet.getExtension(TestMessageSetExtension2.messageSetExtension).getStr()); 377 378 // Check for unknown field with type LENGTH_DELIMITED, 379 // number UNKNOWN_TYPE_ID, and contents "bar". 380 UnknownFieldSet unknownFields = messageSet.getUnknownFields(); 381 assertEquals(1, unknownFields.asMap().size()); 382 assertTrue(unknownFields.hasField(UNKNOWN_TYPE_ID)); 383 384 UnknownFieldSet.Field field = unknownFields.getField(UNKNOWN_TYPE_ID); 385 assertEquals(1, field.getLengthDelimitedList().size()); 386 assertEquals("bar", field.getLengthDelimitedList().get(0).toStringUtf8()); 387 } 388 testParseMessageSetExtensionEagerly()389 public void testParseMessageSetExtensionEagerly() throws Exception { 390 testParseMessageSetExtensionWithFlag(true); 391 } 392 testParseMessageSetExtensionNotEagerly()393 public void testParseMessageSetExtensionNotEagerly() throws Exception { 394 testParseMessageSetExtensionWithFlag(false); 395 } 396 testParseMessageSetExtensionWithFlag(boolean eagerParsing)397 private void testParseMessageSetExtensionWithFlag(boolean eagerParsing) throws Exception { 398 ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing); 399 ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance(); 400 extensionRegistry.add(TestMessageSetExtension1.messageSetExtension); 401 402 // Set up a RawMessageSet with a known messages. 403 RawMessageSet raw = 404 RawMessageSet.newBuilder() 405 .addItem( 406 RawMessageSet.Item.newBuilder() 407 .setTypeId(TYPE_ID_1) 408 .setMessage( 409 TestMessageSetExtension1.newBuilder().setI(123).build().toByteString()) 410 .build()) 411 .build(); 412 413 ByteString data = raw.toByteString(); 414 415 // Parse as a TestMessageSet and check the contents. 416 TestMessageSet messageSet = TestMessageSet.parseFrom(data, extensionRegistry); 417 assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI()); 418 } 419 testMergeLazyMessageSetExtensionEagerly()420 public void testMergeLazyMessageSetExtensionEagerly() throws Exception { 421 testMergeLazyMessageSetExtensionWithFlag(true); 422 } 423 testMergeLazyMessageSetExtensionNotEagerly()424 public void testMergeLazyMessageSetExtensionNotEagerly() throws Exception { 425 testMergeLazyMessageSetExtensionWithFlag(false); 426 } 427 testMergeLazyMessageSetExtensionWithFlag(boolean eagerParsing)428 private void testMergeLazyMessageSetExtensionWithFlag(boolean eagerParsing) throws Exception { 429 ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing); 430 ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance(); 431 extensionRegistry.add(TestMessageSetExtension1.messageSetExtension); 432 433 // Set up a RawMessageSet with a known messages. 434 RawMessageSet raw = 435 RawMessageSet.newBuilder() 436 .addItem( 437 RawMessageSet.Item.newBuilder() 438 .setTypeId(TYPE_ID_1) 439 .setMessage( 440 TestMessageSetExtension1.newBuilder().setI(123).build().toByteString()) 441 .build()) 442 .build(); 443 444 ByteString data = raw.toByteString(); 445 446 // Parse as a TestMessageSet and store value into lazy field 447 TestMessageSet messageSet = TestMessageSet.parseFrom(data, extensionRegistry); 448 // Merge lazy field check the contents. 449 messageSet = messageSet.toBuilder().mergeFrom(data, extensionRegistry).build(); 450 assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI()); 451 } 452 testMergeMessageSetExtensionEagerly()453 public void testMergeMessageSetExtensionEagerly() throws Exception { 454 testMergeMessageSetExtensionWithFlag(true); 455 } 456 testMergeMessageSetExtensionNotEagerly()457 public void testMergeMessageSetExtensionNotEagerly() throws Exception { 458 testMergeMessageSetExtensionWithFlag(false); 459 } 460 testMergeMessageSetExtensionWithFlag(boolean eagerParsing)461 private void testMergeMessageSetExtensionWithFlag(boolean eagerParsing) throws Exception { 462 ExtensionRegistryLite.setEagerlyParseMessageSets(eagerParsing); 463 ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance(); 464 extensionRegistry.add(TestMessageSetExtension1.messageSetExtension); 465 466 // Set up a RawMessageSet with a known messages. 467 RawMessageSet raw = 468 RawMessageSet.newBuilder() 469 .addItem( 470 RawMessageSet.Item.newBuilder() 471 .setTypeId(TYPE_ID_1) 472 .setMessage( 473 TestMessageSetExtension1.newBuilder().setI(123).build().toByteString()) 474 .build()) 475 .build(); 476 477 // Serialize RawMessageSet unnormally (message value before type id) 478 ByteString.CodedBuilder out = ByteString.newCodedBuilder(raw.getSerializedSize()); 479 CodedOutputStream output = out.getCodedOutput(); 480 List<RawMessageSet.Item> items = raw.getItemList(); 481 for (int i = 0; i < items.size(); i++) { 482 RawMessageSet.Item item = items.get(i); 483 output.writeTag(1, WireFormat.WIRETYPE_START_GROUP); 484 output.writeBytes(3, item.getMessage()); 485 output.writeInt32(2, item.getTypeId()); 486 output.writeTag(1, WireFormat.WIRETYPE_END_GROUP); 487 } 488 ByteString data = out.build(); 489 490 // Merge bytes into TestMessageSet and check the contents. 491 TestMessageSet messageSet = 492 TestMessageSet.newBuilder().mergeFrom(data, extensionRegistry).build(); 493 assertEquals(123, messageSet.getExtension(TestMessageSetExtension1.messageSetExtension).getI()); 494 } 495 496 // ================================================================ 497 // oneof testOneofWireFormat()498 public void testOneofWireFormat() throws Exception { 499 TestOneof2.Builder builder = TestOneof2.newBuilder(); 500 TestUtil.setOneof(builder); 501 TestOneof2 message = builder.build(); 502 ByteString rawBytes = message.toByteString(); 503 504 assertEquals(rawBytes.size(), message.getSerializedSize()); 505 506 TestOneof2 message2 = TestOneof2.parseFrom(rawBytes); 507 TestUtil.assertOneofSet(message2); 508 } 509 testOneofOnlyLastSet()510 public void testOneofOnlyLastSet() throws Exception { 511 TestOneofBackwardsCompatible source = 512 TestOneofBackwardsCompatible.newBuilder().setFooInt(100).setFooString("101").build(); 513 514 ByteString rawBytes = source.toByteString(); 515 TestOneof2 message = TestOneof2.parseFrom(rawBytes); 516 assertFalse(message.hasFooInt()); 517 assertTrue(message.hasFooString()); 518 } 519 } 520