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 com.google.protobuf.DescriptorProtos.DescriptorProto;
     34 import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
     35 import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
     36 import com.google.protobuf.Descriptors.DescriptorValidationException;
     37 import com.google.protobuf.Descriptors.FileDescriptor;
     38 import com.google.protobuf.Descriptors.Descriptor;
     39 import com.google.protobuf.Descriptors.FieldDescriptor;
     40 import com.google.protobuf.Descriptors.EnumDescriptor;
     41 import com.google.protobuf.Descriptors.EnumValueDescriptor;
     42 import com.google.protobuf.Descriptors.ServiceDescriptor;
     43 import com.google.protobuf.Descriptors.MethodDescriptor;
     44 
     45 import com.google.protobuf.test.UnittestImport;
     46 import com.google.protobuf.test.UnittestImport.ImportEnum;
     47 import com.google.protobuf.test.UnittestImport.ImportMessage;
     48 import protobuf_unittest.UnittestProto;
     49 import protobuf_unittest.UnittestProto.ForeignEnum;
     50 import protobuf_unittest.UnittestProto.ForeignMessage;
     51 import protobuf_unittest.UnittestProto.TestAllTypes;
     52 import protobuf_unittest.UnittestProto.TestAllExtensions;
     53 import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
     54 import protobuf_unittest.UnittestProto.TestRequired;
     55 import protobuf_unittest.UnittestProto.TestService;
     56 import protobuf_unittest.UnittestCustomOptions;
     57 
     58 
     59 import junit.framework.TestCase;
     60 
     61 import java.util.Arrays;
     62 import java.util.Collections;
     63 
     64 /**
     65  * Unit test for {@link Descriptors}.
     66  *
     67  * @author kenton (at) google.com Kenton Varda
     68  */
     69 public class DescriptorsTest extends TestCase {
     70 
     71   // Regression test for bug where referencing a FieldDescriptor.Type value
     72   // before a FieldDescriptorProto.Type value would yield a
     73   // ExceptionInInitializerError.
     74   private static final Object STATIC_INIT_TEST = FieldDescriptor.Type.BOOL;
     75 
     76   public void testFieldTypeEnumMapping() throws Exception {
     77     assertEquals(FieldDescriptor.Type.values().length,
     78         FieldDescriptorProto.Type.values().length);
     79     for (FieldDescriptor.Type type : FieldDescriptor.Type.values()) {
     80       FieldDescriptorProto.Type protoType = type.toProto();
     81       assertEquals("TYPE_" + type.name(), protoType.name());
     82       assertEquals(type, FieldDescriptor.Type.valueOf(protoType));
     83     }
     84   }
     85 
     86   public void testFileDescriptor() throws Exception {
     87     FileDescriptor file = UnittestProto.getDescriptor();
     88 
     89     assertEquals("google/protobuf/unittest.proto", file.getName());
     90     assertEquals("protobuf_unittest", file.getPackage());
     91 
     92     assertEquals("UnittestProto", file.getOptions().getJavaOuterClassname());
     93     assertEquals("google/protobuf/unittest.proto",
     94                  file.toProto().getName());
     95 
     96     assertEquals(Arrays.asList(UnittestImport.getDescriptor()),
     97                  file.getDependencies());
     98 
     99     Descriptor messageType = TestAllTypes.getDescriptor();
    100     assertEquals(messageType, file.getMessageTypes().get(0));
    101     assertEquals(messageType, file.findMessageTypeByName("TestAllTypes"));
    102     assertNull(file.findMessageTypeByName("NoSuchType"));
    103     assertNull(file.findMessageTypeByName("protobuf_unittest.TestAllTypes"));
    104     for (int i = 0; i < file.getMessageTypes().size(); i++) {
    105       assertEquals(i, file.getMessageTypes().get(i).getIndex());
    106     }
    107 
    108     EnumDescriptor enumType = ForeignEnum.getDescriptor();
    109     assertEquals(enumType, file.getEnumTypes().get(0));
    110     assertEquals(enumType, file.findEnumTypeByName("ForeignEnum"));
    111     assertNull(file.findEnumTypeByName("NoSuchType"));
    112     assertNull(file.findEnumTypeByName("protobuf_unittest.ForeignEnum"));
    113     assertEquals(Arrays.asList(ImportEnum.getDescriptor()),
    114                  UnittestImport.getDescriptor().getEnumTypes());
    115     for (int i = 0; i < file.getEnumTypes().size(); i++) {
    116       assertEquals(i, file.getEnumTypes().get(i).getIndex());
    117     }
    118 
    119     ServiceDescriptor service = TestService.getDescriptor();
    120     assertEquals(service, file.getServices().get(0));
    121     assertEquals(service, file.findServiceByName("TestService"));
    122     assertNull(file.findServiceByName("NoSuchType"));
    123     assertNull(file.findServiceByName("protobuf_unittest.TestService"));
    124     assertEquals(Collections.emptyList(),
    125                  UnittestImport.getDescriptor().getServices());
    126     for (int i = 0; i < file.getServices().size(); i++) {
    127       assertEquals(i, file.getServices().get(i).getIndex());
    128     }
    129 
    130     FieldDescriptor extension =
    131       UnittestProto.optionalInt32Extension.getDescriptor();
    132     assertEquals(extension, file.getExtensions().get(0));
    133     assertEquals(extension,
    134                  file.findExtensionByName("optional_int32_extension"));
    135     assertNull(file.findExtensionByName("no_such_ext"));
    136     assertNull(file.findExtensionByName(
    137       "protobuf_unittest.optional_int32_extension"));
    138     assertEquals(Collections.emptyList(),
    139                  UnittestImport.getDescriptor().getExtensions());
    140     for (int i = 0; i < file.getExtensions().size(); i++) {
    141       assertEquals(i, file.getExtensions().get(i).getIndex());
    142     }
    143   }
    144 
    145   public void testDescriptor() throws Exception {
    146     Descriptor messageType = TestAllTypes.getDescriptor();
    147     Descriptor nestedType = TestAllTypes.NestedMessage.getDescriptor();
    148 
    149     assertEquals("TestAllTypes", messageType.getName());
    150     assertEquals("protobuf_unittest.TestAllTypes", messageType.getFullName());
    151     assertEquals(UnittestProto.getDescriptor(), messageType.getFile());
    152     assertNull(messageType.getContainingType());
    153     assertEquals(DescriptorProtos.MessageOptions.getDefaultInstance(),
    154                  messageType.getOptions());
    155     assertEquals("TestAllTypes", messageType.toProto().getName());
    156 
    157     assertEquals("NestedMessage", nestedType.getName());
    158     assertEquals("protobuf_unittest.TestAllTypes.NestedMessage",
    159                  nestedType.getFullName());
    160     assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
    161     assertEquals(messageType, nestedType.getContainingType());
    162 
    163     FieldDescriptor field = messageType.getFields().get(0);
    164     assertEquals("optional_int32", field.getName());
    165     assertEquals(field, messageType.findFieldByName("optional_int32"));
    166     assertNull(messageType.findFieldByName("no_such_field"));
    167     assertEquals(field, messageType.findFieldByNumber(1));
    168     assertNull(messageType.findFieldByNumber(571283));
    169     for (int i = 0; i < messageType.getFields().size(); i++) {
    170       assertEquals(i, messageType.getFields().get(i).getIndex());
    171     }
    172 
    173     assertEquals(nestedType, messageType.getNestedTypes().get(0));
    174     assertEquals(nestedType, messageType.findNestedTypeByName("NestedMessage"));
    175     assertNull(messageType.findNestedTypeByName("NoSuchType"));
    176     for (int i = 0; i < messageType.getNestedTypes().size(); i++) {
    177       assertEquals(i, messageType.getNestedTypes().get(i).getIndex());
    178     }
    179 
    180     EnumDescriptor enumType = TestAllTypes.NestedEnum.getDescriptor();
    181     assertEquals(enumType, messageType.getEnumTypes().get(0));
    182     assertEquals(enumType, messageType.findEnumTypeByName("NestedEnum"));
    183     assertNull(messageType.findEnumTypeByName("NoSuchType"));
    184     for (int i = 0; i < messageType.getEnumTypes().size(); i++) {
    185       assertEquals(i, messageType.getEnumTypes().get(i).getIndex());
    186     }
    187   }
    188 
    189   public void testFieldDescriptor() throws Exception {
    190     Descriptor messageType = TestAllTypes.getDescriptor();
    191     FieldDescriptor primitiveField =
    192       messageType.findFieldByName("optional_int32");
    193     FieldDescriptor enumField =
    194       messageType.findFieldByName("optional_nested_enum");
    195     FieldDescriptor messageField =
    196       messageType.findFieldByName("optional_foreign_message");
    197     FieldDescriptor cordField =
    198       messageType.findFieldByName("optional_cord");
    199     FieldDescriptor extension =
    200       UnittestProto.optionalInt32Extension.getDescriptor();
    201     FieldDescriptor nestedExtension = TestRequired.single.getDescriptor();
    202 
    203     assertEquals("optional_int32", primitiveField.getName());
    204     assertEquals("protobuf_unittest.TestAllTypes.optional_int32",
    205                  primitiveField.getFullName());
    206     assertEquals(1, primitiveField.getNumber());
    207     assertEquals(messageType, primitiveField.getContainingType());
    208     assertEquals(UnittestProto.getDescriptor(), primitiveField.getFile());
    209     assertEquals(FieldDescriptor.Type.INT32, primitiveField.getType());
    210     assertEquals(FieldDescriptor.JavaType.INT, primitiveField.getJavaType());
    211     assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(),
    212                  primitiveField.getOptions());
    213     assertFalse(primitiveField.isExtension());
    214     assertEquals("optional_int32", primitiveField.toProto().getName());
    215 
    216     assertEquals("optional_nested_enum", enumField.getName());
    217     assertEquals(FieldDescriptor.Type.ENUM, enumField.getType());
    218     assertEquals(FieldDescriptor.JavaType.ENUM, enumField.getJavaType());
    219     assertEquals(TestAllTypes.NestedEnum.getDescriptor(),
    220                  enumField.getEnumType());
    221 
    222     assertEquals("optional_foreign_message", messageField.getName());
    223     assertEquals(FieldDescriptor.Type.MESSAGE, messageField.getType());
    224     assertEquals(FieldDescriptor.JavaType.MESSAGE, messageField.getJavaType());
    225     assertEquals(ForeignMessage.getDescriptor(), messageField.getMessageType());
    226 
    227     assertEquals("optional_cord", cordField.getName());
    228     assertEquals(FieldDescriptor.Type.STRING, cordField.getType());
    229     assertEquals(FieldDescriptor.JavaType.STRING, cordField.getJavaType());
    230     assertEquals(DescriptorProtos.FieldOptions.CType.CORD,
    231                  cordField.getOptions().getCtype());
    232 
    233     assertEquals("optional_int32_extension", extension.getName());
    234     assertEquals("protobuf_unittest.optional_int32_extension",
    235                  extension.getFullName());
    236     assertEquals(1, extension.getNumber());
    237     assertEquals(TestAllExtensions.getDescriptor(),
    238                  extension.getContainingType());
    239     assertEquals(UnittestProto.getDescriptor(), extension.getFile());
    240     assertEquals(FieldDescriptor.Type.INT32, extension.getType());
    241     assertEquals(FieldDescriptor.JavaType.INT, extension.getJavaType());
    242     assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(),
    243                  extension.getOptions());
    244     assertTrue(extension.isExtension());
    245     assertEquals(null, extension.getExtensionScope());
    246     assertEquals("optional_int32_extension", extension.toProto().getName());
    247 
    248     assertEquals("single", nestedExtension.getName());
    249     assertEquals("protobuf_unittest.TestRequired.single",
    250                  nestedExtension.getFullName());
    251     assertEquals(TestRequired.getDescriptor(),
    252                  nestedExtension.getExtensionScope());
    253   }
    254 
    255   public void testFieldDescriptorLabel() throws Exception {
    256     FieldDescriptor requiredField =
    257       TestRequired.getDescriptor().findFieldByName("a");
    258     FieldDescriptor optionalField =
    259       TestAllTypes.getDescriptor().findFieldByName("optional_int32");
    260     FieldDescriptor repeatedField =
    261       TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
    262 
    263     assertTrue(requiredField.isRequired());
    264     assertFalse(requiredField.isRepeated());
    265     assertFalse(optionalField.isRequired());
    266     assertFalse(optionalField.isRepeated());
    267     assertFalse(repeatedField.isRequired());
    268     assertTrue(repeatedField.isRepeated());
    269   }
    270 
    271   public void testFieldDescriptorDefault() throws Exception {
    272     Descriptor d = TestAllTypes.getDescriptor();
    273     assertFalse(d.findFieldByName("optional_int32").hasDefaultValue());
    274     assertEquals(0, d.findFieldByName("optional_int32").getDefaultValue());
    275     assertTrue(d.findFieldByName("default_int32").hasDefaultValue());
    276     assertEquals(41, d.findFieldByName("default_int32").getDefaultValue());
    277 
    278     d = TestExtremeDefaultValues.getDescriptor();
    279     assertEquals(
    280       ByteString.copyFrom(
    281         "\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes("ISO-8859-1")),
    282       d.findFieldByName("escaped_bytes").getDefaultValue());
    283     assertEquals(-1, d.findFieldByName("large_uint32").getDefaultValue());
    284     assertEquals(-1L, d.findFieldByName("large_uint64").getDefaultValue());
    285   }
    286 
    287   public void testEnumDescriptor() throws Exception {
    288     EnumDescriptor enumType = ForeignEnum.getDescriptor();
    289     EnumDescriptor nestedType = TestAllTypes.NestedEnum.getDescriptor();
    290 
    291     assertEquals("ForeignEnum", enumType.getName());
    292     assertEquals("protobuf_unittest.ForeignEnum", enumType.getFullName());
    293     assertEquals(UnittestProto.getDescriptor(), enumType.getFile());
    294     assertNull(enumType.getContainingType());
    295     assertEquals(DescriptorProtos.EnumOptions.getDefaultInstance(),
    296                  enumType.getOptions());
    297 
    298     assertEquals("NestedEnum", nestedType.getName());
    299     assertEquals("protobuf_unittest.TestAllTypes.NestedEnum",
    300                  nestedType.getFullName());
    301     assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
    302     assertEquals(TestAllTypes.getDescriptor(), nestedType.getContainingType());
    303 
    304     EnumValueDescriptor value = ForeignEnum.FOREIGN_FOO.getValueDescriptor();
    305     assertEquals(value, enumType.getValues().get(0));
    306     assertEquals("FOREIGN_FOO", value.getName());
    307     assertEquals(4, value.getNumber());
    308     assertEquals(value, enumType.findValueByName("FOREIGN_FOO"));
    309     assertEquals(value, enumType.findValueByNumber(4));
    310     assertNull(enumType.findValueByName("NO_SUCH_VALUE"));
    311     for (int i = 0; i < enumType.getValues().size(); i++) {
    312       assertEquals(i, enumType.getValues().get(i).getIndex());
    313     }
    314   }
    315 
    316   public void testServiceDescriptor() throws Exception {
    317     ServiceDescriptor service = TestService.getDescriptor();
    318 
    319     assertEquals("TestService", service.getName());
    320     assertEquals("protobuf_unittest.TestService", service.getFullName());
    321     assertEquals(UnittestProto.getDescriptor(), service.getFile());
    322 
    323     assertEquals(2, service.getMethods().size());
    324 
    325     MethodDescriptor fooMethod = service.getMethods().get(0);
    326     assertEquals("Foo", fooMethod.getName());
    327     assertEquals(UnittestProto.FooRequest.getDescriptor(),
    328                  fooMethod.getInputType());
    329     assertEquals(UnittestProto.FooResponse.getDescriptor(),
    330                  fooMethod.getOutputType());
    331     assertEquals(fooMethod, service.findMethodByName("Foo"));
    332 
    333     MethodDescriptor barMethod = service.getMethods().get(1);
    334     assertEquals("Bar", barMethod.getName());
    335     assertEquals(UnittestProto.BarRequest.getDescriptor(),
    336                  barMethod.getInputType());
    337     assertEquals(UnittestProto.BarResponse.getDescriptor(),
    338                  barMethod.getOutputType());
    339     assertEquals(barMethod, service.findMethodByName("Bar"));
    340 
    341     assertNull(service.findMethodByName("NoSuchMethod"));
    342 
    343     for (int i = 0; i < service.getMethods().size(); i++) {
    344       assertEquals(i, service.getMethods().get(i).getIndex());
    345     }
    346   }
    347 
    348 
    349   public void testCustomOptions() throws Exception {
    350     Descriptor descriptor =
    351       UnittestCustomOptions.TestMessageWithCustomOptions.getDescriptor();
    352 
    353     assertTrue(
    354       descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1));
    355     assertEquals(Integer.valueOf(-56),
    356       descriptor.getOptions().getExtension(UnittestCustomOptions.messageOpt1));
    357 
    358     FieldDescriptor field = descriptor.findFieldByName("field1");
    359     assertNotNull(field);
    360 
    361     assertTrue(
    362       field.getOptions().hasExtension(UnittestCustomOptions.fieldOpt1));
    363     assertEquals(Long.valueOf(8765432109L),
    364       field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1));
    365 
    366     EnumDescriptor enumType =
    367       UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor();
    368 
    369     assertTrue(
    370       enumType.getOptions().hasExtension(UnittestCustomOptions.enumOpt1));
    371     assertEquals(Integer.valueOf(-789),
    372       enumType.getOptions().getExtension(UnittestCustomOptions.enumOpt1));
    373 
    374     ServiceDescriptor service =
    375       UnittestCustomOptions.TestServiceWithCustomOptions.getDescriptor();
    376 
    377     assertTrue(
    378       service.getOptions().hasExtension(UnittestCustomOptions.serviceOpt1));
    379     assertEquals(Long.valueOf(-9876543210L),
    380       service.getOptions().getExtension(UnittestCustomOptions.serviceOpt1));
    381 
    382     MethodDescriptor method = service.findMethodByName("Foo");
    383     assertNotNull(method);
    384 
    385     assertTrue(
    386       method.getOptions().hasExtension(UnittestCustomOptions.methodOpt1));
    387     assertEquals(UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2,
    388       method.getOptions().getExtension(UnittestCustomOptions.methodOpt1));
    389   }
    390 
    391   /**
    392    * Test that the FieldDescriptor.Type enum is the same as the
    393    * WireFormat.FieldType enum.
    394    */
    395   public void testFieldTypeTablesMatch() throws Exception {
    396     FieldDescriptor.Type[] values1 = FieldDescriptor.Type.values();
    397     WireFormat.FieldType[] values2 = WireFormat.FieldType.values();
    398 
    399     assertEquals(values1.length, values2.length);
    400 
    401     for (int i = 0; i < values1.length; i++) {
    402       assertEquals(values1[i].toString(), values2[i].toString());
    403     }
    404   }
    405 
    406   /**
    407    * Test that the FieldDescriptor.JavaType enum is the same as the
    408    * WireFormat.JavaType enum.
    409    */
    410   public void testJavaTypeTablesMatch() throws Exception {
    411     FieldDescriptor.JavaType[] values1 = FieldDescriptor.JavaType.values();
    412     WireFormat.JavaType[] values2 = WireFormat.JavaType.values();
    413 
    414     assertEquals(values1.length, values2.length);
    415 
    416     for (int i = 0; i < values1.length; i++) {
    417       assertEquals(values1[i].toString(), values2[i].toString());
    418     }
    419   }
    420 
    421   public void testEnormousDescriptor() throws Exception {
    422     // The descriptor for this file is larger than 64k, yet it did not cause
    423     // a compiler error due to an over-long string literal.
    424     assertTrue(
    425         UnittestEnormousDescriptor.getDescriptor()
    426           .toProto().getSerializedSize() > 65536);
    427   }
    428 
    429   /**
    430    * Tests that the DescriptorValidationException works as intended.
    431    */
    432   public void testDescriptorValidatorException() throws Exception {
    433     FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
    434       .setName("foo.proto")
    435       .addMessageType(DescriptorProto.newBuilder()
    436       .setName("Foo")
    437         .addField(FieldDescriptorProto.newBuilder()
    438           .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
    439           .setType(FieldDescriptorProto.Type.TYPE_INT32)
    440           .setName("foo")
    441           .setNumber(1)
    442           .setDefaultValue("invalid")
    443           .build())
    444         .build())
    445       .build();
    446     try {
    447       Descriptors.FileDescriptor.buildFrom(fileDescriptorProto,
    448           new FileDescriptor[0]);
    449       fail("DescriptorValidationException expected");
    450     } catch (DescriptorValidationException e) {
    451       // Expected; check that the error message contains some useful hints
    452       assertTrue(e.getMessage().indexOf("foo") != -1);
    453       assertTrue(e.getMessage().indexOf("Foo") != -1);
    454       assertTrue(e.getMessage().indexOf("invalid") != -1);
    455       assertTrue(e.getCause() instanceof NumberFormatException);
    456       assertTrue(e.getCause().getMessage().indexOf("invalid") != -1);
    457     }
    458   }
    459 }
    460