From eb10ebd169593600e57106d6cdc84d6ad226f9a8 Mon Sep 17 00:00:00 2001 From: Sandy Zhang Date: Fri, 23 Feb 2024 14:36:51 -0800 Subject: [PATCH] Fix features inheritance of oneof fields and extensions and fix/move unit tests to actually run. JUnit4 does not support nested tests so these weren't running. Fixes setup problems and test logic. Oneof fields now inherit from their oneof, and top-level extensions inherit from top-level file when parent descriptor is null. PiperOrigin-RevId: 609840087 --- .../java/com/google/protobuf/Descriptors.java | 27 +- .../com/google/protobuf/DescriptorsTest.java | 2164 +++++++++-------- 2 files changed, 1117 insertions(+), 1074 deletions(-) diff --git a/java/core/src/main/java/com/google/protobuf/Descriptors.java b/java/core/src/main/java/com/google/protobuf/Descriptors.java index 831d2eeb450b4..dc85b89268fc4 100644 --- a/java/core/src/main/java/com/google/protobuf/Descriptors.java +++ b/java/core/src/main/java/com/google/protobuf/Descriptors.java @@ -75,7 +75,13 @@ public final class Descriptors { @SuppressWarnings("NonFinalStaticField") private static volatile FeatureSetDefaults javaEditionDefaults = null; - private static FeatureSet getEditionDefaults(Edition edition) { + /** Sets the default feature mappings used during the build. Exposed for tests. */ + static void setTestJavaEditionDefaults(FeatureSetDefaults defaults) { + javaEditionDefaults = defaults; + } + + /** Gets the default feature mappings used during the build. */ + static FeatureSetDefaults getJavaEditionDefaults() { // Force explicit initialization before synchronized block which can trigger initialization in // `JavaFeaturesProto.registerAllExtensions()` and `FeatureSetdefaults.parseFrom()` calls. // Otherwise, this can result in deadlock if another threads holds the static init block's @@ -88,18 +94,22 @@ private static FeatureSet getEditionDefaults(Edition edition) { try { ExtensionRegistry registry = ExtensionRegistry.newInstance(); registry.add(JavaFeaturesProto.java); - javaEditionDefaults = + setTestJavaEditionDefaults( FeatureSetDefaults.parseFrom( JavaEditionDefaults.PROTOBUF_INTERNAL_JAVA_EDITION_DEFAULTS.getBytes( Internal.ISO_8859_1), - registry); + registry)); } catch (Exception e) { throw new AssertionError(e); } } } } + return javaEditionDefaults; + } + static FeatureSet getEditionDefaults(Edition edition) { + FeatureSetDefaults javaEditionDefaults = getJavaEditionDefaults(); if (edition.getNumber() < javaEditionDefaults.getMinimumEdition().getNumber()) { throw new IllegalArgumentException( "Edition " @@ -1116,6 +1126,11 @@ private void resolveAllFeatures() { enumType.resolveAllFeatures(); } + // Oneofs must be resolved before any children oneof fields. + for (OneofDescriptor oneof : oneofs) { + oneof.resolveAllFeatures(); + } + for (FieldDescriptor field : fields) { field.resolveAllFeatures(); } @@ -1123,10 +1138,6 @@ private void resolveAllFeatures() { for (FieldDescriptor extension : extensions) { extension.resolveAllFeatures(); } - - for (OneofDescriptor oneof : oneofs) { - oneof.resolveAllFeatures(); - } } /** Look up and cross-link all field types, etc. */ @@ -1703,6 +1714,7 @@ private FieldDescriptor( extensionScope = parent; } else { extensionScope = null; + this.parent = file; } if (proto.hasOneofIndex()) { @@ -1726,6 +1738,7 @@ private FieldDescriptor( } containingOneof = parent.getOneofs().get(proto.getOneofIndex()); containingOneof.fieldCount++; + this.parent = containingOneof; } else { containingOneof = null; } diff --git a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java index 3f0e22edaf29a..12d411f82b7bc 100644 --- a/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java +++ b/java/core/src/test/java/com/google/protobuf/DescriptorsTest.java @@ -12,9 +12,12 @@ import static org.junit.Assert.assertThrows; import com.google.protobuf.DescriptorProtos.DescriptorProto; +import com.google.protobuf.DescriptorProtos.DescriptorProto.ExtensionRange; import com.google.protobuf.DescriptorProtos.Edition; import com.google.protobuf.DescriptorProtos.EnumDescriptorProto; import com.google.protobuf.DescriptorProtos.EnumValueDescriptorProto; +import com.google.protobuf.DescriptorProtos.FeatureSetDefaults; +import com.google.protobuf.DescriptorProtos.FeatureSetDefaults.FeatureSetEditionDefault; import com.google.protobuf.DescriptorProtos.FieldDescriptorProto; import com.google.protobuf.DescriptorProtos.FileDescriptorProto; import com.google.protobuf.DescriptorProtos.FileOptions; @@ -55,1131 +58,1151 @@ import java.util.List; import org.junit.Before; import org.junit.Test; +import org.junit.experimental.runners.Enclosed; import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; + import protobuf_unittest.NestedExtension; import protobuf_unittest.NonNestedExtension; /** Unit test for {@link Descriptors}. */ -@RunWith(JUnit4.class) +@RunWith(Enclosed.class) public class DescriptorsTest { - // 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 static class GeneralDescriptorsTest { + // 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; - @Test - public void testFieldTypeEnumMapping() throws Exception { - assertThat(FieldDescriptor.Type.values()).hasLength(FieldDescriptorProto.Type.values().length); - for (FieldDescriptor.Type type : FieldDescriptor.Type.values()) { - FieldDescriptorProto.Type protoType = type.toProto(); - assertThat(protoType.name()).isEqualTo("TYPE_" + type.name()); - assertThat(FieldDescriptor.Type.valueOf(protoType)).isEqualTo(type); + @Test + public void testFieldTypeEnumMapping() throws Exception { + assertThat(FieldDescriptor.Type.values()) + .hasLength(FieldDescriptorProto.Type.values().length); + for (FieldDescriptor.Type type : FieldDescriptor.Type.values()) { + FieldDescriptorProto.Type protoType = type.toProto(); + assertThat(protoType.name()).isEqualTo("TYPE_" + type.name()); + assertThat(FieldDescriptor.Type.valueOf(protoType)).isEqualTo(type); + } } - } - @Test - public void testFileDescriptor() throws Exception { - FileDescriptor file = UnittestProto.getDescriptor(); - - assertThat(file.getName()).isEqualTo("google/protobuf/unittest.proto"); - assertThat(file.getPackage()).isEqualTo("protobuf_unittest"); - assertThat(file.getOptions().getJavaOuterClassname()).isEqualTo("UnittestProto"); - assertThat(file.toProto().getName()).isEqualTo("google/protobuf/unittest.proto"); - - assertThat(file.getDependencies()).containsExactly(UnittestImport.getDescriptor()); - - Descriptor messageType = TestAllTypes.getDescriptor(); - assertThat(file.getMessageTypes().get(0)).isEqualTo(messageType); - assertThat(file.findMessageTypeByName("TestAllTypes")).isEqualTo(messageType); - assertThat(file.findMessageTypeByName("NoSuchType")).isNull(); - assertThat(file.findMessageTypeByName("protobuf_unittest.TestAllTypes")).isNull(); - for (int i = 0; i < file.getMessageTypes().size(); i++) { - assertThat(file.getMessageTypes().get(i).getIndex()).isEqualTo(i); - } - - EnumDescriptor enumType = ForeignEnum.getDescriptor(); - assertThat(file.getEnumTypes().get(0)).isEqualTo(enumType); - assertThat(file.findEnumTypeByName("ForeignEnum")).isEqualTo(enumType); - assertThat(file.findEnumTypeByName("NoSuchType")).isNull(); - assertThat(file.findEnumTypeByName("protobuf_unittest.ForeignEnum")).isNull(); - assertThat(UnittestImport.getDescriptor().getEnumTypes()) - .containsExactly(ImportEnum.getDescriptor(), ImportEnumForMap.getDescriptor()) - .inOrder(); - for (int i = 0; i < file.getEnumTypes().size(); i++) { - assertThat(file.getEnumTypes().get(i).getIndex()).isEqualTo(i); - } - - ServiceDescriptor service = TestService.getDescriptor(); - assertThat(file.getServices().get(0)).isEqualTo(service); - assertThat(file.findServiceByName("TestService")).isEqualTo(service); - assertThat(file.findServiceByName("NoSuchType")).isNull(); - assertThat(file.findServiceByName("protobuf_unittest.TestService")).isNull(); - assertThat(UnittestImport.getDescriptor().getServices()).isEqualTo(Collections.emptyList()); - for (int i = 0; i < file.getServices().size(); i++) { - assertThat(file.getServices().get(i).getIndex()).isEqualTo(i); - } - - FieldDescriptor extension = UnittestProto.optionalInt32Extension.getDescriptor(); - assertThat(file.getExtensions().get(0)).isEqualTo(extension); - assertThat(file.findExtensionByName("optional_int32_extension")).isEqualTo(extension); - assertThat(file.findExtensionByName("no_such_ext")).isNull(); - assertThat(file.findExtensionByName("protobuf_unittest.optional_int32_extension")).isNull(); - assertThat(UnittestImport.getDescriptor().getExtensions()).isEqualTo(Collections.emptyList()); - for (int i = 0; i < file.getExtensions().size(); i++) { - assertThat(file.getExtensions().get(i).getIndex()).isEqualTo(i); - } - } + @Test + public void testFileDescriptor() throws Exception { + FileDescriptor file = UnittestProto.getDescriptor(); + + assertThat(file.getName()).isEqualTo("google/protobuf/unittest.proto"); + assertThat(file.getPackage()).isEqualTo("protobuf_unittest"); + assertThat(file.getOptions().getJavaOuterClassname()).isEqualTo("UnittestProto"); + assertThat(file.toProto().getName()).isEqualTo("google/protobuf/unittest.proto"); + + assertThat(file.getDependencies()).containsExactly(UnittestImport.getDescriptor()); + + Descriptor messageType = TestAllTypes.getDescriptor(); + assertThat(file.getMessageTypes().get(0)).isEqualTo(messageType); + assertThat(file.findMessageTypeByName("TestAllTypes")).isEqualTo(messageType); + assertThat(file.findMessageTypeByName("NoSuchType")).isNull(); + assertThat(file.findMessageTypeByName("protobuf_unittest.TestAllTypes")).isNull(); + for (int i = 0; i < file.getMessageTypes().size(); i++) { + assertThat(file.getMessageTypes().get(i).getIndex()).isEqualTo(i); + } - @Test - public void testFileDescriptorGetEdition() throws Exception { - FileDescriptorProto proto2 = FileDescriptorProto.newBuilder().setSyntax("proto2").build(); - FileDescriptor file2 = Descriptors.FileDescriptor.buildFrom(proto2, new FileDescriptor[0]); - assertThat(file2.getEdition()).isEqualTo(Edition.EDITION_PROTO2); - - FileDescriptorProto proto3 = FileDescriptorProto.newBuilder().setSyntax("proto3").build(); - FileDescriptor file3 = Descriptors.FileDescriptor.buildFrom(proto3, new FileDescriptor[0]); - assertThat(file3.getEdition()).isEqualTo(Edition.EDITION_PROTO3); - - FileDescriptorProto protoEdition = - FileDescriptorProto.newBuilder() - .setSyntax("editions") - .setEdition(Edition.EDITION_2023) - .build(); - FileDescriptor fileEdition = - Descriptors.FileDescriptor.buildFrom(protoEdition, new FileDescriptor[0]); - assertThat(fileEdition.getEdition()).isEqualTo(Edition.EDITION_2023); - - FileDescriptorProto protoMissingEdition = - FileDescriptorProto.newBuilder().setSyntax("editions").build(); - IllegalArgumentException exception = - assertThrows( - IllegalArgumentException.class, - () -> Descriptors.FileDescriptor.buildFrom(protoMissingEdition, new FileDescriptor[0])); - assertThat(exception) - .hasMessageThat() - .contains("Edition EDITION_UNKNOWN is lower than the minimum supported edition"); - } + EnumDescriptor enumType = ForeignEnum.getDescriptor(); + assertThat(file.getEnumTypes().get(0)).isEqualTo(enumType); + assertThat(file.findEnumTypeByName("ForeignEnum")).isEqualTo(enumType); + assertThat(file.findEnumTypeByName("NoSuchType")).isNull(); + assertThat(file.findEnumTypeByName("protobuf_unittest.ForeignEnum")).isNull(); + assertThat(UnittestImport.getDescriptor().getEnumTypes()) + .containsExactly(ImportEnum.getDescriptor(), ImportEnumForMap.getDescriptor()) + .inOrder(); + for (int i = 0; i < file.getEnumTypes().size(); i++) { + assertThat(file.getEnumTypes().get(i).getIndex()).isEqualTo(i); + } - @Test - public void testFileDescriptorCopyHeadingTo() throws Exception { - FileDescriptorProto.Builder protoBuilder = - FileDescriptorProto.newBuilder() - .setName("foo.proto") - .setPackage("foo.bar.baz") - .setSyntax("proto2") - .setOptions(FileOptions.newBuilder().setJavaPackage("foo.bar.baz").build()) - // Won't be copied. - .addMessageType(DescriptorProto.newBuilder().setName("Foo").build()); - FileDescriptor file2 = - Descriptors.FileDescriptor.buildFrom(protoBuilder.build(), new FileDescriptor[0]); - FileDescriptorProto.Builder protoBuilder2 = FileDescriptorProto.newBuilder(); - file2.copyHeadingTo(protoBuilder2); - FileDescriptorProto toProto2 = protoBuilder2.build(); - assertThat(toProto2.getName()).isEqualTo("foo.proto"); - assertThat(toProto2.getPackage()).isEqualTo("foo.bar.baz"); - assertThat(toProto2.getSyntax()).isEqualTo("proto2"); - assertThat(toProto2.getOptions().getJavaPackage()).isEqualTo("foo.bar.baz"); - assertThat(toProto2.getMessageTypeList()).isEmpty(); - - protoBuilder.setSyntax("proto3"); - FileDescriptor file3 = - Descriptors.FileDescriptor.buildFrom(protoBuilder.build(), new FileDescriptor[0]); - FileDescriptorProto.Builder protoBuilder3 = FileDescriptorProto.newBuilder(); - file3.copyHeadingTo(protoBuilder3); - FileDescriptorProto toProto3 = protoBuilder3.build(); - assertThat(toProto3.getName()).isEqualTo("foo.proto"); - assertThat(toProto3.getPackage()).isEqualTo("foo.bar.baz"); - assertThat(toProto3.getSyntax()).isEqualTo("proto3"); - assertThat(toProto2.getOptions().getJavaPackage()).isEqualTo("foo.bar.baz"); - assertThat(toProto3.getMessageTypeList()).isEmpty(); - } + ServiceDescriptor service = TestService.getDescriptor(); + assertThat(file.getServices().get(0)).isEqualTo(service); + assertThat(file.findServiceByName("TestService")).isEqualTo(service); + assertThat(file.findServiceByName("NoSuchType")).isNull(); + assertThat(file.findServiceByName("protobuf_unittest.TestService")).isNull(); + assertThat(UnittestImport.getDescriptor().getServices()).isEqualTo(Collections.emptyList()); + for (int i = 0; i < file.getServices().size(); i++) { + assertThat(file.getServices().get(i).getIndex()).isEqualTo(i); + } - @Test - public void testDescriptor() throws Exception { - Descriptor messageType = TestAllTypes.getDescriptor(); - Descriptor nestedType = TestAllTypes.NestedMessage.getDescriptor(); - - assertThat(messageType.getName()).isEqualTo("TestAllTypes"); - assertThat(messageType.getFullName()).isEqualTo("protobuf_unittest.TestAllTypes"); - assertThat(messageType.getFile()).isEqualTo(UnittestProto.getDescriptor()); - assertThat(messageType.getContainingType()).isNull(); - assertThat(messageType.getOptions()) - .isEqualTo(DescriptorProtos.MessageOptions.getDefaultInstance()); - assertThat(messageType.toProto().getName()).isEqualTo("TestAllTypes"); - - assertThat(nestedType.getName()).isEqualTo("NestedMessage"); - assertThat(nestedType.getFullName()).isEqualTo("protobuf_unittest.TestAllTypes.NestedMessage"); - assertThat(nestedType.getFile()).isEqualTo(UnittestProto.getDescriptor()); - assertThat(nestedType.getContainingType()).isEqualTo(messageType); - - FieldDescriptor field = messageType.getFields().get(0); - assertThat(field.getName()).isEqualTo("optional_int32"); - assertThat(messageType.findFieldByName("optional_int32")).isEqualTo(field); - assertThat(messageType.findFieldByName("no_such_field")).isNull(); - assertThat(messageType.findFieldByNumber(1)).isEqualTo(field); - assertThat(messageType.findFieldByNumber(571283)).isNull(); - for (int i = 0; i < messageType.getFields().size(); i++) { - assertThat(messageType.getFields().get(i).getIndex()).isEqualTo(i); - } - - assertThat(messageType.getNestedTypes().get(0)).isEqualTo(nestedType); - assertThat(messageType.findNestedTypeByName("NestedMessage")).isEqualTo(nestedType); - assertThat(messageType.findNestedTypeByName("NoSuchType")).isNull(); - for (int i = 0; i < messageType.getNestedTypes().size(); i++) { - assertThat(messageType.getNestedTypes().get(i).getIndex()).isEqualTo(i); - } - - EnumDescriptor enumType = TestAllTypes.NestedEnum.getDescriptor(); - assertThat(messageType.getEnumTypes().get(0)).isEqualTo(enumType); - assertThat(messageType.findEnumTypeByName("NestedEnum")).isEqualTo(enumType); - assertThat(messageType.findEnumTypeByName("NoSuchType")).isNull(); - for (int i = 0; i < messageType.getEnumTypes().size(); i++) { - assertThat(messageType.getEnumTypes().get(i).getIndex()).isEqualTo(i); + FieldDescriptor extension = UnittestProto.optionalInt32Extension.getDescriptor(); + assertThat(file.getExtensions().get(0)).isEqualTo(extension); + assertThat(file.findExtensionByName("optional_int32_extension")).isEqualTo(extension); + assertThat(file.findExtensionByName("no_such_ext")).isNull(); + assertThat(file.findExtensionByName("protobuf_unittest.optional_int32_extension")).isNull(); + assertThat(UnittestImport.getDescriptor().getExtensions()).isEqualTo(Collections.emptyList()); + for (int i = 0; i < file.getExtensions().size(); i++) { + assertThat(file.getExtensions().get(i).getIndex()).isEqualTo(i); + } } - } - - @Test - 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(); - - assertThat(primitiveField.getName()).isEqualTo("optional_int32"); - assertThat(primitiveField.getFullName()) - .isEqualTo("protobuf_unittest.TestAllTypes.optional_int32"); - assertThat(primitiveField.getNumber()).isEqualTo(1); - assertThat(primitiveField.getContainingType()).isEqualTo(messageType); - assertThat(primitiveField.getFile()).isEqualTo(UnittestProto.getDescriptor()); - assertThat(primitiveField.getType()).isEqualTo(FieldDescriptor.Type.INT32); - assertThat(primitiveField.getJavaType()).isEqualTo(FieldDescriptor.JavaType.INT); - assertThat(primitiveField.getOptions()) - .isEqualTo(DescriptorProtos.FieldOptions.getDefaultInstance()); - assertThat(primitiveField.isExtension()).isFalse(); - assertThat(primitiveField.toProto().getName()).isEqualTo("optional_int32"); - - assertThat(enumField.getName()).isEqualTo("optional_nested_enum"); - assertThat(enumField.getType()).isEqualTo(FieldDescriptor.Type.ENUM); - assertThat(enumField.getJavaType()).isEqualTo(FieldDescriptor.JavaType.ENUM); - assertThat(enumField.getEnumType()).isEqualTo(TestAllTypes.NestedEnum.getDescriptor()); - - assertThat(messageField.getName()).isEqualTo("optional_foreign_message"); - assertThat(messageField.getType()).isEqualTo(FieldDescriptor.Type.MESSAGE); - assertThat(messageField.getJavaType()).isEqualTo(FieldDescriptor.JavaType.MESSAGE); - assertThat(messageField.getMessageType()).isEqualTo(ForeignMessage.getDescriptor()); - - assertThat(cordField.getName()).isEqualTo("optional_cord"); - assertThat(cordField.getType()).isEqualTo(FieldDescriptor.Type.STRING); - assertThat(cordField.getJavaType()).isEqualTo(FieldDescriptor.JavaType.STRING); - assertThat(cordField.getOptions().getCtype()) - .isEqualTo(DescriptorProtos.FieldOptions.CType.CORD); - - assertThat(extension.getName()).isEqualTo("optional_int32_extension"); - assertThat(extension.getFullName()).isEqualTo("protobuf_unittest.optional_int32_extension"); - assertThat(extension.getNumber()).isEqualTo(1); - assertThat(extension.getContainingType()).isEqualTo(TestAllExtensions.getDescriptor()); - assertThat(extension.getFile()).isEqualTo(UnittestProto.getDescriptor()); - assertThat(extension.getType()).isEqualTo(FieldDescriptor.Type.INT32); - assertThat(extension.getJavaType()).isEqualTo(FieldDescriptor.JavaType.INT); - assertThat(extension.getOptions()) - .isEqualTo(DescriptorProtos.FieldOptions.getDefaultInstance()); - assertThat(extension.isExtension()).isTrue(); - assertThat(extension.getExtensionScope()).isNull(); - assertThat(extension.toProto().getName()).isEqualTo("optional_int32_extension"); - - assertThat(nestedExtension.getName()).isEqualTo("single"); - assertThat(nestedExtension.getFullName()).isEqualTo("protobuf_unittest.TestRequired.single"); - assertThat(nestedExtension.getExtensionScope()).isEqualTo(TestRequired.getDescriptor()); - } - @Test - 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"); - - assertThat(requiredField.isRequired()).isTrue(); - assertThat(requiredField.isRepeated()).isFalse(); - assertThat(optionalField.isRequired()).isFalse(); - assertThat(optionalField.isRepeated()).isFalse(); - assertThat(repeatedField.isRequired()).isFalse(); - assertThat(repeatedField.isRepeated()).isTrue(); - } + @Test + public void testFileDescriptorGetEdition() throws Exception { + FileDescriptorProto proto2 = FileDescriptorProto.newBuilder().setSyntax("proto2").build(); + FileDescriptor file2 = Descriptors.FileDescriptor.buildFrom(proto2, new FileDescriptor[0]); + assertThat(file2.getEdition()).isEqualTo(Edition.EDITION_PROTO2); + + FileDescriptorProto proto3 = FileDescriptorProto.newBuilder().setSyntax("proto3").build(); + FileDescriptor file3 = Descriptors.FileDescriptor.buildFrom(proto3, new FileDescriptor[0]); + assertThat(file3.getEdition()).isEqualTo(Edition.EDITION_PROTO3); + + FileDescriptorProto protoEdition = + FileDescriptorProto.newBuilder() + .setSyntax("editions") + .setEdition(Edition.EDITION_2023) + .build(); + FileDescriptor fileEdition = + Descriptors.FileDescriptor.buildFrom(protoEdition, new FileDescriptor[0]); + assertThat(fileEdition.getEdition()).isEqualTo(Edition.EDITION_2023); + + FileDescriptorProto protoMissingEdition = + FileDescriptorProto.newBuilder().setSyntax("editions").build(); + IllegalArgumentException exception = + assertThrows( + IllegalArgumentException.class, + () -> + Descriptors.FileDescriptor.buildFrom(protoMissingEdition, new FileDescriptor[0])); + assertThat(exception) + .hasMessageThat() + .contains("Edition EDITION_UNKNOWN is lower than the minimum supported edition"); + } - @Test - 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"); - assertThat(requiredField.getJsonName()).isEqualTo("a"); - assertThat(optionalField.getJsonName()).isEqualTo("optionalInt32"); - assertThat(repeatedField.getJsonName()).isEqualTo("repeatedInt32"); - } + @Test + public void testFileDescriptorCopyHeadingTo() throws Exception { + FileDescriptorProto.Builder protoBuilder = + FileDescriptorProto.newBuilder() + .setName("foo.proto") + .setPackage("foo.bar.baz") + .setSyntax("proto2") + .setOptions(FileOptions.newBuilder().setJavaPackage("foo.bar.baz").build()) + // Won't be copied. + .addMessageType(DescriptorProto.newBuilder().setName("Foo").build()); + FileDescriptor file2 = + Descriptors.FileDescriptor.buildFrom(protoBuilder.build(), new FileDescriptor[0]); + FileDescriptorProto.Builder protoBuilder2 = FileDescriptorProto.newBuilder(); + file2.copyHeadingTo(protoBuilder2); + FileDescriptorProto toProto2 = protoBuilder2.build(); + assertThat(toProto2.getName()).isEqualTo("foo.proto"); + assertThat(toProto2.getPackage()).isEqualTo("foo.bar.baz"); + assertThat(toProto2.getSyntax()).isEqualTo("proto2"); + assertThat(toProto2.getOptions().getJavaPackage()).isEqualTo("foo.bar.baz"); + assertThat(toProto2.getMessageTypeList()).isEmpty(); + + protoBuilder.setSyntax("proto3"); + FileDescriptor file3 = + Descriptors.FileDescriptor.buildFrom(protoBuilder.build(), new FileDescriptor[0]); + FileDescriptorProto.Builder protoBuilder3 = FileDescriptorProto.newBuilder(); + file3.copyHeadingTo(protoBuilder3); + FileDescriptorProto toProto3 = protoBuilder3.build(); + assertThat(toProto3.getName()).isEqualTo("foo.proto"); + assertThat(toProto3.getPackage()).isEqualTo("foo.bar.baz"); + assertThat(toProto3.getSyntax()).isEqualTo("proto3"); + assertThat(toProto2.getOptions().getJavaPackage()).isEqualTo("foo.bar.baz"); + assertThat(toProto3.getMessageTypeList()).isEmpty(); + } - @Test - public void testFieldDescriptorDefault() throws Exception { - Descriptor d = TestAllTypes.getDescriptor(); - assertThat(d.findFieldByName("optional_int32").hasDefaultValue()).isFalse(); - assertThat(d.findFieldByName("optional_int32").getDefaultValue()).isEqualTo(0); - assertThat(d.findFieldByName("default_int32").hasDefaultValue()).isTrue(); - assertThat(d.findFieldByName("default_int32").getDefaultValue()).isEqualTo(41); - - d = TestExtremeDefaultValues.getDescriptor(); - assertThat(d.findFieldByName("escaped_bytes").getDefaultValue()) - .isEqualTo( - ByteString.copyFrom( - "\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes(Internal.ISO_8859_1))); - assertThat(d.findFieldByName("large_uint32").getDefaultValue()).isEqualTo(-1); - assertThat(d.findFieldByName("large_uint64").getDefaultValue()).isEqualTo(-1L); - } + @Test + public void testDescriptor() throws Exception { + Descriptor messageType = TestAllTypes.getDescriptor(); + Descriptor nestedType = TestAllTypes.NestedMessage.getDescriptor(); + + assertThat(messageType.getName()).isEqualTo("TestAllTypes"); + assertThat(messageType.getFullName()).isEqualTo("protobuf_unittest.TestAllTypes"); + assertThat(messageType.getFile()).isEqualTo(UnittestProto.getDescriptor()); + assertThat(messageType.getContainingType()).isNull(); + assertThat(messageType.getOptions()) + .isEqualTo(DescriptorProtos.MessageOptions.getDefaultInstance()); + assertThat(messageType.toProto().getName()).isEqualTo("TestAllTypes"); + + assertThat(nestedType.getName()).isEqualTo("NestedMessage"); + assertThat(nestedType.getFullName()).isEqualTo("protobuf_unittest.TestAllTypes.NestedMessage"); + assertThat(nestedType.getFile()).isEqualTo(UnittestProto.getDescriptor()); + assertThat(nestedType.getContainingType()).isEqualTo(messageType); + + FieldDescriptor field = messageType.getFields().get(0); + assertThat(field.getName()).isEqualTo("optional_int32"); + assertThat(messageType.findFieldByName("optional_int32")).isEqualTo(field); + assertThat(messageType.findFieldByName("no_such_field")).isNull(); + assertThat(messageType.findFieldByNumber(1)).isEqualTo(field); + assertThat(messageType.findFieldByNumber(571283)).isNull(); + for (int i = 0; i < messageType.getFields().size(); i++) { + assertThat(messageType.getFields().get(i).getIndex()).isEqualTo(i); + } - @Test - public void testFieldDescriptorLegacyEnumFieldTreatedAsClosed() throws Exception { - // Make an open enum definition. - FileDescriptorProto openEnumFile = - FileDescriptorProto.newBuilder() - .setName("open_enum.proto") - .setSyntax("proto3") - .addEnumType( - EnumDescriptorProto.newBuilder() - .setName("TestEnumOpen") - .addValue( - EnumValueDescriptorProto.newBuilder() - .setName("TestEnumOpen_VALUE0") - .setNumber(0) - .build()) - .build()) - .build(); - FileDescriptor openFileDescriptor = - Descriptors.FileDescriptor.buildFrom(openEnumFile, new FileDescriptor[0]); - EnumDescriptor openEnum = openFileDescriptor.getEnumTypes().get(0); - assertThat(openEnum.isClosed()).isFalse(); - - // Create a message that treats enum fields as closed. - FileDescriptorProto closedEnumFile = - FileDescriptorProto.newBuilder() - .setName("closed_enum_field.proto") - .addDependency("open_enum.proto") - .setSyntax("proto2") - .addEnumType( - EnumDescriptorProto.newBuilder() - .setName("TestEnum") - .addValue( - EnumValueDescriptorProto.newBuilder() - .setName("TestEnum_VALUE0") - .setNumber(0) - .build()) - .build()) - .addMessageType( - DescriptorProto.newBuilder() - .setName("TestClosedEnumField") - .addField( - FieldDescriptorProto.newBuilder() - .setName("int_field") - .setNumber(1) - .setType(FieldDescriptorProto.Type.TYPE_INT32) - .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) - .build()) - .addField( - FieldDescriptorProto.newBuilder() - .setName("open_enum") - .setNumber(2) - .setType(FieldDescriptorProto.Type.TYPE_ENUM) - .setTypeName("TestEnumOpen") - .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) - .build()) - .addField( - FieldDescriptorProto.newBuilder() - .setName("closed_enum") - .setNumber(3) - .setType(FieldDescriptorProto.Type.TYPE_ENUM) - .setTypeName("TestEnum") - .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) - .build()) - .build()) - .build(); - Descriptor closedMessage = - Descriptors.FileDescriptor.buildFrom( - closedEnumFile, new FileDescriptor[] {openFileDescriptor}) - .getMessageTypes() - .get(0); - assertThat(closedMessage.findFieldByName("int_field").legacyEnumFieldTreatedAsClosed()) - .isFalse(); - - assertThat(closedMessage.findFieldByName("closed_enum").legacyEnumFieldTreatedAsClosed()) - .isTrue(); - assertThat(closedMessage.findFieldByName("open_enum").legacyEnumFieldTreatedAsClosed()) - .isTrue(); - } + assertThat(messageType.getNestedTypes().get(0)).isEqualTo(nestedType); + assertThat(messageType.findNestedTypeByName("NestedMessage")).isEqualTo(nestedType); + assertThat(messageType.findNestedTypeByName("NoSuchType")).isNull(); + for (int i = 0; i < messageType.getNestedTypes().size(); i++) { + assertThat(messageType.getNestedTypes().get(i).getIndex()).isEqualTo(i); + } - @Test - public void testFieldDescriptorLegacyEnumFieldTreatedAsOpen() throws Exception { - // Make an open enum definition and message that treats enum fields as open. - FileDescriptorProto openEnumFile = - FileDescriptorProto.newBuilder() - .setName("open_enum.proto") - .setSyntax("proto3") - .addEnumType( - EnumDescriptorProto.newBuilder() - .setName("TestEnumOpen") - .addValue( - EnumValueDescriptorProto.newBuilder() - .setName("TestEnumOpen_VALUE0") - .setNumber(0) - .build()) - .build()) - .addMessageType( - DescriptorProto.newBuilder() - .setName("TestOpenEnumField") - .addField( - FieldDescriptorProto.newBuilder() - .setName("int_field") - .setNumber(1) - .setType(FieldDescriptorProto.Type.TYPE_INT32) - .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) - .build()) - .addField( - FieldDescriptorProto.newBuilder() - .setName("open_enum") - .setNumber(2) - .setType(FieldDescriptorProto.Type.TYPE_ENUM) - .setTypeName("TestEnumOpen") - .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) - .build()) - .build()) - .build(); - FileDescriptor openEnumFileDescriptor = - Descriptors.FileDescriptor.buildFrom(openEnumFile, new FileDescriptor[0]); - Descriptor openMessage = openEnumFileDescriptor.getMessageTypes().get(0); - EnumDescriptor openEnum = openEnumFileDescriptor.findEnumTypeByName("TestEnumOpen"); - assertThat(openEnum.isClosed()).isFalse(); - assertThat(openMessage.findFieldByName("int_field").legacyEnumFieldTreatedAsClosed()).isFalse(); - assertThat(openMessage.findFieldByName("open_enum").legacyEnumFieldTreatedAsClosed()).isFalse(); - } + EnumDescriptor enumType = TestAllTypes.NestedEnum.getDescriptor(); + assertThat(messageType.getEnumTypes().get(0)).isEqualTo(enumType); + assertThat(messageType.findEnumTypeByName("NestedEnum")).isEqualTo(enumType); + assertThat(messageType.findEnumTypeByName("NoSuchType")).isNull(); + for (int i = 0; i < messageType.getEnumTypes().size(); i++) { + assertThat(messageType.getEnumTypes().get(i).getIndex()).isEqualTo(i); + } + } - @Test - public void testEnumDescriptor() throws Exception { - EnumDescriptor enumType = ForeignEnum.getDescriptor(); - EnumDescriptor nestedType = TestAllTypes.NestedEnum.getDescriptor(); - - assertThat(enumType.getName()).isEqualTo("ForeignEnum"); - assertThat(enumType.getFullName()).isEqualTo("protobuf_unittest.ForeignEnum"); - assertThat(enumType.getFile()).isEqualTo(UnittestProto.getDescriptor()); - assertThat(enumType.isClosed()).isTrue(); - assertThat(enumType.getContainingType()).isNull(); - assertThat(enumType.getOptions()).isEqualTo(DescriptorProtos.EnumOptions.getDefaultInstance()); - - assertThat(nestedType.getName()).isEqualTo("NestedEnum"); - assertThat(nestedType.getFullName()).isEqualTo("protobuf_unittest.TestAllTypes.NestedEnum"); - assertThat(nestedType.getFile()).isEqualTo(UnittestProto.getDescriptor()); - assertThat(nestedType.getContainingType()).isEqualTo(TestAllTypes.getDescriptor()); - - EnumValueDescriptor value = ForeignEnum.FOREIGN_FOO.getValueDescriptor(); - assertThat(enumType.getValues().get(0)).isEqualTo(value); - assertThat(value.getName()).isEqualTo("FOREIGN_FOO"); - assertThat(value.toString()).isEqualTo("FOREIGN_FOO"); - assertThat(value.getNumber()).isEqualTo(4); - assertThat(enumType.findValueByName("FOREIGN_FOO")).isEqualTo(value); - assertThat(enumType.findValueByNumber(4)).isEqualTo(value); - assertThat(enumType.findValueByName("NO_SUCH_VALUE")).isNull(); - for (int i = 0; i < enumType.getValues().size(); i++) { - assertThat(enumType.getValues().get(i).getIndex()).isEqualTo(i); + @Test + 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(); + + assertThat(primitiveField.getName()).isEqualTo("optional_int32"); + assertThat(primitiveField.getFullName()) + .isEqualTo("protobuf_unittest.TestAllTypes.optional_int32"); + assertThat(primitiveField.getNumber()).isEqualTo(1); + assertThat(primitiveField.getContainingType()).isEqualTo(messageType); + assertThat(primitiveField.getFile()).isEqualTo(UnittestProto.getDescriptor()); + assertThat(primitiveField.getType()).isEqualTo(FieldDescriptor.Type.INT32); + assertThat(primitiveField.getJavaType()).isEqualTo(FieldDescriptor.JavaType.INT); + assertThat(primitiveField.getOptions()) + .isEqualTo(DescriptorProtos.FieldOptions.getDefaultInstance()); + assertThat(primitiveField.isExtension()).isFalse(); + assertThat(primitiveField.toProto().getName()).isEqualTo("optional_int32"); + + assertThat(enumField.getName()).isEqualTo("optional_nested_enum"); + assertThat(enumField.getType()).isEqualTo(FieldDescriptor.Type.ENUM); + assertThat(enumField.getJavaType()).isEqualTo(FieldDescriptor.JavaType.ENUM); + assertThat(enumField.getEnumType()).isEqualTo(TestAllTypes.NestedEnum.getDescriptor()); + + assertThat(messageField.getName()).isEqualTo("optional_foreign_message"); + assertThat(messageField.getType()).isEqualTo(FieldDescriptor.Type.MESSAGE); + assertThat(messageField.getJavaType()).isEqualTo(FieldDescriptor.JavaType.MESSAGE); + assertThat(messageField.getMessageType()).isEqualTo(ForeignMessage.getDescriptor()); + + assertThat(cordField.getName()).isEqualTo("optional_cord"); + assertThat(cordField.getType()).isEqualTo(FieldDescriptor.Type.STRING); + assertThat(cordField.getJavaType()).isEqualTo(FieldDescriptor.JavaType.STRING); + assertThat(cordField.getOptions().getCtype()) + .isEqualTo(DescriptorProtos.FieldOptions.CType.CORD); + + assertThat(extension.getName()).isEqualTo("optional_int32_extension"); + assertThat(extension.getFullName()).isEqualTo("protobuf_unittest.optional_int32_extension"); + assertThat(extension.getNumber()).isEqualTo(1); + assertThat(extension.getContainingType()).isEqualTo(TestAllExtensions.getDescriptor()); + assertThat(extension.getFile()).isEqualTo(UnittestProto.getDescriptor()); + assertThat(extension.getType()).isEqualTo(FieldDescriptor.Type.INT32); + assertThat(extension.getJavaType()).isEqualTo(FieldDescriptor.JavaType.INT); + assertThat(extension.getOptions()) + .isEqualTo(DescriptorProtos.FieldOptions.getDefaultInstance()); + assertThat(extension.isExtension()).isTrue(); + assertThat(extension.getExtensionScope()).isNull(); + assertThat(extension.toProto().getName()).isEqualTo("optional_int32_extension"); + + assertThat(nestedExtension.getName()).isEqualTo("single"); + assertThat(nestedExtension.getFullName()).isEqualTo("protobuf_unittest.TestRequired.single"); + assertThat(nestedExtension.getExtensionScope()).isEqualTo(TestRequired.getDescriptor()); } - } - @Test - public void testServiceDescriptor() throws Exception { - ServiceDescriptor service = TestService.getDescriptor(); + @Test + 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"); + + assertThat(requiredField.isRequired()).isTrue(); + assertThat(requiredField.isRepeated()).isFalse(); + assertThat(optionalField.isRequired()).isFalse(); + assertThat(optionalField.isRepeated()).isFalse(); + assertThat(repeatedField.isRequired()).isFalse(); + assertThat(repeatedField.isRepeated()).isTrue(); + } - assertThat(service.getName()).isEqualTo("TestService"); - assertThat(service.getFullName()).isEqualTo("protobuf_unittest.TestService"); - assertThat(service.getFile()).isEqualTo(UnittestProto.getDescriptor()); + @Test + 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"); + assertThat(requiredField.getJsonName()).isEqualTo("a"); + assertThat(optionalField.getJsonName()).isEqualTo("optionalInt32"); + assertThat(repeatedField.getJsonName()).isEqualTo("repeatedInt32"); + } - MethodDescriptor fooMethod = service.getMethods().get(0); - assertThat(fooMethod.getName()).isEqualTo("Foo"); - assertThat(fooMethod.getInputType()).isEqualTo(UnittestProto.FooRequest.getDescriptor()); - assertThat(fooMethod.getOutputType()).isEqualTo(UnittestProto.FooResponse.getDescriptor()); - assertThat(service.findMethodByName("Foo")).isEqualTo(fooMethod); + @Test + public void testFieldDescriptorDefault() throws Exception { + Descriptor d = TestAllTypes.getDescriptor(); + assertThat(d.findFieldByName("optional_int32").hasDefaultValue()).isFalse(); + assertThat(d.findFieldByName("optional_int32").getDefaultValue()).isEqualTo(0); + assertThat(d.findFieldByName("default_int32").hasDefaultValue()).isTrue(); + assertThat(d.findFieldByName("default_int32").getDefaultValue()).isEqualTo(41); + + d = TestExtremeDefaultValues.getDescriptor(); + assertThat(d.findFieldByName("escaped_bytes").getDefaultValue()) + .isEqualTo( + ByteString.copyFrom( + "\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes(Internal.ISO_8859_1))); + assertThat(d.findFieldByName("large_uint32").getDefaultValue()).isEqualTo(-1); + assertThat(d.findFieldByName("large_uint64").getDefaultValue()).isEqualTo(-1L); + } - MethodDescriptor barMethod = service.getMethods().get(1); - assertThat(barMethod.getName()).isEqualTo("Bar"); - assertThat(barMethod.getInputType()).isEqualTo(UnittestProto.BarRequest.getDescriptor()); - assertThat(barMethod.getOutputType()).isEqualTo(UnittestProto.BarResponse.getDescriptor()); - assertThat(service.findMethodByName("Bar")).isEqualTo(barMethod); + @Test + public void testFieldDescriptorLegacyEnumFieldTreatedAsClosed() throws Exception { + // Make an open enum definition. + FileDescriptorProto openEnumFile = + FileDescriptorProto.newBuilder() + .setName("open_enum.proto") + .setSyntax("proto3") + .addEnumType( + EnumDescriptorProto.newBuilder() + .setName("TestEnumOpen") + .addValue( + EnumValueDescriptorProto.newBuilder() + .setName("TestEnumOpen_VALUE0") + .setNumber(0) + .build()) + .build()) + .build(); + FileDescriptor openFileDescriptor = + Descriptors.FileDescriptor.buildFrom(openEnumFile, new FileDescriptor[0]); + EnumDescriptor openEnum = openFileDescriptor.getEnumTypes().get(0); + assertThat(openEnum.isClosed()).isFalse(); + + // Create a message that treats enum fields as closed. + FileDescriptorProto closedEnumFile = + FileDescriptorProto.newBuilder() + .setName("closed_enum_field.proto") + .addDependency("open_enum.proto") + .setSyntax("proto2") + .addEnumType( + EnumDescriptorProto.newBuilder() + .setName("TestEnum") + .addValue( + EnumValueDescriptorProto.newBuilder() + .setName("TestEnum_VALUE0") + .setNumber(0) + .build()) + .build()) + .addMessageType( + DescriptorProto.newBuilder() + .setName("TestClosedEnumField") + .addField( + FieldDescriptorProto.newBuilder() + .setName("int_field") + .setNumber(1) + .setType(FieldDescriptorProto.Type.TYPE_INT32) + .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) + .build()) + .addField( + FieldDescriptorProto.newBuilder() + .setName("open_enum") + .setNumber(2) + .setType(FieldDescriptorProto.Type.TYPE_ENUM) + .setTypeName("TestEnumOpen") + .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) + .build()) + .addField( + FieldDescriptorProto.newBuilder() + .setName("closed_enum") + .setNumber(3) + .setType(FieldDescriptorProto.Type.TYPE_ENUM) + .setTypeName("TestEnum") + .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) + .build()) + .build()) + .build(); + Descriptor closedMessage = + Descriptors.FileDescriptor.buildFrom( + closedEnumFile, new FileDescriptor[] {openFileDescriptor}) + .getMessageTypes() + .get(0); + assertThat(closedMessage.findFieldByName("int_field").legacyEnumFieldTreatedAsClosed()) + .isFalse(); + + assertThat(closedMessage.findFieldByName("closed_enum").legacyEnumFieldTreatedAsClosed()) + .isTrue(); + assertThat(closedMessage.findFieldByName("open_enum").legacyEnumFieldTreatedAsClosed()) + .isTrue(); + } - assertThat(service.findMethodByName("NoSuchMethod")).isNull(); + @Test + public void testFieldDescriptorLegacyEnumFieldTreatedAsOpen() throws Exception { + // Make an open enum definition and message that treats enum fields as open. + FileDescriptorProto openEnumFile = + FileDescriptorProto.newBuilder() + .setName("open_enum.proto") + .setSyntax("proto3") + .addEnumType( + EnumDescriptorProto.newBuilder() + .setName("TestEnumOpen") + .addValue( + EnumValueDescriptorProto.newBuilder() + .setName("TestEnumOpen_VALUE0") + .setNumber(0) + .build()) + .build()) + .addMessageType( + DescriptorProto.newBuilder() + .setName("TestOpenEnumField") + .addField( + FieldDescriptorProto.newBuilder() + .setName("int_field") + .setNumber(1) + .setType(FieldDescriptorProto.Type.TYPE_INT32) + .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) + .build()) + .addField( + FieldDescriptorProto.newBuilder() + .setName("open_enum") + .setNumber(2) + .setType(FieldDescriptorProto.Type.TYPE_ENUM) + .setTypeName("TestEnumOpen") + .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) + .build()) + .build()) + .build(); + FileDescriptor openEnumFileDescriptor = + Descriptors.FileDescriptor.buildFrom(openEnumFile, new FileDescriptor[0]); + Descriptor openMessage = openEnumFileDescriptor.getMessageTypes().get(0); + EnumDescriptor openEnum = openEnumFileDescriptor.findEnumTypeByName("TestEnumOpen"); + assertThat(openEnum.isClosed()).isFalse(); + assertThat(openMessage.findFieldByName("int_field").legacyEnumFieldTreatedAsClosed()) + .isFalse(); + assertThat(openMessage.findFieldByName("open_enum").legacyEnumFieldTreatedAsClosed()) + .isFalse(); + } - for (int i = 0; i < service.getMethods().size(); i++) { - assertThat(service.getMethods().get(i).getIndex()).isEqualTo(i); + @Test + public void testEnumDescriptor() throws Exception { + EnumDescriptor enumType = ForeignEnum.getDescriptor(); + EnumDescriptor nestedType = TestAllTypes.NestedEnum.getDescriptor(); + + assertThat(enumType.getName()).isEqualTo("ForeignEnum"); + assertThat(enumType.getFullName()).isEqualTo("protobuf_unittest.ForeignEnum"); + assertThat(enumType.getFile()).isEqualTo(UnittestProto.getDescriptor()); + assertThat(enumType.isClosed()).isTrue(); + assertThat(enumType.getContainingType()).isNull(); + assertThat(enumType.getOptions()) + .isEqualTo(DescriptorProtos.EnumOptions.getDefaultInstance()); + + assertThat(nestedType.getName()).isEqualTo("NestedEnum"); + assertThat(nestedType.getFullName()).isEqualTo("protobuf_unittest.TestAllTypes.NestedEnum"); + assertThat(nestedType.getFile()).isEqualTo(UnittestProto.getDescriptor()); + assertThat(nestedType.getContainingType()).isEqualTo(TestAllTypes.getDescriptor()); + + EnumValueDescriptor value = ForeignEnum.FOREIGN_FOO.getValueDescriptor(); + assertThat(enumType.getValues().get(0)).isEqualTo(value); + assertThat(value.getName()).isEqualTo("FOREIGN_FOO"); + assertThat(value.toString()).isEqualTo("FOREIGN_FOO"); + assertThat(value.getNumber()).isEqualTo(4); + assertThat(enumType.findValueByName("FOREIGN_FOO")).isEqualTo(value); + assertThat(enumType.findValueByNumber(4)).isEqualTo(value); + assertThat(enumType.findValueByName("NO_SUCH_VALUE")).isNull(); + for (int i = 0; i < enumType.getValues().size(); i++) { + assertThat(enumType.getValues().get(i).getIndex()).isEqualTo(i); + } } - } - @Test - 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(); + @Test + public void testServiceDescriptor() throws Exception { + ServiceDescriptor service = TestService.getDescriptor(); + + assertThat(service.getName()).isEqualTo("TestService"); + assertThat(service.getFullName()).isEqualTo("protobuf_unittest.TestService"); + assertThat(service.getFile()).isEqualTo(UnittestProto.getDescriptor()); + + MethodDescriptor fooMethod = service.getMethods().get(0); + assertThat(fooMethod.getName()).isEqualTo("Foo"); + assertThat(fooMethod.getInputType()).isEqualTo(UnittestProto.FooRequest.getDescriptor()); + assertThat(fooMethod.getOutputType()).isEqualTo(UnittestProto.FooResponse.getDescriptor()); + assertThat(service.findMethodByName("Foo")).isEqualTo(fooMethod); - assertThat(descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1)).isTrue(); - assertThat(descriptor.getOptions().getExtension(UnittestCustomOptions.messageOpt1)) - .isEqualTo(Integer.valueOf(-56)); + MethodDescriptor barMethod = service.getMethods().get(1); + assertThat(barMethod.getName()).isEqualTo("Bar"); + assertThat(barMethod.getInputType()).isEqualTo(UnittestProto.BarRequest.getDescriptor()); + assertThat(barMethod.getOutputType()).isEqualTo(UnittestProto.BarResponse.getDescriptor()); + assertThat(service.findMethodByName("Bar")).isEqualTo(barMethod); - FieldDescriptor field = descriptor.findFieldByName("field1"); - assertThat(field).isNotNull(); + assertThat(service.findMethodByName("NoSuchMethod")).isNull(); - assertThat(field.getOptions().hasExtension(UnittestCustomOptions.fieldOpt1)).isTrue(); - assertThat(field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1)) - .isEqualTo(Long.valueOf(8765432109L)); + for (int i = 0; i < service.getMethods().size(); i++) { + assertThat(service.getMethods().get(i).getIndex()).isEqualTo(i); + } + } - OneofDescriptor oneof = descriptor.getOneofs().get(0); - assertThat(oneof).isNotNull(); + @Test + 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(); - assertThat(oneof.getOptions().hasExtension(UnittestCustomOptions.oneofOpt1)).isTrue(); - assertThat(oneof.getOptions().getExtension(UnittestCustomOptions.oneofOpt1)) - .isEqualTo(Integer.valueOf(-99)); + assertThat(descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1)).isTrue(); + assertThat(descriptor.getOptions().getExtension(UnittestCustomOptions.messageOpt1)) + .isEqualTo(Integer.valueOf(-56)); - EnumDescriptor enumType = - UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor(); + FieldDescriptor field = descriptor.findFieldByName("field1"); + assertThat(field).isNotNull(); - assertThat(enumType.getOptions().hasExtension(UnittestCustomOptions.enumOpt1)).isTrue(); - assertThat(enumType.getOptions().getExtension(UnittestCustomOptions.enumOpt1)) - .isEqualTo(Integer.valueOf(-789)); + assertThat(field.getOptions().hasExtension(UnittestCustomOptions.fieldOpt1)).isTrue(); + assertThat(field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1)) + .isEqualTo(Long.valueOf(8765432109L)); - ServiceDescriptor service = UnittestCustomOptions.TestServiceWithCustomOptions.getDescriptor(); + OneofDescriptor oneof = descriptor.getOneofs().get(0); + assertThat(oneof).isNotNull(); - assertThat(service.getOptions().hasExtension(UnittestCustomOptions.serviceOpt1)).isTrue(); - assertThat(service.getOptions().getExtension(UnittestCustomOptions.serviceOpt1)) - .isEqualTo(Long.valueOf(-9876543210L)); + assertThat(oneof.getOptions().hasExtension(UnittestCustomOptions.oneofOpt1)).isTrue(); + assertThat(oneof.getOptions().getExtension(UnittestCustomOptions.oneofOpt1)) + .isEqualTo(Integer.valueOf(-99)); - MethodDescriptor method = service.findMethodByName("Foo"); - assertThat(method).isNotNull(); + EnumDescriptor enumType = + UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor(); - assertThat(method.getOptions().hasExtension(UnittestCustomOptions.methodOpt1)).isTrue(); - assertThat(method.getOptions().getExtension(UnittestCustomOptions.methodOpt1)) - .isEqualTo(UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2); - } + assertThat(enumType.getOptions().hasExtension(UnittestCustomOptions.enumOpt1)).isTrue(); + assertThat(enumType.getOptions().getExtension(UnittestCustomOptions.enumOpt1)) + .isEqualTo(Integer.valueOf(-789)); - @Test - public void testOptionRetention() throws Exception { - // Verify that options with RETENTION_SOURCE are stripped from the - // generated descriptors. - FileOptions options = UnittestRetention.getDescriptor().getOptions(); - assertThat(options.hasExtension(UnittestRetention.plainOption)).isTrue(); - assertThat(options.hasExtension(UnittestRetention.runtimeRetentionOption)).isTrue(); - assertThat(options.hasExtension(UnittestRetention.sourceRetentionOption)).isFalse(); - } + ServiceDescriptor service = + UnittestCustomOptions.TestServiceWithCustomOptions.getDescriptor(); - /** Test that the FieldDescriptor.Type enum is the same as the WireFormat.FieldType enum. */ - @Test - public void testFieldTypeTablesMatch() throws Exception { - FieldDescriptor.Type[] values1 = FieldDescriptor.Type.values(); - WireFormat.FieldType[] values2 = WireFormat.FieldType.values(); + assertThat(service.getOptions().hasExtension(UnittestCustomOptions.serviceOpt1)).isTrue(); + assertThat(service.getOptions().getExtension(UnittestCustomOptions.serviceOpt1)) + .isEqualTo(Long.valueOf(-9876543210L)); - assertThat(values1).hasLength(values2.length); + MethodDescriptor method = service.findMethodByName("Foo"); + assertThat(method).isNotNull(); - for (int i = 0; i < values1.length; i++) { - assertThat(values1[i].toString()).isEqualTo(values2[i].toString()); + assertThat(method.getOptions().hasExtension(UnittestCustomOptions.methodOpt1)).isTrue(); + assertThat(method.getOptions().getExtension(UnittestCustomOptions.methodOpt1)) + .isEqualTo(UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2); } - } - /** Test that the FieldDescriptor.JavaType enum is the same as the WireFormat.JavaType enum. */ - @Test - public void testJavaTypeTablesMatch() throws Exception { - FieldDescriptor.JavaType[] values1 = FieldDescriptor.JavaType.values(); - WireFormat.JavaType[] values2 = WireFormat.JavaType.values(); + @Test + public void testOptionRetention() throws Exception { + // Verify that options with RETENTION_SOURCE are stripped from the + // generated descriptors. + FileOptions options = UnittestRetention.getDescriptor().getOptions(); + assertThat(options.hasExtension(UnittestRetention.plainOption)).isTrue(); + assertThat(options.hasExtension(UnittestRetention.runtimeRetentionOption)).isTrue(); + assertThat(options.hasExtension(UnittestRetention.sourceRetentionOption)).isFalse(); + } + + /** Test that the FieldDescriptor.Type enum is the same as the WireFormat.FieldType enum. */ + @Test + public void testFieldTypeTablesMatch() throws Exception { + FieldDescriptor.Type[] values1 = FieldDescriptor.Type.values(); + WireFormat.FieldType[] values2 = WireFormat.FieldType.values(); - assertThat(values1).hasLength(values2.length); + assertThat(values1).hasLength(values2.length); - for (int i = 0; i < values1.length; i++) { - assertThat(values1[i].toString()).isEqualTo(values2[i].toString()); + for (int i = 0; i < values1.length; i++) { + assertThat(values1[i].toString()).isEqualTo(values2[i].toString()); + } } - } - @Test - 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. - assertThat(UnittestEnormousDescriptor.getDescriptor().toProto().getSerializedSize()) - .isGreaterThan(65536); - } + /** Test that the FieldDescriptor.JavaType enum is the same as the WireFormat.JavaType enum. */ + @Test + public void testJavaTypeTablesMatch() throws Exception { + FieldDescriptor.JavaType[] values1 = FieldDescriptor.JavaType.values(); + WireFormat.JavaType[] values2 = WireFormat.JavaType.values(); + + assertThat(values1).hasLength(values2.length); - /** Tests that the DescriptorValidationException works as intended. */ - @Test - 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]); - assertWithMessage("DescriptorValidationException expected").fail(); - } catch (DescriptorValidationException e) { - // Expected; check that the error message contains some useful hints - assertThat(e).hasMessageThat().contains("foo"); - assertThat(e).hasMessageThat().contains("Foo"); - assertThat(e).hasMessageThat().contains("invalid"); - assertThat(e).hasCauseThat().isInstanceOf(NumberFormatException.class); - assertThat(e).hasCauseThat().hasMessageThat().contains("invalid"); + for (int i = 0; i < values1.length; i++) { + assertThat(values1[i].toString()).isEqualTo(values2[i].toString()); + } } - } - /** Tests that parsing an unknown enum throws an exception */ - @Test - public void testParseUnknownEnum() { - FieldDescriptorProto.Builder field = - FieldDescriptorProto.newBuilder() - .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) - .setTypeName("UnknownEnum") - .setType(FieldDescriptorProto.Type.TYPE_ENUM) - .setName("bar") - .setNumber(1); - DescriptorProto.Builder messageType = - DescriptorProto.newBuilder().setName("Foo").addField(field); - FileDescriptorProto fooProto = - FileDescriptorProto.newBuilder() - .setName("foo.proto") - .addDependency("bar.proto") - .addMessageType(messageType) - .build(); - try { - Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0], true); - assertWithMessage("DescriptorValidationException expected").fail(); - } catch (DescriptorValidationException expected) { - assertThat(expected.getMessage()).contains("\"UnknownEnum\" is not an enum type."); + @Test + 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. + assertThat(UnittestEnormousDescriptor.getDescriptor().toProto().getSerializedSize()) + .isGreaterThan(65536); } - } - /** - * Tests the translate/crosslink for an example where a message field's name and type name are the - * same. - */ - @Test - 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 = + /** Tests that the DescriptorValidationException works as intended. */ + @Test + 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]); - // verify resulting descriptors - assertThat(file).isNotNull(); - List msglist = file.getMessageTypes(); - assertThat(msglist).isNotNull(); - assertThat(msglist).hasSize(2); - boolean barFound = false; - for (Descriptor desc : msglist) { - if (desc.getName().equals("Bar")) { - barFound = true; - assertThat(desc.getFields()).isNotNull(); - List fieldlist = desc.getFields(); - assertThat(fieldlist).isNotNull(); - assertThat(fieldlist).hasSize(1); - assertThat(fieldlist.get(0).getType()).isSameInstanceAs(FieldDescriptor.Type.MESSAGE); - assertThat(fieldlist.get(0).getMessageType().getName().equals("Foo")).isTrue(); + assertWithMessage("DescriptorValidationException expected").fail(); + } catch (DescriptorValidationException e) { + // Expected; check that the error message contains some useful hints + assertThat(e).hasMessageThat().contains("foo"); + assertThat(e).hasMessageThat().contains("Foo"); + assertThat(e).hasMessageThat().contains("invalid"); + assertThat(e).hasCauseThat().isInstanceOf(NumberFormatException.class); + assertThat(e).hasCauseThat().hasMessageThat().contains("invalid"); } } - assertThat(barFound).isTrue(); - } - @Test - 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}); + /** Tests that parsing an unknown enum throws an exception */ + @Test + public void testParseUnknownEnum() { + FieldDescriptorProto.Builder field = + FieldDescriptorProto.newBuilder() + .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) + .setTypeName("UnknownEnum") + .setType(FieldDescriptorProto.Type.TYPE_ENUM) + .setName("bar") + .setNumber(1); + DescriptorProto.Builder messageType = + DescriptorProto.newBuilder().setName("Foo").addField(field); + FileDescriptorProto fooProto = + FileDescriptorProto.newBuilder() + .setName("foo.proto") + .addDependency("bar.proto") + .addMessageType(messageType) + .build(); + try { + Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0], true); + assertWithMessage("DescriptorValidationException expected").fail(); + } catch (DescriptorValidationException expected) { + assertThat(expected.getMessage()).contains("\"UnknownEnum\" is not an enum type."); + } + } - // Items in the FileDescriptor array can be in any order. - FileDescriptor unused1 = - Descriptors.FileDescriptor.buildFrom(bazProto, new FileDescriptor[] {fooFile, barFile}); - FileDescriptor unused2 = - Descriptors.FileDescriptor.buildFrom(bazProto, new FileDescriptor[] {barFile, fooFile}); - } + /** + * Tests the translate/crosslink for an example where a message field's name and type name are + * the same. + */ + @Test + 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 + assertThat(file).isNotNull(); + List msglist = file.getMessageTypes(); + assertThat(msglist).isNotNull(); + assertThat(msglist).hasSize(2); + boolean barFound = false; + for (Descriptor desc : msglist) { + if (desc.getName().equals("Bar")) { + barFound = true; + assertThat(desc.getFields()).isNotNull(); + List fieldlist = desc.getFields(); + assertThat(fieldlist).isNotNull(); + assertThat(fieldlist).hasSize(1); + assertThat(fieldlist.get(0).getType()).isSameInstanceAs(FieldDescriptor.Type.MESSAGE); + assertThat(fieldlist.get(0).getMessageType().getName().equals("Foo")).isTrue(); + } + } + assertThat(barFound).isTrue(); + } - @Test - 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}); - assertWithMessage("DescriptorValidationException expected").fail(); - } catch (DescriptorValidationException e) { - assertThat(e).hasMessageThat().contains("Invalid public dependency index."); + @Test + 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. + FileDescriptor unused1 = + Descriptors.FileDescriptor.buildFrom(bazProto, new FileDescriptor[] {fooFile, barFile}); + FileDescriptor unused2 = + Descriptors.FileDescriptor.buildFrom(bazProto, new FileDescriptor[] {barFile, fooFile}); } - } - @Test - 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]); - assertWithMessage("DescriptorValidationException expected").fail(); - } catch (DescriptorValidationException e) { - assertThat(e).hasMessageThat().contains("Bar"); - assertThat(e).hasMessageThat().contains("is not defined"); + @Test + 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}); + assertWithMessage("DescriptorValidationException expected").fail(); + } catch (DescriptorValidationException e) { + assertThat(e).hasMessageThat().contains("Invalid public dependency index."); + } } - } - @Test - 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(); - FileDescriptor unused = - Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0], true); - } + @Test + 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]); + assertWithMessage("DescriptorValidationException expected").fail(); + } catch (DescriptorValidationException e) { + assertThat(e).hasMessageThat().contains("Bar"); + assertThat(e).hasMessageThat().contains("is not defined"); + } + } - @Test - 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 { + @Test + 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(); FileDescriptor unused = - Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[] {forwardFile}); - assertWithMessage("DescriptorValidationException expected").fail(); - } catch (DescriptorValidationException e) { - assertThat(e).hasMessageThat().contains("Bar"); - assertThat(e).hasMessageThat().contains("is not defined"); + Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0], true); } - } - - @Test - 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}); - FileDescriptor unused = - Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[] {forwardFile}); - } - /** Tests the translate/crosslink for an example with a more complex namespace referencing. */ - @Test - 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 - assertThat(barFile).isNotNull(); - List msglist = barFile.getMessageTypes(); - assertThat(msglist).isNotNull(); - assertThat(msglist).hasSize(1); - Descriptor desc = msglist.get(0); - if (desc.getName().equals("MyMessage")) { - assertThat(desc.getFields()).isNotNull(); - List fieldlist = desc.getFields(); - assertThat(fieldlist).isNotNull(); - assertThat(fieldlist).hasSize(1); - FieldDescriptor field = fieldlist.get(0); - assertThat(field.getType()).isSameInstanceAs(FieldDescriptor.Type.ENUM); - assertThat(field.getEnumType().getName().equals("MyEnum")).isTrue(); - assertThat(field.getEnumType().getFile().getName().equals("bar.proto")).isTrue(); - assertThat(field.getEnumType().getFile().getPackage().equals("a.b.c.d.bar.shared")).isTrue(); + @Test + 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 { + FileDescriptor unused = + Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[] {forwardFile}); + assertWithMessage("DescriptorValidationException expected").fail(); + } catch (DescriptorValidationException e) { + assertThat(e).hasMessageThat().contains("Bar"); + assertThat(e).hasMessageThat().contains("is not defined"); + } } - } - @Test - public void testOneofDescriptor() throws Exception { - Descriptor messageType = TestAllTypes.getDescriptor(); - FieldDescriptor field = messageType.findFieldByName("oneof_nested_message"); - OneofDescriptor oneofDescriptor = field.getContainingOneof(); - assertThat(oneofDescriptor).isNotNull(); - assertThat(messageType.getOneofs().get(0)).isSameInstanceAs(oneofDescriptor); - assertThat(oneofDescriptor.getName()).isEqualTo("oneof_field"); + @Test + 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}); + FileDescriptor unused = + Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[] {forwardFile}); + } - assertThat(oneofDescriptor.getFieldCount()).isEqualTo(7); - assertThat(field).isSameInstanceAs(oneofDescriptor.getField(1)); + /** Tests the translate/crosslink for an example with a more complex namespace referencing. */ + @Test + 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 + assertThat(barFile).isNotNull(); + List msglist = barFile.getMessageTypes(); + assertThat(msglist).isNotNull(); + assertThat(msglist).hasSize(1); + Descriptor desc = msglist.get(0); + if (desc.getName().equals("MyMessage")) { + assertThat(desc.getFields()).isNotNull(); + List fieldlist = desc.getFields(); + assertThat(fieldlist).isNotNull(); + assertThat(fieldlist).hasSize(1); + FieldDescriptor field = fieldlist.get(0); + assertThat(field.getType()).isSameInstanceAs(FieldDescriptor.Type.ENUM); + assertThat(field.getEnumType().getName().equals("MyEnum")).isTrue(); + assertThat(field.getEnumType().getFile().getName().equals("bar.proto")).isTrue(); + assertThat(field.getEnumType().getFile().getPackage().equals("a.b.c.d.bar.shared")) + .isTrue(); + } + } - assertThat(oneofDescriptor.getFields()).hasSize(7); - assertThat(field).isEqualTo(oneofDescriptor.getFields().get(1)); - } + @Test + public void testOneofDescriptor() throws Exception { + Descriptor messageType = TestAllTypes.getDescriptor(); + FieldDescriptor field = messageType.findFieldByName("oneof_nested_message"); + OneofDescriptor oneofDescriptor = field.getContainingOneof(); + assertThat(oneofDescriptor).isNotNull(); + assertThat(messageType.getOneofs().get(0)).isSameInstanceAs(oneofDescriptor); + assertThat(oneofDescriptor.getName()).isEqualTo("oneof_field"); + + assertThat(oneofDescriptor.getFieldCount()).isEqualTo(7); + assertThat(field).isSameInstanceAs(oneofDescriptor.getField(1)); + + assertThat(oneofDescriptor.getFields()).hasSize(7); + assertThat(field).isEqualTo(oneofDescriptor.getFields().get(1)); + } - @Test - public void testMessageDescriptorExtensions() throws Exception { - assertThat(TestAllTypes.getDescriptor().isExtendable()).isFalse(); - assertThat(TestAllExtensions.getDescriptor().isExtendable()).isTrue(); - assertThat(TestMultipleExtensionRanges.getDescriptor().isExtendable()).isTrue(); - - assertThat(TestAllTypes.getDescriptor().isExtensionNumber(3)).isFalse(); - assertThat(TestAllExtensions.getDescriptor().isExtensionNumber(3)).isTrue(); - assertThat(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(42)).isTrue(); - assertThat(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(43)).isFalse(); - assertThat(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4142)).isFalse(); - assertThat(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4143)).isTrue(); - } + @Test + public void testMessageDescriptorExtensions() throws Exception { + assertThat(TestAllTypes.getDescriptor().isExtendable()).isFalse(); + assertThat(TestAllExtensions.getDescriptor().isExtendable()).isTrue(); + assertThat(TestMultipleExtensionRanges.getDescriptor().isExtendable()).isTrue(); + + assertThat(TestAllTypes.getDescriptor().isExtensionNumber(3)).isFalse(); + assertThat(TestAllExtensions.getDescriptor().isExtensionNumber(3)).isTrue(); + assertThat(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(42)).isTrue(); + assertThat(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(43)).isFalse(); + assertThat(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4142)).isFalse(); + assertThat(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4143)).isTrue(); + } - @Test - public void testReservedFields() { - Descriptor d = TestReservedFields.getDescriptor(); - assertThat(d.isReservedNumber(2)).isTrue(); - assertThat(d.isReservedNumber(8)).isFalse(); - assertThat(d.isReservedNumber(9)).isTrue(); - assertThat(d.isReservedNumber(10)).isTrue(); - assertThat(d.isReservedNumber(11)).isTrue(); - assertThat(d.isReservedNumber(12)).isFalse(); - assertThat(d.isReservedName("foo")).isFalse(); - assertThat(d.isReservedName("bar")).isTrue(); - assertThat(d.isReservedName("baz")).isTrue(); - } + @Test + public void testReservedFields() { + Descriptor d = TestReservedFields.getDescriptor(); + assertThat(d.isReservedNumber(2)).isTrue(); + assertThat(d.isReservedNumber(8)).isFalse(); + assertThat(d.isReservedNumber(9)).isTrue(); + assertThat(d.isReservedNumber(10)).isTrue(); + assertThat(d.isReservedNumber(11)).isTrue(); + assertThat(d.isReservedNumber(12)).isFalse(); + assertThat(d.isReservedName("foo")).isFalse(); + assertThat(d.isReservedName("bar")).isTrue(); + assertThat(d.isReservedName("baz")).isTrue(); + } - @Test - public void testReservedEnumFields() { - EnumDescriptor d = TestReservedEnumFields.getDescriptor(); - assertThat(d.isReservedNumber(2)).isTrue(); - assertThat(d.isReservedNumber(8)).isFalse(); - assertThat(d.isReservedNumber(9)).isTrue(); - assertThat(d.isReservedNumber(10)).isTrue(); - assertThat(d.isReservedNumber(11)).isTrue(); - assertThat(d.isReservedNumber(12)).isFalse(); - assertThat(d.isReservedName("foo")).isFalse(); - assertThat(d.isReservedName("bar")).isTrue(); - assertThat(d.isReservedName("baz")).isTrue(); - } + @Test + public void testReservedEnumFields() { + EnumDescriptor d = TestReservedEnumFields.getDescriptor(); + assertThat(d.isReservedNumber(2)).isTrue(); + assertThat(d.isReservedNumber(8)).isFalse(); + assertThat(d.isReservedNumber(9)).isTrue(); + assertThat(d.isReservedNumber(10)).isTrue(); + assertThat(d.isReservedNumber(11)).isTrue(); + assertThat(d.isReservedNumber(12)).isFalse(); + assertThat(d.isReservedName("foo")).isFalse(); + assertThat(d.isReservedName("bar")).isTrue(); + assertThat(d.isReservedName("baz")).isTrue(); + } - @Test - public void testToString() { - assertThat( - UnittestProto.TestAllTypes.getDescriptor() - .findFieldByNumber(UnittestProto.TestAllTypes.OPTIONAL_UINT64_FIELD_NUMBER) - .toString()) - .isEqualTo("protobuf_unittest.TestAllTypes.optional_uint64"); - } + @Test + public void testToString() { + assertThat( + UnittestProto.TestAllTypes.getDescriptor() + .findFieldByNumber(UnittestProto.TestAllTypes.OPTIONAL_UINT64_FIELD_NUMBER) + .toString()) + .isEqualTo("protobuf_unittest.TestAllTypes.optional_uint64"); + } - @Test - 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(); - FileDescriptor unused = - Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]); - } + @Test + 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(); + FileDescriptor unused = + Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]); + } - @Test - public void testFieldJsonName() throws Exception { - Descriptor d = TestJsonName.getDescriptor(); - assertThat(d.getFields()).hasSize(7); - assertThat(d.getFields().get(0).getJsonName()).isEqualTo("fieldName1"); - assertThat(d.getFields().get(1).getJsonName()).isEqualTo("fieldName2"); - assertThat(d.getFields().get(2).getJsonName()).isEqualTo("FieldName3"); - assertThat(d.getFields().get(3).getJsonName()).isEqualTo("FieldName4"); - assertThat(d.getFields().get(4).getJsonName()).isEqualTo("FIELDNAME5"); - assertThat(d.getFields().get(5).getJsonName()).isEqualTo("@type"); - assertThat(d.getFields().get(6).getJsonName()).isEqualTo("fieldname7"); - } + @Test + public void testFieldJsonName() throws Exception { + Descriptor d = TestJsonName.getDescriptor(); + assertThat(d.getFields()).hasSize(7); + assertThat(d.getFields().get(0).getJsonName()).isEqualTo("fieldName1"); + assertThat(d.getFields().get(1).getJsonName()).isEqualTo("fieldName2"); + assertThat(d.getFields().get(2).getJsonName()).isEqualTo("FieldName3"); + assertThat(d.getFields().get(3).getJsonName()).isEqualTo("FieldName4"); + assertThat(d.getFields().get(4).getJsonName()).isEqualTo("FIELDNAME5"); + assertThat(d.getFields().get(5).getJsonName()).isEqualTo("@type"); + assertThat(d.getFields().get(6).getJsonName()).isEqualTo("fieldname7"); + } - @Test - public void testExtensionRenamesKeywords() { - assertThat(NonNestedExtension.if_).isInstanceOf(GeneratedMessage.GeneratedExtension.class); - assertThat(NestedExtension.MyNestedExtension.default_) - .isInstanceOf(GeneratedMessage.GeneratedExtension.class); - - NonNestedExtension.MessageToBeExtended msg = - NonNestedExtension.MessageToBeExtended.newBuilder() - .setExtension(NonNestedExtension.if_, "!fi") - .build(); - assertThat(msg.getExtension(NonNestedExtension.if_)).isEqualTo("!fi"); - - msg = - NonNestedExtension.MessageToBeExtended.newBuilder() - .setExtension(NestedExtension.MyNestedExtension.default_, 8) - .build(); - assertThat(msg.getExtension(NestedExtension.MyNestedExtension.default_).intValue()) - .isEqualTo(8); - } + @Test + public void testExtensionRenamesKeywords() { + assertThat(NonNestedExtension.if_).isInstanceOf(GeneratedMessage.GeneratedExtension.class); + assertThat(NestedExtension.MyNestedExtension.default_) + .isInstanceOf(GeneratedMessage.GeneratedExtension.class); + + NonNestedExtension.MessageToBeExtended msg = + NonNestedExtension.MessageToBeExtended.newBuilder() + .setExtension(NonNestedExtension.if_, "!fi") + .build(); + assertThat(msg.getExtension(NonNestedExtension.if_)).isEqualTo("!fi"); + + msg = + NonNestedExtension.MessageToBeExtended.newBuilder() + .setExtension(NestedExtension.MyNestedExtension.default_, 8) + .build(); + assertThat(msg.getExtension(NestedExtension.MyNestedExtension.default_).intValue()) + .isEqualTo(8); + } - @Test - public void testDefaultDescriptorExtensionRange() throws Exception { - assertThat(new Descriptor("default").isExtensionNumber(1)).isTrue(); - } + @Test + public void testDefaultDescriptorExtensionRange() throws Exception { + assertThat(new Descriptor("default").isExtensionNumber(1)).isTrue(); + } - @Test - public void testGetOptionsStripsFeatures() { - FieldDescriptor field = - UnittestLegacyFeatures.TestEditionsMessage.getDescriptor() - .findFieldByName("required_field"); - assertThat(field.getOptions().hasFeatures()).isFalse(); - } + @Test + public void testGetOptionsStripsFeatures() { + FieldDescriptor field = + UnittestLegacyFeatures.TestEditionsMessage.getDescriptor() + .findFieldByName("required_field"); + assertThat(field.getOptions().hasFeatures()).isFalse(); + } - @Test - public void testLegacyRequiredTransform() { - Descriptor descriptor = UnittestLegacyFeatures.TestEditionsMessage.getDescriptor(); - assertThat(descriptor.findFieldByName("required_field").isRequired()).isTrue(); - } + @Test + public void testLegacyRequiredTransform() { + Descriptor descriptor = UnittestLegacyFeatures.TestEditionsMessage.getDescriptor(); + assertThat(descriptor.findFieldByName("required_field").isRequired()).isTrue(); + } - @Test - public void testLegacyGroupTransform() { - Descriptor descriptor = UnittestLegacyFeatures.TestEditionsMessage.getDescriptor(); - assertThat(descriptor.findFieldByName("delimited_field").getType()) - .isEqualTo(FieldDescriptor.Type.GROUP); - } + @Test + public void testLegacyGroupTransform() { + Descriptor descriptor = UnittestLegacyFeatures.TestEditionsMessage.getDescriptor(); + assertThat(descriptor.findFieldByName("delimited_field").getType()) + .isEqualTo(FieldDescriptor.Type.GROUP); + } - @Test - public void testLegacyInferRequired() { - FieldDescriptor field = UnittestProto.TestRequired.getDescriptor().findFieldByName("a"); - assertThat(field.features.getFieldPresence()) - .isEqualTo(DescriptorProtos.FeatureSet.FieldPresence.LEGACY_REQUIRED); - } + @Test + public void testLegacyInferRequired() { + FieldDescriptor field = UnittestProto.TestRequired.getDescriptor().findFieldByName("a"); + assertThat(field.features.getFieldPresence()) + .isEqualTo(DescriptorProtos.FeatureSet.FieldPresence.LEGACY_REQUIRED); + } - @Test - public void testLegacyInferGroup() { - FieldDescriptor field = - UnittestProto.TestAllTypes.getDescriptor().findFieldByName("optionalgroup"); - assertThat(field.features.getMessageEncoding()) - .isEqualTo(DescriptorProtos.FeatureSet.MessageEncoding.DELIMITED); - } + @Test + public void testLegacyInferGroup() { + FieldDescriptor field = + UnittestProto.TestAllTypes.getDescriptor().findFieldByName("optionalgroup"); + assertThat(field.features.getMessageEncoding()) + .isEqualTo(DescriptorProtos.FeatureSet.MessageEncoding.DELIMITED); + } - @Test - public void testLegacyInferProto2Packed() { - FieldDescriptor field = - UnittestProto.TestPackedTypes.getDescriptor().findFieldByName("packed_int32"); - assertThat(field.features.getRepeatedFieldEncoding()) - .isEqualTo(DescriptorProtos.FeatureSet.RepeatedFieldEncoding.PACKED); - } + @Test + public void testLegacyInferProto2Packed() { + FieldDescriptor field = + UnittestProto.TestPackedTypes.getDescriptor().findFieldByName("packed_int32"); + assertThat(field.features.getRepeatedFieldEncoding()) + .isEqualTo(DescriptorProtos.FeatureSet.RepeatedFieldEncoding.PACKED); + } - @Test - public void testLegacyInferProto3Expanded() { - FieldDescriptor field = - UnittestProto3.TestUnpackedTypes.getDescriptor().findFieldByName("repeated_int32"); - assertThat(field.features.getRepeatedFieldEncoding()) - .isEqualTo(DescriptorProtos.FeatureSet.RepeatedFieldEncoding.EXPANDED); - } + @Test + public void testLegacyInferProto3Expanded() { + FieldDescriptor field = + UnittestProto3.TestUnpackedTypes.getDescriptor().findFieldByName("repeated_int32"); + assertThat(field.features.getRepeatedFieldEncoding()) + .isEqualTo(DescriptorProtos.FeatureSet.RepeatedFieldEncoding.EXPANDED); + } - @Test - public void testLegacyInferProto2Utf8Validation() throws Exception { - FileDescriptor file = - FileDescriptor.buildFrom( - FileDescriptorProto.newBuilder() - .setName("some/filename/some.proto") - .setPackage("protobuf_unittest") - .setSyntax("proto2") - .setOptions(FileOptions.newBuilder().setJavaStringCheckUtf8(true)) - .build(), - new FileDescriptor[0]); - assertThat(file.features.getExtension(JavaFeaturesProto.java).getUtf8Validation()) - .isEqualTo(JavaFeaturesProto.JavaFeatures.Utf8Validation.VERIFY); - } + @Test + public void testLegacyInferProto2Utf8Validation() throws Exception { + FileDescriptor file = + FileDescriptor.buildFrom( + FileDescriptorProto.newBuilder() + .setName("some/filename/some.proto") + .setPackage("protobuf_unittest") + .setSyntax("proto2") + .setOptions(FileOptions.newBuilder().setJavaStringCheckUtf8(true)) + .build(), + new FileDescriptor[0]); + assertThat(file.features.getExtension(JavaFeaturesProto.java).getUtf8Validation()) + .isEqualTo(JavaFeaturesProto.JavaFeatures.Utf8Validation.VERIFY); + } - @Test - public void testProto2Defaults() { - FieldDescriptor proto2Field = TestAllTypes.getDescriptor().findFieldByName("optional_int32"); - DescriptorProtos.FeatureSet features = proto2Field.features; - assertThat(features.getFieldPresence()) - .isEqualTo(DescriptorProtos.FeatureSet.FieldPresence.EXPLICIT); - assertThat(features.getEnumType()).isEqualTo(DescriptorProtos.FeatureSet.EnumType.CLOSED); - assertThat(features.getRepeatedFieldEncoding()) - .isEqualTo(DescriptorProtos.FeatureSet.RepeatedFieldEncoding.EXPANDED); - assertThat(features.getUtf8Validation()) - .isEqualTo(DescriptorProtos.FeatureSet.Utf8Validation.NONE); - assertThat(features.getMessageEncoding()) - .isEqualTo(DescriptorProtos.FeatureSet.MessageEncoding.LENGTH_PREFIXED); - assertThat(features.getJsonFormat()) - .isEqualTo(DescriptorProtos.FeatureSet.JsonFormat.LEGACY_BEST_EFFORT); - - assertThat(features.getExtension(JavaFeaturesProto.java).getLegacyClosedEnum()).isTrue(); - assertThat(features.getExtension(JavaFeaturesProto.java).getUtf8Validation()) - .isEqualTo(JavaFeaturesProto.JavaFeatures.Utf8Validation.DEFAULT); - } + @Test + public void testProto2Defaults() { + FieldDescriptor proto2Field = TestAllTypes.getDescriptor().findFieldByName("optional_int32"); + DescriptorProtos.FeatureSet features = proto2Field.features; + assertThat(features.getFieldPresence()) + .isEqualTo(DescriptorProtos.FeatureSet.FieldPresence.EXPLICIT); + assertThat(features.getEnumType()).isEqualTo(DescriptorProtos.FeatureSet.EnumType.CLOSED); + assertThat(features.getRepeatedFieldEncoding()) + .isEqualTo(DescriptorProtos.FeatureSet.RepeatedFieldEncoding.EXPANDED); + assertThat(features.getUtf8Validation()) + .isEqualTo(DescriptorProtos.FeatureSet.Utf8Validation.NONE); + assertThat(features.getMessageEncoding()) + .isEqualTo(DescriptorProtos.FeatureSet.MessageEncoding.LENGTH_PREFIXED); + assertThat(features.getJsonFormat()) + .isEqualTo(DescriptorProtos.FeatureSet.JsonFormat.LEGACY_BEST_EFFORT); + + assertThat(features.getExtension(JavaFeaturesProto.java).getLegacyClosedEnum()).isTrue(); + assertThat(features.getExtension(JavaFeaturesProto.java).getUtf8Validation()) + .isEqualTo(JavaFeaturesProto.JavaFeatures.Utf8Validation.DEFAULT); + } - @Test - public void testProto3Defaults() { - FieldDescriptor proto3Field = - UnittestProto3.TestAllTypes.getDescriptor().findFieldByName("optional_int32"); - DescriptorProtos.FeatureSet features = proto3Field.features; - assertThat(features.getFieldPresence()) - .isEqualTo(DescriptorProtos.FeatureSet.FieldPresence.IMPLICIT); - assertThat(features.getEnumType()).isEqualTo(DescriptorProtos.FeatureSet.EnumType.OPEN); - assertThat(features.getRepeatedFieldEncoding()) - .isEqualTo(DescriptorProtos.FeatureSet.RepeatedFieldEncoding.PACKED); - assertThat(features.getUtf8Validation()) - .isEqualTo(DescriptorProtos.FeatureSet.Utf8Validation.VERIFY); - assertThat(features.getMessageEncoding()) - .isEqualTo(DescriptorProtos.FeatureSet.MessageEncoding.LENGTH_PREFIXED); - - assertThat(features.getExtension(JavaFeaturesProto.java).getLegacyClosedEnum()).isFalse(); - assertThat(features.getExtension(JavaFeaturesProto.java).getUtf8Validation()) - .isEqualTo(JavaFeaturesProto.JavaFeatures.Utf8Validation.DEFAULT); + @Test + public void testProto3Defaults() { + FieldDescriptor proto3Field = + UnittestProto3.TestAllTypes.getDescriptor().findFieldByName("optional_int32"); + DescriptorProtos.FeatureSet features = proto3Field.features; + assertThat(features.getFieldPresence()) + .isEqualTo(DescriptorProtos.FeatureSet.FieldPresence.IMPLICIT); + assertThat(features.getEnumType()).isEqualTo(DescriptorProtos.FeatureSet.EnumType.OPEN); + assertThat(features.getRepeatedFieldEncoding()) + .isEqualTo(DescriptorProtos.FeatureSet.RepeatedFieldEncoding.PACKED); + assertThat(features.getUtf8Validation()) + .isEqualTo(DescriptorProtos.FeatureSet.Utf8Validation.VERIFY); + assertThat(features.getMessageEncoding()) + .isEqualTo(DescriptorProtos.FeatureSet.MessageEncoding.LENGTH_PREFIXED); + + assertThat(features.getExtension(JavaFeaturesProto.java).getLegacyClosedEnum()).isFalse(); + assertThat(features.getExtension(JavaFeaturesProto.java).getUtf8Validation()) + .isEqualTo(JavaFeaturesProto.JavaFeatures.Utf8Validation.DEFAULT); + } } - @RunWith(JUnit4.class) public static class FeatureInheritanceTest { FileDescriptorProto.Builder fileProto; FieldDescriptorProto.Builder topExtensionProto; @@ -1197,6 +1220,12 @@ public static class FeatureInheritanceTest { @Before public void setUp() { + FeatureSetDefaults.Builder defaults = Descriptors.getJavaEditionDefaults().toBuilder(); + for (FeatureSetEditionDefault.Builder editionDefaults : defaults.getDefaultsBuilderList()) { + setTestFeature(editionDefaults.getFeaturesBuilder(), 1); + } + Descriptors.setTestJavaEditionDefaults(defaults.build()); + this.fileProto = DescriptorProtos.FileDescriptorProto.newBuilder() .setName("some/filename/some.proto") @@ -1205,59 +1234,61 @@ public void setUp() { .setSyntax("editions"); this.topExtensionProto = - FieldDescriptorProto.newBuilder() + this.fileProto + .addExtensionBuilder() .setName("top_extension") .setNumber(10) .setType(FieldDescriptorProto.Type.TYPE_INT32) .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) .setExtendee(".protobuf_unittest.TopMessage"); - this.fileProto.addExtension(topExtensionProto); - this.topEnumProto = EnumDescriptorProto.newBuilder().setName("TopEnum"); - this.enumValueProto = EnumValueDescriptorProto.newBuilder().setName("TOP_VALUE").setNumber(0); - this.topEnumProto.addValue(enumValueProto); - this.fileProto.addEnumType(topEnumProto); + this.topEnumProto = this.fileProto.addEnumTypeBuilder().setName("TopEnum"); + this.enumValueProto = this.topEnumProto.addValueBuilder().setName("TOP_VALUE").setNumber(0); + + this.topMessageProto = + this.fileProto + .addMessageTypeBuilder() + .setName("TopMessage") + .addExtensionRange(ExtensionRange.newBuilder().setStart(10).setEnd(20).build()); - this.topMessageProto = DescriptorProto.newBuilder().setName("TopMessage"); this.fieldProto = - FieldDescriptorProto.newBuilder() + this.topMessageProto + .addFieldBuilder() .setName("field") .setNumber(1) .setType(FieldDescriptorProto.Type.TYPE_INT32) .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL); - this.topMessageProto.addField(fieldProto); this.nestedExtensionProto = - FieldDescriptorProto.newBuilder() + this.topMessageProto + .addExtensionBuilder() .setName("nested_extension") .setNumber(11) .setType(FieldDescriptorProto.Type.TYPE_INT32) .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) .setExtendee(".protobuf_unittest.TopMessage"); - this.topMessageProto.addExtension(nestedExtensionProto); - this.nestedMessageProto = DescriptorProto.newBuilder().setName("NestedMessage"); - this.topMessageProto.addNestedType(nestedMessageProto); - this.nestedEnumProto = EnumDescriptorProto.newBuilder().setName("NestedEnum"); - this.nestedEnumProto.addValue( - EnumValueDescriptorProto.newBuilder().setName("NESTED_VALUE").setNumber(0)); - this.topMessageProto.addEnumType(nestedEnumProto); - this.topMessageProto.addOneofDecl(OneofDescriptorProto.newBuilder().setName("Oneof")); - this.topMessageProto.addField( - FieldDescriptorProto.newBuilder() + this.nestedMessageProto = + this.topMessageProto.addNestedTypeBuilder().setName("NestedMessage"); + this.nestedEnumProto = + this.topMessageProto + .addEnumTypeBuilder() + .setName("NestedEnum") + .addValue(EnumValueDescriptorProto.newBuilder().setName("NESTED_VALUE").setNumber(0)); + this.oneofProto = this.topMessageProto.addOneofDeclBuilder().setName("Oneof"); + this.oneofFieldProto = + this.topMessageProto + .addFieldBuilder() .setName("oneof_field") .setNumber(2) .setType(FieldDescriptorProto.Type.TYPE_INT32) .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL) - .setOneofIndex(0)); - this.fileProto.addMessageType(topMessageProto); - - this.serviceProto = ServiceDescriptorProto.newBuilder().setName("TestService"); + .setOneofIndex(0); + this.serviceProto = this.fileProto.addServiceBuilder().setName("TestService"); this.methodProto = - MethodDescriptorProto.newBuilder() + this.serviceProto + .addMethodBuilder() .setName("CallMethod") .setInputType(".protobuf_unittest.TopMessage") .setOutputType(".protobuf_unittest.TopMessage"); - this.serviceProto.addMethod(methodProto); - this.fileProto.addService(serviceProto); } void setTestFeature(DescriptorProtos.FeatureSet.Builder features, int value) { @@ -1308,7 +1339,6 @@ public void testFileMessageOverride() throws Exception { public void testFileEnumInherit() throws Exception { setTestFeature(fileProto.getOptionsBuilder().getFeaturesBuilder(), 3); FileDescriptor descriptor = buildFrom(fileProto.build()); - assertThat(getTestFeature(descriptor.getEnumTypes().get(0).features)).isEqualTo(3); } @@ -1360,7 +1390,7 @@ public void testMessageFieldInherit() throws Exception { @Test public void testMessageFieldOverride() throws Exception { - setTestFeature(fileProto.getOptionsBuilder().getFeaturesBuilder(), 3); + setTestFeature(topMessageProto.getOptionsBuilder().getFeaturesBuilder(), 3); setTestFeature(fieldProto.getOptionsBuilder().getFeaturesBuilder(), 5); FileDescriptor descriptor = buildFrom(fileProto.build()); assertThat(getTestFeature(descriptor.getMessageTypes().get(0).getFields().get(0).features)) @@ -1377,7 +1407,7 @@ public void testMessageEnumInherit() throws Exception { @Test public void testMessageEnumOverride() throws Exception { - setTestFeature(fileProto.getOptionsBuilder().getFeaturesBuilder(), 3); + setTestFeature(topMessageProto.getOptionsBuilder().getFeaturesBuilder(), 3); setTestFeature(nestedEnumProto.getOptionsBuilder().getFeaturesBuilder(), 5); FileDescriptor descriptor = buildFrom(fileProto.build()); assertThat(getTestFeature(descriptor.getMessageTypes().get(0).getEnumTypes().get(0).features)) @@ -1441,7 +1471,7 @@ public void testMessageOneofOverride() throws Exception { @Test public void testOneofFieldInherit() throws Exception { - setTestFeature(topMessageProto.getOptionsBuilder().getFeaturesBuilder(), 3); + setTestFeature(oneofProto.getOptionsBuilder().getFeaturesBuilder(), 3); FileDescriptor descriptor = buildFrom(fileProto.build()); assertThat( getTestFeature( @@ -1458,8 +1488,8 @@ public void testOneofFieldInherit() throws Exception { @Test public void testOneofFieldOverride() throws Exception { - setTestFeature(topMessageProto.getOptionsBuilder().getFeaturesBuilder(), 3); - setTestFeature(oneofProto.getOptionsBuilder().getFeaturesBuilder(), 5); + setTestFeature(oneofProto.getOptionsBuilder().getFeaturesBuilder(), 3); + setTestFeature(oneofFieldProto.getOptionsBuilder().getFeaturesBuilder(), 5); FileDescriptor descriptor = buildFrom(fileProto.build()); assertThat( getTestFeature( @@ -1476,7 +1506,7 @@ public void testOneofFieldOverride() throws Exception { @Test public void testEnumValueInherit() throws Exception { - setTestFeature(topMessageProto.getOptionsBuilder().getFeaturesBuilder(), 3); + setTestFeature(topEnumProto.getOptionsBuilder().getFeaturesBuilder(), 3); FileDescriptor descriptor = buildFrom(fileProto.build()); assertThat(getTestFeature(descriptor.getEnumTypes().get(0).getValues().get(0).features)) .isEqualTo(3); @@ -1484,7 +1514,7 @@ public void testEnumValueInherit() throws Exception { @Test public void testEnumValueOverride() throws Exception { - setTestFeature(topMessageProto.getOptionsBuilder().getFeaturesBuilder(), 3); + setTestFeature(topEnumProto.getOptionsBuilder().getFeaturesBuilder(), 3); setTestFeature(enumValueProto.getOptionsBuilder().getFeaturesBuilder(), 5); FileDescriptor descriptor = buildFrom(fileProto.build()); assertThat(getTestFeature(descriptor.getEnumTypes().get(0).getValues().get(0).features))