Home | History | Annotate | Download | only in protobuf
      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