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