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