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 com.google.protobuf.Descriptors.FieldDescriptor; 34 import protobuf_unittest.UnittestOptimizeFor.TestOptimizedForSize; 35 import protobuf_unittest.UnittestProto; 36 import protobuf_unittest.UnittestProto.ForeignMessage; 37 import protobuf_unittest.UnittestProto.TestAllExtensions; 38 import protobuf_unittest.UnittestProto.TestAllTypes; 39 import protobuf_unittest.UnittestProto.TestPackedTypes; 40 import protobuf_unittest.UnittestProto.TestRequired; 41 import protobuf_unittest.UnittestProto.TestRequiredForeign; 42 import protobuf_unittest.UnittestProto.TestUnpackedTypes; 43 44 import junit.framework.TestCase; 45 46 import java.util.Map; 47 48 /** 49 * Unit test for {@link AbstractMessage}. 50 * 51 * @author kenton@google.com Kenton Varda 52 */ 53 public class AbstractMessageTest extends TestCase { 54 /** 55 * Extends AbstractMessage and wraps some other message object. The methods 56 * of the Message interface which aren't explicitly implemented by 57 * AbstractMessage are forwarded to the wrapped object. This allows us to 58 * test that AbstractMessage's implementations work even if the wrapped 59 * object does not use them. 60 */ 61 private static class AbstractMessageWrapper extends AbstractMessage { 62 private final Message wrappedMessage; 63 AbstractMessageWrapper(Message wrappedMessage)64 public AbstractMessageWrapper(Message wrappedMessage) { 65 this.wrappedMessage = wrappedMessage; 66 } 67 getDescriptorForType()68 public Descriptors.Descriptor getDescriptorForType() { 69 return wrappedMessage.getDescriptorForType(); 70 } getDefaultInstanceForType()71 public AbstractMessageWrapper getDefaultInstanceForType() { 72 return new AbstractMessageWrapper( 73 wrappedMessage.getDefaultInstanceForType()); 74 } getAllFields()75 public Map<Descriptors.FieldDescriptor, Object> getAllFields() { 76 return wrappedMessage.getAllFields(); 77 } hasField(Descriptors.FieldDescriptor field)78 public boolean hasField(Descriptors.FieldDescriptor field) { 79 return wrappedMessage.hasField(field); 80 } getField(Descriptors.FieldDescriptor field)81 public Object getField(Descriptors.FieldDescriptor field) { 82 return wrappedMessage.getField(field); 83 } getRepeatedFieldCount(Descriptors.FieldDescriptor field)84 public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) { 85 return wrappedMessage.getRepeatedFieldCount(field); 86 } getRepeatedField( Descriptors.FieldDescriptor field, int index)87 public Object getRepeatedField( 88 Descriptors.FieldDescriptor field, int index) { 89 return wrappedMessage.getRepeatedField(field, index); 90 } getUnknownFields()91 public UnknownFieldSet getUnknownFields() { 92 return wrappedMessage.getUnknownFields(); 93 } newBuilderForType()94 public Builder newBuilderForType() { 95 return new Builder(wrappedMessage.newBuilderForType()); 96 } toBuilder()97 public Builder toBuilder() { 98 return new Builder(wrappedMessage.toBuilder()); 99 } 100 101 static class Builder extends AbstractMessage.Builder<Builder> { 102 private final Message.Builder wrappedBuilder; 103 Builder(Message.Builder wrappedBuilder)104 public Builder(Message.Builder wrappedBuilder) { 105 this.wrappedBuilder = wrappedBuilder; 106 } 107 build()108 public AbstractMessageWrapper build() { 109 return new AbstractMessageWrapper(wrappedBuilder.build()); 110 } buildPartial()111 public AbstractMessageWrapper buildPartial() { 112 return new AbstractMessageWrapper(wrappedBuilder.buildPartial()); 113 } clone()114 public Builder clone() { 115 return new Builder(wrappedBuilder.clone()); 116 } isInitialized()117 public boolean isInitialized() { 118 return clone().buildPartial().isInitialized(); 119 } getDescriptorForType()120 public Descriptors.Descriptor getDescriptorForType() { 121 return wrappedBuilder.getDescriptorForType(); 122 } getDefaultInstanceForType()123 public AbstractMessageWrapper getDefaultInstanceForType() { 124 return new AbstractMessageWrapper( 125 wrappedBuilder.getDefaultInstanceForType()); 126 } getAllFields()127 public Map<Descriptors.FieldDescriptor, Object> getAllFields() { 128 return wrappedBuilder.getAllFields(); 129 } newBuilderForField(Descriptors.FieldDescriptor field)130 public Builder newBuilderForField(Descriptors.FieldDescriptor field) { 131 return new Builder(wrappedBuilder.newBuilderForField(field)); 132 } hasField(Descriptors.FieldDescriptor field)133 public boolean hasField(Descriptors.FieldDescriptor field) { 134 return wrappedBuilder.hasField(field); 135 } getField(Descriptors.FieldDescriptor field)136 public Object getField(Descriptors.FieldDescriptor field) { 137 return wrappedBuilder.getField(field); 138 } setField(Descriptors.FieldDescriptor field, Object value)139 public Builder setField(Descriptors.FieldDescriptor field, Object value) { 140 wrappedBuilder.setField(field, value); 141 return this; 142 } clearField(Descriptors.FieldDescriptor field)143 public Builder clearField(Descriptors.FieldDescriptor field) { 144 wrappedBuilder.clearField(field); 145 return this; 146 } getRepeatedFieldCount(Descriptors.FieldDescriptor field)147 public int getRepeatedFieldCount(Descriptors.FieldDescriptor field) { 148 return wrappedBuilder.getRepeatedFieldCount(field); 149 } getRepeatedField( Descriptors.FieldDescriptor field, int index)150 public Object getRepeatedField( 151 Descriptors.FieldDescriptor field, int index) { 152 return wrappedBuilder.getRepeatedField(field, index); 153 } setRepeatedField(Descriptors.FieldDescriptor field, int index, Object value)154 public Builder setRepeatedField(Descriptors.FieldDescriptor field, 155 int index, Object value) { 156 wrappedBuilder.setRepeatedField(field, index, value); 157 return this; 158 } addRepeatedField( Descriptors.FieldDescriptor field, Object value)159 public Builder addRepeatedField( 160 Descriptors.FieldDescriptor field, Object value) { 161 wrappedBuilder.addRepeatedField(field, value); 162 return this; 163 } getUnknownFields()164 public UnknownFieldSet getUnknownFields() { 165 return wrappedBuilder.getUnknownFields(); 166 } setUnknownFields(UnknownFieldSet unknownFields)167 public Builder setUnknownFields(UnknownFieldSet unknownFields) { 168 wrappedBuilder.setUnknownFields(unknownFields); 169 return this; 170 } 171 @Override getFieldBuilder(FieldDescriptor field)172 public Message.Builder getFieldBuilder(FieldDescriptor field) { 173 return wrappedBuilder.getFieldBuilder(field); 174 } 175 } getParserForType()176 public Parser<? extends Message> getParserForType() { 177 return wrappedMessage.getParserForType(); 178 } 179 } 180 181 // ================================================================= 182 183 TestUtil.ReflectionTester reflectionTester = 184 new TestUtil.ReflectionTester(TestAllTypes.getDescriptor(), null); 185 186 TestUtil.ReflectionTester extensionsReflectionTester = 187 new TestUtil.ReflectionTester(TestAllExtensions.getDescriptor(), 188 TestUtil.getExtensionRegistry()); 189 testClear()190 public void testClear() throws Exception { 191 AbstractMessageWrapper message = 192 new AbstractMessageWrapper.Builder( 193 TestAllTypes.newBuilder(TestUtil.getAllSet())) 194 .clear().build(); 195 TestUtil.assertClear((TestAllTypes) message.wrappedMessage); 196 } 197 testCopy()198 public void testCopy() throws Exception { 199 AbstractMessageWrapper message = 200 new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder()) 201 .mergeFrom(TestUtil.getAllSet()).build(); 202 TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage); 203 } 204 testSerializedSize()205 public void testSerializedSize() throws Exception { 206 TestAllTypes message = TestUtil.getAllSet(); 207 Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet()); 208 209 assertEquals(message.getSerializedSize(), 210 abstractMessage.getSerializedSize()); 211 } 212 testSerialization()213 public void testSerialization() throws Exception { 214 Message abstractMessage = new AbstractMessageWrapper(TestUtil.getAllSet()); 215 216 TestUtil.assertAllFieldsSet( 217 TestAllTypes.parseFrom(abstractMessage.toByteString())); 218 219 assertEquals(TestUtil.getAllSet().toByteString(), 220 abstractMessage.toByteString()); 221 } 222 testParsing()223 public void testParsing() throws Exception { 224 AbstractMessageWrapper.Builder builder = 225 new AbstractMessageWrapper.Builder(TestAllTypes.newBuilder()); 226 AbstractMessageWrapper message = 227 builder.mergeFrom(TestUtil.getAllSet().toByteString()).build(); 228 TestUtil.assertAllFieldsSet((TestAllTypes) message.wrappedMessage); 229 } 230 testParsingUninitialized()231 public void testParsingUninitialized() throws Exception { 232 TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder(); 233 builder.getOptionalMessageBuilder().setDummy2(10); 234 ByteString bytes = builder.buildPartial().toByteString(); 235 Message.Builder abstractMessageBuilder = 236 new AbstractMessageWrapper.Builder(TestRequiredForeign.newBuilder()); 237 // mergeFrom() should not throw initialization error. 238 abstractMessageBuilder.mergeFrom(bytes).buildPartial(); 239 try { 240 abstractMessageBuilder.mergeFrom(bytes).build(); 241 fail(); 242 } catch (UninitializedMessageException ex) { 243 // pass 244 } 245 246 // test DynamicMessage directly. 247 Message.Builder dynamicMessageBuilder = DynamicMessage.newBuilder( 248 TestRequiredForeign.getDescriptor()); 249 // mergeFrom() should not throw initialization error. 250 dynamicMessageBuilder.mergeFrom(bytes).buildPartial(); 251 try { 252 dynamicMessageBuilder.mergeFrom(bytes).build(); 253 fail(); 254 } catch (UninitializedMessageException ex) { 255 // pass 256 } 257 } 258 testPackedSerialization()259 public void testPackedSerialization() throws Exception { 260 Message abstractMessage = 261 new AbstractMessageWrapper(TestUtil.getPackedSet()); 262 263 TestUtil.assertPackedFieldsSet( 264 TestPackedTypes.parseFrom(abstractMessage.toByteString())); 265 266 assertEquals(TestUtil.getPackedSet().toByteString(), 267 abstractMessage.toByteString()); 268 } 269 testPackedParsing()270 public void testPackedParsing() throws Exception { 271 AbstractMessageWrapper.Builder builder = 272 new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder()); 273 AbstractMessageWrapper message = 274 builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build(); 275 TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage); 276 } 277 testUnpackedSerialization()278 public void testUnpackedSerialization() throws Exception { 279 Message abstractMessage = 280 new AbstractMessageWrapper(TestUtil.getUnpackedSet()); 281 282 TestUtil.assertUnpackedFieldsSet( 283 TestUnpackedTypes.parseFrom(abstractMessage.toByteString())); 284 285 assertEquals(TestUtil.getUnpackedSet().toByteString(), 286 abstractMessage.toByteString()); 287 } 288 testParsePackedToUnpacked()289 public void testParsePackedToUnpacked() throws Exception { 290 AbstractMessageWrapper.Builder builder = 291 new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder()); 292 AbstractMessageWrapper message = 293 builder.mergeFrom(TestUtil.getPackedSet().toByteString()).build(); 294 TestUtil.assertUnpackedFieldsSet( 295 (TestUnpackedTypes) message.wrappedMessage); 296 } 297 testParseUnpackedToPacked()298 public void testParseUnpackedToPacked() throws Exception { 299 AbstractMessageWrapper.Builder builder = 300 new AbstractMessageWrapper.Builder(TestPackedTypes.newBuilder()); 301 AbstractMessageWrapper message = 302 builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build(); 303 TestUtil.assertPackedFieldsSet((TestPackedTypes) message.wrappedMessage); 304 } 305 testUnpackedParsing()306 public void testUnpackedParsing() throws Exception { 307 AbstractMessageWrapper.Builder builder = 308 new AbstractMessageWrapper.Builder(TestUnpackedTypes.newBuilder()); 309 AbstractMessageWrapper message = 310 builder.mergeFrom(TestUtil.getUnpackedSet().toByteString()).build(); 311 TestUtil.assertUnpackedFieldsSet( 312 (TestUnpackedTypes) message.wrappedMessage); 313 } 314 testOptimizedForSize()315 public void testOptimizedForSize() throws Exception { 316 // We're mostly only checking that this class was compiled successfully. 317 TestOptimizedForSize message = 318 TestOptimizedForSize.newBuilder().setI(1).build(); 319 message = TestOptimizedForSize.parseFrom(message.toByteString()); 320 assertEquals(2, message.getSerializedSize()); 321 } 322 323 // ----------------------------------------------------------------- 324 // Tests for isInitialized(). 325 326 private static final TestRequired TEST_REQUIRED_UNINITIALIZED = 327 TestRequired.getDefaultInstance(); 328 private static final TestRequired TEST_REQUIRED_INITIALIZED = 329 TestRequired.newBuilder().setA(1).setB(2).setC(3).build(); 330 testIsInitialized()331 public void testIsInitialized() throws Exception { 332 TestRequired.Builder builder = TestRequired.newBuilder(); 333 AbstractMessageWrapper.Builder abstractBuilder = 334 new AbstractMessageWrapper.Builder(builder); 335 336 assertFalse(abstractBuilder.isInitialized()); 337 assertEquals("a, b, c", abstractBuilder.getInitializationErrorString()); 338 builder.setA(1); 339 assertFalse(abstractBuilder.isInitialized()); 340 assertEquals("b, c", abstractBuilder.getInitializationErrorString()); 341 builder.setB(1); 342 assertFalse(abstractBuilder.isInitialized()); 343 assertEquals("c", abstractBuilder.getInitializationErrorString()); 344 builder.setC(1); 345 assertTrue(abstractBuilder.isInitialized()); 346 assertEquals("", abstractBuilder.getInitializationErrorString()); 347 } 348 testForeignIsInitialized()349 public void testForeignIsInitialized() throws Exception { 350 TestRequiredForeign.Builder builder = TestRequiredForeign.newBuilder(); 351 AbstractMessageWrapper.Builder abstractBuilder = 352 new AbstractMessageWrapper.Builder(builder); 353 354 assertTrue(abstractBuilder.isInitialized()); 355 assertEquals("", abstractBuilder.getInitializationErrorString()); 356 357 builder.setOptionalMessage(TEST_REQUIRED_UNINITIALIZED); 358 assertFalse(abstractBuilder.isInitialized()); 359 assertEquals( 360 "optional_message.a, optional_message.b, optional_message.c", 361 abstractBuilder.getInitializationErrorString()); 362 363 builder.setOptionalMessage(TEST_REQUIRED_INITIALIZED); 364 assertTrue(abstractBuilder.isInitialized()); 365 assertEquals("", abstractBuilder.getInitializationErrorString()); 366 367 builder.addRepeatedMessage(TEST_REQUIRED_UNINITIALIZED); 368 assertFalse(abstractBuilder.isInitialized()); 369 assertEquals( 370 "repeated_message[0].a, repeated_message[0].b, repeated_message[0].c", 371 abstractBuilder.getInitializationErrorString()); 372 373 builder.setRepeatedMessage(0, TEST_REQUIRED_INITIALIZED); 374 assertTrue(abstractBuilder.isInitialized()); 375 assertEquals("", abstractBuilder.getInitializationErrorString()); 376 } 377 378 // ----------------------------------------------------------------- 379 // Tests for mergeFrom 380 381 static final TestAllTypes MERGE_SOURCE = 382 TestAllTypes.newBuilder() 383 .setOptionalInt32(1) 384 .setOptionalString("foo") 385 .setOptionalForeignMessage(ForeignMessage.getDefaultInstance()) 386 .addRepeatedString("bar") 387 .build(); 388 389 static final TestAllTypes MERGE_DEST = 390 TestAllTypes.newBuilder() 391 .setOptionalInt64(2) 392 .setOptionalString("baz") 393 .setOptionalForeignMessage(ForeignMessage.newBuilder().setC(3).build()) 394 .addRepeatedString("qux") 395 .build(); 396 397 static final String MERGE_RESULT_TEXT = 398 "optional_int32: 1\n" + 399 "optional_int64: 2\n" + 400 "optional_string: \"foo\"\n" + 401 "optional_foreign_message {\n" + 402 " c: 3\n" + 403 "}\n" + 404 "repeated_string: \"qux\"\n" + 405 "repeated_string: \"bar\"\n"; 406 testMergeFrom()407 public void testMergeFrom() throws Exception { 408 AbstractMessageWrapper result = 409 new AbstractMessageWrapper.Builder( 410 TestAllTypes.newBuilder(MERGE_DEST)) 411 .mergeFrom(MERGE_SOURCE).build(); 412 413 assertEquals(MERGE_RESULT_TEXT, result.toString()); 414 } 415 416 // ----------------------------------------------------------------- 417 // Tests for equals and hashCode 418 testEqualsAndHashCode()419 public void testEqualsAndHashCode() throws Exception { 420 TestAllTypes a = TestUtil.getAllSet(); 421 TestAllTypes b = TestAllTypes.newBuilder().build(); 422 TestAllTypes c = TestAllTypes.newBuilder(b).addRepeatedString("x").build(); 423 TestAllTypes d = TestAllTypes.newBuilder(c).addRepeatedString("y").build(); 424 TestAllExtensions e = TestUtil.getAllExtensionsSet(); 425 TestAllExtensions f = TestAllExtensions.newBuilder(e) 426 .addExtension(UnittestProto.repeatedInt32Extension, 999).build(); 427 428 checkEqualsIsConsistent(a); 429 checkEqualsIsConsistent(b); 430 checkEqualsIsConsistent(c); 431 checkEqualsIsConsistent(d); 432 checkEqualsIsConsistent(e); 433 checkEqualsIsConsistent(f); 434 435 checkNotEqual(a, b); 436 checkNotEqual(a, c); 437 checkNotEqual(a, d); 438 checkNotEqual(a, e); 439 checkNotEqual(a, f); 440 441 checkNotEqual(b, c); 442 checkNotEqual(b, d); 443 checkNotEqual(b, e); 444 checkNotEqual(b, f); 445 446 checkNotEqual(c, d); 447 checkNotEqual(c, e); 448 checkNotEqual(c, f); 449 450 checkNotEqual(d, e); 451 checkNotEqual(d, f); 452 453 checkNotEqual(e, f); 454 455 // Deserializing into the TestEmptyMessage such that every field 456 // is an {@link UnknownFieldSet.Field}. 457 UnittestProto.TestEmptyMessage eUnknownFields = 458 UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray()); 459 UnittestProto.TestEmptyMessage fUnknownFields = 460 UnittestProto.TestEmptyMessage.parseFrom(f.toByteArray()); 461 checkNotEqual(eUnknownFields, fUnknownFields); 462 checkEqualsIsConsistent(eUnknownFields); 463 checkEqualsIsConsistent(fUnknownFields); 464 465 // Subsequent reconstitutions should be identical 466 UnittestProto.TestEmptyMessage eUnknownFields2 = 467 UnittestProto.TestEmptyMessage.parseFrom(e.toByteArray()); 468 checkEqualsIsConsistent(eUnknownFields, eUnknownFields2); 469 } 470 471 472 /** 473 * Asserts that the given proto has symmetric equals and hashCode methods. 474 */ checkEqualsIsConsistent(Message message)475 private void checkEqualsIsConsistent(Message message) { 476 // Object should be equal to itself. 477 assertEquals(message, message); 478 479 // Object should be equal to a dynamic copy of itself. 480 DynamicMessage dynamic = DynamicMessage.newBuilder(message).build(); 481 checkEqualsIsConsistent(message, dynamic); 482 } 483 484 /** 485 * Asserts that the given protos are equal and have the same hash code. 486 */ checkEqualsIsConsistent(Message message1, Message message2)487 private void checkEqualsIsConsistent(Message message1, Message message2) { 488 assertEquals(message1, message2); 489 assertEquals(message2, message1); 490 assertEquals(message2.hashCode(), message1.hashCode()); 491 } 492 493 /** 494 * Asserts that the given protos are not equal and have different hash codes. 495 * 496 * @warning It's valid for non-equal objects to have the same hash code, so 497 * this test is stricter than it needs to be. However, this should happen 498 * relatively rarely. 499 */ checkNotEqual(Message m1, Message m2)500 private void checkNotEqual(Message m1, Message m2) { 501 String equalsError = String.format("%s should not be equal to %s", m1, m2); 502 assertFalse(equalsError, m1.equals(m2)); 503 assertFalse(equalsError, m2.equals(m1)); 504 505 assertFalse( 506 String.format("%s should have a different hash code from %s", m1, m2), 507 m1.hashCode() == m2.hashCode()); 508 } 509 testCheckByteStringIsUtf8OnUtf8()510 public void testCheckByteStringIsUtf8OnUtf8() { 511 ByteString byteString = ByteString.copyFromUtf8("some text"); 512 AbstractMessageLite.checkByteStringIsUtf8(byteString); 513 // No exception thrown. 514 } 515 testCheckByteStringIsUtf8OnNonUtf8()516 public void testCheckByteStringIsUtf8OnNonUtf8() { 517 ByteString byteString = 518 ByteString.copyFrom(new byte[]{(byte) 0x80}); // A lone continuation byte. 519 try { 520 AbstractMessageLite.checkByteStringIsUtf8(byteString); 521 fail("Expected AbstractMessageLite.checkByteStringIsUtf8 to throw IllegalArgumentException"); 522 } catch (IllegalArgumentException exception) { 523 assertEquals("Byte string is not UTF-8.", exception.getMessage()); 524 } 525 } 526 527 } 528