• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 //
4 // Use of this source code is governed by a BSD-style
5 // license that can be found in the LICENSE file or at
6 // https://developers.google.com/open-source/licenses/bsd
7 
8 package com.google.protobuf;
9 
10 import static com.google.common.truth.Truth.assertThat;
11 import static com.google.common.truth.Truth.assertWithMessage;
12 import static org.junit.Assert.assertThrows;
13 
14 import com.google.protobuf.DescriptorProtos.DescriptorProto;
15 import com.google.protobuf.DescriptorProtos.DescriptorProto.ExtensionRange;
16 import com.google.protobuf.DescriptorProtos.Edition;
17 import com.google.protobuf.DescriptorProtos.EnumDescriptorProto;
18 import com.google.protobuf.DescriptorProtos.EnumValueDescriptorProto;
19 import com.google.protobuf.DescriptorProtos.FeatureSetDefaults;
20 import com.google.protobuf.DescriptorProtos.FeatureSetDefaults.FeatureSetEditionDefault;
21 import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
22 import com.google.protobuf.DescriptorProtos.FieldOptions;
23 import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
24 import com.google.protobuf.DescriptorProtos.FileOptions;
25 import com.google.protobuf.DescriptorProtos.MethodDescriptorProto;
26 import com.google.protobuf.DescriptorProtos.OneofDescriptorProto;
27 import com.google.protobuf.DescriptorProtos.ServiceDescriptorProto;
28 import com.google.protobuf.Descriptors.Descriptor;
29 import com.google.protobuf.Descriptors.DescriptorValidationException;
30 import com.google.protobuf.Descriptors.EnumDescriptor;
31 import com.google.protobuf.Descriptors.EnumValueDescriptor;
32 import com.google.protobuf.Descriptors.FieldDescriptor;
33 import com.google.protobuf.Descriptors.FileDescriptor;
34 import com.google.protobuf.Descriptors.MethodDescriptor;
35 import com.google.protobuf.Descriptors.OneofDescriptor;
36 import com.google.protobuf.Descriptors.ServiceDescriptor;
37 import com.google.protobuf.test.UnittestImport;
38 import com.google.protobuf.test.UnittestImport.ImportEnum;
39 import com.google.protobuf.test.UnittestImport.ImportEnumForMap;
40 import legacy_features_unittest.UnittestLegacyFeatures;
41 import pb.UnittestFeatures;
42 import protobuf_unittest.TestCustomOptions;
43 import protobuf_unittest.UnittestCustomOptions;
44 import protobuf_unittest.UnittestProto;
45 import protobuf_unittest.UnittestProto.ForeignEnum;
46 import protobuf_unittest.UnittestProto.ForeignMessage;
47 import protobuf_unittest.UnittestProto.TestAllExtensions;
48 import protobuf_unittest.UnittestProto.TestAllTypes;
49 import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
50 import protobuf_unittest.UnittestProto.TestJsonName;
51 import protobuf_unittest.UnittestProto.TestMultipleExtensionRanges;
52 import protobuf_unittest.UnittestProto.TestRequired;
53 import protobuf_unittest.UnittestProto.TestReservedEnumFields;
54 import protobuf_unittest.UnittestProto.TestReservedFields;
55 import protobuf_unittest.UnittestProto.TestService;
56 import protobuf_unittest.UnittestRetention;
57 import protobuf_unittest.UnittestProto3Extensions.Proto3FileExtensions;
58 import java.util.Collections;
59 import java.util.List;
60 import org.junit.Before;
61 import org.junit.Test;
62 import org.junit.experimental.runners.Enclosed;
63 import org.junit.runner.RunWith;
64 
65 import protobuf_unittest.NestedExtension;
66 import protobuf_unittest.NonNestedExtension;
67 
68 /** Unit test for {@link Descriptors}. */
69 @RunWith(Enclosed.class)
70 public class DescriptorsTest {
71 
72   public static class GeneralDescriptorsTest {
73     // Regression test for bug where referencing a FieldDescriptor.Type value
74     // before a FieldDescriptorProto.Type value would yield a
75     // ExceptionInInitializerError.
76     @SuppressWarnings("unused")
77     private static final Object STATIC_INIT_TEST = FieldDescriptor.Type.BOOL;
78 
79     @Test
testFieldTypeEnumMapping()80     public void testFieldTypeEnumMapping() throws Exception {
81       assertThat(FieldDescriptor.Type.values())
82           .hasLength(FieldDescriptorProto.Type.values().length);
83       for (FieldDescriptor.Type type : FieldDescriptor.Type.values()) {
84         FieldDescriptorProto.Type protoType = type.toProto();
85         assertThat(protoType.name()).isEqualTo("TYPE_" + type.name());
86         assertThat(FieldDescriptor.Type.valueOf(protoType)).isEqualTo(type);
87       }
88     }
89 
90     @Test
testFileDescriptor()91     public void testFileDescriptor() throws Exception {
92       FileDescriptor file = UnittestProto.getDescriptor();
93 
94       assertThat(file.getName()).isEqualTo("google/protobuf/unittest.proto");
95       assertThat(file.getPackage()).isEqualTo("protobuf_unittest");
96       assertThat(file.getOptions().getJavaOuterClassname()).isEqualTo("UnittestProto");
97       assertThat(file.toProto().getName()).isEqualTo("google/protobuf/unittest.proto");
98 
99       assertThat(file.getDependencies()).containsExactly(UnittestImport.getDescriptor());
100 
101       Descriptor messageType = TestAllTypes.getDescriptor();
102       assertThat(file.getMessageTypes().get(0)).isEqualTo(messageType);
103       assertThat(file.findMessageTypeByName("TestAllTypes")).isEqualTo(messageType);
104       assertThat(file.findMessageTypeByName("NoSuchType")).isNull();
105       assertThat(file.findMessageTypeByName("protobuf_unittest.TestAllTypes")).isNull();
106       for (int i = 0; i < file.getMessageTypes().size(); i++) {
107         assertThat(file.getMessageTypes().get(i).getIndex()).isEqualTo(i);
108       }
109 
110       EnumDescriptor enumType = ForeignEnum.getDescriptor();
111       assertThat(file.getEnumTypes().get(0)).isEqualTo(enumType);
112       assertThat(file.findEnumTypeByName("ForeignEnum")).isEqualTo(enumType);
113       assertThat(file.findEnumTypeByName("NoSuchType")).isNull();
114       assertThat(file.findEnumTypeByName("protobuf_unittest.ForeignEnum")).isNull();
115       assertThat(UnittestImport.getDescriptor().getEnumTypes())
116           .containsExactly(ImportEnum.getDescriptor(), ImportEnumForMap.getDescriptor())
117           .inOrder();
118       for (int i = 0; i < file.getEnumTypes().size(); i++) {
119         assertThat(file.getEnumTypes().get(i).getIndex()).isEqualTo(i);
120       }
121 
122       ServiceDescriptor service = TestService.getDescriptor();
123       assertThat(file.getServices().get(0)).isEqualTo(service);
124       assertThat(file.findServiceByName("TestService")).isEqualTo(service);
125       assertThat(file.findServiceByName("NoSuchType")).isNull();
126       assertThat(file.findServiceByName("protobuf_unittest.TestService")).isNull();
127       assertThat(UnittestImport.getDescriptor().getServices()).isEqualTo(Collections.emptyList());
128       for (int i = 0; i < file.getServices().size(); i++) {
129         assertThat(file.getServices().get(i).getIndex()).isEqualTo(i);
130       }
131 
132       FieldDescriptor extension = UnittestProto.optionalInt32Extension.getDescriptor();
133       assertThat(file.getExtensions().get(0)).isEqualTo(extension);
134       assertThat(file.findExtensionByName("optional_int32_extension")).isEqualTo(extension);
135       assertThat(file.findExtensionByName("no_such_ext")).isNull();
136       assertThat(file.findExtensionByName("protobuf_unittest.optional_int32_extension")).isNull();
137       assertThat(UnittestImport.getDescriptor().getExtensions()).isEqualTo(Collections.emptyList());
138       for (int i = 0; i < file.getExtensions().size(); i++) {
139         assertThat(file.getExtensions().get(i).getIndex()).isEqualTo(i);
140       }
141     }
142 
143     @Test
testFileDescriptorGetEdition()144     public void testFileDescriptorGetEdition() throws Exception {
145       FileDescriptorProto proto2 = FileDescriptorProto.newBuilder().setSyntax("proto2").build();
146       FileDescriptor file2 = Descriptors.FileDescriptor.buildFrom(proto2, new FileDescriptor[0]);
147       assertThat(file2.getEdition()).isEqualTo(Edition.EDITION_PROTO2);
148 
149       FileDescriptorProto proto3 = FileDescriptorProto.newBuilder().setSyntax("proto3").build();
150       FileDescriptor file3 = Descriptors.FileDescriptor.buildFrom(proto3, new FileDescriptor[0]);
151       assertThat(file3.getEdition()).isEqualTo(Edition.EDITION_PROTO3);
152 
153       FileDescriptorProto protoEdition =
154           FileDescriptorProto.newBuilder()
155               .setSyntax("editions")
156               .setEdition(Edition.EDITION_2023)
157               .build();
158       FileDescriptor fileEdition =
159           Descriptors.FileDescriptor.buildFrom(protoEdition, new FileDescriptor[0]);
160       assertThat(fileEdition.getEdition()).isEqualTo(Edition.EDITION_2023);
161 
162       FileDescriptorProto protoMissingEdition =
163           FileDescriptorProto.newBuilder().setSyntax("editions").build();
164       IllegalArgumentException exception =
165           assertThrows(
166               IllegalArgumentException.class,
167               () ->
168                   Descriptors.FileDescriptor.buildFrom(protoMissingEdition, new FileDescriptor[0]));
169       assertThat(exception)
170           .hasMessageThat()
171           .contains("Edition EDITION_UNKNOWN is lower than the minimum supported edition");
172     }
173 
174     @Test
testFileDescriptorCopyHeadingTo()175     public void testFileDescriptorCopyHeadingTo() throws Exception {
176       FileDescriptorProto.Builder protoBuilder =
177           FileDescriptorProto.newBuilder()
178               .setName("foo.proto")
179               .setPackage("foo.bar.baz")
180               .setSyntax("proto2")
181               .setOptions(FileOptions.newBuilder().setJavaPackage("foo.bar.baz").build())
182               // Won't be copied.
183               .addMessageType(DescriptorProto.newBuilder().setName("Foo").build());
184       FileDescriptor file2 =
185           Descriptors.FileDescriptor.buildFrom(protoBuilder.build(), new FileDescriptor[0]);
186       FileDescriptorProto.Builder protoBuilder2 = FileDescriptorProto.newBuilder();
187       file2.copyHeadingTo(protoBuilder2);
188       FileDescriptorProto toProto2 = protoBuilder2.build();
189       assertThat(toProto2.getName()).isEqualTo("foo.proto");
190       assertThat(toProto2.getPackage()).isEqualTo("foo.bar.baz");
191       assertThat(toProto2.getSyntax()).isEqualTo("proto2");
192       assertThat(toProto2.getOptions().getJavaPackage()).isEqualTo("foo.bar.baz");
193       assertThat(toProto2.getMessageTypeList()).isEmpty();
194 
195       protoBuilder.setSyntax("proto3");
196       FileDescriptor file3 =
197           Descriptors.FileDescriptor.buildFrom(protoBuilder.build(), new FileDescriptor[0]);
198       FileDescriptorProto.Builder protoBuilder3 = FileDescriptorProto.newBuilder();
199       file3.copyHeadingTo(protoBuilder3);
200       FileDescriptorProto toProto3 = protoBuilder3.build();
201       assertThat(toProto3.getName()).isEqualTo("foo.proto");
202       assertThat(toProto3.getPackage()).isEqualTo("foo.bar.baz");
203       assertThat(toProto3.getSyntax()).isEqualTo("proto3");
204       assertThat(toProto2.getOptions().getJavaPackage()).isEqualTo("foo.bar.baz");
205       assertThat(toProto3.getMessageTypeList()).isEmpty();
206     }
207 
208     @Test
testDescriptor()209     public void testDescriptor() throws Exception {
210       Descriptor messageType = TestAllTypes.getDescriptor();
211       Descriptor nestedType = TestAllTypes.NestedMessage.getDescriptor();
212 
213       assertThat(messageType.getName()).isEqualTo("TestAllTypes");
214       assertThat(messageType.getFullName()).isEqualTo("protobuf_unittest.TestAllTypes");
215       assertThat(messageType.getFile()).isEqualTo(UnittestProto.getDescriptor());
216       assertThat(messageType.getContainingType()).isNull();
217       assertThat(messageType.getOptions())
218           .isEqualTo(DescriptorProtos.MessageOptions.getDefaultInstance());
219       assertThat(messageType.toProto().getName()).isEqualTo("TestAllTypes");
220 
221       assertThat(nestedType.getName()).isEqualTo("NestedMessage");
222       assertThat(nestedType.getFullName()).isEqualTo("protobuf_unittest.TestAllTypes.NestedMessage");
223       assertThat(nestedType.getFile()).isEqualTo(UnittestProto.getDescriptor());
224       assertThat(nestedType.getContainingType()).isEqualTo(messageType);
225 
226       FieldDescriptor field = messageType.getFields().get(0);
227       assertThat(field.getName()).isEqualTo("optional_int32");
228       assertThat(messageType.findFieldByName("optional_int32")).isEqualTo(field);
229       assertThat(messageType.findFieldByName("no_such_field")).isNull();
230       assertThat(messageType.findFieldByNumber(1)).isEqualTo(field);
231       assertThat(messageType.findFieldByNumber(571283)).isNull();
232       for (int i = 0; i < messageType.getFields().size(); i++) {
233         assertThat(messageType.getFields().get(i).getIndex()).isEqualTo(i);
234       }
235 
236       assertThat(messageType.getNestedTypes().get(0)).isEqualTo(nestedType);
237       assertThat(messageType.findNestedTypeByName("NestedMessage")).isEqualTo(nestedType);
238       assertThat(messageType.findNestedTypeByName("NoSuchType")).isNull();
239       for (int i = 0; i < messageType.getNestedTypes().size(); i++) {
240         assertThat(messageType.getNestedTypes().get(i).getIndex()).isEqualTo(i);
241       }
242 
243       EnumDescriptor enumType = TestAllTypes.NestedEnum.getDescriptor();
244       assertThat(messageType.getEnumTypes().get(0)).isEqualTo(enumType);
245       assertThat(messageType.findEnumTypeByName("NestedEnum")).isEqualTo(enumType);
246       assertThat(messageType.findEnumTypeByName("NoSuchType")).isNull();
247       for (int i = 0; i < messageType.getEnumTypes().size(); i++) {
248         assertThat(messageType.getEnumTypes().get(i).getIndex()).isEqualTo(i);
249       }
250     }
251 
252     @Test
testFieldDescriptor()253     public void testFieldDescriptor() throws Exception {
254       Descriptor messageType = TestAllTypes.getDescriptor();
255       FieldDescriptor primitiveField = messageType.findFieldByName("optional_int32");
256       FieldDescriptor enumField = messageType.findFieldByName("optional_nested_enum");
257       FieldDescriptor messageField = messageType.findFieldByName("optional_foreign_message");
258       FieldDescriptor cordField = messageType.findFieldByName("optional_cord");
259       FieldDescriptor extension = UnittestProto.optionalInt32Extension.getDescriptor();
260       FieldDescriptor nestedExtension = TestRequired.single.getDescriptor();
261 
262       assertThat(primitiveField.getName()).isEqualTo("optional_int32");
263       assertThat(primitiveField.getFullName())
264           .isEqualTo("protobuf_unittest.TestAllTypes.optional_int32");
265       assertThat(primitiveField.getNumber()).isEqualTo(1);
266       assertThat(primitiveField.getContainingType()).isEqualTo(messageType);
267       assertThat(primitiveField.getFile()).isEqualTo(UnittestProto.getDescriptor());
268       assertThat(primitiveField.getType()).isEqualTo(FieldDescriptor.Type.INT32);
269       assertThat(primitiveField.getJavaType()).isEqualTo(FieldDescriptor.JavaType.INT);
270       assertThat(primitiveField.getOptions())
271           .isEqualTo(DescriptorProtos.FieldOptions.getDefaultInstance());
272       assertThat(primitiveField.isExtension()).isFalse();
273       assertThat(primitiveField.toProto().getName()).isEqualTo("optional_int32");
274 
275       assertThat(enumField.getName()).isEqualTo("optional_nested_enum");
276       assertThat(enumField.getType()).isEqualTo(FieldDescriptor.Type.ENUM);
277       assertThat(enumField.getJavaType()).isEqualTo(FieldDescriptor.JavaType.ENUM);
278       assertThat(enumField.getEnumType()).isEqualTo(TestAllTypes.NestedEnum.getDescriptor());
279 
280       assertThat(messageField.getName()).isEqualTo("optional_foreign_message");
281       assertThat(messageField.getType()).isEqualTo(FieldDescriptor.Type.MESSAGE);
282       assertThat(messageField.getJavaType()).isEqualTo(FieldDescriptor.JavaType.MESSAGE);
283       assertThat(messageField.getMessageType()).isEqualTo(ForeignMessage.getDescriptor());
284 
285       assertThat(cordField.getName()).isEqualTo("optional_cord");
286       assertThat(cordField.getType()).isEqualTo(FieldDescriptor.Type.STRING);
287       assertThat(cordField.getJavaType()).isEqualTo(FieldDescriptor.JavaType.STRING);
288       assertThat(cordField.getOptions().getCtype())
289           .isEqualTo(DescriptorProtos.FieldOptions.CType.CORD);
290 
291       assertThat(extension.getName()).isEqualTo("optional_int32_extension");
292       assertThat(extension.getFullName()).isEqualTo("protobuf_unittest.optional_int32_extension");
293       assertThat(extension.getNumber()).isEqualTo(1);
294       assertThat(extension.getContainingType()).isEqualTo(TestAllExtensions.getDescriptor());
295       assertThat(extension.getFile()).isEqualTo(UnittestProto.getDescriptor());
296       assertThat(extension.getType()).isEqualTo(FieldDescriptor.Type.INT32);
297       assertThat(extension.getJavaType()).isEqualTo(FieldDescriptor.JavaType.INT);
298       assertThat(extension.getOptions())
299           .isEqualTo(DescriptorProtos.FieldOptions.getDefaultInstance());
300       assertThat(extension.isExtension()).isTrue();
301       assertThat(extension.getExtensionScope()).isNull();
302       assertThat(extension.toProto().getName()).isEqualTo("optional_int32_extension");
303 
304       assertThat(nestedExtension.getName()).isEqualTo("single");
305       assertThat(nestedExtension.getFullName()).isEqualTo("protobuf_unittest.TestRequired.single");
306       assertThat(nestedExtension.getExtensionScope()).isEqualTo(TestRequired.getDescriptor());
307     }
308 
309     @Test
testFieldDescriptorLabel()310     public void testFieldDescriptorLabel() throws Exception {
311       FieldDescriptor requiredField = TestRequired.getDescriptor().findFieldByName("a");
312       FieldDescriptor optionalField =
313           TestAllTypes.getDescriptor().findFieldByName("optional_int32");
314       FieldDescriptor repeatedField =
315           TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
316 
317       assertThat(requiredField.isRequired()).isTrue();
318       assertThat(requiredField.isRepeated()).isFalse();
319       assertThat(optionalField.isRequired()).isFalse();
320       assertThat(optionalField.isRepeated()).isFalse();
321       assertThat(repeatedField.isRequired()).isFalse();
322       assertThat(repeatedField.isRepeated()).isTrue();
323     }
324 
325     @Test
testFieldDescriptorJsonName()326     public void testFieldDescriptorJsonName() throws Exception {
327       FieldDescriptor requiredField = TestRequired.getDescriptor().findFieldByName("a");
328       FieldDescriptor optionalField =
329           TestAllTypes.getDescriptor().findFieldByName("optional_int32");
330       FieldDescriptor repeatedField =
331           TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
332       assertThat(requiredField.getJsonName()).isEqualTo("a");
333       assertThat(optionalField.getJsonName()).isEqualTo("optionalInt32");
334       assertThat(repeatedField.getJsonName()).isEqualTo("repeatedInt32");
335     }
336 
337     @Test
testFieldDescriptorDefault()338     public void testFieldDescriptorDefault() throws Exception {
339       Descriptor d = TestAllTypes.getDescriptor();
340       assertThat(d.findFieldByName("optional_int32").hasDefaultValue()).isFalse();
341       assertThat(d.findFieldByName("optional_int32").getDefaultValue()).isEqualTo(0);
342       assertThat(d.findFieldByName("default_int32").hasDefaultValue()).isTrue();
343       assertThat(d.findFieldByName("default_int32").getDefaultValue()).isEqualTo(41);
344 
345       d = TestExtremeDefaultValues.getDescriptor();
346       assertThat(d.findFieldByName("escaped_bytes").getDefaultValue())
347           .isEqualTo(
348               ByteString.copyFrom(
349                   "\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes(Internal.ISO_8859_1)));
350       assertThat(d.findFieldByName("large_uint32").getDefaultValue()).isEqualTo(-1);
351       assertThat(d.findFieldByName("large_uint64").getDefaultValue()).isEqualTo(-1L);
352     }
353 
354     @Test
testFieldDescriptorLegacyEnumFieldTreatedAsOpen()355     public void testFieldDescriptorLegacyEnumFieldTreatedAsOpen() throws Exception {
356       // Make an open enum definition and message that treats enum fields as open.
357 
358       FileDescriptorProto openEnumFile =
359           FileDescriptorProto.newBuilder()
360               .setName("open_enum.proto")
361               .setSyntax("proto3")
362               .addEnumType(
363                   EnumDescriptorProto.newBuilder()
364                       .setName("TestEnumOpen")
365                       .addValue(
366                           EnumValueDescriptorProto.newBuilder()
367                               .setName("TestEnumOpen_VALUE0")
368                               .setNumber(0)
369                               .build())
370                       .build())
371               .addMessageType(
372                   DescriptorProto.newBuilder()
373                       .setName("TestOpenEnumField")
374                       .addField(
375                           FieldDescriptorProto.newBuilder()
376                               .setName("int_field")
377                               .setNumber(1)
378                               .setType(FieldDescriptorProto.Type.TYPE_INT32)
379                               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
380                               .build())
381                       .addField(
382                           FieldDescriptorProto.newBuilder()
383                               .setName("open_enum")
384                               .setNumber(2)
385                               .setType(FieldDescriptorProto.Type.TYPE_ENUM)
386                               .setTypeName("TestEnumOpen")
387                               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
388                               .build())
389                       .build())
390               .build();
391       FileDescriptor openEnumFileDescriptor =
392           Descriptors.FileDescriptor.buildFrom(openEnumFile, new FileDescriptor[0]);
393       Descriptor openMessage = openEnumFileDescriptor.getMessageTypes().get(0);
394       EnumDescriptor openEnum = openEnumFileDescriptor.findEnumTypeByName("TestEnumOpen");
395       assertThat(openEnum.isClosed()).isFalse();
396       assertThat(openMessage.findFieldByName("int_field").legacyEnumFieldTreatedAsClosed())
397           .isFalse();
398       assertThat(openMessage.findFieldByName("open_enum").legacyEnumFieldTreatedAsClosed())
399           .isFalse();
400     }
401 
402     @Test
testEditionFieldDescriptorLegacyEnumFieldTreatedAsClosedUnknown()403     public void testEditionFieldDescriptorLegacyEnumFieldTreatedAsClosedUnknown() throws Exception {
404       // Make an open enum definition.
405       FileDescriptorProto openEnumFile =
406           FileDescriptorProto.newBuilder()
407               .setName("open_enum.proto")
408               .setSyntax("editions")
409               .setEdition(Edition.EDITION_2023)
410               .addEnumType(
411                   EnumDescriptorProto.newBuilder()
412                       .setName("TestEnumOpen")
413                       .addValue(
414                           EnumValueDescriptorProto.newBuilder()
415                               .setName("TestEnumOpen_VALUE0")
416                               .setNumber(0)
417                               .build())
418                       .build())
419               .build();
420       FileDescriptor openFileDescriptor =
421           Descriptors.FileDescriptor.buildFrom(openEnumFile, new FileDescriptor[0]);
422       EnumDescriptor openEnum = openFileDescriptor.getEnumTypes().get(0);
423       assertThat(openEnum.isClosed()).isFalse();
424 
425       // Create a message that treats enum fields as closed.
426       FileDescriptorProto editionsClosedEnumFile =
427           FileDescriptorProto.newBuilder()
428               .setName("editions_closed_enum_field.proto")
429               .addDependency("open_enum.proto")
430               .setSyntax("editions")
431               .setEdition(Edition.EDITION_2023)
432               .setOptions(
433                   FileOptions.newBuilder()
434                       .setFeatures(
435                           DescriptorProtos.FeatureSet.newBuilder()
436                               .setEnumType(DescriptorProtos.FeatureSet.EnumType.CLOSED)
437                               .build())
438                       .build())
439               .addEnumType(
440                   EnumDescriptorProto.newBuilder()
441                       .setName("TestEnum")
442                       .addValue(
443                           EnumValueDescriptorProto.newBuilder()
444                               .setName("TestEnum_VALUE0")
445                               .setNumber(0)
446                               .build())
447                       .build())
448               .addMessageType(
449                   DescriptorProto.newBuilder()
450                       .setName("TestClosedEnumField")
451                       .addField(
452                           FieldDescriptorProto.newBuilder()
453                               .setName("int_field")
454                               .setNumber(1)
455                               .setType(FieldDescriptorProto.Type.TYPE_INT32)
456                               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
457                               .build())
458                       .addField(
459                           FieldDescriptorProto.newBuilder()
460                               .setName("open_enum")
461                               .setNumber(2)
462                               .setType(FieldDescriptorProto.Type.TYPE_ENUM)
463                               .setTypeName("TestEnumOpen")
464                               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
465                               .setOptions(
466                                   DescriptorProtos.FieldOptions.newBuilder()
467                                       .setFeatures(
468                                           DescriptorProtos.FeatureSet.newBuilder()
469                                               .setExtension(
470                                                   JavaFeaturesProto.java_,
471                                                   JavaFeaturesProto.JavaFeatures.newBuilder()
472                                                       .setLegacyClosedEnum(true)
473                                                       .build())
474                                               .build())
475                                       .build())
476                               .build())
477                       .addField(
478                           FieldDescriptorProto.newBuilder()
479                               .setName("closed_enum")
480                               .setNumber(3)
481                               .setType(FieldDescriptorProto.Type.TYPE_ENUM)
482                               .setTypeName("TestEnum")
483                               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
484                               .build())
485                       .build())
486               .build();
487       // Ensure Java features are in unknown fields.
488       editionsClosedEnumFile =
489           FileDescriptorProto.parseFrom(
490               editionsClosedEnumFile.toByteString(), ExtensionRegistry.getEmptyRegistry());
491       Descriptor editionsClosedMessage =
492           Descriptors.FileDescriptor.buildFrom(
493                   editionsClosedEnumFile, new FileDescriptor[] {openFileDescriptor})
494               .getMessageTypes()
495               .get(0);
496       assertThat(
497               editionsClosedMessage.findFieldByName("int_field").legacyEnumFieldTreatedAsClosed())
498           .isFalse();
499       assertThat(
500               editionsClosedMessage.findFieldByName("closed_enum").legacyEnumFieldTreatedAsClosed())
501           .isTrue();
502       assertThat(
503               editionsClosedMessage.findFieldByName("open_enum").legacyEnumFieldTreatedAsClosed())
504           .isTrue();
505     }
506 
507     @Test
testEditionFieldDescriptorLegacyEnumFieldTreatedAsClosedCustomPool()508     public void testEditionFieldDescriptorLegacyEnumFieldTreatedAsClosedCustomPool()
509         throws Exception {
510 
511       FileDescriptor javaFeaturesDescriptor =
512           Descriptors.FileDescriptor.buildFrom(
513               JavaFeaturesProto.getDescriptor().toProto(),
514               new FileDescriptor[] {DescriptorProtos.getDescriptor()});
515       // Make an open enum definition.
516       FileDescriptorProto openEnumFile =
517           FileDescriptorProto.newBuilder()
518               .setName("open_enum.proto")
519               .setSyntax("editions")
520               .setEdition(Edition.EDITION_2023)
521               .addEnumType(
522                   EnumDescriptorProto.newBuilder()
523                       .setName("TestEnumOpen")
524                       .addValue(
525                           EnumValueDescriptorProto.newBuilder()
526                               .setName("TestEnumOpen_VALUE0")
527                               .setNumber(0)
528                               .build())
529                       .build())
530               .build();
531       FileDescriptor openFileDescriptor =
532           Descriptors.FileDescriptor.buildFrom(openEnumFile, new FileDescriptor[0]);
533       EnumDescriptor openEnum = openFileDescriptor.getEnumTypes().get(0);
534       assertThat(openEnum.isClosed()).isFalse();
535 
536       // Create a message that treats enum fields as closed.
537       FileDescriptorProto editionsClosedEnumFile =
538           FileDescriptorProto.newBuilder()
539               .setName("editions_closed_enum_field.proto")
540               .addDependency("open_enum.proto")
541               .setSyntax("editions")
542               .setEdition(Edition.EDITION_2023)
543               .setOptions(
544                   FileOptions.newBuilder()
545                       .setFeatures(
546                           DescriptorProtos.FeatureSet.newBuilder()
547                               .setEnumType(DescriptorProtos.FeatureSet.EnumType.CLOSED)
548                               .build())
549                       .build())
550               .addEnumType(
551                   EnumDescriptorProto.newBuilder()
552                       .setName("TestEnum")
553                       .addValue(
554                           EnumValueDescriptorProto.newBuilder()
555                               .setName("TestEnum_VALUE0")
556                               .setNumber(0)
557                               .build())
558                       .build())
559               .addMessageType(
560                   DescriptorProto.newBuilder()
561                       .setName("TestClosedEnumField")
562                       .addField(
563                           FieldDescriptorProto.newBuilder()
564                               .setName("int_field")
565                               .setNumber(1)
566                               .setType(FieldDescriptorProto.Type.TYPE_INT32)
567                               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
568                               .build())
569                       .addField(
570                           FieldDescriptorProto.newBuilder()
571                               .setName("open_enum")
572                               .setNumber(2)
573                               .setType(FieldDescriptorProto.Type.TYPE_ENUM)
574                               .setTypeName("TestEnumOpen")
575                               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
576                               .setOptions(
577                                   DescriptorProtos.FieldOptions.newBuilder()
578                                       .setFeatures(
579                                           DescriptorProtos.FeatureSet.newBuilder()
580                                               .setField(
581                                                   // Set extension using custom descriptor
582                                                   javaFeaturesDescriptor.findExtensionByName(
583                                                       JavaFeaturesProto.java_
584                                                           .getDescriptor()
585                                                           .getName()),
586                                                   JavaFeaturesProto.JavaFeatures.newBuilder()
587                                                       .setLegacyClosedEnum(true)
588                                                       .build())
589                                               .build())
590                                       .build())
591                               .build())
592                       .addField(
593                           FieldDescriptorProto.newBuilder()
594                               .setName("closed_enum")
595                               .setNumber(3)
596                               .setType(FieldDescriptorProto.Type.TYPE_ENUM)
597                               .setTypeName("TestEnum")
598                               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
599                               .build())
600                       .build())
601               .build();
602       Descriptor editionsClosedMessage =
603           Descriptors.FileDescriptor.buildFrom(
604                   editionsClosedEnumFile,
605                   new FileDescriptor[] {openFileDescriptor, javaFeaturesDescriptor})
606               .getMessageTypes()
607               .get(0);
608       assertThat(
609               editionsClosedMessage.findFieldByName("int_field").legacyEnumFieldTreatedAsClosed())
610           .isFalse();
611       assertThat(
612               editionsClosedMessage.findFieldByName("closed_enum").legacyEnumFieldTreatedAsClosed())
613           .isTrue();
614       assertThat(
615               editionsClosedMessage.findFieldByName("open_enum").legacyEnumFieldTreatedAsClosed())
616           .isTrue();
617     }
618 
619     @Test
testEnumDescriptor()620     public void testEnumDescriptor() throws Exception {
621       EnumDescriptor enumType = ForeignEnum.getDescriptor();
622       EnumDescriptor nestedType = TestAllTypes.NestedEnum.getDescriptor();
623 
624       assertThat(enumType.getName()).isEqualTo("ForeignEnum");
625       assertThat(enumType.getFullName()).isEqualTo("protobuf_unittest.ForeignEnum");
626       assertThat(enumType.getFile()).isEqualTo(UnittestProto.getDescriptor());
627       assertThat(enumType.isClosed()).isTrue();
628       assertThat(enumType.getContainingType()).isNull();
629       assertThat(enumType.getOptions())
630           .isEqualTo(DescriptorProtos.EnumOptions.getDefaultInstance());
631 
632       assertThat(nestedType.getName()).isEqualTo("NestedEnum");
633       assertThat(nestedType.getFullName()).isEqualTo("protobuf_unittest.TestAllTypes.NestedEnum");
634       assertThat(nestedType.getFile()).isEqualTo(UnittestProto.getDescriptor());
635       assertThat(nestedType.getContainingType()).isEqualTo(TestAllTypes.getDescriptor());
636 
637       EnumValueDescriptor value = ForeignEnum.FOREIGN_FOO.getValueDescriptor();
638       assertThat(enumType.getValues().get(0)).isEqualTo(value);
639       assertThat(value.getName()).isEqualTo("FOREIGN_FOO");
640       assertThat(value.toString()).isEqualTo("FOREIGN_FOO");
641       assertThat(value.getNumber()).isEqualTo(4);
642       assertThat(enumType.findValueByName("FOREIGN_FOO")).isEqualTo(value);
643       assertThat(enumType.findValueByNumber(4)).isEqualTo(value);
644       assertThat(enumType.findValueByName("NO_SUCH_VALUE")).isNull();
645       for (int i = 0; i < enumType.getValues().size(); i++) {
646         assertThat(enumType.getValues().get(i).getIndex()).isEqualTo(i);
647       }
648     }
649 
650     @Test
testServiceDescriptor()651     public void testServiceDescriptor() throws Exception {
652       ServiceDescriptor service = TestService.getDescriptor();
653 
654       assertThat(service.getName()).isEqualTo("TestService");
655       assertThat(service.getFullName()).isEqualTo("protobuf_unittest.TestService");
656       assertThat(service.getFile()).isEqualTo(UnittestProto.getDescriptor());
657 
658       MethodDescriptor fooMethod = service.getMethods().get(0);
659       assertThat(fooMethod.getName()).isEqualTo("Foo");
660       assertThat(fooMethod.getInputType()).isEqualTo(UnittestProto.FooRequest.getDescriptor());
661       assertThat(fooMethod.getOutputType()).isEqualTo(UnittestProto.FooResponse.getDescriptor());
662       assertThat(service.findMethodByName("Foo")).isEqualTo(fooMethod);
663 
664       MethodDescriptor barMethod = service.getMethods().get(1);
665       assertThat(barMethod.getName()).isEqualTo("Bar");
666       assertThat(barMethod.getInputType()).isEqualTo(UnittestProto.BarRequest.getDescriptor());
667       assertThat(barMethod.getOutputType()).isEqualTo(UnittestProto.BarResponse.getDescriptor());
668       assertThat(service.findMethodByName("Bar")).isEqualTo(barMethod);
669 
670       assertThat(service.findMethodByName("NoSuchMethod")).isNull();
671 
672       for (int i = 0; i < service.getMethods().size(); i++) {
673         assertThat(service.getMethods().get(i).getIndex()).isEqualTo(i);
674       }
675     }
676 
677     @Test
testCustomOptions()678     public void testCustomOptions() throws Exception {
679       // Get the descriptor indirectly from a dependent proto class. This is to
680       // ensure that when a proto class is loaded, custom options defined in its
681       // dependencies are also properly initialized.
682       Descriptor descriptor =
683           TestCustomOptions.TestMessageWithCustomOptionsContainer.getDescriptor()
684               .findFieldByName("field")
685               .getMessageType();
686 
687       assertThat(descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1)).isTrue();
688       assertThat(descriptor.getOptions().getExtension(UnittestCustomOptions.messageOpt1))
689           .isEqualTo(Integer.valueOf(-56));
690 
691       FieldDescriptor field = descriptor.findFieldByName("field1");
692       assertThat(field).isNotNull();
693 
694       assertThat(field.getOptions().hasExtension(UnittestCustomOptions.fieldOpt1)).isTrue();
695       assertThat(field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1))
696           .isEqualTo(Long.valueOf(8765432109L));
697 
698       OneofDescriptor oneof = descriptor.getOneofs().get(0);
699       assertThat(oneof).isNotNull();
700 
701       assertThat(oneof.getOptions().hasExtension(UnittestCustomOptions.oneofOpt1)).isTrue();
702       assertThat(oneof.getOptions().getExtension(UnittestCustomOptions.oneofOpt1))
703           .isEqualTo(Integer.valueOf(-99));
704 
705       EnumDescriptor enumType =
706           UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor();
707 
708       assertThat(enumType.getOptions().hasExtension(UnittestCustomOptions.enumOpt1)).isTrue();
709       assertThat(enumType.getOptions().getExtension(UnittestCustomOptions.enumOpt1))
710           .isEqualTo(Integer.valueOf(-789));
711 
712       ServiceDescriptor service =
713           UnittestCustomOptions.TestServiceWithCustomOptions.getDescriptor();
714 
715       assertThat(service.getOptions().hasExtension(UnittestCustomOptions.serviceOpt1)).isTrue();
716       assertThat(service.getOptions().getExtension(UnittestCustomOptions.serviceOpt1))
717           .isEqualTo(Long.valueOf(-9876543210L));
718 
719       MethodDescriptor method = service.findMethodByName("Foo");
720       assertThat(method).isNotNull();
721 
722       assertThat(method.getOptions().hasExtension(UnittestCustomOptions.methodOpt1)).isTrue();
723       assertThat(method.getOptions().getExtension(UnittestCustomOptions.methodOpt1))
724           .isEqualTo(UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2);
725     }
726 
727     @Test
testOptionRetention()728     public void testOptionRetention() throws Exception {
729       // Verify that options with RETENTION_SOURCE are stripped from the
730       // generated descriptors.
731       FileOptions options = UnittestRetention.getDescriptor().getOptions();
732       assertThat(options.hasExtension(UnittestRetention.plainOption)).isTrue();
733       assertThat(options.hasExtension(UnittestRetention.runtimeRetentionOption)).isTrue();
734       assertThat(options.hasExtension(UnittestRetention.sourceRetentionOption)).isFalse();
735     }
736 
737     /** Test that the FieldDescriptor.Type enum is the same as the WireFormat.FieldType enum. */
738     @Test
testFieldTypeTablesMatch()739     public void testFieldTypeTablesMatch() throws Exception {
740       FieldDescriptor.Type[] values1 = FieldDescriptor.Type.values();
741       WireFormat.FieldType[] values2 = WireFormat.FieldType.values();
742 
743       assertThat(values1).hasLength(values2.length);
744 
745       for (int i = 0; i < values1.length; i++) {
746         assertThat(values1[i].toString()).isEqualTo(values2[i].toString());
747       }
748     }
749 
750     /** Test that the FieldDescriptor.JavaType enum is the same as the WireFormat.JavaType enum. */
751     @Test
testJavaTypeTablesMatch()752     public void testJavaTypeTablesMatch() throws Exception {
753       FieldDescriptor.JavaType[] values1 = FieldDescriptor.JavaType.values();
754       WireFormat.JavaType[] values2 = WireFormat.JavaType.values();
755 
756       assertThat(values1).hasLength(values2.length);
757 
758       for (int i = 0; i < values1.length; i++) {
759         assertThat(values1[i].toString()).isEqualTo(values2[i].toString());
760       }
761     }
762 
763     @Test
testEnormousDescriptor()764     public void testEnormousDescriptor() throws Exception {
765       // The descriptor for this file is larger than 64k, yet it did not cause
766       // a compiler error due to an over-long string literal.
767       assertThat(UnittestEnormousDescriptor.getDescriptor().toProto().getSerializedSize())
768           .isGreaterThan(65536);
769     }
770 
771     /** Tests that the DescriptorValidationException works as intended. */
772     @Test
testDescriptorValidatorException()773     public void testDescriptorValidatorException() throws Exception {
774       FileDescriptorProto fileDescriptorProto =
775           FileDescriptorProto.newBuilder()
776               .setName("foo.proto")
777               .addMessageType(
778                   DescriptorProto.newBuilder()
779                       .setName("Foo")
780                       .addField(
781                           FieldDescriptorProto.newBuilder()
782                               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
783                               .setType(FieldDescriptorProto.Type.TYPE_INT32)
784                               .setName("foo")
785                               .setNumber(1)
786                               .setDefaultValue("invalid")
787                               .build())
788                       .build())
789               .build();
790       try {
791         Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]);
792         assertWithMessage("DescriptorValidationException expected").fail();
793       } catch (DescriptorValidationException e) {
794         // Expected; check that the error message contains some useful hints
795         assertThat(e).hasMessageThat().contains("foo");
796         assertThat(e).hasMessageThat().contains("Foo");
797         assertThat(e).hasMessageThat().contains("invalid");
798         assertThat(e).hasCauseThat().isInstanceOf(NumberFormatException.class);
799         assertThat(e).hasCauseThat().hasMessageThat().contains("invalid");
800       }
801     }
802 
803     /** Tests that parsing an unknown enum throws an exception */
804     @Test
testParseUnknownEnum()805     public void testParseUnknownEnum() {
806       FieldDescriptorProto.Builder field =
807           FieldDescriptorProto.newBuilder()
808               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
809               .setTypeName("UnknownEnum")
810               .setType(FieldDescriptorProto.Type.TYPE_ENUM)
811               .setName("bar")
812               .setNumber(1);
813       DescriptorProto.Builder messageType =
814           DescriptorProto.newBuilder().setName("Foo").addField(field);
815       FileDescriptorProto fooProto =
816           FileDescriptorProto.newBuilder()
817               .setName("foo.proto")
818               .addDependency("bar.proto")
819               .addMessageType(messageType)
820               .build();
821       try {
822         Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0], true);
823         assertWithMessage("DescriptorValidationException expected").fail();
824       } catch (DescriptorValidationException expected) {
825         assertThat(expected.getMessage()).contains("\"UnknownEnum\" is not an enum type.");
826       }
827     }
828 
829     /**
830      * Tests the translate/crosslink for an example where a message field's name and type name are
831      * the same.
832      */
833     @Test
testDescriptorComplexCrosslink()834     public void testDescriptorComplexCrosslink() throws Exception {
835       FileDescriptorProto fileDescriptorProto =
836           FileDescriptorProto.newBuilder()
837               .setName("foo.proto")
838               .addMessageType(
839                   DescriptorProto.newBuilder()
840                       .setName("Foo")
841                       .addField(
842                           FieldDescriptorProto.newBuilder()
843                               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
844                               .setType(FieldDescriptorProto.Type.TYPE_INT32)
845                               .setName("foo")
846                               .setNumber(1)
847                               .build())
848                       .build())
849               .addMessageType(
850                   DescriptorProto.newBuilder()
851                       .setName("Bar")
852                       .addField(
853                           FieldDescriptorProto.newBuilder()
854                               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
855                               .setTypeName("Foo")
856                               .setName("Foo")
857                               .setNumber(1)
858                               .build())
859                       .build())
860               .build();
861       // translate and crosslink
862       FileDescriptor file =
863           Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]);
864       // verify resulting descriptors
865       assertThat(file).isNotNull();
866       List<Descriptor> msglist = file.getMessageTypes();
867       assertThat(msglist).isNotNull();
868       assertThat(msglist).hasSize(2);
869       boolean barFound = false;
870       for (Descriptor desc : msglist) {
871         if (desc.getName().equals("Bar")) {
872           barFound = true;
873           assertThat(desc.getFields()).isNotNull();
874           List<FieldDescriptor> fieldlist = desc.getFields();
875           assertThat(fieldlist).isNotNull();
876           assertThat(fieldlist).hasSize(1);
877           assertThat(fieldlist.get(0).getType()).isSameInstanceAs(FieldDescriptor.Type.MESSAGE);
878           assertThat(fieldlist.get(0).getMessageType().getName().equals("Foo")).isTrue();
879         }
880       }
881       assertThat(barFound).isTrue();
882     }
883 
884     @Test
testDependencyOrder()885     public void testDependencyOrder() throws Exception {
886       FileDescriptorProto fooProto = FileDescriptorProto.newBuilder().setName("foo.proto").build();
887       FileDescriptorProto barProto =
888           FileDescriptorProto.newBuilder().setName("bar.proto").addDependency("foo.proto").build();
889       FileDescriptorProto bazProto =
890           FileDescriptorProto.newBuilder()
891               .setName("baz.proto")
892               .addDependency("foo.proto")
893               .addDependency("bar.proto")
894               .addPublicDependency(0)
895               .addPublicDependency(1)
896               .build();
897       FileDescriptor fooFile =
898           Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
899       FileDescriptor barFile =
900           Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[] {fooFile});
901 
902       // Items in the FileDescriptor array can be in any order.
903       FileDescriptor unused1 =
904           Descriptors.FileDescriptor.buildFrom(bazProto, new FileDescriptor[] {fooFile, barFile});
905       FileDescriptor unused2 =
906           Descriptors.FileDescriptor.buildFrom(bazProto, new FileDescriptor[] {barFile, fooFile});
907     }
908 
909     @Test
testInvalidPublicDependency()910     public void testInvalidPublicDependency() throws Exception {
911       FileDescriptorProto fooProto = FileDescriptorProto.newBuilder().setName("foo.proto").build();
912       FileDescriptorProto barProto =
913           FileDescriptorProto.newBuilder()
914               .setName("boo.proto")
915               .addDependency("foo.proto")
916               .addPublicDependency(1) // Error, should be 0.
917               .build();
918       FileDescriptor fooFile =
919           Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
920       try {
921         Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[] {fooFile});
922         assertWithMessage("DescriptorValidationException expected").fail();
923       } catch (DescriptorValidationException e) {
924         assertThat(e).hasMessageThat().contains("Invalid public dependency index.");
925       }
926     }
927 
928     @Test
testUnknownFieldsDenied()929     public void testUnknownFieldsDenied() throws Exception {
930       FileDescriptorProto fooProto =
931           FileDescriptorProto.newBuilder()
932               .setName("foo.proto")
933               .addMessageType(
934                   DescriptorProto.newBuilder()
935                       .setName("Foo")
936                       .addField(
937                           FieldDescriptorProto.newBuilder()
938                               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
939                               .setTypeName("Bar")
940                               .setName("bar")
941                               .setNumber(1)))
942               .build();
943 
944       try {
945         Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
946         assertWithMessage("DescriptorValidationException expected").fail();
947       } catch (DescriptorValidationException e) {
948         assertThat(e).hasMessageThat().contains("Bar");
949         assertThat(e).hasMessageThat().contains("is not defined");
950       }
951     }
952 
953     @Test
testUnknownFieldsAllowed()954     public void testUnknownFieldsAllowed() throws Exception {
955       FileDescriptorProto fooProto =
956           FileDescriptorProto.newBuilder()
957               .setName("foo.proto")
958               .addDependency("bar.proto")
959               .addMessageType(
960                   DescriptorProto.newBuilder()
961                       .setName("Foo")
962                       .addField(
963                           FieldDescriptorProto.newBuilder()
964                               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
965                               .setTypeName("Bar")
966                               .setName("bar")
967                               .setNumber(1)))
968               .build();
969       FileDescriptor unused =
970           Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0], true);
971     }
972 
973     @Test
testHiddenDependency()974     public void testHiddenDependency() throws Exception {
975       FileDescriptorProto barProto =
976           FileDescriptorProto.newBuilder()
977               .setName("bar.proto")
978               .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
979               .build();
980       FileDescriptorProto forwardProto =
981           FileDescriptorProto.newBuilder()
982               .setName("forward.proto")
983               .addDependency("bar.proto")
984               .build();
985       FileDescriptorProto fooProto =
986           FileDescriptorProto.newBuilder()
987               .setName("foo.proto")
988               .addDependency("forward.proto")
989               .addMessageType(
990                   DescriptorProto.newBuilder()
991                       .setName("Foo")
992                       .addField(
993                           FieldDescriptorProto.newBuilder()
994                               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
995                               .setTypeName("Bar")
996                               .setName("bar")
997                               .setNumber(1)))
998               .build();
999       FileDescriptor barFile =
1000           Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[0]);
1001       FileDescriptor forwardFile =
1002           Descriptors.FileDescriptor.buildFrom(forwardProto, new FileDescriptor[] {barFile});
1003 
1004       try {
1005         FileDescriptor unused =
1006             Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[] {forwardFile});
1007         assertWithMessage("DescriptorValidationException expected").fail();
1008       } catch (DescriptorValidationException e) {
1009         assertThat(e).hasMessageThat().contains("Bar");
1010         assertThat(e).hasMessageThat().contains("is not defined");
1011       }
1012     }
1013 
1014     @Test
testPublicDependency()1015     public void testPublicDependency() throws Exception {
1016       FileDescriptorProto barProto =
1017           FileDescriptorProto.newBuilder()
1018               .setName("bar.proto")
1019               .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
1020               .build();
1021       FileDescriptorProto forwardProto =
1022           FileDescriptorProto.newBuilder()
1023               .setName("forward.proto")
1024               .addDependency("bar.proto")
1025               .addPublicDependency(0)
1026               .build();
1027       FileDescriptorProto fooProto =
1028           FileDescriptorProto.newBuilder()
1029               .setName("foo.proto")
1030               .addDependency("forward.proto")
1031               .addMessageType(
1032                   DescriptorProto.newBuilder()
1033                       .setName("Foo")
1034                       .addField(
1035                           FieldDescriptorProto.newBuilder()
1036                               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
1037                               .setTypeName("Bar")
1038                               .setName("bar")
1039                               .setNumber(1)))
1040               .build();
1041       FileDescriptor barFile =
1042           Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[0]);
1043       FileDescriptor forwardFile =
1044           Descriptors.FileDescriptor.buildFrom(forwardProto, new FileDescriptor[] {barFile});
1045       FileDescriptor unused =
1046           Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[] {forwardFile});
1047     }
1048 
1049     /** Tests the translate/crosslink for an example with a more complex namespace referencing. */
1050     @Test
testComplexNamespacePublicDependency()1051     public void testComplexNamespacePublicDependency() throws Exception {
1052       FileDescriptorProto fooProto =
1053           FileDescriptorProto.newBuilder()
1054               .setName("bar.proto")
1055               .setPackage("a.b.c.d.bar.shared")
1056               .addEnumType(
1057                   EnumDescriptorProto.newBuilder()
1058                       .setName("MyEnum")
1059                       .addValue(EnumValueDescriptorProto.newBuilder().setName("BLAH").setNumber(1)))
1060               .build();
1061       FileDescriptorProto barProto =
1062           FileDescriptorProto.newBuilder()
1063               .setName("foo.proto")
1064               .addDependency("bar.proto")
1065               .setPackage("a.b.c.d.foo.shared")
1066               .addMessageType(
1067                   DescriptorProto.newBuilder()
1068                       .setName("MyMessage")
1069                       .addField(
1070                           FieldDescriptorProto.newBuilder()
1071                               .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
1072                               .setTypeName("bar.shared.MyEnum")
1073                               .setName("MyField")
1074                               .setNumber(1)))
1075               .build();
1076       // translate and crosslink
1077       FileDescriptor fooFile =
1078           Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
1079       FileDescriptor barFile =
1080           Descriptors.FileDescriptor.buildFrom(barProto, new FileDescriptor[] {fooFile});
1081       // verify resulting descriptors
1082       assertThat(barFile).isNotNull();
1083       List<Descriptor> msglist = barFile.getMessageTypes();
1084       assertThat(msglist).isNotNull();
1085       assertThat(msglist).hasSize(1);
1086       Descriptor desc = msglist.get(0);
1087       if (desc.getName().equals("MyMessage")) {
1088         assertThat(desc.getFields()).isNotNull();
1089         List<FieldDescriptor> fieldlist = desc.getFields();
1090         assertThat(fieldlist).isNotNull();
1091         assertThat(fieldlist).hasSize(1);
1092         FieldDescriptor field = fieldlist.get(0);
1093         assertThat(field.getType()).isSameInstanceAs(FieldDescriptor.Type.ENUM);
1094         assertThat(field.getEnumType().getName().equals("MyEnum")).isTrue();
1095         assertThat(field.getEnumType().getFile().getName().equals("bar.proto")).isTrue();
1096         assertThat(field.getEnumType().getFile().getPackage().equals("a.b.c.d.bar.shared"))
1097             .isTrue();
1098       }
1099     }
1100 
1101     @Test
testOneofDescriptor()1102     public void testOneofDescriptor() throws Exception {
1103       Descriptor messageType = TestAllTypes.getDescriptor();
1104       FieldDescriptor field = messageType.findFieldByName("oneof_nested_message");
1105       OneofDescriptor oneofDescriptor = field.getContainingOneof();
1106       assertThat(oneofDescriptor).isNotNull();
1107       assertThat(messageType.getOneofs().get(0)).isSameInstanceAs(oneofDescriptor);
1108       assertThat(oneofDescriptor.getName()).isEqualTo("oneof_field");
1109 
1110       assertThat(oneofDescriptor.getFieldCount()).isEqualTo(7);
1111       assertThat(field).isSameInstanceAs(oneofDescriptor.getField(1));
1112 
1113       assertThat(oneofDescriptor.getFields()).hasSize(7);
1114       assertThat(field).isEqualTo(oneofDescriptor.getFields().get(1));
1115     }
1116 
1117     @Test
testMessageDescriptorExtensions()1118     public void testMessageDescriptorExtensions() throws Exception {
1119       assertThat(TestAllTypes.getDescriptor().isExtendable()).isFalse();
1120       assertThat(TestAllExtensions.getDescriptor().isExtendable()).isTrue();
1121       assertThat(TestMultipleExtensionRanges.getDescriptor().isExtendable()).isTrue();
1122 
1123       assertThat(TestAllTypes.getDescriptor().isExtensionNumber(3)).isFalse();
1124       assertThat(TestAllExtensions.getDescriptor().isExtensionNumber(3)).isTrue();
1125       assertThat(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(42)).isTrue();
1126       assertThat(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(43)).isFalse();
1127       assertThat(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4142)).isFalse();
1128       assertThat(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4143)).isTrue();
1129     }
1130 
1131     @Test
testReservedFields()1132     public void testReservedFields() {
1133       Descriptor d = TestReservedFields.getDescriptor();
1134       assertThat(d.isReservedNumber(2)).isTrue();
1135       assertThat(d.isReservedNumber(8)).isFalse();
1136       assertThat(d.isReservedNumber(9)).isTrue();
1137       assertThat(d.isReservedNumber(10)).isTrue();
1138       assertThat(d.isReservedNumber(11)).isTrue();
1139       assertThat(d.isReservedNumber(12)).isFalse();
1140       assertThat(d.isReservedName("foo")).isFalse();
1141       assertThat(d.isReservedName("bar")).isTrue();
1142       assertThat(d.isReservedName("baz")).isTrue();
1143     }
1144 
1145     @Test
testReservedEnumFields()1146     public void testReservedEnumFields() {
1147       EnumDescriptor d = TestReservedEnumFields.getDescriptor();
1148       assertThat(d.isReservedNumber(2)).isTrue();
1149       assertThat(d.isReservedNumber(8)).isFalse();
1150       assertThat(d.isReservedNumber(9)).isTrue();
1151       assertThat(d.isReservedNumber(10)).isTrue();
1152       assertThat(d.isReservedNumber(11)).isTrue();
1153       assertThat(d.isReservedNumber(12)).isFalse();
1154       assertThat(d.isReservedName("foo")).isFalse();
1155       assertThat(d.isReservedName("bar")).isTrue();
1156       assertThat(d.isReservedName("baz")).isTrue();
1157     }
1158 
1159     @Test
testToString()1160     public void testToString() {
1161       assertThat(
1162               UnittestProto.TestAllTypes.getDescriptor()
1163                   .findFieldByNumber(UnittestProto.TestAllTypes.OPTIONAL_UINT64_FIELD_NUMBER)
1164                   .toString())
1165           .isEqualTo("protobuf_unittest.TestAllTypes.optional_uint64");
1166     }
1167 
1168     @Test
testPackedEnumField()1169     public void testPackedEnumField() throws Exception {
1170       FileDescriptorProto fileDescriptorProto =
1171           FileDescriptorProto.newBuilder()
1172               .setName("foo.proto")
1173               .addEnumType(
1174                   EnumDescriptorProto.newBuilder()
1175                       .setName("Enum")
1176                       .addValue(
1177                           EnumValueDescriptorProto.newBuilder().setName("FOO").setNumber(1).build())
1178                       .build())
1179               .addMessageType(
1180                   DescriptorProto.newBuilder()
1181                       .setName("Message")
1182                       .addField(
1183                           FieldDescriptorProto.newBuilder()
1184                               .setName("foo")
1185                               .setTypeName("Enum")
1186                               .setNumber(1)
1187                               .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
1188                               .setOptions(
1189                                   DescriptorProtos.FieldOptions.newBuilder()
1190                                       .setPacked(true)
1191                                       .build())
1192                               .build())
1193                       .build())
1194               .build();
1195       FileDescriptor unused =
1196           Descriptors.FileDescriptor.buildFrom(fileDescriptorProto, new FileDescriptor[0]);
1197     }
1198 
1199     @Test
testFieldJsonName()1200     public void testFieldJsonName() throws Exception {
1201       Descriptor d = TestJsonName.getDescriptor();
1202       assertThat(d.getFields()).hasSize(7);
1203       assertThat(d.getFields().get(0).getJsonName()).isEqualTo("fieldName1");
1204       assertThat(d.getFields().get(1).getJsonName()).isEqualTo("fieldName2");
1205       assertThat(d.getFields().get(2).getJsonName()).isEqualTo("FieldName3");
1206       assertThat(d.getFields().get(3).getJsonName()).isEqualTo("FieldName4");
1207       assertThat(d.getFields().get(4).getJsonName()).isEqualTo("FIELDNAME5");
1208       assertThat(d.getFields().get(5).getJsonName()).isEqualTo("@type");
1209       assertThat(d.getFields().get(6).getJsonName()).isEqualTo("fieldname7");
1210     }
1211 
1212     @Test
testExtensionRenamesKeywords()1213     public void testExtensionRenamesKeywords() {
1214       assertThat(NonNestedExtension.if_).isInstanceOf(GeneratedMessage.GeneratedExtension.class);
1215       assertThat(NestedExtension.MyNestedExtension.default_)
1216           .isInstanceOf(GeneratedMessage.GeneratedExtension.class);
1217 
1218       NonNestedExtension.MessageToBeExtended msg =
1219           NonNestedExtension.MessageToBeExtended.newBuilder()
1220               .setExtension(NonNestedExtension.if_, "!fi")
1221               .build();
1222       assertThat(msg.getExtension(NonNestedExtension.if_)).isEqualTo("!fi");
1223 
1224       msg =
1225           NonNestedExtension.MessageToBeExtended.newBuilder()
1226               .setExtension(NestedExtension.MyNestedExtension.default_, 8)
1227               .build();
1228       assertThat(msg.getExtension(NestedExtension.MyNestedExtension.default_).intValue())
1229           .isEqualTo(8);
1230     }
1231 
1232     @Test
testDefaultDescriptorExtensionRange()1233     public void testDefaultDescriptorExtensionRange() throws Exception {
1234       assertThat(new Descriptor("default").isExtensionNumber(1)).isTrue();
1235     }
1236 
1237     @Test
testGetOptionsStripsFeatures()1238     public void testGetOptionsStripsFeatures() {
1239       FieldDescriptor field =
1240           UnittestLegacyFeatures.TestEditionsMessage.getDescriptor()
1241               .findFieldByName("required_field");
1242       assertThat(field.getOptions().hasFeatures()).isFalse();
1243     }
1244 
1245     @Test
testLegacyRequiredTransform()1246     public void testLegacyRequiredTransform() {
1247       Descriptor descriptor = UnittestLegacyFeatures.TestEditionsMessage.getDescriptor();
1248       assertThat(descriptor.findFieldByName("required_field").isRequired()).isTrue();
1249     }
1250 
1251     @Test
testLegacyGroupTransform()1252     public void testLegacyGroupTransform() {
1253       Descriptor descriptor = UnittestLegacyFeatures.TestEditionsMessage.getDescriptor();
1254       assertThat(descriptor.findFieldByName("delimited_field").getType())
1255           .isEqualTo(FieldDescriptor.Type.GROUP);
1256     }
1257 
1258     @Test
testLegacyInferRequired()1259     public void testLegacyInferRequired() throws Exception {
1260       FileDescriptor file =
1261           FileDescriptor.buildFrom(
1262               FileDescriptorProto.newBuilder()
1263                   .setName("some/filename/some.proto")
1264                   .setSyntax("proto2")
1265                   .addMessageType(
1266                       DescriptorProto.newBuilder()
1267                           .setName("Foo")
1268                           .addField(
1269                               FieldDescriptorProto.newBuilder()
1270                                   .setName("a")
1271                                   .setNumber(1)
1272                                   .setType(FieldDescriptorProto.Type.TYPE_INT32)
1273                                   .setLabel(FieldDescriptorProto.Label.LABEL_REQUIRED)
1274                                   .build())
1275                           .build())
1276                   .build(),
1277               new FileDescriptor[0]);
1278       FieldDescriptor field = file.findMessageTypeByName("Foo").findFieldByName("a");
1279       assertThat(field.features.getFieldPresence())
1280           .isEqualTo(DescriptorProtos.FeatureSet.FieldPresence.LEGACY_REQUIRED);
1281     }
1282 
1283     @Test
testLegacyInferGroup()1284     public void testLegacyInferGroup() throws Exception {
1285       FileDescriptor file =
1286           FileDescriptor.buildFrom(
1287               FileDescriptorProto.newBuilder()
1288                   .setName("some/filename/some.proto")
1289                   .setSyntax("proto2")
1290                   .addMessageType(
1291                       DescriptorProto.newBuilder()
1292                           .setName("Foo")
1293                           .addNestedType(
1294                               DescriptorProto.newBuilder().setName("OptionalGroup").build())
1295                           .addField(
1296                               FieldDescriptorProto.newBuilder()
1297                                   .setName("optionalgroup")
1298                                   .setNumber(1)
1299                                   .setType(FieldDescriptorProto.Type.TYPE_GROUP)
1300                                   .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
1301                                   .setTypeName("Foo.OptionalGroup")
1302                                   .build())
1303                           .build())
1304                   .build(),
1305               new FileDescriptor[0]);
1306       FieldDescriptor field = file.findMessageTypeByName("Foo").findFieldByName("optionalgroup");
1307       assertThat(field.features.getMessageEncoding())
1308           .isEqualTo(DescriptorProtos.FeatureSet.MessageEncoding.DELIMITED);
1309     }
1310 
1311     @Test
testLegacyInferProto2Packed()1312     public void testLegacyInferProto2Packed() throws Exception {
1313       FileDescriptor file =
1314           FileDescriptor.buildFrom(
1315               FileDescriptorProto.newBuilder()
1316                   .setName("some/filename/some.proto")
1317                   .setSyntax("proto2")
1318                   .addMessageType(
1319                       DescriptorProto.newBuilder()
1320                           .setName("Foo")
1321                           .addField(
1322                               FieldDescriptorProto.newBuilder()
1323                                   .setName("a")
1324                                   .setNumber(1)
1325                                   .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
1326                                   .setType(FieldDescriptorProto.Type.TYPE_INT32)
1327                                   .setOptions(FieldOptions.newBuilder().setPacked(true).build())
1328                                   .build())
1329                           .build())
1330                   .build(),
1331               new FileDescriptor[0]);
1332       FieldDescriptor field = file.findMessageTypeByName("Foo").findFieldByName("a");
1333       assertThat(field.features.getRepeatedFieldEncoding())
1334           .isEqualTo(DescriptorProtos.FeatureSet.RepeatedFieldEncoding.PACKED);
1335     }
1336 
1337     @Test
testLegacyInferProto3Expanded()1338     public void testLegacyInferProto3Expanded() throws Exception {
1339       FileDescriptor file =
1340           FileDescriptor.buildFrom(
1341               FileDescriptorProto.newBuilder()
1342                   .setName("some/filename/some.proto")
1343                   .setSyntax("proto3")
1344                   .addMessageType(
1345                       DescriptorProto.newBuilder()
1346                           .setName("Foo")
1347                           .addField(
1348                               FieldDescriptorProto.newBuilder()
1349                                   .setName("a")
1350                                   .setNumber(1)
1351                                   .setType(FieldDescriptorProto.Type.TYPE_INT32)
1352                                   .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
1353                                   .setOptions(FieldOptions.newBuilder().setPacked(false).build())
1354                                   .build())
1355                           .build())
1356                   .build(),
1357               new FileDescriptor[0]);
1358       FieldDescriptor field = file.findMessageTypeByName("Foo").findFieldByName("a");
1359       assertThat(field.features.getRepeatedFieldEncoding())
1360           .isEqualTo(DescriptorProtos.FeatureSet.RepeatedFieldEncoding.EXPANDED);
1361     }
1362 
1363     @Test
testLegacyInferProto2Utf8Validation()1364     public void testLegacyInferProto2Utf8Validation() throws Exception {
1365       FileDescriptor file =
1366           FileDescriptor.buildFrom(
1367               FileDescriptorProto.newBuilder()
1368                   .setName("some/filename/some.proto")
1369                   .setPackage("protobuf_unittest")
1370                   .setSyntax("proto2")
1371                   .setOptions(FileOptions.newBuilder().setJavaStringCheckUtf8(true))
1372                   .build(),
1373               new FileDescriptor[0]);
1374       assertThat(file.features.getExtension(JavaFeaturesProto.java_).getUtf8Validation())
1375           .isEqualTo(JavaFeaturesProto.JavaFeatures.Utf8Validation.VERIFY);
1376     }
1377 
1378     @Test
testProto2Defaults()1379     public void testProto2Defaults() throws Exception {
1380       FileDescriptor proto2File =
1381           FileDescriptor.buildFrom(
1382               FileDescriptorProto.newBuilder()
1383                   .setName("some/filename/some.proto")
1384                   .setPackage("protobuf_unittest")
1385                   .setSyntax("proto2")
1386                   .build(),
1387               new FileDescriptor[0]);
1388       DescriptorProtos.FeatureSet features = proto2File.features;
1389       assertThat(features.getFieldPresence())
1390           .isEqualTo(DescriptorProtos.FeatureSet.FieldPresence.EXPLICIT);
1391       assertThat(features.getEnumType()).isEqualTo(DescriptorProtos.FeatureSet.EnumType.CLOSED);
1392       assertThat(features.getRepeatedFieldEncoding())
1393           .isEqualTo(DescriptorProtos.FeatureSet.RepeatedFieldEncoding.EXPANDED);
1394       assertThat(features.getUtf8Validation())
1395           .isEqualTo(DescriptorProtos.FeatureSet.Utf8Validation.NONE);
1396       assertThat(features.getMessageEncoding())
1397           .isEqualTo(DescriptorProtos.FeatureSet.MessageEncoding.LENGTH_PREFIXED);
1398       assertThat(features.getJsonFormat())
1399           .isEqualTo(DescriptorProtos.FeatureSet.JsonFormat.LEGACY_BEST_EFFORT);
1400 
1401       assertThat(features.getExtension(JavaFeaturesProto.java_).getLegacyClosedEnum()).isTrue();
1402       assertThat(features.getExtension(JavaFeaturesProto.java_).getUtf8Validation())
1403           .isEqualTo(JavaFeaturesProto.JavaFeatures.Utf8Validation.DEFAULT);
1404     }
1405 
1406     @Test
testProto3Defaults()1407     public void testProto3Defaults() throws Exception {
1408       FileDescriptor proto3File =
1409           FileDescriptor.buildFrom(
1410               FileDescriptorProto.newBuilder()
1411                   .setName("some/filename/some.proto")
1412                   .setPackage("proto3_unittest")
1413                   .setSyntax("proto3")
1414                   .build(),
1415               new FileDescriptor[0]);
1416       DescriptorProtos.FeatureSet features = proto3File.features;
1417       assertThat(features.getFieldPresence())
1418           .isEqualTo(DescriptorProtos.FeatureSet.FieldPresence.IMPLICIT);
1419       assertThat(features.getEnumType()).isEqualTo(DescriptorProtos.FeatureSet.EnumType.OPEN);
1420       assertThat(features.getRepeatedFieldEncoding())
1421           .isEqualTo(DescriptorProtos.FeatureSet.RepeatedFieldEncoding.PACKED);
1422       assertThat(features.getUtf8Validation())
1423           .isEqualTo(DescriptorProtos.FeatureSet.Utf8Validation.VERIFY);
1424       assertThat(features.getMessageEncoding())
1425           .isEqualTo(DescriptorProtos.FeatureSet.MessageEncoding.LENGTH_PREFIXED);
1426 
1427       assertThat(features.getExtension(JavaFeaturesProto.java_).getLegacyClosedEnum()).isFalse();
1428       assertThat(features.getExtension(JavaFeaturesProto.java_).getUtf8Validation())
1429           .isEqualTo(JavaFeaturesProto.JavaFeatures.Utf8Validation.DEFAULT);
1430     }
1431 
1432     @Test
testProto3ExtensionPresence()1433     public void testProto3ExtensionPresence() {
1434       FileDescriptorProto.Builder file = FileDescriptorProto.newBuilder();
1435 
1436       assertThat(file.getOptions().hasExtension(Proto3FileExtensions.singularInt)).isFalse();
1437       assertThat(file.getOptions().getExtension(Proto3FileExtensions.singularInt)).isEqualTo(0);
1438 
1439       file.getOptionsBuilder().setExtension(Proto3FileExtensions.singularInt, 1);
1440 
1441       assertThat(file.getOptions().hasExtension(Proto3FileExtensions.singularInt)).isTrue();
1442       assertThat(file.getOptions().getExtension(Proto3FileExtensions.singularInt)).isEqualTo(1);
1443     }
1444 
1445     @Test
testProto3ExtensionHasPresence()1446     public void testProto3ExtensionHasPresence() {
1447       assertThat(Proto3FileExtensions.singularInt.getDescriptor().hasPresence()).isTrue();
1448       assertThat(Proto3FileExtensions.repeatedInt.getDescriptor().hasPresence()).isFalse();
1449     }
1450   }
1451 
1452   public static class FeatureInheritanceTest {
1453     FileDescriptorProto.Builder fileProto;
1454     FieldDescriptorProto.Builder topExtensionProto;
1455     EnumDescriptorProto.Builder topEnumProto;
1456     EnumValueDescriptorProto.Builder enumValueProto;
1457     DescriptorProto.Builder topMessageProto;
1458     FieldDescriptorProto.Builder fieldProto;
1459     FieldDescriptorProto.Builder nestedExtensionProto;
1460     DescriptorProto.Builder nestedMessageProto;
1461     EnumDescriptorProto.Builder nestedEnumProto;
1462     OneofDescriptorProto.Builder oneofProto;
1463     FieldDescriptorProto.Builder oneofFieldProto;
1464     ServiceDescriptorProto.Builder serviceProto;
1465     MethodDescriptorProto.Builder methodProto;
1466 
1467     @Before
setUp()1468     public void setUp() {
1469       FeatureSetDefaults.Builder defaults = Descriptors.getJavaEditionDefaults().toBuilder();
1470       for (FeatureSetEditionDefault.Builder editionDefaults : defaults.getDefaultsBuilderList()) {
1471         setTestFeature(editionDefaults.getOverridableFeaturesBuilder(), 1);
1472       }
1473       Descriptors.setTestJavaEditionDefaults(defaults.build());
1474 
1475       this.fileProto =
1476           DescriptorProtos.FileDescriptorProto.newBuilder()
1477               .setName("some/filename/some.proto")
1478               .setPackage("protobuf_unittest")
1479               .setEdition(DescriptorProtos.Edition.EDITION_2023)
1480               .setSyntax("editions");
1481 
1482       this.topExtensionProto =
1483           this.fileProto
1484               .addExtensionBuilder()
1485               .setName("top_extension")
1486               .setNumber(10)
1487               .setType(FieldDescriptorProto.Type.TYPE_INT32)
1488               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
1489               .setExtendee(".protobuf_unittest.TopMessage");
1490 
1491       this.topEnumProto = this.fileProto.addEnumTypeBuilder().setName("TopEnum");
1492       this.enumValueProto = this.topEnumProto.addValueBuilder().setName("TOP_VALUE").setNumber(0);
1493 
1494       this.topMessageProto =
1495           this.fileProto
1496               .addMessageTypeBuilder()
1497               .setName("TopMessage")
1498               .addExtensionRange(ExtensionRange.newBuilder().setStart(10).setEnd(20).build());
1499 
1500       this.fieldProto =
1501           this.topMessageProto
1502               .addFieldBuilder()
1503               .setName("field")
1504               .setNumber(1)
1505               .setType(FieldDescriptorProto.Type.TYPE_INT32)
1506               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL);
1507       this.nestedExtensionProto =
1508           this.topMessageProto
1509               .addExtensionBuilder()
1510               .setName("nested_extension")
1511               .setNumber(11)
1512               .setType(FieldDescriptorProto.Type.TYPE_INT32)
1513               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
1514               .setExtendee(".protobuf_unittest.TopMessage");
1515       this.nestedMessageProto =
1516           this.topMessageProto.addNestedTypeBuilder().setName("NestedMessage");
1517       this.nestedEnumProto =
1518           this.topMessageProto
1519               .addEnumTypeBuilder()
1520               .setName("NestedEnum")
1521               .addValue(EnumValueDescriptorProto.newBuilder().setName("NESTED_VALUE").setNumber(0));
1522       this.oneofProto = this.topMessageProto.addOneofDeclBuilder().setName("Oneof");
1523       this.oneofFieldProto =
1524           this.topMessageProto
1525               .addFieldBuilder()
1526               .setName("oneof_field")
1527               .setNumber(2)
1528               .setType(FieldDescriptorProto.Type.TYPE_INT32)
1529               .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
1530               .setOneofIndex(0);
1531       this.serviceProto = this.fileProto.addServiceBuilder().setName("TestService");
1532       this.methodProto =
1533           this.serviceProto
1534               .addMethodBuilder()
1535               .setName("CallMethod")
1536               .setInputType(".protobuf_unittest.TopMessage")
1537               .setOutputType(".protobuf_unittest.TopMessage");
1538     }
1539 
setTestFeature(DescriptorProtos.FeatureSet.Builder features, int value)1540     void setTestFeature(DescriptorProtos.FeatureSet.Builder features, int value) {
1541       features.setExtension(
1542           UnittestFeatures.test,
1543           features.getExtension(UnittestFeatures.test).toBuilder()
1544               .setMultipleFeature(UnittestFeatures.EnumFeature.forNumber(value))
1545               .build());
1546     }
1547 
getTestFeature(DescriptorProtos.FeatureSet features)1548     int getTestFeature(DescriptorProtos.FeatureSet features) {
1549       return features.getExtension(UnittestFeatures.test).getMultipleFeature().getNumber();
1550     }
1551 
buildFrom(FileDescriptorProto fileProto)1552     FileDescriptor buildFrom(FileDescriptorProto fileProto) throws Exception {
1553       return FileDescriptor.buildFrom(fileProto, new FileDescriptor[0]);
1554     }
1555 
1556     @Test
testFileDefaults()1557     public void testFileDefaults() throws Exception {
1558       FileDescriptor descriptor = buildFrom(fileProto.build());
1559       assertThat(getTestFeature(descriptor.features)).isEqualTo(1);
1560     }
1561 
1562     @Test
testFileOverrides()1563     public void testFileOverrides() throws Exception {
1564       setTestFeature(fileProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1565       FileDescriptor descriptor = buildFrom(fileProto.build());
1566       assertThat(getTestFeature(descriptor.features)).isEqualTo(3);
1567     }
1568 
1569     @Test
testFileMessageInherit()1570     public void testFileMessageInherit() throws Exception {
1571       setTestFeature(fileProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1572       FileDescriptor descriptor = buildFrom(fileProto.build());
1573       assertThat(getTestFeature(descriptor.getMessageTypes().get(0).features)).isEqualTo(3);
1574     }
1575 
1576     @Test
testFileMessageOverride()1577     public void testFileMessageOverride() throws Exception {
1578       setTestFeature(fileProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1579       setTestFeature(topMessageProto.getOptionsBuilder().getFeaturesBuilder(), 5);
1580       FileDescriptor descriptor = buildFrom(fileProto.build());
1581       assertThat(getTestFeature(descriptor.getMessageTypes().get(0).features)).isEqualTo(5);
1582     }
1583 
1584     @Test
testFileEnumInherit()1585     public void testFileEnumInherit() throws Exception {
1586       setTestFeature(fileProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1587       FileDescriptor descriptor = buildFrom(fileProto.build());
1588       assertThat(getTestFeature(descriptor.getEnumTypes().get(0).features)).isEqualTo(3);
1589     }
1590 
1591     @Test
testFileEnumOverride()1592     public void testFileEnumOverride() throws Exception {
1593       setTestFeature(fileProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1594       setTestFeature(topEnumProto.getOptionsBuilder().getFeaturesBuilder(), 5);
1595       FileDescriptor descriptor = buildFrom(fileProto.build());
1596       assertThat(getTestFeature(descriptor.getEnumTypes().get(0).features)).isEqualTo(5);
1597     }
1598 
1599     @Test
testFileExtensionInherit()1600     public void testFileExtensionInherit() throws Exception {
1601       setTestFeature(fileProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1602       FileDescriptor descriptor = buildFrom(fileProto.build());
1603       assertThat(getTestFeature(descriptor.getExtensions().get(0).features)).isEqualTo(3);
1604     }
1605 
1606     @Test
testFileExtensionOverride()1607     public void testFileExtensionOverride() throws Exception {
1608       setTestFeature(fileProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1609       setTestFeature(topExtensionProto.getOptionsBuilder().getFeaturesBuilder(), 5);
1610       FileDescriptor descriptor = buildFrom(fileProto.build());
1611       assertThat(getTestFeature(descriptor.getExtensions().get(0).features)).isEqualTo(5);
1612     }
1613 
1614     @Test
testFileServiceInherit()1615     public void testFileServiceInherit() throws Exception {
1616       setTestFeature(fileProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1617       FileDescriptor descriptor = buildFrom(fileProto.build());
1618       assertThat(getTestFeature(descriptor.getServices().get(0).features)).isEqualTo(3);
1619     }
1620 
1621     @Test
testFileServiceOverride()1622     public void testFileServiceOverride() throws Exception {
1623       setTestFeature(fileProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1624       setTestFeature(serviceProto.getOptionsBuilder().getFeaturesBuilder(), 5);
1625       FileDescriptor descriptor = buildFrom(fileProto.build());
1626       assertThat(getTestFeature(descriptor.getServices().get(0).features)).isEqualTo(5);
1627     }
1628 
1629     @Test
testMessageFieldInherit()1630     public void testMessageFieldInherit() throws Exception {
1631       setTestFeature(topMessageProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1632       FileDescriptor descriptor = buildFrom(fileProto.build());
1633       assertThat(getTestFeature(descriptor.getMessageTypes().get(0).getFields().get(0).features))
1634           .isEqualTo(3);
1635     }
1636 
1637     @Test
testMessageFieldOverride()1638     public void testMessageFieldOverride() throws Exception {
1639       setTestFeature(topMessageProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1640       setTestFeature(fieldProto.getOptionsBuilder().getFeaturesBuilder(), 5);
1641       FileDescriptor descriptor = buildFrom(fileProto.build());
1642       assertThat(getTestFeature(descriptor.getMessageTypes().get(0).getFields().get(0).features))
1643           .isEqualTo(5);
1644     }
1645 
1646     @Test
testMessageEnumInherit()1647     public void testMessageEnumInherit() throws Exception {
1648       setTestFeature(topMessageProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1649       FileDescriptor descriptor = buildFrom(fileProto.build());
1650       assertThat(getTestFeature(descriptor.getMessageTypes().get(0).getEnumTypes().get(0).features))
1651           .isEqualTo(3);
1652     }
1653 
1654     @Test
testMessageEnumOverride()1655     public void testMessageEnumOverride() throws Exception {
1656       setTestFeature(topMessageProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1657       setTestFeature(nestedEnumProto.getOptionsBuilder().getFeaturesBuilder(), 5);
1658       FileDescriptor descriptor = buildFrom(fileProto.build());
1659       assertThat(getTestFeature(descriptor.getMessageTypes().get(0).getEnumTypes().get(0).features))
1660           .isEqualTo(5);
1661     }
1662 
1663     @Test
testMessageMessageInherit()1664     public void testMessageMessageInherit() throws Exception {
1665       setTestFeature(topMessageProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1666       FileDescriptor descriptor = buildFrom(fileProto.build());
1667       assertThat(
1668               getTestFeature(descriptor.getMessageTypes().get(0).getNestedTypes().get(0).features))
1669           .isEqualTo(3);
1670     }
1671 
1672     @Test
testMessageMessageOverride()1673     public void testMessageMessageOverride() throws Exception {
1674       setTestFeature(topMessageProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1675       setTestFeature(nestedMessageProto.getOptionsBuilder().getFeaturesBuilder(), 5);
1676       FileDescriptor descriptor = buildFrom(fileProto.build());
1677       assertThat(
1678               getTestFeature(descriptor.getMessageTypes().get(0).getNestedTypes().get(0).features))
1679           .isEqualTo(5);
1680     }
1681 
1682     @Test
testMessageExtensionInherit()1683     public void testMessageExtensionInherit() throws Exception {
1684       setTestFeature(topMessageProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1685       FileDescriptor descriptor = buildFrom(fileProto.build());
1686       assertThat(
1687               getTestFeature(descriptor.getMessageTypes().get(0).getExtensions().get(0).features))
1688           .isEqualTo(3);
1689     }
1690 
1691     @Test
testMessageExtensionOverride()1692     public void testMessageExtensionOverride() throws Exception {
1693       setTestFeature(topMessageProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1694       setTestFeature(nestedExtensionProto.getOptionsBuilder().getFeaturesBuilder(), 5);
1695       FileDescriptor descriptor = buildFrom(fileProto.build());
1696       assertThat(
1697               getTestFeature(descriptor.getMessageTypes().get(0).getExtensions().get(0).features))
1698           .isEqualTo(5);
1699     }
1700 
1701     @Test
testMessageOneofInherit()1702     public void testMessageOneofInherit() throws Exception {
1703       setTestFeature(topMessageProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1704       FileDescriptor descriptor = buildFrom(fileProto.build());
1705       assertThat(getTestFeature(descriptor.getMessageTypes().get(0).getOneofs().get(0).features))
1706           .isEqualTo(3);
1707     }
1708 
1709     @Test
testMessageOneofOverride()1710     public void testMessageOneofOverride() throws Exception {
1711       setTestFeature(topMessageProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1712       setTestFeature(oneofProto.getOptionsBuilder().getFeaturesBuilder(), 5);
1713       FileDescriptor descriptor = buildFrom(fileProto.build());
1714       assertThat(getTestFeature(descriptor.getMessageTypes().get(0).getOneofs().get(0).features))
1715           .isEqualTo(5);
1716     }
1717 
1718     @Test
testOneofFieldInherit()1719     public void testOneofFieldInherit() throws Exception {
1720       setTestFeature(oneofProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1721       FileDescriptor descriptor = buildFrom(fileProto.build());
1722       assertThat(
1723               getTestFeature(
1724                   descriptor
1725                       .getMessageTypes()
1726                       .get(0)
1727                       .getOneofs()
1728                       .get(0)
1729                       .getFields()
1730                       .get(0)
1731                       .features))
1732           .isEqualTo(3);
1733     }
1734 
1735     @Test
testOneofFieldOverride()1736     public void testOneofFieldOverride() throws Exception {
1737       setTestFeature(oneofProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1738       setTestFeature(oneofFieldProto.getOptionsBuilder().getFeaturesBuilder(), 5);
1739       FileDescriptor descriptor = buildFrom(fileProto.build());
1740       assertThat(
1741               getTestFeature(
1742                   descriptor
1743                       .getMessageTypes()
1744                       .get(0)
1745                       .getOneofs()
1746                       .get(0)
1747                       .getFields()
1748                       .get(0)
1749                       .features))
1750           .isEqualTo(5);
1751     }
1752 
1753     @Test
testEnumValueInherit()1754     public void testEnumValueInherit() throws Exception {
1755       setTestFeature(topEnumProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1756       FileDescriptor descriptor = buildFrom(fileProto.build());
1757       assertThat(getTestFeature(descriptor.getEnumTypes().get(0).getValues().get(0).features))
1758           .isEqualTo(3);
1759     }
1760 
1761     @Test
testEnumValueOverride()1762     public void testEnumValueOverride() throws Exception {
1763       setTestFeature(topEnumProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1764       setTestFeature(enumValueProto.getOptionsBuilder().getFeaturesBuilder(), 5);
1765       FileDescriptor descriptor = buildFrom(fileProto.build());
1766       assertThat(getTestFeature(descriptor.getEnumTypes().get(0).getValues().get(0).features))
1767           .isEqualTo(5);
1768     }
1769 
1770     @Test
testServiceMethodInherit()1771     public void testServiceMethodInherit() throws Exception {
1772       setTestFeature(serviceProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1773       FileDescriptor descriptor = buildFrom(fileProto.build());
1774       assertThat(getTestFeature(descriptor.getServices().get(0).getMethods().get(0).features))
1775           .isEqualTo(3);
1776     }
1777 
1778     @Test
testServiceMethodOverride()1779     public void testServiceMethodOverride() throws Exception {
1780       setTestFeature(serviceProto.getOptionsBuilder().getFeaturesBuilder(), 3);
1781       setTestFeature(methodProto.getOptionsBuilder().getFeaturesBuilder(), 5);
1782       FileDescriptor descriptor = buildFrom(fileProto.build());
1783       assertThat(getTestFeature(descriptor.getServices().get(0).getMethods().get(0).features))
1784           .isEqualTo(5);
1785     }
1786   }
1787 }
1788