• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 #region Copyright notice and license
2 // Protocol Buffers - Google's data interchange format
3 // Copyright 2008 Google Inc.  All rights reserved.
4 // https://developers.google.com/protocol-buffers/
5 //
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are
8 // met:
9 //
10 //     * Redistributions of source code must retain the above copyright
11 // notice, this list of conditions and the following disclaimer.
12 //     * Redistributions in binary form must reproduce the above
13 // copyright notice, this list of conditions and the following disclaimer
14 // in the documentation and/or other materials provided with the
15 // distribution.
16 //     * Neither the name of Google Inc. nor the names of its
17 // contributors may be used to endorse or promote products derived from
18 // this software without specific prior written permission.
19 //
20 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #endregion
32 
33 using Google.Protobuf.TestProtos;
34 using NUnit.Framework;
35 using ProtobufUnittest;
36 using System;
37 using System.Collections.Generic;
38 using System.Linq;
39 
40 namespace Google.Protobuf.Reflection
41 {
42     /// <summary>
43     /// Tests for descriptors. (Not in its own namespace or broken up into individual classes as the
44     /// size doesn't warrant it. On the other hand, this makes me feel a bit dirty...)
45     /// </summary>
46     public class DescriptorsTest
47     {
48         [Test]
FileDescriptor_GeneratedCode()49         public void FileDescriptor_GeneratedCode()
50         {
51             TestFileDescriptor(
52                 UnittestProto3Reflection.Descriptor,
53                 UnittestImportProto3Reflection.Descriptor,
54                 UnittestImportPublicProto3Reflection.Descriptor);
55         }
56 
57         [Test]
FileDescriptor_BuildFromByteStrings()58         public void FileDescriptor_BuildFromByteStrings()
59         {
60             // The descriptors have to be supplied in an order such that all the
61             // dependencies come before the descriptors depending on them.
62             var descriptorData = new List<ByteString>
63             {
64                 UnittestImportPublicProto3Reflection.Descriptor.SerializedData,
65                 UnittestImportProto3Reflection.Descriptor.SerializedData,
66                 UnittestProto3Reflection.Descriptor.SerializedData
67             };
68             var converted = FileDescriptor.BuildFromByteStrings(descriptorData);
69             Assert.AreEqual(3, converted.Count);
70             TestFileDescriptor(converted[2], converted[1], converted[0]);
71         }
72 
TestFileDescriptor(FileDescriptor file, FileDescriptor importedFile, FileDescriptor importedPublicFile)73         private void TestFileDescriptor(FileDescriptor file, FileDescriptor importedFile, FileDescriptor importedPublicFile)
74         {
75             Assert.AreEqual("unittest_proto3.proto", file.Name);
76             Assert.AreEqual("protobuf_unittest3", file.Package);
77 
78             Assert.AreEqual("UnittestProto", file.Proto.Options.JavaOuterClassname);
79             Assert.AreEqual("unittest_proto3.proto", file.Proto.Name);
80 
81             // unittest_proto3.proto doesn't have any public imports, but unittest_import_proto3.proto does.
82             Assert.AreEqual(0, file.PublicDependencies.Count);
83             Assert.AreEqual(1, importedFile.PublicDependencies.Count);
84             Assert.AreEqual(importedPublicFile, importedFile.PublicDependencies[0]);
85 
86             Assert.AreEqual(1, file.Dependencies.Count);
87             Assert.AreEqual(importedFile, file.Dependencies[0]);
88 
89             Assert.Null(file.FindTypeByName<MessageDescriptor>("NoSuchType"));
90             Assert.Null(file.FindTypeByName<MessageDescriptor>("protobuf_unittest3.TestAllTypes"));
91             for (int i = 0; i < file.MessageTypes.Count; i++)
92             {
93                 Assert.AreEqual(i, file.MessageTypes[i].Index);
94             }
95 
96             Assert.AreEqual(file.EnumTypes[0], file.FindTypeByName<EnumDescriptor>("ForeignEnum"));
97             Assert.Null(file.FindTypeByName<EnumDescriptor>("NoSuchType"));
98             Assert.Null(file.FindTypeByName<EnumDescriptor>("protobuf_unittest3.ForeignEnum"));
99             Assert.AreEqual(1, importedFile.EnumTypes.Count);
100             Assert.AreEqual("ImportEnum", importedFile.EnumTypes[0].Name);
101             for (int i = 0; i < file.EnumTypes.Count; i++)
102             {
103                 Assert.AreEqual(i, file.EnumTypes[i].Index);
104             }
105 
106             Assert.AreEqual(10, file.SerializedData[0]);
107         }
108 
109         [Test]
FileDescriptor_NonRootPath()110         public void FileDescriptor_NonRootPath()
111         {
112             // unittest_proto3.proto used to be in google/protobuf. Now it's in the C#-specific location,
113             // let's test something that's still in a directory.
114             FileDescriptor file = UnittestWellKnownTypesReflection.Descriptor;
115             Assert.AreEqual("google/protobuf/unittest_well_known_types.proto", file.Name);
116             Assert.AreEqual("protobuf_unittest", file.Package);
117         }
118 
119         [Test]
FileDescriptor_BuildFromByteStrings_MissingDependency()120         public void FileDescriptor_BuildFromByteStrings_MissingDependency()
121         {
122             var descriptorData = new List<ByteString>
123             {
124                 UnittestImportProto3Reflection.Descriptor.SerializedData,
125                 UnittestProto3Reflection.Descriptor.SerializedData,
126             };
127             // This will fail, because we're missing UnittestImportPublicProto3Reflection
128             Assert.Throws<ArgumentException>(() => FileDescriptor.BuildFromByteStrings(descriptorData));
129         }
130 
131         [Test]
FileDescriptor_BuildFromByteStrings_DuplicateNames()132         public void FileDescriptor_BuildFromByteStrings_DuplicateNames()
133         {
134             var descriptorData = new List<ByteString>
135             {
136                 UnittestImportPublicProto3Reflection.Descriptor.SerializedData,
137                 UnittestImportPublicProto3Reflection.Descriptor.SerializedData,
138             };
139             // This will fail due to the same name being used twice
140             Assert.Throws<ArgumentException>(() => FileDescriptor.BuildFromByteStrings(descriptorData));
141         }
142 
143         [Test]
FileDescriptor_BuildFromByteStrings_IncorrectOrder()144         public void FileDescriptor_BuildFromByteStrings_IncorrectOrder()
145         {
146             var descriptorData = new List<ByteString>
147             {
148                 UnittestProto3Reflection.Descriptor.SerializedData,
149                 UnittestImportPublicProto3Reflection.Descriptor.SerializedData,
150                 UnittestImportProto3Reflection.Descriptor.SerializedData
151             };
152             // This will fail, because the dependencies should come first
153             Assert.Throws<ArgumentException>(() => FileDescriptor.BuildFromByteStrings(descriptorData));
154 
155         }
156 
157         [Test]
MessageDescriptorFromGeneratedCodeFileDescriptor()158         public void MessageDescriptorFromGeneratedCodeFileDescriptor()
159         {
160             var file = UnittestProto3Reflection.Descriptor;
161 
162             MessageDescriptor messageType = TestAllTypes.Descriptor;
163             Assert.AreSame(typeof(TestAllTypes), messageType.ClrType);
164             Assert.AreSame(TestAllTypes.Parser, messageType.Parser);
165             Assert.AreEqual(messageType, file.MessageTypes[0]);
166             Assert.AreEqual(messageType, file.FindTypeByName<MessageDescriptor>("TestAllTypes"));
167         }
168 
169         [Test]
MessageDescriptor()170         public void MessageDescriptor()
171         {
172             MessageDescriptor messageType = TestAllTypes.Descriptor;
173             MessageDescriptor nestedType = TestAllTypes.Types.NestedMessage.Descriptor;
174 
175             Assert.AreEqual("TestAllTypes", messageType.Name);
176             Assert.AreEqual("protobuf_unittest3.TestAllTypes", messageType.FullName);
177             Assert.AreEqual(UnittestProto3Reflection.Descriptor, messageType.File);
178             Assert.IsNull(messageType.ContainingType);
179             Assert.IsNull(messageType.Proto.Options);
180 
181             Assert.AreEqual("TestAllTypes", messageType.Name);
182 
183             Assert.AreEqual("NestedMessage", nestedType.Name);
184             Assert.AreEqual("protobuf_unittest3.TestAllTypes.NestedMessage", nestedType.FullName);
185             Assert.AreEqual(UnittestProto3Reflection.Descriptor, nestedType.File);
186             Assert.AreEqual(messageType, nestedType.ContainingType);
187 
188             FieldDescriptor field = messageType.Fields.InDeclarationOrder()[0];
189             Assert.AreEqual("single_int32", field.Name);
190             Assert.AreEqual(field, messageType.FindDescriptor<FieldDescriptor>("single_int32"));
191             Assert.Null(messageType.FindDescriptor<FieldDescriptor>("no_such_field"));
192             Assert.AreEqual(field, messageType.FindFieldByNumber(1));
193             Assert.Null(messageType.FindFieldByNumber(571283));
194             var fieldsInDeclarationOrder = messageType.Fields.InDeclarationOrder();
195             for (int i = 0; i < fieldsInDeclarationOrder.Count; i++)
196             {
197                 Assert.AreEqual(i, fieldsInDeclarationOrder[i].Index);
198             }
199 
200             Assert.AreEqual(nestedType, messageType.NestedTypes[0]);
201             Assert.AreEqual(nestedType, messageType.FindDescriptor<MessageDescriptor>("NestedMessage"));
202             Assert.Null(messageType.FindDescriptor<MessageDescriptor>("NoSuchType"));
203             for (int i = 0; i < messageType.NestedTypes.Count; i++)
204             {
205                 Assert.AreEqual(i, messageType.NestedTypes[i].Index);
206             }
207 
208             Assert.AreEqual(messageType.EnumTypes[0], messageType.FindDescriptor<EnumDescriptor>("NestedEnum"));
209             Assert.Null(messageType.FindDescriptor<EnumDescriptor>("NoSuchType"));
210             for (int i = 0; i < messageType.EnumTypes.Count; i++)
211             {
212                 Assert.AreEqual(i, messageType.EnumTypes[i].Index);
213             }
214         }
215 
216         [Test]
FieldDescriptor_GeneratedCode()217         public void FieldDescriptor_GeneratedCode()
218         {
219             TestFieldDescriptor(UnittestProto3Reflection.Descriptor, TestAllTypes.Descriptor, ForeignMessage.Descriptor, ImportMessage.Descriptor);
220         }
221 
222         [Test]
FieldDescriptor_BuildFromByteStrings()223         public void FieldDescriptor_BuildFromByteStrings()
224         {
225             // The descriptors have to be supplied in an order such that all the
226             // dependencies come before the descriptors depending on them.
227             var descriptorData = new List<ByteString>
228             {
229                 UnittestImportPublicProto3Reflection.Descriptor.SerializedData,
230                 UnittestImportProto3Reflection.Descriptor.SerializedData,
231                 UnittestProto3Reflection.Descriptor.SerializedData
232             };
233             var converted = FileDescriptor.BuildFromByteStrings(descriptorData);
234             TestFieldDescriptor(
235                 converted[2],
236                 converted[2].FindTypeByName<MessageDescriptor>("TestAllTypes"),
237                 converted[2].FindTypeByName<MessageDescriptor>("ForeignMessage"),
238                 converted[1].FindTypeByName<MessageDescriptor>("ImportMessage"));
239         }
240 
TestFieldDescriptor( FileDescriptor unitTestProto3Descriptor, MessageDescriptor testAllTypesDescriptor, MessageDescriptor foreignMessageDescriptor, MessageDescriptor importMessageDescriptor)241         public void TestFieldDescriptor(
242             FileDescriptor unitTestProto3Descriptor,
243             MessageDescriptor testAllTypesDescriptor,
244             MessageDescriptor foreignMessageDescriptor,
245             MessageDescriptor importMessageDescriptor)
246         {
247             FieldDescriptor primitiveField = testAllTypesDescriptor.FindDescriptor<FieldDescriptor>("single_int32");
248             FieldDescriptor enumField = testAllTypesDescriptor.FindDescriptor<FieldDescriptor>("single_nested_enum");
249             FieldDescriptor foreignMessageField = testAllTypesDescriptor.FindDescriptor<FieldDescriptor>("single_foreign_message");
250             FieldDescriptor importMessageField = testAllTypesDescriptor.FindDescriptor<FieldDescriptor>("single_import_message");
251             FieldDescriptor fieldInOneof = testAllTypesDescriptor.FindDescriptor<FieldDescriptor>("oneof_string");
252 
253             Assert.AreEqual("single_int32", primitiveField.Name);
254             Assert.AreEqual("protobuf_unittest3.TestAllTypes.single_int32",
255                             primitiveField.FullName);
256             Assert.AreEqual(1, primitiveField.FieldNumber);
257             Assert.AreEqual(testAllTypesDescriptor, primitiveField.ContainingType);
258             Assert.AreEqual(unitTestProto3Descriptor, primitiveField.File);
259             Assert.AreEqual(FieldType.Int32, primitiveField.FieldType);
260             Assert.IsNull(primitiveField.Proto.Options);
261 
262             Assert.AreEqual("single_nested_enum", enumField.Name);
263             Assert.AreEqual(FieldType.Enum, enumField.FieldType);
264             Assert.AreEqual(testAllTypesDescriptor.EnumTypes[0], enumField.EnumType);
265 
266             Assert.AreEqual("single_foreign_message", foreignMessageField.Name);
267             Assert.AreEqual(FieldType.Message, foreignMessageField.FieldType);
268             Assert.AreEqual(foreignMessageDescriptor, foreignMessageField.MessageType);
269 
270             Assert.AreEqual("single_import_message", importMessageField.Name);
271             Assert.AreEqual(FieldType.Message, importMessageField.FieldType);
272             Assert.AreEqual(importMessageDescriptor, importMessageField.MessageType);
273 
274             // For a field in a regular onoef, ContainingOneof and RealContainingOneof should be the same.
275             Assert.AreEqual("oneof_field", fieldInOneof.ContainingOneof.Name);
276             Assert.AreSame(fieldInOneof.ContainingOneof, fieldInOneof.RealContainingOneof);
277         }
278 
279         [Test]
FieldDescriptorLabel()280         public void FieldDescriptorLabel()
281         {
282             FieldDescriptor singleField =
283                 TestAllTypes.Descriptor.FindDescriptor<FieldDescriptor>("single_int32");
284             FieldDescriptor repeatedField =
285                 TestAllTypes.Descriptor.FindDescriptor<FieldDescriptor>("repeated_int32");
286 
287             Assert.IsFalse(singleField.IsRepeated);
288             Assert.IsTrue(repeatedField.IsRepeated);
289         }
290 
291         [Test]
EnumDescriptor()292         public void EnumDescriptor()
293         {
294             // Note: this test is a bit different to the Java version because there's no static way of getting to the descriptor
295             EnumDescriptor enumType = UnittestProto3Reflection.Descriptor.FindTypeByName<EnumDescriptor>("ForeignEnum");
296             EnumDescriptor nestedType = TestAllTypes.Descriptor.FindDescriptor<EnumDescriptor>("NestedEnum");
297 
298             Assert.AreEqual("ForeignEnum", enumType.Name);
299             Assert.AreEqual("protobuf_unittest3.ForeignEnum", enumType.FullName);
300             Assert.AreEqual(UnittestProto3Reflection.Descriptor, enumType.File);
301             Assert.Null(enumType.ContainingType);
302             Assert.Null(enumType.Proto.Options);
303 
304             Assert.AreEqual("NestedEnum", nestedType.Name);
305             Assert.AreEqual("protobuf_unittest3.TestAllTypes.NestedEnum",
306                             nestedType.FullName);
307             Assert.AreEqual(UnittestProto3Reflection.Descriptor, nestedType.File);
308             Assert.AreEqual(TestAllTypes.Descriptor, nestedType.ContainingType);
309 
310             EnumValueDescriptor value = enumType.FindValueByName("FOREIGN_FOO");
311             Assert.AreEqual(value, enumType.Values[1]);
312             Assert.AreEqual("FOREIGN_FOO", value.Name);
313             Assert.AreEqual(4, value.Number);
314             Assert.AreEqual((int) ForeignEnum.ForeignFoo, value.Number);
315             Assert.AreEqual(value, enumType.FindValueByNumber(4));
316             Assert.Null(enumType.FindValueByName("NO_SUCH_VALUE"));
317             for (int i = 0; i < enumType.Values.Count; i++)
318             {
319                 Assert.AreEqual(i, enumType.Values[i].Index);
320             }
321         }
322 
323         [Test]
OneofDescriptor()324         public void OneofDescriptor()
325         {
326             OneofDescriptor descriptor = TestAllTypes.Descriptor.FindDescriptor<OneofDescriptor>("oneof_field");
327             Assert.IsFalse(descriptor.IsSynthetic);
328             Assert.AreEqual("oneof_field", descriptor.Name);
329             Assert.AreEqual("protobuf_unittest3.TestAllTypes.oneof_field", descriptor.FullName);
330 
331             var expectedFields = new[] {
332                 TestAllTypes.OneofBytesFieldNumber,
333                 TestAllTypes.OneofNestedMessageFieldNumber,
334                 TestAllTypes.OneofStringFieldNumber,
335                 TestAllTypes.OneofUint32FieldNumber }
336                 .Select(fieldNumber => TestAllTypes.Descriptor.FindFieldByNumber(fieldNumber))
337                 .ToList();
338             foreach (var field in expectedFields)
339             {
340                 Assert.AreSame(descriptor, field.ContainingOneof);
341             }
342 
343             CollectionAssert.AreEquivalent(expectedFields, descriptor.Fields);
344         }
345 
346         [Test]
MapEntryMessageDescriptor()347         public void MapEntryMessageDescriptor()
348         {
349             var descriptor = MapWellKnownTypes.Descriptor.NestedTypes[0];
350             Assert.IsNull(descriptor.Parser);
351             Assert.IsNull(descriptor.ClrType);
352             Assert.IsNull(descriptor.Fields[1].Accessor);
353         }
354 
355         // From TestFieldOrdering:
356         // string my_string = 11;
357         // int64 my_int = 1;
358         // float my_float = 101;
359         // NestedMessage single_nested_message = 200;
360         [Test]
FieldListOrderings()361         public void FieldListOrderings()
362         {
363             var fields = TestFieldOrderings.Descriptor.Fields;
364             Assert.AreEqual(new[] { 11, 1, 101, 200 }, fields.InDeclarationOrder().Select(x => x.FieldNumber));
365             Assert.AreEqual(new[] { 1, 11, 101, 200 }, fields.InFieldNumberOrder().Select(x => x.FieldNumber));
366         }
367 
368 
369         [Test]
DescriptorProtoFileDescriptor()370         public void DescriptorProtoFileDescriptor()
371         {
372             var descriptor = Google.Protobuf.Reflection.FileDescriptor.DescriptorProtoFileDescriptor;
373             Assert.AreEqual("google/protobuf/descriptor.proto", descriptor.Name);
374         }
375 
376         [Test]
DescriptorImportingExtensionsFromOldCodeGen()377         public void DescriptorImportingExtensionsFromOldCodeGen()
378         {
379             // The extension collection includes a null extension. There's not a lot we can do about that
380             // in itself, as the old generator didn't provide us the extension information.
381             var extensions = TestProtos.OldGenerator.OldExtensions2Reflection.Descriptor.Extensions;
382             Assert.AreEqual(1, extensions.UnorderedExtensions.Count);
383             // Note: this assertion is present so that it will fail if OldExtensions2 is regenerated
384             // with a new generator.
385             Assert.Null(extensions.UnorderedExtensions[0].Extension);
386 
387             // ... but we can make sure we at least don't cause a failure when retrieving descriptors.
388             // In particular, old_extensions1.proto imports old_extensions2.proto, and this used to cause
389             // an execution-time failure.
390             var importingDescriptor = TestProtos.OldGenerator.OldExtensions1Reflection.Descriptor;
391             Assert.NotNull(importingDescriptor);
392         }
393 
394         [Test]
Proto3OptionalDescriptors()395         public void Proto3OptionalDescriptors()
396         {
397             var descriptor = TestProto3Optional.Descriptor;
398             var field = descriptor.Fields[TestProto3Optional.OptionalInt32FieldNumber];
399             Assert.NotNull(field.ContainingOneof);
400             Assert.IsTrue(field.ContainingOneof.IsSynthetic);
401             Assert.Null(field.RealContainingOneof);
402         }
403 
404 
405         [Test]
SyntheticOneofReflection()406         public void SyntheticOneofReflection()
407         {
408             // Expect every oneof in TestProto3Optional to be synthetic
409             var proto3OptionalDescriptor = TestProto3Optional.Descriptor;
410             Assert.AreEqual(0, proto3OptionalDescriptor.RealOneofCount);
411             foreach (var oneof in proto3OptionalDescriptor.Oneofs)
412             {
413                 Assert.True(oneof.IsSynthetic);
414             }
415 
416             // Expect no oneof in the original proto3 unit test file to be synthetic.
417             foreach (var descriptor in ProtobufTestMessages.Proto3.TestMessagesProto3Reflection.Descriptor.MessageTypes)
418             {
419                 Assert.AreEqual(descriptor.Oneofs.Count, descriptor.RealOneofCount);
420                 foreach (var oneof in descriptor.Oneofs)
421                 {
422                     Assert.False(oneof.IsSynthetic);
423                 }
424             }
425 
426             // Expect no oneof in the original proto2 unit test file to be synthetic.
427             foreach (var descriptor in ProtobufTestMessages.Proto2.TestMessagesProto2Reflection.Descriptor.MessageTypes)
428             {
429                 Assert.AreEqual(descriptor.Oneofs.Count, descriptor.RealOneofCount);
430                 foreach (var oneof in descriptor.Oneofs)
431                 {
432                     Assert.False(oneof.IsSynthetic);
433                 }
434             }
435         }
436     }
437 }
438