aboutsummaryrefslogblamecommitdiff
path: root/java/core/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
blob: 86630f65048429b67b2349d8367252b12c496ff4 (plain) (tree)
1
2
3
4
5
6
7
8
                                                      
                                                   
                                                  
  


                                                                         
  








                                                                         
  










                                                                        



                                       
                                                   
                                                         
                                                    
                                                        
                                                                      

                                                            

                        
                                






                                                   
           



















                                                                         

                                                                                                  
 
                                                                                              

























                                                                          
                                                                                    




                                                               
                                                                                      




                                                               
                                                                                       




                                                             
                                                                                      



                                                       
                                                                        








                                                                  
                                                                                          
                                                        
                                                                                                 









                                                                            
                                                                                             





                                                              






                                                                                         
                                  









                                                                                         


                                            
                                                                                                   




                                                   
                                                                              

                                                 
 





                                                                                              




                                                           


                                                                                           






                                                                   
                                                                                  





















                                                                               
                                                                
 
                                                                                          







                                                                              
                                                                                      



                                                                               
                                                                           



                                                            
                                                                             
                                               
                                                                             



                                 
















                                                                       


                                                          
                                                                                 
                   







                                                                                          



                                 






                                                                                  
                   




                                                                                          

     


                                                  



                                                                                                   


                                                             
                                                                           
   

                                       


                                                                                                  
                                                
                                                                                        
                                      
                                                                           
 




                                                                                               



















                               
                                                                                   
    

                                                                                                   










                                                                               
                                                                                   









                                                                   

                                                                      
 
// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

package com.google.protobuf;

import protobuf_unittest.UnittestProto;
import protobuf_unittest.UnittestProto.ForeignEnum;
import protobuf_unittest.UnittestProto.TestAllExtensions;
import protobuf_unittest.UnittestProto.TestAllTypes;
import protobuf_unittest.UnittestProto.TestEmptyMessage;
import protobuf_unittest.UnittestProto.TestEmptyMessageWithExtensions;
import protobuf_unittest.UnittestProto.TestPackedExtensions;
import protobuf_unittest.UnittestProto.TestPackedTypes;
import java.util.Arrays;
import java.util.Map;
import junit.framework.TestCase;

/**
 * Tests related to unknown field handling.
 *
 * @author kenton@google.com (Kenton Varda)
 */
public class UnknownFieldSetTest extends TestCase {
  @Override
  public void setUp() throws Exception {
    descriptor = TestAllTypes.getDescriptor();
    allFields = TestUtil.getAllSet();
    allFieldsData = allFields.toByteString();
    emptyMessage = TestEmptyMessage.parseFrom(allFieldsData);
    unknownFields = emptyMessage.getUnknownFields();
  }

  UnknownFieldSet.Field getField(String name) {
    Descriptors.FieldDescriptor field = descriptor.findFieldByName(name);
    assertNotNull(field);
    return unknownFields.getField(field.getNumber());
  }

  // Constructs a protocol buffer which contains fields with all the same
  // numbers as allFieldsData except that each field is some other wire
  // type.
  ByteString getBizarroData() throws Exception {
    UnknownFieldSet.Builder bizarroFields = UnknownFieldSet.newBuilder();

    UnknownFieldSet.Field varintField = UnknownFieldSet.Field.newBuilder().addVarint(1).build();
    UnknownFieldSet.Field fixed32Field = UnknownFieldSet.Field.newBuilder().addFixed32(1).build();

    for (Map.Entry<Integer, UnknownFieldSet.Field> entry : unknownFields.asMap().entrySet()) {
      if (entry.getValue().getVarintList().isEmpty()) {
        // Original field is not a varint, so use a varint.
        bizarroFields.addField(entry.getKey(), varintField);
      } else {
        // Original field *is* a varint, so use something else.
        bizarroFields.addField(entry.getKey(), fixed32Field);
      }
    }

    return bizarroFields.build().toByteString();
  }

  Descriptors.Descriptor descriptor;
  TestAllTypes allFields;
  ByteString allFieldsData;

