1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 package com.google.protobuf;
32 
33 import com.google.protobuf.DescriptorProtos.DescriptorProto;
34 import com.google.protobuf.DescriptorProtos.EnumDescriptorProto;
35 import com.google.protobuf.DescriptorProtos.EnumValueDescriptorProto;
36 import com.google.protobuf.DescriptorProtos.FieldDescriptorProto;
37 import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
38 import com.google.protobuf.Descriptors.Descriptor;
39 import com.google.protobuf.Descriptors.DescriptorValidationException;
40 import com.google.protobuf.Descriptors.EnumDescriptor;
41 import com.google.protobuf.Descriptors.EnumValueDescriptor;
42 import com.google.protobuf.Descriptors.FieldDescriptor;
43 import com.google.protobuf.Descriptors.FileDescriptor;
44 import com.google.protobuf.Descriptors.MethodDescriptor;
45 import com.google.protobuf.Descriptors.OneofDescriptor;
46 import com.google.protobuf.Descriptors.ServiceDescriptor;
47 import com.google.protobuf.test.UnittestImport;
48 import com.google.protobuf.test.UnittestImport.ImportEnum;
49 import com.google.protobuf.test.UnittestImport.ImportEnumForMap;
50 import protobuf_unittest.TestCustomOptions;
51 import protobuf_unittest.UnittestCustomOptions;
52 import protobuf_unittest.UnittestProto;
53 import protobuf_unittest.UnittestProto.ForeignEnum;
54 import protobuf_unittest.UnittestProto.ForeignMessage;
55 import protobuf_unittest.UnittestProto.TestAllExtensions;
56 import protobuf_unittest.UnittestProto.TestAllTypes;
57 import protobuf_unittest.UnittestProto.TestExtremeDefaultValues;
58 import protobuf_unittest.UnittestProto.TestMultipleExtensionRanges;
59 import protobuf_unittest.UnittestProto.TestRequired;
60 import protobuf_unittest.UnittestProto.TestReservedFields;
61 import protobuf_unittest.UnittestProto.TestService;
62 import junit.framework.TestCase;
63 
64 import java.util.Arrays;
65 import java.util.Collections;
66 import java.util.List;
67 
68 /**
69  * Unit test for {@link Descriptors}.
70  *
71  * @author kenton@google.com Kenton Varda
72  */
73 public class DescriptorsTest extends TestCase {
74 
75   // Regression test for bug where referencing a FieldDescriptor.Type value
76   // before a FieldDescriptorProto.Type value would yield a
77   // ExceptionInInitializerError.
78   @SuppressWarnings("unused")
79   private static final Object STATIC_INIT_TEST = FieldDescriptor.Type.BOOL;
80 
testFieldTypeEnumMapping()81   public void testFieldTypeEnumMapping() throws Exception {
82     assertEquals(FieldDescriptor.Type.values().length,
83         FieldDescriptorProto.Type.values().length);
84     for (FieldDescriptor.Type type : FieldDescriptor.Type.values()) {
85       FieldDescriptorProto.Type protoType = type.toProto();
86       assertEquals("TYPE_" + type.name(), protoType.name());
87       assertEquals(type, FieldDescriptor.Type.valueOf(protoType));
88     }
89   }
90 
testFileDescriptor()91   public void testFileDescriptor() throws Exception {
92     FileDescriptor file = UnittestProto.getDescriptor();
93 
94     assertEquals("google/protobuf/unittest.proto", file.getName());
95     assertEquals("protobuf_unittest", file.getPackage());
96 
97     assertEquals("UnittestProto", file.getOptions().getJavaOuterClassname());
98     assertEquals("google/protobuf/unittest.proto",
99                  file.toProto().getName());
100 
101     assertEquals(Arrays.asList(UnittestImport.getDescriptor()),
102                  file.getDependencies());
103 
104     Descriptor messageType = TestAllTypes.getDescriptor();
105     assertEquals(messageType, file.getMessageTypes().get(0));
106     assertEquals(messageType, file.findMessageTypeByName("TestAllTypes"));
107     assertNull(file.findMessageTypeByName("NoSuchType"));
108     assertNull(file.findMessageTypeByName("protobuf_unittest.TestAllTypes"));
109     for (int i = 0; i < file.getMessageTypes().size(); i++) {
110       assertEquals(i, file.getMessageTypes().get(i).getIndex());
111     }
112 
113     EnumDescriptor enumType = ForeignEnum.getDescriptor();
114     assertEquals(enumType, file.getEnumTypes().get(0));
115     assertEquals(enumType, file.findEnumTypeByName("ForeignEnum"));
116     assertNull(file.findEnumTypeByName("NoSuchType"));
117     assertNull(file.findEnumTypeByName("protobuf_unittest.ForeignEnum"));
118     assertEquals(Arrays.asList(ImportEnum.getDescriptor(),
119                                ImportEnumForMap.getDescriptor()),
120                  UnittestImport.getDescriptor().getEnumTypes());
121     for (int i = 0; i < file.getEnumTypes().size(); i++) {
122       assertEquals(i, file.getEnumTypes().get(i).getIndex());
123     }
124 
125     ServiceDescriptor service = TestService.getDescriptor();
126     assertEquals(service, file.getServices().get(0));
127     assertEquals(service, file.findServiceByName("TestService"));
128     assertNull(file.findServiceByName("NoSuchType"));
129     assertNull(file.findServiceByName("protobuf_unittest.TestService"));
130     assertEquals(Collections.emptyList(),
131                  UnittestImport.getDescriptor().getServices());
132     for (int i = 0; i < file.getServices().size(); i++) {
133       assertEquals(i, file.getServices().get(i).getIndex());
134     }
135 
136     FieldDescriptor extension =
137       UnittestProto.optionalInt32Extension.getDescriptor();
138     assertEquals(extension, file.getExtensions().get(0));
139     assertEquals(extension,
140                  file.findExtensionByName("optional_int32_extension"));
141     assertNull(file.findExtensionByName("no_such_ext"));
142     assertNull(file.findExtensionByName(
143       "protobuf_unittest.optional_int32_extension"));
144     assertEquals(Collections.emptyList(),
145                  UnittestImport.getDescriptor().getExtensions());
146     for (int i = 0; i < file.getExtensions().size(); i++) {
147       assertEquals(i, file.getExtensions().get(i).getIndex());
148     }
149   }
150 
testDescriptor()151   public void testDescriptor() throws Exception {
152     Descriptor messageType = TestAllTypes.getDescriptor();
153     Descriptor nestedType = TestAllTypes.NestedMessage.getDescriptor();
154 
155     assertEquals("TestAllTypes", messageType.getName());
156     assertEquals("protobuf_unittest.TestAllTypes", messageType.getFullName());
157     assertEquals(UnittestProto.getDescriptor(), messageType.getFile());
158     assertNull(messageType.getContainingType());
159     assertEquals(DescriptorProtos.MessageOptions.getDefaultInstance(),
160                  messageType.getOptions());
161     assertEquals("TestAllTypes", messageType.toProto().getName());
162 
163     assertEquals("NestedMessage", nestedType.getName());
164     assertEquals("protobuf_unittest.TestAllTypes.NestedMessage",
165                  nestedType.getFullName());
166     assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
167     assertEquals(messageType, nestedType.getContainingType());
168 
169     FieldDescriptor field = messageType.getFields().get(0);
170     assertEquals("optional_int32", field.getName());
171     assertEquals(field, messageType.findFieldByName("optional_int32"));
172     assertNull(messageType.findFieldByName("no_such_field"));
173     assertEquals(field, messageType.findFieldByNumber(1));
174     assertNull(messageType.findFieldByNumber(571283));
175     for (int i = 0; i < messageType.getFields().size(); i++) {
176       assertEquals(i, messageType.getFields().get(i).getIndex());
177     }
178 
179     assertEquals(nestedType, messageType.getNestedTypes().get(0));
180     assertEquals(nestedType, messageType.findNestedTypeByName("NestedMessage"));
181     assertNull(messageType.findNestedTypeByName("NoSuchType"));
182     for (int i = 0; i < messageType.getNestedTypes().size(); i++) {
183       assertEquals(i, messageType.getNestedTypes().get(i).getIndex());
184     }
185 
186     EnumDescriptor enumType = TestAllTypes.NestedEnum.getDescriptor();
187     assertEquals(enumType, messageType.getEnumTypes().get(0));
188     assertEquals(enumType, messageType.findEnumTypeByName("NestedEnum"));
189     assertNull(messageType.findEnumTypeByName("NoSuchType"));
190     for (int i = 0; i < messageType.getEnumTypes().size(); i++) {
191       assertEquals(i, messageType.getEnumTypes().get(i).getIndex());
192     }
193   }
194 
testFieldDescriptor()195   public void testFieldDescriptor() throws Exception {
196     Descriptor messageType = TestAllTypes.getDescriptor();
197     FieldDescriptor primitiveField =
198       messageType.findFieldByName("optional_int32");
199     FieldDescriptor enumField =
200       messageType.findFieldByName("optional_nested_enum");
201     FieldDescriptor messageField =
202       messageType.findFieldByName("optional_foreign_message");
203     FieldDescriptor cordField =
204       messageType.findFieldByName("optional_cord");
205     FieldDescriptor extension =
206       UnittestProto.optionalInt32Extension.getDescriptor();
207     FieldDescriptor nestedExtension = TestRequired.single.getDescriptor();
208 
209     assertEquals("optional_int32", primitiveField.getName());
210     assertEquals("protobuf_unittest.TestAllTypes.optional_int32",
211                  primitiveField.getFullName());
212     assertEquals(1, primitiveField.getNumber());
213     assertEquals(messageType, primitiveField.getContainingType());
214     assertEquals(UnittestProto.getDescriptor(), primitiveField.getFile());
215     assertEquals(FieldDescriptor.Type.INT32, primitiveField.getType());
216     assertEquals(FieldDescriptor.JavaType.INT, primitiveField.getJavaType());
217     assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(),
218                  primitiveField.getOptions());
219     assertFalse(primitiveField.isExtension());
220     assertEquals("optional_int32", primitiveField.toProto().getName());
221 
222     assertEquals("optional_nested_enum", enumField.getName());
223     assertEquals(FieldDescriptor.Type.ENUM, enumField.getType());
224     assertEquals(FieldDescriptor.JavaType.ENUM, enumField.getJavaType());
225     assertEquals(TestAllTypes.NestedEnum.getDescriptor(),
226                  enumField.getEnumType());
227 
228     assertEquals("optional_foreign_message", messageField.getName());
229     assertEquals(FieldDescriptor.Type.MESSAGE, messageField.getType());
230     assertEquals(FieldDescriptor.JavaType.MESSAGE, messageField.getJavaType());
231     assertEquals(ForeignMessage.getDescriptor(), messageField.getMessageType());
232 
233     assertEquals("optional_cord", cordField.getName());
234     assertEquals(FieldDescriptor.Type.STRING, cordField.getType());
235     assertEquals(FieldDescriptor.JavaType.STRING, cordField.getJavaType());
236     assertEquals(DescriptorProtos.FieldOptions.CType.CORD,
237                  cordField.getOptions().getCtype());
238 
239     assertEquals("optional_int32_extension", extension.getName());
240     assertEquals("protobuf_unittest.optional_int32_extension",
241                  extension.getFullName());
242     assertEquals(1, extension.getNumber());
243     assertEquals(TestAllExtensions.getDescriptor(),
244                  extension.getContainingType());
245     assertEquals(UnittestProto.getDescriptor(), extension.getFile());
246     assertEquals(FieldDescriptor.Type.INT32, extension.getType());
247     assertEquals(FieldDescriptor.JavaType.INT, extension.getJavaType());
248     assertEquals(DescriptorProtos.FieldOptions.getDefaultInstance(),
249                  extension.getOptions());
250     assertTrue(extension.isExtension());
251     assertEquals(null, extension.getExtensionScope());
252     assertEquals("optional_int32_extension", extension.toProto().getName());
253 
254     assertEquals("single", nestedExtension.getName());
255     assertEquals("protobuf_unittest.TestRequired.single",
256                  nestedExtension.getFullName());
257     assertEquals(TestRequired.getDescriptor(),
258                  nestedExtension.getExtensionScope());
259   }
260 
testFieldDescriptorLabel()261   public void testFieldDescriptorLabel() throws Exception {
262     FieldDescriptor requiredField =
263       TestRequired.getDescriptor().findFieldByName("a");
264     FieldDescriptor optionalField =
265       TestAllTypes.getDescriptor().findFieldByName("optional_int32");
266     FieldDescriptor repeatedField =
267       TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
268 
269     assertTrue(requiredField.isRequired());
270     assertFalse(requiredField.isRepeated());
271     assertFalse(optionalField.isRequired());
272     assertFalse(optionalField.isRepeated());
273     assertFalse(repeatedField.isRequired());
274     assertTrue(repeatedField.isRepeated());
275   }
276 
testFieldDescriptorJsonName()277   public void testFieldDescriptorJsonName() throws Exception {
278     FieldDescriptor requiredField = TestRequired.getDescriptor().findFieldByName("a");
279     FieldDescriptor optionalField = TestAllTypes.getDescriptor().findFieldByName("optional_int32");
280     FieldDescriptor repeatedField = TestAllTypes.getDescriptor().findFieldByName("repeated_int32");
281     assertEquals("a", requiredField.getJsonName());
282     assertEquals("optionalInt32", optionalField.getJsonName());
283     assertEquals("repeatedInt32", repeatedField.getJsonName());
284   }
285 
testFieldDescriptorDefault()286   public void testFieldDescriptorDefault() throws Exception {
287     Descriptor d = TestAllTypes.getDescriptor();
288     assertFalse(d.findFieldByName("optional_int32").hasDefaultValue());
289     assertEquals(0, d.findFieldByName("optional_int32").getDefaultValue());
290     assertTrue(d.findFieldByName("default_int32").hasDefaultValue());
291     assertEquals(41, d.findFieldByName("default_int32").getDefaultValue());
292 
293     d = TestExtremeDefaultValues.getDescriptor();
294     assertEquals(
295       ByteString.copyFrom(
296         "\0\001\007\b\f\n\r\t\013\\\'\"\u00fe".getBytes(Internal.ISO_8859_1)),
297       d.findFieldByName("escaped_bytes").getDefaultValue());
298     assertEquals(-1, d.findFieldByName("large_uint32").getDefaultValue());
299     assertEquals(-1L, d.findFieldByName("large_uint64").getDefaultValue());
300   }
301 
testEnumDescriptor()302   public void testEnumDescriptor() throws Exception {
303     EnumDescriptor enumType = ForeignEnum.getDescriptor();
304     EnumDescriptor nestedType = TestAllTypes.NestedEnum.getDescriptor();
305 
306     assertEquals("ForeignEnum", enumType.getName());
307     assertEquals("protobuf_unittest.ForeignEnum", enumType.getFullName());
308     assertEquals(UnittestProto.getDescriptor(), enumType.getFile());
309     assertNull(enumType.getContainingType());
310     assertEquals(DescriptorProtos.EnumOptions.getDefaultInstance(),
311                  enumType.getOptions());
312 
313     assertEquals("NestedEnum", nestedType.getName());
314     assertEquals("protobuf_unittest.TestAllTypes.NestedEnum",
315                  nestedType.getFullName());
316     assertEquals(UnittestProto.getDescriptor(), nestedType.getFile());
317     assertEquals(TestAllTypes.getDescriptor(), nestedType.getContainingType());
318 
319     EnumValueDescriptor value = ForeignEnum.FOREIGN_FOO.getValueDescriptor();
320     assertEquals(value, enumType.getValues().get(0));
321     assertEquals("FOREIGN_FOO", value.getName());
322     assertEquals("FOREIGN_FOO", value.toString());
323     assertEquals(4, value.getNumber());
324     assertEquals(value, enumType.findValueByName("FOREIGN_FOO"));
325     assertEquals(value, enumType.findValueByNumber(4));
326     assertNull(enumType.findValueByName("NO_SUCH_VALUE"));
327     for (int i = 0; i < enumType.getValues().size(); i++) {
328       assertEquals(i, enumType.getValues().get(i).getIndex());
329     }
330   }
331 
testServiceDescriptor()332   public void testServiceDescriptor() throws Exception {
333     ServiceDescriptor service = TestService.getDescriptor();
334 
335     assertEquals("TestService", service.getName());
336     assertEquals("protobuf_unittest.TestService", service.getFullName());
337     assertEquals(UnittestProto.getDescriptor(), service.getFile());
338 
339 
340     MethodDescriptor fooMethod = service.getMethods().get(0);
341     assertEquals("Foo", fooMethod.getName());
342     assertEquals(UnittestProto.FooRequest.getDescriptor(),
343                  fooMethod.getInputType());
344     assertEquals(UnittestProto.FooResponse.getDescriptor(),
345                  fooMethod.getOutputType());
346     assertEquals(fooMethod, service.findMethodByName("Foo"));
347 
348     MethodDescriptor barMethod = service.getMethods().get(1);
349     assertEquals("Bar", barMethod.getName());
350     assertEquals(UnittestProto.BarRequest.getDescriptor(),
351                  barMethod.getInputType());
352     assertEquals(UnittestProto.BarResponse.getDescriptor(),
353                  barMethod.getOutputType());
354     assertEquals(barMethod, service.findMethodByName("Bar"));
355 
356     assertNull(service.findMethodByName("NoSuchMethod"));
357 
358     for (int i = 0; i < service.getMethods().size(); i++) {
359       assertEquals(i, service.getMethods().get(i).getIndex());
360     }
361   }
362 
363 
testCustomOptions()364   public void testCustomOptions() throws Exception {
365     // Get the descriptor indirectly from a dependent proto class. This is to
366     // ensure that when a proto class is loaded, custom options defined in its
367     // dependencies are also properly initialized.
368     Descriptor descriptor =
369         TestCustomOptions.TestMessageWithCustomOptionsContainer.getDescriptor()
370         .findFieldByName("field").getMessageType();
371 
372     assertTrue(
373       descriptor.getOptions().hasExtension(UnittestCustomOptions.messageOpt1));
374     assertEquals(Integer.valueOf(-56),
375       descriptor.getOptions().getExtension(UnittestCustomOptions.messageOpt1));
376 
377     FieldDescriptor field = descriptor.findFieldByName("field1");
378     assertNotNull(field);
379 
380     assertTrue(
381       field.getOptions().hasExtension(UnittestCustomOptions.fieldOpt1));
382     assertEquals(Long.valueOf(8765432109L),
383       field.getOptions().getExtension(UnittestCustomOptions.fieldOpt1));
384 
385     OneofDescriptor oneof = descriptor.getOneofs().get(0);
386     assertNotNull(oneof);
387 
388     assertTrue(
389       oneof.getOptions().hasExtension(UnittestCustomOptions.oneofOpt1));
390     assertEquals(Integer.valueOf(-99),
391       oneof.getOptions().getExtension(UnittestCustomOptions.oneofOpt1));
392 
393     EnumDescriptor enumType =
394       UnittestCustomOptions.TestMessageWithCustomOptions.AnEnum.getDescriptor();
395 
396     assertTrue(
397       enumType.getOptions().hasExtension(UnittestCustomOptions.enumOpt1));
398     assertEquals(Integer.valueOf(-789),
399       enumType.getOptions().getExtension(UnittestCustomOptions.enumOpt1));
400 
401     ServiceDescriptor service =
402       UnittestCustomOptions.TestServiceWithCustomOptions.getDescriptor();
403 
404     assertTrue(
405       service.getOptions().hasExtension(UnittestCustomOptions.serviceOpt1));
406     assertEquals(Long.valueOf(-9876543210L),
407       service.getOptions().getExtension(UnittestCustomOptions.serviceOpt1));
408 
409     MethodDescriptor method = service.findMethodByName("Foo");
410     assertNotNull(method);
411 
412     assertTrue(
413       method.getOptions().hasExtension(UnittestCustomOptions.methodOpt1));
414     assertEquals(UnittestCustomOptions.MethodOpt1.METHODOPT1_VAL2,
415       method.getOptions().getExtension(UnittestCustomOptions.methodOpt1));
416   }
417 
418   /**
419    * Test that the FieldDescriptor.Type enum is the same as the
420    * WireFormat.FieldType enum.
421    */
testFieldTypeTablesMatch()422   public void testFieldTypeTablesMatch() throws Exception {
423     FieldDescriptor.Type[] values1 = FieldDescriptor.Type.values();
424     WireFormat.FieldType[] values2 = WireFormat.FieldType.values();
425 
426     assertEquals(values1.length, values2.length);
427 
428     for (int i = 0; i < values1.length; i++) {
429       assertEquals(values1[i].toString(), values2[i].toString());
430     }
431   }
432 
433   /**
434    * Test that the FieldDescriptor.JavaType enum is the same as the
435    * WireFormat.JavaType enum.
436    */
testJavaTypeTablesMatch()437   public void testJavaTypeTablesMatch() throws Exception {
438     FieldDescriptor.JavaType[] values1 = FieldDescriptor.JavaType.values();
439     WireFormat.JavaType[] values2 = WireFormat.JavaType.values();
440 
441     assertEquals(values1.length, values2.length);
442 
443     for (int i = 0; i < values1.length; i++) {
444       assertEquals(values1[i].toString(), values2[i].toString());
445     }
446   }
447 
testEnormousDescriptor()448   public void testEnormousDescriptor() throws Exception {
449     // The descriptor for this file is larger than 64k, yet it did not cause
450     // a compiler error due to an over-long string literal.
451     assertTrue(
452         UnittestEnormousDescriptor.getDescriptor()
453           .toProto().getSerializedSize() > 65536);
454   }
455 
456   /**
457    * Tests that the DescriptorValidationException works as intended.
458    */
testDescriptorValidatorException()459   public void testDescriptorValidatorException() throws Exception {
460     FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
461       .setName("foo.proto")
462       .addMessageType(DescriptorProto.newBuilder()
463       .setName("Foo")
464         .addField(FieldDescriptorProto.newBuilder()
465           .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
466           .setType(FieldDescriptorProto.Type.TYPE_INT32)
467           .setName("foo")
468           .setNumber(1)
469           .setDefaultValue("invalid")
470           .build())
471         .build())
472       .build();
473     try {
474       Descriptors.FileDescriptor.buildFrom(fileDescriptorProto,
475           new FileDescriptor[0]);
476       fail("DescriptorValidationException expected");
477     } catch (DescriptorValidationException e) {
478       // Expected; check that the error message contains some useful hints
479       assertTrue(e.getMessage().indexOf("foo") != -1);
480       assertTrue(e.getMessage().indexOf("Foo") != -1);
481       assertTrue(e.getMessage().indexOf("invalid") != -1);
482       assertTrue(e.getCause() instanceof NumberFormatException);
483       assertTrue(e.getCause().getMessage().indexOf("invalid") != -1);
484     }
485   }
486 
487   /**
488    * Tests the translate/crosslink for an example where a message field's name
489    * and type name are the same.
490    */
testDescriptorComplexCrosslink()491   public void testDescriptorComplexCrosslink() throws Exception {
492     FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
493       .setName("foo.proto")
494       .addMessageType(DescriptorProto.newBuilder()
495         .setName("Foo")
496         .addField(FieldDescriptorProto.newBuilder()
497           .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
498           .setType(FieldDescriptorProto.Type.TYPE_INT32)
499           .setName("foo")
500           .setNumber(1)
501           .build())
502         .build())
503       .addMessageType(DescriptorProto.newBuilder()
504         .setName("Bar")
505         .addField(FieldDescriptorProto.newBuilder()
506           .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
507           .setTypeName("Foo")
508           .setName("Foo")
509           .setNumber(1)
510           .build())
511         .build())
512       .build();
513     // translate and crosslink
514     FileDescriptor file =
515       Descriptors.FileDescriptor.buildFrom(fileDescriptorProto,
516           new FileDescriptor[0]);
517     // verify resulting descriptors
518     assertNotNull(file);
519     List<Descriptor> msglist = file.getMessageTypes();
520     assertNotNull(msglist);
521     assertTrue(msglist.size() == 2);
522     boolean barFound = false;
523     for (Descriptor desc : msglist) {
524       if (desc.getName().equals("Bar")) {
525         barFound = true;
526         assertNotNull(desc.getFields());
527         List<FieldDescriptor> fieldlist = desc.getFields();
528         assertNotNull(fieldlist);
529         assertTrue(fieldlist.size() == 1);
530         assertTrue(fieldlist.get(0).getType() == FieldDescriptor.Type.MESSAGE);
531         assertTrue(fieldlist.get(0).getMessageType().getName().equals("Foo"));
532       }
533     }
534     assertTrue(barFound);
535   }
536 
testDependencyOrder()537   public void testDependencyOrder() throws Exception {
538     FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
539         .setName("foo.proto").build();
540     FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
541         .setName("bar.proto")
542         .addDependency("foo.proto")
543         .build();
544     FileDescriptorProto bazProto = FileDescriptorProto.newBuilder()
545         .setName("baz.proto")
546         .addDependency("foo.proto")
547         .addDependency("bar.proto")
548         .addPublicDependency(0)
549         .addPublicDependency(1)
550         .build();
551     FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto,
552         new FileDescriptor[0]);
553     FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(barProto,
554         new FileDescriptor[] {fooFile});
555 
556     // Items in the FileDescriptor array can be in any order.
557     Descriptors.FileDescriptor.buildFrom(bazProto,
558         new FileDescriptor[] {fooFile, barFile});
559     Descriptors.FileDescriptor.buildFrom(bazProto,
560         new FileDescriptor[] {barFile, fooFile});
561   }
562 
testInvalidPublicDependency()563   public void testInvalidPublicDependency() throws Exception {
564     FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
565         .setName("foo.proto").build();
566     FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
567         .setName("boo.proto")
568         .addDependency("foo.proto")
569         .addPublicDependency(1)  // Error, should be 0.
570         .build();
571     FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(fooProto,
572         new FileDescriptor[0]);
573     try {
574       Descriptors.FileDescriptor.buildFrom(barProto,
575           new FileDescriptor[] {fooFile});
576       fail("DescriptorValidationException expected");
577     } catch (DescriptorValidationException e) {
578       assertTrue(
579           e.getMessage().indexOf("Invalid public dependency index.") != -1);
580     }
581   }
582 
testUnknownFieldsDenied()583   public void testUnknownFieldsDenied() throws Exception {
584     FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
585         .setName("foo.proto")
586         .addMessageType(DescriptorProto.newBuilder()
587             .setName("Foo")
588             .addField(FieldDescriptorProto.newBuilder()
589                 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
590                 .setTypeName("Bar")
591                 .setName("bar")
592                 .setNumber(1)))
593         .build();
594 
595     try {
596       Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0]);
597       fail("DescriptorValidationException expected");
598     } catch (DescriptorValidationException e) {
599       assertTrue(e.getMessage().indexOf("Bar") != -1);
600       assertTrue(e.getMessage().indexOf("is not defined") != -1);
601     }
602   }
603 
testUnknownFieldsAllowed()604   public void testUnknownFieldsAllowed() throws Exception {
605     FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
606         .setName("foo.proto")
607         .addDependency("bar.proto")
608         .addMessageType(DescriptorProto.newBuilder()
609             .setName("Foo")
610             .addField(FieldDescriptorProto.newBuilder()
611                 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
612                 .setTypeName("Bar")
613                 .setName("bar")
614                 .setNumber(1)))
615         .build();
616     Descriptors.FileDescriptor.buildFrom(fooProto, new FileDescriptor[0], true);
617   }
618 
testHiddenDependency()619   public void testHiddenDependency() throws Exception {
620     FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
621         .setName("bar.proto")
622         .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
623         .build();
624     FileDescriptorProto forwardProto = FileDescriptorProto.newBuilder()
625         .setName("forward.proto")
626         .addDependency("bar.proto")
627         .build();
628     FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
629         .setName("foo.proto")
630         .addDependency("forward.proto")
631         .addMessageType(DescriptorProto.newBuilder()
632             .setName("Foo")
633             .addField(FieldDescriptorProto.newBuilder()
634                 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
635                 .setTypeName("Bar")
636                 .setName("bar")
637                 .setNumber(1)))
638         .build();
639     FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
640         barProto, new FileDescriptor[0]);
641     FileDescriptor forwardFile = Descriptors.FileDescriptor.buildFrom(
642         forwardProto, new FileDescriptor[] {barFile});
643 
644     try {
645       Descriptors.FileDescriptor.buildFrom(
646           fooProto, new FileDescriptor[] {forwardFile});
647       fail("DescriptorValidationException expected");
648     } catch (DescriptorValidationException e) {
649       assertTrue(e.getMessage().indexOf("Bar") != -1);
650       assertTrue(e.getMessage().indexOf("is not defined") != -1);
651     }
652   }
653 
testPublicDependency()654   public void testPublicDependency() throws Exception {
655     FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
656         .setName("bar.proto")
657         .addMessageType(DescriptorProto.newBuilder().setName("Bar"))
658         .build();
659     FileDescriptorProto forwardProto = FileDescriptorProto.newBuilder()
660         .setName("forward.proto")
661         .addDependency("bar.proto")
662         .addPublicDependency(0)
663         .build();
664     FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
665         .setName("foo.proto")
666         .addDependency("forward.proto")
667         .addMessageType(DescriptorProto.newBuilder()
668             .setName("Foo")
669             .addField(FieldDescriptorProto.newBuilder()
670                 .setLabel(FieldDescriptorProto.Label.LABEL_OPTIONAL)
671                 .setTypeName("Bar")
672                 .setName("bar")
673                 .setNumber(1)))
674         .build();
675     FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
676         barProto, new FileDescriptor[0]);
677     FileDescriptor forwardFile = Descriptors.FileDescriptor.buildFrom(
678         forwardProto, new FileDescriptor[]{barFile});
679     Descriptors.FileDescriptor.buildFrom(
680         fooProto, new FileDescriptor[] {forwardFile});
681   }
682 
683   /**
684    * Tests the translate/crosslink for an example with a more complex namespace
685    * referencing.
686    */
testComplexNamespacePublicDependency()687   public void testComplexNamespacePublicDependency() throws Exception {
688     FileDescriptorProto fooProto = FileDescriptorProto.newBuilder()
689         .setName("bar.proto")
690         .setPackage("a.b.c.d.bar.shared")
691         .addEnumType(EnumDescriptorProto.newBuilder()
692             .setName("MyEnum")
693             .addValue(EnumValueDescriptorProto.newBuilder()
694                 .setName("BLAH")
695                 .setNumber(1)))
696         .build();
697     FileDescriptorProto barProto = FileDescriptorProto.newBuilder()
698         .setName("foo.proto")
699         .addDependency("bar.proto")
700         .setPackage("a.b.c.d.foo.shared")
701         .addMessageType(DescriptorProto.newBuilder()
702             .setName("MyMessage")
703             .addField(FieldDescriptorProto.newBuilder()
704                 .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
705                 .setTypeName("bar.shared.MyEnum")
706                 .setName("MyField")
707                 .setNumber(1)))
708         .build();
709     // translate and crosslink
710     FileDescriptor fooFile = Descriptors.FileDescriptor.buildFrom(
711         fooProto, new FileDescriptor[0]);
712     FileDescriptor barFile = Descriptors.FileDescriptor.buildFrom(
713         barProto, new FileDescriptor[]{fooFile});
714     // verify resulting descriptors
715     assertNotNull(barFile);
716     List<Descriptor> msglist = barFile.getMessageTypes();
717     assertNotNull(msglist);
718     assertTrue(msglist.size() == 1);
719     Descriptor desc = msglist.get(0);
720     if (desc.getName().equals("MyMessage")) {
721       assertNotNull(desc.getFields());
722       List<FieldDescriptor> fieldlist = desc.getFields();
723       assertNotNull(fieldlist);
724       assertTrue(fieldlist.size() == 1);
725       FieldDescriptor field = fieldlist.get(0);
726       assertTrue(field.getType() == FieldDescriptor.Type.ENUM);
727       assertTrue(field.getEnumType().getName().equals("MyEnum"));
728       assertTrue(field.getEnumType().getFile().getName().equals("bar.proto"));
729       assertTrue(field.getEnumType().getFile().getPackage().equals(
730           "a.b.c.d.bar.shared"));
731     }
732   }
733 
testOneofDescriptor()734   public void testOneofDescriptor() throws Exception {
735     Descriptor messageType = TestAllTypes.getDescriptor();
736     FieldDescriptor field =
737         messageType.findFieldByName("oneof_nested_message");
738     OneofDescriptor oneofDescriptor = field.getContainingOneof();
739     assertNotNull(oneofDescriptor);
740     assertSame(oneofDescriptor, messageType.getOneofs().get(0));
741     assertEquals("oneof_field", oneofDescriptor.getName());
742 
743     assertEquals(4, oneofDescriptor.getFieldCount());
744     assertSame(oneofDescriptor.getField(1), field);
745 
746     assertEquals(4, oneofDescriptor.getFields().size());
747     assertEquals(oneofDescriptor.getFields().get(1), field);
748   }
749 
testMessageDescriptorExtensions()750   public void testMessageDescriptorExtensions() throws Exception {
751     assertFalse(TestAllTypes.getDescriptor().isExtendable());
752     assertTrue(TestAllExtensions.getDescriptor().isExtendable());
753     assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtendable());
754 
755     assertFalse(TestAllTypes.getDescriptor().isExtensionNumber(3));
756     assertTrue(TestAllExtensions.getDescriptor().isExtensionNumber(3));
757     assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(42));
758     assertFalse(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(43));
759     assertFalse(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4142));
760     assertTrue(TestMultipleExtensionRanges.getDescriptor().isExtensionNumber(4143));
761   }
762 
testReservedFields()763   public void testReservedFields() {
764     Descriptor d = TestReservedFields.getDescriptor();
765     assertTrue(d.isReservedNumber(2));
766     assertFalse(d.isReservedNumber(8));
767     assertTrue(d.isReservedNumber(9));
768     assertTrue(d.isReservedNumber(10));
769     assertTrue(d.isReservedNumber(11));
770     assertFalse(d.isReservedNumber(12));
771     assertFalse(d.isReservedName("foo"));
772     assertTrue(d.isReservedName("bar"));
773     assertTrue(d.isReservedName("baz"));
774   }
775 
testToString()776   public void testToString() {
777     assertEquals("protobuf_unittest.TestAllTypes.optional_uint64",
778         UnittestProto.TestAllTypes.getDescriptor().findFieldByNumber(
779             UnittestProto.TestAllTypes.OPTIONAL_UINT64_FIELD_NUMBER).toString());
780   }
781 
testPackedEnumField()782   public void testPackedEnumField() throws Exception {
783     FileDescriptorProto fileDescriptorProto = FileDescriptorProto.newBuilder()
784         .setName("foo.proto")
785         .addEnumType(EnumDescriptorProto.newBuilder()
786           .setName("Enum")
787           .addValue(EnumValueDescriptorProto.newBuilder()
788             .setName("FOO")
789             .setNumber(1)
790             .build())
791           .build())
792         .addMessageType(DescriptorProto.newBuilder()
793           .setName("Message")
794           .addField(FieldDescriptorProto.newBuilder()
795             .setName("foo")
796             .setTypeName("Enum")
797             .setNumber(1)
798             .setLabel(FieldDescriptorProto.Label.LABEL_REPEATED)
799             .setOptions(DescriptorProtos.FieldOptions.newBuilder()
800               .setPacked(true)
801               .build())
802             .build())
803           .build())
804         .build();
805     Descriptors.FileDescriptor.buildFrom(
806         fileDescriptorProto, new FileDescriptor[0]);
807   }
808 }
809