content: // 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.NestedExtension;
  import protobuf_unittest.NonNestedExtension;
  import com.google.protobuf.DescriptorProtos.DescriptorProto;
  import com.google.protobuf.DescriptorProtos.EnumDescriptorProto;
  import com.google.protobuf.DescriptorProtos.EnumValueDescriptorProto;
  import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
  import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
  import com.google.protobuf.Descriptors.Descriptor;
  import com.google.protobuf.Descriptors.DescriptorValidationException;
  import com.google.protobuf.Descriptors.EnumDescriptor;
  import com.google.protobuf.Descriptors.EnumValueDescriptor;
  import com.google.protobuf.Descriptors.FieldDescriptor;
  import com.google.protobuf.Descriptors.FileDescriptor;
  import com.google.protobuf.Descriptors.MethodDescriptor;
  import com.google.protobuf.Descriptors.OneofDescriptor;
  import com.google.protobuf.Descriptors.ServiceDescriptor;
  import com.google.protobuf.test.UnittestImport;
  import com.google.protobuf.test.UnittestImport.ImportEnum;
  import com.google.protobuf.test.UnittestImport.ImportEnumForMap;
  import protobuf_unittest.TestCustomOptions;
  import protobuf_unittest.UnittestCustomOptions;
  import protobuf_unittest.UnittestProto;
  import protobuf_unittest.UnittestProto.ForeignEnum;
  import protobuf_unittest.UnittestProto.ForeignMessage;
  import protobuf_unittest.UnittestProto.TestAllExtensions;
  import protobuf_unittest.UnittestProto.TestAllTypes;
  import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
  import protobuf_unittest.UnittestProto.TestJsonName;
  import protobuf_unittest.UnittestProto.TestMultipleExtensionRanges;
  import protobuf_unittest.UnittestProto.TestRequired;
  import protobuf_unittest.UnittestProto.TestReservedFields;
  import protobuf_unittest.UnittestProto.TestService;
  import java.util.Arrays;
  import java.util.Collections;
  import java.util.List;
  import junit.framework.TestCase;
  
  /**
   * Unit test for {@link Descriptors}.
   *
   * @author kenton@google.com Kenton Varda
   */
  public class DescriptorsTest extends TestCase {
  
    // Regression test for bug where referencing a FieldDescriptor.Type value
    // before a FieldDescriptorProto.Type value would yield a
    // ExceptionInInitializerError.
    @SuppressWarnings("unused")
    private static final Object STATIC_INIT_TEST = FieldDescriptor.Type.BOOL;
  
    public void testFieldTypeEnumMapping() throws Exception {
      assertEquals(FieldDescriptor.Type.values().length, FieldDescriptorProto.Type.values().length);
      for (FieldDescriptor.Type type : FieldDescriptor.Type.values()) {
        FieldDescriptorProto.Type protoType = type.toProto();
        assertEquals("TYPE_" + type.name(), protoType.name());
        assertEquals(type, FieldDescriptor.Type.valueOf(protoType));
      }
    }
  
    public void testFileDescriptor() throws Exception {
      FileDescriptor file = UnittestProto.getDescriptor();
  
      assertEquals("google/protobuf/unittest.proto", file.getName());
      assertEquals("protobuf_unittest", file.getPackage());
  
      assertEquals("UnittestProto", file.getOptions().getJavaOuterClassname());
      assertEquals("google/protobuf/unittest.proto", file.toProto().getName());
  
      assertEquals(Arrays.asList(UnittestImport.getDescriptor()), file.getDependencies());
  
      Descriptor messageType = TestAllTypes.getDescriptor();
      assertEquals(messageType, file.getMessageTypes().get(0));
      assertEquals(messageType, file.findMessageTypeByName("TestAllTypes"));
      assertNull(file.findMessageTypeByName("NoSuchType"));
      assertNull(file.findMessageTypeByName("protobuf_unittest.TestAllTypes"));
      for (int i = 0; i < file.getMessageTypes().size(); i++) {
        assertEquals(i, file.getMessageTypes().get(i).getIndex());
      }
  
      EnumDescriptor enumType = ForeignEnum.getDescriptor();
      assertEquals(enumType, file.getEnumTypes().get(0));
      assertEquals(enumType, file.findEnumTypeByName("ForeignEnum"));
      assertNull(file.findEnumTypeByName("NoSuchType"));
      assertNull(file.findEnumTypeByName("protobuf_unittest.ForeignEnum"));
      assertEquals(
          Arrays.asList(ImportEnum.getDescriptor(), ImportEnumForMap.getDescriptor()),
          UnittestImport.getDescriptor().getEnumTypes());
      for (int i = 0; i < file.getEnumTypes().size(); i++) {
        assertEquals(i, file.getEnumTypes().get(i).getIndex());
      }
  
      ServiceDescriptor service = TestService.getDescriptor();
      assertEquals(service, file.getServices().get(0));
      assertEquals(service, file.findServiceByName("TestService"));
      assertNull(file.findServiceByName("NoSuchType"));
      assertNull(file.findServiceByName("protobuf_unittest.TestService"));
      assertEquals(Collections.emptyList(), UnittestImport.getDescriptor().getServices());
      for (int i = 0; i < file.getServices().size(); i++) {
        assertEquals(i, file.getServices().get(i).getIndex());
      }
  
      FieldDescriptor extension = UnittestProto.optionalInt32Extension.getDescriptor();
      assertEquals(extension, file.getExtensions().get(0));
      assertEquals(extension, file.findExtensionByName("optional_int32_extension"));
      assertNull(file.findExtensionByName("no_such_ext"));
      assertNull(file.findExtensionByName("protobuf_unittest.optional_int32_extension"));
      assertEquals(Collections.emptyList(), UnittestImport.getDescriptor().getExtensions());
      for (int i = 0; i < file.getExtensions().size(); i++) {
        assertEquals(i, file.getExtensions().get(i).getIndex());
      }
    }
  
    public void testDescriptor() throws Exception {
      Descriptor messageType = TestAllTypes.getDescriptor();
      Descriptor nestedType = TestAllTypes.NestedMessage.getDescriptor();
  
      assertEquals("TestAllTypes", messageType.getName());
      assertEquals("protobuf_unittest.TestAllTypes", messageType.getFullName());
      assertEquals(UnittestProto.getDescriptor(), messageType.getFile());
      assertNull(messageType.getContainingType());
      assertEquals(DescriptorProtos.MessageOptions.getDefaultInstance(), messageType.getOptions());
      assertEquals("TestAllTypes", messageType.toProto().getName());
  
      assertEquals("NestedMessage", nestedType.getName());
      assertEquals("protobuf_unittest.TestAllTypes.NestedMessage", nestedType.getFullName());
      assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
      assertEquals(messageType, nestedType.getContainingType());
  
      FieldDescriptor field = messageType.getFields().get(0);
      assertEquals("optional_int32", field.getName());
      assertEquals(field, messageType.findFieldByName("optional_int32"));
      assertNull(messageType.findFieldByName("no_such_field"));
      assertEquals(field, messageType.findFieldByNumber(1));
      assertNull(messageType.findFieldByNumber(571283));
      for (int i = 0; i < messageType.getFields().size(); i++) {
        assertEquals(i, messageType.getFields().get(i).getIndex());
      }
  
      assertEquals(nestedType, messageType.getNestedTypes().get(0));
      assertEquals(nestedType, messageType.findNestedTypeByName("NestedMessage"));
      assertNull(messageType.findNestedTypeByName("NoSuchType"));
      for (int i = 0; i < messageType.getNestedTypes().size(); i++) {
        assertEquals(i, messageType.getNestedTypes().get(i).getIndex());
      }
  
      EnumDescriptor enumType = TestAllTypes.NestedEnum.getDescriptor();
      assertEquals(enumType, messageType.getEnumTypes().get(0));
      assertEquals(enumType, messageType.findEnumTypeByName("NestedEnum"));
      assertNull(messageType.findEnumTypeByName("NoSuchType"));
      for (int i = 0; i < messageType.getEnumTypes().size(); i++) {
        assertEquals(i, messageType.getEnumTypes().get(i).getIndex());
      }
    }
  
    public void testFieldDescriptor() throws Exception {
      Descriptor messageType = TestAllTypes.getDescriptor();
      FieldDescriptor primitiveField = messageType.findFieldByName("optional_int32");
      FieldDescriptor enumField = messageType.findFieldByName("optional_nested_enum");
      FieldDescriptor messageField = messageType.findFieldByName("optional_foreign_message");
      FieldDescriptor cordField = messageType.findFieldByName("optional_cord");
      FieldDescriptor extension = UnittestProto.optionalInt32Extension.getDescriptor();
      FieldDescriptor nestedExtension = TestRequired.single.getDescriptor();
  
      assertEquals("optional_int32", primitiveField.getName());
      assertEquals("protobuf_unittest.TestAllTypes.optional_int32", primitiveField.getFullName());
      assertEquals(1, primitiveField.getNumber());
      assertEquals(messageType, primitiveField.getContainingType());
      assertEquals(UnittestProto.getDescriptor(), primitiveField.getFile());
      assertEquals(FieldDescriptor.Type.INT32, primitiveField.getType());
      assertEquals(FieldDescriptor.JavaType.INT, primitiveField.getJavaType());
      assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(), primitiveField.getOptions());
      assertFalse(primitiveField.isExtension());
      assertEquals("optional_int32", primitiveField.toProto().getName());
  
      assertEquals("optional_nested_enum", enumField.getName());
      assertEquals(FieldDescriptor.Type.ENUM, enumField.getType());
      assertEquals(FieldDescriptor.JavaType.ENUM, enumField.getJavaType());
      assertEquals(TestAllTypes.NestedEnum.getDescriptor(), enumField.getEnumType());
  
      assertEquals("optional_foreign_message", messageField.getName());
      assertEquals(FieldDescriptor.Type.MESSAGE, messageField.getType());
      assertEquals(FieldDescriptor.JavaType.MESSAGE, messageField.getJavaType());
      assertEquals(ForeignMessage.getDescriptor(), messageField.getMessageType());
  
      assertEquals("optional_cord", cordField.getName());
      assertEquals(FieldDescriptor.Type.STRING, cordField.getType());
      assertEquals(FieldDescriptor.JavaType.STRING, cordField.getJavaType());
      assertEquals(DescriptorProtos.FieldOptions.CType.CORD, cordField.getOptions().getCtype());
  
      assertEquals("optional_int32_extension", extension.getName());
      assertEquals("protobuf_unittest.optional_int32_extension", extension.getFullName());
      assertEquals(1, extension.getNumber());
      assertEquals(TestAllExtensions.getDescriptor(), extension.getContainingType());
      assertEquals(UnittestProto.getDescriptor(), extension.getFile());
      assertEquals(FieldDescriptor.Type.INT32, extension.getType());
      assertEquals(FieldDescriptor.JavaType.INT, extension.getJavaType());
      assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(), extension.getOptions());
      assertTrue(extension.isExtension());
      assertEquals(null, extension.getExtensionScope());
      assertEquals("optional_int32_extension", extension.toProto().getName());
  
      assertEquals("single", nestedExtension.getName());
      assertEquals("protobuf_unittest.TestRequired.single", nestedExtension.getFullName());
      assertEquals(TestRequired.getDescriptor(), nestedExtension.getExtensionScope());
    }
  
    public void testFieldDescriptorLabel() throws Exception {
      FieldDescriptor requiredField = TestRequired.getDescriptor().findFieldByName("a");
      FieldDescriptor optionalField = TestAllTypes.getDescriptor().findFieldByName("optional_int32");
      FieldDescriptor repeatedField = TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
  
      assertTrue(requiredField.isRequired());
      assertFalse(requiredField.isRepeated());
      assertFalse(optionalField.isRequired());
      assertFalse(optionalField.isRepeated());
      assertFalse(repeatedField.isRequired());
      assertTrue(repeatedField.isRepeated());
    }
  
    public void testFieldDescriptorJsonName() throws Exception {
      FieldDescriptor requiredField = TestRequired.getDescriptor().findFieldByName("a");
      FieldDescriptor optionalField = TestAllTypes.getDescriptor().findFieldByName("optional_int32");
      FieldDescriptor repeatedField = TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
      assertEquals("a", requiredField.getJsonName());
      assertEquals("optionalInt32", optionalField.getJsonName());
      assertEquals("repeatedInt32", repeatedField.getJsonName());
    }
  
    public void testFieldDescriptorDefault() throws Exception {
      Descriptor d = TestAllTypes.getDescriptor();
      assertFalse(d.findFieldByName("optional_int32").hasDefaultValue());
      assertEquals(0, d.findFieldByName("optional_int32").getDefaultValue());
      assertTrue(d.findFieldByName("default_int32").hasDefaultValue());
      assertEquals(41, d.findFieldByName("default_int32").getDefaultValue());
  
      d = TestExtremeDefaultValues.getDescriptor();
      assertEquals(
          ByteString.copyFrom("\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes(Internal.ISO_8859_1)),
          d.findFieldByName("escaped_bytes").getDefaultValue());
      assertEquals(-1, d.findFieldByName("large_uint32").getDefaultValue());
      assertEquals(-1L, d.findFieldByName("large_uint64").getDefaultValue());
    }
  
    public void testEnumDescriptor() throws Exception {
      EnumDescriptor enumType = ForeignEnum.getDescriptor();
      EnumDescriptor nestedType = TestAllTypes.NestedEnum.getDescriptor();
  
      assertEquals("ForeignEnum", enumType.getName());
      assertEquals("protobuf_unittest.ForeignEnum", enumType.getFullName());
      assertEquals(UnittestProto.getDescriptor(), enumType.getFile());
      assertNull(enumType.getContainingType());
      assertEquals(DescriptorProtos.EnumOptions.getDefaultInstance(), enumType.getOptions());
  
      assertEquals("NestedEnum", nestedType.getName());
      assertEquals("protobuf_unittest.TestAllTypes.NestedEnum", nestedType.getFullName());
      assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
      assertEquals(TestAllTypes.getDescriptor(), nestedType.getContainingType());
  
      EnumValueDescriptor value = ForeignEnum.FOREIGN_FOO.getValueDescriptor();
      assertEquals(value, enumType.getValues().get(0));
      assertEquals("FOREIGN_FOO", value.getName());
      assertEquals("FOREIGN_FOO", value.toString());
      assertEquals(4, value.getNumber());
      assertEquals(value, enumType.findValueByName("FOREIGN_FOO"));
      assertEquals(value, enumType.findValueByNumber(4));
      assertNull(enumType.findValueByName("NO_SUCH_VALUE"));
      for (int i = 0; i < enumType.getValues().size(); i++) {
        assertEquals(i, enumType.getValues().get(i).getIndex());
      }
    }
  
    public void testServiceDescriptor() throws Exception {
      ServiceDescriptor service = TestService.getDescriptor();
  
      assertEquals("TestService", service.getName());
      assertEquals("protobuf_unittest.TestService", service.getFullName());
      assertEquals(UnittestProto.getDescriptor(), service.getFile());
  
  
      MethodDescriptor fooMethod = service.getMethods().get(0);
      assertEquals("Foo", fooMethod.getName());
      assertEquals(UnittestProto.FooRequest.getDescriptor(), fooMethod.getInputType());
      assertEquals(UnittestProto.FooResponse.getDescriptor(), fooMethod.getOutputType());
      assertEquals(fooMethod, service.findMethodByName("Foo"));
  
      MethodDescriptor barMethod = service.getMethods().get(1);
      assertEquals("Bar", barMethod.getName());
      assertEquals(UnittestProto.BarRequest.getDescriptor(), barMethod.getInputType());
      assertEquals(UnittestProto.BarResponse.getDescriptor(), barMethod.getOutputType());
      assertEquals(barMethod, service.findMethodByName("Bar"));
  
      assertNull(service.findMethodByName("NoSuchMethod"));
  
      for (int i = 0; i < service.getMethods().size(); i++) {
        assertEquals(i, service.getMethods().get(i).getIndex());
      }
    }
  
  
    public void testCustomOptions() throws Exception {
      // Get the descriptor indirectly from a dependent proto class. This is to
      // ensure that when a proto class is loaded, custom options defined in its
      // dependencies are also properly initialized.
      Descriptor descriptor =
          TestCustomOptions.TestMessageWithCustomOptionsContainer.getDescriptor()
              .findFieldByName("field")
              .getMessageType();
  
      assertTrue(descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1));
      assertEquals(
          Integer.valueOf(-56),
          descriptor.getOptions().getExtension(UnittestCustomOptions.messageOpt1));
  
      FieldDescriptor field = descriptor.findFieldByName("field1");
      assertNotNull(field);
  
      assertTrue(field.getOptions().hasExtension(UnittestCustomOptions.fieldOpt1));
      assertEquals(
          Long.valueOf(8765432109L),
          field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1));
  
      OneofDescriptor oneof = descriptor.getOneofs().get(0);
      assertNotNull(oneof);
  
      assertTrue(oneof.getOptions().hasExtension(UnittestCustomOptions.oneofOpt1));
      assertEquals(
          Integer.valueOf(-99), oneof.getOptions().getExtension(UnittestCustomOptions.oneofOpt1));
  
      EnumDescriptor enumType =
          UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor();
  
      assertTrue(enumType.getOptions().hasExtension(UnittestCustomOptions.enumOpt1));
      assertEquals(
          Integer.valueOf(-789), enumType.getOptions().getExtension(UnittestCustomOptions.enumOpt1));
  
      ServiceDescriptor service = UnittestCustomOptions.TestServiceWithCustomOptions.getDescriptor();
  
      assertTrue(service.getOptions().hasExtension(UnittestCustomOptions.serviceOpt1));
      assertEquals(
          Long.valueOf(-9876543210L),
          service.getOptions().getExtension(UnittestCustomOptions.serviceOpt1));
  
      MethodDescriptor method = service.findMethodByName("Foo");
      assertNotNull(method);
  
      assertTrue(method.getOptions().hasExtension(UnittestCustomOptions.methodOpt1));
      assertEquals(
          UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2,
          method.getOptions().getExtension(UnittestCustomOptions.methodOpt1));
    }
  
    /** Test that the FieldDescriptor.Type enum is the same as the WireFormat.FieldType enum. */
    public void testFieldTypeTablesMatch() throws Exception {
      FieldDescriptor.Type[] values1 = FieldDescriptor.Type.values();
      WireFormat.FieldType[] values2 = WireFormat.FieldType.values();
  
      assertEquals(values1.length, values2.length);
  
      for (int i = 0; i < values1.length; i++) {
        assertEquals(values1[i].toString(), values2[i].toString());
      }
    }
  
    /** Test that the FieldDescriptor.JavaType enum is the same as the WireFormat.JavaType enum. */
    public void testJavaTypeTablesMatch() throws Exception {
      FieldDescriptor.JavaType[] values1 = FieldDescriptor.JavaType.values();
      WireFormat.JavaType[] values2 = WireFormat.JavaType.values();
  
      assertEquals(values1.length, values2.length);
  
      for (int i = 0; i < values1.length; i++) {
        assertEquals(values1[i].toString(), values2[i].toString());
      }
    }
  
    public void testEnormousDescriptor() throws Exception {
      // The descriptor for this file is larger than 64k, yet it did not cause
      // a compiler error due to an over-long string literal.
      assertTrue(UnittestEnormousDescriptor.getDescriptor().toProto().getSerializedSize() > 65536);
    }
  
    /** Tests that the DescriptorValidationException works as intended. */
    public void testDescriptorValidatorException() throws Exception {
      FileDescriptorProto fileDescriptorProto =
          FileDescriptorProto.newBuilder()
              .setName("foo.proto")
              .addMessageType(
                  DescriptorProto.newBuilder()
                      .setName("Foo")
                      .addField(
                          FieldDescriptorProto.newBuilder()
                              .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
                              .setType(FieldDescriptorProto.Type.TYPE_INT32)
                              .setName("foo")
                              .setNumber(1)
                              .setDefaultValue("invalid")
                              .build())
                      .build())
              .build();
      try {
        Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]);
        fail("DescriptorValidationException expected");
      } catch (DescriptorValidationException e) {
        // Expected; check that the error message contains some useful hints
        assertTrue(e.getMessage().indexOf("foo") != -1);
        assertTrue(e.getMessage().indexOf("Foo") != -1);
        assertTrue(e.getMessage().indexOf("invalid") != -1);
        assertTrue(e.getCause() instanceof NumberFormatException);
        assertTrue(e.getCause().getMessage().indexOf("invalid") != -1);
      }
    }
  
    /**
     * Tests the translate/crosslink for an example where a message field's name and type name are the
     * same.
     */
    public void testDescriptorComplexCrosslink() throws Exception {
      FileDescriptorProto fileDescriptorProto =
          FileDescriptorProto.newBuilder()
              .setName("foo.proto")
              .addMessageType(
                  DescriptorProto.newBuilder()
                      .setName("Foo")
                      .addField(
                          FieldDescriptorProto.newBuilder()
                              .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
                              .setType(FieldDescriptorProto.Type.TYPE_INT32)
                              .setName("foo")
                              .setNumber(1)
                              .build())
                      .build())
              .addMessageType(
                  DescriptorProto.newBuilder()
                      .setName("Bar")
                      .addField(
                          FieldDescriptorProto.newBuilder()
                              .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
                              .setTypeName("Foo")
                              .setName("Foo")
                              .setNumber(1)
                              .build())
                      .build())
              .build();
      // translate and crosslink
      FileDescriptor file =
          Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]);
      // verify resulting descriptors
      assertNotNull(file);
      List<Descriptor> msglist = file.getMessageTypes();
      assertNotNull(msglist);
      assertTrue(msglist.size() == 2);
      boolean barFound = false;
      for (Descriptor desc : msglist) {
        if (desc.getName().equals("Bar")) {
          barFound = true;
          assertNotNull(desc.getFields());
          List<FieldDescriptor> fieldlist = desc.getFields();
          assertNotNull(fieldlist);
          assertTrue(fieldlist.size() == 1);
          assertTrue(fieldlist.get(0).getType() == FieldDescriptor.Type.MESSAGE);
          assertTrue(fieldlist.get(0).getMessageType().getName().equals("Foo"));
        }
      }
      assertTrue(barFound);
    }
  
    public void testDependencyOrder() throws Exception {
      FileDescriptorProto fooProto = FileDescriptorProto.newBuilder().setName("foo.proto").build();
      FileDescriptorProto barProto =
          FileDescriptorProto.newBuilder().setName("bar.proto").addDependency("foo.proto").build();
      FileDescriptorProto bazProto =
          FileDescriptorProto.newBuilder()
              .setName("baz.proto")
              .addDependency("foo.proto")
              .addDependency("bar.proto")
              .addPublicDependency(0)
              .addPublicDependency(1)
              .build();
      FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
      FileDescriptor barFile =
          Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[] {fooFile});
  
      // Items in the FileDescriptor array can be in any order.
      Descriptors.FileDescriptor.buildFrom(bazProto, new FileDescriptor[] {fooFile, barFile});
      Descriptors.FileDescriptor.buildFrom(bazProto, new FileDescriptor[] {barFile, fooFile});
    }
  
    public void testInvalidPublicDependency() throws Exception {
      FileDescriptorProto fooProto = FileDescriptorProto.newBuilder().setName("foo.proto").build();
      FileDescriptorProto barProto =
          FileDescriptorProto.newBuilder()
              .setName("boo.proto")
              .addDependency("foo.proto")
              .addPublicDependency(1) // Error, should be 0.
              .build();
      FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
      try {
        Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[] {fooFile});
        fail("DescriptorValidationException expected");
      } catch (DescriptorValidationException e) {
        assertTrue(e.getMessage().indexOf("Invalid public dependency index.") != -1);
      }
    }
  
    public void testUnknownFieldsDenied() throws Exception {
      FileDescriptorProto fooProto =
          FileDescriptorProto.newBuilder()
              .setName("foo.proto")
              .addMessageType(
                  DescriptorProto.newBuilder()
                      .setName("Foo")
                      .addField(
                          FieldDescriptorProto.newBuilder()
                              .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
                              .setTypeName("Bar")
                              .setName("bar")
                              .setNumber(1)))
              .build();
  
      try {
        Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
        fail("DescriptorValidationException expected");
      } catch (DescriptorValidationException e) {
        assertTrue(e.getMessage().indexOf("Bar") != -1);
        assertTrue(e.getMessage().indexOf("is not defined") != -1);
      }
    }
  
    public void testUnknownFieldsAllowed() throws Exception {
      FileDescriptorProto fooProto =
          FileDescriptorProto.newBuilder()
              .setName("foo.proto")
              .addDependency("bar.proto")
              .addMessageType(
                  DescriptorProto.newBuilder()
                      .setName("Foo")
                      .addField(
                          FieldDescriptorProto.newBuilder()
                              .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
                              .setTypeName("Bar")
                              .setName("bar")
                              .setNumber(1)))
              .build();
      Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0], true);
    }
  
    public void testHiddenDependency() throws Exception {
      FileDescriptorProto barProto =
          FileDescriptorProto.newBuilder()
              .setName("bar.proto")
              .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
              .build();
      FileDescriptorProto forwardProto =
          FileDescriptorProto.newBuilder()
              .setName("forward.proto")
              .addDependency("bar.proto")
              .build();
      FileDescriptorProto fooProto =
          FileDescriptorProto.newBuilder()
              .setName("foo.proto")
              .addDependency("forward.proto")
              .addMessageType(
                  DescriptorProto.newBuilder()
                      .setName("Foo")
                      .addField(
                          FieldDescriptorProto.newBuilder()
                              .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
                              .setTypeName("Bar")
                              .setName("bar")
                              .setNumber(1)))
              .build();
      FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[0]);
      FileDescriptor forwardFile =
          Descriptors.FileDescriptor.buildFrom(forwardProto, new FileDescriptor[] {barFile});
  
      try {
        Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[] {forwardFile});
        fail("DescriptorValidationException expected");
      } catch (DescriptorValidationException e) {
        assertTrue(e.getMessage().indexOf("Bar") != -1);
        assertTrue(e.getMessage().indexOf("is not defined") != -1);
      }
    }
  
    public void testPublicDependency() throws Exception {
      FileDescriptorProto barProto =
          FileDescriptorProto.newBuilder()
              .setName("bar.proto")
              .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
              .build();
      FileDescriptorProto forwardProto =
          FileDescriptorProto.newBuilder()
              .setName("forward.proto")
              .addDependency("bar.proto")
              .addPublicDependency(0)
              .build();
      FileDescriptorProto fooProto =
          FileDescriptorProto.newBuilder()
              .setName("foo.proto")
              .addDependency("forward.proto")
              .addMessageType(
                  DescriptorProto.newBuilder()
                      .setName("Foo")
                      .addField(
                          FieldDescriptorProto.newBuilder()
                              .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
                              .setTypeName("Bar")
                              .setName("bar")
                              .setNumber(1)))
              .build();
      FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[0]);
      FileDescriptor forwardFile =
          Descriptors.FileDescriptor.buildFrom(forwardProto, new FileDescriptor[] {barFile});
      Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[] {forwardFile});
    }
  
    /** Tests the translate/crosslink for an example with a more complex namespace referencing. */
    public void testComplexNamespacePublicDependency() throws Exception {
      FileDescriptorProto fooProto =
          FileDescriptorProto.newBuilder()
              .setName("bar.proto")
              .setPackage("a.b.c.d.bar.shared")
              .addEnumType(
                  EnumDescriptorProto.newBuilder()
                      .setName("MyEnum")
                      .addValue(EnumValueDescriptorProto.newBuilder().setName("BLAH").setNumber(1)))
              .build();
      FileDescriptorProto barProto =
          FileDescriptorProto.newBuilder()
              .setName("foo.proto")
              .addDependency("bar.proto")
              .setPackage("a.b.c.d.foo.shared")
              .addMessageType(
                  DescriptorProto.newBuilder()
                      .setName("MyMessage")
                      .addField(
                          FieldDescriptorProto.newBuilder()
                              .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
                              .setTypeName("bar.shared.MyEnum")
                              .setName("MyField")
                              .setNumber(1)))
              .build();
      // translate and crosslink
      FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
      FileDescriptor barFile =
          Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[] {fooFile});
      // verify resulting descriptors
      assertNotNull(barFile);
      List<Descriptor> msglist = barFile.getMessageTypes();
      assertNotNull(msglist);
      assertTrue(msglist.size() == 1);
      Descriptor desc = msglist.get(0);
      if (desc.getName().equals("MyMessage")) {
        assertNotNull(desc.getFields());
        List<FieldDescriptor> fieldlist = desc.getFields();
        assertNotNull(fieldlist);
        assertTrue(fieldlist.size() == 1);
        FieldDescriptor field = fieldlist.get(0);
        assertTrue(field.getType() == FieldDescriptor.Type.ENUM);
        assertTrue(field.getEnumType().getName().equals("MyEnum"));
        assertTrue(field.getEnumType().getFile().getName().equals("bar.proto"));
        assertTrue(field.getEnumType().getFile().getPackage().equals("a.b.c.d.bar.shared"));
      }
    }
  
    public void testOneofDescriptor() throws Exception {
      Descriptor messageType = TestAllTypes.getDescriptor();
      FieldDescriptor field = messageType.findFieldByName("oneof_nested_message");
      OneofDescriptor oneofDescriptor = field.getContainingOneof();
      assertNotNull(oneofDescriptor);
      assertSame(oneofDescriptor, messageType.getOneofs().get(0));
      assertEquals("oneof_field", oneofDescriptor.getName());
  
      assertEquals(4, oneofDescriptor.getFieldCount());
      assertSame(oneofDescriptor.getField(1), field);
  
      assertEquals(4, oneofDescriptor.getFields().size());
      assertEquals(oneofDescriptor.getFields().get(1), field);
    }
  
    public void testMessageDescriptorExtensions() throws Exception {
      assertFalse(TestAllTypes.getDescriptor().isExtendable());
      assertTrue(TestAllExtensions.getDescriptor().isExtendable());
      assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtendable());
  
      assertFalse(TestAllTypes.getDescriptor().isExtensionNumber(3));
      assertTrue(TestAllExtensions.getDescriptor().isExtensionNumber(3));
      assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(42));
      assertFalse(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(43));
      assertFalse(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4142));
      assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4143));
    }
  
    public void testReservedFields() {
      Descriptor d = TestReservedFields.getDescriptor();
      assertTrue(d.isReservedNumber(2));
      assertFalse(d.isReservedNumber(8));
      assertTrue(d.isReservedNumber(9));
      assertTrue(d.isReservedNumber(10));
      assertTrue(d.isReservedNumber(11));
      assertFalse(d.isReservedNumber(12));
      assertFalse(d.isReservedName("foo"));
      assertTrue(d.isReservedName("bar"));
      assertTrue(d.isReservedName("baz"));
    }
  
    public void testToString() {
      assertEquals(
          "protobuf_unittest.TestAllTypes.optional_uint64",
          UnittestProto.TestAllTypes.getDescriptor()
              .findFieldByNumber(UnittestProto.TestAllTypes.OPTIONAL_UINT64_FIELD_NUMBER)
              .toString());
    }
  
    public void testPackedEnumField() throws Exception {
      FileDescriptorProto fileDescriptorProto =
          FileDescriptorProto.newBuilder()
              .setName("foo.proto")
              .addEnumType(
                  EnumDescriptorProto.newBuilder()
                      .setName("Enum")
                      .addValue(
                          EnumValueDescriptorProto.newBuilder().setName("FOO").setNumber(1).build())
                      .build())
              .addMessageType(
                  DescriptorProto.newBuilder()
                      .setName("Message")
                      .addField(
                          FieldDescriptorProto.newBuilder()
                              .setName("foo")
                              .setTypeName("Enum")
                              .setNumber(1)
                              .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
                              .setOptions(
                                  DescriptorProtos.FieldOptions.newBuilder().setPacked(true).build())
                              .build())
                      .build())
              .build();
      Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]);
    }
  
    public void testFieldJsonName() throws Exception {
      Descriptor d = TestJsonName.getDescriptor();
      assertEquals(6, d.getFields().size());
      assertEquals("fieldName1", d.getFields().get(0).getJsonName());
      assertEquals("fieldName2", d.getFields().get(1).getJsonName());
      assertEquals("FieldName3", d.getFields().get(2).getJsonName());
      assertEquals("FieldName4", d.getFields().get(3).getJsonName());
      assertEquals("FIELDNAME5", d.getFields().get(4).getJsonName());
      assertEquals("@type", d.getFields().get(5).getJsonName());
    }
  
    public void testExtensionRenamesKeywords() {
      assertTrue(NonNestedExtension.if_ instanceof GeneratedMessage.GeneratedExtension);
      assertTrue(
          NestedExtension.MyNestedExtension.default_
              instanceof GeneratedMessage.GeneratedExtension);
  
      NonNestedExtension.MessageToBeExtended msg =
          NonNestedExtension.MessageToBeExtended.newBuilder()
              .setExtension(NonNestedExtension.if_, "!fi")
              .build();
      assertEquals("!fi", msg.getExtension(NonNestedExtension.if_));
  
      msg =
          NonNestedExtension.MessageToBeExtended.newBuilder()
              .setExtension(NestedExtension.MyNestedExtension.default_, 8)
              .build();
      assertEquals(8, msg.getExtension(NestedExtension.MyNestedExtension.default_).intValue());
    }
  }
  