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 com.google.common.truth.Truth.assertWithMessage; 12 13 import protobuf_unittest.UnittestProto.ForeignMessage; 14 import protobuf_unittest.UnittestProto.TestAllExtensions; 15 import protobuf_unittest.UnittestProto.TestAllTypes; 16 import protobuf_unittest.UnittestProto.TestRequired; 17 import protobuf_unittest.UnittestProto.TestRequiredForeign; 18 import java.util.List; 19 import org.junit.Test; 20 import org.junit.runner.RunWith; 21 import org.junit.runners.JUnit4; 22 23 /** Misc. unit tests for message operations that apply to both generated and dynamic messages. */ 24 @RunWith(JUnit4.class) 25 public class MessageTest { 26 // ================================================================= 27 // Message-merging tests. 28 29 static final TestAllTypes MERGE_SOURCE = 30 TestAllTypes.newBuilder() 31 .setOptionalInt32(1) 32 .setOptionalString("foo") 33 .setOptionalForeignMessage(ForeignMessage.getDefaultInstance()) 34 .addRepeatedString("bar") 35 .build(); 36 37 static final TestAllTypes MERGE_DEST = 38 TestAllTypes.newBuilder() 39 .setOptionalInt64(2) 40 .setOptionalString("baz") 41 .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(3).build()) 42 .addRepeatedString("qux") 43 .build(); 44 45 static final String MERGE_RESULT_TEXT = 46 "" 47 + "optional_int32: 1\n" 48 + "optional_int64: 2\n" 49 + "optional_string: \"foo\"\n" 50 + "optional_foreign_message {\n" 51 + " c: 3\n" 52 + "}\n" 53 + "repeated_string: \"qux\"\n" 54 + "repeated_string: \"bar\"\n"; 55 56 @Test testParsingWithNullExtensionRegistry()57 public void testParsingWithNullExtensionRegistry() throws Exception { 58 try { 59 TestAllTypes.parseFrom(new byte[] {}, null); 60 assertWithMessage("Expected exception").fail(); 61 } catch (NullPointerException expected) { 62 } 63 } 64 65 @Test testMergeFrom()66 public void testMergeFrom() throws Exception { 67 TestAllTypes result = TestAllTypes.newBuilder(MERGE_DEST).mergeFrom(MERGE_SOURCE).build(); 68 69 assertThat(result.toString()).isEqualTo(MERGE_RESULT_TEXT); 70 } 71 72 /** 73 * Test merging a DynamicMessage into a GeneratedMessage. As long as they have the same 74 * descriptor, this should work, but it is an entirely different code path. 75 */ 76 @Test testMergeFromDynamic()77 public void testMergeFromDynamic() throws Exception { 78 TestAllTypes result = 79 TestAllTypes.newBuilder(MERGE_DEST) 80 .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build()) 81 .build(); 82 83 assertThat(result.toString()).isEqualTo(MERGE_RESULT_TEXT); 84 } 85 86 /** Test merging two DynamicMessages. */ 87 @Test testDynamicMergeFrom()88 public void testDynamicMergeFrom() throws Exception { 89 DynamicMessage result = 90 DynamicMessage.newBuilder(MERGE_DEST) 91 .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build()) 92 .build(); 93 94 assertThat(result.toString()).isEqualTo(MERGE_RESULT_TEXT); 95 } 96 97 // ================================================================= 98 // Required-field-related tests. 99 100 private static final TestRequired TEST_REQUIRED_UNINITIALIZED = TestRequired.getDefaultInstance(); 101 private static final TestRequired TEST_REQUIRED_INITIALIZED = 102 TestRequired.newBuilder().setA(1).setB(2).setC(3).build(); 103 104 @Test testRequired()105 public void testRequired() throws Exception { 106 TestRequired.Builder builder = TestRequired.newBuilder(); 107 108 assertThat(builder.isInitialized()).isFalse(); 109 builder.setA(1); 110 assertThat(builder.isInitialized()).isFalse(); 111 builder.setB(1); 112 assertThat(builder.isInitialized()).isFalse(); 113 builder.setC(1); 114 assertThat(builder.isInitialized()).isTrue(); 115 } 116 117 @Test testRequiredForeign()118 public void testRequiredForeign() throws Exception { 119 TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder(); 120 121 assertThat(builder.isInitialized()).isTrue(); 122 123 builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED); 124 assertThat(builder.isInitialized()).isFalse(); 125 126 builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED); 127 assertThat(builder.isInitialized()).isTrue(); 128 129 builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED); 130 assertThat(builder.isInitialized()).isFalse(); 131 132 builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED); 133 assertThat(builder.isInitialized()).isTrue(); 134 } 135 136 @Test testRequiredExtension()137 public void testRequiredExtension() throws Exception { 138 TestAllExtensions.Builder builder = TestAllExtensions.newBuilder(); 139 140 assertThat(builder.isInitialized()).isTrue(); 141 142 builder.setExtension(TestRequired.single, TEST_REQUIRED_UNINITIALIZED); 143 assertThat(builder.isInitialized()).isFalse(); 144 145 builder.setExtension(TestRequired.single, TEST_REQUIRED_INITIALIZED); 146 assertThat(builder.isInitialized()).isTrue(); 147 148 builder.addExtension(TestRequired.multi, TEST_REQUIRED_UNINITIALIZED); 149 assertThat(builder.isInitialized()).isFalse(); 150 151 builder.setExtension(TestRequired.multi, 0, TEST_REQUIRED_INITIALIZED); 152 assertThat(builder.isInitialized()).isTrue(); 153 } 154 155 @Test testRequiredDynamic()156 public void testRequiredDynamic() throws Exception { 157 Descriptors.Descriptor descriptor = TestRequired.getDescriptor(); 158 DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor); 159 160 assertThat(builder.isInitialized()).isFalse(); 161 builder.setField(descriptor.findFieldByName("a"), 1); 162 assertThat(builder.isInitialized()).isFalse(); 163 builder.setField(descriptor.findFieldByName("b"), 1); 164 assertThat(builder.isInitialized()).isFalse(); 165 builder.setField(descriptor.findFieldByName("c"), 1); 166 assertThat(builder.isInitialized()).isTrue(); 167 } 168 169 @Test testRequiredDynamicForeign()170 public void testRequiredDynamicForeign() throws Exception { 171 Descriptors.Descriptor descriptor = TestRequiredForeign.getDescriptor(); 172 DynamicMessage.Builder builder = DynamicMessage.newBuilder(descriptor); 173 174 assertThat(builder.isInitialized()).isTrue(); 175 176 builder.setField(descriptor.findFieldByName("optional_message"), TEST_REQUIRED_UNINITIALIZED); 177 assertThat(builder.isInitialized()).isFalse(); 178 179 builder.setField(descriptor.findFieldByName("optional_message"), TEST_REQUIRED_INITIALIZED); 180 assertThat(builder.isInitialized()).isTrue(); 181 182 builder.addRepeatedField( 183 descriptor.findFieldByName("repeated_message"), TEST_REQUIRED_UNINITIALIZED); 184 assertThat(builder.isInitialized()).isFalse(); 185 186 builder.setRepeatedField( 187 descriptor.findFieldByName("repeated_message"), 0, TEST_REQUIRED_INITIALIZED); 188 assertThat(builder.isInitialized()).isTrue(); 189 } 190 191 @Test testUninitializedException()192 public void testUninitializedException() throws Exception { 193 try { 194 TestRequired.newBuilder().build(); 195 assertWithMessage("Should have thrown an exception.").fail(); 196 } catch (UninitializedMessageException e) { 197 assertThat(e).hasMessageThat().isEqualTo("Message missing required fields: a, b, c"); 198 } 199 } 200 201 @Test testBuildPartial()202 public void testBuildPartial() throws Exception { 203 // We're mostly testing that no exception is thrown. 204 TestRequired message = TestRequired.newBuilder().buildPartial(); 205 assertThat(message.isInitialized()).isFalse(); 206 } 207 208 @Test testNestedUninitializedException()209 public void testNestedUninitializedException() throws Exception { 210 try { 211 TestRequiredForeign.newBuilder() 212 .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED) 213 .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED) 214 .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED) 215 .build(); 216 assertWithMessage("Should have thrown an exception.").fail(); 217 } catch (UninitializedMessageException e) { 218 assertThat(e) 219 .hasMessageThat() 220 .isEqualTo( 221 "Message missing required fields: " 222 + "optional_message.a, " 223 + "optional_message.b, " 224 + "optional_message.c, " 225 + "repeated_message[0].a, " 226 + "repeated_message[0].b, " 227 + "repeated_message[0].c, " 228 + "repeated_message[1].a, " 229 + "repeated_message[1].b, " 230 + "repeated_message[1].c"); 231 } 232 } 233 234 @Test testBuildNestedPartial()235 public void testBuildNestedPartial() throws Exception { 236 // We're mostly testing that no exception is thrown. 237 TestRequiredForeign message = 238 TestRequiredForeign.newBuilder() 239 .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED) 240 .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED) 241 .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED) 242 .buildPartial(); 243 assertThat(message.isInitialized()).isFalse(); 244 } 245 246 @Test testParseUninitialized()247 public void testParseUninitialized() throws Exception { 248 try { 249 TestRequired.parseFrom(ByteString.EMPTY); 250 assertWithMessage("Should have thrown an exception.").fail(); 251 } catch (InvalidProtocolBufferException e) { 252 assertThat(e).hasMessageThat().isEqualTo("Message missing required fields: a, b, c"); 253 } 254 } 255 256 @Test testParseNestedUninitialized()257 public void testParseNestedUninitialized() throws Exception { 258 ByteString data = 259 TestRequiredForeign.newBuilder() 260 .setOptionalMessage(TEST_REQUIRED_UNINITIALIZED) 261 .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED) 262 .addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED) 263 .buildPartial() 264 .toByteString(); 265 266 try { 267 TestRequiredForeign.parseFrom(data); 268 assertWithMessage("Should have thrown an exception.").fail(); 269 } catch (InvalidProtocolBufferException e) { 270 assertThat(e) 271 .hasMessageThat() 272 .isEqualTo( 273 "Message missing required fields: " 274 + "optional_message.a, " 275 + "optional_message.b, " 276 + "optional_message.c, " 277 + "repeated_message[0].a, " 278 + "repeated_message[0].b, " 279 + "repeated_message[0].c, " 280 + "repeated_message[1].a, " 281 + "repeated_message[1].b, " 282 + "repeated_message[1].c"); 283 } 284 } 285 286 @Test testDynamicUninitializedException()287 public void testDynamicUninitializedException() throws Exception { 288 try { 289 DynamicMessage.newBuilder(TestRequired.getDescriptor()).build(); 290 assertWithMessage("Should have thrown an exception.").fail(); 291 } catch (UninitializedMessageException e) { 292 assertThat(e).hasMessageThat().isEqualTo("Message missing required fields: a, b, c"); 293 } 294 } 295 296 @Test testDynamicBuildPartial()297 public void testDynamicBuildPartial() throws Exception { 298 // We're mostly testing that no exception is thrown. 299 DynamicMessage message = DynamicMessage.newBuilder(TestRequired.getDescriptor()).buildPartial(); 300 assertThat(message.isInitialized()).isFalse(); 301 } 302 303 @Test testDynamicParseUninitialized()304 public void testDynamicParseUninitialized() throws Exception { 305 try { 306 Descriptors.Descriptor descriptor = TestRequired.getDescriptor(); 307 DynamicMessage.parseFrom(descriptor, ByteString.EMPTY); 308 assertWithMessage("Should have thrown an exception.").fail(); 309 } catch (InvalidProtocolBufferException e) { 310 assertThat(e).hasMessageThat().isEqualTo("Message missing required fields: a, b, c"); 311 } 312 } 313 314 /** Test reading unset repeated message from DynamicMessage. */ 315 @Test testDynamicRepeatedMessageNull()316 public void testDynamicRepeatedMessageNull() throws Exception { 317 Descriptors.Descriptor unused = TestRequired.getDescriptor(); 318 DynamicMessage result = 319 DynamicMessage.newBuilder(TestAllTypes.getDescriptor()) 320 .mergeFrom(DynamicMessage.newBuilder(MERGE_SOURCE).build()) 321 .build(); 322 323 assertThat( 324 result.getField( 325 result.getDescriptorForType().findFieldByName("repeated_foreign_message"))) 326 .isInstanceOf(List.class); 327 assertThat( 328 result.getRepeatedFieldCount( 329 result.getDescriptorForType().findFieldByName("repeated_foreign_message"))) 330 .isEqualTo(0); 331 } 332 333 /** Test reading repeated message from DynamicMessage. */ 334 @Test testDynamicRepeatedMessageNotNull()335 public void testDynamicRepeatedMessageNotNull() throws Exception { 336 TestAllTypes repeatedNested = 337 TestAllTypes.newBuilder() 338 .setOptionalInt32(1) 339 .setOptionalString("foo") 340 .setOptionalForeignMessage(ForeignMessage.getDefaultInstance()) 341 .addRepeatedString("bar") 342 .addRepeatedForeignMessage(ForeignMessage.getDefaultInstance()) 343 .addRepeatedForeignMessage(ForeignMessage.getDefaultInstance()) 344 .build(); 345 Descriptors.Descriptor unused = TestRequired.getDescriptor(); 346 DynamicMessage result = 347 DynamicMessage.newBuilder(TestAllTypes.getDescriptor()) 348 .mergeFrom(DynamicMessage.newBuilder(repeatedNested).build()) 349 .build(); 350 351 assertThat( 352 result.getField( 353 result.getDescriptorForType().findFieldByName("repeated_foreign_message"))) 354 .isInstanceOf(List.class); 355 assertThat( 356 result.getRepeatedFieldCount( 357 result.getDescriptorForType().findFieldByName("repeated_foreign_message"))) 358 .isEqualTo(2); 359 } 360 361 @Test testPreservesFloatingPointNegative0()362 public void testPreservesFloatingPointNegative0() throws Exception { 363 proto3_unittest.UnittestProto3.TestAllTypes message = 364 proto3_unittest.UnittestProto3.TestAllTypes.newBuilder() 365 .setOptionalFloat(-0.0f) 366 .setOptionalDouble(-0.0) 367 .build(); 368 assertThat( 369 proto3_unittest.UnittestProto3.TestAllTypes.parseFrom( 370 message.toByteString(), ExtensionRegistry.getEmptyRegistry())) 371 .isEqualTo(message); 372 } 373 374 @Test testNegative0FloatingPointEquality()375 public void testNegative0FloatingPointEquality() throws Exception { 376 // Like Double#equals and Float#equals, we treat -0.0 as not being equal to +0.0 even though 377 // IEEE 754 mandates that they are equivalent. This test asserts that behavior. 378 proto3_unittest.UnittestProto3.TestAllTypes message1 = 379 proto3_unittest.UnittestProto3.TestAllTypes.newBuilder() 380 .setOptionalFloat(-0.0f) 381 .setOptionalDouble(-0.0) 382 .build(); 383 proto3_unittest.UnittestProto3.TestAllTypes message2 = 384 proto3_unittest.UnittestProto3.TestAllTypes.newBuilder() 385 .setOptionalFloat(0.0f) 386 .setOptionalDouble(0.0) 387 .build(); 388 assertThat(message1).isNotEqualTo(message2); 389 } 390 } 391