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.UnittestProto;
     34 import protobuf_unittest.UnittestProto.TestAllExtensions;
     35 import protobuf_unittest.UnittestProto.TestAllTypes;
     36 import protobuf_unittest.UnittestProto.TestEmptyMessage;
     37 import protobuf_unittest.UnittestProto.TestEmptyMessageWithExtensions;
     38 
     39 import junit.framework.TestCase;
     40 
     41 import java.util.Arrays;
     42 import java.util.Map;
     43 
     44 /**
     45  * Tests related to unknown field handling.
     46  *
     47  * @author kenton (at) google.com (Kenton Varda)
     48  */
     49 public class UnknownFieldSetTest extends TestCase {
     50   public void setUp() throws Exception {
     51     descriptor = TestAllTypes.getDescriptor();
     52     allFields = TestUtil.getAllSet();
     53     allFieldsData = allFields.toByteString();
     54     emptyMessage = TestEmptyMessage.parseFrom(allFieldsData);
     55     unknownFields = emptyMessage.getUnknownFields();
     56   }
     57 
     58   UnknownFieldSet.Field getField(String name) {
     59     Descriptors.FieldDescriptor field = descriptor.findFieldByName(name);
     60     assertNotNull(field);
     61     return unknownFields.getField(field.getNumber());
     62   }
     63 
     64   // Constructs a protocol buffer which contains fields with all the same
     65   // numbers as allFieldsData except that each field is some other wire
     66   // type.
     67   ByteString getBizarroData() throws Exception {
     68     UnknownFieldSet.Builder bizarroFields = UnknownFieldSet.newBuilder();
     69 
     70     UnknownFieldSet.Field varintField =
     71       UnknownFieldSet.Field.newBuilder().addVarint(1).build();
     72     UnknownFieldSet.Field fixed32Field =
     73       UnknownFieldSet.Field.newBuilder().addFixed32(1).build();
     74 
     75     for (Map.Entry<Integer, UnknownFieldSet.Field> entry :
     76          unknownFields.asMap().entrySet()) {
     77       if (entry.getValue().getVarintList().isEmpty()) {
     78         // Original field is not a varint, so use a varint.
     79         bizarroFields.addField(entry.getKey(), varintField);
     80       } else {
     81         // Original field *is* a varint, so use something else.
     82         bizarroFields.addField(entry.getKey(), fixed32Field);
     83       }
     84     }
     85 
     86     return bizarroFields.build().toByteString();
     87   }
     88 
     89   Descriptors.Descriptor descriptor;
     90   TestAllTypes allFields;
     91   ByteString allFieldsData;
     92 
     93   // An empty message that has been parsed from allFieldsData.  So, it has
     94   // unknown fields of every type.
     95   TestEmptyMessage emptyMessage;
     96   UnknownFieldSet unknownFields;
     97 
     98   // =================================================================
     99 
    100   public void testVarint() throws Exception {
    101     UnknownFieldSet.Field field = getField("optional_int32");
    102     assertEquals(1, field.getVarintList().size());
    103     assertEquals(allFields.getOptionalInt32(),
    104                  (long) field.getVarintList().get(0));
    105   }
    106 
    107   public void testFixed32() throws Exception {
    108     UnknownFieldSet.Field field = getField("optional_fixed32");
    109     assertEquals(1, field.getFixed32List().size());
    110     assertEquals(allFields.getOptionalFixed32(),
    111                  (int) field.getFixed32List().get(0));
    112   }
    113 
    114   public void testFixed64() throws Exception {
    115     UnknownFieldSet.Field field = getField("optional_fixed64");
    116     assertEquals(1, field.getFixed64List().size());
    117     assertEquals(allFields.getOptionalFixed64(),
    118                  (long) field.getFixed64List().get(0));
    119   }
    120 
    121   public void testLengthDelimited() throws Exception {
    122     UnknownFieldSet.Field field = getField("optional_bytes");
    123     assertEquals(1, field.getLengthDelimitedList().size());
    124     assertEquals(allFields.getOptionalBytes(),
    125                  field.getLengthDelimitedList().get(0));
    126   }
    127 
    128   public void testGroup() throws Exception {
    129     Descriptors.FieldDescriptor nestedFieldDescriptor =
    130       TestAllTypes.OptionalGroup.getDescriptor().findFieldByName("a");
    131     assertNotNull(nestedFieldDescriptor);
    132 
    133     UnknownFieldSet.Field field = getField("optionalgroup");
    134     assertEquals(1, field.getGroupList().size());
    135 
    136     UnknownFieldSet group = field.getGroupList().get(0);
    137     assertEquals(1, group.asMap().size());
    138     assertTrue(group.hasField(nestedFieldDescriptor.getNumber()));
    139 
    140     UnknownFieldSet.Field nestedField =
    141       group.getField(nestedFieldDescriptor.getNumber());
    142     assertEquals(1, nestedField.getVarintList().size());
    143     assertEquals(allFields.getOptionalGroup().getA(),
    144                  (long) nestedField.getVarintList().get(0));
    145   }
    146 
    147   public void testSerialize() throws Exception {
    148     // Check that serializing the UnknownFieldSet produces the original data
    149     // again.
    150     ByteString data = emptyMessage.toByteString();
    151     assertEquals(allFieldsData, data);
    152   }
    153 
    154   public void testCopyFrom() throws Exception {
    155     TestEmptyMessage message =
    156       TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).build();
    157 
    158     assertEquals(emptyMessage.toString(), message.toString());
    159   }
    160 
    161   public void testMergeFrom() throws Exception {
    162     TestEmptyMessage source =
    163       TestEmptyMessage.newBuilder()
    164         .setUnknownFields(
    165           UnknownFieldSet.newBuilder()
    166             .addField(2,
    167               UnknownFieldSet.Field.newBuilder()
    168                 .addVarint(2).build())
    169             .addField(3,
    170               UnknownFieldSet.Field.newBuilder()
    171                 .addVarint(4).build())
    172             .build())
    173         .build();
    174     TestEmptyMessage destination =
    175       TestEmptyMessage.newBuilder()
    176         .setUnknownFields(
    177           UnknownFieldSet.newBuilder()
    178             .addField(1,
    179               UnknownFieldSet.Field.newBuilder()
    180                 .addVarint(1).build())
    181             .addField(3,
    182               UnknownFieldSet.Field.newBuilder()
    183                 .addVarint(3).build())
    184             .build())
    185         .mergeFrom(source)
    186         .build();
    187 
    188     assertEquals(
    189       "1: 1\n" +
    190       "2: 2\n" +
    191       "3: 3\n" +
    192       "3: 4\n",
    193       destination.toString());
    194   }
    195 
    196   public void testClear() throws Exception {
    197     UnknownFieldSet fields =
    198       UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clear().build();
    199     assertTrue(fields.asMap().isEmpty());
    200   }
    201 
    202   public void testClearMessage() throws Exception {
    203     TestEmptyMessage message =
    204       TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).clear().build();
    205     assertEquals(0, message.getSerializedSize());
    206   }
    207 
    208   public void testParseKnownAndUnknown() throws Exception {
    209     // Test mixing known and unknown fields when parsing.
    210 
    211     UnknownFieldSet fields =
    212       UnknownFieldSet.newBuilder(unknownFields)
    213         .addField(123456,
    214           UnknownFieldSet.Field.newBuilder().addVarint(654321).build())
    215         .build();
    216 
    217     ByteString data = fields.toByteString();
    218     TestAllTypes destination = TestAllTypes.parseFrom(data);
    219 
    220     TestUtil.assertAllFieldsSet(destination);
    221     assertEquals(1, destination.getUnknownFields().asMap().size());
    222 
    223     UnknownFieldSet.Field field =
    224       destination.getUnknownFields().getField(123456);
    225     assertEquals(1, field.getVarintList().size());
    226     assertEquals(654321, (long) field.getVarintList().get(0));
    227   }
    228 
    229   public void testWrongTypeTreatedAsUnknown() throws Exception {
    230     // Test that fields of the wrong wire type are treated like unknown fields
    231     // when parsing.
    232 
    233     ByteString bizarroData = getBizarroData();
    234     TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData);
    235     TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);
    236 
    237     // All fields should have been interpreted as unknown, so the debug strings
    238     // should be the same.
    239     assertEquals(emptyMessage.toString(), allTypesMessage.toString());
    240   }
    241 
    242   public void testUnknownExtensions() throws Exception {
    243     // Make sure fields are properly parsed to the UnknownFieldSet even when
    244     // they are declared as extension numbers.
    245 
    246     TestEmptyMessageWithExtensions message =
    247       TestEmptyMessageWithExtensions.parseFrom(allFieldsData);
    248 
    249     assertEquals(unknownFields.asMap().size(),
    250                  message.getUnknownFields().asMap().size());
    251     assertEquals(allFieldsData, message.toByteString());
    252   }
    253 
    254   public void testWrongExtensionTypeTreatedAsUnknown() throws Exception {
    255     // Test that fields of the wrong wire type are treated like unknown fields
    256     // when parsing extensions.
    257 
    258     ByteString bizarroData = getBizarroData();
    259     TestAllExtensions allExtensionsMessage =
    260       TestAllExtensions.parseFrom(bizarroData);
    261     TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);
    262 
    263     // All fields should have been interpreted as unknown, so the debug strings
    264     // should be the same.
    265     assertEquals(emptyMessage.toString(),
    266                  allExtensionsMessage.toString());
    267   }
    268 
    269   public void testParseUnknownEnumValue() throws Exception {
    270     Descriptors.FieldDescriptor singularField =
    271       TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum");
    272     Descriptors.FieldDescriptor repeatedField =
    273       TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum");
    274     assertNotNull(singularField);
    275     assertNotNull(repeatedField);
    276 
    277     ByteString data =
    278       UnknownFieldSet.newBuilder()
    279         .addField(singularField.getNumber(),
    280           UnknownFieldSet.Field.newBuilder()
    281             .addVarint(TestAllTypes.NestedEnum.BAR.getNumber())
    282             .addVarint(5)   // not valid
    283             .build())
    284         .addField(repeatedField.getNumber(),
    285           UnknownFieldSet.Field.newBuilder()
    286             .addVarint(TestAllTypes.NestedEnum.FOO.getNumber())
    287             .addVarint(4)   // not valid
    288             .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber())
    289             .addVarint(6)   // not valid
    290             .build())
    291         .build()
    292         .toByteString();
    293 
    294     {
    295       TestAllTypes message = TestAllTypes.parseFrom(data);
    296       assertEquals(TestAllTypes.NestedEnum.BAR,
    297                    message.getOptionalNestedEnum());
    298       assertEquals(
    299         Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
    300         message.getRepeatedNestedEnumList());
    301       assertEquals(Arrays.asList(5L),
    302                    message.getUnknownFields()
    303                           .getField(singularField.getNumber())
    304                           .getVarintList());
    305       assertEquals(Arrays.asList(4L, 6L),
    306                    message.getUnknownFields()
    307                           .getField(repeatedField.getNumber())
    308                           .getVarintList());
    309     }
    310 
    311     {
    312       TestAllExtensions message =
    313         TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
    314       assertEquals(TestAllTypes.NestedEnum.BAR,
    315         message.getExtension(UnittestProto.optionalNestedEnumExtension));
    316       assertEquals(
    317         Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
    318         message.getExtension(UnittestProto.repeatedNestedEnumExtension));
    319       assertEquals(Arrays.asList(5L),
    320                    message.getUnknownFields()
    321                           .getField(singularField.getNumber())
    322                           .getVarintList());
    323       assertEquals(Arrays.asList(4L, 6L),
    324                    message.getUnknownFields()
    325                           .getField(repeatedField.getNumber())
    326                           .getVarintList());
    327     }
    328   }
    329 
    330   public void testLargeVarint() throws Exception {
    331     ByteString data =
    332       UnknownFieldSet.newBuilder()
    333         .addField(1,
    334           UnknownFieldSet.Field.newBuilder()
    335             .addVarint(0x7FFFFFFFFFFFFFFFL)
    336             .build())
    337         .build()
    338         .toByteString();
    339     UnknownFieldSet parsed = UnknownFieldSet.parseFrom(data);
    340     UnknownFieldSet.Field field = parsed.getField(1);
    341     assertEquals(1, field.getVarintList().size());
    342     assertEquals(0x7FFFFFFFFFFFFFFFL, (long)field.getVarintList().get(0));
    343   }
    344 
    345   public void testEqualsAndHashCode() {
    346     UnknownFieldSet.Field fixed32Field =
    347         UnknownFieldSet.Field.newBuilder()
    348             .addFixed32(1)
    349             .build();
    350     UnknownFieldSet.Field fixed64Field =
    351         UnknownFieldSet.Field.newBuilder()
    352             .addFixed64(1)
    353             .build();
    354     UnknownFieldSet.Field varIntField =
    355         UnknownFieldSet.Field.newBuilder()
    356             .addVarint(1)
    357             .build();
    358     UnknownFieldSet.Field lengthDelimitedField =
    359         UnknownFieldSet.Field.newBuilder()
    360             .addLengthDelimited(ByteString.EMPTY)
    361             .build();
    362     UnknownFieldSet.Field groupField =
    363         UnknownFieldSet.Field.newBuilder()
    364             .addGroup(unknownFields)
    365             .build();
    366 
    367     UnknownFieldSet a =
    368         UnknownFieldSet.newBuilder()
    369             .addField(1, fixed32Field)
    370             .build();
    371     UnknownFieldSet b =
    372         UnknownFieldSet.newBuilder()
    373             .addField(1, fixed64Field)
    374             .build();
    375     UnknownFieldSet c =
    376         UnknownFieldSet.newBuilder()
    377             .addField(1, varIntField)
    378             .build();
    379     UnknownFieldSet d =
    380         UnknownFieldSet.newBuilder()
    381             .addField(1, lengthDelimitedField)
    382             .build();
    383     UnknownFieldSet e =
    384         UnknownFieldSet.newBuilder()
    385             .addField(1, groupField)
    386             .build();
    387 
    388     checkEqualsIsConsistent(a);
    389     checkEqualsIsConsistent(b);
    390     checkEqualsIsConsistent(c);
    391     checkEqualsIsConsistent(d);
    392     checkEqualsIsConsistent(e);
    393 
    394     checkNotEqual(a, b);
    395     checkNotEqual(a, c);
    396     checkNotEqual(a, d);
    397     checkNotEqual(a, e);
    398     checkNotEqual(b, c);
    399     checkNotEqual(b, d);
    400     checkNotEqual(b, e);
    401     checkNotEqual(c, d);
    402     checkNotEqual(c, e);
    403     checkNotEqual(d, e);
    404   }
    405 
    406   /**
    407    * Asserts that the given field sets are not equal and have different
    408    * hash codes.
    409    *
    410    * @warning It's valid for non-equal objects to have the same hash code, so
    411    *   this test is stricter than it needs to be. However, this should happen
    412    *   relatively rarely.
    413    */
    414   private void checkNotEqual(UnknownFieldSet s1, UnknownFieldSet s2) {
    415     String equalsError = String.format("%s should not be equal to %s", s1, s2);
    416     assertFalse(equalsError, s1.equals(s2));
    417     assertFalse(equalsError, s2.equals(s1));
    418 
    419     assertFalse(
    420         String.format("%s should have a different hash code from %s", s1, s2),
    421         s1.hashCode() == s2.hashCode());
    422   }
    423 
    424   /**
    425    * Asserts that the given field sets are equal and have identical hash codes.
    426    */
    427   private void checkEqualsIsConsistent(UnknownFieldSet set) {
    428     // Object should be equal to itself.
    429     assertEquals(set, set);
    430 
    431     // Object should be equal to a copy of itself.
    432     UnknownFieldSet copy = UnknownFieldSet.newBuilder(set).build();
    433     assertEquals(set, copy);
    434     assertEquals(copy, set);
    435     assertEquals(set.hashCode(), copy.hashCode());
    436   }
    437 }
    438