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 import static org.junit.Assert.assertThrows; 12 13 import com.google.protobuf.Descriptors.EnumDescriptor; 14 import com.google.protobuf.Descriptors.FieldDescriptor; 15 import com.google.protobuf.Descriptors.OneofDescriptor; 16 import dynamicmessagetest.DynamicMessageTestProto.EmptyMessage; 17 import dynamicmessagetest.DynamicMessageTestProto.MessageWithMapFields; 18 import protobuf_unittest.UnittestMset.TestMessageSetExtension2; 19 import protobuf_unittest.UnittestProto; 20 import protobuf_unittest.UnittestProto.TestAllExtensions; 21 import protobuf_unittest.UnittestProto.TestAllTypes; 22 import protobuf_unittest.UnittestProto.TestAllTypes.NestedMessage; 23 import protobuf_unittest.UnittestProto.TestEmptyMessage; 24 import protobuf_unittest.UnittestProto.TestPackedTypes; 25 import proto2_wireformat_unittest.UnittestMsetWireFormat.TestMessageSet; 26 import java.util.ArrayList; 27 import org.junit.Test; 28 import org.junit.function.ThrowingRunnable; 29 import org.junit.runner.RunWith; 30 import org.junit.runners.JUnit4; 31 32 /** 33 * Unit test for {@link DynamicMessage}. See also {@link MessageTest}, which tests some {@link 34 * DynamicMessage} functionality. 35 */ 36 @RunWith(JUnit4.class) 37 public class DynamicMessageTest { 38 TestUtil.ReflectionTester reflectionTester = 39 new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null); 40 41 TestUtil.ReflectionTester extensionsReflectionTester = 42 new TestUtil.ReflectionTester( 43 TestAllExtensions.getDescriptor(), TestUtil.getFullExtensionRegistry()); 44 TestUtil.ReflectionTester packedReflectionTester = 45 new TestUtil.ReflectionTester(TestPackedTypes.getDescriptor(), null); 46 47 @Test testDynamicMessageAccessors()48 public void testDynamicMessageAccessors() throws Exception { 49 Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor()); 50 reflectionTester.setAllFieldsViaReflection(builder); 51 Message message = builder.build(); 52 reflectionTester.assertAllFieldsSetViaReflection(message); 53 } 54 55 @Test testSettersAfterBuild()56 public void testSettersAfterBuild() throws Exception { 57 Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor()); 58 Message firstMessage = builder.build(); 59 // double build() 60 Message unused = builder.build(); 61 // clear() after build() 62 builder.clear(); 63 // setters after build() 64 reflectionTester.setAllFieldsViaReflection(builder); 65 Message message = builder.build(); 66 reflectionTester.assertAllFieldsSetViaReflection(message); 67 // repeated setters after build() 68 reflectionTester.modifyRepeatedFieldsViaReflection(builder); 69 message = builder.build(); 70 reflectionTester.assertRepeatedFieldsModifiedViaReflection(message); 71 // firstMessage shouldn't have been modified. 72 reflectionTester.assertClearViaReflection(firstMessage); 73 } 74 75 @Test testUnknownFields()76 public void testUnknownFields() throws Exception { 77 Message.Builder builder = DynamicMessage.newBuilder(TestEmptyMessage.getDescriptor()); 78 builder.setUnknownFields( 79 UnknownFieldSet.newBuilder() 80 .addField(1, UnknownFieldSet.Field.newBuilder().addVarint(1).build()) 81 .addField(2, UnknownFieldSet.Field.newBuilder().addFixed32(1).build()) 82 .build()); 83 Message message = builder.build(); 84 assertThat(builder.getUnknownFields().asMap()).hasSize(2); 85 // clone() with unknown fields 86 Message.Builder newBuilder = builder.clone(); 87 assertThat(newBuilder.getUnknownFields().asMap()).hasSize(2); 88 // clear() with unknown fields 89 newBuilder.clear(); 90 assertThat(newBuilder.getUnknownFields().asMap()).isEmpty(); 91 // serialize/parse with unknown fields 92 newBuilder.mergeFrom(message.toByteString()); 93 assertThat(newBuilder.getUnknownFields().asMap()).hasSize(2); 94 } 95 96 @Test testDynamicMessageSettersRejectNull()97 public void testDynamicMessageSettersRejectNull() throws Exception { 98 Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor()); 99 reflectionTester.assertReflectionSettersRejectNull(builder); 100 } 101 102 @Test testDynamicMessageExtensionAccessors()103 public void testDynamicMessageExtensionAccessors() throws Exception { 104 // We don't need to extensively test DynamicMessage's handling of 105 // extensions because, frankly, it doesn't do anything special with them. 106 // It treats them just like any other fields. 107 Message.Builder builder = DynamicMessage.newBuilder(TestAllExtensions.getDescriptor()); 108 extensionsReflectionTester.setAllFieldsViaReflection(builder); 109 Message message = builder.build(); 110 extensionsReflectionTester.assertAllFieldsSetViaReflection(message); 111 } 112 113 @Test testDynamicMessageExtensionSettersRejectNull()114 public void testDynamicMessageExtensionSettersRejectNull() throws Exception { 115 Message.Builder builder = DynamicMessage.newBuilder(TestAllExtensions.getDescriptor()); 116 extensionsReflectionTester.assertReflectionSettersRejectNull(builder); 117 } 118 119 @Test testDynamicMessageRepeatedSetters()120 public void testDynamicMessageRepeatedSetters() throws Exception { 121 Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor()); 122 reflectionTester.setAllFieldsViaReflection(builder); 123 reflectionTester.modifyRepeatedFieldsViaReflection(builder); 124 Message message = builder.build(); 125 reflectionTester.assertRepeatedFieldsModifiedViaReflection(message); 126 } 127 128 @Test testDynamicMessageRepeatedSettersRejectNull()129 public void testDynamicMessageRepeatedSettersRejectNull() throws Exception { 130 Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor()); 131 reflectionTester.assertReflectionRepeatedSettersRejectNull(builder); 132 } 133 134 @Test testDynamicMessageDefaults()135 public void testDynamicMessageDefaults() throws Exception { 136 reflectionTester.assertClearViaReflection( 137 DynamicMessage.getDefaultInstance(TestAllTypes.getDescriptor())); 138 reflectionTester.assertClearViaReflection( 139 DynamicMessage.newBuilder(TestAllTypes.getDescriptor()).build()); 140 } 141 142 @Test testDynamicMessageSerializedSize()143 public void testDynamicMessageSerializedSize() throws Exception { 144 TestAllTypes message = TestUtil.getAllSet(); 145 146 Message.Builder dynamicBuilder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor()); 147 reflectionTester.setAllFieldsViaReflection(dynamicBuilder); 148 Message dynamicMessage = dynamicBuilder.build(); 149 150 assertThat(message.getSerializedSize()).isEqualTo(dynamicMessage.getSerializedSize()); 151 } 152 153 @Test testDynamicMessageSerialization()154 public void testDynamicMessageSerialization() throws Exception { 155 Message.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor()); 156 reflectionTester.setAllFieldsViaReflection(builder); 157 Message message = builder.build(); 158 159 ByteString rawBytes = message.toByteString(); 160 TestAllTypes message2 = TestAllTypes.parseFrom(rawBytes); 161 162 TestUtil.assertAllFieldsSet(message2); 163 164 // In fact, the serialized forms should be exactly the same, byte-for-byte. 165 assertThat(rawBytes).isEqualTo(TestUtil.getAllSet().toByteString()); 166 } 167 168 @Test testDynamicMessageParsing()169 public void testDynamicMessageParsing() throws Exception { 170 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 171 TestUtil.setAllFields(builder); 172 TestAllTypes message = builder.build(); 173 174 ByteString rawBytes = message.toByteString(); 175 176 Message message2 = DynamicMessage.parseFrom(TestAllTypes.getDescriptor(), rawBytes); 177 reflectionTester.assertAllFieldsSetViaReflection(message2); 178 179 // Test Parser interface. 180 Message message3 = message2.getParserForType().parseFrom(rawBytes); 181 reflectionTester.assertAllFieldsSetViaReflection(message3); 182 } 183 184 @Test testDynamicMessageExtensionParsing()185 public void testDynamicMessageExtensionParsing() throws Exception { 186 ByteString rawBytes = TestUtil.getAllExtensionsSet().toByteString(); 187 Message message = 188 DynamicMessage.parseFrom( 189 TestAllExtensions.getDescriptor(), rawBytes, TestUtil.getFullExtensionRegistry()); 190 extensionsReflectionTester.assertAllFieldsSetViaReflection(message); 191 192 // Test Parser interface. 193 Message message2 = 194 message.getParserForType().parseFrom(rawBytes, TestUtil.getExtensionRegistry()); 195 extensionsReflectionTester.assertAllFieldsSetViaReflection(message2); 196 } 197 198 @Test testDynamicMessagePackedSerialization()199 public void testDynamicMessagePackedSerialization() throws Exception { 200 Message.Builder builder = DynamicMessage.newBuilder(TestPackedTypes.getDescriptor()); 201 packedReflectionTester.setPackedFieldsViaReflection(builder); 202 Message message = builder.build(); 203 204 ByteString rawBytes = message.toByteString(); 205 TestPackedTypes message2 = TestPackedTypes.parseFrom(rawBytes); 206 207 TestUtil.assertPackedFieldsSet(message2); 208 209 // In fact, the serialized forms should be exactly the same, byte-for-byte. 210 assertThat(rawBytes).isEqualTo(TestUtil.getPackedSet().toByteString()); 211 } 212 213 @Test testDynamicMessagePackedEmptySerialization()214 public void testDynamicMessagePackedEmptySerialization() throws Exception { 215 Message message = 216 DynamicMessage.newBuilder(TestPackedTypes.getDescriptor()) 217 .setField( 218 TestPackedTypes.getDescriptor() 219 .findFieldByNumber(TestPackedTypes.PACKED_INT64_FIELD_NUMBER), 220 new ArrayList<Long>()) 221 .build(); 222 223 assertThat(message.toByteString()).isEqualTo(ByteString.EMPTY); 224 } 225 226 @Test testDynamicMessagePackedParsing()227 public void testDynamicMessagePackedParsing() throws Exception { 228 TestPackedTypes.Builder builder = TestPackedTypes.newBuilder(); 229 TestUtil.setPackedFields(builder); 230 TestPackedTypes message = builder.build(); 231 232 ByteString rawBytes = message.toByteString(); 233 234 Message message2 = DynamicMessage.parseFrom(TestPackedTypes.getDescriptor(), rawBytes); 235 packedReflectionTester.assertPackedFieldsSetViaReflection(message2); 236 237 // Test Parser interface. 238 Message message3 = message2.getParserForType().parseFrom(rawBytes); 239 packedReflectionTester.assertPackedFieldsSetViaReflection(message3); 240 } 241 242 @Test testGetBuilderForExtensionField()243 public void testGetBuilderForExtensionField() { 244 DynamicMessage.Builder builder = DynamicMessage.newBuilder(TestAllExtensions.getDescriptor()); 245 Message.Builder fieldBuilder = 246 builder.newBuilderForField(UnittestProto.optionalNestedMessageExtension.getDescriptor()); 247 final int expected = 7432; 248 FieldDescriptor field = 249 NestedMessage.getDescriptor().findFieldByNumber(NestedMessage.BB_FIELD_NUMBER); 250 fieldBuilder.setField(field, expected); 251 assertThat(fieldBuilder.build().getField(field)).isEqualTo(expected); 252 } 253 254 @Test testDynamicMessageCopy()255 public void testDynamicMessageCopy() throws Exception { 256 TestAllTypes.Builder builder = TestAllTypes.newBuilder(); 257 TestUtil.setAllFields(builder); 258 TestAllTypes message = builder.build(); 259 260 DynamicMessage copy = DynamicMessage.newBuilder(message).build(); 261 reflectionTester.assertAllFieldsSetViaReflection(copy); 262 263 // Test oneof behavior 264 FieldDescriptor bytesField = TestAllTypes.getDescriptor().findFieldByName("oneof_bytes"); 265 FieldDescriptor uint32Field = TestAllTypes.getDescriptor().findFieldByName("oneof_uint32"); 266 assertThat(copy.hasField(bytesField)).isTrue(); 267 assertThat(copy.hasField(uint32Field)).isFalse(); 268 DynamicMessage copy2 = DynamicMessage.newBuilder(message).setField(uint32Field, 123).build(); 269 assertThat(copy2.hasField(bytesField)).isFalse(); 270 assertThat(copy2.hasField(uint32Field)).isTrue(); 271 assertThat(copy2.getField(uint32Field)).isEqualTo(123); 272 } 273 274 @Test testToBuilder()275 public void testToBuilder() throws Exception { 276 DynamicMessage.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor()); 277 reflectionTester.setAllFieldsViaReflection(builder); 278 int unknownFieldNum = 9; 279 long unknownFieldVal = 90; 280 builder.setUnknownFields( 281 UnknownFieldSet.newBuilder() 282 .addField( 283 unknownFieldNum, 284 UnknownFieldSet.Field.newBuilder().addVarint(unknownFieldVal).build()) 285 .build()); 286 DynamicMessage message = builder.build(); 287 288 DynamicMessage derived = message.toBuilder().build(); 289 reflectionTester.assertAllFieldsSetViaReflection(derived); 290 assertThat(derived.getUnknownFields().getField(unknownFieldNum).getVarintList()) 291 .containsExactly(unknownFieldVal); 292 } 293 294 @Test testDynamicOneofMessage()295 public void testDynamicOneofMessage() throws Exception { 296 DynamicMessage.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor()); 297 OneofDescriptor oneof = TestAllTypes.getDescriptor().getOneofs().get(0); 298 assertThat(builder.hasOneof(oneof)).isFalse(); 299 assertThat(builder.getOneofFieldDescriptor(oneof)).isNull(); 300 301 reflectionTester.setAllFieldsViaReflection(builder); 302 assertThat(builder.hasOneof(oneof)).isTrue(); 303 FieldDescriptor field = oneof.getField(3); 304 assertThat(builder.getOneofFieldDescriptor(oneof)).isSameInstanceAs(field); 305 306 DynamicMessage message = builder.buildPartial(); 307 assertThat(message.hasOneof(oneof)).isTrue(); 308 309 DynamicMessage.Builder mergedBuilder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor()); 310 FieldDescriptor mergedField = oneof.getField(0); 311 mergedBuilder.setField(mergedField, 123); 312 assertThat(mergedBuilder.hasField(mergedField)).isTrue(); 313 mergedBuilder.mergeFrom(message); 314 assertThat(mergedBuilder.hasField(field)).isTrue(); 315 assertThat(mergedBuilder.hasField(mergedField)).isFalse(); 316 317 builder.clearOneof(oneof); 318 assertThat(builder.getOneofFieldDescriptor(oneof)).isNull(); 319 message = builder.build(); 320 assertThat(message.getOneofFieldDescriptor(oneof)).isNull(); 321 } 322 323 // Regression test for a bug that makes setField() not work for repeated 324 // enum fields. 325 @Test testSettersForRepeatedEnumField()326 public void testSettersForRepeatedEnumField() throws Exception { 327 DynamicMessage.Builder builder = DynamicMessage.newBuilder(TestAllTypes.getDescriptor()); 328 FieldDescriptor repeatedEnumField = 329 TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum"); 330 EnumDescriptor enumDescriptor = TestAllTypes.NestedEnum.getDescriptor(); 331 builder.setField(repeatedEnumField, enumDescriptor.getValues()); 332 DynamicMessage message = builder.build(); 333 assertThat(message.getField(repeatedEnumField)).isEqualTo(enumDescriptor.getValues()); 334 } 335 336 @Test testBuilderGetFieldBuilder_mapField_throwsUnsupportedOperationException()337 public void testBuilderGetFieldBuilder_mapField_throwsUnsupportedOperationException() { 338 final DynamicMessage.Builder builder = 339 DynamicMessage.newBuilder(MessageWithMapFields.getDescriptor()); 340 final FieldDescriptor mapField = 341 MessageWithMapFields.getDescriptor().findFieldByName("string_message_map"); 342 343 Message.Builder entryBuilder = builder.newBuilderForField(mapField); 344 entryBuilder.setField(entryBuilder.getDescriptorForType().findFieldByNumber(1), "foo"); 345 entryBuilder.setField( 346 entryBuilder.getDescriptorForType().findFieldByNumber(2), 347 EmptyMessage.getDefaultInstance()); 348 builder.addRepeatedField(mapField, entryBuilder.build()); 349 350 assertThrows( 351 UnsupportedOperationException.class, 352 new ThrowingRunnable() { 353 @Override 354 public void run() throws Throwable { 355 builder.getFieldBuilder(mapField); 356 } 357 }); 358 } 359 360 @Test testBuilderGetRepeatedFieldBuilder_mapField_throwsUnsupportedOperationException()361 public void testBuilderGetRepeatedFieldBuilder_mapField_throwsUnsupportedOperationException() { 362 final DynamicMessage.Builder builder = 363 DynamicMessage.newBuilder(MessageWithMapFields.getDescriptor()); 364 final FieldDescriptor mapField = 365 MessageWithMapFields.getDescriptor().findFieldByName("string_message_map"); 366 367 Message.Builder entryBuilder = builder.newBuilderForField(mapField); 368 entryBuilder.setField(entryBuilder.getDescriptorForType().findFieldByNumber(1), "foo"); 369 entryBuilder.setField( 370 entryBuilder.getDescriptorForType().findFieldByNumber(2), 371 EmptyMessage.getDefaultInstance()); 372 builder.addRepeatedField(mapField, entryBuilder.build()); 373 374 assertThrows( 375 UnsupportedOperationException.class, 376 new ThrowingRunnable() { 377 @Override 378 public void run() throws Throwable { 379 builder.getFieldBuilder(mapField); 380 } 381 }); 382 } 383 384 @Test serialize_lazyFieldInMessageSet()385 public void serialize_lazyFieldInMessageSet() throws Exception { 386 ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance(); 387 extensionRegistry.add(TestMessageSetExtension2.messageSetExtension); 388 TestMessageSetExtension2 messageSetExtension = 389 TestMessageSetExtension2.newBuilder().setStr("foo").build(); 390 // This is a valid serialization of the above message. 391 ByteString suboptimallySerializedMessageSetExtension = 392 messageSetExtension.toByteString().concat(messageSetExtension.toByteString()); 393 DynamicMessage expectedMessage = 394 DynamicMessage.newBuilder(TestMessageSet.getDescriptor()) 395 .setField( 396 TestMessageSetExtension2.messageSetExtension.getDescriptor(), messageSetExtension) 397 .build(); 398 // Constructed with a LazyField, for whom roundtripping the serialized form will shorten the 399 // encoded form. 400 // In particular, this checks matching between lazy field encoding size. 401 DynamicMessage complicatedlyBuiltMessage = 402 DynamicMessage.newBuilder(TestMessageSet.getDescriptor()) 403 .setField( 404 TestMessageSetExtension2.messageSetExtension.getDescriptor(), 405 new LazyField( 406 DynamicMessage.getDefaultInstance(TestMessageSetExtension2.getDescriptor()), 407 extensionRegistry, 408 suboptimallySerializedMessageSetExtension)) 409 .build(); 410 411 DynamicMessage roundtrippedMessage = 412 DynamicMessage.newBuilder(TestMessageSet.getDescriptor()) 413 .mergeFrom(complicatedlyBuiltMessage.toByteString(), extensionRegistry) 414 .build(); 415 416 assertThat(complicatedlyBuiltMessage).isEqualTo(expectedMessage); 417 assertThat(roundtrippedMessage).isEqualTo(expectedMessage); 418 } 419 } 420