  // An empty message that has been parsed from allFieldsData.  So, it has
  // unknown fields of every type.
  TestEmptyMessage emptyMessage;
  UnknownFieldSet unknownFields;

  // =================================================================

  public void testVarint() throws Exception {
    UnknownFieldSet.Field field = getField("optional_int32");
    assertEquals(1, field.getVarintList().size());
    assertEquals(allFields.getOptionalInt32(), (long) field.getVarintList().get(0));
  }

  public void testFixed32() throws Exception {
    UnknownFieldSet.Field field = getField("optional_fixed32");
    assertEquals(1, field.getFixed32List().size());
    assertEquals(allFields.getOptionalFixed32(), (int) field.getFixed32List().get(0));
  }

  public void testFixed64() throws Exception {
    UnknownFieldSet.Field field = getField("optional_fixed64");
    assertEquals(1, field.getFixed64List().size());
    assertEquals(allFields.getOptionalFixed64(), (long) field.getFixed64List().get(0));
  }

  public void testLengthDelimited() throws Exception {
    UnknownFieldSet.Field field = getField("optional_bytes");
    assertEquals(1, field.getLengthDelimitedList().size());
    assertEquals(allFields.getOptionalBytes(), field.getLengthDelimitedList().get(0));
  }

  public void testGroup() throws Exception {
    Descriptors.FieldDescriptor nestedFieldDescriptor =
        TestAllTypes.OptionalGroup.getDescriptor().findFieldByName("a");
    assertNotNull(nestedFieldDescriptor);

    UnknownFieldSet.Field field = getField("optionalgroup");
    assertEquals(1, field.getGroupList().size());

    UnknownFieldSet group = field.getGroupList().get(0);
    assertEquals(1, group.asMap().size());
    assertTrue(group.hasField(nestedFieldDescriptor.getNumber()));

    UnknownFieldSet.Field nestedField = group.getField(nestedFieldDescriptor.getNumber());
    assertEquals(1, nestedField.getVarintList().size());
    assertEquals(allFields.getOptionalGroup().getA(), (long) nestedField.getVarintList().get(0));
  }

  public void testSerialize() throws Exception {
    // Check that serializing the UnknownFieldSet produces the original data
    // again.
    ByteString data = emptyMessage.toByteString();
    assertEquals(allFieldsData, data);
  }

  public void testCopyFrom() throws Exception {
    TestEmptyMessage message = TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).build();

