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