    assertEquals(emptyMessage.toString(), message.toString());
  }

  public void testMergeFrom() throws Exception {
    TestEmptyMessage source =
        TestEmptyMessage.newBuilder()
            .setUnknownFields(
                UnknownFieldSet.newBuilder()
                    .addField(2, UnknownFieldSet.Field.newBuilder().addVarint(2).build())
                    .addField(3, UnknownFieldSet.Field.newBuilder().addVarint(4).build())
                    .build())
            .build();
    TestEmptyMessage destination =
        TestEmptyMessage.newBuilder()
            .setUnknownFields(
                UnknownFieldSet.newBuilder()
                    .addField(1, UnknownFieldSet.Field.newBuilder().addVarint(1).build())
                    .addField(3, UnknownFieldSet.Field.newBuilder().addVarint(3).build())
                    .build())
            .mergeFrom(source)
            .build();

    assertEquals("1: 1\n2: 2\n3: 3\n3: 4\n", destination.toString());
  }

  public void testClear() throws Exception {
    UnknownFieldSet fields = UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clear().build();
    assertTrue(fields.asMap().isEmpty());
  }

  public void testClearMessage() throws Exception {
    TestEmptyMessage message =
        TestEmptyMessage.newBuilder().mergeFrom(emptyMessage).clear().build();
    assertEquals(0, message.getSerializedSize());
  }

  public void testClearField() throws Exception {
    int fieldNumber = unknownFields.asMap().keySet().iterator().next();
    UnknownFieldSet fields =
        UnknownFieldSet.newBuilder().mergeFrom(unknownFields).clearField(fieldNumber).build();
    assertFalse(fields.hasField(fieldNumber));
  }

  public void testParseKnownAndUnknown() throws Exception {
    // Test mixing known and unknown fields when parsing.

    UnknownFieldSet fields =
        UnknownFieldSet.newBuilder(unknownFields)
            .addField(123456, UnknownFieldSet.Field.newBuilder().addVarint(654321).build())
            .build();

    ByteString data = fields.toByteString();
    TestAllTypes destination = TestAllTypes.parseFrom(data);

    TestUtil.assertAllFieldsSet(destination);
    assertEquals(1, destination.getUnknownFields().asMap().size());

    UnknownFieldSet.Field field = destination.getUnknownFields().getField(123456);
    assertEquals(1, field.getVarintList().size());
    assertEquals(654321, (long) field.getVarintList().get(0));
  }

  public void testWrongTypeTreatedAsUnknown() throws Exception {
    // Test that fields of the wrong wire type are treated like unknown fields
    // when parsing.

    ByteString bizarroData = getBizarroData();
    TestAllTypes allTypesMessage = TestAllTypes.parseFrom(bizarroData);
    TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);

    // All fields should have been interpreted as unknown, so the debug strings
    // should be the same.
    assertEquals(emptyMessage.toString(), allTypesMessage.toString());
  }

  public void testUnknownExtensions() throws Exception {
    // Make sure fields are properly parsed to the UnknownFieldSet even when
    // they are declared as extension numbers.

    TestEmptyMessageWithExtensions message =
        TestEmptyMessageWithExtensions.parseFrom(allFieldsData);

    assertEquals(unknownFields.asMap().size(), message.getUnknownFields().asMap().size());
    assertEquals(allFieldsData, message.toByteString());
  }

  public void testWrongExtensionTypeTreatedAsUnknown() throws Exception {
    // Test that fields of the wrong wire type are treated like unknown fields
    // when parsing extensions.

    ByteString bizarroData = getBizarroData();
    TestAllExtensions allExtensionsMessage = TestAllExtensions.parseFrom(bizarroData);
    TestEmptyMessage emptyMessage = TestEmptyMessage.parseFrom(bizarroData);

    // All fields should have been interpreted as unknown, so the debug strings
    // should be the same.
    assertEquals(emptyMessage.toString(), allExtensionsMessage.toString());
  }

  public void testParseUnknownEnumValue() throws Exception {
    Descriptors.FieldDescriptor singularField =
        TestAllTypes.getDescriptor().findFieldByName("optional_nested_enum");
    Descriptors.FieldDescriptor repeatedField =
        TestAllTypes.getDescriptor().findFieldByName("repeated_nested_enum");
    assertNotNull(singularField);
    assertNotNull(repeatedField);

    ByteString data =
        UnknownFieldSet.newBuilder()
            .addField(
                singularField.getNumber(),
                UnknownFieldSet.Field.newBuilder()
                    .addVarint(TestAllTypes.NestedEnum.BAR.getNumber())
                    .addVarint(5) // not valid
                    .build())
            .addField(
                repeatedField.getNumber(),
                UnknownFieldSet.Field.newBuilder()
                    .addVarint(TestAllTypes.NestedEnum.FOO.getNumber())
                    .addVarint(4) // not valid
                    .addVarint(TestAllTypes.NestedEnum.BAZ.getNumber())
                    .addVarint(6) // not valid
                    .build())
            .build()
            .toByteString();

    {
      TestAllTypes message = TestAllTypes.parseFrom(data);
      assertEquals(TestAllTypes.NestedEnum.BAR, message.getOptionalNestedEnum());
      assertEquals(
          Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
          message.getRepeatedNestedEnumList());
      assertEquals(
          Arrays.asList(5L),
          message.getUnknownFields().getField(singularField.getNumber()).getVarintList());
      assertEquals(
          Arrays.asList(4L, 6L),
          message.getUnknownFields().getField(repeatedField.getNumber()).getVarintList());
    }

    {
      TestAllExtensions message =
          TestAllExtensions.parseFrom(data, TestUtil.getExtensionRegistry());
      assertEquals(
          TestAllTypes.NestedEnum.BAR,
          message.getExtension(UnittestProto.optionalNestedEnumExtension));
      assertEquals(
          Arrays.asList(TestAllTypes.NestedEnum.FOO, TestAllTypes.NestedEnum.BAZ),
          message.getExtension(UnittestProto.repeatedNestedEnumExtension));
      assertEquals(
          Arrays.asList(5L),
          message.getUnknownFields().getField(singularField.getNumber()).getVarintList());
      assertEquals(
          Arrays.asList(4L, 6L),
          message.getUnknownFields().getField(repeatedField.getNumber()).getVarintList());
    }
  }

  public void testLargeVarint() throws Exception {
    ByteString data =
        UnknownFieldSet.newBuilder()
            .addField(1, UnknownFieldSet.Field.newBuilder().addVarint(0x7FFFFFFFFFFFFFFFL).build())
            .build()
            .toByteString();
    UnknownFieldSet parsed = UnknownFieldSet.parseFrom(data);
    UnknownFieldSet.Field field = parsed.getField(1);
    assertEquals(1, field.getVarintList().size());
    assertEquals(0x7FFFFFFFFFFFFFFFL, (long) field.getVarintList().get(0));
  }

  public void testEqualsAndHashCode() {
    UnknownFieldSet.Field fixed32Field = UnknownFieldSet.Field.newBuilder().addFixed32(1).build();
    UnknownFieldSet.Field fixed64Field = UnknownFieldSet.Field.newBuilder().addFixed64(1).build();
    UnknownFieldSet.Field varIntField = UnknownFieldSet.Field.newBuilder().addVarint(1).build();
    UnknownFieldSet.Field lengthDelimitedField =
        UnknownFieldSet.Field.newBuilder().addLengthDelimited(ByteString.EMPTY).build();
    UnknownFieldSet.Field groupField =
        UnknownFieldSet.Field.newBuilder().addGroup(unknownFields).build();

    UnknownFieldSet a = UnknownFieldSet.newBuilder().addField(1, fixed32Field).build();
    UnknownFieldSet b = UnknownFieldSet.newBuilder().addField(1, fixed64Field).build();
    UnknownFieldSet c = UnknownFieldSet.newBuilder().addField(1, varIntField).build();
    UnknownFieldSet d = UnknownFieldSet.newBuilder().addField(1, lengthDelimitedField).build();
    UnknownFieldSet e = UnknownFieldSet.newBuilder().addField(1, groupField).build();

    checkEqualsIsConsistent(a);
    checkEqualsIsConsistent(b);
    checkEqualsIsConsistent(c);
    checkEqualsIsConsistent(d);
    checkEqualsIsConsistent(e);

    checkNotEqual(a, b);
    checkNotEqual(a, c);
    checkNotEqual(a, d);
    checkNotEqual(a, e);
    checkNotEqual(b, c);
    checkNotEqual(b, d);
    checkNotEqual(b, e);
    checkNotEqual(c, d);
    checkNotEqual(c, e);
    checkNotEqual(d, e);
  }

  /**
   * Asserts that the given field sets are not equal and have different hash codes.
   *
   * @warning It's valid for non-equal objects to have the same hash code, so this test is stricter
   *     than it needs to be. However, this should happen relatively rarely.
   */
  private void checkNotEqual(UnknownFieldSet s1, UnknownFieldSet s2) {
    String equalsError = String.format("%s should not be equal to %s", s1, s2);
    assertFalse(equalsError, s1.equals(s2));
    assertFalse(equalsError, s2.equals(s1));

    assertFalse(
        String.format("%s should have a different hash code from %s", s1, s2),
        s1.hashCode() == s2.hashCode());
  }

  /** Asserts that the given field sets are equal and have identical hash codes. */
  private void checkEqualsIsConsistent(UnknownFieldSet set) {
    // Object should be equal to itself.
    assertEquals(set, set);

    // Object should be equal to a copy of itself.
    UnknownFieldSet copy = UnknownFieldSet.newBuilder(set).build();
    assertEquals(set, copy);
    assertEquals(copy, set);
    assertEquals(set.hashCode(), copy.hashCode());
  }

  // =================================================================
}